From 530a624fedca9ffaadb65972868173836973cbef Mon Sep 17 00:00:00 2001 From: neillturner Date: Tue, 17 Apr 2018 15:25:46 +0100 Subject: [PATCH 01/11] Support volumes, deregistering task, info logging, increase wait time increment --- README.rst | 6 ++++-- ecs_deploy.py | 54 +++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index 634684d..3bcd5c9 100644 --- a/README.rst +++ b/README.rst @@ -45,7 +45,9 @@ To run the script:: -m | --min minumumHealthyPercent: The lower limit on the number of running tasks during a deployment. -M | --max maximumPercent: The upper limit on the number of running tasks during a deployment. -t | --timeout Default is 90s. Script monitors ECS Service for new task definition to be running. - -v | --verbose Verbose output + -v | --verbose Verbose output. + -vn | --volume-name The name of the volume. This name is referenced in the sourceVolume parameter of container definition mountPoints. + -vs | --volume-source-path The path on the host container instance where your data volume is stored. Examples: Simple (Using env vars for AWS settings): @@ -54,7 +56,7 @@ To run the script:: All options: - $ ecs-deploy-py -k ABC123 -s SECRETKEY -r us-east-1 -c production1 -n doorman-service -i docker.repo.com/doorman -m 50 -M 100 -t 240 -D 2 -v + $ ecs-deploy-py -k ABC123 -s SECRETKEY -r us-east-1 -c production1 -n doorman-service -i docker.repo.com/doorman -m 50 -M 100 -t 240 -D 2 -v -vn data -vs /tmp/ Using profiles (for STS delegated credentials, for instance): diff --git a/ecs_deploy.py b/ecs_deploy.py index 40527fc..741e413 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -11,14 +11,22 @@ import time import argparse import boto3 +import logging from botocore.exceptions import ClientError +logger = logging.getLogger() + class CLI(object): def __init__(self): # get args self.args = self._init_parser() + if self.args.get('verbose'): + logging.basicConfig(level=logging.INFO) + else: + logging.basicConfig(level=logging.ERROR) + # init boto3 client try: # optional aws credentials overrides @@ -30,11 +38,11 @@ def __init__(self): # init boto3 ecs client self.client = boto3.client('ecs', **credentials) except ClientError as err: - print('Failed to create boto3 client.\n%s' % err) + logger.error('Failed to create boto3 client.\n%s' % err) sys.exit(1) if not (self.args.get('task_definition') or self.args.get('service_name')): - print('Either task-definition or service-name must be provided.') + logger.error('Either task-definition or service-name must be provided.') sys.exit(1) # run script @@ -127,6 +135,18 @@ def _init_parser(self): help='Default is 90s. Script monitors ECS Service for new task \ definition to be running.') + parser.add_argument( + '-vn', + '--volume-name', + help='The name of the volume. This name is referenced in the \ + sourceVolume parameter of container definition mountPoints.') + + parser.add_argument( + '-vs', + '--volume-source-path', + help='The path on the host container instance where your data \ + volume is stored.') + parser.add_argument( '-e', '--tag-env-var', @@ -154,24 +174,35 @@ def _run_parser(self): self.service_name = self._service_name() self.task_definition = self.client_fn('describe_task_definition')['taskDefinition'] + + logger.info("Deregister current ECS task definition "+self.task_definition['family']+':'+str(self.task_definition['revision'])) + deregistered_task_definition = self.client_fn('deregister_task_definition')['taskDefinition'] + + logger.info("Registering new ECS task definition") self.new_task_definition = self.client_fn('register_task_definition')['taskDefinition'] + logger.info("New ECS task definition "+self.new_task_definition['family']+':'+str(self.new_task_definition['revision'])+' Registered') if self.task_definition: + logger.info("Updating ECS service: "+self.service_name) if not self.client_fn('update_service'): sys.exit(1) # loop for desired timeout timeout = self.args.get('timeout') or time.time() + 90 + logger.info("Will wait "+str(timeout)+" secs for ECS tasks to update") + wait_time = 0 while True: + logger.info("Waiting for ECS tasks to update......"+str(wait_time)+" secs") updated = False running_tasks = self.client_fn('describe_tasks')['tasks'] for task in running_tasks: if task['taskDefinitionArn'] == self.new_task_definition['taskDefinitionArn']: + logger.info("ECS task updated ") updated = True if updated or time.time() > timeout: sys.exit(0) - time.sleep(1) - + time.sleep(20) + wait_time = wait_time + 20 else: sys.exit(1) @@ -214,12 +245,23 @@ def client_kwargs(self, fn): elif fn == 'describe_task_definition': kwargs['taskDefinition'] = self.task_definition_name + elif fn == 'deregister_task_definition': + kwargs['taskDefinition'] = self.task_definition['family']+':'+ str(self.task_definition['revision']) + elif fn == 'register_task_definition': kwargs['family'] = self.task_definition['family'] kwargs['containerDefinitions'] = self.task_definition['containerDefinitions'] # optional kwargs from args if self.args.get('image'): kwargs['containerDefinitions'][0]['image'] = self.args.get('image') + if self.args.get('service_name') and self.args.get('volume_source_path'): + kwargs['volumes'] = [] + volumes_sourcePath_config = {} + volumes_sourcePath_config["sourcePath"] = self.args.get('volume_source_path') # '/tmp/' + volumes_config = {} + volumes_config['name'] = self.args.get('volume_name') # "data" + volumes_config['host'] = volumes_sourcePath_config + kwargs['volumes'].append(volumes_config) elif fn == 'update_service': kwargs['cluster'] = self.cluster @@ -252,10 +294,10 @@ def client_fn(self, fn): return response except ClientError as e: - print('ClientError: %s' % e) + logger.error('ClientError: %s' % e) sys.exit(1) except Exception as e: - print('Exception: %s' % e) + logger.error('Exception: %s' % e) sys.exit(1) if __name__ == '__main__': From 8da341cdf0571edbf03c50f1e8fe07b6976846be Mon Sep 17 00:00:00 2001 From: neillturner Date: Wed, 18 Apr 2018 13:22:45 +0100 Subject: [PATCH 02/11] DTA-544 production ECS deploys from bitbucket pipelines --- ecs_deploy.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index 741e413..46ae0f1 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -132,6 +132,7 @@ def _init_parser(self): parser.add_argument( '-t', '--timeout', + type=int, help='Default is 90s. Script monitors ECS Service for new task \ definition to be running.') @@ -188,8 +189,9 @@ def _run_parser(self): sys.exit(1) # loop for desired timeout - timeout = self.args.get('timeout') or time.time() + 90 + timeout = self.args.get('timeout') or 90 logger.info("Will wait "+str(timeout)+" secs for ECS tasks to update") + timeout = time.time() + timeout wait_time = 0 while True: logger.info("Waiting for ECS tasks to update......"+str(wait_time)+" secs") From 8da9e79c64712521e4c7c0b34585ce68540bdf40 Mon Sep 17 00:00:00 2001 From: neillturner Date: Wed, 18 Apr 2018 13:56:25 +0100 Subject: [PATCH 03/11] Support volumes, deregistering task, info logging, increase wait time increment --- ecs_deploy.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index 46ae0f1..4fa2f53 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -176,25 +176,25 @@ def _run_parser(self): self.task_definition = self.client_fn('describe_task_definition')['taskDefinition'] - logger.info("Deregister current ECS task definition "+self.task_definition['family']+':'+str(self.task_definition['revision'])) + logger.info("Deregister current ECS task definition " + self.task_definition['family'] + ':' + str(self.task_definition['revision'])) deregistered_task_definition = self.client_fn('deregister_task_definition')['taskDefinition'] logger.info("Registering new ECS task definition") self.new_task_definition = self.client_fn('register_task_definition')['taskDefinition'] - logger.info("New ECS task definition "+self.new_task_definition['family']+':'+str(self.new_task_definition['revision'])+' Registered') + logger.info("New ECS task definition " + self.new_task_definition['family'] + ':' + str(self.new_task_definition['revision']) + ' Registered') if self.task_definition: - logger.info("Updating ECS service: "+self.service_name) + logger.info("Updating ECS service: " + self.service_name) if not self.client_fn('update_service'): sys.exit(1) # loop for desired timeout timeout = self.args.get('timeout') or 90 - logger.info("Will wait "+str(timeout)+" secs for ECS tasks to update") + logger.info("Will wait " + str(timeout) + " secs for ECS tasks to update") timeout = time.time() + timeout wait_time = 0 while True: - logger.info("Waiting for ECS tasks to update......"+str(wait_time)+" secs") + logger.info("Waiting for ECS tasks to update......" + str(wait_time) + " secs") updated = False running_tasks = self.client_fn('describe_tasks')['tasks'] for task in running_tasks: @@ -248,7 +248,7 @@ def client_kwargs(self, fn): kwargs['taskDefinition'] = self.task_definition_name elif fn == 'deregister_task_definition': - kwargs['taskDefinition'] = self.task_definition['family']+':'+ str(self.task_definition['revision']) + kwargs['taskDefinition'] = self.task_definition['family'] + ':' + str(self.task_definition['revision']) elif fn == 'register_task_definition': kwargs['family'] = self.task_definition['family'] @@ -259,9 +259,9 @@ def client_kwargs(self, fn): if self.args.get('service_name') and self.args.get('volume_source_path'): kwargs['volumes'] = [] volumes_sourcePath_config = {} - volumes_sourcePath_config["sourcePath"] = self.args.get('volume_source_path') # '/tmp/' + volumes_sourcePath_config["sourcePath"] = self.args.get('volume_source_path') volumes_config = {} - volumes_config['name'] = self.args.get('volume_name') # "data" + volumes_config['name'] = self.args.get('volume_name') volumes_config['host'] = volumes_sourcePath_config kwargs['volumes'].append(volumes_config) From 03238d9b7d4a1891596e65f249c3283834f7c443 Mon Sep 17 00:00:00 2001 From: neillturner Date: Wed, 18 Apr 2018 14:04:21 +0100 Subject: [PATCH 04/11] Support volumes, deregistering task, info logging, increase wait time increment --- ecs_deploy.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index 4fa2f53..b94823f 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -176,12 +176,14 @@ def _run_parser(self): self.task_definition = self.client_fn('describe_task_definition')['taskDefinition'] - logger.info("Deregister current ECS task definition " + self.task_definition['family'] + ':' + str(self.task_definition['revision'])) - deregistered_task_definition = self.client_fn('deregister_task_definition')['taskDefinition'] + logger.info("Deregister current ECS task definition " + self.task_definition['family'] + + ':' + str(self.task_definition['revision'])) + self.client_fn('deregister_task_definition')['taskDefinition'] logger.info("Registering new ECS task definition") self.new_task_definition = self.client_fn('register_task_definition')['taskDefinition'] - logger.info("New ECS task definition " + self.new_task_definition['family'] + ':' + str(self.new_task_definition['revision']) + ' Registered') + logger.info("New ECS task definition " + self.new_task_definition['family'] + ':' + + str(self.new_task_definition['revision']) + ' Registered') if self.task_definition: logger.info("Updating ECS service: " + self.service_name) @@ -248,7 +250,8 @@ def client_kwargs(self, fn): kwargs['taskDefinition'] = self.task_definition_name elif fn == 'deregister_task_definition': - kwargs['taskDefinition'] = self.task_definition['family'] + ':' + str(self.task_definition['revision']) + kwargs['taskDefinition'] = self.task_definition['family'] + ':' + + str(self.task_definition['revision']) elif fn == 'register_task_definition': kwargs['family'] = self.task_definition['family'] From afcf0cab0673909c637f0d7303df0875edfb56cd Mon Sep 17 00:00:00 2001 From: neillturner Date: Wed, 18 Apr 2018 14:10:29 +0100 Subject: [PATCH 05/11] Support volumes, deregistering task, info logging, increase wait time increment --- ecs_deploy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index b94823f..09b7293 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -176,13 +176,13 @@ def _run_parser(self): self.task_definition = self.client_fn('describe_task_definition')['taskDefinition'] - logger.info("Deregister current ECS task definition " + self.task_definition['family'] + + logger.info("Deregister current ECS task definition " + self.task_definition['family'] + \ ':' + str(self.task_definition['revision'])) self.client_fn('deregister_task_definition')['taskDefinition'] logger.info("Registering new ECS task definition") self.new_task_definition = self.client_fn('register_task_definition')['taskDefinition'] - logger.info("New ECS task definition " + self.new_task_definition['family'] + ':' + + logger.info("New ECS task definition " + self.new_task_definition['family'] + ':' + \ str(self.new_task_definition['revision']) + ' Registered') if self.task_definition: @@ -250,7 +250,7 @@ def client_kwargs(self, fn): kwargs['taskDefinition'] = self.task_definition_name elif fn == 'deregister_task_definition': - kwargs['taskDefinition'] = self.task_definition['family'] + ':' + + kwargs['taskDefinition'] = self.task_definition['family'] + ':' + \ str(self.task_definition['revision']) elif fn == 'register_task_definition': From 64a66b4aa5722369f5db2d9db59bab81607c782e Mon Sep 17 00:00:00 2001 From: neillturner Date: Wed, 18 Apr 2018 14:14:58 +0100 Subject: [PATCH 06/11] Support volumes, deregistering task, info logging, increase wait time increment --- ecs_deploy.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index 09b7293..38825c0 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -176,13 +176,13 @@ def _run_parser(self): self.task_definition = self.client_fn('describe_task_definition')['taskDefinition'] - logger.info("Deregister current ECS task definition " + self.task_definition['family'] + \ + logger.info("Deregister current ECS task definition " + self.task_definition['family'] + ':' + str(self.task_definition['revision'])) self.client_fn('deregister_task_definition')['taskDefinition'] logger.info("Registering new ECS task definition") self.new_task_definition = self.client_fn('register_task_definition')['taskDefinition'] - logger.info("New ECS task definition " + self.new_task_definition['family'] + ':' + \ + logger.info("New ECS task definition " + self.new_task_definition['family'] + ':' + str(self.new_task_definition['revision']) + ' Registered') if self.task_definition: @@ -251,7 +251,7 @@ def client_kwargs(self, fn): elif fn == 'deregister_task_definition': kwargs['taskDefinition'] = self.task_definition['family'] + ':' + \ - str(self.task_definition['revision']) + str(self.task_definition['revision']) elif fn == 'register_task_definition': kwargs['family'] = self.task_definition['family'] From 48f0346c0c2f1a472a55fb700b0ca6baa416c9dc Mon Sep 17 00:00:00 2001 From: neillturner Date: Wed, 18 Apr 2018 14:23:18 +0100 Subject: [PATCH 07/11] Support volumes, deregistering task, info logging, increase wait time increment --- ecs_deploy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index 38825c0..1420256 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -251,7 +251,7 @@ def client_kwargs(self, fn): elif fn == 'deregister_task_definition': kwargs['taskDefinition'] = self.task_definition['family'] + ':' + \ - str(self.task_definition['revision']) + str(self.task_definition['revision']) elif fn == 'register_task_definition': kwargs['family'] = self.task_definition['family'] From 483712e6fdc15c438d429392a2d8254d78df9e59 Mon Sep 17 00:00:00 2001 From: neillturner Date: Thu, 19 Apr 2018 09:30:43 +0100 Subject: [PATCH 08/11] Support volumes, deregistering task, info logging, increase wait time increment --- ecs_deploy.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index 1420256..2fcbe17 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -196,15 +196,19 @@ def _run_parser(self): timeout = time.time() + timeout wait_time = 0 while True: - logger.info("Waiting for ECS tasks to update......" + str(wait_time) + " secs") + logger.info("Waiting for ECS task to update......" + str(wait_time) + " secs") updated = False running_tasks = self.client_fn('describe_tasks')['tasks'] for task in running_tasks: if task['taskDefinitionArn'] == self.new_task_definition['taskDefinitionArn']: - logger.info("ECS task updated ") + logger.info("ECS task updated") updated = True - if updated or time.time() > timeout: + if updated: sys.exit(0) + if time.time() > timeout: + logger.error("Timed out because ECS task had not updated after " + + str(wait_time) + " secs") + sys.exit(1) time.sleep(20) wait_time = wait_time + 20 else: From 69c901dc721438a9803ae5394d553b813c2178c0 Mon Sep 17 00:00:00 2001 From: neillturner Date: Thu, 19 Apr 2018 09:34:50 +0100 Subject: [PATCH 09/11] Support volumes, deregistering task, info logging, increase wait time increment --- ecs_deploy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index 2fcbe17..16c9913 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -208,7 +208,7 @@ def _run_parser(self): if time.time() > timeout: logger.error("Timed out because ECS task had not updated after " + str(wait_time) + " secs") - sys.exit(1) + sys.exit(1) time.sleep(20) wait_time = wait_time + 20 else: From 49bb251b1bc69f1da018598d87b75a1eafa24223 Mon Sep 17 00:00:00 2001 From: neillturner Date: Mon, 23 Apr 2018 15:40:58 +0100 Subject: [PATCH 10/11] Support volumes, deregistering task, info logging, increase wait time increment --- ecs_deploy.py | 48 ++++++++++++++++++++++++++++++++++++++++++------ requirements.txt | 12 ++++++------ 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index 16c9913..2c8faf0 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -154,6 +154,12 @@ def _init_parser(self): help='Get image tag name from environment variable. If provided \ this will override value specified in image name argument.') + parser.add_argument( + '-ev', + '--environment-variable', + help='environment variable to set in task definition. \ + specify var=value.') + parser.add_argument( '-v', '--verbose', @@ -176,9 +182,21 @@ def _run_parser(self): self.task_definition = self.client_fn('describe_task_definition')['taskDefinition'] - logger.info("Deregister current ECS task definition " + self.task_definition['family'] + - ':' + str(self.task_definition['revision'])) - self.client_fn('deregister_task_definition')['taskDefinition'] + if self.args.get('max_definitions'): + family = self.task_definition['family'] + max_definitions = self.args.get('max_definitions') + task_definitions = self.client_fn('list_task_definitions') + task_definition_arns = task_definitions['taskDefinitionArns'] + if len(task_definition_arns) > max_definitions: + logger.info("DeRegistering old ECS task definition as more than " + + str(max_definitions) + " for family " + family) + num_to_delete = len(task_definition_arns) - max_definitions + for task_def_arn in task_definition_arns: + if num_to_delete > 0: + self.deregister_task_definition = task_def_arn + logger.info("Deregistering old ECS task definition " + task_def_arn) + self.client_fn('deregister_task_definition') + num_to_delete = num_to_delete - 1 logger.info("Registering new ECS task definition") self.new_task_definition = self.client_fn('register_task_definition')['taskDefinition'] @@ -192,7 +210,7 @@ def _run_parser(self): # loop for desired timeout timeout = self.args.get('timeout') or 90 - logger.info("Will wait " + str(timeout) + " secs for ECS tasks to update") + logger.info("Will wait " + str(timeout) + " secs for first ECS task to update") timeout = time.time() + timeout wait_time = 0 while True: @@ -254,8 +272,7 @@ def client_kwargs(self, fn): kwargs['taskDefinition'] = self.task_definition_name elif fn == 'deregister_task_definition': - kwargs['taskDefinition'] = self.task_definition['family'] + ':' + \ - str(self.task_definition['revision']) + kwargs['taskDefinition'] = self.deregister_task_definition elif fn == 'register_task_definition': kwargs['family'] = self.task_definition['family'] @@ -263,6 +280,22 @@ def client_kwargs(self, fn): # optional kwargs from args if self.args.get('image'): kwargs['containerDefinitions'][0]['image'] = self.args.get('image') + var_updated = False + if self.args.get('environment_variable'): + logger.info("Updating environment variable " + self.args.get('environment_variable') + " in ECS task definition") + env_var = self.args.get('environment_variable').split("=") + env_vars = kwargs['containerDefinitions'][0]['environment'] + for var in env_vars: + if var['name'] == env_var[0]: + var['value'] = env_var[1] + var_updated = True + kwargs['containerDefinitions'][0]['environment'] = env_vars + if not var_updated: + kwargs['containerDefinitions'][0]['environment'].extend([ + { + 'name' : env_var[0], + 'value' : env_var[1] + }]) if self.args.get('service_name') and self.args.get('volume_source_path'): kwargs['volumes'] = [] volumes_sourcePath_config = {} @@ -285,6 +318,9 @@ def client_kwargs(self, fn): kwargs['deploymentConfiguration'] = deployment_config kwargs = self._arg_kwargs(kwargs, 'desired_count') + elif fn == 'list_task_definitions': + kwargs['familyPrefix'] = self.task_definition['family'] + elif fn == 'list_tasks': kwargs['cluster'] = self.cluster kwargs['serviceName'] = self.service_name diff --git a/requirements.txt b/requirements.txt index fc56728..1bf7fac 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ -boto3==1.4.0 -botocore==1.4.56 -docutils==0.12 +boto3==1.4.7 +botocore==1.7.33 +docutils==0.13.1 futures==3.0.5 -jmespath==0.9.0 -python-dateutil==2.5.3 -s3transfer==0.1.4 +jmespath==0.9.2 +python-dateutil==2.6.0 +s3transfer==0.1.10 six==1.10.0 From 8cc0155f5b807510cc10f685bac42f6e0809497b Mon Sep 17 00:00:00 2001 From: neillturner Date: Mon, 23 Apr 2018 15:48:12 +0100 Subject: [PATCH 11/11] Support volumes, deregistering task, info logging, increase wait time increment --- ecs_deploy.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ecs_deploy.py b/ecs_deploy.py index 2c8faf0..7383985 100644 --- a/ecs_deploy.py +++ b/ecs_deploy.py @@ -282,7 +282,8 @@ def client_kwargs(self, fn): kwargs['containerDefinitions'][0]['image'] = self.args.get('image') var_updated = False if self.args.get('environment_variable'): - logger.info("Updating environment variable " + self.args.get('environment_variable') + " in ECS task definition") + logger.info("Updating environment variable " + + self.args.get('environment_variable') + " in ECS task definition") env_var = self.args.get('environment_variable').split("=") env_vars = kwargs['containerDefinitions'][0]['environment'] for var in env_vars: @@ -291,11 +292,11 @@ def client_kwargs(self, fn): var_updated = True kwargs['containerDefinitions'][0]['environment'] = env_vars if not var_updated: - kwargs['containerDefinitions'][0]['environment'].extend([ - { - 'name' : env_var[0], - 'value' : env_var[1] - }]) + kwargs['containerDefinitions'][0]['environment'].extend([ + { + 'name': env_var[0], + 'value': env_var[1] + }]) if self.args.get('service_name') and self.args.get('volume_source_path'): kwargs['volumes'] = [] volumes_sourcePath_config = {}