diff --git a/ecs_deploy/cli.py b/ecs_deploy/cli.py index 800c019..91deb04 100644 --- a/ecs_deploy/cli.py +++ b/ecs_deploy/cli.py @@ -101,8 +101,7 @@ def deploy(cluster, service, tag, image, command, env, secret, role, execution_r success_message='Deployment successful', failure_message='Deployment failed', timeout=timeout, - deregister=deregister, - previous_task_definition=td, + task_definition_to_deregister=deregister and td, ignore_warnings=ignore_warnings, sleep_time=sleep_time ) @@ -297,9 +296,12 @@ def scale(cluster, service, desired_count, access_key_id, secret_access_key, reg @click.argument('cluster') @click.argument('task') @click.argument('count', required=False, default=1) +@click.option('-t', '--tag', help='Changes the tag for ALL container images') +@click.option('-i', '--image', type=(str, str), multiple=True, help='Overwrites the image for a container: ') @click.option('-c', '--command', type=(str, str), multiple=True, help='Overwrites the command in a container: ') @click.option('-e', '--env', type=(str, str, str), multiple=True, help='Adds or changes an environment variable: ') @click.option('-s', '--secret', type=(str, str, str), multiple=True, help='Adds or changes a secret environment variable from the AWS Parameter Store (Not available for Fargate): ') +@click.option('-r', '--role', type=str, help='Sets the task\'s role ARN: ') @click.option('--launchtype', type=click.Choice([LAUNCH_TYPE_EC2, LAUNCH_TYPE_FARGATE]), default=LAUNCH_TYPE_EC2, help='ECS Launch type (default: EC2)') @click.option('--subnet', type=str, multiple=True, help='A subnet ID to launch the task within. Required for launch type FARGATE (multiple values possible)') @click.option('--securitygroup', type=str, multiple=True, help='A security group ID to launch the task within. Required for launch type FARGATE (multiple values possible)') @@ -308,8 +310,13 @@ def scale(cluster, service, desired_count, access_key_id, secret_access_key, reg @click.option('--access-key-id', help='AWS access key id') @click.option('--secret-access-key', help='AWS secret access key') @click.option('--profile', help='AWS configuration profile name') +@click.option('--timeout', default=300, type=int, help='Amount of seconds to wait for task to finish before command fails (default: 300). To disable timeout (fire and forget) set to -1') +@click.option('--sleep-time', default=1, type=int, help='Amount of seconds to wait between each check of the service (default: 1)') @click.option('--diff/--no-diff', default=True, help='Print what values were changed in the task definition') -def run(cluster, task, count, command, env, secret, launchtype, subnet, securitygroup, public_ip, region, access_key_id, secret_access_key, profile, diff): +@click.option('--exclusive-env', is_flag=True, default=False, help='Set the given environment variables exclusively and remove all other pre-existing env variables from all containers') +@click.option('--exclusive-secrets', is_flag=True, default=False, help='Set the given secrets exclusively and remove all other pre-existing secrets from all containers') +@click.option('--deregister/--no-deregister', default=True, help='Deregister or keep the old task definition (default: --deregister)') +def run(cluster, task, count, tag, image, command, env, secret, role, launchtype, subnet, securitygroup, public_ip, region, access_key_id, secret_access_key, profile, timeout, sleep_time, diff, exclusive_env, exclusive_secrets, deregister): """ Run a one-off task. @@ -318,18 +325,24 @@ def run(cluster, task, count, command, env, secret, launchtype, subnet, security TASK is the name of your task definition (e.g. 'my-task') within ECS. COUNT is the number of tasks your service should run. """ + should_create_task_definition = image or tag or role try: client = get_client(access_key_id, secret_access_key, region, profile) action = RunAction(client, cluster) - td = action.get_task_definition(task) + td = td_old = action.get_task_definition(task) + td.set_images(tag, **{key: value for (key, value) in image}) td.set_commands(**{key: value for (key, value) in command}) - td.set_environment(env) - td.set_secrets(secret) + td.set_environment(env, exclusive_env) + td.set_secrets(secret, exclusive_secrets) + td.set_role_arn(role) if diff: print_diff(td, 'Using task definition: %s' % task) + if should_create_task_definition: + td = create_task_definition(action, td) + action.run(td, count, 'ECS Deploy', launchtype, subnet, securitygroup, public_ip) click.secho( @@ -344,6 +357,18 @@ def run(cluster, task, count, command, env, secret, launchtype, subnet, security click.secho('- %s' % started_task['taskArn'], fg='green') click.secho(' ') + exit_code = wait_for_task( + action=action, + timeout=timeout, + title='Running task', + sleep_time=sleep_time, + ) + + if should_create_task_definition and deregister: + deregister_task_definition(action, td_old) + + exit(exit_code) + except EcsError as e: click.secho('%s\n' % str(e), fg='red', err=True) exit(1) @@ -395,6 +420,33 @@ def diff(task, revision_a, revision_b, region, access_key_id, secret_access_key, exit(1) +def wait_for_task(action, timeout, title, sleep_time=1): + click.secho(title, nl=False) + waiting_timeout = datetime.now() + timedelta(seconds=timeout) + tasks_arn = [task[u'taskArn'] for task in action.started_tasks] + + if timeout == -1: + waiting = False + else: + waiting = True + + exit_code = 0 + + while waiting and datetime.now() < waiting_timeout: + click.secho('.', nl=False) + waiting = False + + for task in action.get_tasks(tasks_arn): + if task.is_stopped: + exit_code = exit_code or task.exit_code + else: + waiting = True + if waiting: + sleep(sleep_time) + + return exit_code + + def wait_for_finish(action, timeout, title, success_message, failure_message, ignore_warnings, sleep_time=1): click.secho(title, nl=False) @@ -433,9 +485,8 @@ def wait_for_finish(action, timeout, title, success_message, failure_message, click.secho('\n%s\n' % success_message, fg='green') -def deploy_task_definition(deployment, task_definition, title, success_message, - failure_message, timeout, deregister, - previous_task_definition, ignore_warnings, sleep_time): +def deploy_task_definition(deployment, task_definition, title, success_message, failure_message, timeout, + ignore_warnings, sleep_time, task_definition_to_deregister=None): click.secho('Updating service') deployment.deploy(task_definition) @@ -456,8 +507,8 @@ def deploy_task_definition(deployment, task_definition, title, success_message, sleep_time=sleep_time ) - if deregister: - deregister_task_definition(deployment, previous_task_definition) + if task_definition_to_deregister: + deregister_task_definition(deployment, task_definition_to_deregister) def get_task_definition(action, task): @@ -501,8 +552,7 @@ def rollback_task_definition(deployment, old, new, timeout=600, sleep_time=1): success_message='Rollback successful', failure_message='Rollback failed. Please check ECS Console', timeout=timeout, - deregister=True, - previous_task_definition=new, + task_definition_to_deregister=new, ignore_warnings=False, sleep_time=sleep_time ) diff --git a/ecs_deploy/ecs.py b/ecs_deploy/ecs.py index 6e99d91..5dbe835 100644 --- a/ecs_deploy/ecs.py +++ b/ecs_deploy/ecs.py @@ -194,6 +194,30 @@ def get_warnings(self, since=None, until=None): return errors +class EcsTask(dict): + def __init__(self, cluster, task=None, **kwargs): + self._cluster = cluster + super(EcsTask, self).__init__(task, **kwargs) + + @property + def status(self): + return self.get(u'lastStatus') + + @property + def is_stopped(self): + return self.status == u'STOPPED' + + @property + def exit_code(self): + if not self.is_stopped: + raise ValueError('exit_code only can be invoked when task is stopped') + + exit_code = 0 + for container in self.get(u'containers'): + exit_code = exit_code or container.get(u'exitCode') + return exit_code + + class EcsTaskDefinition(object): def __init__(self, containerDefinitions, volumes, family, revision, status, taskDefinitionArn, requiresAttributes=None, @@ -697,6 +721,13 @@ def run(self, task_definition, count, started_by, launchtype, subnets, except ClientError as e: raise EcsError(str(e)) + def get_tasks(self, tasks_arn): + tasks_details = self._client.describe_tasks( + cluster_name=self._cluster_name, + task_arns=tasks_arn, + ) + return map(lambda payload: EcsTask(cluster=self._cluster_name, task=payload), tasks_details['tasks']) + class UpdateAction(EcsAction): def __init__(self, client): diff --git a/tests/test_cli.py b/tests/test_cli.py index 534cae1..1fa1004 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -10,8 +10,7 @@ from ecs_deploy.newrelic import Deployment, NewRelicDeploymentException from tests.test_ecs import EcsTestClient, CLUSTER_NAME, SERVICE_NAME, \ TASK_DEFINITION_ARN_1, TASK_DEFINITION_ARN_2, TASK_DEFINITION_FAMILY_1, \ - TASK_DEFINITION_REVISION_2, TASK_DEFINITION_REVISION_1, \ - TASK_DEFINITION_REVISION_3 + TASK_DEFINITION_REVISION_1, TASK_DEFINITION_REVISION_3, TASK_ARN_1, TASK_ARN_2 @pytest.fixture @@ -616,60 +615,271 @@ def test_scale_without_credentials(get_client, runner): @patch('ecs_deploy.cli.get_client') def test_run_task(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task')) - assert not result.exception - assert result.exit_code == 0 + assert result.exit_code == 123 assert u"Successfully started 2 instances of task: test-task:2" in result.output - assert u"- arn:foo:bar" in result.output - assert u"- arn:lorem:ipsum" in result.output + assert u'Successfully deregistered revision: 2' not in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output @patch('ecs_deploy.cli.get_client') -def test_run_task_with_command(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-c', 'webserver', 'date')) +def test_run_with_role_arn_deregister_old_task_definiion(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task:1', '2', '-r', 'arn:new:role')) + assert result.exit_code == 123 + assert u"Using task definition: test-task" in result.output + assert u'Changed role_arn to: "arn:new:role" (was: "arn:test:role:1")' in result.output + assert u"Creating new task definition revision" in result.output + assert u'Successfully created revision: 2' in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert u'Successfully deregistered revision: 1' in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output - assert not result.exception - assert result.exit_code == 0 +@patch('ecs_deploy.cli.get_client') +def test_run_with_role_arn_keep_old_task_definiion(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task:1', '2', '-r', 'arn:new:role', '--no-deregister')) + assert result.exit_code == 123 assert u"Using task definition: test-task" in result.output - assert u'Changed command of container "webserver" to: "date" (was: "run")' in result.output + assert u'Changed role_arn to: "arn:new:role" (was: "arn:test:role:1")' in result.output + assert u"Creating new task definition revision" in result.output + assert u'Successfully created revision: 2' in result.output assert u"Successfully started 2 instances of task: test-task:2" in result.output - assert u"- arn:foo:bar" in result.output - assert u"- arn:lorem:ipsum" in result.output + assert u'Successfully deregistered revision: 1' not in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output @patch('ecs_deploy.cli.get_client') -def test_run_task_with_environment_var(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') +def test_run_new_tag(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-t', 'latest')) + assert result.exit_code == 123 + assert u"Using task definition: test-task" in result.output + assert u"Creating new task definition revision" in result.output + assert u'Changed image of container "webserver" to: "webserver:latest" (was: "webserver:123")' in result.output + assert u'Changed image of container "application" to: "application:latest" (was: "application:123")' in result.output + assert u'Successfully created revision: 2' in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_one_new_image(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-i', 'application', 'application:latest')) + assert result.exit_code == 123 + assert u"Using task definition: test-task" in result.output + assert u"Creating new task definition revision" in result.output + assert u'Changed image of container "application" to: "application:latest" (was: "application:123")' in result.output + assert u'Successfully created revision: 2' in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_two_new_images(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-i', 'application', 'application:latest', + '-i', 'webserver', 'webserver:latest')) + assert result.exit_code == 123 + assert u"Using task definition: test-task" in result.output + assert u"Creating new task definition revision" in result.output + assert u'Changed image of container "webserver" to: "webserver:latest" (was: "webserver:123")' in result.output + assert u'Changed image of container "application" to: "application:latest" (was: "application:123")' in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_one_new_command(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-c', 'application', 'date')) + assert result.exit_code == 123 + assert u"Using task definition: test-task" in result.output + assert u'Changed command of container "application" to: "date" (was: "run")' in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_one_new_environment_variable(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-e', 'application', 'foo', 'bar')) - assert not result.exception - assert result.exit_code == 0 + assert result.exit_code == 123 assert u"Using task definition: test-task" in result.output assert u'Changed environment "foo" of container "application" to: "bar"' in result.output assert u"Successfully started 2 instances of task: test-task:2" in result.output - assert u"- arn:foo:bar" in result.output - assert u"- arn:lorem:ipsum" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_change_environment_variable_empty_string(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-e', 'application', 'foo', '')) + + assert result.exit_code == 123 + + assert u"Using task definition: test-task" in result.output + assert u'Changed environment "foo" of container "application" to: ""' in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_new_empty_environment_variable(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-e', 'application', 'new', '')) + + assert result.exit_code == 123 + + assert u"Using task definition: test-task" in result.output + assert u'Changed environment "new" of container "application" to: ""' in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_empty_environment_variable_again(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-e', 'webserver', 'empty', '')) + + assert result.exit_code == 123 + + assert u"Using task definition: test-task" not in result.output + assert u'Changed environment' not in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_previously_empty_environment_variable_with_value(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-e', 'webserver', 'empty', 'not-empty')) + + assert result.exit_code == 123 + + assert u"Using task definition: test-task" in result.output + assert u'Changed environment "empty" of container "webserver" to: "not-empty"' in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_exclusive_environment(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-e', 'webserver', 'new-env', 'new-value', '--exclusive-env')) + + assert result.exit_code == 123 + + assert u"Using task definition: test-task" in result.output + assert u'Changed environment "new-env" of container "webserver" to: "new-value"' in result.output + + assert u'Removed environment "foo" of container "webserver"' in result.output + assert u'Removed environment "lorem" of container "webserver"' in result.output + + assert u'Removed secret' not in result.output + + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_exclusive_secret(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-s', 'webserver', 'new-secret', 'new-place', '--exclusive-secrets')) + + assert result.exit_code == 123 + + assert u"Using task definition: test-task" in result.output + assert u'Changed secret "new-secret" of container "webserver" to: "new-place"' in result.output + + assert u'Removed secret "baz" of container "webserver"' in result.output + assert u'Removed secret "dolor" of container "webserver"' in result.output + + assert u'Removed environment' not in result.output + + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_one_new_secret_variable(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', + '-s', 'application', 'baz', 'qux', + '-s', 'webserver', 'baz', 'quux')) + + assert result.exit_code == 123 + + assert u"Using task definition: test-task" in result.output + assert u'Changed secret "baz" of container "application" to: "qux"' in result.output + assert u'Changed secret "baz" of container "webserver" to: "quux"' in result.output + assert u'Changed secret "dolor" of container "webserver" to: "sit"' not in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_without_changing_environment_value(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-e', 'webserver', 'foo', 'bar')) + + assert result.exit_code == 123 + + assert u"Using task definition: test-task" not in result.output + assert u'Changed environment' not in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output + + +@patch('ecs_deploy.cli.get_client') +def test_run_without_changing_secrets_value(get_client, runner): + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') + result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-s', 'webserver', 'baz', 'qux')) + + assert result.exit_code == 123 + + assert u"Using task definition: test-task" not in result.output + assert u'Changed secrets' not in result.output + assert u"Successfully started 2 instances of task: test-task:2" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output @patch('ecs_deploy.cli.get_client') def test_run_task_without_diff(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') result = runner.invoke(cli.run, (CLUSTER_NAME, 'test-task', '2', '-e', 'application', 'foo', 'bar', '--no-diff')) - assert not result.exception - assert result.exit_code == 0 + assert result.exit_code == 123 assert u"Using task definition: test-task" not in result.output assert u'Changed environment' not in result.output assert u"Successfully started 2 instances of task: test-task:2" in result.output - assert u"- arn:foo:bar" in result.output - assert u"- arn:lorem:ipsum" in result.output + assert TASK_ARN_1 in result.output + assert TASK_ARN_2 in result.output @patch('ecs_deploy.cli.get_client') @@ -691,7 +901,7 @@ def test_run_task_without_credentials(get_client, runner): @patch('ecs_deploy.cli.get_client') def test_run_task_with_invalid_cluster(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') + get_client.return_value = EcsTestClient('acces_key', 'secret_key', task_status=u'STOPPED') result = runner.invoke(cli.run, ('unknown-cluster', 'test-task')) assert result.exit_code == 1 assert result.output == u'An error occurred (ClusterNotFoundException) when calling the RunTask operation: Cluster not found.\n\n' diff --git a/tests/test_ecs.py b/tests/test_ecs.py index d91bdde..afbad55 100644 --- a/tests/test_ecs.py +++ b/tests/test_ecs.py @@ -109,7 +109,9 @@ u'overrides': {u'containerOverrides': []}, u'lastStatus': u'RUNNING', u'desiredStatus': u'RUNNING', - u'containers': TASK_DEFINITION_CONTAINERS_1, + u'containers': [{ + u'exitCode': 123, + }], u'startedBy': SERVICE_ARN } @@ -898,7 +900,7 @@ def test_ecs_server_get_warnings(): class EcsTestClient(object): def __init__(self, access_key_id=None, secret_access_key=None, region=None, profile=None, deployment_errors=False, client_errors=False, - wait=0): + wait=0, task_status=u'RUNNING'): super(EcsTestClient, self).__init__() self.access_key_id = access_key_id self.secret_access_key = secret_access_key @@ -907,6 +909,7 @@ def __init__(self, access_key_id=None, secret_access_key=None, region=None, self.deployment_errors = deployment_errors self.client_errors = client_errors self.wait_until = datetime.now() + timedelta(seconds=wait) + self.task_status = task_status def describe_services(self, cluster_name, service_name): if not self.access_key_id or not self.secret_access_key: @@ -939,7 +942,10 @@ def list_tasks(self, cluster_name, service_name): return deepcopy(RESPONSE_LIST_TASKS_0) def describe_tasks(self, cluster_name, task_arns): - return deepcopy(RESPONSE_DESCRIBE_TASKS) + tasks = deepcopy(RESPONSE_DESCRIBE_TASKS) + for task in tasks['tasks']: + task[u'lastStatus'] = self.task_status + return tasks def register_task_definition(self, family, containers, volumes, role_arn, execution_role_arn, additional_properties): @@ -968,7 +974,7 @@ def run_task(self, cluster, task_definition, count, started_by, overrides, if self.deployment_errors: error = dict(Error=dict(Code=123, Message="Something went wrong")) raise ClientError(error, 'fake_error') - return dict(tasks=[dict(taskArn='arn:foo:bar'), dict(taskArn='arn:lorem:ipsum')]) + return RESPONSE_DESCRIBE_TASKS def update_rule(self, cluster, rule, task_definition): if not self.access_key_id or not self.secret_access_key: