Created
December 19, 2017 18:17
-
-
Save hardyoyo/cb66844755d5b8f6a87ebdeb4a0bf5ff to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
hpottinger@hpottinger-Oryx-Pro:~/workspace/lando-tomcat |-/ lando.dev rebuild -- -vvvv | |
verbose: Loading event pre-bootstrap priority 1 | |
verbose: Loading event pre-bootstrap priority 1 | |
info: Bootstrap starting... | |
debug: Boostrapping with appConfigFilename=.lando.yml, appsRoot=/home/hpottinger/Lando, appRegistry=/home/hpottinger/.lando/appRegistry.json, cache=true, composeBin=/usr/share/lando/bin/docker-compose, composeVersion=3.2, configFilename=config.yml, , dockerBin=/usr/bin/docker, dockerBinDir=/usr/share/lando/bin, engineId=1000, engineGid=1000, XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.11, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, home=/home/hpottinger, isNW=false, logLevel=debug, logLevelConsole=warn, loadPassphraseProtectedKeys=false, node=v6.9.5, type=Linux, platform=linux, release=4.4.0-103-generic, arch=x64, report=true, url=http://metrics.devwithlando.io, srcRoot=/home/hpottinger/workspace/lando, sysConfRoot=/usr/share/lando, userConfRoot=/home/hpottinger/.lando, version=3.0.0-beta.29, plugins=[lando-core, lando-events, lando-proxy, lando-recipes, lando-services, lando-tooling], proxy=ON, proxyDomain=lndo.site, proxyDash=58086, proxyHttpPort=80, proxyHttpsPort=443, proxyHttpFallbacks=[8000, 8080, 8888, 8008], proxyHttpsFallbacks=[444, 4433, 4444, 4443, 8443], mode=cli, engineHost=127.0.0.1, engineConfigDir=/home/hpottinger/.lando/services/config, engineScriptsDir=/home/hpottinger/.lando/services/config/scripts, engineHelpersDir=/home/hpottinger/.lando/services/config/helpers, engineHome=/home/hpottinger, engineIp=tcp://127.0.0.1, engineRemoteIp=192.168.11.11 | |
silly: It's not particularly silly, is it? I mean, the right leg isn't silly at all and the left leg merely does a forward aerial half turn every alternate step. | |
verbose: Emitting event pre-bootstrap | |
debug: Event pre-bootstrap has 2 listeners | |
debug: Retrieved from file cache with key lando:updates | |
debug: Retrieved from file cache with key lando:updates | |
There is an update available!!! | |
Install it to get the latest and greatest | |
Updating helps us provide the best support | |
https://github.com/lando/lando/releases/tag/v3.0.0-beta.31 | |
verbose: Trying to load plugins 0=lando-core, 1=lando-events, 2=lando-proxy, 3=lando-recipes, 4=lando-services, 5=lando-tooling | |
debug: Searching for lando-core plugin in ["/home/hpottinger/workspace/lando/node_modules/lando-core/index.js","/home/hpottinger/workspace/lando/plugins/lando-core/index.js","/usr/share/lando/node_modules/lando-core/index.js","/usr/share/lando/plugins/lando-core/index.js","/home/hpottinger/.lando/node_modules/lando-core/index.js","/home/hpottinger/.lando/plugins/lando-core/index.js"] | |
debug: Searching for lando-events plugin in ["/home/hpottinger/workspace/lando/node_modules/lando-events/index.js","/home/hpottinger/workspace/lando/plugins/lando-events/index.js","/usr/share/lando/node_modules/lando-events/index.js","/usr/share/lando/plugins/lando-events/index.js","/home/hpottinger/.lando/node_modules/lando-events/index.js","/home/hpottinger/.lando/plugins/lando-events/index.js"] | |
debug: Searching for lando-proxy plugin in ["/home/hpottinger/workspace/lando/node_modules/lando-proxy/index.js","/home/hpottinger/workspace/lando/plugins/lando-proxy/index.js","/usr/share/lando/node_modules/lando-proxy/index.js","/usr/share/lando/plugins/lando-proxy/index.js","/home/hpottinger/.lando/node_modules/lando-proxy/index.js","/home/hpottinger/.lando/plugins/lando-proxy/index.js"] | |
debug: Searching for lando-recipes plugin in ["/home/hpottinger/workspace/lando/node_modules/lando-recipes/index.js","/home/hpottinger/workspace/lando/plugins/lando-recipes/index.js","/usr/share/lando/node_modules/lando-recipes/index.js","/usr/share/lando/plugins/lando-recipes/index.js","/home/hpottinger/.lando/node_modules/lando-recipes/index.js","/home/hpottinger/.lando/plugins/lando-recipes/index.js"] | |
debug: Searching for lando-services plugin in ["/home/hpottinger/workspace/lando/node_modules/lando-services/index.js","/home/hpottinger/workspace/lando/plugins/lando-services/index.js","/usr/share/lando/node_modules/lando-services/index.js","/usr/share/lando/plugins/lando-services/index.js","/home/hpottinger/.lando/node_modules/lando-services/index.js","/home/hpottinger/.lando/plugins/lando-services/index.js"] | |
debug: Searching for lando-tooling plugin in ["/home/hpottinger/workspace/lando/node_modules/lando-tooling/index.js","/home/hpottinger/workspace/lando/plugins/lando-tooling/index.js","/usr/share/lando/node_modules/lando-tooling/index.js","/usr/share/lando/plugins/lando-tooling/index.js","/home/hpottinger/.lando/node_modules/lando-tooling/index.js","/home/hpottinger/.lando/plugins/lando-tooling/index.js"] | |
verbose: Loading event post-bootstrap priority 1 | |
verbose: Loading event post-bootstrap priority 5 | |
verbose: Loading event post-bootstrap priority 9 | |
verbose: Loading event post-instantiate-app priority 1 | |
verbose: Loading event post-instantiate-app priority 5 | |
verbose: Loading event post-instantiate-app priority 1 | |
verbose: Loading event post-instantiate-app priority 1 | |
verbose: Loading event post-bootstrap priority 1 | |
verbose: Loading event post-instantiate-app priority 1 | |
verbose: Loading event post-bootstrap priority 5 | |
verbose: Loading event poweroff priority 5 | |
verbose: Loading event post-instantiate-app priority 5 | |
verbose: Loading event post-bootstrap priority 1 | |
verbose: Loading event post-bootstrap priority 5 | |
verbose: Loading event post-bootstrap priority 8 | |
verbose: Loading event post-instantiate-app priority 2 | |
verbose: Loading event post-bootstrap priority 1 | |
verbose: Loading event post-bootstrap priority 5 | |
verbose: Loading event post-bootstrap priority 9 | |
verbose: Loading event post-instantiate-app priority 3 | |
verbose: Loading event post-bootstrap priority 1 | |
verbose: Loading event post-bootstrap priority 5 | |
verbose: Plugin lando-core loaded from /home/hpottinger/workspace/lando/plugins/lando-core/index.js | |
verbose: Plugin lando-events loaded from /home/hpottinger/workspace/lando/plugins/lando-events/index.js | |
verbose: Plugin lando-proxy loaded from /home/hpottinger/workspace/lando/plugins/lando-proxy/index.js | |
verbose: Plugin lando-recipes loaded from /home/hpottinger/workspace/lando/plugins/lando-recipes/index.js | |
verbose: Plugin lando-services loaded from /home/hpottinger/workspace/lando/plugins/lando-services/index.js | |
verbose: Plugin lando-tooling loaded from /home/hpottinger/workspace/lando/plugins/lando-tooling/index.js | |
info: Core plugins loaded | |
verbose: Emitting event post-bootstrap | |
debug: Event post-bootstrap has 13 listeners | |
info: Initializing init framework | |
info: Initializing events | |
info: Initializing recipes | |
info: Initializing services | |
verbose: Copying scripts config from /home/hpottinger/workspace/lando/plugins/lando-services/scripts to /home/hpottinger/.lando/services/config/scripts | |
verbose: Copying helpers config from /home/hpottinger/workspace/lando/plugins/lando-services/helpers to /home/hpottinger/.lando/services/config/helpers | |
info: Initializing tooling | |
verbose: Loading event task-init-answers priority 5 | |
verbose: Loading event task-init-run priority 5 | |
debug: Retrieved from file cache with key init:auth:github:tokens | |
debug: Cache miss with key init:auth:github:tokens | |
info: Initializing proxy | |
verbose: Proxy initialized with config proxy=ON, proxyDash=58086, proxyHttpPort=80, proxyHttpsPort=443, proxyHttpFallbacks=[8000, 8080, 8888, 8008, 8000, 8080, 8888, 8008], proxyHttpsFallbacks=[444, 4433, 4444, 4443, 444, 4433, 4444, 4443, 8443] | |
verbose: Loading event task-init-answers priority 5 | |
verbose: Loading event task-init-run priority 1 | |
debug: Retrieved from file cache with key init:auth:pantheon:tokens | |
debug: Cache miss with key init:auth:pantheon:tokens | |
verbose: Loading event post-instantiate-app priority 5 | |
verbose: Checking for app config at /home/hpottinger/workspace/lando-tomcat/.lando.yml | |
verbose: Getting app tomcat-demo from /home/hpottinger/workspace/lando-tomcat | |
debug: App tomcat-demo uses config name=tomcat-demo, recipe=custom, type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, tomcat=[tomcat-demo.lndo.site:8080] | |
verbose: Emitting event pre-instantiate-app | |
debug: Event pre-instantiate-app has 0 listeners | |
verbose: Emitting event post-instantiate-app | |
debug: Event post-instantiate-app has 9 listeners | |
verbose: Loading event app-ready priority 5 | |
verbose: Loading event app-ready priority 9 | |
verbose: Loading event app-ready priority 9 | |
verbose: Loading event app-ready priority 5 | |
verbose: Loading event pre-info priority 5 | |
verbose: Loading event post-start priority 1 | |
verbose: Building custom for tomcat-demo | |
debug: Building tomcat-demo with config _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, _recipe=custom | |
verbose: Building tomcat latest ad tomcat | |
debug: Building tomcat with config type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, version=latest | |
verbose: Copying tomcat config from /home/hpottinger/workspace/lando/plugins/lando-services/tomcat to /home/hpottinger/.lando/services/config/tomcat | |
debug: Setting default entrypoint for tomcat | |
verbose: Injecting load-keys.sh from /home/hpottinger/.lando/services/config/scripts to scripts | |
verbose: Injecting mysql-import.sh from /home/hpottinger/.lando/services/config/helpers to helpers | |
verbose: Injecting mysql-export.sh from /home/hpottinger/.lando/services/config/helpers to helpers | |
verbose: Loading event pre-info priority 1 | |
verbose: Loading event post-uninstall priority 5 | |
verbose: Loading event post-start priority 5 | |
verbose: Loading event post-start priority 9 | |
verbose: Loading event post-start priority 5 | |
verbose: Loading event pre-info priority 5 | |
verbose: Loading event pre-start priority 1 | |
verbose: Loading event pre-terminus priority 5 | |
verbose: Loading event post-destroy priority 5 | |
verbose: Added app tomcat-demo to registry with path /home/hpottinger/workspace/lando-tomcat | |
debug: Apps in registry: [{"name":"docs.lando","dir":"/home/hpottinger/workspace/lando"},{"name":"dspace","dir":"/home/hpottinger/workspace/dspace-dev-docker"},{"name":"tomcat-demo","dir":"/home/hpottinger/workspace/lando-tomcat"}] | |
verbose: Retrieved good apps name=docs.lando, dir=/home/hpottinger/workspace/lando, name=tomcat-demo, dir=/home/hpottinger/workspace/lando-tomcat, name=dspace, dir=/home/hpottinger/workspace/dspace-dev-docker | |
verbose: Emitting event app-ready | |
debug: Event app-ready has 4 listeners | |
verbose: App tomcat-demo has global env. LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256 | |
verbose: App tomcat-demo has global labels. io.lando.container=TRUE | |
verbose: App tomcat-demo adds process env. LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
verbose: Building compose file at /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-1.yml with services. 0=services, 1=volumes, 2=version | |
verbose: Writing ["services","volumes","version"] to /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-1.yml | |
debug: Full services for /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-1.yml image=tomcat:latest, ports=[8080], TERM=xterm, LANDO_WEBROOT=/app/./webapps, LANDO_SERVICE_NAME=tomcat, LANDO_SERVICE_TYPE=tomcat, LANDO_MOUNT=/app, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, volumes=[/home/hpottinger/.lando/services/config/tomcat/context.xml:/usr/local/tomcat/conf/context.xml, $LANDO_ENGINE_SCRIPTS_DIR/lando-entrypoint.sh:/lando-entrypoint.sh, $LANDO_APP_ROOT_BIND:/app, $LANDO_ENGINE_HOME:/user, $LANDO_ENGINE_SCRIPTS_DIR/user-perms.sh:/user-perms.sh, /home/hpottinger/.lando/services/config/scripts/load-keys.sh:/scripts/load-keys.sh, /home/hpottinger/.lando/services/config/helpers/mysql-import.sh:/helpers/mysql-import.sh, /home/hpottinger/.lando/services/config/helpers/mysql-export.sh:/helpers/mysql-export.sh], command=catalina.sh run, entrypoint=/lando-entrypoint.sh, io.lando.container=TRUE, , version=3.2 | |
verbose: App tomcat-demo has compose files. 0=/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-1.yml | |
info: App tomcat-demo is ready! | |
debug: App tomcat-demo has config name=tomcat-demo, recipe=custom, type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, version=latest, tomcat=[tomcat-demo.lndo.site:8080] | |
verbose: Recipe custom loaded | |
verbose: Recipe backdrop loaded | |
verbose: Recipe drupal6 loaded | |
verbose: Recipe drupal7 loaded | |
verbose: Recipe drupal8 loaded | |
verbose: Recipe joomla loaded | |
verbose: Recipe laravel loaded | |
verbose: Recipe lamp loaded | |
verbose: Recipe lemp loaded | |
verbose: Recipe mean loaded | |
verbose: Recipe pantheon loaded | |
verbose: Recipe wordpress loaded | |
verbose: Init method github loaded | |
verbose: Init method pantheon loaded | |
verbose: Service apache loaded | |
verbose: Service dotnet loaded | |
verbose: Service elasticsearch loaded | |
verbose: Service go loaded | |
verbose: Service nginx loaded | |
verbose: Service node loaded | |
verbose: Service mailhog loaded | |
verbose: Service mariadb loaded | |
verbose: Service memcached loaded | |
verbose: Service mssql loaded | |
verbose: Service mongo loaded | |
verbose: Service mysql loaded | |
verbose: Service postgres loaded | |
verbose: Service php loaded | |
verbose: Service phpmyadmin loaded | |
verbose: Service python loaded | |
verbose: Service redis loaded | |
verbose: Service ruby loaded | |
verbose: Service solr loaded | |
verbose: Service tomcat loaded | |
verbose: Service varnish loaded | |
info: Bootstrap completed. | |
info: Initializing cli | |
verbose: Emitting event pre-cli-load | |
debug: Event pre-cli-load has 0 listeners | |
verbose: Loading cli task config | |
verbose: Loading cli task destroy | |
verbose: Loading cli task info | |
verbose: Loading cli task init | |
verbose: Loading cli task list | |
verbose: Loading cli task logs | |
verbose: Loading cli task poweroff | |
verbose: Loading cli task rebuild | |
verbose: Loading cli task restart | |
verbose: Loading cli task share | |
verbose: Loading cli task ssh | |
verbose: Loading cli task start | |
verbose: Loading cli task stop | |
verbose: Loading cli task version | |
verbose: Emitting event task-rebuild-answers | |
debug: Event task-rebuild-answers has 0 listeners | |
debug: CLI args _=[rebuild], yes=false, y=false, $0=lando.dev, services=undefined, appname=-vvvv | |
? Are you sure you want to rebuild? Yes | |
verbose: Emitting event task-rebuild-run | |
debug: Event task-rebuild-run has 0 listeners | |
verbose: Trying to get list of apps with opts useCache=true | |
verbose: Retrieved good apps name=docs.lando, dir=/home/hpottinger/workspace/lando, name=tomcat-demo, dir=/home/hpottinger/workspace/lando-tomcat, name=dspace, dir=/home/hpottinger/workspace/dspace-dev-docker | |
verbose: Checking for app config at /home/hpottinger/workspace/lando-tomcat/.lando.yml | |
verbose: Getting app tomcat-demo from /home/hpottinger/workspace/lando-tomcat | |
debug: App tomcat-demo uses config name=tomcat-demo, recipe=custom, type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, tomcat=[tomcat-demo.lndo.site:8080] | |
verbose: Emitting event pre-instantiate-app | |
debug: Event pre-instantiate-app has 0 listeners | |
verbose: Emitting event post-instantiate-app | |
debug: Event post-instantiate-app has 9 listeners | |
verbose: Loading event app-ready priority 5 | |
verbose: Loading event app-ready priority 9 | |
verbose: Loading event app-ready priority 9 | |
verbose: Loading event app-ready priority 5 | |
verbose: Loading event pre-info priority 5 | |
verbose: Loading event post-start priority 1 | |
verbose: Building custom for tomcat-demo | |
debug: Building tomcat-demo with config _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, _recipe=custom | |
verbose: Building tomcat latest ad tomcat | |
debug: Building tomcat with config type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, version=latest | |
verbose: Copying tomcat config from /home/hpottinger/workspace/lando/plugins/lando-services/tomcat to /home/hpottinger/.lando/services/config/tomcat | |
debug: Setting default entrypoint for tomcat | |
verbose: Injecting load-keys.sh from /home/hpottinger/.lando/services/config/scripts to scripts | |
verbose: Injecting mysql-import.sh from /home/hpottinger/.lando/services/config/helpers to helpers | |
verbose: Injecting mysql-export.sh from /home/hpottinger/.lando/services/config/helpers to helpers | |
verbose: Loading event pre-info priority 1 | |
verbose: Loading event post-uninstall priority 5 | |
verbose: Loading event post-start priority 5 | |
verbose: Loading event post-start priority 9 | |
verbose: Loading event post-start priority 5 | |
verbose: Loading event pre-info priority 5 | |
verbose: Loading event pre-start priority 1 | |
verbose: Loading event pre-terminus priority 5 | |
verbose: Loading event post-destroy priority 5 | |
verbose: Added app tomcat-demo to registry with path /home/hpottinger/workspace/lando-tomcat | |
verbose: Retrieved good apps name=docs.lando, dir=/home/hpottinger/workspace/lando, name=tomcat-demo, dir=/home/hpottinger/workspace/lando-tomcat, name=dspace, dir=/home/hpottinger/workspace/dspace-dev-docker | |
verbose: Emitting event app-ready | |
debug: Event app-ready has 4 listeners | |
verbose: App tomcat-demo has global env. LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256 | |
verbose: App tomcat-demo has global labels. io.lando.container=TRUE | |
verbose: App tomcat-demo adds process env. LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
verbose: Building compose file at /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml with services. 0=services, 1=volumes, 2=version | |
verbose: Writing ["services","volumes","version"] to /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml | |
debug: Full services for /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml image=tomcat:latest, ports=[8080], TERM=xterm, LANDO_WEBROOT=/app/./webapps, LANDO_SERVICE_NAME=tomcat, LANDO_SERVICE_TYPE=tomcat, LANDO_MOUNT=/app, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, volumes=[/home/hpottinger/.lando/services/config/tomcat/context.xml:/usr/local/tomcat/conf/context.xml, $LANDO_ENGINE_SCRIPTS_DIR/lando-entrypoint.sh:/lando-entrypoint.sh, $LANDO_APP_ROOT_BIND:/app, $LANDO_ENGINE_HOME:/user, $LANDO_ENGINE_SCRIPTS_DIR/user-perms.sh:/user-perms.sh, /home/hpottinger/.lando/services/config/scripts/load-keys.sh:/scripts/load-keys.sh, /home/hpottinger/.lando/services/config/helpers/mysql-import.sh:/helpers/mysql-import.sh, /home/hpottinger/.lando/services/config/helpers/mysql-export.sh:/helpers/mysql-export.sh], command=catalina.sh run, entrypoint=/lando-entrypoint.sh, io.lando.container=TRUE, , version=3.2 | |
verbose: App tomcat-demo has compose files. 0=/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml | |
info: App tomcat-demo is ready! | |
debug: App tomcat-demo has config name=tomcat-demo, recipe=custom, type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, version=latest, tomcat=[tomcat-demo.lndo.site:8080] | |
verbose: Emitting event status | |
debug: Event status has 0 listeners | |
verbose: Emitting event status | |
debug: Event status has 0 listeners | |
debug: Retrieved from file cache with key site:meta:undefined | |
debug: Cache miss with key site:meta:undefined | |
info: Rebuilding tomcat-demo | |
info: Stopping tomcat-demo | |
debug: Reporting. action=stop, app=36a7ebf24b7a91b0db0cb82be0dbf42910f3b092, type=custom, services=[tomcat:latest], mode=cli, devMode=false, version=3.0.0-beta.29, type=Linux, platform=linux, release=4.4.0-103-generic, arch=x64, nodeVersion=v6.9.5, created=2017-12-19T18:15:56.708Z | |
verbose: Emitting event status | |
debug: Event status has 0 listeners | |
verbose: Trying to get list of apps with opts useCache=false | |
info: Cleaning up app registry and containers | |
debug: Apps in registry: [{"name":"docs.lando","dir":"/home/hpottinger/workspace/lando"},{"name":"dspace","dir":"/home/hpottinger/workspace/dspace-dev-docker"},{"name":"tomcat-demo","dir":"/home/hpottinger/workspace/lando-tomcat"}] | |
verbose: Retrieved good apps name=docs.lando, dir=/home/hpottinger/workspace/lando, name=dspace, dir=/home/hpottinger/workspace/dspace-dev-docker, name=tomcat-demo, dir=/home/hpottinger/workspace/lando-tomcat | |
debug: Retrieved from file cache with key engineUp | |
debug: Cache miss with key engineUp | |
debug: About to run 0=/usr/bin/docker, 1=info | |
silly: With pre run opts | |
verbose: Running exec /usr/bin/docker,info | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers | |
debug: Engine is up. | |
debug: Cached true with key engineUp for {"persist":false,"ttl":5} | |
debug: Failed to cache true with key engineUp | |
debug: Retrieved from memcache with key engineUp | |
verbose: Emitting event pre-engine-stop | |
debug: Event pre-engine-stop has 0 listeners | |
verbose: Emitting event post-engine-stop | |
debug: Event post-engine-stop has 0 listeners | |
debug: Retrieved from memcache with key engineUp | |
verbose: Emitting event pre-engine-destroy | |
debug: Event pre-engine-destroy has 0 listeners | |
verbose: Emitting event post-engine-destroy | |
debug: Event post-engine-destroy has 0 listeners | |
verbose: Emitting event pre-stop | |
debug: Event pre-stop has 0 listeners | |
debug: Retrieved from memcache with key engineUp | |
verbose: Emitting event pre-engine-stop | |
debug: Event pre-engine-stop has 0 listeners | |
debug: About to run 0=/usr/share/lando/bin/docker-compose, 1=--project-name, 2=tomcat-demo, 3=--file, 4=/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml, 5=stop | |
silly: With pre run opts list=function (opts) { | |
// Set opt defaults | |
opts = opts || {useCache: true}; | |
// Log | |
lando.log.verbose('Trying to get list of apps with opts', opts); | |
// Get list of app names. | |
return registry.getApps(opts) | |
// Validate list of apps, look for duplicates. | |
.then(function(apps) { | |
// Group apps by app names. | |
var groups = _.groupBy(apps, function(app) { | |
return app.name; | |
}); | |
// Find a set of duplicates. | |
var duplicates = _.find(groups, function(group) { | |
return group.length !== 1; | |
}); | |
// If a set of duplicates were found throw an error. | |
if (duplicates) { | |
throw new Error('Duplicate app names exist', duplicates); | |
} | |
// Pass the apps on to the each | |
return apps; | |
}); | |
}, get=function (appName) { | |
// If we have an appName lets try to match it with a diretory | |
return Promise.try(function() { | |
if (appName) { | |
return exports.list() | |
.then(function(apps) { | |
return _.find(apps, function(app) { | |
return app.name === appName || app.dockerName === appName; | |
}); | |
}); | |
} | |
}) | |
// Try to use a found app first if possible then default to the cwd | |
.then(function(app) { | |
return _.get(app, 'dir') || path.join(process.cwd()); | |
}) | |
// Return an app or warn the user there is no such app | |
.then(function(dir) { | |
// Split up our dir | |
var pieces = dir.split(path.sep); | |
// Go through all dir pieces | |
return _.map(pieces, function() { | |
// Build the dir | |
var dir = pieces.join(path.sep); | |
// Drop the last path for next iteration | |
pieces = _.dropRight(pieces); | |
// Return the possible location of lando files | |
return path.join(dir, lando.config.appConfigFilename); | |
}); | |
}) | |
// Return the first directory that has an app | |
.then(function(files) { | |
// Find the first directory that has a lando.yml | |
var configFile = _.find(files, function(file) { | |
lando.log.verbose('Checking for app config at %s', file); | |
return fs.existsSync(file); | |
}); | |
// If we have a config file let's load up the app | |
if (!_.isEmpty(configFile)) { | |
// TRy to load the config | |
var appConfig = lando.yaml.load(configFile); | |
// If we have appConfig then load the app | |
if (!_.isEmpty(appConfig)) { | |
return instantiate(appConfig.name, path.dirname(configFile), appConfig); | |
} | |
} | |
}); | |
}, isRunning=function (app, checkall) { | |
// Log | |
lando.log.verbose('Checking if %s is running', app.name); | |
// Clarify the checkall | |
checkall = checkall || false; | |
// Check if our engine is up | |
return lando.engine.isUp() | |
// If we are up check for containers running for an app | |
// otherwise return false | |
.then(function(isUp) { | |
// Engine is up so lets check if the app has running containers | |
if (isUp) { | |
// Get list of containers | |
return lando.engine.list(app.name) | |
// Filter out autostart containers since those will always report TRUE | |
.filter(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
return data.HostConfig.RestartPolicy.Name !== 'always'; | |
}); | |
}) | |
// Reduce containers to a true false running value | |
.reduce(function(isRunning, container) { | |
if (checkall) { | |
return isRunning && lando.engine.isRunning(container.id); | |
} | |
else { | |
return (isRunning) ? true : lando.engine.isRunning(container.id); | |
} | |
}, checkall); | |
} | |
// Engine is down so nothing can be running | |
else { | |
return false; | |
} | |
}); | |
}, exists=function (appName) { | |
// Get app. | |
return _app.get(appName) | |
// Return false if we get an app does not exist error. | |
.catch(function(err) { | |
if (_.contains(err.message, ' does not exist.')) { | |
return false; | |
} | |
else { | |
throw err; | |
} | |
}) | |
// Return true if app was returned. | |
.then(function(app) { | |
return !!app; | |
}); | |
}, info=function (app) { | |
/** | |
* Event that allows other things to add useful metadata to the apps services. | |
* | |
* Its helpful to use this event to add in information for the end user such as | |
* how to access their services, where their code exsts or relevant credential info. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-info | |
* @example | |
* | |
* // Add urls to the app | |
* app.events.on('pre-info', function() { | |
* return getUrls(app); | |
* }); | |
*/ | |
return app.events.emit('pre-info') | |
// Return all the app info | |
.then(function() { | |
if (app && app.info) { | |
return app.info; | |
} | |
}); | |
}, uninstall=function (app) { | |
// Cleaning up | |
app.status('Uninstalling %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('uninstall', {app: app}) | |
/** | |
* Event that runs before an app is uninstalled. | |
* | |
* This is useful if you want to add or remove parts of the uninstall process. | |
* For example, it might be nice to persist a container whose data you do not | |
* want to replace in a rebuild and that cannot persist easily with a volume. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-uninstall | |
* @example | |
* | |
* // Do not uninstall the solr service | |
* app.events.on('pre-uninstall', function() { | |
* delete app.services.solr; | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-uninstall'); | |
}) | |
// Kill components. | |
.then(function() { | |
return lando.engine.destroy(app); | |
}) | |
/** | |
* Event that runs after an app is uninstalled. | |
* | |
* This is useful if you want to do some additional cleanup steps after an | |
* app is uninstalled such as invalidating any cached data. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-uninstall | |
* @example | |
* | |
* // Make sure we remove our build cache | |
* app.events.on('post-uninstall', function() { | |
* lando.cache.remove(app.name + ':last_build'); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-uninstall'); | |
}); | |
}, cleanup=function (app) { | |
// Cleaning up | |
app.status('Cleaning up app registry and containers'); | |
// Get all our containers | |
return _app.list({useCache: false}) | |
// We need to use the dockername | |
.map(function(app) { | |
return lando.utils.dockerComposify(app.name); | |
}) | |
// Filter out non-app containers | |
.then(function(apps) { | |
return Promise.filter(lando.engine.list(), function(container) { | |
return container.kind === 'app' && !_.includes(apps, container.app); | |
}); | |
}) | |
// Stop containers if needed | |
.tap(function(containers) { | |
return lando.engine.stop(containers); | |
}) | |
// Kill containers if needed | |
.tap(function(containers) { | |
return lando.engine.destroy(containers); | |
}); | |
}, start=function (app) { | |
// Start it up | |
app.status('Starting %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('start', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app starts up. | |
* | |
* This is useful if you want to start up any support services before an app | |
* stars. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-start | |
* @example | |
* | |
* // Start up a DNS server before our app starts | |
* app.events.on('pre-start', function() { | |
* return lando.engine.start(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-start'); | |
}) | |
// Start core containers | |
.then(function() { | |
return lando.engine.start(app); | |
}) | |
/** | |
* Event that runs after an app is started. | |
* | |
* This is useful if you want to perform additional operations after an app | |
* starts such as running additional build commands. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-start | |
* @example | |
* | |
* // Go through each service and run additional build commands as needed | |
* app.events.on('post-start', function() { | |
* | |
* // Start up a build collector | |
* var build = []; | |
* | |
* // Go through each service | |
* _.forEach(app.config.services, function(service, name) { | |
* | |
* // If the service has extras let's loop through and run some commands | |
* if (!_.isEmpty(service.extras)) { | |
* | |
* // Normalize data for loopage | |
* if (!_.isArray(service.extras)) { | |
* service.extras = [service.extras]; | |
* } | |
* | |
* // Run each command | |
* _.forEach(service.extras, function(cmd) { | |
* | |
* // Build out the compose object | |
* var compose = { | |
* id: [app.dockerName, name, '1'].join('_'), | |
* cmd: cmd, | |
* opts: { | |
* mode: 'attach' | |
* } | |
* }; | |
* | |
* // Push to the build | |
* build.push(compose); | |
* | |
* }); | |
* | |
* } | |
* | |
* }); | |
* | |
* // Only proceed if build is non-empty | |
* if (!_.isEmpty(build)) { | |
* | |
* // Get the last build cache key | |
* var key = app.name + ':last_build'; | |
* | |
* // Compute the build hash | |
* var newHash = lando.node.hasher(app.config.services); | |
* | |
* // If our new hash is different then lets build | |
* if (lando.cache.get(key) !== newHash) { | |
* | |
* // Set the new hash | |
* lando.cache.set(key, newHash, {persist:true}); | |
* | |
* // Run all our post build steps serially | |
* return lando.engine.run(build); | |
* | |
* } | |
* } | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-start'); | |
}); | |
}, stop=function (app) { | |
// Stop it! | |
app.status('Stopping %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('stop', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app stops. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-stop | |
* @example | |
* | |
* // Stop a DNS server before our app stops. | |
* app.events.on('pre-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-stop'); | |
}) | |
// Stop components. | |
.then(function() { | |
return lando.engine.stop(app); | |
}) | |
/** | |
* Event that runs after an app stop. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-stop | |
* @example | |
* | |
* // Stop a DNS server after our app stops. | |
* app.events.on('post-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-stop'); | |
}); | |
}, restart=function (app) { | |
// Start it off | |
app.status('Restarting %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
// Start app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, destroy=function (app) { | |
// Start it off | |
app.status('Destroying %s', app.name); | |
/** | |
* Event that runs before an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-destroy | |
* @example | |
* | |
* // Make sure the proxy is down before we destroy | |
* app.events.on('pre-destroy', function() { | |
* if (fs.existsSync(proxyFile)) { | |
* return lando.engine.stop(getProxy(proxyFile)); | |
* } | |
* }); | |
*/ | |
return app.events.emit('pre-destroy') | |
// Make sure app is stopped. | |
.then(function() { | |
return _app.stop(app); | |
}) | |
// Uninstall app. | |
.then(function() { | |
app.opts = _.merge(app.opts, {purge: true}); | |
return _app.uninstall(app); | |
}) | |
// Remove from appRegistry | |
.then(function() { | |
return registry.remove({name: app.name}); | |
}) | |
/** | |
* Event that runs after an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-destroy | |
* @example | |
* | |
* // Make sure the proxy is up brought back up after we destroy | |
* app.events.on('post-destroy', function() { | |
* return startProxy(); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-destroy'); | |
}); | |
}, rebuild=function (app) { | |
// Start it off | |
app.status('Rebuilding %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
/** | |
* Event that runs before an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-rebuild'); | |
}) | |
// Uninstall app | |
.then(function() { | |
return _app.uninstall(app); | |
}) | |
// Repull/build components. | |
.then(function() { | |
return lando.engine.build(app); | |
}) | |
/** | |
* Event that runs after an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-rebuild'); | |
}) | |
// Install app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, name=tomcat-demo, dockerName=tomcatdemo, name=tomcat-demo, recipe=custom, type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, version=latest, tomcat=[tomcat-demo.lndo.site:8080], _listeners=[name=app-ready, priority=5, fn=function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, name=app-ready, priority=9, fn=function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, name=app-ready, priority=9, fn=function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, name=app-ready, priority=5, fn=function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}, name=pre-info, priority=5, fn=function () { | |
return getUrls(app); | |
}, name=post-start, priority=1, fn=function () { | |
return getUrls(app); | |
}, name=pre-info, priority=1, fn=function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, name=post-uninstall, priority=5, fn=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, name=post-start, priority=5, fn=function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, name=post-start, priority=9, fn=function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, name=post-start, priority=5, fn=function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}, name=pre-info, priority=5, fn=function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}, name=pre-start, priority=1, fn=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, name=pre-terminus, priority=5, fn=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, name=post-destroy, priority=5, fn=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}], domain=null, app-ready=[function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}], pre-info=[function () { | |
return getUrls(app); | |
}, function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}], post-start=[function () { | |
return getUrls(app); | |
}, function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}], post-uninstall=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, pre-start=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, pre-terminus=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, post-destroy=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}, _eventsCount=7, _maxListeners=20, , root=/home/hpottinger/workspace/lando-tomcat, rootBind=/home/hpottinger/workspace/lando-tomcat, mount=/app, tasks=[command=config, describe=Display the lando configuration, run=function () { | |
console.log(JSON.stringify(lando.config, null, 2)); | |
}, name=config, command=destroy [appname], describe=Destroy app in current directory or [appname], describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to DESTROY?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('DESTRUCTION AVERTED!')); | |
return; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.destroy(app) | |
.then(function() { | |
console.log(chalk.red('App destroyed!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=destroy, command=info [appname], describe=Prints info about app in current directory or [appname], describe=Get ALL the info, alias=[d], default=false, boolean=true, run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// GEt the app info | |
.then(function(app) { | |
if (app) { | |
// If this is deep, go deep | |
if (options.deep) { | |
return lando.engine.list(app.name) | |
.each(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
console.log(JSON.stringify(data, null, 2)); | |
}); | |
}); | |
} | |
// Return the basic info | |
else { | |
return lando.app.info(app) | |
.then(function(info) { | |
console.log(JSON.stringify(info, null, 2)); | |
}); | |
} | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=info, command=list, describe=List all lando apps, run=function () { | |
// List all the apps | |
return lando.app.list() | |
// Map each app to a summary and print results | |
.map(function(app) { | |
return appSummary(app) | |
.then(function(summary) { | |
console.log(JSON.stringify(summary, null, 2)); | |
}); | |
}); | |
}, name=list, command=logs [appname], describe=Get logs for app in current directory or [appname], describe=Follow the logs, alias=[f], default=false, boolean=true, describe=Show logs for the specified services only, alias=[s], array=true, describe=Show log timestamps, alias=[t], default=false, boolean=true, run=function (options) { | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
// Add opts to our app | |
app.opts.follow = options.follow; | |
app.opts.timestamps = options.timestamps; | |
app.opts.services = options.services; | |
// Get the logs | |
return lando.engine.logs(app); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=logs, command=poweroff, describe=Spin down all lando related containers, run=function () { | |
// Start | |
console.log(chalk.yellow('Spinning containers down... Standby.')); | |
// Get all our apps | |
return lando.app.list() | |
// SHUT IT ALL DOWN | |
.map(function(app) { | |
return lando.app.get(app.name) | |
.then(function(app) { | |
lando.app.stop(app); | |
}); | |
}) | |
// Emit poweroff | |
.then(function() { | |
return lando.events.emit('poweroff'); | |
}) | |
// Finish up | |
.then(function() { | |
console.log(chalk.red('Lando containers have been spun down.')); | |
}); | |
}, name=poweroff, command=rebuild [appname], describe=Rebuilds app in current directory or [appname], describe=Rebuild only the specified services, alias=[s], array=true, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to rebuild?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('Rebuild aborted')); | |
return; | |
} | |
// Attempt to grab the app if we can | |
return lando.app.get(options.appname) | |
// Rebuild the app | |
.then(function(app) { | |
if (app) { | |
// Rebuild only particlar services if specified | |
if (!_.isEmpty(options.services)) { | |
app.opts.services = options.services; | |
} | |
return lando.app.rebuild(app) | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=rebuild, command=restart [appname], describe=Restarts app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Resttart the app | |
.then(function(app) { | |
if (app) { | |
// REstart the app | |
return lando.app.restart(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=restart, command=share [appname], describe=Get a publicly available url, describe=Url to share. Needs to be in the form http://localhost:port, alias=[u], required=true, run=function (options) { | |
// Do some validation of the url | |
var url = u.parse(options.url); | |
// Validate URL | |
var hnf = _.isEmpty(url.hostname) || url.hostname !== 'localhost'; | |
if (hnf || url.protocol !== 'http:') { | |
lando.log.error('Need a url of the form http://localhost:port!'); | |
lando.log.error('Run "lando info" for help finding the correct url!'); | |
process.exit(153); | |
} | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Get the sharing url | |
.then(function(app) { | |
if (app) { | |
// Start the app if needed | |
return lando.app.isRunning(app) | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Get the URLS | |
.then(function() { | |
// Assume a port to start | |
var port = 80; | |
// Override port if specified | |
if (!_.isEmpty(url.port)) { | |
port = url.port; | |
} | |
// Translate the app.name into a localtunnel suitable address | |
// eg lowercase/alphanumeric 4-63 chars | |
// lowercase and alphanumeric it | |
var tunnelHost = _.lowerCase(app.name).replace(/[^0-9a-z]/g, ''); | |
// Make sure we are at least 4 characters | |
if (_.size(tunnelHost) <= 4) { | |
tunnelHost = tunnelHost + 'xxxx'; | |
} | |
// Makes sure we are at most 64 chars | |
if (_.size(tunnelHost) >= 63) { | |
tunnelHost = tunnelHost.substring(0, 57); | |
} | |
// Build opts array | |
var opts = {subdomain: tunnelHost}; | |
// Set up the localtunnel | |
var tunnel = localtunnel(port, opts, function(err, tunnel) { | |
// Error if needed | |
if (err) { | |
lando.log.error(err); | |
} | |
// Header it | |
console.log(lando.cli.tunnelHeader()); | |
// the assigned public url for your tunnel | |
// i.e. https://abcdefgjhij.localtunnel.me | |
console.log(chalk.blue(tunnel.url)); | |
console.log(''); | |
console.log(chalk.yellow('Press any key to close the tunnel.')); | |
// Set stdin to the correct mode | |
process.stdin.resume(); | |
process.stdin.setEncoding('utf8'); | |
process.stdin.setRawMode(true); | |
// Start the keypress listener for the process | |
process.stdin.on('data', function() { | |
tunnel.close(); | |
}); | |
}); | |
tunnel.on('close', function() { | |
console.log(''); | |
console.log(chalk.green('Tunnel closed!')); | |
process.exit(0); | |
}); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=share, command=start [appname], describe=Start app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Start the app if we have one | |
.then(function(app) { | |
if (app) { | |
// Start the app | |
return lando.app.start(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=start, command=stop [appname], describe=Stops app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Restart the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.stop(app) | |
.then(function() { | |
console.log(chalk.red('App stopped!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=stop, command=version, describe=Display the lando version, run=function () { | |
console.log('v' + lando.config.version); | |
}, name=version, command=ssh [appname] [service], describe=SSH into [service] in current app directory or [appname], describe=Run a command in the service, alias=[c], describe=Run as a specific user, alias=[u], run=function (options) { | |
// Handle our options | |
if (!_.has(options, 'service') && _.has(options, 'appname')) { | |
options.service = options.appname; | |
options.appname = undefined; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Handle app or no app | |
.then(function(app) { | |
// We have an app so lets try to build a ssh exec | |
if (app) { | |
// Default to appserver if we have no second arg | |
var service = options.service || 'appserver'; | |
// Build out our run | |
var run = { | |
id: [app.dockerName, service, '1'].join('_'), | |
compose: app.compose, | |
project: app.name, | |
cmd: options.command || 'cd $LANDO_MOUNT && bash', | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: options.user || 'www-data', | |
services: [service] | |
} | |
}; | |
// Let's check to see if the app has been started | |
return lando.app.isRunning(app) | |
// If not let's make sure we start it | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Exec | |
.then(function() { | |
return lando.engine.run(run); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=ssh, command=init [method], describe=Initialize a lando app, optional methods: github, pantheon, describe=The recipe to use, choices=[custom, backdrop, drupal6, drupal7, drupal8, joomla, laravel, lamp, lemp, mean, pantheon, wordpress], alias=[r], string=true, type=list, message=What recipe do you want to use?, default=custom, choices=[name=custom, value=custom, name=backdrop, value=backdrop, name=drupal6, value=drupal6, name=drupal7, value=drupal7, name=drupal8, value=drupal8, name=joomla, value=joomla, name=laravel, value=laravel, name=lamp, value=lamp, name=lemp, value=lemp, name=mean, value=mean, name=pantheon, value=pantheon, name=wordpress, value=wordpress], weight=500, name=recipe, describe=GitHub token or email of previously used token, string=true, type=list, message=Choose a GitHub account, choices=[], when=function (answers) { | |
return !_.isEmpty(gitHubAccounts()) && askQuestions(answers); | |
}, weight=400, name=github-auth, name=github-auth, type=password, message=Enter a GitHub token, when=function (answers) { | |
var token = _.get(answers, 'github-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=401, describe=GitHub repo URL, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Repo collector | |
var repos = []; | |
// Spin things up | |
var tpath = 'github-auth'; | |
var token = _.get(lando.tasks.argv(), tpath, answers[tpath]); | |
var options = {affliation: 'owner,collaborator', 'per_page': 100}; | |
var done = this.async(); | |
// Check to see if token is cached already and use that | |
var tokens = lando.cache.get(tokenCacheKey) || {}; | |
if (_.includes(_.keys(tokens), token)) { | |
token = tokens[token]; | |
} | |
/* | |
* Helper to resursively load all our repos | |
*/ | |
var getAllRepos = function(err, res) { | |
// Error | |
if (err) { | |
lando.log.error('Problem getting sites from GitHub'); | |
} | |
// Add previous data to current | |
repos = repos.concat(res.data); | |
// IF we have more pages lets add them | |
if (github.hasNextPage(res)) { | |
github.getNextPage(res, getAllRepos); | |
} | |
// Otherwise lets send back our result | |
else { | |
done(null, _.map(repos, function(site) { | |
var name = _.get(site, 'full_name'); | |
var value = _.get(site, 'ssh_url'); | |
return {name: name, value: value}; | |
})); | |
} | |
}; | |
// Start the github authchain | |
github.authenticate({type: 'token', token: token}); | |
// Get all our sites | |
github.repos.getAll(options, getAllRepos); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=402, name=github-repo, describe=Pantheon machine token or email of previously used token, string=true, type=list, message=Choose a Pantheon account, choices=[], when=function (answers) { | |
return !_.isEmpty(pantheonAccounts()) && askQuestions(answers); | |
}, weight=600, name=pantheon-auth, name=pantheon-auth, type=password, message=Enter a Pantheon machine token, when=function (answers) { | |
var token = _.get(answers, 'pantheon-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=601, describe=Pantheon site machine name, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Token path | |
var tpath = 'pantheon-auth'; | |
// Make this async cause we need to hit the terminus | |
var done = this.async(); | |
// Get the pantheon sites using the token | |
api.getSites(_.get(lando.tasks.argv(), tpath, answers[tpath])) | |
// Parse the sites into choices | |
.map(function(site) { | |
return {name: site.name, value: site.name}; | |
}) | |
// Done | |
.then(function(sites) { | |
done(null, sites); | |
}); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=602, name=pantheon-site, describe=Specify where to init the app, alias=[dest, d], string=true, default=/home/hpottinger/workspace/lando-tomcat, describe=Specify the webroot relative to destination, string=true, type=input, message=Where is your webroot relative to the init destination?, default=., when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.webroot(recipe); | |
}, weight=900, name=webroot, describe=The name of the app, string=true, type=input, message=What do you want to call this app?, default=My Lando App, filter=function (value) { | |
if (value) { | |
return _.kebabCase(value); | |
} | |
}, when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.name(recipe); | |
}, weight=1000, name=name, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, run=function (options) { | |
// Set the basics | |
var config = { | |
name: options.name, | |
recipe: options.recipe, | |
}; | |
// If we have a webroot let's set it | |
if (!_.isEmpty(options.webroot)) { | |
_.set(config, 'config.webroot', options.webroot); | |
} | |
// Method specific build steps if applicable | |
return Promise.try(function() { | |
return lando.init.build(config.name, options.method, options); | |
}) | |
// Kill any build containers if needed | |
.then(function() { | |
return lando.init.kill(config.name, options.destination); | |
}) | |
// Check to see if our recipe provides additional yaml augment | |
.then(function() { | |
return lando.init.yaml(options.recipe, config, options); | |
}) | |
// Create the lando yml | |
.then(function(config) { | |
// Where are we going? | |
var dest = path.join(options.destination, '.lando.yml'); | |
// Rebase on top of any existing yaml | |
if (fs.existsSync(dest)) { | |
var pec = lando.yaml.load(dest); | |
config = _.mergeWith(pec, config, lando.utils.merger); | |
} | |
// Dump it | |
lando.yaml.dump(dest, config); | |
}) | |
// Tell the user things | |
.then(function() { | |
// Header it | |
console.log(lando.cli.initHeader()); | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Get docs link | |
var docBase = 'https://docs.devwithlando.io/tutorials/'; | |
var docUrl = docBase + config.recipe + '.html'; | |
// Add data | |
table.add('NAME', config.name); | |
table.add('RECIPE', options.recipe); | |
table.add('DOCS', docUrl); | |
// Add some other things if needed | |
if (!_.isEmpty(options.method)) { | |
table.add('METHOD', options.method); | |
} | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
}, name=init], webRoot=., status=function () { | |
var args = _.toArray(arguments); | |
var msg = util.format.apply(null, args); | |
return app.events.emit('status', msg) | |
// Make sure app status messages make it to global status. | |
.then(function() { | |
lando.log.info(msg); | |
}); | |
}, trollForStatus=function (msg) { | |
// Update status when pulling an image. | |
var images = msg.match(/Pulling from (.*)/); | |
if (images) { | |
app.status('Pulling image %s.', images[1]); | |
} | |
}, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, io.lando.container=TRUE, project=tomcat-demo, compose=[], image=tomcat:latest, ports=[8080], TERM=xterm, LANDO_WEBROOT=/app/./webapps, LANDO_SERVICE_NAME=tomcat, LANDO_SERVICE_TYPE=tomcat, LANDO_MOUNT=/app, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, volumes=[/home/hpottinger/.lando/services/config/tomcat/context.xml:/usr/local/tomcat/conf/context.xml, $LANDO_ENGINE_SCRIPTS_DIR/lando-entrypoint.sh:/lando-entrypoint.sh, $LANDO_APP_ROOT_BIND:/app, $LANDO_ENGINE_HOME:/user, $LANDO_ENGINE_SCRIPTS_DIR/user-perms.sh:/user-perms.sh, /home/hpottinger/.lando/services/config/scripts/load-keys.sh:/scripts/load-keys.sh, /home/hpottinger/.lando/services/config/helpers/mysql-import.sh:/helpers/mysql-import.sh, /home/hpottinger/.lando/services/config/helpers/mysql-export.sh:/helpers/mysql-export.sh], command=catalina.sh run, entrypoint=/lando-entrypoint.sh, io.lando.container=TRUE, , , mode=collect | |
verbose: Running spawn /usr/share/lando/bin/docker-compose with args ["--project-name","tomcat-demo","--file","/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml","stop"] | |
debug: In mode collect with detached false | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
Stopping tomcatdemo_tomcat_1 ... done | |
verbose: Spawn exited with code: 0 | |
silly: Spawn finished with | |
verbose: Emitting event post-engine-stop | |
debug: Event post-engine-stop has 0 listeners | |
verbose: Emitting event post-stop | |
debug: Event post-stop has 0 listeners | |
verbose: Emitting event pre-rebuild | |
debug: Event pre-rebuild has 0 listeners | |
verbose: Emitting event status | |
debug: Event status has 0 listeners | |
debug: Retrieved from file cache with key site:meta:undefined | |
debug: Cache miss with key site:meta:undefined | |
info: Uninstalling tomcat-demo | |
debug: Reporting. action=uninstall, app=36a7ebf24b7a91b0db0cb82be0dbf42910f3b092, type=custom, services=[tomcat:latest], mode=cli, devMode=false, version=3.0.0-beta.29, type=Linux, platform=linux, release=4.4.0-103-generic, arch=x64, nodeVersion=v6.9.5, created=2017-12-19T18:16:08.676Z | |
verbose: Emitting event pre-uninstall | |
debug: Event pre-uninstall has 0 listeners | |
debug: Retrieved from file cache with key engineUp | |
debug: Cache miss with key engineUp | |
debug: About to run 0=/usr/bin/docker, 1=info | |
silly: With pre run opts | |
verbose: Running exec /usr/bin/docker,info | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
debug: Engine is up. | |
debug: Cached true with key engineUp for {"persist":false,"ttl":5} | |
debug: Failed to cache true with key engineUp | |
verbose: Emitting event pre-engine-destroy | |
debug: Event pre-engine-destroy has 0 listeners | |
debug: About to run 0=/usr/share/lando/bin/docker-compose, 1=--project-name, 2=tomcat-demo, 3=--file, 4=/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml, 5=rm, 6=--force, 7=-v | |
silly: With pre run opts list=function (opts) { | |
// Set opt defaults | |
opts = opts || {useCache: true}; | |
// Log | |
lando.log.verbose('Trying to get list of apps with opts', opts); | |
// Get list of app names. | |
return registry.getApps(opts) | |
// Validate list of apps, look for duplicates. | |
.then(function(apps) { | |
// Group apps by app names. | |
var groups = _.groupBy(apps, function(app) { | |
return app.name; | |
}); | |
// Find a set of duplicates. | |
var duplicates = _.find(groups, function(group) { | |
return group.length !== 1; | |
}); | |
// If a set of duplicates were found throw an error. | |
if (duplicates) { | |
throw new Error('Duplicate app names exist', duplicates); | |
} | |
// Pass the apps on to the each | |
return apps; | |
}); | |
}, get=function (appName) { | |
// If we have an appName lets try to match it with a diretory | |
return Promise.try(function() { | |
if (appName) { | |
return exports.list() | |
.then(function(apps) { | |
return _.find(apps, function(app) { | |
return app.name === appName || app.dockerName === appName; | |
}); | |
}); | |
} | |
}) | |
// Try to use a found app first if possible then default to the cwd | |
.then(function(app) { | |
return _.get(app, 'dir') || path.join(process.cwd()); | |
}) | |
// Return an app or warn the user there is no such app | |
.then(function(dir) { | |
// Split up our dir | |
var pieces = dir.split(path.sep); | |
// Go through all dir pieces | |
return _.map(pieces, function() { | |
// Build the dir | |
var dir = pieces.join(path.sep); | |
// Drop the last path for next iteration | |
pieces = _.dropRight(pieces); | |
// Return the possible location of lando files | |
return path.join(dir, lando.config.appConfigFilename); | |
}); | |
}) | |
// Return the first directory that has an app | |
.then(function(files) { | |
// Find the first directory that has a lando.yml | |
var configFile = _.find(files, function(file) { | |
lando.log.verbose('Checking for app config at %s', file); | |
return fs.existsSync(file); | |
}); | |
// If we have a config file let's load up the app | |
if (!_.isEmpty(configFile)) { | |
// TRy to load the config | |
var appConfig = lando.yaml.load(configFile); | |
// If we have appConfig then load the app | |
if (!_.isEmpty(appConfig)) { | |
return instantiate(appConfig.name, path.dirname(configFile), appConfig); | |
} | |
} | |
}); | |
}, isRunning=function (app, checkall) { | |
// Log | |
lando.log.verbose('Checking if %s is running', app.name); | |
// Clarify the checkall | |
checkall = checkall || false; | |
// Check if our engine is up | |
return lando.engine.isUp() | |
// If we are up check for containers running for an app | |
// otherwise return false | |
.then(function(isUp) { | |
// Engine is up so lets check if the app has running containers | |
if (isUp) { | |
// Get list of containers | |
return lando.engine.list(app.name) | |
// Filter out autostart containers since those will always report TRUE | |
.filter(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
return data.HostConfig.RestartPolicy.Name !== 'always'; | |
}); | |
}) | |
// Reduce containers to a true false running value | |
.reduce(function(isRunning, container) { | |
if (checkall) { | |
return isRunning && lando.engine.isRunning(container.id); | |
} | |
else { | |
return (isRunning) ? true : lando.engine.isRunning(container.id); | |
} | |
}, checkall); | |
} | |
// Engine is down so nothing can be running | |
else { | |
return false; | |
} | |
}); | |
}, exists=function (appName) { | |
// Get app. | |
return _app.get(appName) | |
// Return false if we get an app does not exist error. | |
.catch(function(err) { | |
if (_.contains(err.message, ' does not exist.')) { | |
return false; | |
} | |
else { | |
throw err; | |
} | |
}) | |
// Return true if app was returned. | |
.then(function(app) { | |
return !!app; | |
}); | |
}, info=function (app) { | |
/** | |
* Event that allows other things to add useful metadata to the apps services. | |
* | |
* Its helpful to use this event to add in information for the end user such as | |
* how to access their services, where their code exsts or relevant credential info. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-info | |
* @example | |
* | |
* // Add urls to the app | |
* app.events.on('pre-info', function() { | |
* return getUrls(app); | |
* }); | |
*/ | |
return app.events.emit('pre-info') | |
// Return all the app info | |
.then(function() { | |
if (app && app.info) { | |
return app.info; | |
} | |
}); | |
}, uninstall=function (app) { | |
// Cleaning up | |
app.status('Uninstalling %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('uninstall', {app: app}) | |
/** | |
* Event that runs before an app is uninstalled. | |
* | |
* This is useful if you want to add or remove parts of the uninstall process. | |
* For example, it might be nice to persist a container whose data you do not | |
* want to replace in a rebuild and that cannot persist easily with a volume. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-uninstall | |
* @example | |
* | |
* // Do not uninstall the solr service | |
* app.events.on('pre-uninstall', function() { | |
* delete app.services.solr; | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-uninstall'); | |
}) | |
// Kill components. | |
.then(function() { | |
return lando.engine.destroy(app); | |
}) | |
/** | |
* Event that runs after an app is uninstalled. | |
* | |
* This is useful if you want to do some additional cleanup steps after an | |
* app is uninstalled such as invalidating any cached data. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-uninstall | |
* @example | |
* | |
* // Make sure we remove our build cache | |
* app.events.on('post-uninstall', function() { | |
* lando.cache.remove(app.name + ':last_build'); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-uninstall'); | |
}); | |
}, cleanup=function (app) { | |
// Cleaning up | |
app.status('Cleaning up app registry and containers'); | |
// Get all our containers | |
return _app.list({useCache: false}) | |
// We need to use the dockername | |
.map(function(app) { | |
return lando.utils.dockerComposify(app.name); | |
}) | |
// Filter out non-app containers | |
.then(function(apps) { | |
return Promise.filter(lando.engine.list(), function(container) { | |
return container.kind === 'app' && !_.includes(apps, container.app); | |
}); | |
}) | |
// Stop containers if needed | |
.tap(function(containers) { | |
return lando.engine.stop(containers); | |
}) | |
// Kill containers if needed | |
.tap(function(containers) { | |
return lando.engine.destroy(containers); | |
}); | |
}, start=function (app) { | |
// Start it up | |
app.status('Starting %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('start', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app starts up. | |
* | |
* This is useful if you want to start up any support services before an app | |
* stars. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-start | |
* @example | |
* | |
* // Start up a DNS server before our app starts | |
* app.events.on('pre-start', function() { | |
* return lando.engine.start(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-start'); | |
}) | |
// Start core containers | |
.then(function() { | |
return lando.engine.start(app); | |
}) | |
/** | |
* Event that runs after an app is started. | |
* | |
* This is useful if you want to perform additional operations after an app | |
* starts such as running additional build commands. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-start | |
* @example | |
* | |
* // Go through each service and run additional build commands as needed | |
* app.events.on('post-start', function() { | |
* | |
* // Start up a build collector | |
* var build = []; | |
* | |
* // Go through each service | |
* _.forEach(app.config.services, function(service, name) { | |
* | |
* // If the service has extras let's loop through and run some commands | |
* if (!_.isEmpty(service.extras)) { | |
* | |
* // Normalize data for loopage | |
* if (!_.isArray(service.extras)) { | |
* service.extras = [service.extras]; | |
* } | |
* | |
* // Run each command | |
* _.forEach(service.extras, function(cmd) { | |
* | |
* // Build out the compose object | |
* var compose = { | |
* id: [app.dockerName, name, '1'].join('_'), | |
* cmd: cmd, | |
* opts: { | |
* mode: 'attach' | |
* } | |
* }; | |
* | |
* // Push to the build | |
* build.push(compose); | |
* | |
* }); | |
* | |
* } | |
* | |
* }); | |
* | |
* // Only proceed if build is non-empty | |
* if (!_.isEmpty(build)) { | |
* | |
* // Get the last build cache key | |
* var key = app.name + ':last_build'; | |
* | |
* // Compute the build hash | |
* var newHash = lando.node.hasher(app.config.services); | |
* | |
* // If our new hash is different then lets build | |
* if (lando.cache.get(key) !== newHash) { | |
* | |
* // Set the new hash | |
* lando.cache.set(key, newHash, {persist:true}); | |
* | |
* // Run all our post build steps serially | |
* return lando.engine.run(build); | |
* | |
* } | |
* } | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-start'); | |
}); | |
}, stop=function (app) { | |
// Stop it! | |
app.status('Stopping %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('stop', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app stops. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-stop | |
* @example | |
* | |
* // Stop a DNS server before our app stops. | |
* app.events.on('pre-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-stop'); | |
}) | |
// Stop components. | |
.then(function() { | |
return lando.engine.stop(app); | |
}) | |
/** | |
* Event that runs after an app stop. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-stop | |
* @example | |
* | |
* // Stop a DNS server after our app stops. | |
* app.events.on('post-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-stop'); | |
}); | |
}, restart=function (app) { | |
// Start it off | |
app.status('Restarting %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
// Start app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, destroy=function (app) { | |
// Start it off | |
app.status('Destroying %s', app.name); | |
/** | |
* Event that runs before an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-destroy | |
* @example | |
* | |
* // Make sure the proxy is down before we destroy | |
* app.events.on('pre-destroy', function() { | |
* if (fs.existsSync(proxyFile)) { | |
* return lando.engine.stop(getProxy(proxyFile)); | |
* } | |
* }); | |
*/ | |
return app.events.emit('pre-destroy') | |
// Make sure app is stopped. | |
.then(function() { | |
return _app.stop(app); | |
}) | |
// Uninstall app. | |
.then(function() { | |
app.opts = _.merge(app.opts, {purge: true}); | |
return _app.uninstall(app); | |
}) | |
// Remove from appRegistry | |
.then(function() { | |
return registry.remove({name: app.name}); | |
}) | |
/** | |
* Event that runs after an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-destroy | |
* @example | |
* | |
* // Make sure the proxy is up brought back up after we destroy | |
* app.events.on('post-destroy', function() { | |
* return startProxy(); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-destroy'); | |
}); | |
}, rebuild=function (app) { | |
// Start it off | |
app.status('Rebuilding %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
/** | |
* Event that runs before an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-rebuild'); | |
}) | |
// Uninstall app | |
.then(function() { | |
return _app.uninstall(app); | |
}) | |
// Repull/build components. | |
.then(function() { | |
return lando.engine.build(app); | |
}) | |
/** | |
* Event that runs after an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-rebuild'); | |
}) | |
// Install app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, name=tomcat-demo, dockerName=tomcatdemo, name=tomcat-demo, recipe=custom, type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, version=latest, tomcat=[tomcat-demo.lndo.site:8080], _listeners=[name=app-ready, priority=5, fn=function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, name=app-ready, priority=9, fn=function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, name=app-ready, priority=9, fn=function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, name=app-ready, priority=5, fn=function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}, name=pre-info, priority=5, fn=function () { | |
return getUrls(app); | |
}, name=post-start, priority=1, fn=function () { | |
return getUrls(app); | |
}, name=pre-info, priority=1, fn=function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, name=post-uninstall, priority=5, fn=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, name=post-start, priority=5, fn=function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, name=post-start, priority=9, fn=function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, name=post-start, priority=5, fn=function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}, name=pre-info, priority=5, fn=function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}, name=pre-start, priority=1, fn=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, name=pre-terminus, priority=5, fn=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, name=post-destroy, priority=5, fn=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}], domain=null, app-ready=[function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}], pre-info=[function () { | |
return getUrls(app); | |
}, function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}], post-start=[function () { | |
return getUrls(app); | |
}, function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}], post-uninstall=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, pre-start=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, pre-terminus=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, post-destroy=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}, _eventsCount=7, _maxListeners=20, , root=/home/hpottinger/workspace/lando-tomcat, rootBind=/home/hpottinger/workspace/lando-tomcat, mount=/app, tasks=[command=config, describe=Display the lando configuration, run=function () { | |
console.log(JSON.stringify(lando.config, null, 2)); | |
}, name=config, command=destroy [appname], describe=Destroy app in current directory or [appname], describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to DESTROY?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('DESTRUCTION AVERTED!')); | |
return; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.destroy(app) | |
.then(function() { | |
console.log(chalk.red('App destroyed!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=destroy, command=info [appname], describe=Prints info about app in current directory or [appname], describe=Get ALL the info, alias=[d], default=false, boolean=true, run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// GEt the app info | |
.then(function(app) { | |
if (app) { | |
// If this is deep, go deep | |
if (options.deep) { | |
return lando.engine.list(app.name) | |
.each(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
console.log(JSON.stringify(data, null, 2)); | |
}); | |
}); | |
} | |
// Return the basic info | |
else { | |
return lando.app.info(app) | |
.then(function(info) { | |
console.log(JSON.stringify(info, null, 2)); | |
}); | |
} | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=info, command=list, describe=List all lando apps, run=function () { | |
// List all the apps | |
return lando.app.list() | |
// Map each app to a summary and print results | |
.map(function(app) { | |
return appSummary(app) | |
.then(function(summary) { | |
console.log(JSON.stringify(summary, null, 2)); | |
}); | |
}); | |
}, name=list, command=logs [appname], describe=Get logs for app in current directory or [appname], describe=Follow the logs, alias=[f], default=false, boolean=true, describe=Show logs for the specified services only, alias=[s], array=true, describe=Show log timestamps, alias=[t], default=false, boolean=true, run=function (options) { | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
// Add opts to our app | |
app.opts.follow = options.follow; | |
app.opts.timestamps = options.timestamps; | |
app.opts.services = options.services; | |
// Get the logs | |
return lando.engine.logs(app); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=logs, command=poweroff, describe=Spin down all lando related containers, run=function () { | |
// Start | |
console.log(chalk.yellow('Spinning containers down... Standby.')); | |
// Get all our apps | |
return lando.app.list() | |
// SHUT IT ALL DOWN | |
.map(function(app) { | |
return lando.app.get(app.name) | |
.then(function(app) { | |
lando.app.stop(app); | |
}); | |
}) | |
// Emit poweroff | |
.then(function() { | |
return lando.events.emit('poweroff'); | |
}) | |
// Finish up | |
.then(function() { | |
console.log(chalk.red('Lando containers have been spun down.')); | |
}); | |
}, name=poweroff, command=rebuild [appname], describe=Rebuilds app in current directory or [appname], describe=Rebuild only the specified services, alias=[s], array=true, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to rebuild?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('Rebuild aborted')); | |
return; | |
} | |
// Attempt to grab the app if we can | |
return lando.app.get(options.appname) | |
// Rebuild the app | |
.then(function(app) { | |
if (app) { | |
// Rebuild only particlar services if specified | |
if (!_.isEmpty(options.services)) { | |
app.opts.services = options.services; | |
} | |
return lando.app.rebuild(app) | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=rebuild, command=restart [appname], describe=Restarts app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Resttart the app | |
.then(function(app) { | |
if (app) { | |
// REstart the app | |
return lando.app.restart(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=restart, command=share [appname], describe=Get a publicly available url, describe=Url to share. Needs to be in the form http://localhost:port, alias=[u], required=true, run=function (options) { | |
// Do some validation of the url | |
var url = u.parse(options.url); | |
// Validate URL | |
var hnf = _.isEmpty(url.hostname) || url.hostname !== 'localhost'; | |
if (hnf || url.protocol !== 'http:') { | |
lando.log.error('Need a url of the form http://localhost:port!'); | |
lando.log.error('Run "lando info" for help finding the correct url!'); | |
process.exit(153); | |
} | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Get the sharing url | |
.then(function(app) { | |
if (app) { | |
// Start the app if needed | |
return lando.app.isRunning(app) | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Get the URLS | |
.then(function() { | |
// Assume a port to start | |
var port = 80; | |
// Override port if specified | |
if (!_.isEmpty(url.port)) { | |
port = url.port; | |
} | |
// Translate the app.name into a localtunnel suitable address | |
// eg lowercase/alphanumeric 4-63 chars | |
// lowercase and alphanumeric it | |
var tunnelHost = _.lowerCase(app.name).replace(/[^0-9a-z]/g, ''); | |
// Make sure we are at least 4 characters | |
if (_.size(tunnelHost) <= 4) { | |
tunnelHost = tunnelHost + 'xxxx'; | |
} | |
// Makes sure we are at most 64 chars | |
if (_.size(tunnelHost) >= 63) { | |
tunnelHost = tunnelHost.substring(0, 57); | |
} | |
// Build opts array | |
var opts = {subdomain: tunnelHost}; | |
// Set up the localtunnel | |
var tunnel = localtunnel(port, opts, function(err, tunnel) { | |
// Error if needed | |
if (err) { | |
lando.log.error(err); | |
} | |
// Header it | |
console.log(lando.cli.tunnelHeader()); | |
// the assigned public url for your tunnel | |
// i.e. https://abcdefgjhij.localtunnel.me | |
console.log(chalk.blue(tunnel.url)); | |
console.log(''); | |
console.log(chalk.yellow('Press any key to close the tunnel.')); | |
// Set stdin to the correct mode | |
process.stdin.resume(); | |
process.stdin.setEncoding('utf8'); | |
process.stdin.setRawMode(true); | |
// Start the keypress listener for the process | |
process.stdin.on('data', function() { | |
tunnel.close(); | |
}); | |
}); | |
tunnel.on('close', function() { | |
console.log(''); | |
console.log(chalk.green('Tunnel closed!')); | |
process.exit(0); | |
}); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=share, command=start [appname], describe=Start app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Start the app if we have one | |
.then(function(app) { | |
if (app) { | |
// Start the app | |
return lando.app.start(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=start, command=stop [appname], describe=Stops app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Restart the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.stop(app) | |
.then(function() { | |
console.log(chalk.red('App stopped!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=stop, command=version, describe=Display the lando version, run=function () { | |
console.log('v' + lando.config.version); | |
}, name=version, command=ssh [appname] [service], describe=SSH into [service] in current app directory or [appname], describe=Run a command in the service, alias=[c], describe=Run as a specific user, alias=[u], run=function (options) { | |
// Handle our options | |
if (!_.has(options, 'service') && _.has(options, 'appname')) { | |
options.service = options.appname; | |
options.appname = undefined; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Handle app or no app | |
.then(function(app) { | |
// We have an app so lets try to build a ssh exec | |
if (app) { | |
// Default to appserver if we have no second arg | |
var service = options.service || 'appserver'; | |
// Build out our run | |
var run = { | |
id: [app.dockerName, service, '1'].join('_'), | |
compose: app.compose, | |
project: app.name, | |
cmd: options.command || 'cd $LANDO_MOUNT && bash', | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: options.user || 'www-data', | |
services: [service] | |
} | |
}; | |
// Let's check to see if the app has been started | |
return lando.app.isRunning(app) | |
// If not let's make sure we start it | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Exec | |
.then(function() { | |
return lando.engine.run(run); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=ssh, command=init [method], describe=Initialize a lando app, optional methods: github, pantheon, describe=The recipe to use, choices=[custom, backdrop, drupal6, drupal7, drupal8, joomla, laravel, lamp, lemp, mean, pantheon, wordpress], alias=[r], string=true, type=list, message=What recipe do you want to use?, default=custom, choices=[name=custom, value=custom, name=backdrop, value=backdrop, name=drupal6, value=drupal6, name=drupal7, value=drupal7, name=drupal8, value=drupal8, name=joomla, value=joomla, name=laravel, value=laravel, name=lamp, value=lamp, name=lemp, value=lemp, name=mean, value=mean, name=pantheon, value=pantheon, name=wordpress, value=wordpress], weight=500, name=recipe, describe=GitHub token or email of previously used token, string=true, type=list, message=Choose a GitHub account, choices=[], when=function (answers) { | |
return !_.isEmpty(gitHubAccounts()) && askQuestions(answers); | |
}, weight=400, name=github-auth, name=github-auth, type=password, message=Enter a GitHub token, when=function (answers) { | |
var token = _.get(answers, 'github-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=401, describe=GitHub repo URL, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Repo collector | |
var repos = []; | |
// Spin things up | |
var tpath = 'github-auth'; | |
var token = _.get(lando.tasks.argv(), tpath, answers[tpath]); | |
var options = {affliation: 'owner,collaborator', 'per_page': 100}; | |
var done = this.async(); | |
// Check to see if token is cached already and use that | |
var tokens = lando.cache.get(tokenCacheKey) || {}; | |
if (_.includes(_.keys(tokens), token)) { | |
token = tokens[token]; | |
} | |
/* | |
* Helper to resursively load all our repos | |
*/ | |
var getAllRepos = function(err, res) { | |
// Error | |
if (err) { | |
lando.log.error('Problem getting sites from GitHub'); | |
} | |
// Add previous data to current | |
repos = repos.concat(res.data); | |
// IF we have more pages lets add them | |
if (github.hasNextPage(res)) { | |
github.getNextPage(res, getAllRepos); | |
} | |
// Otherwise lets send back our result | |
else { | |
done(null, _.map(repos, function(site) { | |
var name = _.get(site, 'full_name'); | |
var value = _.get(site, 'ssh_url'); | |
return {name: name, value: value}; | |
})); | |
} | |
}; | |
// Start the github authchain | |
github.authenticate({type: 'token', token: token}); | |
// Get all our sites | |
github.repos.getAll(options, getAllRepos); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=402, name=github-repo, describe=Pantheon machine token or email of previously used token, string=true, type=list, message=Choose a Pantheon account, choices=[], when=function (answers) { | |
return !_.isEmpty(pantheonAccounts()) && askQuestions(answers); | |
}, weight=600, name=pantheon-auth, name=pantheon-auth, type=password, message=Enter a Pantheon machine token, when=function (answers) { | |
var token = _.get(answers, 'pantheon-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=601, describe=Pantheon site machine name, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Token path | |
var tpath = 'pantheon-auth'; | |
// Make this async cause we need to hit the terminus | |
var done = this.async(); | |
// Get the pantheon sites using the token | |
api.getSites(_.get(lando.tasks.argv(), tpath, answers[tpath])) | |
// Parse the sites into choices | |
.map(function(site) { | |
return {name: site.name, value: site.name}; | |
}) | |
// Done | |
.then(function(sites) { | |
done(null, sites); | |
}); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=602, name=pantheon-site, describe=Specify where to init the app, alias=[dest, d], string=true, default=/home/hpottinger/workspace/lando-tomcat, describe=Specify the webroot relative to destination, string=true, type=input, message=Where is your webroot relative to the init destination?, default=., when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.webroot(recipe); | |
}, weight=900, name=webroot, describe=The name of the app, string=true, type=input, message=What do you want to call this app?, default=My Lando App, filter=function (value) { | |
if (value) { | |
return _.kebabCase(value); | |
} | |
}, when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.name(recipe); | |
}, weight=1000, name=name, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, run=function (options) { | |
// Set the basics | |
var config = { | |
name: options.name, | |
recipe: options.recipe, | |
}; | |
// If we have a webroot let's set it | |
if (!_.isEmpty(options.webroot)) { | |
_.set(config, 'config.webroot', options.webroot); | |
} | |
// Method specific build steps if applicable | |
return Promise.try(function() { | |
return lando.init.build(config.name, options.method, options); | |
}) | |
// Kill any build containers if needed | |
.then(function() { | |
return lando.init.kill(config.name, options.destination); | |
}) | |
// Check to see if our recipe provides additional yaml augment | |
.then(function() { | |
return lando.init.yaml(options.recipe, config, options); | |
}) | |
// Create the lando yml | |
.then(function(config) { | |
// Where are we going? | |
var dest = path.join(options.destination, '.lando.yml'); | |
// Rebase on top of any existing yaml | |
if (fs.existsSync(dest)) { | |
var pec = lando.yaml.load(dest); | |
config = _.mergeWith(pec, config, lando.utils.merger); | |
} | |
// Dump it | |
lando.yaml.dump(dest, config); | |
}) | |
// Tell the user things | |
.then(function() { | |
// Header it | |
console.log(lando.cli.initHeader()); | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Get docs link | |
var docBase = 'https://docs.devwithlando.io/tutorials/'; | |
var docUrl = docBase + config.recipe + '.html'; | |
// Add data | |
table.add('NAME', config.name); | |
table.add('RECIPE', options.recipe); | |
table.add('DOCS', docUrl); | |
// Add some other things if needed | |
if (!_.isEmpty(options.method)) { | |
table.add('METHOD', options.method); | |
} | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
}, name=init], webRoot=., status=function () { | |
var args = _.toArray(arguments); | |
var msg = util.format.apply(null, args); | |
return app.events.emit('status', msg) | |
// Make sure app status messages make it to global status. | |
.then(function() { | |
lando.log.info(msg); | |
}); | |
}, trollForStatus=function (msg) { | |
// Update status when pulling an image. | |
var images = msg.match(/Pulling from (.*)/); | |
if (images) { | |
app.status('Pulling image %s.', images[1]); | |
} | |
}, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, io.lando.container=TRUE, project=tomcat-demo, compose=[], image=tomcat:latest, ports=[8080], TERM=xterm, LANDO_WEBROOT=/app/./webapps, LANDO_SERVICE_NAME=tomcat, LANDO_SERVICE_TYPE=tomcat, LANDO_MOUNT=/app, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, volumes=[/home/hpottinger/.lando/services/config/tomcat/context.xml:/usr/local/tomcat/conf/context.xml, $LANDO_ENGINE_SCRIPTS_DIR/lando-entrypoint.sh:/lando-entrypoint.sh, $LANDO_APP_ROOT_BIND:/app, $LANDO_ENGINE_HOME:/user, $LANDO_ENGINE_SCRIPTS_DIR/user-perms.sh:/user-perms.sh, /home/hpottinger/.lando/services/config/scripts/load-keys.sh:/scripts/load-keys.sh, /home/hpottinger/.lando/services/config/helpers/mysql-import.sh:/helpers/mysql-import.sh, /home/hpottinger/.lando/services/config/helpers/mysql-export.sh:/helpers/mysql-export.sh], command=catalina.sh run, entrypoint=/lando-entrypoint.sh, io.lando.container=TRUE, , , mode=collect | |
verbose: Running spawn /usr/share/lando/bin/docker-compose with args ["--project-name","tomcat-demo","--file","/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml","rm","--force","-v"] | |
debug: In mode collect with detached false | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
Removing tomcatdemo_tomcat_1 ... done | |
debug: Collected output: Going to remove tomcatdemo_tomcat_1 | |
verbose: Spawn exited with code: 0 | |
silly: Spawn finished with Going to remove tomcatdemo_tomcat_1 | |
verbose: Emitting event post-engine-destroy | |
debug: Event post-engine-destroy has 0 listeners | |
verbose: Emitting event post-uninstall | |
debug: Event post-uninstall has 1 listeners | |
debug: No file cache with key tomcat-demo:last_build | |
debug: Retrieved from memcache with key engineUp | |
verbose: Emitting event pre-engine-build | |
debug: Event pre-engine-build has 0 listeners | |
debug: About to run 0=/usr/share/lando/bin/docker-compose, 1=--project-name, 2=tomcat-demo, 3=--file, 4=/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml, 5=pull | |
silly: With pre run opts list=function (opts) { | |
// Set opt defaults | |
opts = opts || {useCache: true}; | |
// Log | |
lando.log.verbose('Trying to get list of apps with opts', opts); | |
// Get list of app names. | |
return registry.getApps(opts) | |
// Validate list of apps, look for duplicates. | |
.then(function(apps) { | |
// Group apps by app names. | |
var groups = _.groupBy(apps, function(app) { | |
return app.name; | |
}); | |
// Find a set of duplicates. | |
var duplicates = _.find(groups, function(group) { | |
return group.length !== 1; | |
}); | |
// If a set of duplicates were found throw an error. | |
if (duplicates) { | |
throw new Error('Duplicate app names exist', duplicates); | |
} | |
// Pass the apps on to the each | |
return apps; | |
}); | |
}, get=function (appName) { | |
// If we have an appName lets try to match it with a diretory | |
return Promise.try(function() { | |
if (appName) { | |
return exports.list() | |
.then(function(apps) { | |
return _.find(apps, function(app) { | |
return app.name === appName || app.dockerName === appName; | |
}); | |
}); | |
} | |
}) | |
// Try to use a found app first if possible then default to the cwd | |
.then(function(app) { | |
return _.get(app, 'dir') || path.join(process.cwd()); | |
}) | |
// Return an app or warn the user there is no such app | |
.then(function(dir) { | |
// Split up our dir | |
var pieces = dir.split(path.sep); | |
// Go through all dir pieces | |
return _.map(pieces, function() { | |
// Build the dir | |
var dir = pieces.join(path.sep); | |
// Drop the last path for next iteration | |
pieces = _.dropRight(pieces); | |
// Return the possible location of lando files | |
return path.join(dir, lando.config.appConfigFilename); | |
}); | |
}) | |
// Return the first directory that has an app | |
.then(function(files) { | |
// Find the first directory that has a lando.yml | |
var configFile = _.find(files, function(file) { | |
lando.log.verbose('Checking for app config at %s', file); | |
return fs.existsSync(file); | |
}); | |
// If we have a config file let's load up the app | |
if (!_.isEmpty(configFile)) { | |
// TRy to load the config | |
var appConfig = lando.yaml.load(configFile); | |
// If we have appConfig then load the app | |
if (!_.isEmpty(appConfig)) { | |
return instantiate(appConfig.name, path.dirname(configFile), appConfig); | |
} | |
} | |
}); | |
}, isRunning=function (app, checkall) { | |
// Log | |
lando.log.verbose('Checking if %s is running', app.name); | |
// Clarify the checkall | |
checkall = checkall || false; | |
// Check if our engine is up | |
return lando.engine.isUp() | |
// If we are up check for containers running for an app | |
// otherwise return false | |
.then(function(isUp) { | |
// Engine is up so lets check if the app has running containers | |
if (isUp) { | |
// Get list of containers | |
return lando.engine.list(app.name) | |
// Filter out autostart containers since those will always report TRUE | |
.filter(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
return data.HostConfig.RestartPolicy.Name !== 'always'; | |
}); | |
}) | |
// Reduce containers to a true false running value | |
.reduce(function(isRunning, container) { | |
if (checkall) { | |
return isRunning && lando.engine.isRunning(container.id); | |
} | |
else { | |
return (isRunning) ? true : lando.engine.isRunning(container.id); | |
} | |
}, checkall); | |
} | |
// Engine is down so nothing can be running | |
else { | |
return false; | |
} | |
}); | |
}, exists=function (appName) { | |
// Get app. | |
return _app.get(appName) | |
// Return false if we get an app does not exist error. | |
.catch(function(err) { | |
if (_.contains(err.message, ' does not exist.')) { | |
return false; | |
} | |
else { | |
throw err; | |
} | |
}) | |
// Return true if app was returned. | |
.then(function(app) { | |
return !!app; | |
}); | |
}, info=function (app) { | |
/** | |
* Event that allows other things to add useful metadata to the apps services. | |
* | |
* Its helpful to use this event to add in information for the end user such as | |
* how to access their services, where their code exsts or relevant credential info. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-info | |
* @example | |
* | |
* // Add urls to the app | |
* app.events.on('pre-info', function() { | |
* return getUrls(app); | |
* }); | |
*/ | |
return app.events.emit('pre-info') | |
// Return all the app info | |
.then(function() { | |
if (app && app.info) { | |
return app.info; | |
} | |
}); | |
}, uninstall=function (app) { | |
// Cleaning up | |
app.status('Uninstalling %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('uninstall', {app: app}) | |
/** | |
* Event that runs before an app is uninstalled. | |
* | |
* This is useful if you want to add or remove parts of the uninstall process. | |
* For example, it might be nice to persist a container whose data you do not | |
* want to replace in a rebuild and that cannot persist easily with a volume. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-uninstall | |
* @example | |
* | |
* // Do not uninstall the solr service | |
* app.events.on('pre-uninstall', function() { | |
* delete app.services.solr; | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-uninstall'); | |
}) | |
// Kill components. | |
.then(function() { | |
return lando.engine.destroy(app); | |
}) | |
/** | |
* Event that runs after an app is uninstalled. | |
* | |
* This is useful if you want to do some additional cleanup steps after an | |
* app is uninstalled such as invalidating any cached data. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-uninstall | |
* @example | |
* | |
* // Make sure we remove our build cache | |
* app.events.on('post-uninstall', function() { | |
* lando.cache.remove(app.name + ':last_build'); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-uninstall'); | |
}); | |
}, cleanup=function (app) { | |
// Cleaning up | |
app.status('Cleaning up app registry and containers'); | |
// Get all our containers | |
return _app.list({useCache: false}) | |
// We need to use the dockername | |
.map(function(app) { | |
return lando.utils.dockerComposify(app.name); | |
}) | |
// Filter out non-app containers | |
.then(function(apps) { | |
return Promise.filter(lando.engine.list(), function(container) { | |
return container.kind === 'app' && !_.includes(apps, container.app); | |
}); | |
}) | |
// Stop containers if needed | |
.tap(function(containers) { | |
return lando.engine.stop(containers); | |
}) | |
// Kill containers if needed | |
.tap(function(containers) { | |
return lando.engine.destroy(containers); | |
}); | |
}, start=function (app) { | |
// Start it up | |
app.status('Starting %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('start', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app starts up. | |
* | |
* This is useful if you want to start up any support services before an app | |
* stars. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-start | |
* @example | |
* | |
* // Start up a DNS server before our app starts | |
* app.events.on('pre-start', function() { | |
* return lando.engine.start(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-start'); | |
}) | |
// Start core containers | |
.then(function() { | |
return lando.engine.start(app); | |
}) | |
/** | |
* Event that runs after an app is started. | |
* | |
* This is useful if you want to perform additional operations after an app | |
* starts such as running additional build commands. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-start | |
* @example | |
* | |
* // Go through each service and run additional build commands as needed | |
* app.events.on('post-start', function() { | |
* | |
* // Start up a build collector | |
* var build = []; | |
* | |
* // Go through each service | |
* _.forEach(app.config.services, function(service, name) { | |
* | |
* // If the service has extras let's loop through and run some commands | |
* if (!_.isEmpty(service.extras)) { | |
* | |
* // Normalize data for loopage | |
* if (!_.isArray(service.extras)) { | |
* service.extras = [service.extras]; | |
* } | |
* | |
* // Run each command | |
* _.forEach(service.extras, function(cmd) { | |
* | |
* // Build out the compose object | |
* var compose = { | |
* id: [app.dockerName, name, '1'].join('_'), | |
* cmd: cmd, | |
* opts: { | |
* mode: 'attach' | |
* } | |
* }; | |
* | |
* // Push to the build | |
* build.push(compose); | |
* | |
* }); | |
* | |
* } | |
* | |
* }); | |
* | |
* // Only proceed if build is non-empty | |
* if (!_.isEmpty(build)) { | |
* | |
* // Get the last build cache key | |
* var key = app.name + ':last_build'; | |
* | |
* // Compute the build hash | |
* var newHash = lando.node.hasher(app.config.services); | |
* | |
* // If our new hash is different then lets build | |
* if (lando.cache.get(key) !== newHash) { | |
* | |
* // Set the new hash | |
* lando.cache.set(key, newHash, {persist:true}); | |
* | |
* // Run all our post build steps serially | |
* return lando.engine.run(build); | |
* | |
* } | |
* } | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-start'); | |
}); | |
}, stop=function (app) { | |
// Stop it! | |
app.status('Stopping %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('stop', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app stops. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-stop | |
* @example | |
* | |
* // Stop a DNS server before our app stops. | |
* app.events.on('pre-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-stop'); | |
}) | |
// Stop components. | |
.then(function() { | |
return lando.engine.stop(app); | |
}) | |
/** | |
* Event that runs after an app stop. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-stop | |
* @example | |
* | |
* // Stop a DNS server after our app stops. | |
* app.events.on('post-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-stop'); | |
}); | |
}, restart=function (app) { | |
// Start it off | |
app.status('Restarting %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
// Start app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, destroy=function (app) { | |
// Start it off | |
app.status('Destroying %s', app.name); | |
/** | |
* Event that runs before an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-destroy | |
* @example | |
* | |
* // Make sure the proxy is down before we destroy | |
* app.events.on('pre-destroy', function() { | |
* if (fs.existsSync(proxyFile)) { | |
* return lando.engine.stop(getProxy(proxyFile)); | |
* } | |
* }); | |
*/ | |
return app.events.emit('pre-destroy') | |
// Make sure app is stopped. | |
.then(function() { | |
return _app.stop(app); | |
}) | |
// Uninstall app. | |
.then(function() { | |
app.opts = _.merge(app.opts, {purge: true}); | |
return _app.uninstall(app); | |
}) | |
// Remove from appRegistry | |
.then(function() { | |
return registry.remove({name: app.name}); | |
}) | |
/** | |
* Event that runs after an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-destroy | |
* @example | |
* | |
* // Make sure the proxy is up brought back up after we destroy | |
* app.events.on('post-destroy', function() { | |
* return startProxy(); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-destroy'); | |
}); | |
}, rebuild=function (app) { | |
// Start it off | |
app.status('Rebuilding %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
/** | |
* Event that runs before an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-rebuild'); | |
}) | |
// Uninstall app | |
.then(function() { | |
return _app.uninstall(app); | |
}) | |
// Repull/build components. | |
.then(function() { | |
return lando.engine.build(app); | |
}) | |
/** | |
* Event that runs after an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-rebuild'); | |
}) | |
// Install app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, name=tomcat-demo, dockerName=tomcatdemo, name=tomcat-demo, recipe=custom, type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, version=latest, tomcat=[tomcat-demo.lndo.site:8080], _listeners=[name=app-ready, priority=5, fn=function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, name=app-ready, priority=9, fn=function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, name=app-ready, priority=9, fn=function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, name=app-ready, priority=5, fn=function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}, name=pre-info, priority=5, fn=function () { | |
return getUrls(app); | |
}, name=post-start, priority=1, fn=function () { | |
return getUrls(app); | |
}, name=pre-info, priority=1, fn=function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, name=post-uninstall, priority=5, fn=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, name=post-start, priority=5, fn=function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, name=post-start, priority=9, fn=function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, name=post-start, priority=5, fn=function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}, name=pre-info, priority=5, fn=function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}, name=pre-start, priority=1, fn=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, name=pre-terminus, priority=5, fn=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, name=post-destroy, priority=5, fn=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}], domain=null, app-ready=[function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}], pre-info=[function () { | |
return getUrls(app); | |
}, function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}], post-start=[function () { | |
return getUrls(app); | |
}, function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}], post-uninstall=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, pre-start=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, pre-terminus=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, post-destroy=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}, _eventsCount=7, _maxListeners=20, , root=/home/hpottinger/workspace/lando-tomcat, rootBind=/home/hpottinger/workspace/lando-tomcat, mount=/app, tasks=[command=config, describe=Display the lando configuration, run=function () { | |
console.log(JSON.stringify(lando.config, null, 2)); | |
}, name=config, command=destroy [appname], describe=Destroy app in current directory or [appname], describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to DESTROY?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('DESTRUCTION AVERTED!')); | |
return; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.destroy(app) | |
.then(function() { | |
console.log(chalk.red('App destroyed!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=destroy, command=info [appname], describe=Prints info about app in current directory or [appname], describe=Get ALL the info, alias=[d], default=false, boolean=true, run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// GEt the app info | |
.then(function(app) { | |
if (app) { | |
// If this is deep, go deep | |
if (options.deep) { | |
return lando.engine.list(app.name) | |
.each(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
console.log(JSON.stringify(data, null, 2)); | |
}); | |
}); | |
} | |
// Return the basic info | |
else { | |
return lando.app.info(app) | |
.then(function(info) { | |
console.log(JSON.stringify(info, null, 2)); | |
}); | |
} | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=info, command=list, describe=List all lando apps, run=function () { | |
// List all the apps | |
return lando.app.list() | |
// Map each app to a summary and print results | |
.map(function(app) { | |
return appSummary(app) | |
.then(function(summary) { | |
console.log(JSON.stringify(summary, null, 2)); | |
}); | |
}); | |
}, name=list, command=logs [appname], describe=Get logs for app in current directory or [appname], describe=Follow the logs, alias=[f], default=false, boolean=true, describe=Show logs for the specified services only, alias=[s], array=true, describe=Show log timestamps, alias=[t], default=false, boolean=true, run=function (options) { | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
// Add opts to our app | |
app.opts.follow = options.follow; | |
app.opts.timestamps = options.timestamps; | |
app.opts.services = options.services; | |
// Get the logs | |
return lando.engine.logs(app); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=logs, command=poweroff, describe=Spin down all lando related containers, run=function () { | |
// Start | |
console.log(chalk.yellow('Spinning containers down... Standby.')); | |
// Get all our apps | |
return lando.app.list() | |
// SHUT IT ALL DOWN | |
.map(function(app) { | |
return lando.app.get(app.name) | |
.then(function(app) { | |
lando.app.stop(app); | |
}); | |
}) | |
// Emit poweroff | |
.then(function() { | |
return lando.events.emit('poweroff'); | |
}) | |
// Finish up | |
.then(function() { | |
console.log(chalk.red('Lando containers have been spun down.')); | |
}); | |
}, name=poweroff, command=rebuild [appname], describe=Rebuilds app in current directory or [appname], describe=Rebuild only the specified services, alias=[s], array=true, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to rebuild?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('Rebuild aborted')); | |
return; | |
} | |
// Attempt to grab the app if we can | |
return lando.app.get(options.appname) | |
// Rebuild the app | |
.then(function(app) { | |
if (app) { | |
// Rebuild only particlar services if specified | |
if (!_.isEmpty(options.services)) { | |
app.opts.services = options.services; | |
} | |
return lando.app.rebuild(app) | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=rebuild, command=restart [appname], describe=Restarts app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Resttart the app | |
.then(function(app) { | |
if (app) { | |
// REstart the app | |
return lando.app.restart(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=restart, command=share [appname], describe=Get a publicly available url, describe=Url to share. Needs to be in the form http://localhost:port, alias=[u], required=true, run=function (options) { | |
// Do some validation of the url | |
var url = u.parse(options.url); | |
// Validate URL | |
var hnf = _.isEmpty(url.hostname) || url.hostname !== 'localhost'; | |
if (hnf || url.protocol !== 'http:') { | |
lando.log.error('Need a url of the form http://localhost:port!'); | |
lando.log.error('Run "lando info" for help finding the correct url!'); | |
process.exit(153); | |
} | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Get the sharing url | |
.then(function(app) { | |
if (app) { | |
// Start the app if needed | |
return lando.app.isRunning(app) | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Get the URLS | |
.then(function() { | |
// Assume a port to start | |
var port = 80; | |
// Override port if specified | |
if (!_.isEmpty(url.port)) { | |
port = url.port; | |
} | |
// Translate the app.name into a localtunnel suitable address | |
// eg lowercase/alphanumeric 4-63 chars | |
// lowercase and alphanumeric it | |
var tunnelHost = _.lowerCase(app.name).replace(/[^0-9a-z]/g, ''); | |
// Make sure we are at least 4 characters | |
if (_.size(tunnelHost) <= 4) { | |
tunnelHost = tunnelHost + 'xxxx'; | |
} | |
// Makes sure we are at most 64 chars | |
if (_.size(tunnelHost) >= 63) { | |
tunnelHost = tunnelHost.substring(0, 57); | |
} | |
// Build opts array | |
var opts = {subdomain: tunnelHost}; | |
// Set up the localtunnel | |
var tunnel = localtunnel(port, opts, function(err, tunnel) { | |
// Error if needed | |
if (err) { | |
lando.log.error(err); | |
} | |
// Header it | |
console.log(lando.cli.tunnelHeader()); | |
// the assigned public url for your tunnel | |
// i.e. https://abcdefgjhij.localtunnel.me | |
console.log(chalk.blue(tunnel.url)); | |
console.log(''); | |
console.log(chalk.yellow('Press any key to close the tunnel.')); | |
// Set stdin to the correct mode | |
process.stdin.resume(); | |
process.stdin.setEncoding('utf8'); | |
process.stdin.setRawMode(true); | |
// Start the keypress listener for the process | |
process.stdin.on('data', function() { | |
tunnel.close(); | |
}); | |
}); | |
tunnel.on('close', function() { | |
console.log(''); | |
console.log(chalk.green('Tunnel closed!')); | |
process.exit(0); | |
}); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=share, command=start [appname], describe=Start app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Start the app if we have one | |
.then(function(app) { | |
if (app) { | |
// Start the app | |
return lando.app.start(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=start, command=stop [appname], describe=Stops app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Restart the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.stop(app) | |
.then(function() { | |
console.log(chalk.red('App stopped!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=stop, command=version, describe=Display the lando version, run=function () { | |
console.log('v' + lando.config.version); | |
}, name=version, command=ssh [appname] [service], describe=SSH into [service] in current app directory or [appname], describe=Run a command in the service, alias=[c], describe=Run as a specific user, alias=[u], run=function (options) { | |
// Handle our options | |
if (!_.has(options, 'service') && _.has(options, 'appname')) { | |
options.service = options.appname; | |
options.appname = undefined; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Handle app or no app | |
.then(function(app) { | |
// We have an app so lets try to build a ssh exec | |
if (app) { | |
// Default to appserver if we have no second arg | |
var service = options.service || 'appserver'; | |
// Build out our run | |
var run = { | |
id: [app.dockerName, service, '1'].join('_'), | |
compose: app.compose, | |
project: app.name, | |
cmd: options.command || 'cd $LANDO_MOUNT && bash', | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: options.user || 'www-data', | |
services: [service] | |
} | |
}; | |
// Let's check to see if the app has been started | |
return lando.app.isRunning(app) | |
// If not let's make sure we start it | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Exec | |
.then(function() { | |
return lando.engine.run(run); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=ssh, command=init [method], describe=Initialize a lando app, optional methods: github, pantheon, describe=The recipe to use, choices=[custom, backdrop, drupal6, drupal7, drupal8, joomla, laravel, lamp, lemp, mean, pantheon, wordpress], alias=[r], string=true, type=list, message=What recipe do you want to use?, default=custom, choices=[name=custom, value=custom, name=backdrop, value=backdrop, name=drupal6, value=drupal6, name=drupal7, value=drupal7, name=drupal8, value=drupal8, name=joomla, value=joomla, name=laravel, value=laravel, name=lamp, value=lamp, name=lemp, value=lemp, name=mean, value=mean, name=pantheon, value=pantheon, name=wordpress, value=wordpress], weight=500, name=recipe, describe=GitHub token or email of previously used token, string=true, type=list, message=Choose a GitHub account, choices=[], when=function (answers) { | |
return !_.isEmpty(gitHubAccounts()) && askQuestions(answers); | |
}, weight=400, name=github-auth, name=github-auth, type=password, message=Enter a GitHub token, when=function (answers) { | |
var token = _.get(answers, 'github-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=401, describe=GitHub repo URL, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Repo collector | |
var repos = []; | |
// Spin things up | |
var tpath = 'github-auth'; | |
var token = _.get(lando.tasks.argv(), tpath, answers[tpath]); | |
var options = {affliation: 'owner,collaborator', 'per_page': 100}; | |
var done = this.async(); | |
// Check to see if token is cached already and use that | |
var tokens = lando.cache.get(tokenCacheKey) || {}; | |
if (_.includes(_.keys(tokens), token)) { | |
token = tokens[token]; | |
} | |
/* | |
* Helper to resursively load all our repos | |
*/ | |
var getAllRepos = function(err, res) { | |
// Error | |
if (err) { | |
lando.log.error('Problem getting sites from GitHub'); | |
} | |
// Add previous data to current | |
repos = repos.concat(res.data); | |
// IF we have more pages lets add them | |
if (github.hasNextPage(res)) { | |
github.getNextPage(res, getAllRepos); | |
} | |
// Otherwise lets send back our result | |
else { | |
done(null, _.map(repos, function(site) { | |
var name = _.get(site, 'full_name'); | |
var value = _.get(site, 'ssh_url'); | |
return {name: name, value: value}; | |
})); | |
} | |
}; | |
// Start the github authchain | |
github.authenticate({type: 'token', token: token}); | |
// Get all our sites | |
github.repos.getAll(options, getAllRepos); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=402, name=github-repo, describe=Pantheon machine token or email of previously used token, string=true, type=list, message=Choose a Pantheon account, choices=[], when=function (answers) { | |
return !_.isEmpty(pantheonAccounts()) && askQuestions(answers); | |
}, weight=600, name=pantheon-auth, name=pantheon-auth, type=password, message=Enter a Pantheon machine token, when=function (answers) { | |
var token = _.get(answers, 'pantheon-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=601, describe=Pantheon site machine name, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Token path | |
var tpath = 'pantheon-auth'; | |
// Make this async cause we need to hit the terminus | |
var done = this.async(); | |
// Get the pantheon sites using the token | |
api.getSites(_.get(lando.tasks.argv(), tpath, answers[tpath])) | |
// Parse the sites into choices | |
.map(function(site) { | |
return {name: site.name, value: site.name}; | |
}) | |
// Done | |
.then(function(sites) { | |
done(null, sites); | |
}); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=602, name=pantheon-site, describe=Specify where to init the app, alias=[dest, d], string=true, default=/home/hpottinger/workspace/lando-tomcat, describe=Specify the webroot relative to destination, string=true, type=input, message=Where is your webroot relative to the init destination?, default=., when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.webroot(recipe); | |
}, weight=900, name=webroot, describe=The name of the app, string=true, type=input, message=What do you want to call this app?, default=My Lando App, filter=function (value) { | |
if (value) { | |
return _.kebabCase(value); | |
} | |
}, when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.name(recipe); | |
}, weight=1000, name=name, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, run=function (options) { | |
// Set the basics | |
var config = { | |
name: options.name, | |
recipe: options.recipe, | |
}; | |
// If we have a webroot let's set it | |
if (!_.isEmpty(options.webroot)) { | |
_.set(config, 'config.webroot', options.webroot); | |
} | |
// Method specific build steps if applicable | |
return Promise.try(function() { | |
return lando.init.build(config.name, options.method, options); | |
}) | |
// Kill any build containers if needed | |
.then(function() { | |
return lando.init.kill(config.name, options.destination); | |
}) | |
// Check to see if our recipe provides additional yaml augment | |
.then(function() { | |
return lando.init.yaml(options.recipe, config, options); | |
}) | |
// Create the lando yml | |
.then(function(config) { | |
// Where are we going? | |
var dest = path.join(options.destination, '.lando.yml'); | |
// Rebase on top of any existing yaml | |
if (fs.existsSync(dest)) { | |
var pec = lando.yaml.load(dest); | |
config = _.mergeWith(pec, config, lando.utils.merger); | |
} | |
// Dump it | |
lando.yaml.dump(dest, config); | |
}) | |
// Tell the user things | |
.then(function() { | |
// Header it | |
console.log(lando.cli.initHeader()); | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Get docs link | |
var docBase = 'https://docs.devwithlando.io/tutorials/'; | |
var docUrl = docBase + config.recipe + '.html'; | |
// Add data | |
table.add('NAME', config.name); | |
table.add('RECIPE', options.recipe); | |
table.add('DOCS', docUrl); | |
// Add some other things if needed | |
if (!_.isEmpty(options.method)) { | |
table.add('METHOD', options.method); | |
} | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
}, name=init], webRoot=., status=function () { | |
var args = _.toArray(arguments); | |
var msg = util.format.apply(null, args); | |
return app.events.emit('status', msg) | |
// Make sure app status messages make it to global status. | |
.then(function() { | |
lando.log.info(msg); | |
}); | |
}, trollForStatus=function (msg) { | |
// Update status when pulling an image. | |
var images = msg.match(/Pulling from (.*)/); | |
if (images) { | |
app.status('Pulling image %s.', images[1]); | |
} | |
}, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, io.lando.container=TRUE, project=tomcat-demo, compose=[], image=tomcat:latest, ports=[8080], TERM=xterm, LANDO_WEBROOT=/app/./webapps, LANDO_SERVICE_NAME=tomcat, LANDO_SERVICE_TYPE=tomcat, LANDO_MOUNT=/app, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, volumes=[/home/hpottinger/.lando/services/config/tomcat/context.xml:/usr/local/tomcat/conf/context.xml, $LANDO_ENGINE_SCRIPTS_DIR/lando-entrypoint.sh:/lando-entrypoint.sh, $LANDO_APP_ROOT_BIND:/app, $LANDO_ENGINE_HOME:/user, $LANDO_ENGINE_SCRIPTS_DIR/user-perms.sh:/user-perms.sh, /home/hpottinger/.lando/services/config/scripts/load-keys.sh:/scripts/load-keys.sh, /home/hpottinger/.lando/services/config/helpers/mysql-import.sh:/helpers/mysql-import.sh, /home/hpottinger/.lando/services/config/helpers/mysql-export.sh:/helpers/mysql-export.sh], command=catalina.sh run, entrypoint=/lando-entrypoint.sh, io.lando.container=TRUE, , , mode=collect | |
verbose: Running spawn /usr/share/lando/bin/docker-compose with args ["--project-name","tomcat-demo","--file","/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml","pull"] | |
debug: In mode collect with detached false | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
Pulling tomcat (tomcat:latest)... | |
debug: Collected output: latest: Pulling from library/tomcat | |
verbose: Emitting event status | |
debug: Event status has 0 listeners | |
info: Pulling image library/tomcat. | |
debug: Collected output: Digest: sha256:4b6c1405af51a2fde824358de18cdb83457d1b4dc1cbfaac767cc0875fd25a41 | |
debug: Collected output: Status: Image is up to date for tomcat:latest | |
verbose: Spawn exited with code: 0 | |
silly: Spawn finished with latest: Pulling from library/tomcat | |
Digest: sha256:4b6c1405af51a2fde824358de18cdb83457d1b4dc1cbfaac767cc0875fd25a41 | |
Status: Image is up to date for tomcat:latest | |
debug: About to run 0=/usr/share/lando/bin/docker-compose, 1=--project-name, 2=tomcat-demo, 3=--file, 4=/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml, 5=build, 6=--no-cache, 7=--pull | |
silly: With pre run opts list=function (opts) { | |
// Set opt defaults | |
opts = opts || {useCache: true}; | |
// Log | |
lando.log.verbose('Trying to get list of apps with opts', opts); | |
// Get list of app names. | |
return registry.getApps(opts) | |
// Validate list of apps, look for duplicates. | |
.then(function(apps) { | |
// Group apps by app names. | |
var groups = _.groupBy(apps, function(app) { | |
return app.name; | |
}); | |
// Find a set of duplicates. | |
var duplicates = _.find(groups, function(group) { | |
return group.length !== 1; | |
}); | |
// If a set of duplicates were found throw an error. | |
if (duplicates) { | |
throw new Error('Duplicate app names exist', duplicates); | |
} | |
// Pass the apps on to the each | |
return apps; | |
}); | |
}, get=function (appName) { | |
// If we have an appName lets try to match it with a diretory | |
return Promise.try(function() { | |
if (appName) { | |
return exports.list() | |
.then(function(apps) { | |
return _.find(apps, function(app) { | |
return app.name === appName || app.dockerName === appName; | |
}); | |
}); | |
} | |
}) | |
// Try to use a found app first if possible then default to the cwd | |
.then(function(app) { | |
return _.get(app, 'dir') || path.join(process.cwd()); | |
}) | |
// Return an app or warn the user there is no such app | |
.then(function(dir) { | |
// Split up our dir | |
var pieces = dir.split(path.sep); | |
// Go through all dir pieces | |
return _.map(pieces, function() { | |
// Build the dir | |
var dir = pieces.join(path.sep); | |
// Drop the last path for next iteration | |
pieces = _.dropRight(pieces); | |
// Return the possible location of lando files | |
return path.join(dir, lando.config.appConfigFilename); | |
}); | |
}) | |
// Return the first directory that has an app | |
.then(function(files) { | |
// Find the first directory that has a lando.yml | |
var configFile = _.find(files, function(file) { | |
lando.log.verbose('Checking for app config at %s', file); | |
return fs.existsSync(file); | |
}); | |
// If we have a config file let's load up the app | |
if (!_.isEmpty(configFile)) { | |
// TRy to load the config | |
var appConfig = lando.yaml.load(configFile); | |
// If we have appConfig then load the app | |
if (!_.isEmpty(appConfig)) { | |
return instantiate(appConfig.name, path.dirname(configFile), appConfig); | |
} | |
} | |
}); | |
}, isRunning=function (app, checkall) { | |
// Log | |
lando.log.verbose('Checking if %s is running', app.name); | |
// Clarify the checkall | |
checkall = checkall || false; | |
// Check if our engine is up | |
return lando.engine.isUp() | |
// If we are up check for containers running for an app | |
// otherwise return false | |
.then(function(isUp) { | |
// Engine is up so lets check if the app has running containers | |
if (isUp) { | |
// Get list of containers | |
return lando.engine.list(app.name) | |
// Filter out autostart containers since those will always report TRUE | |
.filter(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
return data.HostConfig.RestartPolicy.Name !== 'always'; | |
}); | |
}) | |
// Reduce containers to a true false running value | |
.reduce(function(isRunning, container) { | |
if (checkall) { | |
return isRunning && lando.engine.isRunning(container.id); | |
} | |
else { | |
return (isRunning) ? true : lando.engine.isRunning(container.id); | |
} | |
}, checkall); | |
} | |
// Engine is down so nothing can be running | |
else { | |
return false; | |
} | |
}); | |
}, exists=function (appName) { | |
// Get app. | |
return _app.get(appName) | |
// Return false if we get an app does not exist error. | |
.catch(function(err) { | |
if (_.contains(err.message, ' does not exist.')) { | |
return false; | |
} | |
else { | |
throw err; | |
} | |
}) | |
// Return true if app was returned. | |
.then(function(app) { | |
return !!app; | |
}); | |
}, info=function (app) { | |
/** | |
* Event that allows other things to add useful metadata to the apps services. | |
* | |
* Its helpful to use this event to add in information for the end user such as | |
* how to access their services, where their code exsts or relevant credential info. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-info | |
* @example | |
* | |
* // Add urls to the app | |
* app.events.on('pre-info', function() { | |
* return getUrls(app); | |
* }); | |
*/ | |
return app.events.emit('pre-info') | |
// Return all the app info | |
.then(function() { | |
if (app && app.info) { | |
return app.info; | |
} | |
}); | |
}, uninstall=function (app) { | |
// Cleaning up | |
app.status('Uninstalling %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('uninstall', {app: app}) | |
/** | |
* Event that runs before an app is uninstalled. | |
* | |
* This is useful if you want to add or remove parts of the uninstall process. | |
* For example, it might be nice to persist a container whose data you do not | |
* want to replace in a rebuild and that cannot persist easily with a volume. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-uninstall | |
* @example | |
* | |
* // Do not uninstall the solr service | |
* app.events.on('pre-uninstall', function() { | |
* delete app.services.solr; | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-uninstall'); | |
}) | |
// Kill components. | |
.then(function() { | |
return lando.engine.destroy(app); | |
}) | |
/** | |
* Event that runs after an app is uninstalled. | |
* | |
* This is useful if you want to do some additional cleanup steps after an | |
* app is uninstalled such as invalidating any cached data. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-uninstall | |
* @example | |
* | |
* // Make sure we remove our build cache | |
* app.events.on('post-uninstall', function() { | |
* lando.cache.remove(app.name + ':last_build'); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-uninstall'); | |
}); | |
}, cleanup=function (app) { | |
// Cleaning up | |
app.status('Cleaning up app registry and containers'); | |
// Get all our containers | |
return _app.list({useCache: false}) | |
// We need to use the dockername | |
.map(function(app) { | |
return lando.utils.dockerComposify(app.name); | |
}) | |
// Filter out non-app containers | |
.then(function(apps) { | |
return Promise.filter(lando.engine.list(), function(container) { | |
return container.kind === 'app' && !_.includes(apps, container.app); | |
}); | |
}) | |
// Stop containers if needed | |
.tap(function(containers) { | |
return lando.engine.stop(containers); | |
}) | |
// Kill containers if needed | |
.tap(function(containers) { | |
return lando.engine.destroy(containers); | |
}); | |
}, start=function (app) { | |
// Start it up | |
app.status('Starting %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('start', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app starts up. | |
* | |
* This is useful if you want to start up any support services before an app | |
* stars. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-start | |
* @example | |
* | |
* // Start up a DNS server before our app starts | |
* app.events.on('pre-start', function() { | |
* return lando.engine.start(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-start'); | |
}) | |
// Start core containers | |
.then(function() { | |
return lando.engine.start(app); | |
}) | |
/** | |
* Event that runs after an app is started. | |
* | |
* This is useful if you want to perform additional operations after an app | |
* starts such as running additional build commands. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-start | |
* @example | |
* | |
* // Go through each service and run additional build commands as needed | |
* app.events.on('post-start', function() { | |
* | |
* // Start up a build collector | |
* var build = []; | |
* | |
* // Go through each service | |
* _.forEach(app.config.services, function(service, name) { | |
* | |
* // If the service has extras let's loop through and run some commands | |
* if (!_.isEmpty(service.extras)) { | |
* | |
* // Normalize data for loopage | |
* if (!_.isArray(service.extras)) { | |
* service.extras = [service.extras]; | |
* } | |
* | |
* // Run each command | |
* _.forEach(service.extras, function(cmd) { | |
* | |
* // Build out the compose object | |
* var compose = { | |
* id: [app.dockerName, name, '1'].join('_'), | |
* cmd: cmd, | |
* opts: { | |
* mode: 'attach' | |
* } | |
* }; | |
* | |
* // Push to the build | |
* build.push(compose); | |
* | |
* }); | |
* | |
* } | |
* | |
* }); | |
* | |
* // Only proceed if build is non-empty | |
* if (!_.isEmpty(build)) { | |
* | |
* // Get the last build cache key | |
* var key = app.name + ':last_build'; | |
* | |
* // Compute the build hash | |
* var newHash = lando.node.hasher(app.config.services); | |
* | |
* // If our new hash is different then lets build | |
* if (lando.cache.get(key) !== newHash) { | |
* | |
* // Set the new hash | |
* lando.cache.set(key, newHash, {persist:true}); | |
* | |
* // Run all our post build steps serially | |
* return lando.engine.run(build); | |
* | |
* } | |
* } | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-start'); | |
}); | |
}, stop=function (app) { | |
// Stop it! | |
app.status('Stopping %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('stop', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app stops. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-stop | |
* @example | |
* | |
* // Stop a DNS server before our app stops. | |
* app.events.on('pre-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-stop'); | |
}) | |
// Stop components. | |
.then(function() { | |
return lando.engine.stop(app); | |
}) | |
/** | |
* Event that runs after an app stop. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-stop | |
* @example | |
* | |
* // Stop a DNS server after our app stops. | |
* app.events.on('post-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-stop'); | |
}); | |
}, restart=function (app) { | |
// Start it off | |
app.status('Restarting %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
// Start app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, destroy=function (app) { | |
// Start it off | |
app.status('Destroying %s', app.name); | |
/** | |
* Event that runs before an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-destroy | |
* @example | |
* | |
* // Make sure the proxy is down before we destroy | |
* app.events.on('pre-destroy', function() { | |
* if (fs.existsSync(proxyFile)) { | |
* return lando.engine.stop(getProxy(proxyFile)); | |
* } | |
* }); | |
*/ | |
return app.events.emit('pre-destroy') | |
// Make sure app is stopped. | |
.then(function() { | |
return _app.stop(app); | |
}) | |
// Uninstall app. | |
.then(function() { | |
app.opts = _.merge(app.opts, {purge: true}); | |
return _app.uninstall(app); | |
}) | |
// Remove from appRegistry | |
.then(function() { | |
return registry.remove({name: app.name}); | |
}) | |
/** | |
* Event that runs after an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-destroy | |
* @example | |
* | |
* // Make sure the proxy is up brought back up after we destroy | |
* app.events.on('post-destroy', function() { | |
* return startProxy(); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-destroy'); | |
}); | |
}, rebuild=function (app) { | |
// Start it off | |
app.status('Rebuilding %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
/** | |
* Event that runs before an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-rebuild'); | |
}) | |
// Uninstall app | |
.then(function() { | |
return _app.uninstall(app); | |
}) | |
// Repull/build components. | |
.then(function() { | |
return lando.engine.build(app); | |
}) | |
/** | |
* Event that runs after an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-rebuild'); | |
}) | |
// Install app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, name=tomcat-demo, dockerName=tomcatdemo, name=tomcat-demo, recipe=custom, type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, version=latest, tomcat=[tomcat-demo.lndo.site:8080], _listeners=[name=app-ready, priority=5, fn=function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, name=app-ready, priority=9, fn=function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, name=app-ready, priority=9, fn=function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, name=app-ready, priority=5, fn=function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}, name=pre-info, priority=5, fn=function () { | |
return getUrls(app); | |
}, name=post-start, priority=1, fn=function () { | |
return getUrls(app); | |
}, name=pre-info, priority=1, fn=function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, name=post-uninstall, priority=5, fn=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, name=post-start, priority=5, fn=function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, name=post-start, priority=9, fn=function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, name=post-start, priority=5, fn=function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}, name=pre-info, priority=5, fn=function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}, name=pre-start, priority=1, fn=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, name=pre-terminus, priority=5, fn=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, name=post-destroy, priority=5, fn=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}], domain=null, app-ready=[function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}], pre-info=[function () { | |
return getUrls(app); | |
}, function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}], post-start=[function () { | |
return getUrls(app); | |
}, function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}], post-uninstall=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, pre-start=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, pre-terminus=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, post-destroy=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}, _eventsCount=7, _maxListeners=20, , root=/home/hpottinger/workspace/lando-tomcat, rootBind=/home/hpottinger/workspace/lando-tomcat, mount=/app, tasks=[command=config, describe=Display the lando configuration, run=function () { | |
console.log(JSON.stringify(lando.config, null, 2)); | |
}, name=config, command=destroy [appname], describe=Destroy app in current directory or [appname], describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to DESTROY?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('DESTRUCTION AVERTED!')); | |
return; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.destroy(app) | |
.then(function() { | |
console.log(chalk.red('App destroyed!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=destroy, command=info [appname], describe=Prints info about app in current directory or [appname], describe=Get ALL the info, alias=[d], default=false, boolean=true, run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// GEt the app info | |
.then(function(app) { | |
if (app) { | |
// If this is deep, go deep | |
if (options.deep) { | |
return lando.engine.list(app.name) | |
.each(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
console.log(JSON.stringify(data, null, 2)); | |
}); | |
}); | |
} | |
// Return the basic info | |
else { | |
return lando.app.info(app) | |
.then(function(info) { | |
console.log(JSON.stringify(info, null, 2)); | |
}); | |
} | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=info, command=list, describe=List all lando apps, run=function () { | |
// List all the apps | |
return lando.app.list() | |
// Map each app to a summary and print results | |
.map(function(app) { | |
return appSummary(app) | |
.then(function(summary) { | |
console.log(JSON.stringify(summary, null, 2)); | |
}); | |
}); | |
}, name=list, command=logs [appname], describe=Get logs for app in current directory or [appname], describe=Follow the logs, alias=[f], default=false, boolean=true, describe=Show logs for the specified services only, alias=[s], array=true, describe=Show log timestamps, alias=[t], default=false, boolean=true, run=function (options) { | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
// Add opts to our app | |
app.opts.follow = options.follow; | |
app.opts.timestamps = options.timestamps; | |
app.opts.services = options.services; | |
// Get the logs | |
return lando.engine.logs(app); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=logs, command=poweroff, describe=Spin down all lando related containers, run=function () { | |
// Start | |
console.log(chalk.yellow('Spinning containers down... Standby.')); | |
// Get all our apps | |
return lando.app.list() | |
// SHUT IT ALL DOWN | |
.map(function(app) { | |
return lando.app.get(app.name) | |
.then(function(app) { | |
lando.app.stop(app); | |
}); | |
}) | |
// Emit poweroff | |
.then(function() { | |
return lando.events.emit('poweroff'); | |
}) | |
// Finish up | |
.then(function() { | |
console.log(chalk.red('Lando containers have been spun down.')); | |
}); | |
}, name=poweroff, command=rebuild [appname], describe=Rebuilds app in current directory or [appname], describe=Rebuild only the specified services, alias=[s], array=true, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to rebuild?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('Rebuild aborted')); | |
return; | |
} | |
// Attempt to grab the app if we can | |
return lando.app.get(options.appname) | |
// Rebuild the app | |
.then(function(app) { | |
if (app) { | |
// Rebuild only particlar services if specified | |
if (!_.isEmpty(options.services)) { | |
app.opts.services = options.services; | |
} | |
return lando.app.rebuild(app) | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=rebuild, command=restart [appname], describe=Restarts app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Resttart the app | |
.then(function(app) { | |
if (app) { | |
// REstart the app | |
return lando.app.restart(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=restart, command=share [appname], describe=Get a publicly available url, describe=Url to share. Needs to be in the form http://localhost:port, alias=[u], required=true, run=function (options) { | |
// Do some validation of the url | |
var url = u.parse(options.url); | |
// Validate URL | |
var hnf = _.isEmpty(url.hostname) || url.hostname !== 'localhost'; | |
if (hnf || url.protocol !== 'http:') { | |
lando.log.error('Need a url of the form http://localhost:port!'); | |
lando.log.error('Run "lando info" for help finding the correct url!'); | |
process.exit(153); | |
} | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Get the sharing url | |
.then(function(app) { | |
if (app) { | |
// Start the app if needed | |
return lando.app.isRunning(app) | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Get the URLS | |
.then(function() { | |
// Assume a port to start | |
var port = 80; | |
// Override port if specified | |
if (!_.isEmpty(url.port)) { | |
port = url.port; | |
} | |
// Translate the app.name into a localtunnel suitable address | |
// eg lowercase/alphanumeric 4-63 chars | |
// lowercase and alphanumeric it | |
var tunnelHost = _.lowerCase(app.name).replace(/[^0-9a-z]/g, ''); | |
// Make sure we are at least 4 characters | |
if (_.size(tunnelHost) <= 4) { | |
tunnelHost = tunnelHost + 'xxxx'; | |
} | |
// Makes sure we are at most 64 chars | |
if (_.size(tunnelHost) >= 63) { | |
tunnelHost = tunnelHost.substring(0, 57); | |
} | |
// Build opts array | |
var opts = {subdomain: tunnelHost}; | |
// Set up the localtunnel | |
var tunnel = localtunnel(port, opts, function(err, tunnel) { | |
// Error if needed | |
if (err) { | |
lando.log.error(err); | |
} | |
// Header it | |
console.log(lando.cli.tunnelHeader()); | |
// the assigned public url for your tunnel | |
// i.e. https://abcdefgjhij.localtunnel.me | |
console.log(chalk.blue(tunnel.url)); | |
console.log(''); | |
console.log(chalk.yellow('Press any key to close the tunnel.')); | |
// Set stdin to the correct mode | |
process.stdin.resume(); | |
process.stdin.setEncoding('utf8'); | |
process.stdin.setRawMode(true); | |
// Start the keypress listener for the process | |
process.stdin.on('data', function() { | |
tunnel.close(); | |
}); | |
}); | |
tunnel.on('close', function() { | |
console.log(''); | |
console.log(chalk.green('Tunnel closed!')); | |
process.exit(0); | |
}); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=share, command=start [appname], describe=Start app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Start the app if we have one | |
.then(function(app) { | |
if (app) { | |
// Start the app | |
return lando.app.start(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=start, command=stop [appname], describe=Stops app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Restart the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.stop(app) | |
.then(function() { | |
console.log(chalk.red('App stopped!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=stop, command=version, describe=Display the lando version, run=function () { | |
console.log('v' + lando.config.version); | |
}, name=version, command=ssh [appname] [service], describe=SSH into [service] in current app directory or [appname], describe=Run a command in the service, alias=[c], describe=Run as a specific user, alias=[u], run=function (options) { | |
// Handle our options | |
if (!_.has(options, 'service') && _.has(options, 'appname')) { | |
options.service = options.appname; | |
options.appname = undefined; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Handle app or no app | |
.then(function(app) { | |
// We have an app so lets try to build a ssh exec | |
if (app) { | |
// Default to appserver if we have no second arg | |
var service = options.service || 'appserver'; | |
// Build out our run | |
var run = { | |
id: [app.dockerName, service, '1'].join('_'), | |
compose: app.compose, | |
project: app.name, | |
cmd: options.command || 'cd $LANDO_MOUNT && bash', | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: options.user || 'www-data', | |
services: [service] | |
} | |
}; | |
// Let's check to see if the app has been started | |
return lando.app.isRunning(app) | |
// If not let's make sure we start it | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Exec | |
.then(function() { | |
return lando.engine.run(run); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=ssh, command=init [method], describe=Initialize a lando app, optional methods: github, pantheon, describe=The recipe to use, choices=[custom, backdrop, drupal6, drupal7, drupal8, joomla, laravel, lamp, lemp, mean, pantheon, wordpress], alias=[r], string=true, type=list, message=What recipe do you want to use?, default=custom, choices=[name=custom, value=custom, name=backdrop, value=backdrop, name=drupal6, value=drupal6, name=drupal7, value=drupal7, name=drupal8, value=drupal8, name=joomla, value=joomla, name=laravel, value=laravel, name=lamp, value=lamp, name=lemp, value=lemp, name=mean, value=mean, name=pantheon, value=pantheon, name=wordpress, value=wordpress], weight=500, name=recipe, describe=GitHub token or email of previously used token, string=true, type=list, message=Choose a GitHub account, choices=[], when=function (answers) { | |
return !_.isEmpty(gitHubAccounts()) && askQuestions(answers); | |
}, weight=400, name=github-auth, name=github-auth, type=password, message=Enter a GitHub token, when=function (answers) { | |
var token = _.get(answers, 'github-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=401, describe=GitHub repo URL, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Repo collector | |
var repos = []; | |
// Spin things up | |
var tpath = 'github-auth'; | |
var token = _.get(lando.tasks.argv(), tpath, answers[tpath]); | |
var options = {affliation: 'owner,collaborator', 'per_page': 100}; | |
var done = this.async(); | |
// Check to see if token is cached already and use that | |
var tokens = lando.cache.get(tokenCacheKey) || {}; | |
if (_.includes(_.keys(tokens), token)) { | |
token = tokens[token]; | |
} | |
/* | |
* Helper to resursively load all our repos | |
*/ | |
var getAllRepos = function(err, res) { | |
// Error | |
if (err) { | |
lando.log.error('Problem getting sites from GitHub'); | |
} | |
// Add previous data to current | |
repos = repos.concat(res.data); | |
// IF we have more pages lets add them | |
if (github.hasNextPage(res)) { | |
github.getNextPage(res, getAllRepos); | |
} | |
// Otherwise lets send back our result | |
else { | |
done(null, _.map(repos, function(site) { | |
var name = _.get(site, 'full_name'); | |
var value = _.get(site, 'ssh_url'); | |
return {name: name, value: value}; | |
})); | |
} | |
}; | |
// Start the github authchain | |
github.authenticate({type: 'token', token: token}); | |
// Get all our sites | |
github.repos.getAll(options, getAllRepos); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=402, name=github-repo, describe=Pantheon machine token or email of previously used token, string=true, type=list, message=Choose a Pantheon account, choices=[], when=function (answers) { | |
return !_.isEmpty(pantheonAccounts()) && askQuestions(answers); | |
}, weight=600, name=pantheon-auth, name=pantheon-auth, type=password, message=Enter a Pantheon machine token, when=function (answers) { | |
var token = _.get(answers, 'pantheon-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=601, describe=Pantheon site machine name, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Token path | |
var tpath = 'pantheon-auth'; | |
// Make this async cause we need to hit the terminus | |
var done = this.async(); | |
// Get the pantheon sites using the token | |
api.getSites(_.get(lando.tasks.argv(), tpath, answers[tpath])) | |
// Parse the sites into choices | |
.map(function(site) { | |
return {name: site.name, value: site.name}; | |
}) | |
// Done | |
.then(function(sites) { | |
done(null, sites); | |
}); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=602, name=pantheon-site, describe=Specify where to init the app, alias=[dest, d], string=true, default=/home/hpottinger/workspace/lando-tomcat, describe=Specify the webroot relative to destination, string=true, type=input, message=Where is your webroot relative to the init destination?, default=., when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.webroot(recipe); | |
}, weight=900, name=webroot, describe=The name of the app, string=true, type=input, message=What do you want to call this app?, default=My Lando App, filter=function (value) { | |
if (value) { | |
return _.kebabCase(value); | |
} | |
}, when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.name(recipe); | |
}, weight=1000, name=name, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, run=function (options) { | |
// Set the basics | |
var config = { | |
name: options.name, | |
recipe: options.recipe, | |
}; | |
// If we have a webroot let's set it | |
if (!_.isEmpty(options.webroot)) { | |
_.set(config, 'config.webroot', options.webroot); | |
} | |
// Method specific build steps if applicable | |
return Promise.try(function() { | |
return lando.init.build(config.name, options.method, options); | |
}) | |
// Kill any build containers if needed | |
.then(function() { | |
return lando.init.kill(config.name, options.destination); | |
}) | |
// Check to see if our recipe provides additional yaml augment | |
.then(function() { | |
return lando.init.yaml(options.recipe, config, options); | |
}) | |
// Create the lando yml | |
.then(function(config) { | |
// Where are we going? | |
var dest = path.join(options.destination, '.lando.yml'); | |
// Rebase on top of any existing yaml | |
if (fs.existsSync(dest)) { | |
var pec = lando.yaml.load(dest); | |
config = _.mergeWith(pec, config, lando.utils.merger); | |
} | |
// Dump it | |
lando.yaml.dump(dest, config); | |
}) | |
// Tell the user things | |
.then(function() { | |
// Header it | |
console.log(lando.cli.initHeader()); | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Get docs link | |
var docBase = 'https://docs.devwithlando.io/tutorials/'; | |
var docUrl = docBase + config.recipe + '.html'; | |
// Add data | |
table.add('NAME', config.name); | |
table.add('RECIPE', options.recipe); | |
table.add('DOCS', docUrl); | |
// Add some other things if needed | |
if (!_.isEmpty(options.method)) { | |
table.add('METHOD', options.method); | |
} | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
}, name=init], webRoot=., status=function () { | |
var args = _.toArray(arguments); | |
var msg = util.format.apply(null, args); | |
return app.events.emit('status', msg) | |
// Make sure app status messages make it to global status. | |
.then(function() { | |
lando.log.info(msg); | |
}); | |
}, trollForStatus=function (msg) { | |
// Update status when pulling an image. | |
var images = msg.match(/Pulling from (.*)/); | |
if (images) { | |
app.status('Pulling image %s.', images[1]); | |
} | |
}, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, io.lando.container=TRUE, project=tomcat-demo, compose=[], image=tomcat:latest, ports=[8080], TERM=xterm, LANDO_WEBROOT=/app/./webapps, LANDO_SERVICE_NAME=tomcat, LANDO_SERVICE_TYPE=tomcat, LANDO_MOUNT=/app, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, volumes=[/home/hpottinger/.lando/services/config/tomcat/context.xml:/usr/local/tomcat/conf/context.xml, $LANDO_ENGINE_SCRIPTS_DIR/lando-entrypoint.sh:/lando-entrypoint.sh, $LANDO_APP_ROOT_BIND:/app, $LANDO_ENGINE_HOME:/user, $LANDO_ENGINE_SCRIPTS_DIR/user-perms.sh:/user-perms.sh, /home/hpottinger/.lando/services/config/scripts/load-keys.sh:/scripts/load-keys.sh, /home/hpottinger/.lando/services/config/helpers/mysql-import.sh:/helpers/mysql-import.sh, /home/hpottinger/.lando/services/config/helpers/mysql-export.sh:/helpers/mysql-export.sh], command=catalina.sh run, entrypoint=/lando-entrypoint.sh, io.lando.container=TRUE, , , mode=collect | |
verbose: Running spawn /usr/share/lando/bin/docker-compose with args ["--project-name","tomcat-demo","--file","/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml","build","--no-cache","--pull"] | |
debug: In mode collect with detached false | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
tomcat uses an image, skipping | |
verbose: Spawn exited with code: 0 | |
silly: Spawn finished with | |
verbose: Emitting event post-engine-build | |
debug: Event post-engine-build has 0 listeners | |
verbose: Emitting event post-rebuild | |
debug: Event post-rebuild has 0 listeners | |
verbose: Emitting event status | |
debug: Event status has 0 listeners | |
debug: Retrieved from file cache with key site:meta:undefined | |
debug: Cache miss with key site:meta:undefined | |
info: Starting tomcat-demo | |
debug: Reporting. action=start, app=36a7ebf24b7a91b0db0cb82be0dbf42910f3b092, type=custom, services=[tomcat:latest], mode=cli, devMode=false, version=3.0.0-beta.29, type=Linux, platform=linux, release=4.4.0-103-generic, arch=x64, nodeVersion=v6.9.5, created=2017-12-19T18:16:12.374Z | |
verbose: Emitting event status | |
debug: Event status has 0 listeners | |
verbose: Trying to get list of apps with opts useCache=false | |
info: Cleaning up app registry and containers | |
debug: Apps in registry: [{"name":"docs.lando","dir":"/home/hpottinger/workspace/lando"},{"name":"dspace","dir":"/home/hpottinger/workspace/dspace-dev-docker"},{"name":"tomcat-demo","dir":"/home/hpottinger/workspace/lando-tomcat"}] | |
verbose: Retrieved good apps name=docs.lando, dir=/home/hpottinger/workspace/lando, name=dspace, dir=/home/hpottinger/workspace/dspace-dev-docker, name=tomcat-demo, dir=/home/hpottinger/workspace/lando-tomcat | |
debug: Retrieved from memcache with key engineUp | |
debug: Retrieved from memcache with key engineUp | |
verbose: Emitting event pre-engine-stop | |
debug: Event pre-engine-stop has 0 listeners | |
verbose: Emitting event post-engine-stop | |
debug: Event post-engine-stop has 0 listeners | |
debug: Retrieved from memcache with key engineUp | |
verbose: Emitting event pre-engine-destroy | |
debug: Event pre-engine-destroy has 0 listeners | |
verbose: Emitting event post-engine-destroy | |
debug: Event post-engine-destroy has 0 listeners | |
verbose: Emitting event pre-start | |
debug: Event pre-start has 1 listeners | |
debug: Run proxy service from /home/hpottinger/.lando/proxy/proxy.yml | |
debug: Retrieved from memcache with key engineUp | |
debug: About to run 0=/usr/share/lando/bin/docker-compose, 1=--project-name, 2=landoproxyhyperion5000gandalfedition, 3=--file, 4=/home/hpottinger/.lando/proxy/proxy.yml, 5=ps, 6=-q, 7=proxy | |
silly: With pre run opts app=undefined | |
verbose: Running exec /usr/share/lando/bin/docker-compose,--project-name,landoproxyhyperion5000gandalfedition,--file,/home/hpottinger/.lando/proxy/proxy.yml,ps,-q,proxy | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
verbose: Proxying on 80 | |
verbose: Proxying on 443 | |
debug: Run proxy service from /home/hpottinger/.lando/proxy/proxy.yml | |
debug: Retrieved from memcache with key engineUp | |
verbose: Emitting event pre-engine-start | |
debug: Event pre-engine-start has 0 listeners | |
debug: About to run 0=/usr/share/lando/bin/docker-compose, 1=--project-name, 2=landoproxyhyperion5000gandalfedition, 3=--file, 4=/home/hpottinger/.lando/proxy/proxy.yml, 5=up, 6=-d, 7=--remove-orphans, 8=proxy | |
silly: With pre run opts app=undefined, mode=collect | |
verbose: Running spawn /usr/share/lando/bin/docker-compose with args ["--project-name","landoproxyhyperion5000gandalfedition","--file","/home/hpottinger/.lando/proxy/proxy.yml","up","-d","--remove-orphans","proxy"] | |
debug: In mode collect with detached false | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
landoproxyhyperion5000gandalfedition_proxy_1 is up-to-date | |
verbose: Spawn exited with code: 0 | |
silly: Spawn finished with | |
verbose: Emitting event post-engine-start | |
debug: Event post-engine-start has 0 listeners | |
debug: Run proxy service from /home/hpottinger/.lando/proxy/proxy.yml | |
debug: Retrieved from memcache with key engineUp | |
debug: About to run 0=/usr/share/lando/bin/docker-compose, 1=--project-name, 2=landoproxyhyperion5000gandalfedition, 3=--file, 4=/home/hpottinger/.lando/proxy/proxy.yml, 5=ps, 6=-q, 7=proxy | |
silly: With pre run opts app=undefined | |
verbose: Running exec /usr/share/lando/bin/docker-compose,--project-name,landoproxyhyperion5000gandalfedition,--file,/home/hpottinger/.lando/proxy/proxy.yml,ps,-q,proxy | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
verbose: Building compose file at /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-proxy-3.yml with services. 0=version, 1=networks, 2=services | |
verbose: Writing ["version","networks","services"] to /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-proxy-3.yml | |
debug: Full services for /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-proxy-3.yml version=3.2, name=landoproxyhyperion5000gandalfedition_edge, , , io.lando.container=TRUE, traefik.docker.network=landoproxyhyperion5000gandalfedition_edge, traefik.frontend.rule=Host:tomcat-demo.lndo.site, traefik.port=8080/tcp, extra_hosts=[tomcat-demo.lndo.site:192.168.11.16] | |
verbose: App tomcat-demo has proxy compose file /home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-proxy-3.yml | |
debug: Retrieved from file cache with key engineUp | |
debug: Cache miss with key engineUp | |
debug: About to run 0=/usr/bin/docker, 1=info | |
silly: With pre run opts | |
verbose: Running exec /usr/bin/docker,info | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
debug: Engine is up. | |
debug: Cached true with key engineUp for {"persist":false,"ttl":5} | |
debug: Failed to cache true with key engineUp | |
verbose: Emitting event pre-engine-start | |
debug: Event pre-engine-start has 0 listeners | |
debug: About to run 0=/usr/share/lando/bin/docker-compose, 1=--project-name, 2=tomcat-demo, 3=--file, 4=/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml, 5=--file, 6=/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-proxy-3.yml, 7=up, 8=-d, 9=--remove-orphans | |
silly: With pre run opts list=function (opts) { | |
// Set opt defaults | |
opts = opts || {useCache: true}; | |
// Log | |
lando.log.verbose('Trying to get list of apps with opts', opts); | |
// Get list of app names. | |
return registry.getApps(opts) | |
// Validate list of apps, look for duplicates. | |
.then(function(apps) { | |
// Group apps by app names. | |
var groups = _.groupBy(apps, function(app) { | |
return app.name; | |
}); | |
// Find a set of duplicates. | |
var duplicates = _.find(groups, function(group) { | |
return group.length !== 1; | |
}); | |
// If a set of duplicates were found throw an error. | |
if (duplicates) { | |
throw new Error('Duplicate app names exist', duplicates); | |
} | |
// Pass the apps on to the each | |
return apps; | |
}); | |
}, get=function (appName) { | |
// If we have an appName lets try to match it with a diretory | |
return Promise.try(function() { | |
if (appName) { | |
return exports.list() | |
.then(function(apps) { | |
return _.find(apps, function(app) { | |
return app.name === appName || app.dockerName === appName; | |
}); | |
}); | |
} | |
}) | |
// Try to use a found app first if possible then default to the cwd | |
.then(function(app) { | |
return _.get(app, 'dir') || path.join(process.cwd()); | |
}) | |
// Return an app or warn the user there is no such app | |
.then(function(dir) { | |
// Split up our dir | |
var pieces = dir.split(path.sep); | |
// Go through all dir pieces | |
return _.map(pieces, function() { | |
// Build the dir | |
var dir = pieces.join(path.sep); | |
// Drop the last path for next iteration | |
pieces = _.dropRight(pieces); | |
// Return the possible location of lando files | |
return path.join(dir, lando.config.appConfigFilename); | |
}); | |
}) | |
// Return the first directory that has an app | |
.then(function(files) { | |
// Find the first directory that has a lando.yml | |
var configFile = _.find(files, function(file) { | |
lando.log.verbose('Checking for app config at %s', file); | |
return fs.existsSync(file); | |
}); | |
// If we have a config file let's load up the app | |
if (!_.isEmpty(configFile)) { | |
// TRy to load the config | |
var appConfig = lando.yaml.load(configFile); | |
// If we have appConfig then load the app | |
if (!_.isEmpty(appConfig)) { | |
return instantiate(appConfig.name, path.dirname(configFile), appConfig); | |
} | |
} | |
}); | |
}, isRunning=function (app, checkall) { | |
// Log | |
lando.log.verbose('Checking if %s is running', app.name); | |
// Clarify the checkall | |
checkall = checkall || false; | |
// Check if our engine is up | |
return lando.engine.isUp() | |
// If we are up check for containers running for an app | |
// otherwise return false | |
.then(function(isUp) { | |
// Engine is up so lets check if the app has running containers | |
if (isUp) { | |
// Get list of containers | |
return lando.engine.list(app.name) | |
// Filter out autostart containers since those will always report TRUE | |
.filter(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
return data.HostConfig.RestartPolicy.Name !== 'always'; | |
}); | |
}) | |
// Reduce containers to a true false running value | |
.reduce(function(isRunning, container) { | |
if (checkall) { | |
return isRunning && lando.engine.isRunning(container.id); | |
} | |
else { | |
return (isRunning) ? true : lando.engine.isRunning(container.id); | |
} | |
}, checkall); | |
} | |
// Engine is down so nothing can be running | |
else { | |
return false; | |
} | |
}); | |
}, exists=function (appName) { | |
// Get app. | |
return _app.get(appName) | |
// Return false if we get an app does not exist error. | |
.catch(function(err) { | |
if (_.contains(err.message, ' does not exist.')) { | |
return false; | |
} | |
else { | |
throw err; | |
} | |
}) | |
// Return true if app was returned. | |
.then(function(app) { | |
return !!app; | |
}); | |
}, info=function (app) { | |
/** | |
* Event that allows other things to add useful metadata to the apps services. | |
* | |
* Its helpful to use this event to add in information for the end user such as | |
* how to access their services, where their code exsts or relevant credential info. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-info | |
* @example | |
* | |
* // Add urls to the app | |
* app.events.on('pre-info', function() { | |
* return getUrls(app); | |
* }); | |
*/ | |
return app.events.emit('pre-info') | |
// Return all the app info | |
.then(function() { | |
if (app && app.info) { | |
return app.info; | |
} | |
}); | |
}, uninstall=function (app) { | |
// Cleaning up | |
app.status('Uninstalling %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('uninstall', {app: app}) | |
/** | |
* Event that runs before an app is uninstalled. | |
* | |
* This is useful if you want to add or remove parts of the uninstall process. | |
* For example, it might be nice to persist a container whose data you do not | |
* want to replace in a rebuild and that cannot persist easily with a volume. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-uninstall | |
* @example | |
* | |
* // Do not uninstall the solr service | |
* app.events.on('pre-uninstall', function() { | |
* delete app.services.solr; | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-uninstall'); | |
}) | |
// Kill components. | |
.then(function() { | |
return lando.engine.destroy(app); | |
}) | |
/** | |
* Event that runs after an app is uninstalled. | |
* | |
* This is useful if you want to do some additional cleanup steps after an | |
* app is uninstalled such as invalidating any cached data. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-uninstall | |
* @example | |
* | |
* // Make sure we remove our build cache | |
* app.events.on('post-uninstall', function() { | |
* lando.cache.remove(app.name + ':last_build'); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-uninstall'); | |
}); | |
}, cleanup=function (app) { | |
// Cleaning up | |
app.status('Cleaning up app registry and containers'); | |
// Get all our containers | |
return _app.list({useCache: false}) | |
// We need to use the dockername | |
.map(function(app) { | |
return lando.utils.dockerComposify(app.name); | |
}) | |
// Filter out non-app containers | |
.then(function(apps) { | |
return Promise.filter(lando.engine.list(), function(container) { | |
return container.kind === 'app' && !_.includes(apps, container.app); | |
}); | |
}) | |
// Stop containers if needed | |
.tap(function(containers) { | |
return lando.engine.stop(containers); | |
}) | |
// Kill containers if needed | |
.tap(function(containers) { | |
return lando.engine.destroy(containers); | |
}); | |
}, start=function (app) { | |
// Start it up | |
app.status('Starting %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('start', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app starts up. | |
* | |
* This is useful if you want to start up any support services before an app | |
* stars. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-start | |
* @example | |
* | |
* // Start up a DNS server before our app starts | |
* app.events.on('pre-start', function() { | |
* return lando.engine.start(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-start'); | |
}) | |
// Start core containers | |
.then(function() { | |
return lando.engine.start(app); | |
}) | |
/** | |
* Event that runs after an app is started. | |
* | |
* This is useful if you want to perform additional operations after an app | |
* starts such as running additional build commands. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-start | |
* @example | |
* | |
* // Go through each service and run additional build commands as needed | |
* app.events.on('post-start', function() { | |
* | |
* // Start up a build collector | |
* var build = []; | |
* | |
* // Go through each service | |
* _.forEach(app.config.services, function(service, name) { | |
* | |
* // If the service has extras let's loop through and run some commands | |
* if (!_.isEmpty(service.extras)) { | |
* | |
* // Normalize data for loopage | |
* if (!_.isArray(service.extras)) { | |
* service.extras = [service.extras]; | |
* } | |
* | |
* // Run each command | |
* _.forEach(service.extras, function(cmd) { | |
* | |
* // Build out the compose object | |
* var compose = { | |
* id: [app.dockerName, name, '1'].join('_'), | |
* cmd: cmd, | |
* opts: { | |
* mode: 'attach' | |
* } | |
* }; | |
* | |
* // Push to the build | |
* build.push(compose); | |
* | |
* }); | |
* | |
* } | |
* | |
* }); | |
* | |
* // Only proceed if build is non-empty | |
* if (!_.isEmpty(build)) { | |
* | |
* // Get the last build cache key | |
* var key = app.name + ':last_build'; | |
* | |
* // Compute the build hash | |
* var newHash = lando.node.hasher(app.config.services); | |
* | |
* // If our new hash is different then lets build | |
* if (lando.cache.get(key) !== newHash) { | |
* | |
* // Set the new hash | |
* lando.cache.set(key, newHash, {persist:true}); | |
* | |
* // Run all our post build steps serially | |
* return lando.engine.run(build); | |
* | |
* } | |
* } | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-start'); | |
}); | |
}, stop=function (app) { | |
// Stop it! | |
app.status('Stopping %s', app.name); | |
// Report to metrics. | |
return lando.metrics.reportAction('stop', {app: app}) | |
// Make sure we are in a clean place before we get dirty | |
.then(function() { | |
return _app.cleanup(app); | |
}) | |
/** | |
* Event that runs before an app stops. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-stop | |
* @example | |
* | |
* // Stop a DNS server before our app stops. | |
* app.events.on('pre-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-stop'); | |
}) | |
// Stop components. | |
.then(function() { | |
return lando.engine.stop(app); | |
}) | |
/** | |
* Event that runs after an app stop. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-stop | |
* @example | |
* | |
* // Stop a DNS server after our app stops. | |
* app.events.on('post-stop', function() { | |
* return lando.engine.stop(dnsServer); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-stop'); | |
}); | |
}, restart=function (app) { | |
// Start it off | |
app.status('Restarting %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
// Start app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, destroy=function (app) { | |
// Start it off | |
app.status('Destroying %s', app.name); | |
/** | |
* Event that runs before an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-destroy | |
* @example | |
* | |
* // Make sure the proxy is down before we destroy | |
* app.events.on('pre-destroy', function() { | |
* if (fs.existsSync(proxyFile)) { | |
* return lando.engine.stop(getProxy(proxyFile)); | |
* } | |
* }); | |
*/ | |
return app.events.emit('pre-destroy') | |
// Make sure app is stopped. | |
.then(function() { | |
return _app.stop(app); | |
}) | |
// Uninstall app. | |
.then(function() { | |
app.opts = _.merge(app.opts, {purge: true}); | |
return _app.uninstall(app); | |
}) | |
// Remove from appRegistry | |
.then(function() { | |
return registry.remove({name: app.name}); | |
}) | |
/** | |
* Event that runs after an app is destroyed. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-destroy | |
* @example | |
* | |
* // Make sure the proxy is up brought back up after we destroy | |
* app.events.on('post-destroy', function() { | |
* return startProxy(); | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-destroy'); | |
}); | |
}, rebuild=function (app) { | |
// Start it off | |
app.status('Rebuilding %s', app.name); | |
// Stop app. | |
return _app.stop(app) | |
/** | |
* Event that runs before an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:pre-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('pre-rebuild'); | |
}) | |
// Uninstall app | |
.then(function() { | |
return _app.uninstall(app); | |
}) | |
// Repull/build components. | |
.then(function() { | |
return lando.engine.build(app); | |
}) | |
/** | |
* Event that runs after an app is rebuilt. | |
* | |
* @since 3.0.0 | |
* @event module:app.event:post-rebuild | |
* @example | |
* | |
* // Do something | |
* app.events.on('post-rebuild', function() { | |
* // Do something | |
* }); | |
*/ | |
.then(function() { | |
return app.events.emit('post-rebuild'); | |
}) | |
// Install app. | |
.then(function() { | |
return _app.start(app); | |
}); | |
}, name=tomcat-demo, dockerName=tomcatdemo, name=tomcat-demo, recipe=custom, type=tomcat:latest, config=null, webroot=./webapps, serverxmlfile=./config/server.xml, tomcatusersfile=./config/tomcat-users.xml, managercontext=./config/manager-context.xml, _app=tomcat-demo, _root=/home/hpottinger/workspace/lando-tomcat, _mount=/app, version=latest, tomcat=[tomcat-demo.lndo.site:8080], _listeners=[name=app-ready, priority=5, fn=function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, name=app-ready, priority=9, fn=function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, name=app-ready, priority=9, fn=function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, name=app-ready, priority=5, fn=function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}, name=pre-info, priority=5, fn=function () { | |
return getUrls(app); | |
}, name=post-start, priority=1, fn=function () { | |
return getUrls(app); | |
}, name=pre-info, priority=1, fn=function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, name=post-uninstall, priority=5, fn=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, name=post-start, priority=5, fn=function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, name=post-start, priority=9, fn=function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, name=post-start, priority=5, fn=function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}, name=pre-info, priority=5, fn=function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}, name=pre-start, priority=1, fn=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, name=pre-terminus, priority=5, fn=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, name=post-destroy, priority=5, fn=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}], domain=null, app-ready=[function () { | |
// Log | |
lando.log.verbose('App %s has global env.', app.name, app.env); | |
lando.log.verbose('App %s has global labels.', app.name, app.labels); | |
lando.log.verbose('App %s adds process env.', app.name, app.processEnv); | |
// If we have some services lets add in our global envs and labels | |
if (!_.isEmpty(app.services)) { | |
_.forEach(app.services, function(service, name) { | |
// Get existing ENV and LABELS | |
var env = service.environment || {}; | |
var labels = service.labels || {}; | |
// Add our env globals | |
_.forEach(app.env, function(value, key) { | |
env[key] = value; | |
}); | |
service.environment = env; | |
// Add our global labels | |
_.forEach(app.labels, function(value, key) { | |
labels[key] = value; | |
}); | |
service.labels = labels; | |
// Reset the app conatiner | |
app.services[name] = _.cloneDeep(service); | |
}); | |
} | |
}, function () { | |
app.opts = {app: _.cloneDeep(app)}; | |
}, function () { | |
// Start a compose collector | |
var compose = {}; | |
// Check if some properties exist and then add them if they do | |
var tlos = ['services', 'volumes', 'networks']; | |
// Check for each and add as needed | |
_.forEach(tlos, function(option) { | |
if (!_.isEmpty(app[option])) { | |
compose[option] = app[option]; | |
} | |
}); | |
// If we have some services lets create the file | |
if (!_.isEmpty(compose)) { | |
// Set the compose version | |
compose.version = lando.config.composeVersion; | |
// Get project name | |
var project = app.project || app.name; | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has compose files.', project, app.compose); | |
} | |
}, function () { | |
// Add service keys | |
_.forEach(_.keys(app.services), function(service) { | |
app.info[service] = {}; | |
}); | |
}], pre-info=[function () { | |
return getUrls(app); | |
}, function () { | |
_.forEach(app.config.services, function(service, name) { | |
// Merge in any computed service info with starting conf | |
var config = _.mergeWith(app.services[name], service, merger); | |
// Merge create the info for the service | |
app.info[name] = lando.services.info(name, service.type, config); | |
}); | |
}, function () { | |
// Kick off the chain by seeing if our app is up | |
return lando.app.isRunning(app) | |
// If app is not running then we are done | |
.then(function(isRunning) { | |
// Log | |
lando.log.verbose('App %s is up = %s', app.name, isRunning); | |
// If app is running then continue | |
if (isRunning) { | |
return addUrls(app); | |
} | |
}); | |
}], post-start=[function () { | |
return getUrls(app); | |
}, function () { | |
// Start up a build collector | |
var build = []; | |
/* | |
* Helper to build out some runs | |
*/ | |
var buildRun = function(container, cmd, user) { | |
return { | |
id: container, | |
cmd: cmd, | |
compose: app.compose, | |
project: app.name, | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: user, | |
services: [container.split('_')[1]] | |
} | |
}; | |
}; | |
// Go through each service | |
_.forEach(app.config.services, function(service, name) { | |
// Loop through both extras and build | |
_.forEach(['extras', 'build'], function(section) { | |
// If the service has extras let's loop through and run some commands | |
if (!_.isEmpty(service[section])) { | |
// Normalize data for loopage | |
if (!_.isArray(service[section])) { | |
service[section] = [service[section]]; | |
} | |
// Run each command | |
_.forEach(service[section], function(cmd) { | |
// Get the user | |
var userPath = 'environment.LANDO_WEBROOT_USER'; | |
var user = _.get(app.services[name], userPath, 'root'); | |
// Force root if we are doing extras | |
var by = (section === 'extras') ? 'root' : user; | |
// Get teh container name | |
var container = [app.dockerName, name, '1'].join('_'); | |
// Push to the build | |
build.push(buildRun(container, cmd, by)); | |
}); | |
} | |
}); | |
}); | |
// Only proceed if build is non-empty | |
if (!_.isEmpty(build)) { | |
// Get the last build cache key | |
var key = app.name + ':last_build'; | |
// Compute the build hash | |
var newHash = lando.node.hasher(app.config.services); | |
// If our new hash is different then lets build | |
if (lando.cache.get(key) !== newHash) { | |
// Set the new hash | |
lando.cache.set(key, newHash, {persist:true}); | |
// Run all our post build steps serially | |
return lando.engine.run(build); | |
} | |
} | |
}, function () { | |
// Get app URLs | |
var urls = _.filter(_.flatMap(app.info, 'urls'), _.identity); | |
// Scan the urls | |
return lando.utils.scanUrls(urls, {max: 17}) | |
// Add our URLS to the app | |
.then(function(urls) { | |
app.urls = urls; | |
}); | |
}, function () { | |
return addUrls(app, ['80/tcp', '443/tcp']); | |
}], post-uninstall=function () { | |
lando.cache.remove(app.name + ':last_build'); | |
}, pre-start=function () { | |
// Get project name | |
var project = app.project || app.name; | |
// Kick off the proxy compose file | |
var compose = { | |
version: lando.config.composeVersion, | |
networks: { | |
'lando_proxyedge': { | |
external: { | |
name: projectName + '_edge' | |
} | |
} | |
}, | |
services: {} | |
}; | |
// Start the proxy | |
return startProxy() | |
// Get the data | |
.then(function() { | |
return getProxyData(app); | |
}) | |
// Go through those services one by one | |
.map(function(service) { | |
// Get name and port | |
var name = service.name; | |
var port = _.get(service, 'routes[0].port', '80'); | |
// If port is 443 switch back to 80 | |
if (port === 443) { | |
port = 80; | |
} | |
// Get hostnames without ports | |
var hosts = _.map(_.get(service, 'routes[0].urls', []), function(u) { | |
var hasProtocol = !_.isEmpty(u.split('://')[1]); | |
var f = (hasProtocol) ? (u.split('://')[1]) : (u.split('://')[0]); | |
return f.split(':')[0]; | |
}); | |
// Add in relevant labels if we have hosts | |
if (!_.isEmpty(hosts)) { | |
var labels = _.get(app.services[service.name], 'labels', {}); | |
labels['traefik.docker.network'] = projectName + '_edge'; | |
labels['traefik.frontend.rule'] = 'Host:' + hosts.join(','); | |
labels['traefik.port'] = _.toString(port); | |
// Get any networks that might already exist | |
var defaultNets = {'lando_proxyedge': {}, 'default': {}}; | |
var preNets = _.get(app.services[name], 'networks', {}); | |
// Start building the augment | |
compose.services[name] = { | |
networks: _.mergeWith(defaultNets, preNets, lando.utils.merger), | |
labels: labels, | |
}; | |
} | |
// Send hosts down the pipe | |
return hosts; | |
}) | |
// Add extra hosts to all the service | |
.then(function(hosts) { | |
// Compute extra hosts | |
var hostList = _.map(_.flatten(hosts), function(host) { | |
return [host, lando.config.env.LANDO_ENGINE_REMOTE_IP].join(':'); | |
}); | |
// And add them if applicable | |
if (!_.isEmpty(hostList)) { | |
_.forEach(_.keys(app.services), function(name) { | |
// Look for preexisting extra_hosts | |
var peeh = []; | |
if (!_.isEmpty(_.get(app.services[name], 'extra_hosts', []))) { | |
peeh = _.get(app.services[name], 'extra_hosts', []); | |
} | |
// Merge the whole shebang | |
compose.services[name] = _.merge(compose.services[name], { | |
'extra_hosts': _.flatten(hostList.concat(peeh)) | |
}); | |
}); | |
} | |
}) | |
// Spit out the proxy compose file | |
.then(function() { | |
// Write the services | |
var projectDir = path.join(lando.config.userConfRoot, 'tmp', project); | |
var fileName = [project, 'proxy', _.uniqueId()].join('-'); | |
var file = path.join(projectDir, fileName + '.yml'); | |
// Add that file to our compose list | |
app.compose.push(lando.utils.compose(file, compose)); | |
lando.log.verbose('App %s has proxy compose file %s', project, file); | |
}); | |
}, pre-terminus=function () { | |
if (_.get(lando.tasks.argv()._, '[1]') === 'auth:login') { | |
if (_.has(lando.tasks.argv(), 'machineToken')) { | |
// Build the cache | |
// @TODO: what do do about email? | |
var token = _.get(lando.tasks.argv(), 'machineToken'); | |
var data = {token: token}; | |
// Mix in any existing cache data | |
if (!_.isEmpty(lando.cache.get(siteMetaDataKey + app.name))) { | |
data = _.merge(lando.cache.get(siteMetaDataKey + app.name), data); | |
} | |
// Reset the cache | |
lando.cache.set(siteMetaDataKey + app.name, data, {persist: true}); | |
} | |
} | |
}, post-destroy=function () { | |
lando.cache.remove(siteMetaDataKey + app.name); | |
}, _eventsCount=7, _maxListeners=20, , root=/home/hpottinger/workspace/lando-tomcat, rootBind=/home/hpottinger/workspace/lando-tomcat, mount=/app, tasks=[command=config, describe=Display the lando configuration, run=function () { | |
console.log(JSON.stringify(lando.config, null, 2)); | |
}, name=config, command=destroy [appname], describe=Destroy app in current directory or [appname], describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to DESTROY?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('DESTRUCTION AVERTED!')); | |
return; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.destroy(app) | |
.then(function() { | |
console.log(chalk.red('App destroyed!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=destroy, command=info [appname], describe=Prints info about app in current directory or [appname], describe=Get ALL the info, alias=[d], default=false, boolean=true, run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// GEt the app info | |
.then(function(app) { | |
if (app) { | |
// If this is deep, go deep | |
if (options.deep) { | |
return lando.engine.list(app.name) | |
.each(function(container) { | |
return lando.engine.inspect(container) | |
.then(function(data) { | |
console.log(JSON.stringify(data, null, 2)); | |
}); | |
}); | |
} | |
// Return the basic info | |
else { | |
return lando.app.info(app) | |
.then(function(info) { | |
console.log(JSON.stringify(info, null, 2)); | |
}); | |
} | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=info, command=list, describe=List all lando apps, run=function () { | |
// List all the apps | |
return lando.app.list() | |
// Map each app to a summary and print results | |
.map(function(app) { | |
return appSummary(app) | |
.then(function(summary) { | |
console.log(JSON.stringify(summary, null, 2)); | |
}); | |
}); | |
}, name=list, command=logs [appname], describe=Get logs for app in current directory or [appname], describe=Follow the logs, alias=[f], default=false, boolean=true, describe=Show logs for the specified services only, alias=[s], array=true, describe=Show log timestamps, alias=[t], default=false, boolean=true, run=function (options) { | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Destroy the app | |
.then(function(app) { | |
if (app) { | |
// Add opts to our app | |
app.opts.follow = options.follow; | |
app.opts.timestamps = options.timestamps; | |
app.opts.services = options.services; | |
// Get the logs | |
return lando.engine.logs(app); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=logs, command=poweroff, describe=Spin down all lando related containers, run=function () { | |
// Start | |
console.log(chalk.yellow('Spinning containers down... Standby.')); | |
// Get all our apps | |
return lando.app.list() | |
// SHUT IT ALL DOWN | |
.map(function(app) { | |
return lando.app.get(app.name) | |
.then(function(app) { | |
lando.app.stop(app); | |
}); | |
}) | |
// Emit poweroff | |
.then(function() { | |
return lando.events.emit('poweroff'); | |
}) | |
// Finish up | |
.then(function() { | |
console.log(chalk.red('Lando containers have been spun down.')); | |
}); | |
}, name=poweroff, command=rebuild [appname], describe=Rebuilds app in current directory or [appname], describe=Rebuild only the specified services, alias=[s], array=true, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, type=confirm, message=Are you sure you want to rebuild?, name=yes, weight=0, run=function (options) { | |
// Stop rebuild if user decides its a nogo | |
if (!options.yes) { | |
console.log(chalk.yellow('Rebuild aborted')); | |
return; | |
} | |
// Attempt to grab the app if we can | |
return lando.app.get(options.appname) | |
// Rebuild the app | |
.then(function(app) { | |
if (app) { | |
// Rebuild only particlar services if specified | |
if (!_.isEmpty(options.services)) { | |
app.opts.services = options.services; | |
} | |
return lando.app.rebuild(app) | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=rebuild, command=restart [appname], describe=Restarts app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Resttart the app | |
.then(function(app) { | |
if (app) { | |
// REstart the app | |
return lando.app.restart(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=restart, command=share [appname], describe=Get a publicly available url, describe=Url to share. Needs to be in the form http://localhost:port, alias=[u], required=true, run=function (options) { | |
// Do some validation of the url | |
var url = u.parse(options.url); | |
// Validate URL | |
var hnf = _.isEmpty(url.hostname) || url.hostname !== 'localhost'; | |
if (hnf || url.protocol !== 'http:') { | |
lando.log.error('Need a url of the form http://localhost:port!'); | |
lando.log.error('Run "lando info" for help finding the correct url!'); | |
process.exit(153); | |
} | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Get the sharing url | |
.then(function(app) { | |
if (app) { | |
// Start the app if needed | |
return lando.app.isRunning(app) | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Get the URLS | |
.then(function() { | |
// Assume a port to start | |
var port = 80; | |
// Override port if specified | |
if (!_.isEmpty(url.port)) { | |
port = url.port; | |
} | |
// Translate the app.name into a localtunnel suitable address | |
// eg lowercase/alphanumeric 4-63 chars | |
// lowercase and alphanumeric it | |
var tunnelHost = _.lowerCase(app.name).replace(/[^0-9a-z]/g, ''); | |
// Make sure we are at least 4 characters | |
if (_.size(tunnelHost) <= 4) { | |
tunnelHost = tunnelHost + 'xxxx'; | |
} | |
// Makes sure we are at most 64 chars | |
if (_.size(tunnelHost) >= 63) { | |
tunnelHost = tunnelHost.substring(0, 57); | |
} | |
// Build opts array | |
var opts = {subdomain: tunnelHost}; | |
// Set up the localtunnel | |
var tunnel = localtunnel(port, opts, function(err, tunnel) { | |
// Error if needed | |
if (err) { | |
lando.log.error(err); | |
} | |
// Header it | |
console.log(lando.cli.tunnelHeader()); | |
// the assigned public url for your tunnel | |
// i.e. https://abcdefgjhij.localtunnel.me | |
console.log(chalk.blue(tunnel.url)); | |
console.log(''); | |
console.log(chalk.yellow('Press any key to close the tunnel.')); | |
// Set stdin to the correct mode | |
process.stdin.resume(); | |
process.stdin.setEncoding('utf8'); | |
process.stdin.setRawMode(true); | |
// Start the keypress listener for the process | |
process.stdin.on('data', function() { | |
tunnel.close(); | |
}); | |
}); | |
tunnel.on('close', function() { | |
console.log(''); | |
console.log(chalk.green('Tunnel closed!')); | |
process.exit(0); | |
}); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=share, command=start [appname], describe=Start app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Start the app if we have one | |
.then(function(app) { | |
if (app) { | |
// Start the app | |
return lando.app.start(app) | |
// Report the app has started and some extra info | |
.then(function() { | |
// Header it | |
console.log(lando.cli.startHeader()); | |
// Spin up a url collector | |
var urls = {}; | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Categorize and colorize URLS if and as appropriate | |
_.forEach(app.info, function(info, service) { | |
if (_.has(info, 'urls') && !_.isEmpty(info.urls)) { | |
urls[service] = _.filter(app.urls, function(item) { | |
var good = chalk.green(item.url); | |
var bad = chalk.red(item.url); | |
item.theme = (item.status) ? good : bad; | |
return _.includes(info.urls, item.url); | |
}); | |
} | |
}); | |
// Add generic data | |
table.add('NAME', app.name); | |
table.add('LOCATION', app.root); | |
table.add('SERVICES', _.keys(app.services)); | |
// Add service URLS | |
_.forEach(urls, function(items, service) { | |
// Build table data | |
var header = _.upperCase(service) + ' URLS'; | |
var data = _.map(items, 'theme'); | |
// And add to table | |
table.add('', ''); | |
table.add(header, data, {arrayJoiner: '\n'}); | |
}); | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=start, command=stop [appname], describe=Stops app in current directory or [appname], run=function (options) { | |
// Try to get the app | |
return lando.app.get(options.appname) | |
// Restart the app | |
.then(function(app) { | |
if (app) { | |
return lando.app.stop(app) | |
.then(function() { | |
console.log(chalk.red('App stopped!')); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=stop, command=version, describe=Display the lando version, run=function () { | |
console.log('v' + lando.config.version); | |
}, name=version, command=ssh [appname] [service], describe=SSH into [service] in current app directory or [appname], describe=Run a command in the service, alias=[c], describe=Run as a specific user, alias=[u], run=function (options) { | |
// Handle our options | |
if (!_.has(options, 'service') && _.has(options, 'appname')) { | |
options.service = options.appname; | |
options.appname = undefined; | |
} | |
// Try to get the app if we can | |
return lando.app.get(options.appname) | |
// Handle app or no app | |
.then(function(app) { | |
// We have an app so lets try to build a ssh exec | |
if (app) { | |
// Default to appserver if we have no second arg | |
var service = options.service || 'appserver'; | |
// Build out our run | |
var run = { | |
id: [app.dockerName, service, '1'].join('_'), | |
compose: app.compose, | |
project: app.name, | |
cmd: options.command || 'cd $LANDO_MOUNT && bash', | |
opts: { | |
app: app, | |
mode: 'attach', | |
user: options.user || 'www-data', | |
services: [service] | |
} | |
}; | |
// Let's check to see if the app has been started | |
return lando.app.isRunning(app) | |
// If not let's make sure we start it | |
.then(function(isRunning) { | |
if (!isRunning) { | |
return lando.app.start(app); | |
} | |
}) | |
// Exec | |
.then(function() { | |
return lando.engine.run(run); | |
}); | |
} | |
// Warn user we couldn't find an app | |
else { | |
lando.log.warn('Could not find app in this dir'); | |
} | |
}); | |
}, name=ssh, command=init [method], describe=Initialize a lando app, optional methods: github, pantheon, describe=The recipe to use, choices=[custom, backdrop, drupal6, drupal7, drupal8, joomla, laravel, lamp, lemp, mean, pantheon, wordpress], alias=[r], string=true, type=list, message=What recipe do you want to use?, default=custom, choices=[name=custom, value=custom, name=backdrop, value=backdrop, name=drupal6, value=drupal6, name=drupal7, value=drupal7, name=drupal8, value=drupal8, name=joomla, value=joomla, name=laravel, value=laravel, name=lamp, value=lamp, name=lemp, value=lemp, name=mean, value=mean, name=pantheon, value=pantheon, name=wordpress, value=wordpress], weight=500, name=recipe, describe=GitHub token or email of previously used token, string=true, type=list, message=Choose a GitHub account, choices=[], when=function (answers) { | |
return !_.isEmpty(gitHubAccounts()) && askQuestions(answers); | |
}, weight=400, name=github-auth, name=github-auth, type=password, message=Enter a GitHub token, when=function (answers) { | |
var token = _.get(answers, 'github-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=401, describe=GitHub repo URL, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Repo collector | |
var repos = []; | |
// Spin things up | |
var tpath = 'github-auth'; | |
var token = _.get(lando.tasks.argv(), tpath, answers[tpath]); | |
var options = {affliation: 'owner,collaborator', 'per_page': 100}; | |
var done = this.async(); | |
// Check to see if token is cached already and use that | |
var tokens = lando.cache.get(tokenCacheKey) || {}; | |
if (_.includes(_.keys(tokens), token)) { | |
token = tokens[token]; | |
} | |
/* | |
* Helper to resursively load all our repos | |
*/ | |
var getAllRepos = function(err, res) { | |
// Error | |
if (err) { | |
lando.log.error('Problem getting sites from GitHub'); | |
} | |
// Add previous data to current | |
repos = repos.concat(res.data); | |
// IF we have more pages lets add them | |
if (github.hasNextPage(res)) { | |
github.getNextPage(res, getAllRepos); | |
} | |
// Otherwise lets send back our result | |
else { | |
done(null, _.map(repos, function(site) { | |
var name = _.get(site, 'full_name'); | |
var value = _.get(site, 'ssh_url'); | |
return {name: name, value: value}; | |
})); | |
} | |
}; | |
// Start the github authchain | |
github.authenticate({type: 'token', token: token}); | |
// Get all our sites | |
github.repos.getAll(options, getAllRepos); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=402, name=github-repo, describe=Pantheon machine token or email of previously used token, string=true, type=list, message=Choose a Pantheon account, choices=[], when=function (answers) { | |
return !_.isEmpty(pantheonAccounts()) && askQuestions(answers); | |
}, weight=600, name=pantheon-auth, name=pantheon-auth, type=password, message=Enter a Pantheon machine token, when=function (answers) { | |
var token = _.get(answers, 'pantheon-auth'); | |
return (!token || token === 'more') && askQuestions(answers); | |
}, weight=601, describe=Pantheon site machine name, string=true, type=list, message=Which site?, choices=function (answers) { | |
// Token path | |
var tpath = 'pantheon-auth'; | |
// Make this async cause we need to hit the terminus | |
var done = this.async(); | |
// Get the pantheon sites using the token | |
api.getSites(_.get(lando.tasks.argv(), tpath, answers[tpath])) | |
// Parse the sites into choices | |
.map(function(site) { | |
return {name: site.name, value: site.name}; | |
}) | |
// Done | |
.then(function(sites) { | |
done(null, sites); | |
}); | |
}, when=function (answers) { | |
return askQuestions(answers); | |
}, weight=602, name=pantheon-site, describe=Specify where to init the app, alias=[dest, d], string=true, default=/home/hpottinger/workspace/lando-tomcat, describe=Specify the webroot relative to destination, string=true, type=input, message=Where is your webroot relative to the init destination?, default=., when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.webroot(recipe); | |
}, weight=900, name=webroot, describe=The name of the app, string=true, type=input, message=What do you want to call this app?, default=My Lando App, filter=function (value) { | |
if (value) { | |
return _.kebabCase(value); | |
} | |
}, when=function (answers) { | |
var recipe = answers.recipe || lando.tasks.argv().recipe; | |
return lando.recipes.name(recipe); | |
}, weight=1000, name=name, describe=Auto answer yes to prompts, alias=[y], default=false, boolean=true, run=function (options) { | |
// Set the basics | |
var config = { | |
name: options.name, | |
recipe: options.recipe, | |
}; | |
// If we have a webroot let's set it | |
if (!_.isEmpty(options.webroot)) { | |
_.set(config, 'config.webroot', options.webroot); | |
} | |
// Method specific build steps if applicable | |
return Promise.try(function() { | |
return lando.init.build(config.name, options.method, options); | |
}) | |
// Kill any build containers if needed | |
.then(function() { | |
return lando.init.kill(config.name, options.destination); | |
}) | |
// Check to see if our recipe provides additional yaml augment | |
.then(function() { | |
return lando.init.yaml(options.recipe, config, options); | |
}) | |
// Create the lando yml | |
.then(function(config) { | |
// Where are we going? | |
var dest = path.join(options.destination, '.lando.yml'); | |
// Rebase on top of any existing yaml | |
if (fs.existsSync(dest)) { | |
var pec = lando.yaml.load(dest); | |
config = _.mergeWith(pec, config, lando.utils.merger); | |
} | |
// Dump it | |
lando.yaml.dump(dest, config); | |
}) | |
// Tell the user things | |
.then(function() { | |
// Header it | |
console.log(lando.cli.initHeader()); | |
// Grab a new cli table | |
var table = new lando.cli.Table(); | |
// Get docs link | |
var docBase = 'https://docs.devwithlando.io/tutorials/'; | |
var docUrl = docBase + config.recipe + '.html'; | |
// Add data | |
table.add('NAME', config.name); | |
table.add('RECIPE', options.recipe); | |
table.add('DOCS', docUrl); | |
// Add some other things if needed | |
if (!_.isEmpty(options.method)) { | |
table.add('METHOD', options.method); | |
} | |
// Print the table | |
console.log(table.toString()); | |
// Space it | |
console.log(''); | |
}); | |
}, name=init], webRoot=., status=function () { | |
var args = _.toArray(arguments); | |
var msg = util.format.apply(null, args); | |
return app.events.emit('status', msg) | |
// Make sure app status messages make it to global status. | |
.then(function() { | |
lando.log.info(msg); | |
}); | |
}, trollForStatus=function (msg) { | |
// Update status when pulling an image. | |
var images = msg.match(/Pulling from (.*)/); | |
if (images) { | |
app.status('Pulling image %s.', images[1]); | |
} | |
}, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, io.lando.container=TRUE, project=tomcat-demo, compose=[], image=tomcat:latest, ports=[8080], TERM=xterm, LANDO_WEBROOT=/app/./webapps, LANDO_SERVICE_NAME=tomcat, LANDO_SERVICE_TYPE=tomcat, LANDO_MOUNT=/app, LANDO=ON, LANDO_HOST_OS=linux, LANDO_HOST_UID=1000, LANDO_HOST_GID=1000, LANDO_HOST_IP=192.168.11.16, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_NAME=tomcat-demo, LANDO_WEBROOT_USER=www-data, LANDO_WEBROOT_GROUP=www-data, LANDO_WEBROOT_UID=33, LANDO_WEBROOT_GID=33, LANDO_LOAD_PP_KEYS=false, COLUMNS=256, volumes=[/home/hpottinger/.lando/services/config/tomcat/context.xml:/usr/local/tomcat/conf/context.xml, $LANDO_ENGINE_SCRIPTS_DIR/lando-entrypoint.sh:/lando-entrypoint.sh, $LANDO_APP_ROOT_BIND:/app, $LANDO_ENGINE_HOME:/user, $LANDO_ENGINE_SCRIPTS_DIR/user-perms.sh:/user-perms.sh, /home/hpottinger/.lando/services/config/scripts/load-keys.sh:/scripts/load-keys.sh, /home/hpottinger/.lando/services/config/helpers/mysql-import.sh:/helpers/mysql-import.sh, /home/hpottinger/.lando/services/config/helpers/mysql-export.sh:/helpers/mysql-export.sh], command=catalina.sh run, entrypoint=/lando-entrypoint.sh, io.lando.container=TRUE, , , mode=collect | |
verbose: Running spawn /usr/share/lando/bin/docker-compose with args ["--project-name","tomcat-demo","--file","/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-2.yml","--file","/home/hpottinger/.lando/tmp/tomcat-demo/tomcat-demo-proxy-3.yml","up","-d","--remove-orphans"] | |
debug: In mode collect with detached false | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
Creating tomcatdemo_tomcat_1 ... | |
Creating tomcatdemo_tomcat_1 ... done | |
verbose: Spawn exited with code: 0 | |
silly: Spawn finished with | |
verbose: Emitting event post-engine-start | |
debug: Event post-engine-start has 0 listeners | |
verbose: Emitting event post-start | |
debug: Event post-start has 4 listeners | |
debug: Retrieved from memcache with key engineUp | |
debug: Retrieved from memcache with key engineUp | |
debug: Retrieved from memcache with key engineUp | |
debug: Run proxy service from /home/hpottinger/.lando/proxy/proxy.yml | |
debug: Retrieved from memcache with key engineUp | |
debug: About to run 0=/usr/share/lando/bin/docker-compose, 1=--project-name, 2=landoproxyhyperion5000gandalfedition, 3=--file, 4=/home/hpottinger/.lando/proxy/proxy.yml, 5=ps, 6=-q, 7=proxy | |
silly: With pre run opts app=undefined | |
verbose: Running exec /usr/share/lando/bin/docker-compose,--project-name,landoproxyhyperion5000gandalfedition,--file,/home/hpottinger/.lando/proxy/proxy.yml,ps,-q,proxy | |
debug: With env XDG_VTNR=7, MANPATH=:/home/hpottinger/.fzf/man, ORBIT_SOCKETDIR=/tmp/orbit-hpottinger, XDG_SESSION_ID=c2, XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/hpottinger, TERMINATOR_UUID=urn:uuid:2bea968c-967f-4f46-a802-48fe97a3efe2, IBUS_DISABLE_SNOOPER=1, CLUTTER_IM_MODULE=xim, SESSION=ubuntu, GIO_LAUNCHED_DESKTOP_FILE_PID=2706, GPG_AGENT_INFO=/home/hpottinger/.gnupg/S.gpg-agent:0:1, TERM=xterm, SHELL=/bin/bash, NLS_LANG=AMERICAN_AMERICA.UTF8, QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1, WINDOWID=102760452, UPSTART_SESSION=unix:abstract=/com/ubuntu/upstart-session/1000/1607, GNOME_KEYRING_CONTROL=, GTK_MODULES=gail:atk-bridge:unity-gtk-module, USER=hpottinger, LD_LIBRARY_PATH=/usr/local/oracle:, QT_ACCESSIBILITY=1, XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0, XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0, SSH_AUTH_SOCK=/run/user/1000/keyring/ssh, DEFAULTS_PATH=/usr/share/gconf/ubuntu.default.path, GIO_LAUNCHED_DESKTOP_FILE=/home/hpottinger/.config/autostart/mutate.desktop, XDG_CONFIG_DIRS=/etc/xdg/xdg-ubuntu:/usr/share/upstart/xdg:/etc/xdg, DESKTOP_SESSION=ubuntu, PATH=/usr/share/lando/bin:/usr/local/oracle:/home/hpottinger/bin:/usr/local/sbin:/usr/local/bin:/home/hpottinger/gocode//bin:/usr/local/idea/bin:/home/hpottinger/.rbenv/shims:/home/hpottinger/bin:/home/hpottinger/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin:/usr/local/idea/bin:/usr/local/visualvm/bin:/usr/local/yjp/bin:/usr/local/node/bin:/bin:/bin:/home/hpottinger/.fzf/bin, QT_IM_MODULE=ibus, QT_QPA_PLATFORMTHEME=appmenu-qt5, XDG_SESSION_TYPE=x11, PWD=/home/hpottinger/.lando, JOB=dbus, XMODIFIERS=@im=ibus, GNOME_KEYRING_PID=, LANG=en_US.UTF-8, GDM_LANG=en_US, MANDATORY_PATH=/usr/share/gconf/ubuntu.mandatory.path, COMPIZ_CONFIG_PROFILE=ubuntu, IM_CONFIG_PHASE=1, SQLPATH=/usr/local/oracle:, GDMSESSION=ubuntu, SESSIONTYPE=gnome-session, GTK2_MODULES=overlay-scrollbar, SHLVL=1, HOME=/home/hpottinger, XDG_SEAT=seat0, LANGUAGE=en_US, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, UPSTART_INSTANCE=, XDG_SESSION_DESKTOP=ubuntu, UPSTART_EVENTS=xsession started, LOGNAME=hpottinger, _fzf_completion_loaded=0.11.3, COMPIZ_BIN_PATH=/usr/bin/, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-2gUpZJDvVI, XDG_DATA_DIRS=/usr/share/ubuntu:/usr/share/gnome:/usr/local/share:/usr/share:/var/lib/snapd/desktop:/var/lib/snapd/desktop, QT4_IM_MODULE=ibus, GOPATH=/home/hpottinger/gocode/, INSTANCE=, UPSTART_JOB=unity7, XDG_RUNTIME_DIR=/run/user/1000, DISPLAY=:0, ORACLE_HOME=/usr/local/oracle, XDG_CURRENT_DESKTOP=Unity, GTK_IM_MODULE=ibus, _fzf_orig_completion_git=complete -o bashdefault -o default -o nospace -F %s git #__git_wrap__git_main, XAUTHORITY=/home/hpottinger/.Xauthority, COLORTERM=gnome-terminal, _=/usr/local/bin/lando.dev, OLDPWD=/home/hpottinger/.lando/services, XDG_MENU_PREFIX=gnome-, SESSION_MANAGER=local/hpottinger-Oryx-Pro:@/tmp/.ICE-unix/2299,unix/hpottinger-Oryx-Pro:/tmp/.ICE-unix/2299, LANDO_ENGINE_ID=1000, LANDO_ENGINE_GID=1000, LANDO_ENGINE_HOME=/home/hpottinger, LANDO_ENGINE_IP=tcp://127.0.0.1, LANDO_ENGINE_REMOTE_IP=192.168.11.16, LANDO_ENGINE_CONFIG_DIR=/home/hpottinger/.lando/services/config, LANDO_ENGINE_SCRIPTS_DIR=/home/hpottinger/.lando/services/config/scripts, LANDO_ENGINE_HELPERS_DIR=/home/hpottinger/.lando/services/config/helpers, LANDO_APP_NAME=tomcat-demo, LANDO_APP_ROOT=/home/hpottinger/workspace/lando-tomcat, LANDO_APP_ROOT_BIND=/home/hpottinger/workspace/lando-tomcat | |
debug: Adding app URLs 0=[] | |
debug: Starting url scan with opts max=17, waitCodes=[400, 502, 404] | |
debug: URL scan results | |
BOOMSHAKALAKA!!! | |
Your app has started up correctly. | |
Here are some vitals: | |
NAME tomcat-demo | |
LOCATION /home/hpottinger/workspace/lando-tomcat | |
SERVICES tomcat |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment