@ -44,12 +44,14 @@ options:
required : false
required : false
default : false
default : false
type : bool
type : bool
delet e_policy:
purg e_policy:
description :
description :
- If yes , remove the policy from the repository .
- If yes , remove the policy from the repository .
- Alias C ( delete_policy ) has been deprecated and will be removed in Ansible 2.14
required : false
required : false
default : false
default : false
type : bool
type : bool
aliases : [ delete_policy ]
image_tag_mutability :
image_tag_mutability :
description :
description :
- Configure whether repository should be mutable ( ie . an already existing tag can be overwritten ) or not .
- Configure whether repository should be mutable ( ie . an already existing tag can be overwritten ) or not .
@ -58,6 +60,19 @@ options:
default : ' mutable '
default : ' mutable '
version_added : ' 2.10 '
version_added : ' 2.10 '
type : str
type : str
lifecycle_policy :
description :
- JSON or dict that represents the new lifecycle policy
required : false
version_added : ' 2.10 '
type : json
purge_lifecycle_policy :
description :
- if yes , remove the lifecycle policy from the repository
required : false
default : false
version_added : ' 2.10 '
type : bool
state :
state :
description :
description :
- Create or destroy the repository .
- Create or destroy the repository .
@ -107,13 +122,32 @@ EXAMPLES = '''
- name : delete - policy
- name : delete - policy
ecs_ecr :
ecs_ecr :
name : needs - no - policy
name : needs - no - policy
delet e_policy: yes
purg e_policy: yes
- name : create immutable ecr - repo
- name : create immutable ecr - repo
ecs_ecr :
ecs_ecr :
name : super / cool
name : super / cool
image_tag_mutability : immutable
image_tag_mutability : immutable
- name : set - lifecycle - policy
ecs_ecr :
name : needs - lifecycle - policy
lifecycle_policy :
rules :
- rulePriority : 1
description : new policy
selection :
tagStatus : untagged
countType : sinceImagePushed
countUnit : days
countNumber : 365
action :
type : expire
- name : purge - lifecycle - policy
ecs_ecr :
name : needs - no - lifecycle - policy
purge_lifecycle_policy : true
'''
'''
RETURN = '''
RETURN = '''
@ -151,7 +185,8 @@ except ImportError:
from ansible . module_utils . basic import AnsibleModule
from ansible . module_utils . basic import AnsibleModule
from ansible . module_utils . ec2 import ( HAS_BOTO3 , boto3_conn , boto_exception , ec2_argument_spec ,
from ansible . module_utils . ec2 import ( HAS_BOTO3 , boto3_conn , boto_exception , ec2_argument_spec ,
get_aws_connection_info , compare_policies )
get_aws_connection_info , compare_policies ,
sort_json_policy_dict )
from ansible . module_utils . six import string_types
from ansible . module_utils . six import string_types
@ -286,6 +321,49 @@ class EcsEcr:
repo [ ' imageTagMutability ' ] = new_mutability_configuration
repo [ ' imageTagMutability ' ] = new_mutability_configuration
return repo
return repo
def get_lifecycle_policy ( self , registry_id , name ) :
try :
res = self . ecr . get_lifecycle_policy (
repositoryName = name , * * build_kwargs ( registry_id ) )
text = res . get ( ' lifecyclePolicyText ' )
return text and json . loads ( text )
except ClientError as err :
code = err . response [ ' Error ' ] . get ( ' Code ' , ' Unknown ' )
if code == ' LifecyclePolicyNotFoundException ' :
return None
raise
def put_lifecycle_policy ( self , registry_id , name , policy_text ) :
if not self . check_mode :
policy = self . ecr . put_lifecycle_policy (
repositoryName = name ,
lifecyclePolicyText = policy_text ,
* * build_kwargs ( registry_id ) )
self . changed = True
return policy
else :
self . skipped = True
if self . get_repository ( registry_id , name ) is None :
printable = name
if registry_id :
printable = ' {0} : {1} ' . format ( registry_id , name )
raise Exception (
' could not find repository {0} ' . format ( printable ) )
return
def purge_lifecycle_policy ( self , registry_id , name ) :
if not self . check_mode :
policy = self . ecr . delete_lifecycle_policy (
repositoryName = name , * * build_kwargs ( registry_id ) )
self . changed = True
return policy
else :
policy = self . get_lifecycle_policy ( registry_id , name )
if policy :
self . skipped = True
return policy
return None
def sort_lists_of_strings ( policy ) :
def sort_lists_of_strings ( policy ) :
for statement_index in range ( 0 , len ( policy . get ( ' Statement ' , [ ] ) ) ) :
for statement_index in range ( 0 , len ( policy . get ( ' Statement ' , [ ] ) ) ) :
@ -296,20 +374,35 @@ def sort_lists_of_strings(policy):
return policy
return policy
def run ( ecr , params , verbosity ):
def run ( ecr , params ):
# type: (EcsEcr, dict, int) -> Tuple[bool, dict]
# type: (EcsEcr, dict, int) -> Tuple[bool, dict]
result = { }
result = { }
try :
try :
name = params [ ' name ' ]
name = params [ ' name ' ]
state = params [ ' state ' ]
state = params [ ' state ' ]
policy_text = params [ ' policy ' ]
policy_text = params [ ' policy ' ]
delete_policy = params [ ' delet e_policy' ]
purge_policy = params [ ' purg e_policy' ]
registry_id = params [ ' registry_id ' ]
registry_id = params [ ' registry_id ' ]
force_set_policy = params [ ' force_set_policy ' ]
force_set_policy = params [ ' force_set_policy ' ]
image_tag_mutability = params [ ' image_tag_mutability ' ] . upper ( )
image_tag_mutability = params [ ' image_tag_mutability ' ] . upper ( )
lifecycle_policy_text = params [ ' lifecycle_policy ' ]
purge_lifecycle_policy = params [ ' purge_lifecycle_policy ' ]
# Parse policies, if they are given
try :
policy = policy_text and json . loads ( policy_text )
except ValueError :
result [ ' policy ' ] = policy_text
result [ ' msg ' ] = ' Could not parse policy '
return False , result
# If a policy was given, parse it
try :
policy = policy_text and json . loads ( policy_text )
lifecycle_policy = \
lifecycle_policy_text and json . loads ( lifecycle_policy_text )
except ValueError :
result [ ' lifecycle_policy ' ] = lifecycle_policy_text
result [ ' msg ' ] = ' Could not parse lifecycle_policy '
return False , result
result [ ' state ' ] = state
result [ ' state ' ] = state
result [ ' created ' ] = False
result [ ' created ' ] = False
@ -327,14 +420,42 @@ def run(ecr, params, verbosity):
repo = ecr . put_image_tag_mutability ( registry_id , name , image_tag_mutability )
repo = ecr . put_image_tag_mutability ( registry_id , name , image_tag_mutability )
result [ ' repository ' ] = repo
result [ ' repository ' ] = repo
if delete_policy :
if purge_lifecycle_policy :
original_policy = ecr . get_repository_policy ( registry_id , name )
original_lifecycle_policy = \
ecr . get_lifecycle_policy ( registry_id , name )
if verbosity > = 2 :
result [ ' lifecycle_policy ' ] = None
result [ ' policy ' ] = None
if verbosity > = 3 :
if original_lifecycle_policy :
result [ ' original_policy ' ] = original_policy
ecr . purge_lifecycle_policy ( registry_id , name )
result [ ' changed ' ] = True
elif lifecycle_policy_text is not None :
try :
lifecycle_policy = sort_json_policy_dict ( lifecycle_policy )
result [ ' lifecycle_policy ' ] = lifecycle_policy
original_lifecycle_policy = ecr . get_lifecycle_policy (
registry_id , name )
if original_lifecycle_policy :
original_lifecycle_policy = sort_json_policy_dict (
original_lifecycle_policy )
if original_lifecycle_policy != lifecycle_policy :
ecr . put_lifecycle_policy ( registry_id , name ,
lifecycle_policy_text )
result [ ' changed ' ] = True
except Exception :
# Some failure w/ the policy. It's helpful to know what the
# policy is.
result [ ' lifecycle_policy ' ] = lifecycle_policy_text
raise
if purge_policy :
original_policy = ecr . get_repository_policy ( registry_id , name )
result [ ' policy ' ] = None
if original_policy :
if original_policy :
ecr . delete_repository_policy ( registry_id , name )
ecr . delete_repository_policy ( registry_id , name )
@ -345,17 +466,13 @@ def run(ecr, params, verbosity):
# Sort any lists containing only string types
# Sort any lists containing only string types
policy = sort_lists_of_strings ( policy )
policy = sort_lists_of_strings ( policy )
if verbosity > = 2 :
result [ ' policy ' ] = policy
result [ ' policy ' ] = policy
original_policy = ecr . get_repository_policy (
original_policy = ecr . get_repository_policy (
registry_id , name )
registry_id , name )
if original_policy :
if original_policy :
original_policy = sort_lists_of_strings ( original_policy )
original_policy = sort_lists_of_strings ( original_policy )
if verbosity > = 3 :
result [ ' original_policy ' ] = original_policy
if compare_policies ( original_policy , policy ) :
if compare_policies ( original_policy , policy ) :
ecr . set_repository_policy (
ecr . set_repository_policy (
registry_id , name , policy_text , force_set_policy )
registry_id , name , policy_text , force_set_policy )
@ -398,20 +515,28 @@ def main():
default = ' present ' ) ,
default = ' present ' ) ,
force_set_policy = dict ( required = False , type = ' bool ' , default = False ) ,
force_set_policy = dict ( required = False , type = ' bool ' , default = False ) ,
policy = dict ( required = False , type = ' json ' ) ,
policy = dict ( required = False , type = ' json ' ) ,
delete_policy = dict ( required = False , type = ' bool ' ) ,
image_tag_mutability = dict ( required = False , choices = [ ' mutable ' , ' immutable ' ] ,
image_tag_mutability = dict ( required = False , choices = [ ' mutable ' , ' immutable ' ] ,
default = ' mutable ' ) ) )
default = ' mutable ' ) ,
purge_policy = dict ( required = False , type = ' bool ' , aliases = [ ' delete_policy ' ] ) ,
lifecycle_policy = dict ( required = False , type = ' json ' ) ,
purge_lifecycle_policy = dict ( required = False , type = ' bool ' ) ) )
module = AnsibleModule ( argument_spec = argument_spec ,
module = AnsibleModule ( argument_spec = argument_spec ,
supports_check_mode = True ,
supports_check_mode = True ,
mutually_exclusive = [
mutually_exclusive = [
[ ' policy ' , ' delete_policy ' ] ] )
[ ' policy ' , ' purge_policy ' ] ,
[ ' lifecycle_policy ' , ' purge_lifecycle_policy ' ] ] )
if module . params . get ( ' delete_policy ' ) :
module . deprecate (
' The alias " delete_policy " has been deprecated and will be removed, '
' use " purge_policy " instead ' ,
version = ' 2.14 ' )
if not HAS_BOTO3 :
if not HAS_BOTO3 :
module . fail_json ( msg = ' boto3 required for this module ' )
module . fail_json ( msg = ' boto3 required for this module ' )
ecr = EcsEcr ( module )
ecr = EcsEcr ( module )
passed , result = run ( ecr , module . params , module . _verbosity )
passed , result = run ( ecr , module . params )
if passed :
if passed :
module . exit_json ( * * result )
module . exit_json ( * * result )