Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for multiple input artifacts to the CloudFormation action #16

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cumulus/chain/chain.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from cumulus.chain import chaincontext # noqa
from cumulus.chain.params import TemplateRequirements # noqa
from cumulus.util.tropo import TemplateQuery # noqa
from cumulus.util.template_query import TemplateQuery # noqa


class Chain:
Expand Down
4 changes: 2 additions & 2 deletions cumulus/steps/dev_tools/approval_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import cumulus.policies
import cumulus.policies.codebuild
import cumulus.types.codebuild.buildaction
import cumulus.util.tropo
import cumulus.util.template_query
from cumulus.chain import step
from cumulus.steps.dev_tools import META_PIPELINE_BUCKET_POLICY_REF

Expand Down Expand Up @@ -67,7 +67,7 @@ def handle(self, chain_context):
template = chain_context.template
stage_to_add = self.stage_name_to_add

stage = cumulus.util.tropo.TemplateQuery.get_pipeline_stage_by_name(
stage = cumulus.util.template_query.TemplateQuery.get_pipeline_stage_by_name(
template=template,
stage_name=stage_to_add,
)
Expand Down
34 changes: 22 additions & 12 deletions cumulus/steps/dev_tools/cloud_formation_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,26 @@ class CloudFormationAction(step.Step):

def __init__(self,
action_name,
input_artifact_name,
input_template_file,
input_configuration_file,
input_artifact_names,
input_template_path,
input_template_configuration,
stage_name_to_add,
stack_name,
action_mode):
"""
:type action_name: basestring Displayed on the console
:type input_artifact_names: [basestring] List of input artifacts
:type input_template_path: basestring Full path to cloudformation template (ex. ArtifactName::templatefolder/template.json)
:type input_configuration: basestring Full path to cloudformation config file (ex. ArtifactName::envfolder/parameters.json)
:type stage_name_to_add: basestring Name of the pipeline stage to add this action to
:type stack_name: basestring name of the stack that this action will build
:type action_mode: cumulus.types.cloudformation.action_mode.ActionMode The actual CloudFormation action to execute
"""
step.Step.__init__(self)
self.action_name = action_name
self.input_artifact_name = input_artifact_name
self.input_template_file = input_template_file
self.input_configuration_file = input_configuration_file
self.input_artifact_names = input_artifact_names
self.input_template_path = input_template_path
self.input_template_configuration = input_template_configuration
self.stage_name_to_add = stage_name_to_add
self.stack_name = stack_name
self.action_mode = action_mode
Expand Down Expand Up @@ -60,25 +66,29 @@ def handle(self, chain_context):
]
)

input_artifacts = []
for artifact_name in self.input_artifact_names:
input_artifacts.append(codepipeline.InputArtifacts(
Name=artifact_name
))

cloud_formation_action = cumulus.types.codebuild.buildaction.CloudFormationAction(
Name=self.action_name,
InputArtifacts=[
codepipeline.InputArtifacts(Name=self.input_artifact_name)
],
InputArtifacts=input_artifacts,
Configuration={
'ActionMode': self.action_mode.value,
'RoleArn': GetAtt(cloud_formation_role, 'Arn'),
'StackName': self.stack_name,
'Capabilities': 'CAPABILITY_NAMED_IAM',
'TemplateConfiguration': self.input_artifact_name + "::" + self.input_configuration_file,
'TemplatePath': self.input_artifact_name + '::' + self.input_template_file
'TemplateConfiguration': self.input_template_configuration,
'TemplatePath': self.input_template_path
},
RunOrder="1"
)

chain_context.template.add_resource(cloud_formation_role)

stage = cumulus.util.tropo.TemplateQuery.get_pipeline_stage_by_name(
stage = cumulus.util.template_query.TemplateQuery.get_pipeline_stage_by_name(
template=chain_context.template,
stage_name=self.stage_name_to_add
)
Expand Down
4 changes: 2 additions & 2 deletions cumulus/steps/dev_tools/code_build_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import cumulus.policies
import cumulus.policies.codebuild
import cumulus.types.codebuild.buildaction
import cumulus.util.tropo
import cumulus.util.template_query

from troposphere import iam,\
codebuild, codepipeline, Ref, ec2
Expand Down Expand Up @@ -107,7 +107,7 @@ def handle(self, chain_context):
chain_context.template.add_resource(project)

template = chain_context.template
stage = cumulus.util.tropo.TemplateQuery.get_pipeline_stage_by_name(
stage = cumulus.util.template_query.TemplateQuery.get_pipeline_stage_by_name(
template=template,
stage_name=self.stage_name_to_add,
)
Expand Down
2 changes: 1 addition & 1 deletion cumulus/steps/dev_tools/pipeline_source_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from cumulus.chain import step
from cumulus.steps.dev_tools import META_PIPELINE_BUCKET_POLICY_REF
from cumulus.types.codebuild.buildaction import SourceS3Action
from cumulus.util.tropo import TemplateQuery
from cumulus.util.template_query import TemplateQuery


class PipelineSourceAction(step.Step):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from cumulus.chain import step
from cumulus.steps.dev_tools import META_PIPELINE_BUCKET_POLICY_REF
from cumulus.types.codebuild.buildaction import SourceCodeCommitAction
from cumulus.util.tropo import TemplateQuery
from cumulus.util.template_query import TemplateQuery


class SourceActionCodeCommit(step.Step):
Expand Down
2 changes: 1 addition & 1 deletion cumulus/steps/dev_tools/pipeline_stage.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from troposphere import codepipeline

from cumulus.chain import step
from cumulus.util.tropo import TemplateQuery
from cumulus.util.template_query import TemplateQuery


class PipelineStage(step.Step):
Expand Down
File renamed without changes.
115 changes: 115 additions & 0 deletions tests/unit/steps/dev_tools/test_cloud_formation_action.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
try:
# python 3
from unittest.mock import patch # noqa
from unittest.mock import MagicMock
except: # noqa
# python 2
from mock import patch, MagicMock # noqa

import unittest

import troposphere
from troposphere import codepipeline

from cumulus.chain import chaincontext
from cumulus.steps.dev_tools import cloud_formation_action, META_PIPELINE_BUCKET_POLICY_REF
from cumulus.types.cloudformation import action_mode
from cumulus.util.template_query import TemplateQuery


class TestCloudFormationAction(unittest.TestCase):

def setUp(self):
self.context = chaincontext.ChainContext(
template=troposphere.Template(),
instance_name='justtestin'
)
self.context.metadata[META_PIPELINE_BUCKET_POLICY_REF] = "blah"

self.pipeline_name = "ThatPipeline"
self.deploy_stage_name = "DeployIt"
TestCloudFormationAction._add_pipeline_and_stage_to_template(self.context.template, self.pipeline_name, self.deploy_stage_name)

def tearDown(self):
del self.context

@staticmethod
def _add_pipeline_and_stage_to_template(template, pipeline_name, deploy_stage_name):
pipeline = template.add_resource(troposphere.codepipeline.Pipeline(
pipeline_name,
Stages=[]
))

# Not worrying about adding a source stage right now, as the tests are not assumed to actually
# trigger a CloudFormation build of the pipeline

deploy_stage = template.add_resource(troposphere.codepipeline.Stages(
Name=deploy_stage_name,
Actions=[]
))
pipeline.properties['Stages'].append(deploy_stage)

def test_handle_adds_cloud_formation_action_to_stage(self):
action = cloud_formation_action.CloudFormationAction(
action_name="CloudFormation",
input_artifact_names=["InfraInput"],
input_template_path="InfraInput::template.json",
input_template_configuration="InfraInput::myenv.json",
stage_name_to_add=self.deploy_stage_name,
stack_name="my-microservice",
action_mode=action_mode.ActionMode.REPLACE_ON_FAILURE
)

action.handle(self.context)

deploy_stage = TemplateQuery.get_resource_by_type(self.context.template, codepipeline.Stages)[0]
self.assertEqual(len(deploy_stage.Actions), 1)

test_action = deploy_stage.Actions[0]
self.assertEqual(test_action.Name, "CloudFormation")
self.assertEqual(test_action.ActionTypeId.Category, "Deploy")
self.assertEqual(test_action.ActionTypeId.Provider, "CloudFormation")
self.assertEqual(test_action.Configuration['TemplatePath'], "InfraInput::template.json")
self.assertEqual(test_action.Configuration['TemplateConfiguration'], "InfraInput::myenv.json")
self.assertEqual(test_action.Configuration['ActionMode'], action_mode.ActionMode.REPLACE_ON_FAILURE.value)
self.assertEquals(len(test_action.InputArtifacts), 1)
self.assertEquals(test_action.InputArtifacts[0].Name, "InfraInput")

def test_raises_error_if_target_stage_does_not_exist(self):
action = cloud_formation_action.CloudFormationAction(
action_name="CloudFormation",
input_artifact_names=["InfraInput"],
input_template_path="InfraInput::template.json",
input_template_configuration="InfraInput::myenv.json",
stage_name_to_add="ThisStageDoesNotExist",
stack_name="my-microservice",
action_mode=action_mode.ActionMode.REPLACE_ON_FAILURE
)
self.assertRaises(
ValueError,
action.handle,
self.context)

def test_can_add_multiple_input_artifacts(self):
action = cloud_formation_action.CloudFormationAction(
action_name="CloudFormation",
input_artifact_names=["InfraInput", "ParameterInput"],
input_template_path="InfraInput::template.json",
input_template_configuration="ParameterInput::myenv.json",
stage_name_to_add=self.deploy_stage_name,
stack_name="my-microservice",
action_mode=action_mode.ActionMode.REPLACE_ON_FAILURE
)

action.handle(self.context)

deploy_stage = TemplateQuery.get_resource_by_type(self.context.template, codepipeline.Stages)[0]
self.assertEqual(len(deploy_stage.Actions), 1)

test_action = deploy_stage.Actions[0]
self.assertEqual(test_action.Name, "CloudFormation")
self.assertEqual(test_action.Configuration['TemplatePath'], "InfraInput::template.json")
self.assertEqual(test_action.Configuration['TemplateConfiguration'], "ParameterInput::myenv.json")
self.assertEquals(len(test_action.InputArtifacts), 2)
self.assertEquals(test_action.InputArtifacts[0].Name, "InfraInput")
self.assertEquals(test_action.InputArtifacts[1].Name, "ParameterInput")
2 changes: 1 addition & 1 deletion tests/unit/steps/test_pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from cumulus.chain import chaincontext
from cumulus.steps.dev_tools import pipeline, code_build_action
from cumulus.steps.dev_tools.vpc_config import VpcConfig
from cumulus.util.tropo import TemplateQuery
from cumulus.util.template_query import TemplateQuery


class TestPipelineStep(unittest.TestCase):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
import troposphere
import troposphere.s3

from cumulus.util.tropo import TemplateQuery
from cumulus.util.template_query import TemplateQuery


class TestPipelineStep(unittest.TestCase):
class TestTemplateQuery(unittest.TestCase):

def setUp(self):
pass
Expand Down