firespring_dev_commands 2.2.2 → 2.2.3
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 599f3f484514462356186c8d52adfac32e8aa925f7aeaa488bb5fa109db678f3
|
4
|
+
data.tar.gz: 3dffab80edf84b75d073adfc21c1a2c3e0d9dcc666a526f2bda2d5471ff24d6e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ea2c7d6d09e1e5ad6a85ee3d7d3e90826018bee1afc7c1ce1a206ca8514b658c8ef29534dc5b4082bf185d1540a9292218eb3836f6c3405b44d3ff10d98b484
|
7
|
+
data.tar.gz: c06fa865de8acedba8ec7b2934094f7a03fb46e2e1d5a116fc2b12fa4febcf6874940771a843bb022f5f571d5b77e9d4f00d5b3f4930f4cd2f16aa44293a66dd
|
@@ -1,44 +1,59 @@
|
|
1
|
+
require 'aws-sdk-route53'
|
2
|
+
|
1
3
|
module Dev
|
2
4
|
class Aws
|
3
5
|
# Class for performing Route53 functions
|
4
6
|
class Route53
|
5
7
|
attr_reader :client
|
6
8
|
|
7
|
-
def initialize(domains)
|
9
|
+
def initialize(domains = nil)
|
8
10
|
@client = ::Aws::Route53::Client.new
|
9
|
-
@domains = domains
|
11
|
+
@domains = Array(domains || [])
|
10
12
|
end
|
11
13
|
|
12
|
-
|
14
|
+
def zones(&)
|
13
15
|
if @domains.empty?
|
14
|
-
|
16
|
+
each_zone(&)
|
15
17
|
else
|
16
|
-
|
18
|
+
each_zone_by_domains(&)
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
|
-
private def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
private def each_zone
|
23
|
+
Dev::Aws.each_page(client, :list_hosted_zones) do |response|
|
24
|
+
response.hosted_zones&.each do |hosted_zone|
|
25
|
+
next if hosted_zone.config.private_zone
|
26
|
+
|
27
|
+
yield hosted_zone
|
26
28
|
end
|
29
|
+
rescue ::Aws::Route53::Errors::Throttling
|
30
|
+
sleep(1)
|
31
|
+
retry
|
27
32
|
end
|
28
33
|
end
|
29
34
|
|
30
|
-
private def
|
31
|
-
|
32
|
-
|
33
|
-
response = client.list_hosted_zones_by_name({dns_name: domain_name})
|
34
|
-
target = response.hosted_zones.find { |it| it.name.chomp('.') == domain_name }
|
35
|
-
raise "The #{domain_name} hosted zone not found." unless target
|
35
|
+
private def each_zone_by_domains(&)
|
36
|
+
@domains.each do |domain|
|
37
|
+
response = client.list_hosted_zones_by_name({dns_name: domain})
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
# The 'list_hosted_zones_by_name' returns fuzzy matches (so "foo.com" would return both "bar.foo.com" and "foo.com"
|
40
|
+
# So we are only selecting domains that match exactly since that's what we really want here
|
41
|
+
targets = response.hosted_zones.select { |it| it.name.chomp('.') == domain }
|
42
|
+
raise "The #{domain} hosted zone not found." if targets.empty?
|
43
|
+
|
44
|
+
targets.each(&)
|
45
|
+
rescue ::Aws::Route53::Errors::Throttling
|
46
|
+
sleep(1)
|
47
|
+
retry
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
51
|
+
private def ip_address(domain)
|
52
|
+
Addrinfo.ip(domain.to_s.strip)&.ip_address
|
53
|
+
rescue SocketError
|
54
|
+
"Unable to resolve domain: #{domain}"
|
55
|
+
end
|
56
|
+
|
42
57
|
private def target_config_id(zone_id)
|
43
58
|
client.list_query_logging_configs(
|
44
59
|
hosted_zone_id: zone_id,
|
@@ -46,61 +61,78 @@ module Dev
|
|
46
61
|
).query_logging_configs&.first&.id
|
47
62
|
end
|
48
63
|
|
49
|
-
|
50
|
-
|
51
|
-
|
64
|
+
# Get the hosted zone details for the zone id
|
65
|
+
private def details(zone_id)
|
66
|
+
response = client.get_hosted_zone(id: zone_id)
|
67
|
+
[response.hosted_zone, response.delegation_set]
|
68
|
+
end
|
69
|
+
|
70
|
+
def list_zone_details
|
71
|
+
zones do |zone|
|
72
|
+
puts
|
73
|
+
zone_details, delegation_set = details(zone.id)
|
74
|
+
dns_resource = Dev::Dns::Resource.new(zone_details.name)
|
52
75
|
|
53
|
-
|
54
|
-
puts
|
76
|
+
puts "#{zone_details.name.chomp('.').light_white} (#{zone_details.id}):"
|
77
|
+
puts format(' %-50s %s', 'Delegation Set:', delegation_set.id)
|
78
|
+
puts format(' %-50s %s', 'Delegation Defined Nameservers:', delegation_set.name_servers.sort.join(', '))
|
79
|
+
puts format(' %-50s %s', 'DNS Reported Nameservers:', dns_resource.recursive_nameserver_lookup.sort.join(', '))
|
80
|
+
puts format(' %-50s %s', 'DNS Reported Nameserver IPs:', dns_resource.recursive_nameserver_lookup.sort.map { |it| dns_resource.recursive_a_lookup(it) }.join(', '))
|
81
|
+
puts format(' %-50s %s', 'Domain Apex IP Resolution:', dns_resource.recursive_a_lookup.sort.join(', '))
|
82
|
+
rescue ::Aws::Route53::Errors::Throttling
|
83
|
+
sleep(1)
|
84
|
+
retry
|
55
85
|
end
|
86
|
+
puts
|
56
87
|
end
|
57
88
|
|
58
89
|
def list_query_configs
|
59
|
-
|
60
|
-
zones.each do |zone|
|
90
|
+
zones do |zone|
|
61
91
|
target_config_id = target_config_id(zone.id)
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
92
|
+
message = if target_config_id
|
93
|
+
"Config\t=>\t#{target_config_id}".colorize(:green)
|
94
|
+
else
|
95
|
+
'No query logging config assigned.'.colorize(:red)
|
96
|
+
end
|
97
|
+
puts format('%-50s => %s', zone.name, message)
|
98
|
+
rescue ::Aws::Route53::Errors::Throttling
|
99
|
+
sleep(1)
|
100
|
+
retry
|
68
101
|
end
|
69
|
-
|
70
|
-
pretty_puts(output)
|
71
102
|
end
|
72
103
|
|
73
104
|
def activate_query_logging(log_group)
|
74
|
-
|
75
|
-
|
76
|
-
zones.each do |zone|
|
105
|
+
zones do |zone|
|
77
106
|
response = client.create_query_logging_config(
|
78
107
|
hosted_zone_id: zone.id,
|
79
108
|
cloud_watch_logs_log_group_arn: log_group
|
80
109
|
)
|
81
|
-
|
110
|
+
puts format('%-50s => %s', zone.id, response.location)
|
111
|
+
rescue ::Aws::Route53::Errors::Throttling
|
112
|
+
sleep(1)
|
113
|
+
retry
|
82
114
|
rescue ::Aws::Route53::Errors::ServiceError => e
|
83
115
|
raise "Error: #{e.message}" unless e.instance_of?(::Aws::Route53::Errors::QueryLoggingConfigAlreadyExists)
|
84
116
|
|
85
|
-
|
117
|
+
puts format('%-50s => %s', zone.id, e.message)
|
86
118
|
end
|
87
|
-
pretty_puts(output)
|
88
119
|
end
|
89
120
|
|
90
121
|
def deactivate_query_logging
|
91
|
-
|
92
|
-
zones.each do |zone|
|
122
|
+
zones do |zone|
|
93
123
|
target_config_id = target_config_id(zone.id)
|
94
124
|
if target_config_id
|
95
125
|
client.delete_query_logging_config(
|
96
126
|
id: target_config_id
|
97
127
|
)
|
98
|
-
|
128
|
+
puts format('%-50s => %s', zone.id, 'Query logging config removed.'.colorize(:green))
|
99
129
|
else
|
100
|
-
|
130
|
+
puts format('%-50s => %s', zone.id, 'No query logging config assigned.'.colorize(:red))
|
101
131
|
end
|
132
|
+
rescue ::Aws::Route53::Errors::Throttling
|
133
|
+
sleep(1)
|
134
|
+
retry
|
102
135
|
end
|
103
|
-
pretty_puts(output)
|
104
136
|
end
|
105
137
|
end
|
106
138
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Dev
|
2
|
+
class Dns
|
3
|
+
class Resource
|
4
|
+
attr_reader :domain
|
5
|
+
|
6
|
+
def initialize(domain)
|
7
|
+
@domain = domain
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns whether or not the given value is a valid IPv4 or IPv6 address
|
11
|
+
def self.ip?(value)
|
12
|
+
ipv4?(value) || ipv6?(value)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns whether or not the given value is a valid IPv4 address
|
16
|
+
def self.ipv4?(value)
|
17
|
+
value.match?(Resolv::IPv4::Regex)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Returns whether or not the given value is a valid IPv6 address
|
21
|
+
def self.ipv6?(value)
|
22
|
+
value.match?(Resolv::IPv6::Regex)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Recursively determine the correct nameservers for the given domain.
|
26
|
+
# If nameservers are not found, strip subdomains off until we've reached the TLD
|
27
|
+
def recursive_nameserver_lookup(name = domain)
|
28
|
+
records = lookup(name, type: Resolv::DNS::Resource::IN::NS)
|
29
|
+
|
30
|
+
# Strip the subdomain and try again if we didn't find any nameservers (this can happen with wildcards)
|
31
|
+
return recursive_nameserver_lookup(name.split('.', 2).last) if records.empty?
|
32
|
+
|
33
|
+
# Look up the IPs for the nameservers
|
34
|
+
records
|
35
|
+
end
|
36
|
+
|
37
|
+
# Recursively attempt to find an A record for the given domain.
|
38
|
+
# If one isn't found, also check for CNAMEs continually until we have either found an IP or run out of things to check
|
39
|
+
def recursive_a_lookup(name = domain)
|
40
|
+
# Try looking up an A record first. If we find one, we are done.
|
41
|
+
records = lookup(name, type: Resolv::DNS::Resource::IN::A)
|
42
|
+
return records unless records.empty?
|
43
|
+
|
44
|
+
# Try looking up a CNAME record
|
45
|
+
records = lookup(name, type: Resolv::DNS::Resource::IN::CNAME)
|
46
|
+
|
47
|
+
# If we didn't find an A record _or_ a CNAME, just return empty
|
48
|
+
return records if records.empty?
|
49
|
+
|
50
|
+
# If we found more than one CNAME that is a DNS error
|
51
|
+
raise "Found more than one CNAME entry for #{name}. This is not allowed by DNS" if records.length > 1
|
52
|
+
|
53
|
+
recursive_a_lookup(records.first)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Lookup the given name using the record type provided.
|
57
|
+
def lookup(name = domain, type: Resolv::DNS::Resource::IN::A)
|
58
|
+
# Validate the type
|
59
|
+
raise 'lookup type must be a Resolv::DNS::Resource' unless type.ancestors.include?(Resolv::DNS::Resource)
|
60
|
+
|
61
|
+
# If we were given a tld, return empty
|
62
|
+
return [] unless name.include?('.')
|
63
|
+
|
64
|
+
# Look up NS records for the given host
|
65
|
+
records = Resolv::DNS.new.getresources(name, type)
|
66
|
+
|
67
|
+
# Return the record names
|
68
|
+
records.map do |record|
|
69
|
+
if record.respond_to?(:address)
|
70
|
+
record.address.to_s
|
71
|
+
elsif record.respond_to?(:name)
|
72
|
+
record.name.to_s
|
73
|
+
else
|
74
|
+
''
|
75
|
+
end
|
76
|
+
end
|
77
|
+
rescue
|
78
|
+
sleep(1)
|
79
|
+
retry
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -6,16 +6,21 @@ module Dev
|
|
6
6
|
module Services
|
7
7
|
# Class contains rake templates for managing your AWS settings and logging in
|
8
8
|
class Route53 < Dev::Template::BaseInterface
|
9
|
-
|
10
|
-
def create_ensure_credentials_task!
|
9
|
+
def create_list_zone_details_task!
|
11
10
|
# Have to set a local variable to be accessible inside of the instance_eval block
|
12
11
|
exclude = @exclude
|
13
12
|
|
14
13
|
DEV_COMMANDS_TOP_LEVEL.instance_eval do
|
15
|
-
return if exclude.include?(:
|
14
|
+
return if exclude.include?(:list_details)
|
16
15
|
|
17
|
-
|
18
|
-
|
16
|
+
namespace :aws do
|
17
|
+
namespace :hosted_zone do
|
18
|
+
desc 'print details for all hosted zones'
|
19
|
+
task list_details: %w(ensure_aws_credentials) do
|
20
|
+
route53 = Dev::Aws::Route53.new(ENV['DOMAINS'].to_s.strip.split(','))
|
21
|
+
route53.list_zone_details
|
22
|
+
end
|
23
|
+
end
|
19
24
|
end
|
20
25
|
end
|
21
26
|
end
|
@@ -26,9 +31,9 @@ module Dev
|
|
26
31
|
exclude = @exclude
|
27
32
|
|
28
33
|
DEV_COMMANDS_TOP_LEVEL.instance_eval do
|
29
|
-
|
30
|
-
return if exclude.include?(:dns_logging)
|
34
|
+
return if exclude.include?(:dns_logging_activate)
|
31
35
|
|
36
|
+
namespace :aws do
|
32
37
|
namespace :hosted_zone do
|
33
38
|
namespace :dns_logging do
|
34
39
|
desc 'Activates query logging for all hosted zones by default.' \
|
@@ -56,9 +61,9 @@ module Dev
|
|
56
61
|
exclude = @exclude
|
57
62
|
|
58
63
|
DEV_COMMANDS_TOP_LEVEL.instance_eval do
|
59
|
-
|
60
|
-
return if exclude.include?(:dns_logging)
|
64
|
+
return if exclude.include?(:dns_logging_deactivate)
|
61
65
|
|
66
|
+
namespace :aws do
|
62
67
|
namespace :hosted_zone do
|
63
68
|
namespace :dns_logging do
|
64
69
|
desc 'Deactivates query logging for all hosted zones by default. ' \
|
@@ -81,9 +86,9 @@ module Dev
|
|
81
86
|
exclude = @exclude
|
82
87
|
|
83
88
|
DEV_COMMANDS_TOP_LEVEL.instance_eval do
|
84
|
-
|
85
|
-
return if exclude.include?(:dns_logging)
|
89
|
+
return if exclude.include?(:dns_logging_config)
|
86
90
|
|
91
|
+
namespace :aws do
|
87
92
|
namespace :hosted_zone do
|
88
93
|
namespace :dns_logging do
|
89
94
|
desc 'Lists the current config for domain(s). ' \
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: firespring_dev_commands
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.2.
|
4
|
+
version: 2.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Firespring
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-07-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -353,6 +353,7 @@ files:
|
|
353
353
|
- lib/firespring_dev_commands/coverage/cobertura.rb
|
354
354
|
- lib/firespring_dev_commands/coverage/none.rb
|
355
355
|
- lib/firespring_dev_commands/daterange.rb
|
356
|
+
- lib/firespring_dev_commands/dns/resource.rb
|
356
357
|
- lib/firespring_dev_commands/docker.rb
|
357
358
|
- lib/firespring_dev_commands/docker/compose.rb
|
358
359
|
- lib/firespring_dev_commands/docker/desktop.rb
|