Improve ecs_ecr module to handle image_tag_mutability feature (#62871)
Since 2019 jul. 26, AWS Elastic Container Registry can be configured to be immutable that prevent overwritting of an existing tag in the registry. https://aws.amazon.com/fr/about-aws/whats-new/2019/07/amazon-ecr-now-supports-immutable-image-tags/ https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-tag-mutability.html By default, ecr is created MUTABLE, as this was the only option before this feature. This module leverage new capabilities of boto3 to configure image_tag_mutability option. https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ecr.html#ECR.Client.put_image_tag_mutability The image_tag_mutability option definition was inspired by existing terraform module. https://www.terraform.io/docs/providers/aws/r/ecr_repository.html
This commit is contained in:
parent
df283788e5
commit
29939383e6
2 changed files with 121 additions and 8 deletions
|
@ -5,14 +5,13 @@
|
||||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
|
||||||
from __future__ import absolute_import, division, print_function
|
from __future__ import absolute_import, division, print_function
|
||||||
__metaclass__ = type
|
|
||||||
|
|
||||||
|
__metaclass__ = type
|
||||||
|
|
||||||
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
ANSIBLE_METADATA = {'metadata_version': '1.1',
|
||||||
'status': ['preview'],
|
'status': ['preview'],
|
||||||
'supported_by': 'community'}
|
'supported_by': 'community'}
|
||||||
|
|
||||||
|
|
||||||
DOCUMENTATION = '''
|
DOCUMENTATION = '''
|
||||||
---
|
---
|
||||||
module: ecs_ecr
|
module: ecs_ecr
|
||||||
|
@ -48,6 +47,13 @@ options:
|
||||||
required: false
|
required: false
|
||||||
default: false
|
default: false
|
||||||
type: bool
|
type: bool
|
||||||
|
image_tag_mutability:
|
||||||
|
description:
|
||||||
|
- configure whether repository should be mutable (ie. an already existing tag can be overwritten) or not
|
||||||
|
required: false
|
||||||
|
choices: [mutable, immutable]
|
||||||
|
default: 'mutable'
|
||||||
|
version_added: '2.10'
|
||||||
state:
|
state:
|
||||||
description:
|
description:
|
||||||
- create or destroy the repository
|
- create or destroy the repository
|
||||||
|
@ -97,6 +103,12 @@ EXAMPLES = '''
|
||||||
ecs_ecr:
|
ecs_ecr:
|
||||||
name: needs-no-policy
|
name: needs-no-policy
|
||||||
delete_policy: yes
|
delete_policy: yes
|
||||||
|
|
||||||
|
- name: create immutable ecr-repo
|
||||||
|
ecs_ecr:
|
||||||
|
name: super/cool
|
||||||
|
image_tag_mutability: immutable
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
RETURN = '''
|
RETURN = '''
|
||||||
|
@ -190,15 +202,17 @@ class EcsEcr:
|
||||||
return None
|
return None
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def create_repository(self, registry_id, name):
|
def create_repository(self, registry_id, name, image_tag_mutability):
|
||||||
if registry_id:
|
if registry_id:
|
||||||
default_registry_id = self.sts.get_caller_identity().get('Account')
|
default_registry_id = self.sts.get_caller_identity().get('Account')
|
||||||
if registry_id != default_registry_id:
|
if registry_id != default_registry_id:
|
||||||
raise Exception('Cannot create repository in registry {0}.'
|
raise Exception('Cannot create repository in registry {0}.'
|
||||||
'Would be created in {1} instead.'.format(
|
'Would be created in {1} instead.'.format(registry_id, default_registry_id))
|
||||||
registry_id, default_registry_id))
|
|
||||||
if not self.check_mode:
|
if not self.check_mode:
|
||||||
repo = self.ecr.create_repository(repositoryName=name).get('repository')
|
repo = self.ecr.create_repository(
|
||||||
|
repositoryName=name,
|
||||||
|
imageTagMutability=image_tag_mutability).get('repository')
|
||||||
self.changed = True
|
self.changed = True
|
||||||
return repo
|
return repo
|
||||||
else:
|
else:
|
||||||
|
@ -250,6 +264,23 @@ class EcsEcr:
|
||||||
return policy
|
return policy
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def put_image_tag_mutability(self, registry_id, name, new_mutability_configuration):
|
||||||
|
repo = self.get_repository(registry_id, name)
|
||||||
|
current_mutability_configuration = repo.get('imageTagMutability')
|
||||||
|
|
||||||
|
if current_mutability_configuration != new_mutability_configuration:
|
||||||
|
if not self.check_mode:
|
||||||
|
self.ecr.put_image_tag_mutability(
|
||||||
|
repositoryName=name,
|
||||||
|
imageTagMutability=new_mutability_configuration,
|
||||||
|
**build_kwargs(registry_id))
|
||||||
|
else:
|
||||||
|
self.skipped = True
|
||||||
|
self.changed = True
|
||||||
|
|
||||||
|
repo['imageTagMutability'] = new_mutability_configuration
|
||||||
|
return repo
|
||||||
|
|
||||||
|
|
||||||
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', []))):
|
||||||
|
@ -270,6 +301,7 @@ def run(ecr, params, verbosity):
|
||||||
delete_policy = params['delete_policy']
|
delete_policy = params['delete_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()
|
||||||
|
|
||||||
# If a policy was given, parse it
|
# If a policy was given, parse it
|
||||||
policy = policy_text and json.loads(policy_text)
|
policy = policy_text and json.loads(policy_text)
|
||||||
|
@ -281,10 +313,13 @@ def run(ecr, params, verbosity):
|
||||||
|
|
||||||
if state == 'present':
|
if state == 'present':
|
||||||
result['created'] = False
|
result['created'] = False
|
||||||
|
|
||||||
if not repo:
|
if not repo:
|
||||||
repo = ecr.create_repository(registry_id, name)
|
repo = ecr.create_repository(registry_id, name, image_tag_mutability)
|
||||||
result['changed'] = True
|
result['changed'] = True
|
||||||
result['created'] = True
|
result['created'] = True
|
||||||
|
else:
|
||||||
|
repo = ecr.put_image_tag_mutability(registry_id, name, image_tag_mutability)
|
||||||
result['repository'] = repo
|
result['repository'] = repo
|
||||||
|
|
||||||
if delete_policy:
|
if delete_policy:
|
||||||
|
@ -358,7 +393,9 @@ 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')))
|
delete_policy=dict(required=False, type='bool'),
|
||||||
|
image_tag_mutability=dict(required=False, choices=['mutable', 'immutable'],
|
||||||
|
default='mutable')))
|
||||||
|
|
||||||
module = AnsibleModule(argument_spec=argument_spec,
|
module = AnsibleModule(argument_spec=argument_spec,
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
|
|
|
@ -55,6 +55,11 @@
|
||||||
- result is changed
|
- result is changed
|
||||||
- result.created
|
- result.created
|
||||||
|
|
||||||
|
- name: it should have been configured as mutable by default
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.repository.imageTagMutability == "MUTABLE"
|
||||||
|
|
||||||
|
|
||||||
- name: When creating a repository that already exists in check mode
|
- name: When creating a repository that already exists in check mode
|
||||||
ecs_ecr:
|
ecs_ecr:
|
||||||
|
@ -329,6 +334,77 @@
|
||||||
that:
|
that:
|
||||||
- result is not changed
|
- result is not changed
|
||||||
|
|
||||||
|
- name: When creating an immutable repository
|
||||||
|
ecs_ecr:
|
||||||
|
name: '{{ ecr_name }}'
|
||||||
|
region: '{{ ec2_region }}'
|
||||||
|
ec2_access_key: '{{ec2_access_key}}'
|
||||||
|
ec2_secret_key: '{{ec2_secret_key}}'
|
||||||
|
security_token: '{{security_token}}'
|
||||||
|
image_tag_mutability: immutable
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: it should change and create
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.created
|
||||||
|
|
||||||
|
- name: it should have been configured as immutable
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result.repository.imageTagMutability == "IMMUTABLE"
|
||||||
|
|
||||||
|
|
||||||
|
- name: When configuring an existing immutable repository to be mutable in check mode
|
||||||
|
ecs_ecr:
|
||||||
|
name: '{{ ecr_name }}'
|
||||||
|
region: '{{ ec2_region }}'
|
||||||
|
ec2_access_key: '{{ec2_access_key}}'
|
||||||
|
ec2_secret_key: '{{ec2_secret_key}}'
|
||||||
|
security_token: '{{security_token}}'
|
||||||
|
image_tag_mutability: mutable
|
||||||
|
register: result
|
||||||
|
check_mode: yes
|
||||||
|
|
||||||
|
- name: it should skip, change and configured mutable
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is skipped
|
||||||
|
- result is changed
|
||||||
|
- result.repository.imageTagMutability == "MUTABLE"
|
||||||
|
|
||||||
|
- name: When configuring an existing immutable repository to be mutable
|
||||||
|
ecs_ecr:
|
||||||
|
name: '{{ ecr_name }}'
|
||||||
|
region: '{{ ec2_region }}'
|
||||||
|
ec2_access_key: '{{ec2_access_key}}'
|
||||||
|
ec2_secret_key: '{{ec2_secret_key}}'
|
||||||
|
security_token: '{{security_token}}'
|
||||||
|
image_tag_mutability: mutable
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: it should change and configured mutable
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is changed
|
||||||
|
- result.repository.imageTagMutability == "MUTABLE"
|
||||||
|
|
||||||
|
- name: When configuring an already mutable repository to be mutable
|
||||||
|
ecs_ecr:
|
||||||
|
name: '{{ ecr_name }}'
|
||||||
|
region: '{{ ec2_region }}'
|
||||||
|
ec2_access_key: '{{ec2_access_key}}'
|
||||||
|
ec2_secret_key: '{{ec2_secret_key}}'
|
||||||
|
security_token: '{{security_token}}'
|
||||||
|
image_tag_mutability: mutable
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: it should not change
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- result is not changed
|
||||||
|
|
||||||
always:
|
always:
|
||||||
|
|
||||||
- name: Delete lingering ECR repository
|
- name: Delete lingering ECR repository
|
||||||
|
|
Loading…
Reference in a new issue