cumulus-aws 0.11.1
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 +15 -0
- data/.gitignore +3 -0
- data/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +29 -0
- data/LICENSE +202 -0
- data/README.md +41 -0
- data/autocomplete +137 -0
- data/bin/cumulus +658 -0
- data/cumulus +2 -0
- data/cumulus-aws.gemspec +20 -0
- data/lib/autoscaling/AutoScaling.rb +40 -0
- data/lib/autoscaling/loader/Loader.rb +56 -0
- data/lib/autoscaling/manager/Manager.rb +360 -0
- data/lib/autoscaling/models/AlarmConfig.rb +165 -0
- data/lib/autoscaling/models/AlarmDiff.rb +172 -0
- data/lib/autoscaling/models/AutoScalingDiff.rb +178 -0
- data/lib/autoscaling/models/GroupConfig.rb +330 -0
- data/lib/autoscaling/models/PolicyConfig.rb +135 -0
- data/lib/autoscaling/models/PolicyDiff.rb +73 -0
- data/lib/autoscaling/models/ScheduledActionDiff.rb +53 -0
- data/lib/autoscaling/models/ScheduledConfig.rb +96 -0
- data/lib/aws_extensions/ec2/DhcpOptions.rb +41 -0
- data/lib/aws_extensions/ec2/Instance.rb +29 -0
- data/lib/aws_extensions/ec2/NetworkAcl.rb +25 -0
- data/lib/aws_extensions/ec2/NetworkInterface.rb +14 -0
- data/lib/aws_extensions/ec2/RouteTable.rb +26 -0
- data/lib/aws_extensions/ec2/SecurityGroup.rb +16 -0
- data/lib/aws_extensions/ec2/Subnet.rb +28 -0
- data/lib/aws_extensions/ec2/Volume.rb +24 -0
- data/lib/aws_extensions/ec2/Vpc.rb +14 -0
- data/lib/aws_extensions/ec2/VpcEndpoint.rb +11 -0
- data/lib/aws_extensions/elb/BackendServerDescription.rb +12 -0
- data/lib/aws_extensions/elb/PolicyDescription.rb +14 -0
- data/lib/aws_extensions/kinesis/StreamDescription.rb +12 -0
- data/lib/aws_extensions/route53/AliasTarget.rb +21 -0
- data/lib/aws_extensions/s3/Bucket.rb +33 -0
- data/lib/aws_extensions/s3/BucketAcl.rb +28 -0
- data/lib/aws_extensions/s3/BucketCors.rb +17 -0
- data/lib/aws_extensions/s3/BucketLifecycle.rb +21 -0
- data/lib/aws_extensions/s3/BucketLogging.rb +18 -0
- data/lib/aws_extensions/s3/BucketNotification.rb +23 -0
- data/lib/aws_extensions/s3/BucketPolicy.rb +18 -0
- data/lib/aws_extensions/s3/BucketTagging.rb +15 -0
- data/lib/aws_extensions/s3/BucketVersioning.rb +14 -0
- data/lib/aws_extensions/s3/BucketWebsite.rb +49 -0
- data/lib/aws_extensions/s3/CORSRule.rb +27 -0
- data/lib/aws_extensions/s3/ReplicationConfiguration.rb +22 -0
- data/lib/cloudfront/CloudFront.rb +83 -0
- data/lib/cloudfront/loader/Loader.rb +31 -0
- data/lib/cloudfront/manager/Manager.rb +183 -0
- data/lib/cloudfront/models/CacheBehaviorConfig.rb +237 -0
- data/lib/cloudfront/models/CacheBehaviorDiff.rb +211 -0
- data/lib/cloudfront/models/CustomOriginConfig.rb +51 -0
- data/lib/cloudfront/models/CustomOriginDiff.rb +74 -0
- data/lib/cloudfront/models/DistributionConfig.rb +183 -0
- data/lib/cloudfront/models/DistributionDiff.rb +131 -0
- data/lib/cloudfront/models/InvalidationConfig.rb +37 -0
- data/lib/cloudfront/models/OriginConfig.rb +144 -0
- data/lib/cloudfront/models/OriginDiff.rb +86 -0
- data/lib/cloudfront/models/OriginSslProtocols.rb +28 -0
- data/lib/cloudfront/models/OriginSslProtocolsDiff.rb +39 -0
- data/lib/common/BaseLoader.rb +80 -0
- data/lib/common/manager/Manager.rb +148 -0
- data/lib/common/models/Diff.rb +114 -0
- data/lib/common/models/ListChange.rb +21 -0
- data/lib/common/models/TagsDiff.rb +55 -0
- data/lib/common/models/UTCTimeSource.rb +17 -0
- data/lib/conf/Configuration.rb +365 -0
- data/lib/ec2/EC2.rb +503 -0
- data/lib/ec2/IPProtocolMapping.rb +165 -0
- data/lib/ec2/loaders/EbsLoader.rb +19 -0
- data/lib/ec2/loaders/InstanceLoader.rb +32 -0
- data/lib/ec2/managers/EbsManager.rb +176 -0
- data/lib/ec2/managers/InstanceManager.rb +509 -0
- data/lib/ec2/models/EbsGroupConfig.rb +133 -0
- data/lib/ec2/models/EbsGroupDiff.rb +48 -0
- data/lib/ec2/models/InstanceConfig.rb +202 -0
- data/lib/ec2/models/InstanceDiff.rb +95 -0
- data/lib/elb/ELB.rb +148 -0
- data/lib/elb/loader/Loader.rb +65 -0
- data/lib/elb/manager/Manager.rb +581 -0
- data/lib/elb/models/AccessLogConfig.rb +82 -0
- data/lib/elb/models/AccessLogDiff.rb +47 -0
- data/lib/elb/models/HealthCheckConfig.rb +91 -0
- data/lib/elb/models/HealthCheckDiff.rb +50 -0
- data/lib/elb/models/ListenerConfig.rb +99 -0
- data/lib/elb/models/ListenerDiff.rb +91 -0
- data/lib/elb/models/LoadBalancerConfig.rb +239 -0
- data/lib/elb/models/LoadBalancerDiff.rb +265 -0
- data/lib/iam/IAM.rb +36 -0
- data/lib/iam/loader/Loader.rb +117 -0
- data/lib/iam/manager/IamGroups.rb +98 -0
- data/lib/iam/manager/IamResource.rb +288 -0
- data/lib/iam/manager/IamRoles.rb +112 -0
- data/lib/iam/manager/IamUsers.rb +54 -0
- data/lib/iam/manager/Manager.rb +29 -0
- data/lib/iam/migration/AssumeRoleUnifier.rb +34 -0
- data/lib/iam/migration/PolicyUnifier.rb +90 -0
- data/lib/iam/models/GroupConfig.rb +40 -0
- data/lib/iam/models/IamDiff.rb +132 -0
- data/lib/iam/models/PolicyConfig.rb +67 -0
- data/lib/iam/models/ResourceWithPolicy.rb +208 -0
- data/lib/iam/models/RoleConfig.rb +53 -0
- data/lib/iam/models/StatementConfig.rb +35 -0
- data/lib/iam/models/UserConfig.rb +21 -0
- data/lib/kinesis/Kinesis.rb +94 -0
- data/lib/kinesis/loader/Loader.rb +19 -0
- data/lib/kinesis/manager/Manager.rb +206 -0
- data/lib/kinesis/models/StreamConfig.rb +75 -0
- data/lib/kinesis/models/StreamDiff.rb +58 -0
- data/lib/lambda/Lambda.rb +41 -0
- data/lib/route53/loader/Loader.rb +32 -0
- data/lib/route53/manager/Manager.rb +241 -0
- data/lib/route53/models/AliasTarget.rb +86 -0
- data/lib/route53/models/RecordConfig.rb +178 -0
- data/lib/route53/models/RecordDiff.rb +140 -0
- data/lib/route53/models/Vpc.rb +24 -0
- data/lib/route53/models/ZoneConfig.rb +156 -0
- data/lib/route53/models/ZoneDiff.rb +118 -0
- data/lib/s3/S3.rb +89 -0
- data/lib/s3/loader/Loader.rb +66 -0
- data/lib/s3/manager/Manager.rb +296 -0
- data/lib/s3/models/BucketConfig.rb +321 -0
- data/lib/s3/models/BucketDiff.rb +167 -0
- data/lib/s3/models/GrantConfig.rb +189 -0
- data/lib/s3/models/GrantDiff.rb +50 -0
- data/lib/s3/models/LifecycleConfig.rb +142 -0
- data/lib/s3/models/LifecycleDiff.rb +46 -0
- data/lib/s3/models/LoggingConfig.rb +81 -0
- data/lib/s3/models/NotificationConfig.rb +157 -0
- data/lib/s3/models/NotificationDiff.rb +62 -0
- data/lib/s3/models/ReplicationConfig.rb +133 -0
- data/lib/s3/models/ReplicationDiff.rb +60 -0
- data/lib/s3/models/WebsiteConfig.rb +107 -0
- data/lib/security/SecurityGroups.rb +39 -0
- data/lib/security/loader/Loader.rb +94 -0
- data/lib/security/manager/Manager.rb +246 -0
- data/lib/security/models/RuleConfig.rb +161 -0
- data/lib/security/models/RuleDiff.rb +72 -0
- data/lib/security/models/RuleMigration.rb +127 -0
- data/lib/security/models/SecurityGroupConfig.rb +172 -0
- data/lib/security/models/SecurityGroupDiff.rb +112 -0
- data/lib/sns/SNS.rb +40 -0
- data/lib/sqs/SQS.rb +62 -0
- data/lib/sqs/loader/Loader.rb +34 -0
- data/lib/sqs/manager/Manager.rb +128 -0
- data/lib/sqs/models/DeadLetterConfig.rb +70 -0
- data/lib/sqs/models/DeadLetterDiff.rb +35 -0
- data/lib/sqs/models/QueueConfig.rb +115 -0
- data/lib/sqs/models/QueueDiff.rb +89 -0
- data/lib/util/Colors.rb +111 -0
- data/lib/util/StatusCodes.rb +51 -0
- data/lib/vpc/loader/Loader.rb +73 -0
- data/lib/vpc/manager/Manager.rb +954 -0
- data/lib/vpc/models/AclEntryConfig.rb +150 -0
- data/lib/vpc/models/AclEntryDiff.rb +54 -0
- data/lib/vpc/models/DhcpConfig.rb +100 -0
- data/lib/vpc/models/DhcpDiff.rb +90 -0
- data/lib/vpc/models/EndpointConfig.rb +76 -0
- data/lib/vpc/models/EndpointDiff.rb +69 -0
- data/lib/vpc/models/NetworkAclConfig.rb +87 -0
- data/lib/vpc/models/NetworkAclDiff.rb +116 -0
- data/lib/vpc/models/RouteConfig.rb +82 -0
- data/lib/vpc/models/RouteDiff.rb +50 -0
- data/lib/vpc/models/RouteTableConfig.rb +92 -0
- data/lib/vpc/models/RouteTableDiff.rb +101 -0
- data/lib/vpc/models/SubnetConfig.rb +113 -0
- data/lib/vpc/models/SubnetDiff.rb +78 -0
- data/lib/vpc/models/VpcConfig.rb +173 -0
- data/lib/vpc/models/VpcDiff.rb +315 -0
- data/rakefile.rb +8 -0
- metadata +245 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require "cloudfront/CloudFront"
|
|
2
|
+
require "elb/ELB"
|
|
3
|
+
require "s3/S3"
|
|
4
|
+
|
|
5
|
+
module Cumulus
|
|
6
|
+
module Route53
|
|
7
|
+
# Public: A struct that matches the structure of the AWS alias target struct
|
|
8
|
+
AliasTarget = Struct.new(:name, :type, :local_zone_id) do
|
|
9
|
+
# Public: Produce the dns_name for this alias
|
|
10
|
+
#
|
|
11
|
+
# Returns the dns_name
|
|
12
|
+
def dns_name
|
|
13
|
+
if is_elb?
|
|
14
|
+
"dualstack.#{ELB::get_aws(name).dns_name}"
|
|
15
|
+
elsif is_s3?
|
|
16
|
+
"s3-website-#{S3::get_aws(name).location}.amazonaws.com"
|
|
17
|
+
elsif is_cloudfront?
|
|
18
|
+
CloudFront::get_aws(name).domain_name
|
|
19
|
+
else
|
|
20
|
+
name
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Public: Produce a hash representing this alias target
|
|
25
|
+
#
|
|
26
|
+
# Returns the hash
|
|
27
|
+
def to_hash
|
|
28
|
+
{
|
|
29
|
+
"name" => name,
|
|
30
|
+
"type" => type
|
|
31
|
+
}.reject { |k, v| v.nil? }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Public: Produce the hosted_zone_id for this alias
|
|
35
|
+
#
|
|
36
|
+
# Returns the hosted_zone_id
|
|
37
|
+
def hosted_zone_id
|
|
38
|
+
if is_elb?
|
|
39
|
+
ELB::get_aws(name).canonical_hosted_zone_name_id
|
|
40
|
+
elsif is_record_set?
|
|
41
|
+
local_zone_id
|
|
42
|
+
elsif is_s3?
|
|
43
|
+
S3::zone_ids[S3::get_aws(name).location]
|
|
44
|
+
elsif is_cloudfront?
|
|
45
|
+
"Z2FDTNDATAQYW2" # AWS hard codes this
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Public: Determine whether to evaluate the health check on the target. Always
|
|
50
|
+
# false.
|
|
51
|
+
#
|
|
52
|
+
# Returns false
|
|
53
|
+
def evaluate_target_health
|
|
54
|
+
false
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Public: Determine if this alias is for an ELB
|
|
58
|
+
#
|
|
59
|
+
# Returns true if the alias is an ELB
|
|
60
|
+
def is_elb?
|
|
61
|
+
type.downcase == "elb"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Public: Determine if this alias is for a record set
|
|
65
|
+
#
|
|
66
|
+
# Returns true if the alias is for a record set
|
|
67
|
+
def is_record_set?
|
|
68
|
+
type.downcase == "record"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Public: Determine if this alias is for an s3 website
|
|
72
|
+
#
|
|
73
|
+
# Returns true if the alias is for an s3 website
|
|
74
|
+
def is_s3?
|
|
75
|
+
type.downcase == "s3"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Public: Determine if this alias is for a Cloudfront distribution
|
|
79
|
+
#
|
|
80
|
+
# Returns true if the alias is for a Cloudfront distribution
|
|
81
|
+
def is_cloudfront?
|
|
82
|
+
type.downcase == "cloudfront"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
require "aws_extensions/route53/AliasTarget"
|
|
2
|
+
require "aws_extensions/s3/Bucket"
|
|
3
|
+
require "cloudfront/CloudFront"
|
|
4
|
+
require "elb/ELB"
|
|
5
|
+
require "route53/models/AliasTarget"
|
|
6
|
+
require "route53/models/RecordDiff"
|
|
7
|
+
require "s3/S3"
|
|
8
|
+
|
|
9
|
+
require "aws-sdk"
|
|
10
|
+
|
|
11
|
+
module Cumulus
|
|
12
|
+
module Route53
|
|
13
|
+
# Monkey patch AliasTarget so we can call a method that will compare ELB DNS names correctly
|
|
14
|
+
Aws::Route53::Types::AliasTarget.send(:include, AwsExtensions::Route53::AliasTarget)
|
|
15
|
+
# Monkey patch Bucket so we can get the location of the bucket
|
|
16
|
+
Aws::S3::Types::Bucket.send(:include, AwsExtensions::S3::Types::Bucket)
|
|
17
|
+
|
|
18
|
+
# Public: An object representing configurationf for a single record in a zone
|
|
19
|
+
class RecordConfig
|
|
20
|
+
|
|
21
|
+
attr_reader :alias_target
|
|
22
|
+
attr_reader :name
|
|
23
|
+
attr_reader :ttl
|
|
24
|
+
attr_reader :type
|
|
25
|
+
attr_reader :value
|
|
26
|
+
|
|
27
|
+
# Public: Constructor.
|
|
28
|
+
#
|
|
29
|
+
# json - a hash containing the JSON configuration for the record
|
|
30
|
+
# domain - the domain of the zone this record belongs to
|
|
31
|
+
# zone_id - the id of the zone this record belongs to
|
|
32
|
+
def initialize(json = nil, domain = nil, zone_id = nil)
|
|
33
|
+
if !json.nil?
|
|
34
|
+
@name = if json["name"] == "" then domain else "#{json["name"].chomp(".")}.#{domain}".chomp(".") end
|
|
35
|
+
@ttl = json["ttl"]
|
|
36
|
+
@type = json["type"]
|
|
37
|
+
|
|
38
|
+
if !json["value"].nil?
|
|
39
|
+
@value = json["value"]
|
|
40
|
+
|
|
41
|
+
# TXT and SPF records have each value wrapped in quotes
|
|
42
|
+
if @type == "TXT" or @type == "SPF"
|
|
43
|
+
@value = @value.map { |v| "\"#{v}\"" }
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
alias_name = if json["alias"]["name"].nil?
|
|
47
|
+
if json["alias"]["type"] == "s3" then @name else domain end
|
|
48
|
+
else
|
|
49
|
+
json["alias"]["name"].chomp(".")
|
|
50
|
+
end
|
|
51
|
+
@alias_target = AliasTarget.new(
|
|
52
|
+
alias_name,
|
|
53
|
+
json["alias"]["type"],
|
|
54
|
+
zone_id
|
|
55
|
+
)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Public: Populate this RecordConfig from an AWS resource.
|
|
61
|
+
#
|
|
62
|
+
# aws - the aws resource
|
|
63
|
+
# domain - the domain of the parent hosted zone
|
|
64
|
+
def populate(aws, domain)
|
|
65
|
+
@name = aws.name.chomp(domain).chomp(".")
|
|
66
|
+
@ttl = aws.ttl
|
|
67
|
+
@type = aws.type
|
|
68
|
+
if !aws.resource_records.nil?
|
|
69
|
+
if @type == "TXT" or @type == "SPF"
|
|
70
|
+
@value = aws.resource_records.map { |r| r.value[1..-2] }
|
|
71
|
+
else
|
|
72
|
+
@value = aws.resource_records.map(&:value)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if !aws.alias_target.nil?
|
|
77
|
+
if aws.alias_target.dns_name.include? "elb"
|
|
78
|
+
@alias_target = AliasTarget.new(
|
|
79
|
+
Cumulus::ELB::get_aws_by_dns_name(aws.alias_target.elb_dns_name).load_balancer_name,
|
|
80
|
+
"elb",
|
|
81
|
+
nil
|
|
82
|
+
)
|
|
83
|
+
elsif aws.alias_target.dns_name.include? "s3"
|
|
84
|
+
@alias_target = AliasTarget.new(nil, "s3", nil)
|
|
85
|
+
elsif aws.alias_target.dns_name.include? "cloudfront"
|
|
86
|
+
@alias_target = AliasTarget.new(nil, "cloudfront", nil)
|
|
87
|
+
else
|
|
88
|
+
@alias_target = AliasTarget.new(aws.alias_target.dns_name.chomp("."), "record", nil)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Public: Get the config as a hash
|
|
94
|
+
#
|
|
95
|
+
# Returns the hash
|
|
96
|
+
def to_hash
|
|
97
|
+
{
|
|
98
|
+
"name" => @name,
|
|
99
|
+
"type" => @type,
|
|
100
|
+
"ttl" => @ttl,
|
|
101
|
+
"value" => @value,
|
|
102
|
+
"alias" => if @alias_target.nil? then nil else @alias_target.to_hash end,
|
|
103
|
+
}.reject { |k, v| v.nil? }
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Public: Produce an array of differences between this local configuration and the
|
|
107
|
+
# configuration in AWS
|
|
108
|
+
#
|
|
109
|
+
# aws - the AWS resource
|
|
110
|
+
#
|
|
111
|
+
# Returns an array of the RecordDiffs that were found
|
|
112
|
+
def diff(aws)
|
|
113
|
+
diffs = []
|
|
114
|
+
|
|
115
|
+
if @ttl != aws.ttl
|
|
116
|
+
diffs << SingleRecordDiff.new(RecordChange::TTL, aws, self)
|
|
117
|
+
end
|
|
118
|
+
if !@value.nil? and @value.sort != aws.resource_records.map(&:value).sort
|
|
119
|
+
diffs << SingleRecordDiff.new(RecordChange::VALUE, aws, self)
|
|
120
|
+
end
|
|
121
|
+
if !@alias_target.nil?
|
|
122
|
+
if aws.alias_target.nil? or
|
|
123
|
+
(is_elb_alias? and aws.alias_target.elb_dns_name != ELB::get_aws(@alias_target.name).dns_name) or
|
|
124
|
+
(aws.alias_target.chomped_dns != @alias_target.dns_name)
|
|
125
|
+
diffs << SingleRecordDiff.new(RecordChange::ALIAS, aws, self)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
diffs
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Public: Determine if the record is an alias for an ELB
|
|
133
|
+
#
|
|
134
|
+
# Returns whether this record is an alias for an ELB
|
|
135
|
+
def is_elb_alias?
|
|
136
|
+
!@alias_target.nil? and @alias_target.is_elb?
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Public: Determine if the recourd is an alias for another record
|
|
140
|
+
#
|
|
141
|
+
# Returns whether this record is an alias for another record
|
|
142
|
+
def is_record_set_alias?
|
|
143
|
+
!@alias_target.nil? and @alias_target.is_record_set?
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Public: Determine if the record is an alias for an S3 website
|
|
147
|
+
#
|
|
148
|
+
# Returns whether this record is an alias for an S3 website
|
|
149
|
+
def is_s3_alias?
|
|
150
|
+
!@alias_target.nil? and @alias_target.is_s3?
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Public: Determine if the record is an alias for a Cloudfront distribution
|
|
154
|
+
#
|
|
155
|
+
# Returns whether this record is an alias for a Cloudfront distribution
|
|
156
|
+
def is_cloudfront_alias?
|
|
157
|
+
!@alias_target.nil? and @alias_target.is_cloudfront?
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Public: Produce a `resource_records` array that is analogous to the one used in AWS from
|
|
161
|
+
# the values array used by Cumulus
|
|
162
|
+
#
|
|
163
|
+
# Returns the `resource_records`
|
|
164
|
+
def resource_records
|
|
165
|
+
if !@value.nil?
|
|
166
|
+
@value.map { |v| { value: v } }
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
# Public: Produce a useful human readable version of the name of this RecordConfig
|
|
171
|
+
#
|
|
172
|
+
# Returns the string name
|
|
173
|
+
def readable_name
|
|
174
|
+
"(#{@type}) #{@name}"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
require "common/models/Diff"
|
|
2
|
+
require "elb/ELB"
|
|
3
|
+
require "util/Colors"
|
|
4
|
+
|
|
5
|
+
module Cumulus
|
|
6
|
+
module Route53
|
|
7
|
+
# Public: The types of changes that can be made to records
|
|
8
|
+
module RecordChange
|
|
9
|
+
include Common::DiffChange
|
|
10
|
+
|
|
11
|
+
ALIAS = Common::DiffChange::next_change_id
|
|
12
|
+
CHANGED = Common::DiffChange::next_change_id
|
|
13
|
+
DEFAULT = Common::DiffChange::next_change_id
|
|
14
|
+
IGNORED = Common::DiffChange::next_change_id
|
|
15
|
+
TTL = Common::DiffChange::next_change_id
|
|
16
|
+
VALUE = Common::DiffChange::next_change_id
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Public: Represents differences between local configuration and AWS
|
|
20
|
+
# configuration for records.
|
|
21
|
+
class RecordDiff < Common::Diff
|
|
22
|
+
include RecordChange
|
|
23
|
+
|
|
24
|
+
attr_accessor :message
|
|
25
|
+
attr_accessor :changes
|
|
26
|
+
|
|
27
|
+
# Public: Static method that will create a diff that contains a message but is
|
|
28
|
+
# ignored when syncing because it is a default record.
|
|
29
|
+
#
|
|
30
|
+
# message - the message to display
|
|
31
|
+
# aws - the aws configuration for the record
|
|
32
|
+
#
|
|
33
|
+
# Returns the diff
|
|
34
|
+
def self.default(message, aws)
|
|
35
|
+
diff = RecordDiff.new(DEFAULT, aws)
|
|
36
|
+
diff.message = message
|
|
37
|
+
diff
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Public: Static method that will create a diff that contains a message but is
|
|
41
|
+
# ignored when syncing.
|
|
42
|
+
#
|
|
43
|
+
# message - the message to display
|
|
44
|
+
# aws - the aws configuration for the record
|
|
45
|
+
#
|
|
46
|
+
# Returns the diff
|
|
47
|
+
def self.ignored(message, aws)
|
|
48
|
+
diff = RecordDiff.new(IGNORED, aws)
|
|
49
|
+
diff.message = message
|
|
50
|
+
diff.info_only = true
|
|
51
|
+
diff
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Public: Static method that will create a diff that contains a bunch of
|
|
55
|
+
# singular changes.
|
|
56
|
+
#
|
|
57
|
+
# changes - the changes for the record
|
|
58
|
+
# local - the local configuration for the record
|
|
59
|
+
#
|
|
60
|
+
# Returns the diff
|
|
61
|
+
def self.changed(changes, local)
|
|
62
|
+
diff = RecordDiff.new(CHANGED, nil, local)
|
|
63
|
+
diff.changes = changes
|
|
64
|
+
diff
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def asset_type
|
|
68
|
+
"Record"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def aws_name
|
|
72
|
+
"(#{@aws.type}) #{@aws.name}"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def local_name
|
|
76
|
+
@local.readable_name
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def diff_string
|
|
80
|
+
case @type
|
|
81
|
+
when IGNORED
|
|
82
|
+
message
|
|
83
|
+
when DEFAULT
|
|
84
|
+
message
|
|
85
|
+
when CHANGED
|
|
86
|
+
[
|
|
87
|
+
"Record #{local_name}:",
|
|
88
|
+
changes.map { |c| "\t\t#{c}" }
|
|
89
|
+
].flatten.join("\n")
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Public: Represents a single difference between local configuration and AWS
|
|
96
|
+
# configuration for a single record. This class allows all the changes for a
|
|
97
|
+
# record to be grouped together when printed.
|
|
98
|
+
class SingleRecordDiff < Common::Diff
|
|
99
|
+
include RecordChange
|
|
100
|
+
|
|
101
|
+
def diff_string
|
|
102
|
+
case @type
|
|
103
|
+
when ALIAS
|
|
104
|
+
if @local.is_elb_alias?
|
|
105
|
+
aws_name = ELB::get_aws_by_dns_name(@aws.alias_target.elb_dns_name).load_balancer_name
|
|
106
|
+
"Alias: AWS - #{Colors.aws_changes(aws_name)}, Local - #{Colors.local_changes(@local.alias_target.name)}"
|
|
107
|
+
else
|
|
108
|
+
"Alias: AWS - #{Colors.aws_changes(@aws.alias_target.chomped_dns)}, Local - #{Colors.local_changes(@local.alias_target.dns_name)}"
|
|
109
|
+
end
|
|
110
|
+
when TTL
|
|
111
|
+
"TTL: AWS - #{Colors.aws_changes(@aws.ttl)}, Local - #{Colors.local_changes(@local.ttl)}"
|
|
112
|
+
when VALUE
|
|
113
|
+
[
|
|
114
|
+
"Value:",
|
|
115
|
+
values_to_add.map { |v| Colors.added("\t\t\t#{v}") },
|
|
116
|
+
values_to_remove.map { |v| Colors.removed("\t\t\t#{v}") }
|
|
117
|
+
].flatten.join("\n")
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
# Internal: Get the value parts that are in local configuration but not in AWS
|
|
124
|
+
#
|
|
125
|
+
# Returns the local value parts
|
|
126
|
+
def values_to_add
|
|
127
|
+
aws_value = @aws.resource_records.map(&:value)
|
|
128
|
+
@local.value.reject { |v| aws_value.include?(v) }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Internal: Get the value parts that are in AWS but not local configuration
|
|
132
|
+
#
|
|
133
|
+
# Returns the AWS value parts
|
|
134
|
+
def values_to_remove
|
|
135
|
+
aws_value = @aws.resource_records.map(&:value)
|
|
136
|
+
aws_value.reject { |v| @local.value.include?(v) }
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Cumulus
|
|
2
|
+
module Route53
|
|
3
|
+
Vpc = Struct.new(:id, :region) do
|
|
4
|
+
# Public: Implement <=> to allow sorting. Sorts by id and then region
|
|
5
|
+
def <=>(other)
|
|
6
|
+
if self.id == other.id
|
|
7
|
+
self.region <=> other.region
|
|
8
|
+
else
|
|
9
|
+
self.id <=> self.id
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Public: Produce a hash representing the VPC
|
|
14
|
+
#
|
|
15
|
+
# Returns the hash
|
|
16
|
+
def to_hash
|
|
17
|
+
{
|
|
18
|
+
"id" => id,
|
|
19
|
+
"region" => region
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
require "conf/Configuration"
|
|
2
|
+
require "route53/loader/Loader"
|
|
3
|
+
require "route53/models/RecordConfig"
|
|
4
|
+
require "route53/models/RecordDiff"
|
|
5
|
+
require "route53/models/Vpc"
|
|
6
|
+
require "route53/models/ZoneDiff"
|
|
7
|
+
|
|
8
|
+
require "json"
|
|
9
|
+
|
|
10
|
+
module Cumulus
|
|
11
|
+
module Route53
|
|
12
|
+
# Public: An object representing configuration for a zone
|
|
13
|
+
class ZoneConfig
|
|
14
|
+
attr_reader :comment
|
|
15
|
+
attr_reader :domain
|
|
16
|
+
attr_reader :id
|
|
17
|
+
attr_reader :name
|
|
18
|
+
attr_reader :private
|
|
19
|
+
attr_reader :records
|
|
20
|
+
attr_reader :vpc
|
|
21
|
+
|
|
22
|
+
# Public: Constructor
|
|
23
|
+
#
|
|
24
|
+
# json - a hash containing the JSON configuration for the zone
|
|
25
|
+
def initialize(name, json = nil)
|
|
26
|
+
@name = name
|
|
27
|
+
if !json.nil?
|
|
28
|
+
@id = "/hostedzone/#{json["zone-id"]}"
|
|
29
|
+
@domain = json["domain"].chomp(".")
|
|
30
|
+
@private = json["private"]
|
|
31
|
+
@vpc = if @private then json["vpc"].map { |v| Vpc.new(v["id"], v["region"]) } else [] end
|
|
32
|
+
@comment = json["comment"]
|
|
33
|
+
|
|
34
|
+
includes = if json["records"]["includes"].nil? then [] else json["records"]["includes"] end
|
|
35
|
+
includes = includes.flat_map(&Loader.method(:includes_file))
|
|
36
|
+
@records = (json["records"]["inlines"] + includes).map do |j|
|
|
37
|
+
RecordConfig.new(j, @domain, json["zone-id"])
|
|
38
|
+
end
|
|
39
|
+
@ignored = if json["records"]["ignored"].nil? then [] else json["records"]["ignored"] end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Public: Populate this ZoneConfig from an AWS resource
|
|
44
|
+
#
|
|
45
|
+
# aws - the aws resource
|
|
46
|
+
def populate(aws)
|
|
47
|
+
@id = aws.id.sub(/\/hostedzone\//, '')
|
|
48
|
+
@domain = aws.name
|
|
49
|
+
@private = aws.config.private_zone
|
|
50
|
+
@vpc = if @private then aws.vpc else nil end
|
|
51
|
+
@comment = aws.config.comment
|
|
52
|
+
@records = aws.records.map do |record|
|
|
53
|
+
r = RecordConfig.new()
|
|
54
|
+
r.populate(record, @domain)
|
|
55
|
+
r
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Public: Get the config as a prettified JSON string.
|
|
60
|
+
#
|
|
61
|
+
# Returns the JSON string
|
|
62
|
+
def pretty_json
|
|
63
|
+
JSON.pretty_generate({
|
|
64
|
+
"zone-id" => @id,
|
|
65
|
+
"domain" => @domain,
|
|
66
|
+
"private" => @private,
|
|
67
|
+
"vpc" => if @vpc.nil? then nil else @vpc.map(&:to_hash) end,
|
|
68
|
+
"comment" => @comment,
|
|
69
|
+
"records" => {
|
|
70
|
+
"ignored" => if @ignored.nil? then [] else @ignored end,
|
|
71
|
+
"includes" => [],
|
|
72
|
+
"inlines" => @records.map(&:to_hash),
|
|
73
|
+
},
|
|
74
|
+
}.reject { |k, v| v.nil? })
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Public: Produce an array of differences between this local configuration and the
|
|
78
|
+
# configuration in AWS
|
|
79
|
+
#
|
|
80
|
+
# aws - the AWS resource
|
|
81
|
+
#
|
|
82
|
+
# Returns an array of the ZoneDiffs that were found
|
|
83
|
+
def diff(aws)
|
|
84
|
+
diffs = []
|
|
85
|
+
|
|
86
|
+
if @comment != aws.config.comment
|
|
87
|
+
diffs << ZoneDiff.new(ZoneChange::COMMENT, aws, self)
|
|
88
|
+
end
|
|
89
|
+
if @domain != aws.name
|
|
90
|
+
diffs << ZoneDiff.new(ZoneChange::DOMAIN, aws, self)
|
|
91
|
+
end
|
|
92
|
+
if @private != aws.config.private_zone
|
|
93
|
+
diffs << ZoneDiff.new(ZoneChange::PRIVATE, aws, self)
|
|
94
|
+
end
|
|
95
|
+
if @private and @vpc.sort != aws.vpc.sort
|
|
96
|
+
diffs << ZoneDiff.new(ZoneChange::VPC, aws, self)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
record_diffs = diff_records(aws.records)
|
|
100
|
+
if !record_diffs.empty?
|
|
101
|
+
diffs << ZoneDiff.records(record_diffs, self)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
diffs
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
# The unique key on a record is a combination of name and type
|
|
110
|
+
RecordKey = Struct.new(:name, :type)
|
|
111
|
+
|
|
112
|
+
# Internal: Produce an array of differences between local record configuration and the
|
|
113
|
+
# configuration in AWS.
|
|
114
|
+
#
|
|
115
|
+
# aws - an array of records in aws
|
|
116
|
+
#
|
|
117
|
+
# Returns an array of the RecordDiffs that were found
|
|
118
|
+
def diff_records(aws)
|
|
119
|
+
diffs = []
|
|
120
|
+
|
|
121
|
+
# map the records to their keys
|
|
122
|
+
aws = Hash[aws.map { |r| [RecordKey.new(r.name.gsub(/\\100/, "@"), r.type), r] }]
|
|
123
|
+
local = Hash[@records.map { |r| [RecordKey.new(r.name, r.type), r] }]
|
|
124
|
+
|
|
125
|
+
# find records in aws that are not configured locally, ignoring the NS and SOA
|
|
126
|
+
# record for the domain
|
|
127
|
+
aws.each do |key, record|
|
|
128
|
+
if !local.include?(key)
|
|
129
|
+
if @domain == record.name and record.type == "NS"
|
|
130
|
+
diffs << RecordDiff.default("Default NS record is supplied in AWS, but not locally. It will be ignored when syncing.", record)
|
|
131
|
+
elsif @domain == record.name and record.type == "SOA"
|
|
132
|
+
diffs << RecordDiff.default("Default SOA record is supplied in AWS, but not locally. It will be ignored when syncing.", record)
|
|
133
|
+
elsif !@ignored.find_index { |i| !record.name.match(i).nil? }.nil?
|
|
134
|
+
diffs << RecordDiff.ignored("Record (#{record.type}) #{record.name} is ignored by your blacklist", record)
|
|
135
|
+
else
|
|
136
|
+
diffs << RecordDiff.unmanaged(record)
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
local.each do |key, record|
|
|
142
|
+
if !aws.include?(key)
|
|
143
|
+
diffs << RecordDiff.added(record)
|
|
144
|
+
else
|
|
145
|
+
d = record.diff(aws[key])
|
|
146
|
+
if !d.empty?
|
|
147
|
+
diffs << RecordDiff.changed(d, record)
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
diffs.flatten
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|