diff --git a/jenkins-ec2-agents.cfhighlander.rb b/jenkins-ec2-agents.cfhighlander.rb index bed01b6..18b6464 100644 --- a/jenkins-ec2-agents.cfhighlander.rb +++ b/jenkins-ec2-agents.cfhighlander.rb @@ -13,5 +13,6 @@ ComponentParam 'Subnets', type: 'CommaDelimitedList' end + LambdaFunctions 'ami_finder_custom_resources' end diff --git a/jenkins-ec2-agents.cfndsl.rb b/jenkins-ec2-agents.cfndsl.rb index 6841885..acc8863 100644 --- a/jenkins-ec2-agents.cfndsl.rb +++ b/jenkins-ec2-agents.cfndsl.rb @@ -40,18 +40,24 @@ Tags agent_tags } + Resource(:LinuxAmiFinder) { + Type 'Custom::LinuxAmiFinder' + Property 'ServiceToken', FnGetAtt(:AmiFinderCR, :Arn) + Property 'Name', linux_ami + } + SSM_Parameter(:LinuxAmiParameter) { Description "AMI Id for the Jenkins linux agent" Name FnSub("/ciinabox/${EnvironmentName}/agent/linux/ami") Property('Tier','Standard') Type 'String' - Value 'ami-replaceme' + Value Ref(:LinuxAmiFinder) Property('Tags',{ Name: "#{external_parameters[:component_name]}-linux-ami", EnvironmentName: Ref(:EnvironmentName) }) } - + SSM_Parameter(:WindowsAmiParameter) { Description "AMI Id for the Jenkins linux agent" Name FnSub("/ciinabox/${EnvironmentName}/agent/windows/ami") diff --git a/jenkins-ec2-agents.config.yaml b/jenkins-ec2-agents.config.yaml index 741c31f..3d4b023 100644 --- a/jenkins-ec2-agents.config.yaml +++ b/jenkins-ec2-agents.config.yaml @@ -1,3 +1,5 @@ +linux_ami: 'Amzn2_Linux_Jenkins_Agent-*' + iam_policies: sts: action: @@ -27,4 +29,30 @@ iam_policies: - ssmmessages:CreateControlChannel - ssmmessages:CreateDataChannel - ssmmessages:OpenControlChannel - - ssmmessages:OpenDataChannel \ No newline at end of file + - ssmmessages:OpenDataChannel + +ami_finder_custom_resources: + custom_policies: + ami: + action: + - ec2:DescribeImages + resource: '*' + lambda: + action: + - lambda:InvokeFunction + resource: + Fn::Sub: arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:AmiFinderCR + roles: + AmiFinderResource: + policies_inline: + - cloudwatch-logs + - ami + - lambda + functions: + AmiFinderCR: + code: ami_finder/app.py + handler: app.handler + runtime: python3.8 + timeout: 600 + role: AmiFinderResource + package_cmd: 'pip install -r requirements.txt -t .' \ No newline at end of file diff --git a/lambdas/ami_finder/app.py b/lambdas/ami_finder/app.py new file mode 100644 index 0000000..ca7a9e7 --- /dev/null +++ b/lambdas/ami_finder/app.py @@ -0,0 +1,41 @@ +import boto3 +from crhelper import CfnResource +import logging +import json + +logger = logging.getLogger(__name__) +# Initialise the helper, all inputs are optional, this example shows the defaults +helper = CfnResource(json_logging=False, log_level='DEBUG', boto_level='CRITICAL') + +@helper.create +def create(event, context): + logger.info(f"Creating resource {event}") + return get_latest_ami(event['ResourceProperties']['Name']) + +@helper.update +def update(event, context): + logger.info(f"Updating resource {event}") + return get_latest_ami(event['ResourceProperties']['Name']) + +@helper.delete +def delete(event, context): + logger.info(f"Deleting resource {event}") + +def get_latest_ami(name): + client = boto3.client('ec2') + + filters = [] + filters.append({'Name': 'name', 'Values': [name]}) + response = client.describe_images(Filters=filters) + + if not response['Images']: + return None + + response['Images'].sort(key=lambda r: r['CreationDate']) + return response['Images'][-1]['ImageId'] + +def handler(event, context): + helper(event, context) + + + 'Amzn2_Linux_Jenkins_Agent-*' \ No newline at end of file diff --git a/lambdas/ami_finder/requirements.txt b/lambdas/ami_finder/requirements.txt new file mode 100644 index 0000000..aa484ff --- /dev/null +++ b/lambdas/ami_finder/requirements.txt @@ -0,0 +1 @@ +crhelper \ No newline at end of file