Skip to content

Commit

Permalink
[run] wait command to finish
Browse files Browse the repository at this point in the history
  • Loading branch information
Maks3w committed Feb 13, 2019
1 parent 9dee06b commit f5dd343
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 56 deletions.
38 changes: 37 additions & 1 deletion ecs_deploy/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,11 @@ def scale(cluster, service, desired_count, access_key_id, secret_access_key, reg
@click.option('--access-key-id', required=False, help='AWS access key id')
@click.option('--secret-access-key', required=False, help='AWS secret access key')
@click.option('--profile', required=False, help='AWS configuration profile name')
@click.option('--timeout', required=False, default=300, type=int, help='Amount of seconds to wait for deployment before command fails (default: 300). To disable timeout (fire and forget) set to -1')
@click.option('--diff/--no-diff', default=True, help='Print which values were changed in the task definition (default: --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')
def run(cluster, task, count, tag, image, command, env, secret, role, region, access_key_id, secret_access_key, profile, diff, exclusive_env, exclusive_secrets):
def run(cluster, task, count, tag, image, command, env, secret, role, region, access_key_id, secret_access_key, profile, timeout, diff, exclusive_env, exclusive_secrets):
"""
Run a one-off task.
Expand Down Expand Up @@ -204,11 +205,46 @@ def run(cluster, task, count, tag, image, command, env, secret, role, region, ac
click.secho('- %s' % started_task['taskArn'], fg='green')
click.secho(' ')

exit_code = wait_for_task(
action=action,
timeout=timeout,
title='Running task'
)
exit(exit_code)

except EcsError as e:
click.secho('%s\n' % str(e), fg='red', err=True)
exit(1)


def wait_for_task(action: RunAction, timeout, title):
click.secho(title, nl=False)
waiting_timeout = datetime.now() + timedelta(seconds=timeout)

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 started_task in action.started_tasks:
task = action.get_task(started_task[u'taskArn'])
if task[u'lastStatus'] != u'STOPPED':
waiting = True
else:
for container in task[u'containers']:
exit_code = exit_code or container[u'exitCode']
if waiting:
sleep(1)

return exit_code


def wait_for_finish(action, timeout, title, success_message, failure_message,
ignore_warnings):
click.secho(title, nl=False)
Expand Down
7 changes: 7 additions & 0 deletions ecs_deploy/ecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,13 @@ def get_service(self):
service_definition=services_definition[u'services'][0]
)

def get_task(self, task_arn):
tasks_details = self._client.describe_tasks(
cluster_name=self._cluster_name,
task_arns=[task_arn]
)
return tasks_details[u'tasks'][0]

def get_current_task_definition(self, service):
return self.get_task_definition(service.task_definition)

Expand Down
87 changes: 35 additions & 52 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,11 +602,10 @@ 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
Expand All @@ -615,10 +614,9 @@ def test_run_task(get_client, runner):

@patch('ecs_deploy.cli.get_client')
def test_run_with_role_arn(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:1', '2', '-r', 'arn:new:role'))
assert result.exit_code == 0
assert not result.exception
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
Expand All @@ -630,10 +628,9 @@ def test_run_with_role_arn(get_client, runner):

@patch('ecs_deploy.cli.get_client')
def test_run_new_tag(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', '-t', 'latest'))
assert result.exit_code == 0
assert not result.exception
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
Expand All @@ -646,10 +643,9 @@ def test_run_new_tag(get_client, runner):

@patch('ecs_deploy.cli.get_client')
def test_run_one_new_image(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', '-i', 'application', 'application:latest'))
assert result.exit_code == 0
assert not result.exception
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
Expand All @@ -661,11 +657,10 @@ def test_run_one_new_image(get_client, runner):

@patch('ecs_deploy.cli.get_client')
def test_run_two_new_images(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', '-i', 'application', 'application:latest',
'-i', 'webserver', 'webserver:latest'))
assert result.exit_code == 0
assert not result.exception
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
Expand All @@ -677,10 +672,9 @@ def test_run_two_new_images(get_client, runner):

@patch('ecs_deploy.cli.get_client')
def test_run_one_new_command(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', '-c', 'application', 'date'))
assert result.exit_code == 0
assert not result.exception
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
Expand All @@ -690,11 +684,10 @@ def test_run_one_new_command(get_client, runner):

@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')
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 result.exit_code == 0
assert not result.exception
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
Expand All @@ -705,11 +698,10 @@ def test_run_one_new_environment_variable(get_client, runner):

@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')
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 == 0
assert not result.exception
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
Expand All @@ -720,11 +712,10 @@ def test_run_change_environment_variable_empty_string(get_client, runner):

@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')
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 == 0
assert not result.exception
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
Expand All @@ -735,11 +726,10 @@ def test_run_new_empty_environment_variable(get_client, runner):

@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')
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 == 0
assert not result.exception
assert result.exit_code == 123

assert u"Using task definition: test-task" not in result.output
assert u'Changed environment' not in result.output
Expand All @@ -750,11 +740,10 @@ def test_run_empty_environment_variable_again(get_client, runner):

@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')
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 == 0
assert not result.exception
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
Expand All @@ -765,11 +754,10 @@ def test_run_previously_empty_environment_variable_with_value(get_client, runner

@patch('ecs_deploy.cli.get_client')
def test_run_exclusive_environment(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', 'webserver', 'new-env', 'new-value', '--exclusive-env'))

assert result.exit_code == 0
assert not result.exception
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
Expand All @@ -786,11 +774,10 @@ def test_run_exclusive_environment(get_client, runner):

@patch('ecs_deploy.cli.get_client')
def test_run_exclusive_secret(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', '-s', 'webserver', 'new-secret', 'new-place', '--exclusive-secrets'))

assert result.exit_code == 0
assert not result.exception
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
Expand All @@ -807,13 +794,12 @@ def test_run_exclusive_secret(get_client, runner):

@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')
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 == 0
assert not result.exception
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
Expand All @@ -826,11 +812,10 @@ def test_run_one_new_secret_variable(get_client, runner):

@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')
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 == 0
assert not result.exception
assert result.exit_code == 123

assert u"Using task definition: test-task" not in result.output
assert u'Changed environment' not in result.output
Expand All @@ -841,11 +826,10 @@ def test_run_without_changing_environment_value(get_client, runner):

@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')
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 == 0
assert not result.exception
assert result.exit_code == 123

assert u"Using task definition: test-task" not in result.output
assert u'Changed secrets' not in result.output
Expand All @@ -856,11 +840,10 @@ def test_run_without_changing_secrets_value(get_client, runner):

@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
Expand Down Expand Up @@ -888,7 +871,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'
Expand Down
12 changes: 9 additions & 3 deletions tests/test_ecs.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,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
}

Expand Down Expand Up @@ -802,7 +804,7 @@ def test_run_action_run(client, task_definition):
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
Expand All @@ -811,6 +813,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:
Expand Down Expand Up @@ -841,7 +844,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, additional_properties):
return deepcopy(RESPONSE_TASK_DEFINITION_2)
Expand Down

0 comments on commit f5dd343

Please sign in to comment.