added deployment configuration as an option. this fixes #2434
This commit is contained in:
parent
76d563af79
commit
d811b1d942
1 changed files with 99 additions and 18 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue