Skip to content

Commit

Permalink
Add support for cf and codepipeline parameters file formats to cf dep…
Browse files Browse the repository at this point in the history
…loy command
  • Loading branch information
Illia Batozskyi committed Aug 4, 2020
1 parent c8e273a commit d23c1e8
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 10 deletions.
79 changes: 69 additions & 10 deletions awscli/customizations/cloudformation/deploy.py
Expand Up @@ -11,13 +11,16 @@
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.

import functools
import json
import os
import sys
import logging

from botocore.client import Config

from awscli.compat import compat_open
from awscli.customizations.exceptions import ParamValidationError
from awscli.customizations.cloudformation import exceptions
from awscli.customizations.cloudformation.deployer import Deployer
from awscli.customizations.s3uploader import S3Uploader
Expand Down Expand Up @@ -107,12 +110,7 @@ class DeployCommand(BasicCommand):
'name': PARAMETER_OVERRIDE_CMD,
'action': 'store',
'required': False,
'schema': {
'type': 'array',
'items': {
'type': 'string'
}
},
'nargs': '+',
'default': [],
'help_text': (
'A list of parameter structures that specify input parameters'
Expand Down Expand Up @@ -255,10 +253,9 @@ def _run_main(self, parsed_args, parsed_globals):
template_str = handle.read()

stack_name = parsed_args.stack_name
parameter_overrides = self.parse_key_value_arg(
parsed_args.parameter_overrides,
self.PARAMETER_OVERRIDE_CMD)

parameter_overrides = self.parse_parameter_overrides(
parsed_args.parameter_overrides
)
tags_dict = self.parse_key_value_arg(parsed_args.tags, self.TAGS_CMD)
tags = [{"Key": key, "Value": value}
for key, value in tags_dict.items()]
Expand Down Expand Up @@ -359,6 +356,68 @@ def merge_parameters(self, template_dict, parameter_overrides):

return parameter_values

def _validate_cf_params(self, param):
if 'ParameterKey' in param and 'ParameterValue' in param:
if len(param.keys()) > 2:
raise ParamValidationError(
'CloudFormation like parameter JSON should have format '
'[{"ParameterKey": "string", "ParameterValue": "string"}]')
return True

def _cf_param_parser(self, data):
# Parse parameter_overrides if they were given in
# CloudFormation params file format
# [{
# "ParameterKey": "string",
# "ParameterValue": "string",
# }]
try:
return {
param['ParameterKey']: param['ParameterValue']
for param in data if self._validate_cf_params(param)
}
except (KeyError, TypeError):
return None

def _codepipeline_param_parser(self, data):
# Parse parameter_overrides if they were given in
# CodePipeline params file format
# {
# "Parameters": {
# "ParameterKey": "ParameterValue"
# }
# }
if isinstance(data, dict):
return data.get('Parameters', None)

def parse_parameter_overrides(self, arg_value):
if isinstance(arg_value, str):
data = json.loads(arg_value)
parsers = [
self._cf_param_parser,
self._codepipeline_param_parser,

]
result = functools.reduce(
lambda a, parser: a or parser(data),
parsers, None
)
# In case it was in deploy command format
# but was in file
if result is None:
return self.parse_key_value_arg(
data,
self.PARAMETER_OVERRIDE_CMD
)
return result
else:
# In case it was in deploy command format
# and was input via command line
return self.parse_key_value_arg(
arg_value,
self.PARAMETER_OVERRIDE_CMD
)

def parse_key_value_arg(self, arg_value, argname):
"""
Converts arguments that are passed as list of "Key=Value" strings
Expand Down
90 changes: 90 additions & 0 deletions tests/unit/customizations/cloudformation/test_deploy.py
Expand Up @@ -10,6 +10,8 @@
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
# ANY KIND, either express or implied. See the License for the specific
# language governing permissions and limitations under the License.
import json

import mock
import tempfile
import six
Expand All @@ -20,6 +22,7 @@
from awscli.customizations.cloudformation.deployer import Deployer
from awscli.customizations.cloudformation.yamlhelper import yaml_parse
from awscli.customizations.cloudformation import exceptions
from awscli.customizations.exceptions import ParamValidationError
from tests.unit.customizations.cloudformation import BaseYAMLTest


Expand Down Expand Up @@ -400,6 +403,93 @@ def test_parse_key_value_arg_success(self):
result = self.deploy_command.parse_key_value_arg([], argname)
self.assertEqual(result, {})

def test_parse_parameter_override_with_cf_data_format(self):
"""
Tests that we can parse parameter arguments from file in
CloudFormation parameters file format
:return:
"""
data = json.dumps([
{'ParameterKey': 'Key1',
'ParameterValue': 'Value1'},
{'ParameterKey': 'Key2',
'ParameterValue': '[1,2,3]'},
{'ParameterKey': 'Key3',
'ParameterValue': '{"a":"val", "b": 2}'}
])
output = {"Key1": "Value1",
"Key2": '[1,2,3]',
"Key3": '{"a":"val", "b": 2}'}
result = self.deploy_command.parse_parameter_overrides(data)
self.assertEqual(result, output)

def test_validate_parameter_override_with_cf_data_format(self):
"""
Tests that we through exception if have redundant keys in json
CloudFormation parameters file format
:return:
"""
data = json.dumps([
{'ParameterKey': 'Key1',
'ParameterValue': 'Value1',
'RedundantKey': 'foo'}
])
with self.assertRaises(ParamValidationError):
self.deploy_command.parse_parameter_overrides(data)

def test_parse_parameter_override_with_codepipeline_data_format(self):
"""
Tests that we can parse parameter arguments from file in
CodePipeline parameters file format
:return:
"""
data = json.dumps({
'Parameters': {
"Key1": "Value1",
"Key2": '[1,2,3]',
"Key3": '{"a":"val", "b": 2}'
}
})
output = {"Key1": "Value1",
"Key2": '[1,2,3]',
"Key3": '{"a":"val", "b": 2}'}
result = self.deploy_command.parse_parameter_overrides(data)
self.assertEqual(result, output)

def test_parse_parameter_override_with_deploy_data_format_from_file(self):
"""
Tests that we can parse parameter arguments from file in
deploy command parameters file format
:return:
"""
data = json.dumps([
'Key1=Value1',
'Key2=[1,2,3]',
'Key3={"a":"val", "b": 2}'
])
output = {"Key1": "Value1",
"Key2": '[1,2,3]',
"Key3": '{"a":"val", "b": 2}'}
result = self.deploy_command.parse_parameter_overrides(data)
self.assertEqual(result, output)

def test_parse_parameter_override_with_deploy_data_format(self):
"""
Tests that we can parse parameter arguments in
deploy command parameters command line format
:return:
"""
data = [
'Key1=Value1',
'Key2=[1,2,3]',
'Key3={"a":"val", "b": 2}'
]
output = {"Key1": "Value1",
"Key2": '[1,2,3]',
"Key3": '{"a":"val", "b": 2}'}
result = self.deploy_command.parse_parameter_overrides(data)
self.assertEqual(result, output)

def test_parse_key_value_arg_invalid_input(self):
# non-list input
argname = "parameter-overrides"
Expand Down

0 comments on commit d23c1e8

Please sign in to comment.