Skip to content

Commit

Permalink
Merge branch 'release/1.1.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
fabfuel committed Nov 15, 2016
2 parents df77635 + c3df13d commit 553be18
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 16 deletions.
20 changes: 19 additions & 1 deletion README.rst
Expand Up @@ -71,7 +71,10 @@ For detailed information about the available actions, arguments and options, run

Examples
--------
All examples assume, that authentication has already been configured.
All examples assume, that authentication has already been configured.

Deployment
----------

Simple Redeploy
===============
Expand Down Expand Up @@ -134,13 +137,28 @@ To change the command of a specific container, run the following command::

This will modify the **webserver** container and change its command to "nginx".


Set a task role
===============
To change or set the role, the service's task should run as, use the following command::

$ ecs deploy my-cluster my-service -r arn:aws:iam::123456789012:role/MySpecialEcsTaskRole

This will set the task role to "MySpecialEcsTaskRole".

Scaling
-------

Scale a service
===============
To change the number of running tasks and scale a service up and down, run this command::

$ ecs scale my-cluster my-service 4


Running a Task
--------------

Run a one-off task
==================
To run a one-off task, based on an existing task-definition, run this command::
Expand Down
4 changes: 3 additions & 1 deletion ecs_deploy/cli.py
Expand Up @@ -27,6 +27,7 @@ def get_client(access_key_id, secret_access_key, region, profile):
@click.option('-i', '--image', type=(str, str), multiple=True, help='Overwrites the image for a container: <container> <image>')
@click.option('-c', '--command', type=(str, str), multiple=True, help='Overwrites the command in a container: <container> <command>')
@click.option('-e', '--env', type=(str, str, str), multiple=True, help='Adds or changes an environment variable: <container> <name> <value>')
@click.option('-r', '--role', type=str, help='Sets the task\'s role ARN: <task role ARN>')
@click.option('--region', required=False, help='AWS region')
@click.option('--access-key-id', required=False, help='AWS access key id')
@click.option('--secret-access-key', required=False, help='AWS secret access yey')
Expand All @@ -36,7 +37,7 @@ def get_client(access_key_id, secret_access_key, region, profile):
@click.option('--newrelic-appid', required=False, help='New Relic App ID for recording the deployment')
@click.option('--comment', required=False, help='Description/comment for recording the deployment')
@click.option('--user', required=False, help='User who executes the deployment (used for recording)')
def deploy(cluster, service, tag, image, command, env, access_key_id, secret_access_key, region, profile, timeout,
def deploy(cluster, service, tag, image, command, env, role, access_key_id, secret_access_key, region, profile, timeout,
newrelic_apikey, newrelic_appid, comment, user):
"""
Redeploy or modify a service.
Expand All @@ -57,6 +58,7 @@ def deploy(cluster, service, tag, image, command, env, access_key_id, secret_acc
task_definition.set_images(tag, **{key: value for (key, value) in image})
task_definition.set_commands(**{key: value for (key, value) in command})
task_definition.set_environment(env)
task_definition.set_role_arn(role)
print_diff(task_definition)

click.secho('Creating new task definition revision')
Expand Down
43 changes: 37 additions & 6 deletions ecs_deploy/ecs.py
Expand Up @@ -25,8 +25,13 @@ def list_tasks(self, cluster_name, service_name):
def describe_tasks(self, cluster_name, task_arns):
return self.boto.describe_tasks(cluster=cluster_name, tasks=task_arns)

def register_task_definition(self, family, containers, volumes):
return self.boto.register_task_definition(family=family, containerDefinitions=containers, volumes=volumes)
def register_task_definition(self, family, containers, volumes, role_arn):
return self.boto.register_task_definition(
family=family,
containerDefinitions=containers,
volumes=volumes,
taskRoleArn=role_arn or ''
)

def deregister_task_definition(self, task_definition_arn):
return self.boto.deregister_task_definition(taskDefinition=task_definition_arn)
Expand Down Expand Up @@ -134,6 +139,10 @@ def arn(self):
def family(self):
return self.get(u'family')

@property
def role_arn(self):
return self.get(u'taskRoleArn')

@property
def revision(self):
return self.get(u'revision')
Expand Down Expand Up @@ -216,6 +225,12 @@ def validate_container_options(self, **container_options):
if container_name not in self.container_names:
raise UnknownContainerError(u'Unknown container: %s' % container_name)

def set_role_arn(self, role_arn):
if role_arn:
diff = EcsTaskDefinitionDiff(None, u'role_arn', role_arn, self[u'taskRoleArn'])
self[u'taskRoleArn'] = role_arn
self._diff.append(diff)


class EcsTaskDefinitionDiff(object):
def __init__(self, container, field, value, old_value):
Expand All @@ -225,8 +240,20 @@ def __init__(self, container, field, value, old_value):
self.old_value = old_value

def __repr__(self):
return u"Changed %s of container '%s' to: %s (was: %s)" % \
(self.field, self.container, dumps(self.value), dumps(self.old_value))
if self.container:
return u"Changed %s of container '%s' to: %s (was: %s)" % (
self.field,
self.container,
dumps(self.value),
dumps(self.old_value)
)
else:
return u"Changed %s to: %s (was: %s)" % (
self.field,
dumps(self.value),
dumps(self.old_value)
)



class EcsAction(object):
Expand Down Expand Up @@ -259,8 +286,12 @@ def get_task_definition(self, task_definition):
return task_definition

def update_task_definition(self, task_definition):
response = self._client.register_task_definition(task_definition.family, task_definition.containers,
task_definition.volumes)
response = self._client.register_task_definition(
task_definition.family,
task_definition.containers,
task_definition.volumes,
task_definition.role_arn
)
new_task_definition = EcsTaskDefinition(response[u'taskDefinition'])
self._client.deregister_task_definition(task_definition.arn)
return new_task_definition
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Expand Up @@ -3,7 +3,7 @@
"""
from setuptools import find_packages, setup

dependencies = ['click', 'botocore', 'boto3', 'future', 'requests']
dependencies = ['click', 'botocore', 'boto3>=1.4.0', 'future', 'requests']

setup(
name='ecs-deploy',
Expand Down
14 changes: 14 additions & 0 deletions tests/test_cli.py
Expand Up @@ -69,6 +69,20 @@ def test_deploy(get_client, runner):
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'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_new_tag(get_client, runner):
get_client.return_value = EcsTestClient('acces_key', 'secret_key')
Expand Down
28 changes: 21 additions & 7 deletions tests/test_ecs.py
Expand Up @@ -19,6 +19,7 @@
DESIRED_COUNT = 2
TASK_DEFINITION_FAMILY_1 = u'test-task'
TASK_DEFINITION_REVISION_1 = 1
TASK_DEFINITION_ROLE_ARN_1 = u'arn:test:role:1'
TASK_DEFINITION_ARN_1 = u'arn:aws:ecs:eu-central-1:123456789012:task-definition/%s:%s' % (TASK_DEFINITION_FAMILY_1,
TASK_DEFINITION_REVISION_1)
TASK_DEFINITION_VOLUMES_1 = []
Expand All @@ -42,6 +43,7 @@
u'taskDefinitionArn': TASK_DEFINITION_ARN_1,
u'family': TASK_DEFINITION_FAMILY_1,
u'revision': TASK_DEFINITION_REVISION_1,
u'taskRoleArn': TASK_DEFINITION_ROLE_ARN_1,
u'volumes': deepcopy(TASK_DEFINITION_VOLUMES_1),
u'containerDefinitions': deepcopy(TASK_DEFINITION_CONTAINERS_1),
}
Expand All @@ -51,6 +53,7 @@
u'family': TASK_DEFINITION_FAMILY_2,
u'revision': TASK_DEFINITION_REVISION_2,
u'volumes': deepcopy(TASK_DEFINITION_VOLUMES_2),
u'taskRoleArn': '',
u'containerDefinitions': deepcopy(TASK_DEFINITION_CONTAINERS_2),
}

Expand Down Expand Up @@ -423,9 +426,14 @@ def test_client_describe_tasks(client):
def test_client_register_task_definition(client):
containers = [{u'name': u'foo'}]
volumes = [{u'foo': u'bar'}]
client.register_task_definition(u'family', containers, volumes)
client.boto.register_task_definition.assert_called_once_with(family=u'family', containerDefinitions=containers,
volumes=volumes)
role_arn = 'arn:test:role'
client.register_task_definition(u'family', containers, volumes, role_arn)
client.boto.register_task_definition.assert_called_once_with(
family=u'family',
containerDefinitions=containers,
volumes=volumes,
taskRoleArn=role_arn
)


def test_client_deregister_task_definition(client):
Expand Down Expand Up @@ -522,9 +530,15 @@ def test_update_task_definition(client, task_definition):
new_task_definition = action.update_task_definition(task_definition)

assert isinstance(new_task_definition, EcsTaskDefinition)
client.register_task_definition.assert_called_once_with(task_definition.family, task_definition.containers,
task_definition.volumes)
client.deregister_task_definition.assert_called_once_with(task_definition.arn)
client.register_task_definition.assert_called_once_with(
task_definition.family,
task_definition.containers,
task_definition.volumes,
task_definition.role_arn,
)
client.deregister_task_definition.assert_called_once_with(
task_definition.arn
)


@patch.object(EcsClient, '__init__')
Expand Down Expand Up @@ -685,7 +699,7 @@ def list_tasks(self, cluster_name, service_name):
def describe_tasks(self, cluster_name, task_arns):
return deepcopy(RESPONSE_DESCRIBE_TASKS)

def register_task_definition(self, family, containers, volumes):
def register_task_definition(self, family, containers, volumes, role_arn):
return deepcopy(RESPONSE_TASK_DEFINITION_2)

def deregister_task_definition(self, task_definition_arn):
Expand Down

0 comments on commit 553be18

Please sign in to comment.