From 0c6513e9b141fb6cdd6bfaae6f0090456a0a86ce Mon Sep 17 00:00:00 2001 From: Shuang Wang Date: Thu, 18 Oct 2018 13:32:06 +0900 Subject: [PATCH] add module aws_codecommit to represent AWS CodeCommit (#46161) * kick off * done for the day * beta code and test * fix a typo * boto3_conn and boto_exception aren't used in this code, ec2_argument_spec is used but unneeded. * Returning when find a match avoids doing extra work, especially when pagination is involved * add new permissions for test * (output is changed) is preferred over accessing the attribute directly. * pass the result through camel_dict_to_snake_dict() before returning it. * AnsibleAWSModule automatically merges the argument_spec. * deletes the created resources even if a test fails. * AnsibleAWSModule automatically merges the argument_spec. * fix typo * fix pep8 * paginate list_repositories * specify permissions for test * cut the unnecessary code. * add return doc string * add missed ':' * fix syntax error: mapping values are not allowed here * add description for return * fix syntax error * rename module name and turn off automated integration test. --- .../testing_policies/devops-policy.json | 17 ++ .../modules/cloud/amazon/aws_codecommit.py | 213 ++++++++++++++++++ .../targets/aws_codecommit/aliases | 2 + .../targets/aws_codecommit/tasks/main.yml | 67 ++++++ 4 files changed, 299 insertions(+) create mode 100644 hacking/aws_config/testing_policies/devops-policy.json create mode 100644 lib/ansible/modules/cloud/amazon/aws_codecommit.py create mode 100644 test/integration/targets/aws_codecommit/aliases create mode 100644 test/integration/targets/aws_codecommit/tasks/main.yml diff --git a/hacking/aws_config/testing_policies/devops-policy.json b/hacking/aws_config/testing_policies/devops-policy.json new file mode 100644 index 00000000000..3b8def2d65e --- /dev/null +++ b/hacking/aws_config/testing_policies/devops-policy.json @@ -0,0 +1,17 @@ +{ + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "AllowCodeCommitModuleTests", + "Effect": "Allow", + "Action": [ + "codecommit:ListRepositories", + "codecommit:CreateRepositories", + "codecommit:DeleteRpositories" + ], + "Resource": [ + "arn:aws:codecommit:*" + ] + } + ] +} \ No newline at end of file diff --git a/lib/ansible/modules/cloud/amazon/aws_codecommit.py b/lib/ansible/modules/cloud/amazon/aws_codecommit.py new file mode 100644 index 00000000000..154a410fe44 --- /dev/null +++ b/lib/ansible/modules/cloud/amazon/aws_codecommit.py @@ -0,0 +1,213 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# Copyright: (c) 2018, Shuang Wang +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +ANSIBLE_METADATA = {'status': ['preview'], + 'supported_by': 'community', + 'metadata_version': '1.1'} + +DOCUMENTATION = ''' +--- +module: aws_codecommit +version_added: "2.8" +short_description: Manage repositories in AWS CodeCommit +description: + - Supports creation and deletion of CodeCommit repositories. + - See U(https://aws.amazon.com/codecommit/) for more information about CodeCommit. +author: Shuang Wang (@ptux) + +requirements: + - botocore + - boto3 + - python >= 2.6 + +options: + name: + description: + - name of repository. + required: true + comment: + description: + - description or comment of repository. + required: false + state: + description: + - Specifies the state of repository. + required: true + choices: [ 'present', 'absent' ] + +extends_documentation_fragment: + - aws + - ec2 +''' + +RETURN = ''' +repository_metadata: + description: "Information about the repository." + returned: always + type: complex + contains: + account_id: + description: "The ID of the AWS account associated with the repository." + returned: when state is present + type: string + sample: "268342293637" + arn: + description: "The Amazon Resource Name (ARN) of the repository." + returned: when state is present + type: string + sample: "arn:aws:codecommit:ap-northeast-1:268342293637:username" + clone_url_http: + description: "The URL to use for cloning the repository over HTTPS." + returned: when state is present + type: string + sample: "https://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/reponame" + clone_url_ssh: + description: "The URL to use for cloning the repository over SSH." + returned: when state is present + type: string + sample: "ssh://git-codecommit.ap-northeast-1.amazonaws.com/v1/repos/reponame" + creation_date: + description: "The date and time the repository was created, in timestamp format." + returned: when state is present + type: datetime + sample: "2018-10-16T13:21:41.261000+09:00" + last_modified_date: + description: "The date and time the repository was last modified, in timestamp format." + returned: when state is present + type: string + sample: "2018-10-16T13:21:41.261000+09:00" + repository_description: + description: "A comment or description about the repository." + returned: when state is present + type: string + sample: "test from ptux" + repository_id: + description: "The ID of the repository that was created or deleted" + returned: always + type: string + sample: "e62a5c54-i879-497b-b62f-9f99e4ebfk8e" + repository_name: + description: "The repository's name." + returned: when state is present + type: string + sample: "reponame" + +response_metadata: + description: "Information about the response." + returned: always + type: complex + contains: + http_headers: + description: "http headers of http response" + returned: always + type: complex + http_status_code: + description: "http status code of http response" + returned: always + type: string + sample: "200" + request_id: + description: "http request id" + returned: always + type: string + sample: "fb49cfca-d0fa-11e8-85cb-b3cc4b5045ef" + retry_attempts: + description: "numbers of retry attempts" + returned: always + type: string + sample: "0" +''' + +EXAMPLES = ''' +# Create a new repository +- aws_codecommit: + name: repo + state: present + +# Delete a repository +- aws_codecommit: + name: repo + state: absent +''' + +try: + import botocore +except ImportError: + pass # Handled by AnsibleAWSModule + +from ansible.module_utils.aws.core import AnsibleAWSModule +from ansible.module_utils.ec2 import camel_dict_to_snake_dict + + +class CodeCommit(object): + def __init__(self, module=None): + self._module = module + self._client = self._module.client('codecommit') + self._check_mode = self._module.check_mode + + def process(self): + result = dict(changed=False) + + if self._module.params['state'] == 'present' and not self._repository_exists(): + if not self._module.check_mode: + result = self._create_repository() + result['changed'] = True + if self._module.params['state'] == 'absent' and self._repository_exists(): + if not self._module.check_mode: + result = self._delete_repository() + result['changed'] = True + return result + + def _repository_exists(self): + try: + paginator = self._client.get_paginator('list_repositories') + for page in paginator.paginate(): + repositories = page['repositories'] + for item in repositories: + if self._module.params['name'] in item.values(): + return True + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + self._module.fail_json_aws(e, msg="couldn't get repository") + return False + + def _create_repository(self): + try: + result = self._client.create_repository( + repositoryName=self._module.params['name'], + repositoryDescription=self._module.params['comment'] + ) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + self._module.fail_json_aws(e, msg="couldn't create repository") + return result + + def _delete_repository(self): + try: + result = self._client.delete_repository( + repositoryName=self._module.params['name'] + ) + except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e: + self._module.fail_json_aws(e, msg="couldn't delete repository") + return result + + +def main(): + argument_spec = dict( + name=dict(required=True), + state=dict(choices=['present', 'absent'], required=True), + comment=dict(default='') + ) + + ansible_aws_module = AnsibleAWSModule( + argument_spec=argument_spec, + supports_check_mode=True + ) + + aws_codecommit = CodeCommit(module=ansible_aws_module) + result = aws_codecommit.process() + ansible_aws_module.exit_json(**camel_dict_to_snake_dict(result)) + + +if __name__ == '__main__': + main() diff --git a/test/integration/targets/aws_codecommit/aliases b/test/integration/targets/aws_codecommit/aliases new file mode 100644 index 00000000000..56927195182 --- /dev/null +++ b/test/integration/targets/aws_codecommit/aliases @@ -0,0 +1,2 @@ +cloud/aws +unsupported diff --git a/test/integration/targets/aws_codecommit/tasks/main.yml b/test/integration/targets/aws_codecommit/tasks/main.yml new file mode 100644 index 00000000000..834ddc1e08b --- /dev/null +++ b/test/integration/targets/aws_codecommit/tasks/main.yml @@ -0,0 +1,67 @@ +--- +- block: + # ============================================================ + - name: set connection information for all tasks + set_fact: + aws_connection_info: &aws_connection_info + aws_access_key: "{{ aws_access_key }}" + aws_secret_key: "{{ aws_secret_key }}" + security_token: "{{ security_token }}" + region: "{{ aws_region }}" + no_log: true + # ============================================================ + - name: Create a repository + aws_codecommit: + name: "{{ resource_prefix }}_repo" + comment: original comment + state: present + <<: *aws_connection_info + register: output + - assert: + that: + - output is changed + - output.repositoryName == '{{ resource_prefix }}_repo' + - output.repositoryDescription == 'original comment' + # ============================================================ + - name: Create a repository (CHECK MODE) + aws_codecommit: + name: "{{ resource_prefix }}_check_repo" + comment: original comment + state: present + <<: *aws_connection_info + register: output + check_mode: yes + - assert: + that: + - output is changed + - output.repositoryName == '{{ resource_prefix }}_check_repo' + - output.repositoryDescription == 'original comment' + # ============================================================ + - name: Delete a repository (CHECK MODE) + aws_codecommit: + name: "{{ resource_prefix }}_repo" + state: absent + <<: *aws_connection_info + register: output + check_mode: yes + - assert: + that: + - output is changed + - name: Delete a repository + aws_codecommit: + name: "{{ resource_prefix }}_repo" + state: absent + <<: *aws_connection_info + register: output + - assert: + that: + - output is changed + + always: + ###### TEARDOWN STARTS HERE ###### + - name: Delete a repository + aws_codecommit: + name: "{{ resource_prefix }}_repo" + state: absent + <<: *aws_connection_info + ignore_errors: yes