@ -132,6 +132,27 @@ options:
- Seconds to wait before health checking the freshly added / updated services . This option requires botocore > = 1.8 .20 .
- Seconds to wait before health checking the freshly added / updated services . This option requires botocore > = 1.8 .20 .
required : false
required : false
version_added : 2.8
version_added : 2.8
service_registries :
description :
- describes service disovery registries this service will register with .
required : false
version_added : 2.8
suboptions :
container_name :
description :
- container name for service disovery registration
container_port :
description :
- container port for service disovery registration
arn :
description :
- Service discovery registry ARN
scheduling_strategy :
description :
- The scheduling strategy , defaults to " REPLICA " if not given to preserve previous behavior
required : false
version_added : 2.8
choices : [ " DAEMON " , " REPLICA " ]
extends_documentation_fragment :
extends_documentation_fragment :
- aws
- aws
- ec2
- ec2
@ -387,6 +408,9 @@ class EcsServiceManager:
if ( expected [ ' load_balancers ' ] or [ ] ) != existing [ ' loadBalancers ' ] :
if ( expected [ ' load_balancers ' ] or [ ] ) != existing [ ' loadBalancers ' ] :
return False
return False
# expected is params. DAEMON scheduling strategy returns desired count equal to
# number of instances running; don't check desired count if scheduling strat is daemon
if ( expected [ ' scheduling_strategy ' ] != ' DAEMON ' ) :
if ( expected [ ' desired_count ' ] or 0 ) != existing [ ' desiredCount ' ] :
if ( expected [ ' desired_count ' ] or 0 ) != existing [ ' desiredCount ' ] :
return False
return False
@ -394,14 +418,14 @@ class EcsServiceManager:
def create_service ( self , service_name , cluster_name , task_definition , load_balancers ,
def create_service ( self , service_name , cluster_name , task_definition , load_balancers ,
desired_count , client_token , role , deployment_configuration ,
desired_count , client_token , role , deployment_configuration ,
placement_constraints , placement_strategy , network_configuration ,
placement_constraints , placement_strategy , health_check_grace_period_seconds ,
launch_type , health_check_grace_period_seconds ) :
network_configuration , service_registries , launch_type , scheduling_strategy ) :
params = dict (
params = dict (
cluster = cluster_name ,
cluster = cluster_name ,
serviceName = service_name ,
serviceName = service_name ,
taskDefinition = task_definition ,
taskDefinition = task_definition ,
loadBalancers = load_balancers ,
loadBalancers = load_balancers ,
desiredCount = desired_count ,
clientToken = client_token ,
clientToken = client_token ,
role = role ,
role = role ,
deploymentConfiguration = deployment_configuration ,
deploymentConfiguration = deployment_configuration ,
@ -414,6 +438,14 @@ class EcsServiceManager:
params [ ' launchType ' ] = launch_type
params [ ' launchType ' ] = launch_type
if self . health_check_setable ( params ) and health_check_grace_period_seconds is not None :
if self . health_check_setable ( params ) and health_check_grace_period_seconds is not None :
params [ ' healthCheckGracePeriodSeconds ' ] = health_check_grace_period_seconds
params [ ' healthCheckGracePeriodSeconds ' ] = health_check_grace_period_seconds
if service_registries :
params [ ' serviceRegistries ' ] = service_registries
# desired count is not required if scheduling strategy is daemon
if desired_count is not None :
params [ ' desiredCount ' ] = desired_count
if scheduling_strategy :
params [ ' schedulingStrategy ' ] = scheduling_strategy
response = self . ecs . create_service ( * * params )
response = self . ecs . create_service ( * * params )
return self . jsonize ( response [ ' service ' ] )
return self . jsonize ( response [ ' service ' ] )
@ -424,14 +456,17 @@ class EcsServiceManager:
cluster = cluster_name ,
cluster = cluster_name ,
service = service_name ,
service = service_name ,
taskDefinition = task_definition ,
taskDefinition = task_definition ,
desiredCount = desired_count ,
deploymentConfiguration = deployment_configuration )
deploymentConfiguration = deployment_configuration )
if network_configuration :
if network_configuration :
params [ ' networkConfiguration ' ] = network_configuration
params [ ' networkConfiguration ' ] = network_configuration
if self . health_check_setable ( params ) :
params [ ' healthCheckGracePeriodSeconds ' ] = health_check_grace_period_seconds
if force_new_deployment :
if force_new_deployment :
params [ ' forceNewDeployment ' ] = force_new_deployment
params [ ' forceNewDeployment ' ] = force_new_deployment
if health_check_grace_period_seconds is not None :
params [ ' healthCheckGracePeriodSeconds ' ] = health_check_grace_period_seconds
# desired count is not required if scheduling strategy is daemon
if desired_count is not None :
params [ ' desiredCount ' ] = desired_count
response = self . ecs . update_service ( * * params )
response = self . ecs . update_service ( * * params )
return self . jsonize ( response [ ' service ' ] )
return self . jsonize ( response [ ' service ' ] )
@ -484,21 +519,27 @@ def main():
deployment_configuration = dict ( required = False , default = { } , type = ' dict ' ) ,
deployment_configuration = dict ( required = False , default = { } , type = ' dict ' ) ,
placement_constraints = dict ( required = False , default = [ ] , type = ' list ' ) ,
placement_constraints = dict ( required = False , default = [ ] , type = ' list ' ) ,
placement_strategy = dict ( required = False , default = [ ] , type = ' list ' ) ,
placement_strategy = dict ( required = False , default = [ ] , type = ' list ' ) ,
health_check_grace_period_seconds = dict ( required = False , type = ' int ' ) ,
network_configuration = dict ( required = False , type = ' dict ' , options = dict (
network_configuration = dict ( required = False , type = ' dict ' , options = dict (
subnets = dict ( type = ' list ' ) ,
subnets = dict ( type = ' list ' ) ,
security_groups = dict ( type = ' list ' ) ,
security_groups = dict ( type = ' list ' ) ,
assign_public_ip = dict ( type = ' bool ' ) ,
assign_public_ip = dict ( type = ' bool ' )
) ) ,
) ) ,
launch_type = dict ( required = False , choices = [ ' EC2 ' , ' FARGATE ' ] ) ,
launch_type = dict ( required = False , choices = [ ' EC2 ' , ' FARGATE ' ] ) ,
health_check_grace_period_seconds = dict ( required = False , type = ' int ' )
service_registries = dict ( required = False , type = ' list ' , default = [ ] ) ,
scheduling_strategy = dict ( required = False , choices = [ ' DAEMON ' , ' REPLICA ' ] )
) )
) )
module = AnsibleAWSModule ( argument_spec = argument_spec ,
module = AnsibleAWSModule ( argument_spec = argument_spec ,
supports_check_mode = True ,
supports_check_mode = True ,
required_if = [ ( ' state ' , ' present ' , [ ' task_definition ' , ' desired_count ' ]) ,
required_if = [ ( ' state ' , ' present ' , [ ' task_definition ' ]) ,
( ' launch_type ' , ' FARGATE ' , [ ' network_configuration ' ] ) ] ,
( ' launch_type ' , ' FARGATE ' , [ ' network_configuration ' ] ) ] ,
required_together = [ [ ' load_balancers ' , ' role ' ] ] )
required_together = [ [ ' load_balancers ' , ' role ' ] ] )
if module . params [ ' state ' ] == ' present ' and module . params [ ' scheduling_strategy ' ] == ' REPLICA ' :
if module . params [ ' desired_count ' ] is None :
module . fail_json ( msg = ' state is present, scheduling_strategy is REPLICA; missing desired_count ' )
service_mgr = EcsServiceManager ( module )
service_mgr = EcsServiceManager ( module )
if module . params [ ' network_configuration ' ] :
if module . params [ ' network_configuration ' ] :
if not service_mgr . ecs_api_handles_network_configuration ( ) :
if not service_mgr . ecs_api_handles_network_configuration ( ) :
@ -511,6 +552,7 @@ def main():
DEPLOYMENT_CONFIGURATION_TYPE_MAP )
DEPLOYMENT_CONFIGURATION_TYPE_MAP )
deploymentConfiguration = snake_dict_to_camel_dict ( deployment_configuration )
deploymentConfiguration = snake_dict_to_camel_dict ( deployment_configuration )
serviceRegistries = list ( map ( snake_dict_to_camel_dict , module . params [ ' service_registries ' ] ) )
try :
try :
existing = service_mgr . describe_service ( module . params [ ' cluster ' ] , module . params [ ' name ' ] )
existing = service_mgr . describe_service ( module . params [ ' cluster ' ] , module . params [ ' name ' ] )
@ -525,6 +567,9 @@ def main():
if module . params [ ' force_new_deployment ' ] :
if module . params [ ' force_new_deployment ' ] :
if not module . botocore_at_least ( ' 1.8.4 ' ) :
if not module . botocore_at_least ( ' 1.8.4 ' ) :
module . fail_json ( msg = ' botocore needs to be version 1.8.4 or higher to use force_new_deployment ' )
module . fail_json ( msg = ' botocore needs to be version 1.8.4 or higher to use force_new_deployment ' )
if module . params [ ' health_check_grace_period_seconds ' ] :
if not module . botocore_at_least ( ' 1.8.20 ' ) :
module . fail_json ( msg = ' botocore needs to be version 1.8.20 or higher to use health_check_grace_period_seconds ' )
if module . params [ ' state ' ] == ' present ' :
if module . params [ ' state ' ] == ' present ' :
@ -557,8 +602,23 @@ def main():
loadBalancer [ ' containerPort ' ] = int ( loadBalancer [ ' containerPort ' ] )
loadBalancer [ ' containerPort ' ] = int ( loadBalancer [ ' containerPort ' ] )
if update :
if update :
# check various parameters and boto versions and give a helpful erro in boto is not new enough for feature
if module . params [ ' scheduling_strategy ' ] :
if not module . botocore_at_least ( ' 1.10.37 ' ) :
module . fail_json ( msg = ' botocore needs to be version 1.10.37 or higher to use scheduling_strategy ' )
elif ( existing [ ' schedulingStrategy ' ] ) != module . params [ ' scheduling_strategy ' ] :
module . fail_json ( msg = " It is not possible to update the scheduling strategy of an existing service " )
if module . params [ ' service_registries ' ] :
if not module . botocore_at_least ( ' 1.9.15 ' ) :
module . fail_json ( msg = ' botocore needs to be version 1.9.15 or higher to use service_registries ' )
elif ( existing [ ' serviceRegistries ' ] or [ ] ) != serviceRegistries :
module . fail_json ( msg = " It is not possible to update the service registries of an existing service " )
if ( existing [ ' loadBalancers ' ] or [ ] ) != loadBalancers :
if ( existing [ ' loadBalancers ' ] or [ ] ) != loadBalancers :
module . fail_json ( msg = " It is not possible to update the load balancers of an existing service " )
module . fail_json ( msg = " It is not possible to update the load balancers of an existing service " )
# update required
# update required
response = service_mgr . update_service ( module . params [ ' name ' ] ,
response = service_mgr . update_service ( module . params [ ' name ' ] ,
module . params [ ' cluster ' ] ,
module . params [ ' cluster ' ] ,
@ -568,6 +628,7 @@ def main():
network_configuration ,
network_configuration ,
module . params [ ' health_check_grace_period_seconds ' ] ,
module . params [ ' health_check_grace_period_seconds ' ] ,
module . params [ ' force_new_deployment ' ] )
module . params [ ' force_new_deployment ' ] )
else :
else :
try :
try :
response = service_mgr . create_service ( module . params [ ' name ' ] ,
response = service_mgr . create_service ( module . params [ ' name ' ] ,
@ -580,9 +641,11 @@ def main():
deploymentConfiguration ,
deploymentConfiguration ,
module . params [ ' placement_constraints ' ] ,
module . params [ ' placement_constraints ' ] ,
module . params [ ' placement_strategy ' ] ,
module . params [ ' placement_strategy ' ] ,
module . params [ ' health_check_grace_period_seconds ' ] ,
network_configuration ,
network_configuration ,
serviceRegistries ,
module . params [ ' launch_type ' ] ,
module . params [ ' launch_type ' ] ,
module . params [ ' health_check_grace_period_seconds ' ]
module . params [ ' scheduling_strategy ' ]
)
)
except botocore . exceptions . ClientError as e :
except botocore . exceptions . ClientError as e :
module . fail_json_aws ( e , msg = " Couldn ' t create service " )
module . fail_json_aws ( e , msg = " Couldn ' t create service " )