diff --git a/README.md b/README.md index 46317d5..eaebf72 100644 --- a/README.md +++ b/README.md @@ -160,9 +160,11 @@ All Keys that are in **bold** are required | ports | List of Strings | The ports that should be "published" using the same notation as the `--publish` option to `docker run` | | mounts | List of Strings | List of mounts in the format `SOURCE_ON_HOST:DESTINATION_IN_CONTAINER`. If using a relative path then the paths are relative to the project's root | | run_opts | List of Strings | Additional options to pass to `docker run`. Each CLI arg must be it's own element. For example: `[ '--ip', '172.30.255.2' ]` would become `docker run --ip 172.30.255.2 IMAGE COMMAND` etc... | -| pre_scripts | List of Strings | Scripts to run *before* starting the component's container. These are only executed the first time a component is started, and are part of the 'provisioning' steps. The string follows the [Script Runner Syntax](#script-runner-syntax) | +| pre_scripts | List of Strings | Scripts to run *before* starting the component's container. These are only executed the first time a component is started, and are part of the 'provisioning' steps. These scripts are run in an interactive mode, so output is to your console, and not wrapped in log output. The string follows the [Script Runner Syntax](#script-runner-syntax) | | scripts | List of Strings | Scripts to run *after* starting the component's container. These are only excecuted the first time a component is started, and are part of the 'provisioning' steps. The string follows the [Script Runner Syntax](#script-runner-syntax) | | post_up_scripts | List of Strings | Scripts to run *after* the component has been started and provisioned. These are executed ***EVERY*** single time the component is started. The string follows the [Script Runner Syntax](#script-runner-syntax) | +| down_scripts | List of Strings | Script to run before bringing a component "down". The string follows the [Script Runner Syntax](#script-runner-syntax) | +| post_down_scripts | List of Strings | Script to run *after* bringing a component "down". These scripts are run in an interactive mode, so output is to your console, and not wrapped in log output. The string follows the [Script Runner Syntax](#script-runner-syntax) | | status_script | String | Script to run for the component as part of the devlab [status](#status-action) action. The string follows the [Script Runner Syntax](#script-runner-syntax). The output must conform to the [Status Command API](#status-command-api) | | shell | String | The path to the shell inside the container that will be the default command when using the devlab [sh](#sh-action) action | | ordinal | Hash | This is used indicate the order of the components. When parallel execution is supported, the `group` key indicates the components that can be brought up at the same time, `number` indicates the order inside the group to start up | diff --git a/devlab_bench/actions/down.py b/devlab_bench/actions/down.py index 698a73b..fd74f58 100644 --- a/devlab_bench/actions/down.py +++ b/devlab_bench/actions/down.py @@ -6,7 +6,7 @@ import time import devlab_bench.helpers.docker -from devlab_bench.helpers.common import get_config, get_env_from_file, get_components, get_ordinal_sorting, save_env_file, unnest_list +from devlab_bench.helpers.common import get_config, get_env_from_file, get_components, get_ordinal_sorting, save_env_file, script_runner, script_runner_parse, unnest_list def action(components='*', rm=False, **kwargs): """ @@ -52,12 +52,28 @@ def action(components='*', rm=False, **kwargs): components_to_stop = get_ordinal_sorting(components_to_stop, config['components']) components_to_stop.reverse() for comp in components_to_stop: - comp_cont_name = '{}-devlab'.format(comp) #pylint: disable=duplicate-code + comp_cont_name = '{}-devlab'.format(comp) if comp == foreground_comp_name: - comp_type = config['foreground_component'].get('type', 'container') + comp_config = config['foreground_component'] else: - comp_type = config['components'][comp].get('type', 'container') + comp_config = config['components'][comp] + comp_type = comp_config.get('type', 'container') if comp_type == 'host': + if 'down_scripts' in comp_config: + errors = False + for script in comp_config['down_scripts']: + script_parse = script_runner_parse(script) + if not script_parse['name']: + if not script_parse['mode'] == 'host': + log.debug("Assuming Down-script is to be run on host, because the component type is 'host'") + script = 'host:{}'.format(script) + log.debug("Found Down script: '%s'", script) + script_ret = script_runner(script, name=comp_cont_name, interactive=False, log_output=True) + if script_ret[0] != 0: + errors = True + break + if errors: + break if up_env.get('{}_PID'.format(comp.upper()), None): comp_pid = int(up_env.get('{}_PID'.format(comp.upper()), 0)) if comp_pid: @@ -99,12 +115,47 @@ def action(components='*', rm=False, **kwargs): else: try: if 'up' in containers_dict[comp_cont_name]['status'].lower(): + if 'down_scripts' in comp_config: + errors = False + for script in comp_config['down_scripts']: + log.debug("Found Down script: '%s'", script) + script_ret = script_runner(script, name=comp_cont_name, interactive=False, log_output=True) + if script_ret[0] != 0: + errors = True + break + if errors: + break log.info("Component: Stopping container: %s...", comp) devlab_bench.helpers.docker.DOCKER.stop_container(comp_cont_name) else: + if 'down_scripts' in comp_config: + for script in comp_config['down_scripts']: + script_parse = script_runner_parse(script) + if not script_parse['name']: + if not script_parse['mode'] == 'host': + log.warning("Container already exited. Skipping discovered Post-Down script: '%s'", script) + continue log.info("Component: %s is already stopped. skipping...", comp) if rm: log.info("Removing container: %s", comp) devlab_bench.helpers.docker.DOCKER.rm_container(comp_cont_name, force=True) except KeyError: log.info("Component: %s has no container. skipping...", comp) + if 'post_down_scripts' in comp_config: + errors = False + for script in comp_config['post_down_scripts']: + log.debug("Found Post-Down script: '%s'", script) + #Because the component is now down, these scripts can't default to running inside + #the component container. Check to make sure that the script isn't going to try that + #and default to running on the host + script_parse = script_runner_parse(script) + if not script_parse['name']: + if not script_parse['mode'] == 'host': + log.warning("Post-Down scripts cannot run inside of the now down container: '%s' defaulting to running on your host. Consider changing your post down script to have a 'host:' prefix to avoid this warning", comp) + script = 'host:{}'.format(script) + script_ret = script_runner(script, name=comp_cont_name, interactive=True) + if script_ret[0] != 0: + errors = True + break + if errors: + break diff --git a/devlab_bench/actions/up.py b/devlab_bench/actions/up.py index 39c770e..9a3a379 100644 --- a/devlab_bench/actions/up.py +++ b/devlab_bench/actions/up.py @@ -279,7 +279,7 @@ def component_up(name, comp_config, skip_provision=False, keep_up_on_error=False if 'pre_scripts' in comp_config: for script in comp_config['pre_scripts']: log.debug("Found Pre script: '%s'", script) - script_ret = script_runner(script, name=comp_cont_name, interactive=True, log_output=True) + script_ret = script_runner(script, name=comp_cont_name, interactive=True) if script_ret[0] != 0: errors = True break