chef-provisioning-aws 1.4.1 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +8 -0
- data/README.md +26 -39
- data/Rakefile +13 -5
- data/lib/chef/provider/aws_iam_instance_profile.rb +60 -0
- data/lib/chef/provider/aws_iam_role.rb +98 -0
- data/lib/chef/provider/aws_image.rb +1 -1
- data/lib/chef/provider/aws_internet_gateway.rb +75 -0
- data/lib/chef/provider/aws_route_table.rb +3 -2
- data/lib/chef/provider/aws_s3_bucket.rb +4 -1
- data/lib/chef/provider/aws_security_group.rb +1 -1
- data/lib/chef/provider/aws_vpc.rb +50 -45
- data/lib/chef/provisioning/aws_driver.rb +22 -1
- data/lib/chef/provisioning/aws_driver/aws_provider.rb +13 -5
- data/lib/chef/provisioning/aws_driver/aws_resource.rb +173 -165
- data/lib/chef/provisioning/aws_driver/credentials.rb +12 -0
- data/lib/chef/provisioning/aws_driver/driver.rb +82 -37
- data/lib/chef/provisioning/aws_driver/super_lwrp.rb +56 -43
- data/lib/chef/provisioning/aws_driver/version.rb +1 -1
- data/lib/chef/resource/aws_dhcp_options.rb +1 -1
- data/lib/chef/resource/aws_ebs_volume.rb +1 -1
- data/lib/chef/resource/aws_eip_address.rb +1 -1
- data/lib/chef/resource/aws_iam_instance_profile.rb +33 -0
- data/lib/chef/resource/aws_iam_role.rb +55 -0
- data/lib/chef/resource/aws_image.rb +1 -1
- data/lib/chef/resource/aws_instance.rb +1 -1
- data/lib/chef/resource/aws_internet_gateway.rb +36 -6
- data/lib/chef/resource/aws_load_balancer.rb +1 -1
- data/lib/chef/resource/aws_network_acl.rb +1 -1
- data/lib/chef/resource/aws_network_interface.rb +1 -1
- data/lib/chef/resource/aws_route53_hosted_zone.rb +261 -0
- data/lib/chef/resource/aws_route53_record_set.rb +162 -0
- data/lib/chef/resource/aws_route_table.rb +1 -1
- data/lib/chef/resource/aws_security_group.rb +1 -1
- data/lib/chef/resource/aws_sns_topic.rb +1 -1
- data/lib/chef/resource/aws_subnet.rb +1 -1
- data/lib/chef/resource/aws_vpc.rb +1 -1
- data/lib/chef/resource/aws_vpc_peering_connection.rb +1 -1
- data/spec/aws_support.rb +11 -13
- data/spec/aws_support/matchers/create_an_aws_object.rb +7 -1
- data/spec/aws_support/matchers/have_aws_object_tags.rb +1 -1
- data/spec/aws_support/matchers/match_an_aws_object.rb +7 -1
- data/spec/aws_support/matchers/update_an_aws_object.rb +8 -2
- data/spec/integration/aws_eip_address_spec.rb +74 -0
- data/spec/integration/aws_iam_instance_profile_spec.rb +159 -0
- data/spec/integration/aws_iam_role_spec.rb +177 -0
- data/spec/integration/aws_internet_gateway_spec.rb +161 -0
- data/spec/integration/aws_network_interface_spec.rb +3 -4
- data/spec/integration/aws_route53_hosted_zone_spec.rb +522 -0
- data/spec/integration/aws_route_table_spec.rb +52 -4
- data/spec/integration/aws_s3_bucket_spec.rb +1 -1
- data/spec/integration/load_balancer_spec.rb +303 -8
- data/spec/integration/machine_batch_spec.rb +1 -0
- data/spec/integration/machine_image_spec.rb +32 -17
- data/spec/integration/machine_spec.rb +11 -29
- data/spec/unit/chef/provisioning/aws_driver/driver_spec.rb +0 -1
- data/spec/unit/chef/provisioning/aws_driver/route53_spec.rb +105 -0
- metadata +48 -6
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'securerandom'
|
3
|
+
|
4
|
+
def ec2_principal
|
5
|
+
<<-EOF
|
6
|
+
{
|
7
|
+
"Version": "2012-10-17",
|
8
|
+
"Statement": [
|
9
|
+
{
|
10
|
+
"Action": "sts:AssumeRole",
|
11
|
+
"Principal": {
|
12
|
+
"Service": "ec2.amazonaws.com"
|
13
|
+
},
|
14
|
+
"Effect": "Allow",
|
15
|
+
"Sid": ""
|
16
|
+
}
|
17
|
+
]
|
18
|
+
}
|
19
|
+
EOF
|
20
|
+
end
|
21
|
+
|
22
|
+
def rds_principal
|
23
|
+
<<-EOF
|
24
|
+
{
|
25
|
+
"Version": "2012-10-17",
|
26
|
+
"Statement": [
|
27
|
+
{
|
28
|
+
"Action": "sts:AssumeRole",
|
29
|
+
"Principal": {
|
30
|
+
"Service": "rds.amazonaws.com"
|
31
|
+
},
|
32
|
+
"Effect": "Allow",
|
33
|
+
"Sid": ""
|
34
|
+
}
|
35
|
+
]
|
36
|
+
}
|
37
|
+
EOF
|
38
|
+
end
|
39
|
+
|
40
|
+
def rds_role_policy
|
41
|
+
<<-EOF
|
42
|
+
{
|
43
|
+
"Version": "2012-10-17",
|
44
|
+
"Statement": [
|
45
|
+
{
|
46
|
+
"Sid": "Stmt1441787971000",
|
47
|
+
"Effect": "Allow",
|
48
|
+
"Action": [
|
49
|
+
"rds:*"
|
50
|
+
],
|
51
|
+
"Resource": [
|
52
|
+
"*"
|
53
|
+
]
|
54
|
+
}
|
55
|
+
]
|
56
|
+
}
|
57
|
+
EOF
|
58
|
+
end
|
59
|
+
|
60
|
+
def iam_role_policy
|
61
|
+
<<-EOF
|
62
|
+
{
|
63
|
+
"Version": "2012-10-17",
|
64
|
+
"Statement": [
|
65
|
+
{
|
66
|
+
"Effect": "Allow",
|
67
|
+
"Action": "iam:*",
|
68
|
+
"Resource": "*"
|
69
|
+
}
|
70
|
+
]
|
71
|
+
}
|
72
|
+
EOF
|
73
|
+
end
|
74
|
+
|
75
|
+
describe Chef::Resource::AwsIamRole do
|
76
|
+
extend AWSSupport
|
77
|
+
|
78
|
+
when_the_chef_12_server "exists", organization: "foo", server_scope: :context do
|
79
|
+
with_aws "when connected to AWS" do
|
80
|
+
|
81
|
+
let(:role_name) {
|
82
|
+
name_postfix = SecureRandom.hex(8)
|
83
|
+
"cp_test_iam_role_#{name_postfix}"
|
84
|
+
}
|
85
|
+
|
86
|
+
it "creates an aws_iam_role with minimum attributes" do
|
87
|
+
expect_recipe {
|
88
|
+
aws_iam_role role_name do
|
89
|
+
assume_role_policy_document ec2_principal
|
90
|
+
end
|
91
|
+
}.to create_an_aws_iam_role(role_name) { |aws_object|
|
92
|
+
expect(Chef::JSONCompat.parse(URI.decode(aws_object.assume_role_policy_document))).to eq(Chef::JSONCompat.parse(ec2_principal))
|
93
|
+
}.and be_idempotent
|
94
|
+
end
|
95
|
+
|
96
|
+
it "creates an aws_iam_role with maximum attributes" do
|
97
|
+
expect_recipe {
|
98
|
+
aws_iam_role role_name do
|
99
|
+
path "/"
|
100
|
+
assume_role_policy_document ec2_principal
|
101
|
+
inline_policies a: iam_role_policy
|
102
|
+
end
|
103
|
+
}.to create_an_aws_iam_role(role_name,
|
104
|
+
path: "/",
|
105
|
+
policies: [{name: "a"}]
|
106
|
+
) { |aws_object|
|
107
|
+
expect(Chef::JSONCompat.parse(URI.decode(aws_object.assume_role_policy_document))).to eq(Chef::JSONCompat.parse(ec2_principal))
|
108
|
+
expect(Chef::JSONCompat.parse(URI.decode(aws_object.policies.first.policy_document))).to eq(Chef::JSONCompat.parse(iam_role_policy))
|
109
|
+
}.and be_idempotent
|
110
|
+
end
|
111
|
+
|
112
|
+
context "with an existing aws_iam_role" do
|
113
|
+
# Doing this in a before(:each) block for 2 reasons:
|
114
|
+
# 1) the context-level methods only destroy the item after the context is finished,
|
115
|
+
# and I want the tests to assert on a new item each example
|
116
|
+
# 2) the let(:role_name) cannot be used at the context level, only at
|
117
|
+
# the example/before/after level
|
118
|
+
before(:each) do
|
119
|
+
converge {
|
120
|
+
aws_iam_role role_name do
|
121
|
+
path "/"
|
122
|
+
assume_role_policy_document ec2_principal
|
123
|
+
inline_policies a: iam_role_policy
|
124
|
+
end
|
125
|
+
}
|
126
|
+
end
|
127
|
+
|
128
|
+
after(:each) do
|
129
|
+
converge {
|
130
|
+
aws_iam_role role_name do
|
131
|
+
action :destroy
|
132
|
+
end
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
it "updates all available fields" do
|
138
|
+
expect_recipe {
|
139
|
+
aws_iam_role role_name do
|
140
|
+
assume_role_policy_document rds_principal
|
141
|
+
inline_policies b: rds_role_policy
|
142
|
+
end
|
143
|
+
}.to create_an_aws_iam_role(role_name,
|
144
|
+
path: "/",
|
145
|
+
policies: [{name: "b"}]
|
146
|
+
) { |aws_object|
|
147
|
+
expect(Chef::JSONCompat.parse(URI.decode(aws_object.assume_role_policy_document))).to eq(Chef::JSONCompat.parse(rds_principal))
|
148
|
+
expect(Chef::JSONCompat.parse(URI.decode(aws_object.policies.first.policy_document))).to eq(Chef::JSONCompat.parse(rds_role_policy))
|
149
|
+
}.and be_idempotent
|
150
|
+
end
|
151
|
+
|
152
|
+
it "clears inline_policies with an empty hash" do
|
153
|
+
expect_recipe {
|
154
|
+
aws_iam_role role_name do
|
155
|
+
inline_policies Hash.new
|
156
|
+
end
|
157
|
+
}.to create_an_aws_iam_role(role_name,
|
158
|
+
path: "/",
|
159
|
+
policies: []
|
160
|
+
).and be_idempotent
|
161
|
+
end
|
162
|
+
|
163
|
+
it "deletes the aws_iam_role" do
|
164
|
+
r = recipe {
|
165
|
+
aws_iam_role role_name do
|
166
|
+
action :destroy
|
167
|
+
end
|
168
|
+
}
|
169
|
+
expect(r).to destroy_an_aws_iam_role(role_name)
|
170
|
+
expect { driver.iam_client.list_role_policies(role_name: role_name).policy_names }.to raise_error(::Aws::IAM::Errors::NoSuchEntity)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chef::Resource::AwsInternetGateway do
|
4
|
+
extend AWSSupport
|
5
|
+
|
6
|
+
when_the_chef_12_server 'exists', organization: 'foo', server_scope: :context do
|
7
|
+
with_aws 'with a VPC' do
|
8
|
+
|
9
|
+
aws_vpc 'test_vpc_igw_a' do
|
10
|
+
cidr_block '10.0.0.0/24'
|
11
|
+
end
|
12
|
+
|
13
|
+
aws_vpc 'test_vpc_igw_b' do
|
14
|
+
cidr_block '10.0.1.0/24'
|
15
|
+
end
|
16
|
+
|
17
|
+
it "creates an aws_internet_gateway with no parameters" do
|
18
|
+
expect_recipe {
|
19
|
+
aws_internet_gateway 'test_internet_gateway'
|
20
|
+
}.to create_an_aws_internet_gateway('test_internet_gateway').and be_idempotent
|
21
|
+
end
|
22
|
+
|
23
|
+
it "creates an aws_internet_gateway and attaches it to the specified VPC" do
|
24
|
+
expect_recipe {
|
25
|
+
aws_internet_gateway 'test_internet_gateway' do
|
26
|
+
vpc test_vpc_igw_a.aws_object.id
|
27
|
+
end
|
28
|
+
}.to create_an_aws_internet_gateway('test_internet_gateway',
|
29
|
+
vpc: test_vpc_igw_a.aws_object
|
30
|
+
).and be_idempotent
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with the IGW attached to an existing VPC' do
|
34
|
+
aws_internet_gateway 'test_internet_gateway' do
|
35
|
+
vpc test_vpc_igw_a.aws_object.id
|
36
|
+
end
|
37
|
+
|
38
|
+
it "updates it to the new VPC" do
|
39
|
+
expect_recipe {
|
40
|
+
aws_internet_gateway 'test_internet_gateway' do
|
41
|
+
vpc test_vpc_igw_b
|
42
|
+
end
|
43
|
+
}.to update_an_aws_internet_gateway('test_internet_gateway',
|
44
|
+
vpc: test_vpc_igw_b.aws_object
|
45
|
+
).and be_idempotent
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with the IGW attached to an existing VPC' do
|
50
|
+
aws_internet_gateway 'test_internet_gateway' do
|
51
|
+
vpc test_vpc_igw_a.aws_object.id
|
52
|
+
end
|
53
|
+
|
54
|
+
it "detaches it from the VPC" do
|
55
|
+
expect_recipe {
|
56
|
+
aws_internet_gateway 'test_internet_gateway' do
|
57
|
+
action :detach
|
58
|
+
end
|
59
|
+
}.to update_an_aws_internet_gateway('test_internet_gateway',
|
60
|
+
vpc: nil
|
61
|
+
).and be_idempotent
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with the IGW attached to an existing VPC' do
|
66
|
+
aws_internet_gateway 'test_internet_gateway' do
|
67
|
+
vpc test_vpc_igw_a.aws_object.id
|
68
|
+
end
|
69
|
+
|
70
|
+
it "detaches the VPC and destroys the IGW" do
|
71
|
+
r = recipe {
|
72
|
+
aws_internet_gateway 'test_internet_gateway' do
|
73
|
+
action :destroy
|
74
|
+
end
|
75
|
+
}
|
76
|
+
expect(r).to destroy_an_aws_internet_gateway('test_internet_gateway').and be_idempotent
|
77
|
+
|
78
|
+
expect(test_vpc_igw_a.aws_object.internet_gateway).to eq(nil)
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'with a VPC with its own managed internet gateway' do
|
82
|
+
aws_vpc 'test_vpc_preexisting_igw' do
|
83
|
+
cidr_block '10.0.1.0/24'
|
84
|
+
internet_gateway true
|
85
|
+
end
|
86
|
+
|
87
|
+
it "deletes the old managed IGW and attaches the new one" do
|
88
|
+
existing_igw = test_vpc_preexisting_igw.aws_object.internet_gateway
|
89
|
+
|
90
|
+
expect_recipe {
|
91
|
+
aws_internet_gateway 'test_internet_gateway' do
|
92
|
+
vpc test_vpc_preexisting_igw.aws_object
|
93
|
+
end
|
94
|
+
}.to create_an_aws_internet_gateway('test_internet_gateway',
|
95
|
+
vpc: test_vpc_preexisting_igw.aws_object
|
96
|
+
).and be_idempotent
|
97
|
+
|
98
|
+
expect(existing_igw.exists?).to eq(false)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'with a VPC and an attached aws_internet_gateway resource' do
|
103
|
+
aws_internet_gateway 'test_internet_gateway'
|
104
|
+
aws_vpc 'test_vpc_preexisting_igw' do
|
105
|
+
cidr_block '10.0.1.0/24'
|
106
|
+
internet_gateway test_internet_gateway
|
107
|
+
end
|
108
|
+
|
109
|
+
it "leaves the attachment alone if internet_gateway is set to true" do
|
110
|
+
expect(test_vpc_preexisting_igw.aws_object.internet_gateway).to eq(test_internet_gateway.aws_object)
|
111
|
+
expect_recipe {
|
112
|
+
aws_vpc 'test_vpc_preexisting_igw' do
|
113
|
+
cidr_block '10.0.1.0/24'
|
114
|
+
internet_gateway true
|
115
|
+
end
|
116
|
+
}.to match_an_aws_vpc('test_vpc_preexisting_igw',
|
117
|
+
internet_gateway: test_internet_gateway.aws_object
|
118
|
+
).and be_idempotent
|
119
|
+
end
|
120
|
+
|
121
|
+
it "deletes the attachment if internet_gateway is set to false" do
|
122
|
+
expect_recipe {
|
123
|
+
aws_vpc 'test_vpc_preexisting_igw' do
|
124
|
+
cidr_block '10.0.1.0/24'
|
125
|
+
internet_gateway false
|
126
|
+
end
|
127
|
+
}.to match_an_aws_vpc('test_vpc_preexisting_igw',
|
128
|
+
internet_gateway: nil
|
129
|
+
).and match_an_aws_internet_gateway('test_internet_gateway',
|
130
|
+
vpc: nil
|
131
|
+
).and be_idempotent
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context 'with a VPC and an attached aws_internet_gateway resource' do
|
136
|
+
aws_internet_gateway 'test_internet_gateway1'
|
137
|
+
aws_internet_gateway 'test_internet_gateway2'
|
138
|
+
aws_vpc 'test_vpc_preexisting_igw' do
|
139
|
+
cidr_block '10.0.1.0/24'
|
140
|
+
internet_gateway test_internet_gateway1.aws_object
|
141
|
+
end
|
142
|
+
|
143
|
+
it "switches the attachment to a newly specified aws_internet_gateway" do
|
144
|
+
expect(test_vpc_preexisting_igw.aws_object.internet_gateway).to eq(test_internet_gateway1.aws_object)
|
145
|
+
expect_recipe {
|
146
|
+
aws_internet_gateway 'test_internet_gateway2' do
|
147
|
+
vpc 'test_vpc_preexisting_igw'
|
148
|
+
end
|
149
|
+
}.to match_an_aws_internet_gateway('test_internet_gateway1',
|
150
|
+
vpc: nil
|
151
|
+
).and match_an_aws_internet_gateway('test_internet_gateway2',
|
152
|
+
vpc: test_vpc_preexisting_igw.aws_object
|
153
|
+
).and be_idempotent
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -4,19 +4,18 @@ describe "AwsNetworkInterface" do
|
|
4
4
|
when_the_chef_12_server "exists", organization: 'foo', server_scope: :context do
|
5
5
|
with_aws "when connected to AWS" do
|
6
6
|
|
7
|
-
context "setting up public VPC"
|
7
|
+
context "setting up public VPC" do
|
8
8
|
|
9
|
-
# Putting this in its own context so it doesn't slow down other tests
|
10
9
|
setup_public_vpc
|
11
10
|
|
12
|
-
it "creates an aws_network_interface resource with maximum attributes" do
|
11
|
+
it "creates an aws_network_interface resource with maximum attributes", :super_slow do
|
13
12
|
expect_recipe {
|
14
13
|
machine "test_machine" do
|
15
14
|
machine_options bootstrap_options: {
|
16
15
|
subnet_id: 'test_public_subnet',
|
17
16
|
security_group_ids: ['test_security_group']
|
18
17
|
}
|
19
|
-
action :
|
18
|
+
action :ready
|
20
19
|
end
|
21
20
|
|
22
21
|
aws_network_interface 'test_network_interface' do
|
@@ -0,0 +1,522 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Chef::Resource::AwsRoute53HostedZone do
|
4
|
+
extend AWSSupport
|
5
|
+
|
6
|
+
when_the_chef_12_server "exists", organization: 'foo', server_scope: :context do
|
7
|
+
with_aws "when connected to AWS" do
|
8
|
+
|
9
|
+
context "aws_route53_hosted_zone" do
|
10
|
+
|
11
|
+
# for the occasional spec where the test zone won't be automatically deleted, the spec can set
|
12
|
+
# @zone_to_delete to communicate the zone name to the 'after' block. (this can't be done just with
|
13
|
+
# let-vars because attribute values in dependent RecordSet resources have to be hard-coded.)
|
14
|
+
let(:zone_to_delete) { @zone_to_delete }
|
15
|
+
|
16
|
+
after(:example) {
|
17
|
+
if zone_to_delete
|
18
|
+
converge {
|
19
|
+
aws_route53_hosted_zone zone_to_delete do
|
20
|
+
action :destroy
|
21
|
+
end
|
22
|
+
}
|
23
|
+
end
|
24
|
+
}
|
25
|
+
|
26
|
+
let(:zone_name) { "aws-spec-#{Time.now.to_i}.com" }
|
27
|
+
|
28
|
+
context ":create" do
|
29
|
+
it "creates a hosted zone without attributes" do
|
30
|
+
expect(recipe {
|
31
|
+
aws_route53_hosted_zone zone_name
|
32
|
+
}).to create_an_aws_route53_hosted_zone(zone_name).and be_idempotent
|
33
|
+
end
|
34
|
+
|
35
|
+
it "creates a hosted zone with attributes" do
|
36
|
+
test_comment = "Test comment for spec."
|
37
|
+
|
38
|
+
expect_recipe {
|
39
|
+
aws_route53_hosted_zone zone_name do
|
40
|
+
comment test_comment
|
41
|
+
end
|
42
|
+
}.to create_an_aws_route53_hosted_zone(zone_name,
|
43
|
+
config: { comment: test_comment }).and be_idempotent
|
44
|
+
end
|
45
|
+
|
46
|
+
# we don't want to go overboard testing all our validations, but this is the one that can cause the
|
47
|
+
# most difficult user confusion, and AWS won't catch it.
|
48
|
+
it "crashes if the zone name has a trailing dot" do
|
49
|
+
expect_converge {
|
50
|
+
aws_route53_hosted_zone "#{zone_name}."
|
51
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /domain name cannot end with a dot/)
|
52
|
+
end
|
53
|
+
|
54
|
+
it "updates the zone comment" do
|
55
|
+
expected_comment = "Updated comment."
|
56
|
+
|
57
|
+
expect_recipe {
|
58
|
+
aws_route53_hosted_zone zone_name do
|
59
|
+
comment "Initial comment."
|
60
|
+
end
|
61
|
+
aws_route53_hosted_zone zone_name do
|
62
|
+
comment expected_comment
|
63
|
+
end
|
64
|
+
}.to create_an_aws_route53_hosted_zone(zone_name,
|
65
|
+
config: { comment: expected_comment }).and be_idempotent
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "RecordSets" do
|
70
|
+
let(:sdk_cname_rr) {
|
71
|
+
{
|
72
|
+
name: "some-host.feegle.com.", # AWS adds the trailing dot.
|
73
|
+
type: "CNAME",
|
74
|
+
ttl: 3600,
|
75
|
+
resource_records: [{ value: "some-other-host" }],
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
it "crashes on duplicate RecordSets" do
|
80
|
+
expect_converge {
|
81
|
+
aws_route53_hosted_zone "chasm.com" do
|
82
|
+
record_sets {
|
83
|
+
aws_route53_record_set "wooster1" do
|
84
|
+
rr_name "wooster.chasm.com"
|
85
|
+
type "CNAME"
|
86
|
+
ttl 300
|
87
|
+
resource_records ["some-other-host"]
|
88
|
+
end
|
89
|
+
aws_route53_record_set "wooster2" do
|
90
|
+
rr_name "wooster.chasm.com"
|
91
|
+
type "A"
|
92
|
+
ttl 3600
|
93
|
+
resource_records ["141.222.1.1"]
|
94
|
+
end
|
95
|
+
}
|
96
|
+
end
|
97
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /Duplicate RecordSet found in resource/)
|
98
|
+
end
|
99
|
+
|
100
|
+
# normally wouldn't bother with this, but it's best to be safe with the inlined resources.
|
101
|
+
it "crashes on a RecordSet with an invalid action" do
|
102
|
+
expect_converge {
|
103
|
+
aws_route53_hosted_zone zone_name do
|
104
|
+
record_sets {
|
105
|
+
aws_route53_record_set "wooster1" do
|
106
|
+
action :invoke
|
107
|
+
rr_name "wooster.example.com"
|
108
|
+
type "CNAME"
|
109
|
+
ttl 300
|
110
|
+
end
|
111
|
+
}
|
112
|
+
end
|
113
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /Option action must be equal to one of/)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "creates a hosted zone with a RecordSet" do
|
117
|
+
expect_recipe {
|
118
|
+
aws_route53_hosted_zone "feegle.com" do
|
119
|
+
record_sets {
|
120
|
+
aws_route53_record_set "some-hostname CNAME" do
|
121
|
+
rr_name "some-host.feegle.com"
|
122
|
+
type "CNAME"
|
123
|
+
ttl 3600
|
124
|
+
resource_records ["some-other-host"]
|
125
|
+
end
|
126
|
+
}
|
127
|
+
end
|
128
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
129
|
+
resource_record_sets: [{}, {}, sdk_cname_rr]).and be_idempotent
|
130
|
+
# the empty {} acts as a wildcard, and all zones have SOA and NS records we want to skip.
|
131
|
+
end
|
132
|
+
|
133
|
+
it "creates a hosted zone with a RecordSet with an RR name with a trailing dot" do
|
134
|
+
expect_recipe {
|
135
|
+
aws_route53_hosted_zone "feegle.com" do
|
136
|
+
record_sets {
|
137
|
+
aws_route53_record_set "some-host.feegle.com." do
|
138
|
+
type "CNAME"
|
139
|
+
ttl 3600
|
140
|
+
resource_records ["some-other-host"]
|
141
|
+
end
|
142
|
+
}
|
143
|
+
end
|
144
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
145
|
+
resource_record_sets: [{}, {}, sdk_cname_rr]).and be_idempotent
|
146
|
+
end
|
147
|
+
|
148
|
+
# AWS's error for this is "FATAL problem: DomainLabelEmpty encountered", so we help the user out.
|
149
|
+
it "crashes with a RecordSet with a mismatched zone name with a trailing dot" do
|
150
|
+
expect_converge {
|
151
|
+
aws_route53_hosted_zone "feegle.com" do
|
152
|
+
record_sets {
|
153
|
+
aws_route53_record_set "some-host.wrong-zone.com." do
|
154
|
+
type "CNAME"
|
155
|
+
ttl 3600
|
156
|
+
resource_records ["some-other-host"]
|
157
|
+
end
|
158
|
+
}
|
159
|
+
end
|
160
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /RecordSet name.*does not match parent/)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "creates and updates a RecordSet" do
|
164
|
+
expected_rr = sdk_cname_rr.merge({ ttl: 1800 })
|
165
|
+
|
166
|
+
expect_recipe {
|
167
|
+
aws_route53_hosted_zone "feegle.com" do
|
168
|
+
record_sets {
|
169
|
+
aws_route53_record_set "some-hostname CNAME" do
|
170
|
+
rr_name "some-host"
|
171
|
+
type "CNAME"
|
172
|
+
ttl 3600
|
173
|
+
resource_records ["some-other-host"]
|
174
|
+
end
|
175
|
+
}
|
176
|
+
end
|
177
|
+
|
178
|
+
aws_route53_hosted_zone "feegle.com" do
|
179
|
+
record_sets {
|
180
|
+
aws_route53_record_set "some-hostname CNAME" do
|
181
|
+
rr_name "some-host"
|
182
|
+
type "CNAME"
|
183
|
+
ttl 1800
|
184
|
+
resource_records ["some-other-host"]
|
185
|
+
end
|
186
|
+
}
|
187
|
+
end
|
188
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
189
|
+
resource_record_sets: [{}, {}, expected_rr]).and be_idempotent
|
190
|
+
end
|
191
|
+
|
192
|
+
it "creates and deletes a RecordSet" do
|
193
|
+
expect_recipe {
|
194
|
+
aws_route53_hosted_zone "feegle.com" do
|
195
|
+
record_sets {
|
196
|
+
aws_route53_record_set "some-api-host" do
|
197
|
+
type "CNAME"
|
198
|
+
ttl 3600
|
199
|
+
resource_records ["some-other-host"]
|
200
|
+
end
|
201
|
+
}
|
202
|
+
end
|
203
|
+
|
204
|
+
aws_route53_hosted_zone "feegle.com" do
|
205
|
+
record_sets {
|
206
|
+
aws_route53_record_set "some-api-host" do
|
207
|
+
action :destroy
|
208
|
+
type "CNAME"
|
209
|
+
ttl 3600
|
210
|
+
resource_records ["some-other-host"]
|
211
|
+
end
|
212
|
+
}
|
213
|
+
end
|
214
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
215
|
+
resource_record_sets: [{}, {}]).and be_idempotent
|
216
|
+
end
|
217
|
+
|
218
|
+
it "automatically uses the parent zone name in the RecordSet name" do
|
219
|
+
expect_recipe {
|
220
|
+
aws_route53_hosted_zone "feegle.com" do
|
221
|
+
record_sets {
|
222
|
+
aws_route53_record_set "some-host" do
|
223
|
+
type "CNAME"
|
224
|
+
ttl 3600
|
225
|
+
resource_records ["some-other-host"]
|
226
|
+
end
|
227
|
+
}
|
228
|
+
end
|
229
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
230
|
+
resource_record_sets: [{}, {}, sdk_cname_rr]).and be_idempotent
|
231
|
+
end
|
232
|
+
|
233
|
+
it "raises the AWS exception when trying to delete a record using mismatched values" do
|
234
|
+
@zone_to_delete = zone_name = "raise-aws-exception.com"
|
235
|
+
|
236
|
+
expect_converge {
|
237
|
+
aws_route53_hosted_zone zone_name do
|
238
|
+
record_sets {
|
239
|
+
aws_route53_record_set "some-hostname CNAME" do
|
240
|
+
rr_name "some-api-host.raise-aws-exception.com"
|
241
|
+
type "CNAME"
|
242
|
+
ttl 3600
|
243
|
+
resource_records ["some-other-host"]
|
244
|
+
end
|
245
|
+
}
|
246
|
+
end
|
247
|
+
}.not_to raise_error
|
248
|
+
|
249
|
+
expect_converge {
|
250
|
+
aws_route53_hosted_zone zone_name do
|
251
|
+
record_sets {
|
252
|
+
aws_route53_record_set "some-hostname CNAME" do
|
253
|
+
action :destroy
|
254
|
+
rr_name "some-api-host.raise-aws-exception.com"
|
255
|
+
type "CNAME"
|
256
|
+
ttl 100
|
257
|
+
resource_records ["some-other-host"]
|
258
|
+
end
|
259
|
+
}
|
260
|
+
end
|
261
|
+
}.to raise_error(Aws::Route53::Errors::InvalidChangeBatch, /Tried to delete.*the values provided do not match the current values/)
|
262
|
+
end
|
263
|
+
|
264
|
+
it "uses the resource name as the :rr_name" do
|
265
|
+
expect_recipe {
|
266
|
+
aws_route53_hosted_zone "feegle.com" do
|
267
|
+
record_sets {
|
268
|
+
aws_route53_record_set "some-host" do
|
269
|
+
type "CNAME"
|
270
|
+
ttl 3600
|
271
|
+
resource_records ["some-other-host"]
|
272
|
+
end
|
273
|
+
}
|
274
|
+
end
|
275
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
276
|
+
resource_record_sets: [{}, {}, sdk_cname_rr]).and be_idempotent
|
277
|
+
end
|
278
|
+
|
279
|
+
context "inheriting default property values" do
|
280
|
+
it "provides zone defaults for RecordSet values" do
|
281
|
+
expected_a = {
|
282
|
+
name: "another-host.feegle.com.",
|
283
|
+
type: "A",
|
284
|
+
ttl: 3600,
|
285
|
+
resource_records: [{value: "8.8.8.8"}]
|
286
|
+
}
|
287
|
+
expect_recipe {
|
288
|
+
aws_route53_hosted_zone "feegle.com" do
|
289
|
+
defaults ttl: 3600, type: "CNAME"
|
290
|
+
record_sets {
|
291
|
+
aws_route53_record_set "some-host" do
|
292
|
+
resource_records ["some-other-host"]
|
293
|
+
end
|
294
|
+
aws_route53_record_set "another-host" do
|
295
|
+
type "A"
|
296
|
+
resource_records ["8.8.8.8"]
|
297
|
+
end
|
298
|
+
}
|
299
|
+
end
|
300
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
301
|
+
resource_record_sets: [{}, {},
|
302
|
+
expected_a, sdk_cname_rr]).and be_idempotent
|
303
|
+
end
|
304
|
+
|
305
|
+
it "only provides defaults for certain properties" do
|
306
|
+
expect_converge {
|
307
|
+
aws_route53_hosted_zone "feegle.com" do
|
308
|
+
defaults invalid_default: 42
|
309
|
+
record_sets {
|
310
|
+
aws_route53_record_set "some-host" do
|
311
|
+
resource_records ["some-other-host"]
|
312
|
+
end
|
313
|
+
aws_route53_record_set "another-host" do
|
314
|
+
type "A"
|
315
|
+
resource_records ["8.8.8.8"]
|
316
|
+
end
|
317
|
+
}
|
318
|
+
end
|
319
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /'defaults' keys may be any of/)
|
320
|
+
end
|
321
|
+
|
322
|
+
it "checks for requiredness" do
|
323
|
+
expect_converge {
|
324
|
+
aws_route53_hosted_zone "feegle.com" do
|
325
|
+
defaults ttl: 3600
|
326
|
+
record_sets {
|
327
|
+
aws_route53_record_set "some-host" do
|
328
|
+
resource_records ["some-other-host"]
|
329
|
+
end
|
330
|
+
}
|
331
|
+
end
|
332
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /required/i)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
context "individual RR types" do
|
337
|
+
let(:expected) {{
|
338
|
+
cname: {
|
339
|
+
name: "cname-host.feegle.com.",
|
340
|
+
type: "CNAME",
|
341
|
+
ttl: 1800,
|
342
|
+
resource_records: [{ value: "8.8.8.8" }],
|
343
|
+
},
|
344
|
+
a: {
|
345
|
+
name: "a-host.feegle.com.",
|
346
|
+
type: "A",
|
347
|
+
ttl: 1800,
|
348
|
+
resource_records: [{ value: "141.222.1.1"}, { value: "8.8.8.8" }],
|
349
|
+
},
|
350
|
+
aaaa: {
|
351
|
+
name: "aaaa-host.feegle.com.",
|
352
|
+
type: "AAAA",
|
353
|
+
ttl: 1800,
|
354
|
+
resource_records: [{ value: "2607:f8b0:4010:801::1001"},
|
355
|
+
{ value: "2607:f8b9:4010:801::1001" }],
|
356
|
+
},
|
357
|
+
mx: {
|
358
|
+
name: "mx-host.feegle.com.",
|
359
|
+
type: "MX",
|
360
|
+
ttl: 1800,
|
361
|
+
# AWS does *not* append a dot to these.
|
362
|
+
resource_records: [{ value: "10 mail1.example.com"}, { value: "15 mail2.example.com."}],
|
363
|
+
},
|
364
|
+
txt: {
|
365
|
+
name: "txt-host.feegle.com.",
|
366
|
+
type: "TXT",
|
367
|
+
resource_records: [{ value: '"Very Important Data"' },
|
368
|
+
{ value: '"Even More Important Data"' }],
|
369
|
+
},
|
370
|
+
srv: {
|
371
|
+
name: "srv-host.feegle.com.",
|
372
|
+
type: "SRV",
|
373
|
+
resource_records: [{ value: "10 50 8889 chef-server.example.com" },
|
374
|
+
{ value: "20 70 80 narf.net" }],
|
375
|
+
},
|
376
|
+
}}
|
377
|
+
|
378
|
+
it "handles CNAME records" do
|
379
|
+
expect_recipe {
|
380
|
+
aws_route53_hosted_zone "feegle.com" do
|
381
|
+
record_sets {
|
382
|
+
aws_route53_record_set "CNAME-host" do
|
383
|
+
type "CNAME"
|
384
|
+
ttl 1800
|
385
|
+
resource_records ["8.8.8.8"]
|
386
|
+
end
|
387
|
+
}
|
388
|
+
end
|
389
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
390
|
+
resource_record_sets: [ {}, {}, expected[:cname] ]).and be_idempotent
|
391
|
+
|
392
|
+
expect_converge {
|
393
|
+
aws_route53_hosted_zone "feegle.com" do
|
394
|
+
record_sets {
|
395
|
+
aws_route53_record_set "CNAME-host" do
|
396
|
+
type "CNAME"
|
397
|
+
ttl 1800
|
398
|
+
resource_records ["141.222.1.1", "8.8.8.8"]
|
399
|
+
end
|
400
|
+
}
|
401
|
+
end
|
402
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /CNAME records.*have a single value/)
|
403
|
+
end
|
404
|
+
|
405
|
+
it "handles A records" do
|
406
|
+
expect_recipe {
|
407
|
+
aws_route53_hosted_zone "feegle.com" do
|
408
|
+
record_sets {
|
409
|
+
aws_route53_record_set "A-host" do
|
410
|
+
type "A"
|
411
|
+
ttl 1800
|
412
|
+
resource_records ["141.222.1.1", "8.8.8.8"]
|
413
|
+
end
|
414
|
+
}
|
415
|
+
end
|
416
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
417
|
+
resource_record_sets: [ {}, {}, expected[:a] ]).and be_idempotent
|
418
|
+
|
419
|
+
expect_converge {
|
420
|
+
aws_route53_hosted_zone "feegle.com" do
|
421
|
+
record_sets {
|
422
|
+
aws_route53_record_set "A-host" do
|
423
|
+
type "A"
|
424
|
+
ttl 1800
|
425
|
+
resource_records ["hostnames-dont-go-here.com", "8.8.8.8"]
|
426
|
+
end
|
427
|
+
}
|
428
|
+
end
|
429
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /A records are of the form/)
|
430
|
+
end
|
431
|
+
|
432
|
+
# we don't validate IPv6 addresses, because they are complex.
|
433
|
+
it "handles AAAA records" do
|
434
|
+
expect_recipe {
|
435
|
+
aws_route53_hosted_zone "feegle.com" do
|
436
|
+
record_sets {
|
437
|
+
aws_route53_record_set "AAAA-host" do
|
438
|
+
type "AAAA"
|
439
|
+
ttl 1800
|
440
|
+
resource_records ["2607:f8b0:4010:801::1001", "2607:f8b9:4010:801::1001"]
|
441
|
+
end
|
442
|
+
}
|
443
|
+
end
|
444
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
445
|
+
resource_record_sets: [ {}, {}, expected[:aaaa] ]).and be_idempotent
|
446
|
+
end
|
447
|
+
|
448
|
+
it "handles MX records" do
|
449
|
+
expect_recipe {
|
450
|
+
aws_route53_hosted_zone "feegle.com" do
|
451
|
+
record_sets {
|
452
|
+
aws_route53_record_set "MX-host" do
|
453
|
+
type "MX"
|
454
|
+
ttl 1800
|
455
|
+
resource_records ["10 mail1.example.com", "15 mail2.example.com."]
|
456
|
+
end
|
457
|
+
}
|
458
|
+
end
|
459
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
460
|
+
resource_record_sets: [ {}, {}, expected[:mx] ]).and be_idempotent
|
461
|
+
expect_converge {
|
462
|
+
aws_route53_hosted_zone "feegle.com" do
|
463
|
+
record_sets {
|
464
|
+
aws_route53_record_set "MX-host" do
|
465
|
+
type "MX"
|
466
|
+
ttl 1800
|
467
|
+
resource_records ["10mail1.example.com", "mail2.example.com."]
|
468
|
+
end
|
469
|
+
}
|
470
|
+
end
|
471
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /MX records must have a priority and mail server/)
|
472
|
+
end
|
473
|
+
|
474
|
+
# we don't validate TXT values:
|
475
|
+
# http://docs.aws.amazon.com/Route53/latest/DeveloperGuide/ResourceRecordTypes.html#TXTFormat
|
476
|
+
it "handles TXT records" do
|
477
|
+
expect_recipe {
|
478
|
+
aws_route53_hosted_zone "feegle.com" do
|
479
|
+
record_sets {
|
480
|
+
aws_route53_record_set "TXT-host" do
|
481
|
+
type "TXT"
|
482
|
+
ttl 300
|
483
|
+
resource_records %w["Very\ Important\ Data" "Even\ More\ Important\ Data"]
|
484
|
+
end
|
485
|
+
}
|
486
|
+
end
|
487
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
488
|
+
resource_record_sets: [ {}, {}, expected[:txt] ]).and be_idempotent
|
489
|
+
end
|
490
|
+
|
491
|
+
it "handles SRV records" do
|
492
|
+
expect_recipe {
|
493
|
+
aws_route53_hosted_zone "feegle.com" do
|
494
|
+
record_sets {
|
495
|
+
aws_route53_record_set "SRV-host" do
|
496
|
+
type "SRV"
|
497
|
+
ttl 300
|
498
|
+
resource_records ["10 50 8889 chef-server.example.com", "20 70 80 narf.net"]
|
499
|
+
end
|
500
|
+
}
|
501
|
+
end
|
502
|
+
}.to create_an_aws_route53_hosted_zone("feegle.com",
|
503
|
+
resource_record_sets: [ {}, {}, expected[:srv] ]).and be_idempotent
|
504
|
+
|
505
|
+
expect_converge {
|
506
|
+
aws_route53_hosted_zone "feegle.com" do
|
507
|
+
record_sets {
|
508
|
+
aws_route53_record_set "SRV-host" do
|
509
|
+
type "SRV"
|
510
|
+
ttl 300
|
511
|
+
resource_records ["1050 8889 chef-server.example.com", "narf.net"]
|
512
|
+
end
|
513
|
+
}
|
514
|
+
end
|
515
|
+
}.to raise_error(Chef::Exceptions::ValidationFailed, /SRV.*priority, weight, port, and hostname/)
|
516
|
+
end
|
517
|
+
end # end RR types
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|
521
|
+
end
|
522
|
+
end
|