added deployment configuration as an option. this fixes #2434

This commit is contained in:
simplesteph 2017-01-05 12:48:40 +11:00 committed by jctanner
parent 76d563af79
commit d811b1d942

View file

@ -33,6 +33,9 @@ version_added: "2.1"
author: author:
- "Mark Chance (@java1guy)" - "Mark Chance (@java1guy)"
- "Darek Kaczynski (@kaczynskid)" - "Darek Kaczynski (@kaczynskid)"
- "Stephane Maarek (@simplesteph)"
- "Zac Blazic (@zacblazic)"
requirements: [ json, boto, botocore, boto3 ] requirements: [ json, boto, botocore, boto3 ]
options: options:
state: state:
@ -78,6 +81,11 @@ options:
- The number of times to check that the service is available - The number of times to check that the service is available
required: false required: false
default: 10 default: 10
deployment_configuration:
description:
- Optional parameters that control the deployment_configuration; format is '{"maximum_percent":<integer>, "minimum_healthy_percent":<integer>}
required: false
version_added: 2.3
extends_documentation_fragment: extends_documentation_fragment:
- aws - aws
- ec2 - ec2
@ -103,6 +111,17 @@ EXAMPLES = '''
name: default name: default
state: absent state: absent
cluster: new_cluster cluster: new_cluster
# With custom deployment configuration
- ecs_service:
name: test-service
cluster: test-cluster
task_definition: test-task-definition
desired_count: 3
deployment_configuration:
minimum_healthy_percent: 75
maximum_percent: 150
state: present
''' '''
RETURN = ''' RETURN = '''
@ -164,6 +183,19 @@ service:
description: list of service deployments description: list of service deployments
returned: always returned: always
type: list of complex type: list of complex
deploymentConfiguration:
description: dictionary of deploymentConfiguration
returned: always
type: complex
contains:
maximumPercent:
description: maximumPercent param
returned: always
type: int
minimumHealthyPercent:
description: minimumHealthyPercent param
returned: always
type: int
events: events:
description: lost of service events description: lost of service events
returned: always returned: always
@ -180,6 +212,55 @@ ansible_facts:
''' '''
import time import time
DEPLOYMENT_CONFIGURATION_TYPE_MAP = {
'maximum_percent': 'int',
'minimum_healthy_percent': 'int'
}
class TypeMapper:
def map_complex_type(self, complex_type, type_map):
if complex_type is None:
return
new_type = type(complex_type)()
if isinstance(complex_type, dict):
for key in complex_type:
if key in type_map:
if isinstance(type_map[key], list):
new_type[key] = self.map_complex_type(
complex_type[key],
type_map[key][0])
else:
new_type[key] = self.map_complex_type(
complex_type[key],
type_map[key])
else:
return complex_type
elif isinstance(complex_type, list):
for i in range(len(complex_type)):
new_type.append(self.map_complex_type(
complex_type[i],
type_map))
elif type_map:
return vars(globals()['__builtins__'])[type_map](complex_type)
return new_type
def camelize(self, complex_type):
if complex_type is None:
return
new_type = type(complex_type)()
if isinstance(complex_type, dict):
for key in complex_type:
new_type[self.camel(key)] = self.camelize(complex_type[key])
elif isinstance(complex_type, list):
for i in range(len(complex_type)):
new_type.append(self.camelize(complex_type[i]))
else:
return complex_type
return new_type
def camel(self, words):
return words.split('_')[0] + ''.join(x.capitalize() or '_' for x in words.split('_')[1:])
try: try:
import boto import boto
import botocore import botocore
@ -204,7 +285,6 @@ class EcsServiceManager:
self.module = module self.module = module
try: try:
# self.ecs = boto3.client('ecs')
region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True) region, ec2_url, aws_connect_kwargs = get_aws_connection_info(module, boto3=True)
if not region: if not region:
module.fail_json(msg="Region must be specified as a parameter, in EC2_REGION or AWS_REGION environment variables or in boto configuration file") module.fail_json(msg="Region must be specified as a parameter, in EC2_REGION or AWS_REGION environment variables or in boto configuration file")
@ -212,15 +292,6 @@ class EcsServiceManager:
except boto.exception.NoAuthHandlerFound as e: except boto.exception.NoAuthHandlerFound as e:
self.module.fail_json(msg="Can't authorize connection - %s" % str(e)) self.module.fail_json(msg="Can't authorize connection - %s" % str(e))
# def list_clusters(self):
# return self.client.list_clusters()
# {'failures=[],
# 'ResponseMetadata={'HTTPStatusCode=200, 'RequestId='ce7b5880-1c41-11e5-8a31-47a93a8a98eb'},
# 'clusters=[{'activeServicesCount=0, 'clusterArn='arn:aws:ecs:us-west-2:777110527155:cluster/default', 'status='ACTIVE', 'pendingTasksCount=0, 'runningTasksCount=0, 'registeredContainerInstancesCount=0, 'clusterName='default'}]}
# {'failures=[{'arn='arn:aws:ecs:us-west-2:777110527155:cluster/bogus', 'reason='MISSING'}],
# 'ResponseMetadata={'HTTPStatusCode=200, 'RequestId='0f66c219-1c42-11e5-8a31-47a93a8a98eb'},
# 'clusters=[]}
def find_in_array(self, array_of_services, service_name, field_name='serviceArn'): def find_in_array(self, array_of_services, service_name, field_name='serviceArn'):
for c in array_of_services: for c in array_of_services:
if c[field_name].endswith(service_name): if c[field_name].endswith(service_name):
@ -259,7 +330,7 @@ class EcsServiceManager:
return True return True
def create_service(self, service_name, cluster_name, task_definition, def create_service(self, service_name, cluster_name, task_definition,
load_balancers, desired_count, client_token, role): load_balancers, desired_count, client_token, role, deployment_configuration):
response = self.ecs.create_service( response = self.ecs.create_service(
cluster=cluster_name, cluster=cluster_name,
serviceName=service_name, serviceName=service_name,
@ -267,16 +338,18 @@ class EcsServiceManager:
loadBalancers=load_balancers, loadBalancers=load_balancers,
desiredCount=desired_count, desiredCount=desired_count,
clientToken=client_token, clientToken=client_token,
role=role) role=role,
deploymentConfiguration=deployment_configuration)
return self.jsonize(response['service']) return self.jsonize(response['service'])
def update_service(self, service_name, cluster_name, task_definition, def update_service(self, service_name, cluster_name, task_definition,
load_balancers, desired_count, client_token, role): load_balancers, desired_count, client_token, role, deployment_configuration):
response = self.ecs.update_service( response = self.ecs.update_service(
cluster=cluster_name, cluster=cluster_name,
service=service_name, service=service_name,
taskDefinition=task_definition, taskDefinition=task_definition,
desiredCount=desired_count) desiredCount=desired_count,
deploymentConfiguration=deployment_configuration)
return self.jsonize(response['service']) return self.jsonize(response['service'])
def jsonize(self, service): def jsonize(self, service):
@ -297,7 +370,6 @@ class EcsServiceManager:
def delete_service(self, service, cluster=None): def delete_service(self, service, cluster=None):
return self.ecs.delete_service(cluster=cluster, service=service) return self.ecs.delete_service(cluster=cluster, service=service)
def main(): def main():
argument_spec = ec2_argument_spec() argument_spec = ec2_argument_spec()
@ -311,7 +383,8 @@ def main():
client_token=dict(required=False, default='', type='str'), client_token=dict(required=False, default='', type='str'),
role=dict(required=False, default='', type='str'), role=dict(required=False, default='', type='str'),
delay=dict(required=False, type='int', default=10), delay=dict(required=False, type='int', default=10),
repeat=dict(required=False, type='int', default=10) repeat=dict(required=False, type='int', default=10),
deployment_configuration=dict(required=False, default={}, type='dict')
)) ))
module = AnsibleModule(argument_spec=argument_spec, module = AnsibleModule(argument_spec=argument_spec,
@ -329,6 +402,12 @@ def main():
module.fail_json(msg='boto3 is required.') module.fail_json(msg='boto3 is required.')
service_mgr = EcsServiceManager(module) service_mgr = EcsServiceManager(module)
type_mapper = TypeMapper()
deployment_configuration = type_mapper.map_complex_type(module.params['deployment_configuration'],
DEPLOYMENT_CONFIGURATION_TYPE_MAP)
deployment_configuration = type_mapper.camelize(deployment_configuration)
try: try:
existing = service_mgr.describe_service(module.params['cluster'], module.params['name']) existing = service_mgr.describe_service(module.params['cluster'], module.params['name'])
except Exception as e: except Exception as e:
@ -360,7 +439,8 @@ def main():
loadBalancers, loadBalancers,
module.params['desired_count'], module.params['desired_count'],
clientToken, clientToken,
role) role,
deployment_configuration)
else: else:
# doesn't exist. create it. # doesn't exist. create it.
response = service_mgr.create_service(module.params['name'], response = service_mgr.create_service(module.params['name'],
@ -369,7 +449,8 @@ def main():
loadBalancers, loadBalancers,
module.params['desired_count'], module.params['desired_count'],
clientToken, clientToken,
role) role,
deployment_configuration)
results['service'] = response results['service'] = response