Add Ability to use the AWS Cloudformation Plugin

* This plugin gives Jenkins the ability to spawn amazon
cloudformation stacks before running the build and stopping it at
the end

* This change adds cloudformation ability to the builders and the
publishers to create stacks and to the publishers to tear the stack
down

Change-Id: I8041382fc6f1d569c322088a3bc8812332a131e8
This commit is contained in:
Will Soula 2015-07-15 15:44:08 -05:00
parent dc28559b05
commit 7de0dc598e
8 changed files with 316 additions and 1 deletions

View File

@ -40,6 +40,9 @@ Example::
import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base
from jenkins_jobs.modules import hudson_model
from jenkins_jobs.modules.helpers import cloudformation_init
from jenkins_jobs.modules.helpers import cloudformation_region_dict
from jenkins_jobs.modules.helpers import cloudformation_stack
from jenkins_jobs.modules.helpers import config_file_provider_builder
from jenkins_jobs.modules.helpers import config_file_provider_settings
from jenkins_jobs.errors import (JenkinsJobsException,
@ -2389,3 +2392,46 @@ def beaker(parser, xml_parent, data):
XML.SubElement(beaker, 'downloadFiles').text = str(data.get(
'download-logs', False)).lower()
def cloudformation(parser, xml_parent, data):
"""yaml: cloudformation
Create cloudformation stacks before running a build and optionally
delete them at the end. Requires the Jenkins :jenkins-wiki:`AWS
Cloudformation Plugin <AWS+Cloudformation+Plugin>`.
:arg list name: The names of the stacks to create (Required)
:arg str description: Description of the stack (Optional)
:arg str recipe: The cloudformation recipe file (Required)
:arg list parameters: List of key/value pairs to pass
into the recipe, will be joined together into a comma separated
string (Optional)
:arg int timeout: Number of seconds to wait before giving up creating
a stack (default 0)
:arg str access-key: The Amazon API Access Key (Required)
:arg str secret-key: The Amazon API Secret Key (Required)
:arg int sleep: Number of seconds to wait before continuing to the
next step (default 0)
:arg array region: The region to run cloudformation in (Required)
:region values:
* **us-east-1**
* **us-west-1**
* **us-west-2**
* **eu-central-1**
* **eu-west-1**
* **ap-southeast-1**
* **ap-southeast-2**
* **ap-northeast-1**
* **sa-east-1**
Example:
.. literalinclude:: ../../tests/builders/fixtures/cloudformation.yaml
:language: yaml
"""
region_dict = cloudformation_region_dict()
stacks = cloudformation_init(xml_parent, data, 'CloudFormationBuildStep')
for stack in data:
cloudformation_stack(xml_parent, stack, 'PostBuildStackBean', stacks,
region_dict)

View File

@ -15,8 +15,10 @@
import xml.etree.ElementTree as XML
import logging
from jenkins_jobs.errors import JenkinsJobsException
from six.moves import configparser
from jenkins_jobs.errors import (JenkinsJobsException,
MissingAttributeError,
InvalidAttributeError)
def build_trends_publisher(plugin_name, xml_element, data):
@ -189,3 +191,54 @@ def get_value_from_yaml_or_config_file(key, section, data, parser):
" the " + section + " section, blank default" +
" value will be applied:\n{0}".format(e))
return result
def cloudformation_region_dict():
region_dict = {'us-east-1': 'US_East_Northern_Virginia',
'us-west-1': 'US_WEST_Northern_California',
'us-west-2': 'US_WEST_Oregon',
'eu-central-1': 'EU_Frankfurt',
'eu-west-1': 'EU_Ireland',
'ap-southeast-1': 'Asia_Pacific_Singapore',
'ap-southeast-2': 'Asia_Pacific_Sydney',
'ap-northeast-1': 'Asia_Pacific_Tokyo',
'sa-east-1': 'South_America_Sao_Paulo'}
return region_dict
def cloudformation_init(xml_parent, data, xml_tag):
cloudformation = XML.SubElement(
xml_parent, 'com.syncapse.jenkinsci.'
'plugins.awscloudformationwrapper.' + xml_tag)
return XML.SubElement(cloudformation, 'stacks')
def cloudformation_stack(xml_parent, stack, xml_tag, stacks, region_dict):
if 'name' not in stack or stack['name'] == '':
raise MissingAttributeError('name')
step = XML.SubElement(
stacks, 'com.syncapse.jenkinsci.plugins.'
'awscloudformationwrapper.' + xml_tag)
try:
XML.SubElement(step, 'stackName').text = stack['name']
XML.SubElement(step, 'awsAccessKey').text = stack['access-key']
XML.SubElement(step, 'awsSecretKey').text = stack['secret-key']
region = stack['region']
except KeyError as e:
raise MissingAttributeError(e.args[0])
if region not in region_dict:
raise InvalidAttributeError('region', region, region_dict.keys())
XML.SubElement(step, 'awsRegion').text = region_dict.get(region)
if xml_tag == 'SimpleStackBean':
prefix = str(stack.get('prefix', False)).lower()
XML.SubElement(step, 'isPrefixSelected').text = prefix
else:
XML.SubElement(step, 'description').text = stack.get('description', '')
XML.SubElement(step, 'parameters').text = ','.join(
stack.get('parameters', []))
XML.SubElement(step, 'timeout').text = str(stack.get('timeout', '0'))
XML.SubElement(step, 'sleep').text = str(stack.get('sleep', '0'))
try:
XML.SubElement(step, 'cloudFormationRecipe').text = stack['recipe']
except KeyError as e:
raise MissingAttributeError(e.args[0])

View File

@ -30,6 +30,9 @@ import xml.etree.ElementTree as XML
import jenkins_jobs.modules.base
from jenkins_jobs.modules import hudson_model
from jenkins_jobs.modules.helpers import build_trends_publisher
from jenkins_jobs.modules.helpers import cloudformation_init
from jenkins_jobs.modules.helpers import cloudformation_region_dict
from jenkins_jobs.modules.helpers import cloudformation_stack
from jenkins_jobs.modules.helpers import config_file_provider_settings
from jenkins_jobs.modules.helpers import findbugs_settings
from jenkins_jobs.modules.helpers import get_value_from_yaml_or_config_file
@ -4952,6 +4955,80 @@ def clamav(parser, xml_parent, data):
data.get('excludes', ''))
def cloudformation(parser, xml_parent, data):
"""yaml: cloudformation
Create cloudformation stacks before running a build and optionally
delete them at the end. Requires the Jenkins :jenkins-wiki:`AWS
Cloudformation Plugin <AWS+Cloudformation+Plugin>`.
:arg list create-stacks: List of stacks to create
:create-stacks attributes:
* **arg str name** - The name of the stack (Required)
* **arg str description** - Description of the stack (Optional)
* **arg str recipe** - The cloudformation recipe file (Required)
* **arg list parameters** - A list of key/value pairs, will be
joined together into a comma separated string (Optional)
* **arg int timeout** - Number of seconds to wait before giving up
creating a stack (default 0)
* **arg str access-key** - The Amazon API Access Key (Required)
* **arg str secret-key** - The Amazon API Secret Key (Required)
* **arg int sleep** - Number of seconds to wait before continuing
to the next step (default 0)
* **arg array region** - The region to run cloudformation in.
(Required)
:region values:
* **us-east-1**
* **us-west-1**
* **us-west-2**
* **eu-central-1**
* **eu-west-1**
* **ap-southeast-1**
* **ap-southeast-2**
* **ap-northeast-1**
* **sa-east-1**
:arg list delete-stacks: List of stacks to delete
:delete-stacks attributes:
* **arg list name** - The names of the stacks to delete (Required)
* **arg str access-key** - The Amazon API Access Key (Required)
* **arg str secret-key** - The Amazon API Secret Key (Required)
* **arg bool prefix** - If selected the tear down process will look
for the stack that Starts with the stack name with the oldest
creation date and will delete it. (Default False)
* **arg array region** - The region to run cloudformation in.
(Required)
:region values:
* **us-east-1**
* **us-west-1**
* **us-west-2**
* **eu-central-1**
* **eu-west-1**
* **ap-southeast-1**
* **ap-southeast-2**
* **ap-northeast-1**
* **sa-east-1**
Example:
.. literalinclude:: /../../tests/publishers/fixtures/cloudformation.yaml
:language: yaml
"""
region_dict = cloudformation_region_dict()
stacks = cloudformation_init(xml_parent, data, 'CloudFormationPostBuild'
'Notifier')
for stack in data.get('create-stacks', []):
cloudformation_stack(xml_parent, stack, 'PostBuildStackBean',
stacks, region_dict)
delete_stacks = cloudformation_init(xml_parent, data, 'CloudFormation'
'Notifier')
for delete_stack in data.get('delete-stacks', []):
cloudformation_stack(xml_parent, delete_stack, 'SimpleStackBean',
delete_stacks, region_dict)
class Publishers(jenkins_jobs.modules.base.Base):
sequence = 70

View File

@ -51,6 +51,7 @@ jenkins_jobs.builders =
beaker=jenkins_jobs.modules.builders:beaker
builders-from=jenkins_jobs.modules.builders:builders_from
change-assembly-version=jenkins_jobs.modules.builders:change_assembly_version
cloudformation=jenkins_jobs.modules.builders:cloudformation
cmake=jenkins_jobs.modules.builders:cmake
conditional-step=jenkins_jobs.modules.builders:conditional_step
config-file-provider=jenkins_jobs.modules.builders:config_file_provider
@ -145,6 +146,7 @@ jenkins_jobs.publishers =
claim-build=jenkins_jobs.modules.publishers:claim_build
clamav=jenkins_jobs.modules.publishers:clamav
clone-workspace=jenkins_jobs.modules.publishers:clone_workspace
cloudformation=jenkins_jobs.modules.publishers:cloudformation
cloverphp=jenkins_jobs.modules.publishers:cloverphp
cobertura=jenkins_jobs.modules.publishers:cobertura
conditional-publisher=jenkins_jobs.modules.publishers:conditional_publisher

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<builders>
<com.syncapse.jenkinsci.plugins.awscloudformationwrapper.CloudFormationBuildStep>
<stacks>
<com.syncapse.jenkinsci.plugins.awscloudformationwrapper.PostBuildStackBean>
<stackName>foo</stackName>
<awsAccessKey>$AWS_ACCESS_KEY</awsAccessKey>
<awsSecretKey>$AWS_SECRET_KEY</awsSecretKey>
<awsRegion>US_WEST_Oregon</awsRegion>
<description>Build the foo stack</description>
<parameters>Key1=foo,Key2=fuu</parameters>
<timeout>3600</timeout>
<sleep>5</sleep>
<cloudFormationRecipe>foo.json</cloudFormationRecipe>
</com.syncapse.jenkinsci.plugins.awscloudformationwrapper.PostBuildStackBean>
<com.syncapse.jenkinsci.plugins.awscloudformationwrapper.PostBuildStackBean>
<stackName>bar</stackName>
<awsAccessKey>$AWS_ACCESS_KEY</awsAccessKey>
<awsSecretKey>$AWS_SECRET_KEY</awsSecretKey>
<awsRegion>US_WEST_Northern_California</awsRegion>
<description>Build the bar stack</description>
<parameters>Key1=bar,Key2=baa</parameters>
<timeout>3600</timeout>
<sleep>0</sleep>
<cloudFormationRecipe>bar.json</cloudFormationRecipe>
</com.syncapse.jenkinsci.plugins.awscloudformationwrapper.PostBuildStackBean>
</stacks>
</com.syncapse.jenkinsci.plugins.awscloudformationwrapper.CloudFormationBuildStep>
</builders>
</project>

View File

@ -0,0 +1,23 @@
builders:
- cloudformation:
- name: "foo"
description: "Build the foo stack"
recipe: "foo.json"
parameters:
- "Key1=foo"
- "Key2=fuu"
timeout: 3600
access-key: "$AWS_ACCESS_KEY"
secret-key: "$AWS_SECRET_KEY"
region: us-west-2
sleep: 5
- name: "bar"
description: "Build the bar stack"
recipe: "bar.json"
parameters:
- "Key1=bar"
- "Key2=baa"
timeout: 3600
access-key: "$AWS_ACCESS_KEY"
secret-key: "$AWS_SECRET_KEY"
region: us-west-1

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<project>
<publishers>
<com.syncapse.jenkinsci.plugins.awscloudformationwrapper.CloudFormationPostBuildNotifier>
<stacks>
<com.syncapse.jenkinsci.plugins.awscloudformationwrapper.PostBuildStackBean>
<stackName>foo</stackName>
<awsAccessKey>$AWS_ACCESS_KEY</awsAccessKey>
<awsSecretKey>$AWS_SECRET_KEY</awsSecretKey>
<awsRegion>US_WEST_Oregon</awsRegion>
<description>Build the foo stack</description>
<parameters>Key1=foo,Key2=fuu</parameters>
<timeout>3600</timeout>
<sleep>5</sleep>
<cloudFormationRecipe>foo.json</cloudFormationRecipe>
</com.syncapse.jenkinsci.plugins.awscloudformationwrapper.PostBuildStackBean>
<com.syncapse.jenkinsci.plugins.awscloudformationwrapper.PostBuildStackBean>
<stackName>bar</stackName>
<awsAccessKey>$AWS_ACCESS_KEY</awsAccessKey>
<awsSecretKey>$AWS_SECRET_KEY</awsSecretKey>
<awsRegion>US_WEST_Northern_California</awsRegion>
<description>Build the bar stack</description>
<parameters>Key1=bar,Key2=baa</parameters>
<timeout>3600</timeout>
<sleep>0</sleep>
<cloudFormationRecipe>bar.json</cloudFormationRecipe>
</com.syncapse.jenkinsci.plugins.awscloudformationwrapper.PostBuildStackBean>
</stacks>
</com.syncapse.jenkinsci.plugins.awscloudformationwrapper.CloudFormationPostBuildNotifier>
<com.syncapse.jenkinsci.plugins.awscloudformationwrapper.CloudFormationNotifier>
<stacks>
<com.syncapse.jenkinsci.plugins.awscloudformationwrapper.SimpleStackBean>
<stackName>foo</stackName>
<awsAccessKey>$AWS_ACCESS_KEY</awsAccessKey>
<awsSecretKey>$AWS_SECRET_KEY</awsSecretKey>
<awsRegion>US_WEST_Oregon</awsRegion>
<isPrefixSelected>true</isPrefixSelected>
</com.syncapse.jenkinsci.plugins.awscloudformationwrapper.SimpleStackBean>
<com.syncapse.jenkinsci.plugins.awscloudformationwrapper.SimpleStackBean>
<stackName>bar</stackName>
<awsAccessKey>$AWS_ACCESS_KEY</awsAccessKey>
<awsSecretKey>$AWS_SECRET_KEY</awsSecretKey>
<awsRegion>US_WEST_Northern_California</awsRegion>
<isPrefixSelected>false</isPrefixSelected>
</com.syncapse.jenkinsci.plugins.awscloudformationwrapper.SimpleStackBean>
</stacks>
</com.syncapse.jenkinsci.plugins.awscloudformationwrapper.CloudFormationNotifier>
</publishers>
</project>

View File

@ -0,0 +1,34 @@
publishers:
- cloudformation:
create-stacks:
- name: "foo"
description: "Build the foo stack"
recipe: "foo.json"
parameters:
- "Key1=foo"
- "Key2=fuu"
timeout: 3600
access-key: "$AWS_ACCESS_KEY"
secret-key: "$AWS_SECRET_KEY"
region: us-west-2
sleep: 5
- name: "bar"
description: "Build the bar stack"
recipe: "bar.json"
parameters:
- "Key1=bar"
- "Key2=baa"
timeout: 3600
access-key: "$AWS_ACCESS_KEY"
secret-key: "$AWS_SECRET_KEY"
region: us-west-1
delete-stacks:
- name: "foo"
prefix: true
region: us-west-2
access-key: "$AWS_ACCESS_KEY"
secret-key: "$AWS_SECRET_KEY"
- name: "bar"
region: us-west-1
access-key: "$AWS_ACCESS_KEY"
secret-key: "$AWS_SECRET_KEY"