sprinkle_dns 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +76 -0
- data/LICENSE +21 -0
- data/README.md +181 -0
- data/Rakefile +1 -0
- data/examples/example01.rb +47 -0
- data/examples/example02.rb +61 -0
- data/examples/example03.rb +27 -0
- data/examples/example04.rb +22 -0
- data/lib/sprinkle_dns/cli/hosted_zone_diff.rb +206 -0
- data/lib/sprinkle_dns/cli/interactive_change_request_printer.rb +32 -0
- data/lib/sprinkle_dns/cli/propagated_change_request_printer.rb +33 -0
- data/lib/sprinkle_dns/client.rb +169 -0
- data/lib/sprinkle_dns/config.rb +43 -0
- data/lib/sprinkle_dns/core_ext/array_wrap.rb +11 -0
- data/lib/sprinkle_dns/core_ext/zonify.rb +4 -0
- data/lib/sprinkle_dns/entry_policy_service.rb +100 -0
- data/lib/sprinkle_dns/exceptions.rb +9 -0
- data/lib/sprinkle_dns/hosted_zone.rb +36 -0
- data/lib/sprinkle_dns/hosted_zone_alias.rb +91 -0
- data/lib/sprinkle_dns/hosted_zone_domain.rb +18 -0
- data/lib/sprinkle_dns/hosted_zone_entry.rb +97 -0
- data/lib/sprinkle_dns/providers/mock_client.rb +60 -0
- data/lib/sprinkle_dns/providers/route53_client.rb +155 -0
- data/lib/sprinkle_dns/version.rb +3 -0
- data/lib/sprinkle_dns.rb +5 -0
- data/logos/SDNS.png +0 -0
- data/logos/SDNS.svg +1 -0
- data/readme_files/delete_true_and_diff.png +0 -0
- data/readme_files/dry_run_and_diff.png +0 -0
- data/readme_files/force_false.png +0 -0
- data/spec/spec_helper.rb +110 -0
- data/spec/support/entry_helpers.rb +18 -0
- data/spec/unit/cli_hosted_zone_diff_spec.rb +30 -0
- data/spec/unit/hosted_zone_domain_spec.rb +12 -0
- data/spec/unit/hosted_zone_spec.rb +343 -0
- data/spec/unit/mock_client_spec.rb +59 -0
- data/spec/unit/sprinkle_dns_spec.rb +235 -0
- data/sprinkle_dns.gemspec +29 -0
- data/test_perms.rb.example +2 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1fab0389257851cf18cca41f85ba7902d2d6991599f6f41467612fad0861f754
|
4
|
+
data.tar.gz: daa92a1e2c7a5ad893c606bfadc181e355c76622ee55bc905f8a1afcda734f2a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c2e87abb06df0034e18b215e688fd6808452fbb95fa105d95a4ab6f1532b4bdc7d35db72ae0ef8afda82f6d445dcfc21e200cb7bb07ca70cb83d1711555aaa22
|
7
|
+
data.tar.gz: c26276c21b51b54b22a589fcfe622bee85261cf20f9907b36ea7792a300ea81e2e31a830ae8967b0e35c89ada0636f0b8c347261c3fe6b1c2710d483f6b066fb
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.2
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
sprinkle_dns (1.0.0)
|
5
|
+
aws-sdk-route53 (~> 1.21)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
addressable (2.6.0)
|
11
|
+
public_suffix (>= 2.0.2, < 4.0)
|
12
|
+
aws-eventstream (1.0.3)
|
13
|
+
aws-partitions (1.160.0)
|
14
|
+
aws-sdk-core (3.50.0)
|
15
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
16
|
+
aws-partitions (~> 1.0)
|
17
|
+
aws-sigv4 (~> 1.1)
|
18
|
+
jmespath (~> 1.0)
|
19
|
+
aws-sdk-route53 (1.22.0)
|
20
|
+
aws-sdk-core (~> 3, >= 3.48.2)
|
21
|
+
aws-sigv4 (~> 1.1)
|
22
|
+
aws-sigv4 (1.1.0)
|
23
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
24
|
+
coderay (1.1.2)
|
25
|
+
crack (0.4.3)
|
26
|
+
safe_yaml (~> 1.0.0)
|
27
|
+
diff-lcs (1.3)
|
28
|
+
docile (1.3.1)
|
29
|
+
hashdiff (0.3.9)
|
30
|
+
jmespath (1.4.0)
|
31
|
+
json (2.2.0)
|
32
|
+
method_source (0.9.2)
|
33
|
+
pry (0.12.2)
|
34
|
+
coderay (~> 1.1.0)
|
35
|
+
method_source (~> 0.9.0)
|
36
|
+
public_suffix (3.0.3)
|
37
|
+
rake (12.3.2)
|
38
|
+
rspec (3.8.0)
|
39
|
+
rspec-core (~> 3.8.0)
|
40
|
+
rspec-expectations (~> 3.8.0)
|
41
|
+
rspec-mocks (~> 3.8.0)
|
42
|
+
rspec-core (3.8.0)
|
43
|
+
rspec-support (~> 3.8.0)
|
44
|
+
rspec-expectations (3.8.3)
|
45
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
46
|
+
rspec-support (~> 3.8.0)
|
47
|
+
rspec-mocks (3.8.0)
|
48
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
49
|
+
rspec-support (~> 3.8.0)
|
50
|
+
rspec-support (3.8.0)
|
51
|
+
safe_yaml (1.0.5)
|
52
|
+
simplecov (0.16.1)
|
53
|
+
docile (~> 1.1)
|
54
|
+
json (>= 1.8, < 3)
|
55
|
+
simplecov-html (~> 0.10.0)
|
56
|
+
simplecov-html (0.10.2)
|
57
|
+
vcr (3.0.3)
|
58
|
+
webmock (2.3.2)
|
59
|
+
addressable (>= 2.3.6)
|
60
|
+
crack (>= 0.3.2)
|
61
|
+
hashdiff
|
62
|
+
|
63
|
+
PLATFORMS
|
64
|
+
ruby
|
65
|
+
|
66
|
+
DEPENDENCIES
|
67
|
+
pry (~> 0.12)
|
68
|
+
rake (~> 12.3)
|
69
|
+
rspec (~> 3.8)
|
70
|
+
simplecov (~> 0.16)
|
71
|
+
sprinkle_dns!
|
72
|
+
vcr (~> 3.0)
|
73
|
+
webmock (~> 2.3)
|
74
|
+
|
75
|
+
BUNDLED WITH
|
76
|
+
1.17.2
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2015 Billetto
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
![SprinkleDNS logo](logos/SDNS.png)
|
2
|
+
|
3
|
+
# SprinkleDNS
|
4
|
+
|
5
|
+
A diff-based way of managing DNS for people with lots of domains for AWS Route53.
|
6
|
+
|
7
|
+
## How
|
8
|
+
|
9
|
+
Use plain old Ruby to define your DNS configuration:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
require 'sprinkle_dns'
|
13
|
+
|
14
|
+
client = SprinkleDNS::Route53Client.new(ACCESS_KEY_ID, SECRET_ACCESS_KEY)
|
15
|
+
sdns = SprinkleDNS::Client.new(client)
|
16
|
+
|
17
|
+
sdns.entry('A', 'www.billetto.com', '88.80.188.142', 360)
|
18
|
+
sdns.entry('A', 'staging.billetto.com', '88.80.188.143', 360)
|
19
|
+
|
20
|
+
sdns.sprinkle!
|
21
|
+
```
|
22
|
+
|
23
|
+
Or a more advanced example using loops and interpolation:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'sprinkle_dns'
|
27
|
+
|
28
|
+
client = SprinkleDNS::Route53Client.new(ACCESS_KEY_ID, SECRET_ACCESS_KEY)
|
29
|
+
sdns = SprinkleDNS::Client.new(client)
|
30
|
+
|
31
|
+
domains = ['billetto.dk', 'billetto.co.uk', 'billetto.com', 'billetto.se']
|
32
|
+
|
33
|
+
domains.each do |domain|
|
34
|
+
sdns.entry('A', domain, '88.80.188.142', 360)
|
35
|
+
sdns.entry('A', "www.#{domain}", '88.80.188.142', 360)
|
36
|
+
|
37
|
+
s.entry("CNAME", "docs.#{domain}", 'ghs.googlehosted.com', 43200)
|
38
|
+
s.entry("CNAME", "mail.#{domain}", 'ghs.googlehosted.com', 43200)
|
39
|
+
s.entry("CNAME", "drive.#{domain}", 'ghs.googlehosted.com', 43200)
|
40
|
+
|
41
|
+
s.entry("MX", domain, ['1 aspmx.l.google.com',
|
42
|
+
'5 alt1.aspmx.l.google.com',
|
43
|
+
'5 alt2.aspmx.l.google.com',
|
44
|
+
'10 aspmx2.googlemail.com',
|
45
|
+
'10 aspmx3.googlemail.com'], 60)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Overwrite one of the domains, to test our new loadbalancer:
|
49
|
+
sdns.entry('A', 'billetto.com', '89.81.189.143', 360)
|
50
|
+
|
51
|
+
sdns.sprinkle!
|
52
|
+
```
|
53
|
+
|
54
|
+
## Configuration
|
55
|
+
|
56
|
+
You can configure the `SprinkleDNS::Client` like so:
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
client = SprinkleDNS::Route53Client.new(ACCESS_KEY_ID, SECRET_ACCESS_KEY)
|
60
|
+
sdns = SprinkleDNS::Client.new(client,
|
61
|
+
dry_run: false,
|
62
|
+
diff: true,
|
63
|
+
force: true,
|
64
|
+
delete: false,
|
65
|
+
interactive_progress: true,
|
66
|
+
create_hosted_zones: false,
|
67
|
+
)
|
68
|
+
```
|
69
|
+
|
70
|
+
Here is a table that shows the different configuration options:
|
71
|
+
|
72
|
+
| Name | Description | Default value |
|
73
|
+
|------------------------|-----------------------------------------------------------------------------------------------------------|---------------|
|
74
|
+
| `dry_run` | Do not make any changes, just compare and exit, useful with `diff: true`. | `true` |
|
75
|
+
| `diff` | Prints a diff to list the changes that are going to be made. | `true` |
|
76
|
+
| `force` | Do not ask before changes are made, just apply. | `false` |
|
77
|
+
| `delete` | Specifies whether unreferenced entries should be deleted. | `false` |
|
78
|
+
| `interactive_progress` | Shows interactive progress whilst changes are being applied, nice for your terminal, not for your CI-job. | `true` |
|
79
|
+
| `create_hosted_zones` | Specifies whether or not hosted zones should be created. | `false` |
|
80
|
+
|
81
|
+
### `dry_run` and `diff`
|
82
|
+
|
83
|
+
`dry_run` is useful combined with `diff` because it will let you see the changes in a safe manner without any changes being applied:
|
84
|
+
|
85
|
+
![dry_run and diff](readme_files/dry_run_and_diff.png)
|
86
|
+
|
87
|
+
### `force: false`
|
88
|
+
|
89
|
+
With `force` being set to `false` you will be asked whether or not you want to apply the changes:
|
90
|
+
|
91
|
+
![force set to false](readme_files/force_false.png)
|
92
|
+
|
93
|
+
### `delete: true`
|
94
|
+
|
95
|
+
With `delete` being set to `true` SprinkleDNS will delete **any** entries not being referenced, these will also show up in the diff (if it is enabled):
|
96
|
+
|
97
|
+
![delete true shows up in diffs](readme_files/delete_true_and_diff.png)
|
98
|
+
|
99
|
+
### `create_hosted_zones: true`
|
100
|
+
|
101
|
+
With `create_hosted_zones` set to `true`, SprinkleDNS will create a hosted zone if not existing, it requires the `route53:CreateHostedZone` permission.
|
102
|
+
|
103
|
+
## Support for ALIAS-records
|
104
|
+
|
105
|
+
Route53 supports ALIAS-records to achieve CNAME-flattening, SprinkleDNS also supports that, here we point our root domain to an ELB:
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
require 'sprinkle_dns'
|
109
|
+
|
110
|
+
client = SprinkleDNS::Route53Client.new(ACCESS_KEY_ID, SECRET_ACCESS_KEY)
|
111
|
+
sdns = SprinkleDNS::Client.new(client)
|
112
|
+
|
113
|
+
sdns.alias('A', 'billetto.com', 'Z215JYRZR1TBD5', 'dualstack.mothership-test-elb-546580691.eu-central-1.elb.amazonaws.com')
|
114
|
+
|
115
|
+
sdns.sprinkle!
|
116
|
+
```
|
117
|
+
|
118
|
+
## Amazon policy
|
119
|
+
|
120
|
+
This gem uses the following permissions to manage hosted zones:
|
121
|
+
|
122
|
+
- `route53:ListHostedZones`, for getting the list of hosted zones.
|
123
|
+
- `route53:ListResourceRecordSets`, to read the records for a hosted zone.
|
124
|
+
- `route53:ChangeResourceRecordSets`, to change records for a hosted zone.
|
125
|
+
- `route53:GetChange`, for reading when a change have been applied.
|
126
|
+
|
127
|
+
Additionally, you can consider adding the following permissions:
|
128
|
+
|
129
|
+
- `route53:CreateHostedZone`, for allowing the gem to create hosted zones.
|
130
|
+
|
131
|
+
You can allow it for all of your hosted zones:
|
132
|
+
|
133
|
+
```json
|
134
|
+
{
|
135
|
+
"Version": "2012-10-17",
|
136
|
+
"Statement": [
|
137
|
+
{
|
138
|
+
"Effect": "Allow",
|
139
|
+
"Action": [
|
140
|
+
"route53:ListResourceRecordSets",
|
141
|
+
"route53:ChangeResourceRecordSets",
|
142
|
+
"route53:GetChange",
|
143
|
+
"route53:ListHostedZones"
|
144
|
+
],
|
145
|
+
"Resource": [
|
146
|
+
"*"
|
147
|
+
]
|
148
|
+
}
|
149
|
+
]
|
150
|
+
}
|
151
|
+
```
|
152
|
+
|
153
|
+
For a more "locked down" policy you can use this (remember to update the `resource` array):
|
154
|
+
|
155
|
+
```json
|
156
|
+
{
|
157
|
+
"Version": "2012-10-17",
|
158
|
+
"Statement": [
|
159
|
+
{
|
160
|
+
"Effect": "Allow",
|
161
|
+
"Action": [
|
162
|
+
"route53:ListResourceRecordSets",
|
163
|
+
"route53:ChangeResourceRecordSets"
|
164
|
+
],
|
165
|
+
"Resource": [
|
166
|
+
"arn:aws:route53:::hostedzone/Z3EATJAGJWXQE8"
|
167
|
+
]
|
168
|
+
},
|
169
|
+
{
|
170
|
+
"Effect": "Allow",
|
171
|
+
"Action": [
|
172
|
+
"route53:GetChange",
|
173
|
+
"route53:ListHostedZones"
|
174
|
+
],
|
175
|
+
"Resource": [
|
176
|
+
"*"
|
177
|
+
]
|
178
|
+
}
|
179
|
+
]
|
180
|
+
}
|
181
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'sprinkle_dns'
|
2
|
+
|
3
|
+
# require_relative '../test_perms'
|
4
|
+
# client = SprinkleDNS::Route53Client.new(ACCESS_KEY_ID, SECRET_ACCESS_KEY)
|
5
|
+
|
6
|
+
require 'sprinkle_dns/providers/mock_client'
|
7
|
+
hz = SprinkleDNS::HostedZone.new('test.colourful.com.')
|
8
|
+
pe01 = SprinkleDNS::HostedZoneEntry.new('A', 'noref.test.colourful.com.', Array.wrap('80.80.80.80'), 3600, hz.name)
|
9
|
+
pe02 = SprinkleDNS::HostedZoneEntry.new('A', 'updateme.test.colourful.com.', Array.wrap('80.80.80.80'), 3600, hz.name)
|
10
|
+
pe03 = SprinkleDNS::HostedZoneEntry.new('TXT', 'txt.test.colourful.com.', %Q{"#{Time.now.to_i}"}, 60, hz.name)
|
11
|
+
pe04 = SprinkleDNS::HostedZoneEntry.new('A', 'nochange.test.colourful.com.', Array.wrap('80.80.80.80'), 60, hz.name)
|
12
|
+
sleep(1)
|
13
|
+
# We are emulating that these records are already live, mark them as persisted
|
14
|
+
[pe01, pe02, pe03, pe04].each do |persisted|
|
15
|
+
persisted.persisted!
|
16
|
+
hz.resource_record_sets << persisted
|
17
|
+
end
|
18
|
+
|
19
|
+
client = SprinkleDNS::MockClient.new([hz])
|
20
|
+
sdns = SprinkleDNS::Client.new(client, delete: true, force: true)
|
21
|
+
|
22
|
+
sdns.entry('A', 'noref.test.billetto.com.', '127.0.0.1', 7200, 'test.billetto.com')
|
23
|
+
sdns.alias('A', 'www.test.billetto.com', 'Z215JYRZR1TBD5', 'dualstack.mothership-prod-elb-546580691.eu-central-1.elb.amazonaws.com', 'test.billetto.com')
|
24
|
+
sdns.entry('A', 'updateme.test.billetto.com.', '90.90.90.90', 7200, 'test.billetto.com')
|
25
|
+
sdns.entry('TXT', 'txt.test.billetto.com', %Q{"#{Time.now.to_i}"}, 60, 'test.billetto.com')
|
26
|
+
sdns.entry('A', 'nochange.test.billetto.com.', '80.80.80.80', 60, 'test.billetto.com')
|
27
|
+
|
28
|
+
existing_hosted_zones, _ = sdns.sprinkle!
|
29
|
+
|
30
|
+
# ------------------------------------------------------------------------------------------
|
31
|
+
# ##########################################################################################
|
32
|
+
# ------------------------------------------------------------------------------------------
|
33
|
+
|
34
|
+
sdns = SprinkleDNS::Client.new(client, delete: true, force: true)
|
35
|
+
|
36
|
+
sdns.entry('A', 'www.test.billetto.com', '90.90.90.90', 7200, 'test.billetto.com')
|
37
|
+
sdns.entry('A', 'updateme.test.billetto.com.', '90.90.90.90', 7200, 'test.billetto.com')
|
38
|
+
#sdns.entry('TXT', 'txt.test.billetto.com', %Q{"#{Time.now.to_i}"}, 60, 'test.billetto.com')
|
39
|
+
sdns.entry('A', 'nochange.test.billetto.com.', '80.80.80.80', 60, 'test.billetto.com')
|
40
|
+
|
41
|
+
sdns.entry("MX", 'test.billetto.com', ['1 aspmx.l.google.com',
|
42
|
+
'5 alt1.aspmx.l.google.com',
|
43
|
+
'5 alt2.aspmx.l.google.com',
|
44
|
+
'10 aspmx2.googlemail.com',
|
45
|
+
'10 aspmx3.googlemail.com'], 60, 'test.billetto.com')
|
46
|
+
|
47
|
+
existing_hosted_zones, _ = sdns.sprinkle!
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'sprinkle_dns'
|
2
|
+
require 'sprinkle_dns/providers/mock_client'
|
3
|
+
|
4
|
+
hz01 = SprinkleDNS::HostedZone.new('colourful.co.uk.')
|
5
|
+
pe01 = SprinkleDNS::HostedZoneEntry.new('A', 'noref.colourful.co.uk.', Array.wrap('80.80.80.80'), 3600, hz01.name)
|
6
|
+
pe02 = SprinkleDNS::HostedZoneEntry.new('A', 'updateme.colourful.co.uk.', Array.wrap('80.80.80.80'), 3600, hz01.name)
|
7
|
+
pe03 = SprinkleDNS::HostedZoneEntry.new('TXT', 'txt.colourful.co.uk.', %Q{"#{Time.now.to_i}"}, 60, hz01.name)
|
8
|
+
pe04 = SprinkleDNS::HostedZoneEntry.new('A', 'unchanged.colourful.co.uk.', Array.wrap('80.80.80.80'), 60, hz01.name)
|
9
|
+
|
10
|
+
# We are emulating that these records are already live, mark them as persisted
|
11
|
+
[pe01, pe02, pe03, pe04].each do |persisted|
|
12
|
+
persisted.persisted!
|
13
|
+
hz01.resource_record_sets << persisted
|
14
|
+
end
|
15
|
+
|
16
|
+
hz02 = SprinkleDNS::HostedZone.new('colorful.com.')
|
17
|
+
pe05 = SprinkleDNS::HostedZoneEntry.new('A', 'noref.colorful.com.', Array.wrap('80.80.80.80'), 3600, hz02.name)
|
18
|
+
pe06 = SprinkleDNS::HostedZoneEntry.new('A', 'updateme.colorful.com.', Array.wrap('80.80.80.80'), 3600, hz02.name)
|
19
|
+
pe07 = SprinkleDNS::HostedZoneEntry.new('TXT', 'txt.colorful.com.', %Q{"#{Time.now.to_i}"}, 60, hz02.name)
|
20
|
+
pe08 = SprinkleDNS::HostedZoneEntry.new('A', 'nochange.colorful.com.', Array.wrap('80.80.80.80'), 60, hz02.name)
|
21
|
+
|
22
|
+
# We are emulating that these records are already live, mark them as persisted
|
23
|
+
[pe05, pe06, pe07, pe08].each do |persisted|
|
24
|
+
persisted.persisted!
|
25
|
+
hz02.resource_record_sets << persisted
|
26
|
+
end
|
27
|
+
|
28
|
+
hz03 = SprinkleDNS::HostedZone.new('kolorowy.pl.')
|
29
|
+
pe09 = SprinkleDNS::HostedZoneEntry.new('A', 'noref.kolorowy.pl.', Array.wrap('80.80.80.80'), 3600, hz03.name)
|
30
|
+
pe10 = SprinkleDNS::HostedZoneEntry.new('A', 'updateme.kolorowy.pl.', Array.wrap('80.80.80.80'), 3600, hz03.name)
|
31
|
+
pe11 = SprinkleDNS::HostedZoneEntry.new('TXT', 'txt.kolorowy.pl.', %Q{"#{Time.now.to_i}"}, 60, hz03.name)
|
32
|
+
pe12 = SprinkleDNS::HostedZoneEntry.new('A', 'nochange.kolorowy.pl.', Array.wrap('80.80.80.80'), 60, hz03.name)
|
33
|
+
|
34
|
+
# We are emulating that these records are already live, mark them as persisted
|
35
|
+
[pe09, pe10, pe11, pe12].each do |persisted|
|
36
|
+
persisted.persisted!
|
37
|
+
hz03.resource_record_sets << persisted
|
38
|
+
end
|
39
|
+
|
40
|
+
client = SprinkleDNS::MockClient.new([hz01, hz02, hz03])
|
41
|
+
sdns = SprinkleDNS::Client.new(client, force: true, diff: true, delete: true, interactive_progress: true)
|
42
|
+
|
43
|
+
sdns.entry('A', 'colourful.co.uk', '90.90.90.90', 3600)
|
44
|
+
sdns.entry('A', 'updateme.colourful.co.uk', '90.90.90.90', 3600)
|
45
|
+
sdns.entry('A', 'unchanged.colourful.co.uk', '80.80.80.80', 60)
|
46
|
+
sdns.entry('TXT', 'txt.colourful.co.uk', %Q{"#{Time.now.to_i+1}"}, 60)
|
47
|
+
sdns.entry('A', 'colorful.com.', '80.80.80.80', 3601)
|
48
|
+
sdns.entry('A', 'kolorowy.pl.', '80.80.80.80', 3601)
|
49
|
+
|
50
|
+
existing_hosted_zones, _ = sdns.sprinkle!
|
51
|
+
|
52
|
+
puts "--------------------------------------------------------------------------------------------"
|
53
|
+
|
54
|
+
client = SprinkleDNS::MockClient.new([hz02, hz01, hz03])
|
55
|
+
sdns = SprinkleDNS::Client.new(client, delete: false, interactive_progress: false, force: false)
|
56
|
+
|
57
|
+
sdns.entry('A', 'colourful.co.uk', '90.90.90.90', 3601)
|
58
|
+
sdns.entry('A', 'colorful.com.', '80.80.80.80', 3601)
|
59
|
+
sdns.entry('A', 'kolorowy.pl.', '80.80.80.80', 3601)
|
60
|
+
|
61
|
+
existing_hosted_zones, _ = sdns.sprinkle!
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'sprinkle_dns'
|
2
|
+
|
3
|
+
require_relative 'test_perms'
|
4
|
+
client = SprinkleDNS::Route53Client.new(ACCESS_KEY_ID, SECRET_ACCESS_KEY)
|
5
|
+
|
6
|
+
25.times do |retry_count|
|
7
|
+
sdns = SprinkleDNS::Client.new(client, delete: true, force: true)
|
8
|
+
|
9
|
+
sdns.entry('A', 'www.mxtest.billetto.com', '90.90.90.90', 7200, 'mxtest.billetto.com')
|
10
|
+
sdns.entry('A', 'updateme.mxtest.billetto.com.', '90.90.90.90', 7200, 'mxtest.billetto.com')
|
11
|
+
sdns.entry('TXT', 'txt.mxtest.billetto.com', %Q{"#{Time.now.to_i}"}, 60, 'mxtest.billetto.com')
|
12
|
+
sdns.entry('A', 'nochange.mxtest.billetto.com.', '80.80.80.80', 60, 'mxtest.billetto.com')
|
13
|
+
|
14
|
+
sdns.entry("MX", 'mxtest.billetto.com', ['1 aspmx.l.google.com',
|
15
|
+
'5 alt1.aspmx.l.google.com',
|
16
|
+
'5 alt2.aspmx.l.google.com',
|
17
|
+
'10 aspmx2.googlemail.com',
|
18
|
+
'10 aspmx3.googlemail.com'], 60, 'mxtest.billetto.com')
|
19
|
+
|
20
|
+
existing_hosted_zones, _ = sdns.sprinkle!
|
21
|
+
|
22
|
+
sleep_time = (retry_count ** 4) + 15 + (rand(30) * (retry_count + 1))
|
23
|
+
sleep_time_time = Time.now + sleep_time
|
24
|
+
puts "Sleeping #{sleep_time} seconds until #{sleep_time_time}"
|
25
|
+
puts "------------------------------------------------------------------------------------"
|
26
|
+
sleep sleep_time
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'sprinkle_dns'
|
2
|
+
require 'sprinkle_dns/providers/mock_client'
|
3
|
+
|
4
|
+
hz01 = SprinkleDNS::HostedZone.new('colorful.com.')
|
5
|
+
pe01 = SprinkleDNS::HostedZoneEntry.new('A', 'colorful.com.', Array.wrap('80.80.80.80'), 3601, hz01.name)
|
6
|
+
# We are emulating that these records are already live, mark them as persisted
|
7
|
+
[pe01].each do |persisted|
|
8
|
+
persisted.persisted!
|
9
|
+
hz01.resource_record_sets << persisted
|
10
|
+
end
|
11
|
+
|
12
|
+
client = SprinkleDNS::MockClient.new([hz01])
|
13
|
+
sdns = SprinkleDNS::Client.new(client, force: false, diff: true, delete: true, interactive_progress: true, create_hosted_zones: true)
|
14
|
+
|
15
|
+
sdns.entry('A', 'colourful.co.uk', '90.90.90.90', 3600)
|
16
|
+
sdns.entry('A', 'updateme.colourful.co.uk', '90.90.90.90', 3600)
|
17
|
+
sdns.entry('A', 'unchanged.colourful.co.uk', '80.80.80.80', 60)
|
18
|
+
sdns.entry('TXT', 'txt.colourful.co.uk', %Q{"#{Time.now.to_i+1}"}, 60)
|
19
|
+
sdns.entry('A', 'colorful.com.', '80.80.80.80', 3601)
|
20
|
+
sdns.entry('A', 'kolorowy.pl.', '80.80.80.80', 3601)
|
21
|
+
|
22
|
+
existing_hosted_zones, _ = sdns.sprinkle!
|
@@ -0,0 +1,206 @@
|
|
1
|
+
module SprinkleDNS::CLI
|
2
|
+
class HostedZoneDiff
|
3
|
+
HostedZone = Struct.new(:action, :name)
|
4
|
+
Entry = Struct.new(:action, :type, :type_highlight, :name, :name_highlight, :value1, :value1_highlight, :value2, :value2_highlight, :hosted_zone)
|
5
|
+
|
6
|
+
def diff(existing_hosted_zones, missing_hosted_zones, configuration)
|
7
|
+
entries = []
|
8
|
+
|
9
|
+
hosted_zones = if configuration.create_hosted_zones?
|
10
|
+
(existing_hosted_zones + missing_hosted_zones)
|
11
|
+
else
|
12
|
+
existing_hosted_zones
|
13
|
+
end
|
14
|
+
|
15
|
+
hosted_zones.each do |hosted_zone|
|
16
|
+
policy_service = SprinkleDNS::EntryPolicyService.new(hosted_zone, configuration)
|
17
|
+
|
18
|
+
to_create = policy_service.entries_to_create
|
19
|
+
to_update = policy_service.entries_to_update
|
20
|
+
to_delete = policy_service.entries_to_delete
|
21
|
+
|
22
|
+
if missing_hosted_zones.include?(hosted_zone)
|
23
|
+
entries << hosted_zone_to_struct('+', hosted_zone)
|
24
|
+
end
|
25
|
+
|
26
|
+
hosted_zone.entries.each do |entry|
|
27
|
+
if to_create.include?(entry)
|
28
|
+
entries << entry_to_struct('+', entry, hosted_zone)
|
29
|
+
elsif to_update.include?(entry)
|
30
|
+
old_entry = entry
|
31
|
+
new_entry = entry.new_entry
|
32
|
+
|
33
|
+
entries << entry_to_struct('u-', old_entry, hosted_zone)
|
34
|
+
entries << entry_to_struct('u+', new_entry, hosted_zone, old_entry)
|
35
|
+
elsif to_delete.include?(entry)
|
36
|
+
entries << entry_to_struct('-', entry, hosted_zone)
|
37
|
+
else
|
38
|
+
entries << entry_to_struct(nil, entry, hosted_zone)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
coloured_entries = []
|
44
|
+
|
45
|
+
entries.each do |e|
|
46
|
+
colour_mod = case e.action
|
47
|
+
when '+'
|
48
|
+
->(text) { "#{fg(*green)}#{text}#{color_reset}" }
|
49
|
+
when '-'
|
50
|
+
->(text) { "#{fg(*red)}#{text}#{color_reset}" }
|
51
|
+
when nil
|
52
|
+
->(text) { "#{text}" }
|
53
|
+
end
|
54
|
+
|
55
|
+
colour_mod_highlight = case e.action
|
56
|
+
when '+'
|
57
|
+
->(text) { "#{fg(*black)}#{bg(*green)}#{text}#{color_reset}" }
|
58
|
+
when '-'
|
59
|
+
->(text) { "#{fg(*black)}#{bg(*red)}#{text}#{color_reset}" }
|
60
|
+
when nil
|
61
|
+
->(text) { "#{text}" }
|
62
|
+
end
|
63
|
+
|
64
|
+
case e
|
65
|
+
when HostedZone
|
66
|
+
information = [colour_mod.call(e.action), colour_mod_highlight.call(bold(e.name))]
|
67
|
+
when Entry
|
68
|
+
information = [colour_mod.call(e.action)]
|
69
|
+
|
70
|
+
information << if e.type_highlight
|
71
|
+
colour_mod_highlight.call(e.type)
|
72
|
+
else
|
73
|
+
colour_mod.call(e.type)
|
74
|
+
end
|
75
|
+
|
76
|
+
information << if e.name_highlight
|
77
|
+
colour_mod_highlight.call(e.name)
|
78
|
+
else
|
79
|
+
colour_mod.call(e.name)
|
80
|
+
end
|
81
|
+
|
82
|
+
information << if e.value1_highlight
|
83
|
+
colour_mod_highlight.call(e.value1)
|
84
|
+
else
|
85
|
+
colour_mod.call(e.value1)
|
86
|
+
end
|
87
|
+
|
88
|
+
information << if e.value2_highlight
|
89
|
+
colour_mod_highlight.call(e.value2)
|
90
|
+
else
|
91
|
+
colour_mod.call(e.value2)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
coloured_entries << information.compact.delete_if(&:empty?)
|
96
|
+
end
|
97
|
+
|
98
|
+
coloured_entries
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def hex_to_rgb(hex)
|
104
|
+
hex_split = hex.match(/#(..)(..)(..)/)
|
105
|
+
[hex_split[1], hex_split[2], hex_split[3]].map(&:hex)
|
106
|
+
end
|
107
|
+
|
108
|
+
def red
|
109
|
+
hex_to_rgb('#ff6e67')
|
110
|
+
end
|
111
|
+
|
112
|
+
def green
|
113
|
+
hex_to_rgb('#5bf68c')
|
114
|
+
end
|
115
|
+
|
116
|
+
def black
|
117
|
+
hex_to_rgb('#000000')
|
118
|
+
end
|
119
|
+
|
120
|
+
def fg(r, g, b)
|
121
|
+
"\x1b[38;2;#{r};#{g};#{b}m"
|
122
|
+
end
|
123
|
+
|
124
|
+
def bg(r, g, b)
|
125
|
+
"\x1b[48;2;#{r};#{g};#{b}m"
|
126
|
+
end
|
127
|
+
|
128
|
+
def color_reset
|
129
|
+
"\x1b[0m"
|
130
|
+
end
|
131
|
+
|
132
|
+
def bold(text)
|
133
|
+
"\033[1m#{text}\033[0m"
|
134
|
+
end
|
135
|
+
|
136
|
+
def hosted_zone_to_struct(action, hosted_zone)
|
137
|
+
HostedZone.new(action, hosted_zone.name)
|
138
|
+
end
|
139
|
+
|
140
|
+
def entry_to_struct(action, entry, hosted_zone, parent_entry = nil)
|
141
|
+
type_highlight, name_highlight, value1_highlight, value2_highlight = if !parent_entry && ['+', '-'].include?(action)
|
142
|
+
[true, true, true, true]
|
143
|
+
else
|
144
|
+
[false, false, nil, nil]
|
145
|
+
end
|
146
|
+
|
147
|
+
action = case action
|
148
|
+
when 'u-'
|
149
|
+
'-'
|
150
|
+
when 'u+'
|
151
|
+
'+'
|
152
|
+
else
|
153
|
+
action
|
154
|
+
end
|
155
|
+
|
156
|
+
value1_highlight ||= if parent_entry
|
157
|
+
case parent_entry
|
158
|
+
when SprinkleDNS::HostedZoneEntry
|
159
|
+
parent_entry.changed_value
|
160
|
+
when SprinkleDNS::HostedZoneAlias
|
161
|
+
parent_entry.changed_target_hosted_zone_id
|
162
|
+
end
|
163
|
+
else
|
164
|
+
case entry
|
165
|
+
when SprinkleDNS::HostedZoneEntry
|
166
|
+
entry.changed_value
|
167
|
+
when SprinkleDNS::HostedZoneAlias
|
168
|
+
entry.changed_target_hosted_zone_id
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
value2_highlight ||= if parent_entry
|
173
|
+
case parent_entry
|
174
|
+
when SprinkleDNS::HostedZoneEntry
|
175
|
+
parent_entry.changed_ttl
|
176
|
+
when SprinkleDNS::HostedZoneAlias
|
177
|
+
parent_entry.changed_target_dns_name
|
178
|
+
end
|
179
|
+
else
|
180
|
+
case entry
|
181
|
+
when SprinkleDNS::HostedZoneEntry
|
182
|
+
entry.changed_ttl
|
183
|
+
when SprinkleDNS::HostedZoneAlias
|
184
|
+
entry.changed_target_dns_name
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
case entry
|
189
|
+
when SprinkleDNS::HostedZoneEntry
|
190
|
+
Entry.new(action,
|
191
|
+
entry.type, type_highlight,
|
192
|
+
entry.name, name_highlight,
|
193
|
+
entry.value, value1_highlight,
|
194
|
+
entry.ttl, value2_highlight,
|
195
|
+
hosted_zone.name)
|
196
|
+
when SprinkleDNS::HostedZoneAlias
|
197
|
+
Entry.new(action,
|
198
|
+
entry.type, type_highlight,
|
199
|
+
entry.name, name_highlight,
|
200
|
+
entry.target_hosted_zone_id, value1_highlight,
|
201
|
+
entry.target_dns_name, value2_highlight,
|
202
|
+
hosted_zone.name)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|