cfndsl 0.15.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +3 -0
- data/.rubocop.yml +6 -6
- data/.travis.yml +10 -5
- data/CHANGELOG.md +721 -400
- data/Gemfile +2 -0
- data/README.md +85 -23
- data/Rakefile +28 -6
- data/TODO.md +18 -0
- data/UPGRADING.md +22 -0
- data/cfndsl.gemspec +17 -16
- data/exe/cfndsl +5 -0
- data/lib/cfndsl.rb +3 -113
- data/lib/cfndsl/aws/cloud_formation_template.rb +10 -1
- data/lib/cfndsl/aws/patches/000_CloudFormationResourceSpecification.json +51726 -0
- data/lib/cfndsl/aws/patches/000_sam.spec.json +1242 -0
- data/lib/cfndsl/aws/patches/100_sam.spec_DeploymentPreference_patch.json +64 -0
- data/lib/cfndsl/aws/patches/200_Scrutinies_patch.json +86 -0
- data/lib/cfndsl/aws/patches/500_Cognito_IdentityPoolRoleAttachment_patches.json +25 -0
- data/lib/cfndsl/aws/patches/500_IoT1Click_patch_PlacementTemplate_DeviceTemplates.json +20 -0
- data/lib/cfndsl/aws/patches/500_NetworkAclEntry_patch.json +16 -0
- data/lib/cfndsl/aws/patches/500_SAM_Serverless_Function_S3Event_Events_patch.json +16 -0
- data/lib/cfndsl/aws/patches/500_SAM_Serverless_Function_S3Location_Version_patch.json +16 -0
- data/lib/cfndsl/aws/patches/500_SSM_AssociationName_patch.json +16 -0
- data/lib/cfndsl/aws/patches/500_VPCEndpoint_patch.json +17 -0
- data/lib/cfndsl/aws/patches/510_ElasticSearch_Domain_patches.json +15 -0
- data/lib/cfndsl/aws/patches/520_ServiceDiscovery_InstanceAttributes_patch.json +16 -0
- data/lib/cfndsl/aws/patches/600_RefKinds_patch.json +3654 -0
- data/lib/cfndsl/aws/patches/700_SAM_Serverless_Function_InlineCode_patch.json +20 -0
- data/lib/cfndsl/aws/patches/800_List_types_patch.json +115 -0
- data/lib/cfndsl/aws/resource_specification.json +39955 -9293
- data/lib/cfndsl/aws/types.rb +5 -3
- data/lib/cfndsl/cfnlego.rb +34 -0
- data/lib/{cfnlego → cfndsl/cfnlego}/cloudformation.erb +0 -0
- data/lib/{cfnlego → cfndsl/cfnlego}/cloudformation.rb +3 -1
- data/lib/{cfnlego → cfndsl/cfnlego}/resource.rb +5 -8
- data/lib/cfndsl/cloudformation.rb +114 -0
- data/lib/cfndsl/conditions.rb +13 -1
- data/lib/cfndsl/creation_policy.rb +3 -1
- data/lib/cfndsl/deep_merge.rb +4 -0
- data/lib/cfndsl/external_parameters.rb +12 -13
- data/lib/cfndsl/globals.rb +51 -10
- data/lib/cfndsl/json_serialisable_object.rb +4 -2
- data/lib/cfndsl/jsonable.rb +51 -68
- data/lib/cfndsl/mappings.rb +3 -1
- data/lib/cfndsl/module.rb +18 -5
- data/lib/cfndsl/names.rb +2 -0
- data/lib/cfndsl/orchestration_template.rb +193 -73
- data/lib/cfndsl/outputs.rb +7 -1
- data/lib/cfndsl/parameters.rb +3 -1
- data/lib/cfndsl/plurals.rb +23 -10
- data/lib/cfndsl/properties.rb +3 -1
- data/lib/cfndsl/rake_task.rb +217 -15
- data/lib/cfndsl/ref_check.rb +21 -11
- data/lib/cfndsl/resources.rb +8 -19
- data/lib/cfndsl/rules.rb +46 -0
- data/lib/cfndsl/runner.rb +143 -0
- data/lib/cfndsl/specification.rb +82 -84
- data/lib/cfndsl/types.rb +212 -95
- data/lib/cfndsl/update_policy.rb +3 -1
- data/lib/cfndsl/version.rb +3 -1
- data/lib/deep_merge/core.rb +10 -6
- data/lib/deep_merge/deep_merge.rb +3 -1
- data/sample/autoscale.rb +1 -1
- data/sample/autoscale2.rb +4 -3
- data/sample/circular.rb +2 -0
- data/sample/codedeploy.rb +3 -1
- data/sample/config_service.rb +5 -3
- data/sample/ecs.rb +3 -1
- data/sample/export.rb +5 -3
- data/sample/iam_policies.rb +2 -0
- data/sample/import.rb +4 -2
- data/sample/lambda.rb +3 -1
- data/sample/s3.rb +2 -0
- data/sample/t1.rb +3 -1
- data/sample/vpc_example.rb +3 -1
- data/sample/vpc_with_vpn_example.rb +3 -1
- data/spec/aws/ec2_security_group_spec.rb +2 -0
- data/spec/aws/ecs_task_definition_spec.rb +2 -0
- data/spec/aws/iam_managed_policy_spec.rb +2 -0
- data/spec/aws/kms_alias_spec.rb +2 -0
- data/spec/aws/list_type_patches_spec.rb +35 -0
- data/spec/aws/logs_log_group_spec.rb +2 -0
- data/spec/aws/nested_arrays_spec.rb +194 -0
- data/spec/aws/rds_db_instance_spec.rb +2 -0
- data/spec/aws/serverless_spec.rb +2 -2
- data/spec/cfndsl_spec.rb +102 -63
- data/spec/cli_spec.rb +52 -49
- data/spec/cloud_formation_template_spec.rb +235 -0
- data/spec/condition_spec.rb +24 -0
- data/spec/deep_merge_spec.rb +2 -0
- data/spec/direct_ruby_spec.rb +19 -0
- data/spec/external_parameters_spec.rb +25 -20
- data/spec/fixtures/condition-assertion.json +1 -0
- data/spec/fixtures/params.json +1 -0
- data/spec/fixtures/params.yaml +2 -0
- data/spec/fixtures/params_struct1.yaml +4 -0
- data/spec/fixtures/params_struct2.yaml +4 -0
- data/spec/fixtures/rule-assertion.json +1 -0
- data/spec/fixtures/test.rb +12 -4
- data/spec/generate_spec.rb +4 -0
- data/spec/jsonable_spec.rb +2 -0
- data/spec/metadata_spec.rb +2 -0
- data/spec/names_spec.rb +2 -0
- data/spec/output_spec.rb +2 -0
- data/spec/plurals_spec.rb +2 -0
- data/spec/resource_name_spec.rb +21 -0
- data/spec/resources_spec.rb +2 -7
- data/spec/rule_spec.rb +17 -0
- data/spec/spec_helper.rb +4 -7
- data/spec/support/shared_examples/orchestration_template.rb +17 -2
- data/spec/transform_spec.rb +2 -0
- data/spec/types_definition_spec.rb +6 -7
- metadata +79 -25
- data/bin/cfndsl +0 -143
- data/lib/cfndsl/errors.rb +0 -29
- data/lib/cfndsl/os/heat_template.rb +0 -16
- data/lib/cfndsl/os/types.rb +0 -12
- data/lib/cfndsl/os/types.yaml +0 -2423
- data/lib/cfndsl/patches.rb +0 -98
- data/lib/cfnlego.rb +0 -42
- data/spec/fixtures/heattest.rb +0 -22
- data/spec/heat_template_spec.rb +0 -5
data/lib/cfndsl/update_policy.rb
CHANGED
data/lib/cfndsl/version.rb
CHANGED
data/lib/deep_merge/core.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# rubocop:disable Metrics/AbcSize, Metrics/BlockNesting, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
2
4
|
# rubocop:disable Metrics/ModuleLength, Metrics/PerceivedComplexity, Style/IfInsideElse, Style/Semicolon
|
3
5
|
#
|
@@ -5,7 +7,7 @@
|
|
5
7
|
module DeepMerge
|
6
8
|
class InvalidParameter < StandardError; end
|
7
9
|
|
8
|
-
DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
|
10
|
+
DEFAULT_FIELD_KNOCKOUT_PREFIX = '--'
|
9
11
|
|
10
12
|
# Deep Merge core documentation.
|
11
13
|
# deep_merge! method permits merging of arbitrary child elements. The two top level
|
@@ -85,6 +87,7 @@ module DeepMerge
|
|
85
87
|
knockout_prefix = options[:knockout_prefix] || nil
|
86
88
|
raise InvalidParameter, 'knockout_prefix cannot be an empty string in deep_merge!' if knockout_prefix == ''
|
87
89
|
raise InvalidParameter, 'overwrite_unmergeable must be true if knockout_prefix is specified in deep_merge!' if knockout_prefix && !overwrite_unmergeable
|
90
|
+
|
88
91
|
# if present: we will split and join arrays on this char before merging
|
89
92
|
array_split_char = options[:unpack_arrays] || false
|
90
93
|
# request that we avoid merging arrays
|
@@ -103,6 +106,7 @@ module DeepMerge
|
|
103
106
|
di = options[:debug_indent] || ''
|
104
107
|
# do nothing if source is nil
|
105
108
|
return dest if !merge_nil_values && source.nil?
|
109
|
+
|
106
110
|
# if dest doesn't exist, then simply copy source to it
|
107
111
|
if !dest && overwrite_unmergeable
|
108
112
|
dest = source; return dest
|
@@ -146,9 +150,7 @@ module DeepMerge
|
|
146
150
|
if array_split_char
|
147
151
|
puts "#{di} split/join on source: #{source.inspect}" if merge_debug
|
148
152
|
source = source.join(array_split_char).split(array_split_char)
|
149
|
-
if dest.is_a?(Array)
|
150
|
-
dest = dest.join(array_split_char).split(array_split_char)
|
151
|
-
end
|
153
|
+
dest = dest.join(array_split_char).split(array_split_char) if dest.is_a?(Array)
|
152
154
|
end
|
153
155
|
# if there's a naked knockout_prefix in source, that means we are to truncate dest
|
154
156
|
if knockout_prefix && source.index(knockout_prefix)
|
@@ -204,7 +206,7 @@ module DeepMerge
|
|
204
206
|
end
|
205
207
|
puts "#{di}Returning #{dest.inspect}" if merge_debug
|
206
208
|
dest
|
207
|
-
end
|
209
|
+
end
|
208
210
|
|
209
211
|
# allows deep_merge! to uniformly handle overwriting of unmergeable entities
|
210
212
|
def self.overwrite_unmergeables(source, dest, options)
|
@@ -241,4 +243,6 @@ module DeepMerge
|
|
241
243
|
end
|
242
244
|
obj
|
243
245
|
end
|
244
|
-
end
|
246
|
+
end
|
247
|
+
# rubocop:enable Metrics/AbcSize, Metrics/BlockNesting, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
248
|
+
# rubocop:enable Metrics/ModuleLength, Metrics/PerceivedComplexity, Style/IfInsideElse, Style/Semicolon
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# Totally borrowed from https://github.com/danielsdeleo/deep_merge
|
2
4
|
require 'deep_merge/core'
|
3
5
|
|
@@ -9,7 +11,7 @@ module DeepMerge
|
|
9
11
|
default_opts = { preserve_unmergeables: false }
|
10
12
|
DeepMerge.deep_merge!(source, self, default_opts.merge(options))
|
11
13
|
end
|
12
|
-
end
|
14
|
+
end
|
13
15
|
end
|
14
16
|
|
15
17
|
# Extends hash with deep merge
|
data/sample/autoscale.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
|
2
3
|
# We start things off by calling the CloudFormation function.
|
3
4
|
CloudFormation do
|
@@ -15,7 +16,6 @@ availability zones in a region. The instances are load balanced with a
|
|
15
16
|
simple health check. The web site is available on port 80, however,
|
16
17
|
the instances can be configured to listen on any port (8888 by
|
17
18
|
default).
|
18
|
-
|
19
19
|
**WARNING** This template creates one or more Amazon EC2
|
20
20
|
instances. You will be billed for the AWS resources used if you create
|
21
21
|
a stack from this template.
|
data/sample/autoscale2.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# We start things off by calling the CloudFormation function.
|
2
4
|
CloudFormation do
|
3
5
|
# Declare the template format version
|
@@ -14,7 +16,6 @@ availability zones in a region. The instances are load balanced with a
|
|
14
16
|
simple health check. The web site is available on port 80, however,
|
15
17
|
the instances can be configured to listen on any port (8888 by
|
16
18
|
default).
|
17
|
-
|
18
19
|
**WARNING** This template creates one or more Amazon EC2
|
19
20
|
instances. You will be billed for the AWS resources used if you create
|
20
21
|
a stack from this template.
|
@@ -89,8 +90,8 @@ a stack from this template.
|
|
89
90
|
AutoScalingGroup('WebServerGroup') do
|
90
91
|
UpdatePolicy('AutoScalingRollingUpdate',
|
91
92
|
'MinInstancesInService' => '1',
|
92
|
-
'MaxBatchSize'
|
93
|
-
'PauseTime'
|
93
|
+
'MaxBatchSize' => '1',
|
94
|
+
'PauseTime' => 'PT15M')
|
94
95
|
AvailabilityZones FnGetAZs('')
|
95
96
|
LaunchConfigurationName Ref('LaunchConfig')
|
96
97
|
MinSize 1
|
data/sample/circular.rb
CHANGED
data/sample/codedeploy.rb
CHANGED
data/sample/config_service.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
CloudFormation do
|
2
4
|
AWSTemplateFormatVersion '2010-09-09'
|
3
5
|
|
4
6
|
Description 'Creates SNS, SQS, S3 bucket and enables AWS Config.'
|
5
7
|
|
6
|
-
|
8
|
+
SQS_Queue('ConfigServiceQueue') do
|
7
9
|
QueueName 'ConfigServiceQueue'
|
8
10
|
end
|
9
11
|
|
10
12
|
Bucket('ConfigServiceBucket') do
|
11
13
|
end
|
12
14
|
|
13
|
-
|
15
|
+
IAM_Policy('ConfigServiceS3BucketAccessPolicy') do
|
14
16
|
PolicyName 'ConfigServiceS3BucketAccessPolicy'
|
15
17
|
PolicyDocument(
|
16
18
|
'Version' => '2012-10-17',
|
@@ -66,7 +68,7 @@ CloudFormation do
|
|
66
68
|
}]
|
67
69
|
end
|
68
70
|
|
69
|
-
|
71
|
+
IAM_Policy('ConfigServiceSNSTopicAccessPolicy') do
|
70
72
|
PolicyName 'ConfigServiceSNSTopicAccessPolicy'
|
71
73
|
PolicyDocument(
|
72
74
|
'Version' => '2012-10-17',
|
data/sample/ecs.rb
CHANGED
data/sample/export.rb
CHANGED
@@ -1,12 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
CloudFormation do
|
2
4
|
EC2_SecurityGroup(:webSecurityGroup) do
|
3
5
|
GroupDescription 'Allow incoming HTTP traffic from anywhere'
|
4
6
|
SecurityGroupIngress [
|
5
7
|
{
|
6
|
-
'CidrIp'
|
8
|
+
'CidrIp' => '0.0.0.0/0',
|
7
9
|
'IpProtocol' => 'tcp',
|
8
|
-
'FromPort'
|
9
|
-
'ToPort'
|
10
|
+
'FromPort' => 80,
|
11
|
+
'ToPort' => 80
|
10
12
|
}
|
11
13
|
]
|
12
14
|
end
|
data/sample/iam_policies.rb
CHANGED
data/sample/import.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
CloudFormation do
|
2
4
|
EC2_SecurityGroup(:databaseSecurityGroup) do
|
3
5
|
GroupDescription 'Allow access from only web instances'
|
@@ -5,8 +7,8 @@ CloudFormation do
|
|
5
7
|
{
|
6
8
|
'SourceSecurityGroupId' => FnImportValue(:webSecurityGroupId),
|
7
9
|
'IpProtocol' => 'tcp',
|
8
|
-
'FromPort'
|
9
|
-
'ToPort'
|
10
|
+
'FromPort' => 7777,
|
11
|
+
'ToPort' => 7777
|
10
12
|
}
|
11
13
|
]
|
12
14
|
end
|
data/sample/lambda.rb
CHANGED
data/sample/s3.rb
CHANGED
data/sample/t1.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
CloudFormation do
|
2
4
|
description = external_parameters.fetch(:description, 'default description')
|
3
5
|
machines = external_parameters.fetch(:machines, 1).to_i
|
@@ -8,7 +10,7 @@ CloudFormation do
|
|
8
10
|
name = "machine#{i}"
|
9
11
|
EC2_Instance(name) do
|
10
12
|
ImageId 'ami-12345678'
|
11
|
-
|
13
|
+
InstanceType 't1.micro'
|
12
14
|
end
|
13
15
|
end
|
14
16
|
end
|
data/sample/vpc_example.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cfndsl'
|
2
4
|
|
3
5
|
CloudFormation do
|
@@ -40,7 +42,7 @@ CloudFormation do
|
|
40
42
|
RouteTableId Ref(route_table)
|
41
43
|
end
|
42
44
|
|
43
|
-
|
45
|
+
EC2_Route(subnet + 'GatewayRoute') do
|
44
46
|
DependsOn :GatewayToInternet
|
45
47
|
RouteTableId Ref(route_table)
|
46
48
|
DestinationCidrBlock '0.0.0.0/0'
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'cfndsl'
|
2
4
|
|
3
5
|
CloudFormation do
|
@@ -58,7 +60,7 @@ CloudFormation do
|
|
58
60
|
RouteTableId Ref(route_table)
|
59
61
|
end
|
60
62
|
|
61
|
-
|
63
|
+
EC2_Route(subnet + 'GatewayRoute') do
|
62
64
|
DependsOn :GatewayToInternet
|
63
65
|
RouteTableId Ref(route_table)
|
64
66
|
DestinationCidrBlock '0.0.0.0/0'
|
data/spec/aws/kms_alias_spec.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe CfnDsl::CloudFormationTemplate do
|
6
|
+
subject(:template) { described_class.new }
|
7
|
+
|
8
|
+
describe 'Bogus Properties that are type List' do
|
9
|
+
it 'fixes Resource property type to a List of its item type' do
|
10
|
+
template.LakeFormation_DataLakeSettings('lake') do
|
11
|
+
Admin { DataLakePrincipalIdentifier 'principal' }
|
12
|
+
end
|
13
|
+
expect(template.to_json).to include('"Type":"AWS::LakeFormation::DataLakeSettings","Properties":{"Admins":[{"DataLakePrincipalIdentifier":"principal"')
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'fixes Subtype property Tags to a list of Tags' do
|
17
|
+
template.AppSync_GraphQLApi('api') do
|
18
|
+
Tag do
|
19
|
+
Key 'tagkey'
|
20
|
+
Value 'tagvalue'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
expect(template.to_json).to include('"Properties":{"Tags":[{"Key":"tagkey","Value":"tagvalue"}]}}}')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'fixes Subtype property type to a List of its item type' do
|
27
|
+
template.Glue_SecurityConfiguration('glue') do
|
28
|
+
EncryptionConfiguration do
|
29
|
+
S3Encryption { S3EncryptionMode 'mode' }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
expect(template.to_json).to include('"EncryptionConfiguration":{"S3Encryptions":[{"S3EncryptionMode":"mode"}]}}}}}')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe CfnDsl::CloudFormationTemplate do
|
6
|
+
subject(:template) { described_class.new }
|
7
|
+
|
8
|
+
describe 'Nested_Arrays' do
|
9
|
+
it 'ensure nested arrays are not duplicated' do
|
10
|
+
template.DirectoryService_SimpleAD(:Test) do
|
11
|
+
VpcSettings do
|
12
|
+
SubnetId %w[subnet-a subnet-b]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
expect(template.to_json).to include('"SubnetIds":["subnet-a","subnet-b"]}')
|
17
|
+
expect(template.to_json).not_to include('"SubnetIds":[["subnet-a","subnet-b"],["subnet-a","subnet-b"]]')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'appends entries with multiple invocations' do
|
21
|
+
template.DirectoryService_SimpleAD(:Test) do
|
22
|
+
VpcSettings do
|
23
|
+
SubnetId 'subnet-a'
|
24
|
+
SubnetId 'subnet-b'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
expect(template.to_json).to include('"SubnetIds":["subnet-a","subnet-b"]}')
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'appends entries with multiple array invocations' do
|
32
|
+
template.DirectoryService_SimpleAD(:Test) do
|
33
|
+
VpcSettings do
|
34
|
+
SubnetId %w[subnet-a subnet-b]
|
35
|
+
SubnetId %w[subnet-c subnet-d]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
expect(template.to_json).to include('"SubnetIds":["subnet-a","subnet-b","subnet-c","subnet-d"]')
|
40
|
+
end
|
41
|
+
|
42
|
+
# Previous behaviour produces valid result, but appends rather than replaces (inconsistent with top level item)
|
43
|
+
it 'appends entries when plural form is used' do
|
44
|
+
template.DirectoryService_SimpleAD(:Test) do
|
45
|
+
VpcSettings do
|
46
|
+
SubnetId 'subnet-x'
|
47
|
+
SubnetIds %w[subnet-a subnet-b]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
expect(template.to_json).to include('"SubnetIds":["subnet-a","subnet-b"]}')
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'plural form accepts a Ref' do
|
55
|
+
template.EC2_LaunchTemplate(:test) do
|
56
|
+
LaunchTemplateData do
|
57
|
+
SecurityGroupIds Ref('AListParam')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
expect(template.to_json).to include('"LaunchTemplateData":{"SecurityGroupIds":{"Ref":"AListParam"}')
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'Nested Arrays With Subtype items' do
|
65
|
+
it 'can add a subtype to a list' do
|
66
|
+
template.EC2_SpotFleet('SpotFleet') do
|
67
|
+
SpotFleetRequestConfigData do
|
68
|
+
LaunchSpecification do
|
69
|
+
ImageId 'ami-1234'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
expect(template.to_json).to include('"LaunchSpecifications":[{"ImageId":"ami-1234"}]')
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'can conditionally add a subtype to a list' do
|
77
|
+
template.EC2_SpotFleet('SpotFleet') do
|
78
|
+
SpotFleetRequestConfigData do
|
79
|
+
# We want all the DSL goodness
|
80
|
+
LaunchSpecification fn_if: 'ACondition' do
|
81
|
+
ImageId 'ami-1234'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
json = template.to_json
|
86
|
+
expect(json).to include('"LaunchSpecifications":[{"Fn::If":["ACondition",{"ImageId":"ami-1234"},{"Ref":"AWS::NoValue"}]}]')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'Top level Lists' do
|
91
|
+
it 'appends item if singular form != plural form is passed a single item' do
|
92
|
+
template.AutoScaling_AutoScalingGroup('ASG') do
|
93
|
+
AvailabilityZone 'region-2a'
|
94
|
+
AvailabilityZone 'region-2b'
|
95
|
+
end
|
96
|
+
expect(template.to_json).to include('"AvailabilityZones":["region-2a","region-2b"]')
|
97
|
+
end
|
98
|
+
|
99
|
+
# Change from prior behaviour which produced an invalid result
|
100
|
+
it 'appends multiple items if singular form != plural form is passed an array' do
|
101
|
+
template.AutoScaling_AutoScalingGroup('ASG') do
|
102
|
+
AvailabilityZone %w[region-2a region-2b]
|
103
|
+
AvailabilityZone ['region-2c']
|
104
|
+
end
|
105
|
+
expect(template.to_json).to include('"AvailabilityZones":["region-2a","region-2b","region-2c"]')
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'replaces items if plural form is passed an array' do
|
109
|
+
template.AutoScaling_AutoScalingGroup('ASG') do
|
110
|
+
AvailabilityZones ['region-2z']
|
111
|
+
AvailabilityZones ['region-2a']
|
112
|
+
end
|
113
|
+
expect(template.to_json).to include('"AvailabilityZones":["region-2a"]')
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'accepts a Ref in plural form' do
|
117
|
+
template.AutoScaling_AutoScalingGroup('ASG') do
|
118
|
+
AvailabilityZones Ref('AListParam')
|
119
|
+
end
|
120
|
+
expect(template.to_json).to include('"AvailabilityZones":{"Ref":"AListParam"}')
|
121
|
+
end
|
122
|
+
|
123
|
+
# This produces an invalid result (item not encapsulated as a List), so could be changed
|
124
|
+
# later
|
125
|
+
it 'replaces items if plural form is passed a single item' do
|
126
|
+
template.AutoScaling_AutoScalingGroup('ASG') do
|
127
|
+
AvailabilityZones 'region-xx'
|
128
|
+
AvailabilityZones 'region-2a'
|
129
|
+
end
|
130
|
+
expect(template.to_json).to include('"AvailabilityZones":"region-2a"')
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'replaces items if list attribute is singlar, and plural form is passed an array' do
|
134
|
+
template.AutoScaling_AutoScalingGroup('ASG') do
|
135
|
+
VPCZoneIdentifiers ['subnet-9999']
|
136
|
+
VPCZoneIdentifiers ['subnet-1234']
|
137
|
+
end
|
138
|
+
expect(template.to_json).to include('"VPCZoneIdentifier":["subnet-1234"]')
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'replaces items if list attribute is singlar, and plural form is passed an array' do
|
142
|
+
template.AutoScaling_AutoScalingGroup('ASG') do
|
143
|
+
VPCZoneIdentifier 'subnet-9999'
|
144
|
+
VPCZoneIdentifiers ['subnet-1234']
|
145
|
+
end
|
146
|
+
expect(template.to_json).to include('"VPCZoneIdentifier":["subnet-1234"]')
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'appends items if list attribute is singlar and passed arrays' do
|
150
|
+
template.AutoScaling_AutoScalingGroup('ASG') do
|
151
|
+
VPCZoneIdentifier ['subnet-9999']
|
152
|
+
VPCZoneIdentifier ['subnet-1234']
|
153
|
+
end
|
154
|
+
expect(template.to_json).to include('"VPCZoneIdentifier":["subnet-9999","subnet-1234"]')
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'appends items if plural form == singular form and passed a single item' do
|
158
|
+
template.AutoScaling_AutoScalingGroup('ASG') do
|
159
|
+
VPCZoneIdentifier 'subnet-9999'
|
160
|
+
VPCZoneIdentifier 'subnet-1234'
|
161
|
+
end
|
162
|
+
expect(template.to_json).to include('"VPCZoneIdentifier":["subnet-9999","subnet-1234"]')
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'does not create plural method if both singlular and plural forms are legitimate properties' do
|
166
|
+
template.CodePipeline_Pipeline('pipeline') do
|
167
|
+
ArtifactStore do
|
168
|
+
Location 'abucketname'
|
169
|
+
Type 'S3'
|
170
|
+
end
|
171
|
+
ArtifactStores do
|
172
|
+
ArtifactStore do
|
173
|
+
Location 'a different bucket'
|
174
|
+
Type 'S3'
|
175
|
+
end
|
176
|
+
Region 'ax-eastwest-5'
|
177
|
+
end
|
178
|
+
end
|
179
|
+
json = template.to_json
|
180
|
+
expect(json).to include('"ArtifactStore":{"Location":"abucketname"')
|
181
|
+
expect(json).to include('"ArtifactStores":[{"ArtifactStore":{')
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'can conditionally add a subtype to a list property' do
|
185
|
+
template.SSM_MaintenanceWindowTask('Task') do
|
186
|
+
# We want all the DSL goodness
|
187
|
+
Target fn_if: 'ACondition' do
|
188
|
+
Key 'AKey'
|
189
|
+
end
|
190
|
+
end
|
191
|
+
expect(template.to_json).to include('"Targets":[{"Fn::If":["ACondition",{"Key":"AKey"},{"Ref":"AWS::NoValue"}]}]')
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|