ansible/test/support/integration/plugins/modules/aws_codebuild.py
Matt Clay e3591223a0
Second batch of incidental integration tests. (#67765)
* Update incidental test aliases.

* Rewrite target references for renamed targets.

* Add incidental tests to CI.

* Update sanity tests for incidental cloud tests.

* Initial copy of incidental tests.

* Copy contrib files into test.

* Update paths in test.

* Add support plugins.

* Update plugin to work around missing deps.

* Update sanity ignores.

* Fix matrix entries.

* Remove debug echo.
2020-02-25 23:18:50 -08:00

408 lines
15 KiB
Python

#!/usr/bin/python
# Copyright: Ansible Project
# 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
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: aws_codebuild
short_description: Create or delete an AWS CodeBuild project
notes:
- For details of the parameters and returns see U(http://boto3.readthedocs.io/en/latest/reference/services/codebuild.html).
description:
- Create or delete a CodeBuild projects on AWS, used for building code artifacts from source code.
version_added: "2.9"
author:
- Stefan Horning (@stefanhorning) <horning@mediapeers.com>
requirements: [ botocore, boto3 ]
options:
name:
description:
- Name of the CodeBuild project.
required: true
type: str
description:
description:
- Descriptive text of the CodeBuild project.
type: str
source:
description:
- Configure service and location for the build input source.
required: true
suboptions:
type:
description:
- "The type of the source. Allows one of these: C(CODECOMMIT), C(CODEPIPELINE), C(GITHUB), C(S3), C(BITBUCKET), C(GITHUB_ENTERPRISE)."
required: true
type: str
location:
description:
- Information about the location of the source code to be built. For type CODEPIPELINE location should not be specified.
type: str
git_clone_depth:
description:
- When using git you can specify the clone depth as an integer here.
type: int
buildspec:
description:
- The build spec declaration to use for the builds in this build project. Leave empty if part of the code project.
type: str
insecure_ssl:
description:
- Enable this flag to ignore SSL warnings while connecting to the project source code.
type: bool
type: dict
artifacts:
description:
- Information about the build output artifacts for the build project.
required: true
suboptions:
type:
description:
- "The type of build output for artifacts. Can be one of the following: C(CODEPIPELINE), C(NO_ARTIFACTS), C(S3)."
required: true
location:
description:
- Information about the build output artifact location. When choosing type S3, set the bucket name here.
path:
description:
- Along with namespace_type and name, the pattern that AWS CodeBuild will use to name and store the output artifacts.
- Used for path in S3 bucket when type is C(S3).
namespace_type:
description:
- Along with path and name, the pattern that AWS CodeBuild will use to determine the name and location to store the output artifacts.
- Accepts C(BUILD_ID) and C(NONE).
- "See docs here: U(http://boto3.readthedocs.io/en/latest/reference/services/codebuild.html#CodeBuild.Client.create_project)."
name:
description:
- Along with path and namespace_type, the pattern that AWS CodeBuild will use to name and store the output artifact.
packaging:
description:
- The type of build output artifact to create on S3, can be NONE for creating a folder or ZIP for a ZIP file.
type: dict
cache:
description:
- Caching params to speed up following builds.
suboptions:
type:
description:
- Cache type. Can be C(NO_CACHE) or C(S3).
required: true
location:
description:
- Caching location on S3.
required: true
type: dict
environment:
description:
- Information about the build environment for the build project.
suboptions:
type:
description:
- The type of build environment to use for the project. Usually C(LINUX_CONTAINER).
required: true
image:
description:
- The ID of the Docker image to use for this build project.
required: true
compute_type:
description:
- Information about the compute resources the build project will use.
- "Available values include: C(BUILD_GENERAL1_SMALL), C(BUILD_GENERAL1_MEDIUM), C(BUILD_GENERAL1_LARGE)."
required: true
environment_variables:
description:
- A set of environment variables to make available to builds for the build project. List of dictionaries with name and value fields.
- "Example: { name: 'MY_ENV_VARIABLE', value: 'test' }"
privileged_mode:
description:
- Enables running the Docker daemon inside a Docker container. Set to true only if the build project is be used to build Docker images.
type: dict
service_role:
description:
- The ARN of the AWS IAM role that enables AWS CodeBuild to interact with dependent AWS services on behalf of the AWS account.
type: str
timeout_in_minutes:
description:
- How long CodeBuild should wait until timing out any build that has not been marked as completed.
default: 60
type: int
encryption_key:
description:
- The AWS Key Management Service (AWS KMS) customer master key (CMK) to be used for encrypting the build output artifacts.
type: str
tags:
description:
- A set of tags for the build project.
type: list
elements: dict
suboptions:
key:
description: The name of the Tag.
type: str
value:
description: The value of the Tag.
type: str
vpc_config:
description:
- The VPC config enables AWS CodeBuild to access resources in an Amazon VPC.
type: dict
state:
description:
- Create or remove code build project.
default: 'present'
choices: ['present', 'absent']
type: str
extends_documentation_fragment:
- aws
- ec2
'''
EXAMPLES = '''
# Note: These examples do not set authentication details, see the AWS Guide for details.
- aws_codebuild:
name: my_project
description: My nice little project
service_role: "arn:aws:iam::123123:role/service-role/code-build-service-role"
source:
# Possible values: BITBUCKET, CODECOMMIT, CODEPIPELINE, GITHUB, S3
type: CODEPIPELINE
buildspec: ''
artifacts:
namespaceType: NONE
packaging: NONE
type: CODEPIPELINE
name: my_project
environment:
computeType: BUILD_GENERAL1_SMALL
privilegedMode: "true"
image: "aws/codebuild/docker:17.09.0"
type: LINUX_CONTAINER
environmentVariables:
- { name: 'PROFILE', value: 'staging' }
encryption_key: "arn:aws:kms:us-east-1:123123:alias/aws/s3"
region: us-east-1
state: present
'''
RETURN = '''
project:
description: Returns the dictionary describing the code project configuration.
returned: success
type: complex
contains:
name:
description: Name of the CodeBuild project
returned: always
type: str
sample: my_project
arn:
description: ARN of the CodeBuild project
returned: always
type: str
sample: arn:aws:codebuild:us-east-1:123123123:project/vod-api-app-builder
description:
description: A description of the build project
returned: always
type: str
sample: My nice little project
source:
description: Information about the build input source code.
returned: always
type: complex
contains:
type:
description: The type of the repository
returned: always
type: str
sample: CODEPIPELINE
location:
description: Location identifier, depending on the source type.
returned: when configured
type: str
git_clone_depth:
description: The git clone depth
returned: when configured
type: int
build_spec:
description: The build spec declaration to use for the builds in this build project.
returned: always
type: str
auth:
description: Information about the authorization settings for AWS CodeBuild to access the source code to be built.
returned: when configured
type: complex
insecure_ssl:
description: True if set to ignore SSL warnings.
returned: when configured
type: bool
artifacts:
description: Information about the output of build artifacts
returned: always
type: complex
contains:
type:
description: The type of build artifact.
returned: always
type: str
sample: CODEPIPELINE
location:
description: Output location for build artifacts
returned: when configured
type: str
# and more... see http://boto3.readthedocs.io/en/latest/reference/services/codebuild.html#CodeBuild.Client.create_project
cache:
description: Cache settings for the build project.
returned: when configured
type: dict
environment:
description: Environment settings for the build
returned: always
type: dict
service_role:
description: IAM role to be used during build to access other AWS services.
returned: always
type: str
sample: arn:aws:iam::123123123:role/codebuild-service-role
timeout_in_minutes:
description: The timeout of a build in minutes
returned: always
type: int
sample: 60
tags:
description: Tags added to the project
returned: when configured
type: list
created:
description: Timestamp of the create time of the project
returned: always
type: str
sample: "2018-04-17T16:56:03.245000+02:00"
'''
from ansible.module_utils.aws.core import AnsibleAWSModule, get_boto3_client_method_parameters
from ansible.module_utils.ec2 import camel_dict_to_snake_dict, snake_dict_to_camel_dict
try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule
def create_or_update_project(client, params, module):
resp = {}
name = params['name']
# clean up params
formatted_params = snake_dict_to_camel_dict(dict((k, v) for k, v in params.items() if v is not None))
permitted_create_params = get_boto3_client_method_parameters(client, 'create_project')
permitted_update_params = get_boto3_client_method_parameters(client, 'update_project')
formatted_create_params = dict((k, v) for k, v in formatted_params.items() if k in permitted_create_params)
formatted_update_params = dict((k, v) for k, v in formatted_params.items() if k in permitted_update_params)
# Check if project with that name already exists and if so update existing:
found = describe_project(client=client, name=name, module=module)
changed = False
if 'name' in found:
found_project = found
resp = update_project(client=client, params=formatted_update_params, module=module)
updated_project = resp['project']
# Prep both dicts for sensible change comparison:
found_project.pop('lastModified')
updated_project.pop('lastModified')
if 'tags' not in updated_project:
updated_project['tags'] = []
if updated_project != found_project:
changed = True
return resp, changed
# Or create new project:
try:
resp = client.create_project(**formatted_create_params)
changed = True
return resp, changed
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to create CodeBuild project")
def update_project(client, params, module):
name = params['name']
try:
resp = client.update_project(**params)
return resp
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to update CodeBuild project")
def delete_project(client, name, module):
found = describe_project(client=client, name=name, module=module)
changed = False
if 'name' in found:
# Mark as changed when a project with that name existed before calling delete
changed = True
try:
resp = client.delete_project(name=name)
return resp, changed
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to delete CodeBuild project")
def describe_project(client, name, module):
project = {}
try:
projects = client.batch_get_projects(names=[name])['projects']
if len(projects) > 0:
project = projects[0]
return project
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="Unable to describe CodeBuild projects")
def main():
argument_spec = dict(
name=dict(required=True),
description=dict(),
source=dict(required=True, type='dict'),
artifacts=dict(required=True, type='dict'),
cache=dict(type='dict'),
environment=dict(type='dict'),
service_role=dict(),
timeout_in_minutes=dict(type='int', default=60),
encryption_key=dict(),
tags=dict(type='list'),
vpc_config=dict(type='dict'),
state=dict(choices=['present', 'absent'], default='present')
)
module = AnsibleAWSModule(argument_spec=argument_spec)
client_conn = module.client('codebuild')
state = module.params.get('state')
changed = False
if state == 'present':
project_result, changed = create_or_update_project(
client=client_conn,
params=module.params,
module=module)
elif state == 'absent':
project_result, changed = delete_project(client=client_conn, name=module.params['name'], module=module)
module.exit_json(changed=changed, **camel_dict_to_snake_dict(project_result))
if __name__ == '__main__':
main()