From 20fa79c7c6ed10e2b3c28c346cb757f0b8f0e132 Mon Sep 17 00:00:00 2001 From: efi shtain Date: Thu, 15 Feb 2024 22:55:23 +0000 Subject: [PATCH 1/2] update boto3 deps --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 8d608ab..c639545 100644 --- a/setup.py +++ b/setup.py @@ -14,8 +14,8 @@ def readme(): dependencies = [ 'click>=7.1.2, <9', 'click-log==0.3.2', - 'botocore>=1.32.6', - 'boto3>=1.29.6', + 'botocore>=1.34.42', + 'boto3>=1.34.42', 'future', 'requests<2.30.0', 'dictdiffer>=0.9.0', From b6cb33a5ea7402acedf33c82fa9cbc05e4a8065e Mon Sep 17 00:00:00 2001 From: efi shtain Date: Thu, 15 Feb 2024 22:55:36 +0000 Subject: [PATCH 2/2] Add support for passing aws session token --- ecs_deploy/cli.py | 34 +- tests/test_cli.py | 2147 +++++++++++++++------------------------------ 2 files changed, 723 insertions(+), 1458 deletions(-) diff --git a/ecs_deploy/cli.py b/ecs_deploy/cli.py index 679fe93..d328b9d 100644 --- a/ecs_deploy/cli.py +++ b/ecs_deploy/cli.py @@ -21,8 +21,8 @@ def ecs(): # pragma: no cover pass -def get_client(access_key_id, secret_access_key, region, profile, assume_account, assume_role): - return EcsClient(access_key_id, secret_access_key, region, profile, assume_account=assume_account, assume_role=assume_role) +def get_client(access_key_id, secret_access_key, region, profile, session_token, assume_account, assume_role): + return EcsClient(access_key_id, secret_access_key, region, profile, session_token, assume_account=assume_account, assume_role=assume_role) @click.command() @@ -57,6 +57,7 @@ def get_client(access_key_id, secret_access_key, region, profile, assume_account @click.option('--region', required=False, help='AWS region (e.g. eu-central-1)') @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('--session-token', required=False, help='AWS session token') @click.option('--profile', required=False, help='AWS configuration profile name') @click.option('--account', help='Target AWS account id to deploy in') @click.option('--assume-role', help='AWS Role to assume in target account') @@ -85,7 +86,7 @@ def get_client(access_key_id, secret_access_key, region, profile, assume_account @click.option('--volume', type=(str, str), multiple=True, required=False, help='Set volume mapping from host to container in the task definition.') @click.option('--add-container', type=str, multiple=True, required=False, help='Add a placeholder container in the task definition.') @click.option('--remove-container', type=str, multiple=True, required=False, help='Remove a container from the task definition.') -def deploy(cluster, service, tag, image, command, health_check, cpu, memory, memoryreservation, task_cpu, task_memory, privileged, essential, env, env_file, s3_env_file, secret, secrets_env_file, ulimit, system_control, port, mount, log, role, execution_role, runtime_platform, task, region, access_key_id, secret_access_key, profile, account, assume_role, timeout, newrelic_apikey, newrelic_appid, newrelic_region, newrelic_revision, comment, user, ignore_warnings, diff, deregister, rollback, exclusive_env, exclusive_secrets, exclusive_s3_env_file, sleep_time, exclusive_ulimits, exclusive_system_controls, exclusive_ports, exclusive_mounts, volume, add_container, remove_container, slack_url, docker_label, exclusive_docker_labels, slack_service_match='.*'): +def deploy(cluster, service, tag, image, command, health_check, cpu, memory, memoryreservation, task_cpu, task_memory, privileged, essential, env, env_file, s3_env_file, secret, secrets_env_file, ulimit, system_control, port, mount, log, role, execution_role, runtime_platform, task, region, access_key_id, secret_access_key, session_token, profile, account, assume_role, timeout, newrelic_apikey, newrelic_appid, newrelic_region, newrelic_revision, comment, user, ignore_warnings, diff, deregister, rollback, exclusive_env, exclusive_secrets, exclusive_s3_env_file, sleep_time, exclusive_ulimits, exclusive_system_controls, exclusive_ports, exclusive_mounts, volume, add_container, remove_container, slack_url, docker_label, exclusive_docker_labels, slack_service_match='.*'): """ Redeploy or modify a service. @@ -98,7 +99,7 @@ def deploy(cluster, service, tag, image, command, health_check, cpu, memory, mem and redeployed. """ try: - client = get_client(access_key_id, secret_access_key, region, profile, account, assume_role) + client = get_client(access_key_id, secret_access_key, region, profile, session_token, account, assume_role) deployment = DeployAction(client, cluster, service) td = get_task_definition(deployment, task) @@ -203,6 +204,7 @@ def deploy(cluster, service, tag, image, command, health_check, cpu, memory, mem @click.option('--region', help='AWS region (e.g. eu-central-1)') @click.option('--access-key-id', help='AWS access key id') @click.option('--secret-access-key', help='AWS secret access key') +@click.option('--session-token', required=False, help='AWS session token') @click.option('--newrelic-apikey', required=False, help='New Relic API Key for recording the deployment. Can also be defined via environment variable NEW_RELIC_API_KEY') @click.option('--newrelic-appid', required=False, help='New Relic App ID for recording the deployment. Can also be defined via environment variable NEW_RELIC_APP_ID') @click.option('--newrelic-region', required=False, help='New Relic region: US or EU (default: US). Can also be defined via environment variable NEW_RELIC_REGION') @@ -226,7 +228,7 @@ def deploy(cluster, service, tag, image, command, health_check, cpu, memory, mem @click.option('--exclusive-ports', is_flag=True, default=False, help='Set the given port mappings exclusively and remove all other pre-existing port mappings from all containers') @click.option('--exclusive-mounts', is_flag=True, default=False, help='Set the given mount points exclusively and remove all other pre-existing mount points from all containers') @click.option('--volume', type=(str, str), multiple=True, required=False, help='Set volume mapping from host to container in the task definition.') -def cron(cluster, task, rule, image, tag, command, cpu, memory, memoryreservation, task_cpu, task_memory, privileged, env, env_file, s3_env_file, secret, secrets_env_file, ulimit, system_control, port, mount, log, role, execution_role, region, access_key_id, secret_access_key, newrelic_apikey, newrelic_appid, newrelic_region, newrelic_revision, comment, user, profile, account, assume_role, diff, deregister, rollback, exclusive_env, exclusive_secrets, exclusive_s3_env_file, slack_url, slack_service_match, exclusive_ulimits, exclusive_system_controls, exclusive_ports, exclusive_mounts, volume, docker_label, exclusive_docker_labels): +def cron(cluster, task, rule, image, tag, command, cpu, memory, memoryreservation, task_cpu, task_memory, privileged, env, env_file, s3_env_file, secret, secrets_env_file, ulimit, system_control, port, mount, log, role, execution_role, region, access_key_id, secret_access_key, session_token, newrelic_apikey, newrelic_appid, newrelic_region, newrelic_revision, comment, user, profile, account, assume_role, diff, deregister, rollback, exclusive_env, exclusive_secrets, exclusive_s3_env_file, slack_url, slack_service_match, exclusive_ulimits, exclusive_system_controls, exclusive_ports, exclusive_mounts, volume, docker_label, exclusive_docker_labels): """ Update a scheduled task. @@ -236,7 +238,7 @@ def cron(cluster, task, rule, image, tag, command, cpu, memory, memoryreservatio RULE is the name of the rule to use the new task definition. """ try: - client = get_client(access_key_id, secret_access_key, region, profile, account, assume_role) + client = get_client(access_key_id, secret_access_key, region, profile, session_token, account, assume_role) action = RunAction(client, cluster) td = action.get_task_definition(task) @@ -310,6 +312,7 @@ def cron(cluster, task, rule, image, tag, command, cpu, memory, memoryreservatio @click.option('--region', help='AWS region (e.g. eu-central-1)') @click.option('--access-key-id', help='AWS access key id') @click.option('--secret-access-key', help='AWS secret access key') +@click.option('--session-token', required=False, help='AWS session token') @click.option('--profile', help='AWS configuration profile name') @click.option('--account', help='Target AWS account id to deploy in') @click.option('--assume-role', help='AWS Role to assume in target account') @@ -319,7 +322,7 @@ def cron(cluster, task, rule, image, tag, command, cpu, memory, memoryreservatio @click.option('--exclusive-docker-labels', is_flag=True, default=False, help='Set the given docker labels exclusively and remove all other pre-existing docker-labels from all containers') @click.option('--exclusive-s3-env-file', is_flag=True, default=False, help='Set the given s3 env files exclusively and remove all other pre-existing s3 env files from all containers') @click.option('--deregister/--no-deregister', default=True, help='Deregister or keep the old task definition (default: --deregister)') -def update(task, image, tag, command, env, env_file, s3_env_file, secret, secrets_env_file, role, region, access_key_id, secret_access_key, profile, account, assume_role, diff, exclusive_env, exclusive_s3_env_file, exclusive_secrets, runtime_platform, deregister, docker_label, exclusive_docker_labels): +def update(task, image, tag, command, env, env_file, s3_env_file, secret, secrets_env_file, role, region, access_key_id, secret_access_key, session_token, profile, account, assume_role, diff, exclusive_env, exclusive_s3_env_file, exclusive_secrets, runtime_platform, deregister, docker_label, exclusive_docker_labels): """ Update a task definition. @@ -327,7 +330,7 @@ def update(task, image, tag, command, env, env_file, s3_env_file, secret, secret TASK is the name of your task definition family (e.g. 'my-task') within ECS. """ try: - client = get_client(access_key_id, secret_access_key, region, profile, account, assume_role) + client = get_client(access_key_id, secret_access_key, region, profile, session_token, account, assume_role) action = UpdateAction(client) td = action.get_task_definition(task) @@ -362,13 +365,14 @@ def update(task, image, tag, command, env, env_file, s3_env_file, secret, secret @click.option('--region', help='AWS region (e.g. eu-central-1)') @click.option('--access-key-id', help='AWS access key id') @click.option('--secret-access-key', help='AWS secret access key') +@click.option('--session-token', required=False, help='AWS session token') @click.option('--profile', help='AWS configuration profile name') @click.option('--account', help='Target AWS account id to deploy in') @click.option('--assume-role', help='AWS Role to assume in target account') @click.option('--timeout', 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('--ignore-warnings', is_flag=True, help='Do not fail deployment on warnings (port already in use or insufficient memory/CPU)') @click.option('--sleep-time', default=1, type=int, help='Amount of seconds to wait between each check of the service (default: 1)') -def scale(cluster, service, desired_count, access_key_id, secret_access_key, region, profile, account, assume_role, timeout, ignore_warnings, sleep_time): +def scale(cluster, service, desired_count, access_key_id, secret_access_key, session_token, region, profile, account, assume_role, timeout, ignore_warnings, sleep_time): """ Scale a service up or down. @@ -378,7 +382,7 @@ def scale(cluster, service, desired_count, access_key_id, secret_access_key, reg DESIRED_COUNT is the number of tasks your service should run. """ try: - client = get_client(access_key_id, secret_access_key, region, profile, account, assume_role) + client = get_client(access_key_id, secret_access_key, session_token, region, profile, account, assume_role) scaling = ScaleAction(client, cluster, service) click.secho('Updating service') scaling.scale(desired_count) @@ -420,6 +424,7 @@ def scale(cluster, service, desired_count, access_key_id, secret_access_key, reg @click.option('--region', help='AWS region (e.g. eu-central-1)') @click.option('--access-key-id', help='AWS access key id') @click.option('--secret-access-key', help='AWS secret access key') +@click.option('--session-token', required=False, help='AWS session token') @click.option('--profile', help='AWS configuration profile name') @click.option('--account', help='Target AWS account id to deploy in') @click.option('--assume-role', help='AWS Role to assume in target account') @@ -428,7 +433,7 @@ def scale(cluster, service, desired_count, access_key_id, secret_access_key, reg @click.option('--exclusive-docker-labels', is_flag=True, default=False, help='Set the given docker labels exclusively and remove all other pre-existing docker-labels from all containers') @click.option('--exclusive-s3-env-file', is_flag=True, default=False, help='Set the given s3 env files exclusively and remove all other pre-existing s3 env files from all containers') @click.option('--diff/--no-diff', default=True, help='Print what values were changed in the task definition') -def run(cluster, task, count, command, env, env_file, s3_env_file, secret, secrets_env_file, launchtype, subnet, securitygroup, public_ip, platform_version, region, access_key_id, secret_access_key, profile, account, assume_role, exclusive_env, exclusive_secrets, exclusive_s3_env_file, diff, docker_label, exclusive_docker_labels): +def run(cluster, task, count, command, env, env_file, s3_env_file, secret, secrets_env_file, launchtype, subnet, securitygroup, public_ip, platform_version, region, access_key_id, secret_access_key, session_token, profile, account, assume_role, exclusive_env, exclusive_secrets, exclusive_s3_env_file, diff, docker_label, exclusive_docker_labels): """ Run a one-off task. @@ -438,7 +443,7 @@ def run(cluster, task, count, command, env, env_file, s3_env_file, secret, secre COUNT is the number of tasks your service should run. """ try: - client = get_client(access_key_id, secret_access_key, region, profile, account, assume_role) + client = get_client(access_key_id, secret_access_key, session_token, region, profile, account, assume_role) action = RunAction(client, cluster) td = action.get_task_definition(task) @@ -477,10 +482,11 @@ def run(cluster, task, count, command, env, env_file, s3_env_file, secret, secre @click.option('--region', help='AWS region (e.g. eu-central-1)') @click.option('--access-key-id', help='AWS access key id') @click.option('--secret-access-key', help='AWS secret access key') +@click.option('--session-token', required=False, help='AWS session token') @click.option('--profile', help='AWS configuration profile name') @click.option('--account', help='Target AWS account id to deploy in') @click.option('--assume-role', help='AWS Role to assume in target account') -def diff(task, revision_a, revision_b, region, access_key_id, secret_access_key, profile, account, assume_role): +def diff(task, revision_a, revision_b, region, access_key_id, secret_access_key, session_token, profile, account, assume_role): """ Compare two task definition revisions. @@ -490,7 +496,7 @@ def diff(task, revision_a, revision_b, region, access_key_id, secret_access_key, """ try: - client = get_client(access_key_id, secret_access_key, region, profile, account, assume_role) + client = get_client(access_key_id, secret_access_key, session_token, region, profile, account, assume_role) action = DiffAction(client) td_a = action.get_task_definition('%s:%s' % (task, revision_a)) diff --git a/tests/test_cli.py b/tests/test_cli.py index 96bff7b..d328b9d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,1472 +1,731 @@ -from datetime import datetime - -import pytest -from click.testing import CliRunner -from mock.mock import patch - -from ecs_deploy import cli -from ecs_deploy.cli import get_client, record_deployment -from ecs_deploy.ecs import EcsClient -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 - - -@pytest.fixture -def runner(): - return CliRunner() - - -@patch.object(EcsClient, '__init__') -def test_get_client(ecs_client): - ecs_client.return_value = None - client = get_client('access_key_id', 'secret_access_key', 'region', 'profile', 'account', 'role') - ecs_client.assert_called_once_with('access_key_id', 'secret_access_key', 'region', 'profile', - assume_account='account', assume_role='role') - assert isinstance(client, EcsClient) - - -def test_ecs(runner): - result = runner.invoke(cli.ecs) - assert result.exit_code == 0 - assert not result.exception - assert 'Usage: ecs [OPTIONS] COMMAND [ARGS]' in result.output - assert ' deploy ' in result.output - assert ' scale ' in result.output - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_without_credentials(get_client, runner): - get_client.return_value = EcsTestClient() - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME)) - assert result.exit_code == 1 - assert result.output == u'Unable to locate credentials. Configure credentials by running "aws configure".\n\n' - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_with_invalid_cluster(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, ('unknown-cluster', SERVICE_NAME)) - assert result.exit_code == 1 - assert result.output == u'An error occurred (ClusterNotFoundException) when calling the DescribeServices ' \ - u'operation: Cluster not found.\n\n' - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_with_invalid_service(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, (CLUSTER_NAME, 'unknown-service')) - assert result.exit_code == 1 - assert result.output == u'An error occurred when calling the DescribeServices operation: Service not found.\n\n' - - -@patch('ecs_deploy.cli.get_client') -def test_deploy(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME)) - assert result.exit_code == 0 - assert not result.exception - assert u"Deploying based on task definition: test-task:1" in result.output - assert u'Successfully created revision: 2' in result.output - assert u'Successfully deregistered revision: 1' in result.output - assert u'Successfully changed task definition to: test-task:2' in result.output - assert u'Deployment successful' in result.output - assert u"Updating task definition" not in result.output - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_with_rollback(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key', wait=2) - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME, '--timeout=1', '--rollback')) - - assert result.exit_code == 1 - assert result.exception - assert u"Deploying based on task definition: test-task:1" in result.output - - assert u"Deployment failed" in result.output - assert u"Rolling back to task definition: test-task:1" in result.output - assert u'Successfully changed task definition to: test-task:1' in result.output - - assert u"Rollback successful" in result.output - assert u'Deployment failed, but service has been rolled back to ' \ - u'previous task definition: test-task:1' in result.output - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_without_deregister(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME, '--no-deregister')) - assert result.exit_code == 0 - assert not result.exception - assert u"Deploying based on task definition: test-task:1" in result.output - assert u'Successfully created revision: 2' in result.output - assert u'Successfully deregistered revision: 1' not in result.output - assert u'Successfully changed task definition to: test-task:2' in result.output - assert u'Deployment successful' in result.output - assert u"Updating task definition" not in result.output - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_with_role_arn(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME, '-r', 'arn:new:role')) - assert result.exit_code == 0 - assert not result.exception - assert u"Deploying based on task definition: test-task:1" in result.output - assert u'Successfully created revision: 2' in result.output - assert u'Successfully deregistered revision: 1' in result.output - assert u'Successfully changed task definition to: test-task:2' in result.output - assert u'Deployment successful' in result.output - assert u"Updating task definition" in result.output - assert u'Changed role_arn to: "arn:new:role" (was: "arn:test:role:1")' in result.output - -@patch('ecs_deploy.cli.get_client') -def test_deploy_with_execution_role_arn(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME, '-x', 'arn:new:role')) - assert result.exit_code == 0 - assert not result.exception - assert u"Deploying based on task definition: test-task:1" in result.output - assert u'Successfully created revision: 2' in result.output - assert u'Successfully deregistered revision: 1' in result.output - assert u'Successfully changed task definition to: test-task:2' in result.output - assert u'Deployment successful' in result.output - assert u"Updating task definition" in result.output - assert u'Changed execution_role_arn to: "arn:new:role" (was: "arn:test:role:1")' in result.output - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_new_tag(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME, '-t', 'latest')) - assert result.exit_code == 0 - assert not result.exception - assert u"Deploying based on task definition: test-task:1" in result.output - assert u"Updating task definition" 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 deregistered revision: 1' in result.output - assert u'Successfully changed task definition to: test-task:2' in result.output - assert u'Deployment successful' in result.output - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_one_new_image(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME, '-i', 'application', 'application:latest')) - assert result.exit_code == 0 - assert not result.exception - assert u"Deploying based on task definition: test-task:1" in result.output - assert u"Updating task definition" 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 deregistered revision: 1' in result.output - assert u'Successfully changed task definition to: test-task:2' in result.output - assert u'Deployment successful' in result.output - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_two_new_images(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME, '-i', 'application', 'application:latest', - '-i', 'webserver', 'webserver:latest')) - assert result.exit_code == 0 - assert not result.exception - assert u"Deploying based on task definition: test-task:1" in result.output - assert u"Updating task definition" 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 deregistered revision: 1' in result.output - assert u'Successfully changed task definition to: test-task:2' in result.output - assert u'Deployment successful' in result.output - - -@patch('ecs_deploy.cli.get_client') -def test_deploy_one_new_command(get_client, runner): - get_client.return_value = EcsTestClient('acces_key', 'secret_key') - result = runner.invoke(cli.deploy, (CLUSTER_NAME, SERVICE_NAME, '-c', 'application', 'foobar')) - assert result.exit_code == 0 - assert not result.exception - assert u"Deploying based on task definition: test-task:1" in result.output - assert u"Updating task definition" in result.output - assert u'Changed command of container "application" to: "foobar" (was: "run")' in result.output - assert u'Successfully created revision: 2' in result.output - assert u'Successfully deregistered revision: 1' in result.output - assert u'Successfully changed task definition to: test-task:2' in result.output - assert u'Deployment successful' in result.output - -@pytest.mark.parametrize( - 'cmd_input, cmd_expected', - ( - ( - u'curl -f http://localhost/alive/', - u'curl -f http://localhost/alive/', - ), - ( - u'CMD-SHELL curl -f http://localhost/alive/ || 1', - u'CMD-SHELL curl -f http://localhost/alive/ || 1', +from __future__ import print_function, absolute_import + +from os import getenv +from time import sleep + +import click +import json +import getpass +from datetime import datetime, timedelta +from botocore.exceptions import ClientError +from ecs_deploy import VERSION +from ecs_deploy.ecs import DeployAction, ScaleAction, RunAction, EcsClient, DiffAction, \ + TaskPlacementError, EcsError, UpdateAction, LAUNCH_TYPE_EC2, LAUNCH_TYPE_FARGATE +from ecs_deploy.newrelic import Deployment, NewRelicException +from ecs_deploy.slack import SlackNotification + + +@click.group() +@click.version_option(version=VERSION, prog_name='ecs-deploy') +def ecs(): # pragma: no cover + pass + + +def get_client(access_key_id, secret_access_key, region, profile, session_token, assume_account, assume_role): + return EcsClient(access_key_id, secret_access_key, region, profile, session_token, assume_account=assume_account, assume_role=assume_role) + + +@click.command() +@click.argument('cluster') +@click.argument('service') +@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('-h', '--health-check', type=(str, str, int, int, int, int), multiple=True, help='Overwrites the healthcheck in a container: ') +@click.option('--cpu', type=(str, int), multiple=True, help='Overwrites the cpu value for a container: ') +@click.option('--memory', type=(str, int), multiple=True, help='Overwrites the memory value for a container: ') +@click.option('--memoryreservation', type=(str, int), multiple=True, help='Overwrites the memory reservation value for a container: ') +@click.option('--task-cpu', type=int, help='Overwrites the cpu value for a task: ') +@click.option('--task-memory', type=int, help='Overwrites the memory value for a task: ') +@click.option('--privileged', type=(str, bool), multiple=True, help='Overwrites the privileged value for a container: ') +@click.option('--essential', type=(str, bool), multiple=True, help='Overwrites the essential value for a container: ') +@click.option('-e', '--env', type=(str, str, str), multiple=True, help='Adds or changes an environment variable: ') +@click.option('--env-file', type=(str, str), default=((None, None),), multiple=True, required=False, help='Load environment variables from .env-file: ') +@click.option('--s3-env-file', type=(str, str), multiple=True, required=False, help='Location of .env-file in S3 in ARN format (eg arn:aws:s3:::/bucket_name/object_name): ') +@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('--secrets-env-file', type=(str, str), default=((None, None),), multiple=True, required=False, help='Load secrets from .env-file: ') +@click.option('-d', '--docker-label', type=(str, str, str), multiple=True, help='Adds or changes a docker label: ') +@click.option('-u', '--ulimit', type=(str, str, int, int), multiple=True, help='Adds or changes a ulimit variable in the container description (Not available for Fargate): ') +@click.option('--system-control', type=(str, str, str), multiple=True, help='Adds or changes a system control variable in the container description (Not available for Fargate): ') +@click.option('-p', '--port', type=(str, int, int), multiple=True, help='Adds or changes a port mappings in the container description (Not available for Fargate): ') +@click.option('-m', '--mount', type=(str, str, str), multiple=True, help='Adds or changes a mount points in the container description (Not available for Fargate): ') +@click.option('-l', '--log', type=(str, str, str, str), multiple=True, help='Adds or changes a log configuration in the container description (Not available for Fargate):