Skip to content

Instantly share code, notes, and snippets.

@hardyoyo
Created December 19, 2017 18:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hardyoyo/cb66844755d5b8f6a87ebdeb4a0bf5ff to your computer and use it in GitHub Desktop.
Save hardyoyo/cb66844755d5b8f6a87ebdeb4a0bf5ff to your computer and use it in GitHub Desktop.
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