cumulus-aws 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (173) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +12 -0
  4. data/Gemfile +4 -0
  5. data/Gemfile.lock +29 -0
  6. data/LICENSE +202 -0
  7. data/README.md +41 -0
  8. data/autocomplete +137 -0
  9. data/bin/cumulus +658 -0
  10. data/cumulus +2 -0
  11. data/cumulus-aws.gemspec +20 -0
  12. data/lib/autoscaling/AutoScaling.rb +40 -0
  13. data/lib/autoscaling/loader/Loader.rb +56 -0
  14. data/lib/autoscaling/manager/Manager.rb +360 -0
  15. data/lib/autoscaling/models/AlarmConfig.rb +165 -0
  16. data/lib/autoscaling/models/AlarmDiff.rb +172 -0
  17. data/lib/autoscaling/models/AutoScalingDiff.rb +178 -0
  18. data/lib/autoscaling/models/GroupConfig.rb +330 -0
  19. data/lib/autoscaling/models/PolicyConfig.rb +135 -0
  20. data/lib/autoscaling/models/PolicyDiff.rb +73 -0
  21. data/lib/autoscaling/models/ScheduledActionDiff.rb +53 -0
  22. data/lib/autoscaling/models/ScheduledConfig.rb +96 -0
  23. data/lib/aws_extensions/ec2/DhcpOptions.rb +41 -0
  24. data/lib/aws_extensions/ec2/Instance.rb +29 -0
  25. data/lib/aws_extensions/ec2/NetworkAcl.rb +25 -0
  26. data/lib/aws_extensions/ec2/NetworkInterface.rb +14 -0
  27. data/lib/aws_extensions/ec2/RouteTable.rb +26 -0
  28. data/lib/aws_extensions/ec2/SecurityGroup.rb +16 -0
  29. data/lib/aws_extensions/ec2/Subnet.rb +28 -0
  30. data/lib/aws_extensions/ec2/Volume.rb +24 -0
  31. data/lib/aws_extensions/ec2/Vpc.rb +14 -0
  32. data/lib/aws_extensions/ec2/VpcEndpoint.rb +11 -0
  33. data/lib/aws_extensions/elb/BackendServerDescription.rb +12 -0
  34. data/lib/aws_extensions/elb/PolicyDescription.rb +14 -0
  35. data/lib/aws_extensions/kinesis/StreamDescription.rb +12 -0
  36. data/lib/aws_extensions/route53/AliasTarget.rb +21 -0
  37. data/lib/aws_extensions/s3/Bucket.rb +33 -0
  38. data/lib/aws_extensions/s3/BucketAcl.rb +28 -0
  39. data/lib/aws_extensions/s3/BucketCors.rb +17 -0
  40. data/lib/aws_extensions/s3/BucketLifecycle.rb +21 -0
  41. data/lib/aws_extensions/s3/BucketLogging.rb +18 -0
  42. data/lib/aws_extensions/s3/BucketNotification.rb +23 -0
  43. data/lib/aws_extensions/s3/BucketPolicy.rb +18 -0
  44. data/lib/aws_extensions/s3/BucketTagging.rb +15 -0
  45. data/lib/aws_extensions/s3/BucketVersioning.rb +14 -0
  46. data/lib/aws_extensions/s3/BucketWebsite.rb +49 -0
  47. data/lib/aws_extensions/s3/CORSRule.rb +27 -0
  48. data/lib/aws_extensions/s3/ReplicationConfiguration.rb +22 -0
  49. data/lib/cloudfront/CloudFront.rb +83 -0
  50. data/lib/cloudfront/loader/Loader.rb +31 -0
  51. data/lib/cloudfront/manager/Manager.rb +183 -0
  52. data/lib/cloudfront/models/CacheBehaviorConfig.rb +237 -0
  53. data/lib/cloudfront/models/CacheBehaviorDiff.rb +211 -0
  54. data/lib/cloudfront/models/CustomOriginConfig.rb +51 -0
  55. data/lib/cloudfront/models/CustomOriginDiff.rb +74 -0
  56. data/lib/cloudfront/models/DistributionConfig.rb +183 -0
  57. data/lib/cloudfront/models/DistributionDiff.rb +131 -0
  58. data/lib/cloudfront/models/InvalidationConfig.rb +37 -0
  59. data/lib/cloudfront/models/OriginConfig.rb +144 -0
  60. data/lib/cloudfront/models/OriginDiff.rb +86 -0
  61. data/lib/cloudfront/models/OriginSslProtocols.rb +28 -0
  62. data/lib/cloudfront/models/OriginSslProtocolsDiff.rb +39 -0
  63. data/lib/common/BaseLoader.rb +80 -0
  64. data/lib/common/manager/Manager.rb +148 -0
  65. data/lib/common/models/Diff.rb +114 -0
  66. data/lib/common/models/ListChange.rb +21 -0
  67. data/lib/common/models/TagsDiff.rb +55 -0
  68. data/lib/common/models/UTCTimeSource.rb +17 -0
  69. data/lib/conf/Configuration.rb +365 -0
  70. data/lib/ec2/EC2.rb +503 -0
  71. data/lib/ec2/IPProtocolMapping.rb +165 -0
  72. data/lib/ec2/loaders/EbsLoader.rb +19 -0
  73. data/lib/ec2/loaders/InstanceLoader.rb +32 -0
  74. data/lib/ec2/managers/EbsManager.rb +176 -0
  75. data/lib/ec2/managers/InstanceManager.rb +509 -0
  76. data/lib/ec2/models/EbsGroupConfig.rb +133 -0
  77. data/lib/ec2/models/EbsGroupDiff.rb +48 -0
  78. data/lib/ec2/models/InstanceConfig.rb +202 -0
  79. data/lib/ec2/models/InstanceDiff.rb +95 -0
  80. data/lib/elb/ELB.rb +148 -0
  81. data/lib/elb/loader/Loader.rb +65 -0
  82. data/lib/elb/manager/Manager.rb +581 -0
  83. data/lib/elb/models/AccessLogConfig.rb +82 -0
  84. data/lib/elb/models/AccessLogDiff.rb +47 -0
  85. data/lib/elb/models/HealthCheckConfig.rb +91 -0
  86. data/lib/elb/models/HealthCheckDiff.rb +50 -0
  87. data/lib/elb/models/ListenerConfig.rb +99 -0
  88. data/lib/elb/models/ListenerDiff.rb +91 -0
  89. data/lib/elb/models/LoadBalancerConfig.rb +239 -0
  90. data/lib/elb/models/LoadBalancerDiff.rb +265 -0
  91. data/lib/iam/IAM.rb +36 -0
  92. data/lib/iam/loader/Loader.rb +117 -0
  93. data/lib/iam/manager/IamGroups.rb +98 -0
  94. data/lib/iam/manager/IamResource.rb +288 -0
  95. data/lib/iam/manager/IamRoles.rb +112 -0
  96. data/lib/iam/manager/IamUsers.rb +54 -0
  97. data/lib/iam/manager/Manager.rb +29 -0
  98. data/lib/iam/migration/AssumeRoleUnifier.rb +34 -0
  99. data/lib/iam/migration/PolicyUnifier.rb +90 -0
  100. data/lib/iam/models/GroupConfig.rb +40 -0
  101. data/lib/iam/models/IamDiff.rb +132 -0
  102. data/lib/iam/models/PolicyConfig.rb +67 -0
  103. data/lib/iam/models/ResourceWithPolicy.rb +208 -0
  104. data/lib/iam/models/RoleConfig.rb +53 -0
  105. data/lib/iam/models/StatementConfig.rb +35 -0
  106. data/lib/iam/models/UserConfig.rb +21 -0
  107. data/lib/kinesis/Kinesis.rb +94 -0
  108. data/lib/kinesis/loader/Loader.rb +19 -0
  109. data/lib/kinesis/manager/Manager.rb +206 -0
  110. data/lib/kinesis/models/StreamConfig.rb +75 -0
  111. data/lib/kinesis/models/StreamDiff.rb +58 -0
  112. data/lib/lambda/Lambda.rb +41 -0
  113. data/lib/route53/loader/Loader.rb +32 -0
  114. data/lib/route53/manager/Manager.rb +241 -0
  115. data/lib/route53/models/AliasTarget.rb +86 -0
  116. data/lib/route53/models/RecordConfig.rb +178 -0
  117. data/lib/route53/models/RecordDiff.rb +140 -0
  118. data/lib/route53/models/Vpc.rb +24 -0
  119. data/lib/route53/models/ZoneConfig.rb +156 -0
  120. data/lib/route53/models/ZoneDiff.rb +118 -0
  121. data/lib/s3/S3.rb +89 -0
  122. data/lib/s3/loader/Loader.rb +66 -0
  123. data/lib/s3/manager/Manager.rb +296 -0
  124. data/lib/s3/models/BucketConfig.rb +321 -0
  125. data/lib/s3/models/BucketDiff.rb +167 -0
  126. data/lib/s3/models/GrantConfig.rb +189 -0
  127. data/lib/s3/models/GrantDiff.rb +50 -0
  128. data/lib/s3/models/LifecycleConfig.rb +142 -0
  129. data/lib/s3/models/LifecycleDiff.rb +46 -0
  130. data/lib/s3/models/LoggingConfig.rb +81 -0
  131. data/lib/s3/models/NotificationConfig.rb +157 -0
  132. data/lib/s3/models/NotificationDiff.rb +62 -0
  133. data/lib/s3/models/ReplicationConfig.rb +133 -0
  134. data/lib/s3/models/ReplicationDiff.rb +60 -0
  135. data/lib/s3/models/WebsiteConfig.rb +107 -0
  136. data/lib/security/SecurityGroups.rb +39 -0
  137. data/lib/security/loader/Loader.rb +94 -0
  138. data/lib/security/manager/Manager.rb +246 -0
  139. data/lib/security/models/RuleConfig.rb +161 -0
  140. data/lib/security/models/RuleDiff.rb +72 -0
  141. data/lib/security/models/RuleMigration.rb +127 -0
  142. data/lib/security/models/SecurityGroupConfig.rb +172 -0
  143. data/lib/security/models/SecurityGroupDiff.rb +112 -0
  144. data/lib/sns/SNS.rb +40 -0
  145. data/lib/sqs/SQS.rb +62 -0
  146. data/lib/sqs/loader/Loader.rb +34 -0
  147. data/lib/sqs/manager/Manager.rb +128 -0
  148. data/lib/sqs/models/DeadLetterConfig.rb +70 -0
  149. data/lib/sqs/models/DeadLetterDiff.rb +35 -0
  150. data/lib/sqs/models/QueueConfig.rb +115 -0
  151. data/lib/sqs/models/QueueDiff.rb +89 -0
  152. data/lib/util/Colors.rb +111 -0
  153. data/lib/util/StatusCodes.rb +51 -0
  154. data/lib/vpc/loader/Loader.rb +73 -0
  155. data/lib/vpc/manager/Manager.rb +954 -0
  156. data/lib/vpc/models/AclEntryConfig.rb +150 -0
  157. data/lib/vpc/models/AclEntryDiff.rb +54 -0
  158. data/lib/vpc/models/DhcpConfig.rb +100 -0
  159. data/lib/vpc/models/DhcpDiff.rb +90 -0
  160. data/lib/vpc/models/EndpointConfig.rb +76 -0
  161. data/lib/vpc/models/EndpointDiff.rb +69 -0
  162. data/lib/vpc/models/NetworkAclConfig.rb +87 -0
  163. data/lib/vpc/models/NetworkAclDiff.rb +116 -0
  164. data/lib/vpc/models/RouteConfig.rb +82 -0
  165. data/lib/vpc/models/RouteDiff.rb +50 -0
  166. data/lib/vpc/models/RouteTableConfig.rb +92 -0
  167. data/lib/vpc/models/RouteTableDiff.rb +101 -0
  168. data/lib/vpc/models/SubnetConfig.rb +113 -0
  169. data/lib/vpc/models/SubnetDiff.rb +78 -0
  170. data/lib/vpc/models/VpcConfig.rb +173 -0
  171. data/lib/vpc/models/VpcDiff.rb +315 -0
  172. data/rakefile.rb +8 -0
  173. metadata +245 -0
@@ -0,0 +1,239 @@
1
+ require "conf/Configuration"
2
+ require "elb/models/LoadBalancerDiff"
3
+ require "elb/models/ListenerConfig"
4
+ require "elb/models/HealthCheckConfig"
5
+ require "elb/models/AccessLogConfig"
6
+ require "elb/loader/Loader"
7
+ require "elb/ELB"
8
+ require "ec2/EC2"
9
+ require "security/SecurityGroups"
10
+
11
+ require "json"
12
+
13
+ module Cumulus
14
+ module ELB
15
+
16
+ # Public: An object representing configuration for a load balancer
17
+ class LoadBalancerConfig
18
+ attr_reader :name
19
+ attr_reader :listeners
20
+ attr_reader :availability_zones
21
+ attr_reader :subnets
22
+ attr_reader :security_groups
23
+ attr_reader :internal
24
+ attr_reader :tags
25
+ attr_reader :manage_instances
26
+ attr_reader :health_check
27
+ attr_reader :cross_zone
28
+ attr_reader :access_log
29
+ attr_reader :connection_draining
30
+ attr_reader :idle_timeout
31
+ attr_reader :backend_policies
32
+
33
+ require "aws_extensions/elb/BackendServerDescription"
34
+ Aws::ElasticLoadBalancing::Types::BackendServerDescription.send(:include, AwsExtensions::ELB::BackendServerDescription)
35
+
36
+ # Public: Constructor
37
+ #
38
+ # json - a hash containing the JSON configuration for the load balancer
39
+ def initialize(name, json = nil)
40
+ @name = name
41
+ if !json.nil?
42
+
43
+ # load the included listeners and templates
44
+ @listeners = []
45
+ if json["listeners"]
46
+ if json["listeners"]["includes"]
47
+ json["listeners"]["includes"].each do |template_json|
48
+ @listeners << Loader.listener(template_json["template"], template_json["vars"])
49
+ end
50
+ end
51
+ if json["listeners"]["inlines"]
52
+ json["listeners"]["inlines"].each do |inline|
53
+ @listeners << ListenerConfig.new(inline)
54
+ end
55
+ end
56
+ end
57
+
58
+ # Map subnets to their actual subnet description from aws
59
+ @subnets = (json["subnets"] || []).map do |subnet|
60
+ full_subnet = EC2::named_subnets[subnet]
61
+
62
+ if full_subnet.nil?
63
+ raise "#{subnet} is not a valid subnet name or id"
64
+ else
65
+ full_subnet
66
+ end
67
+ end
68
+
69
+ # Map backend policies to the Aws::ElasticLoadBalancing::Types::BackendServerDescription
70
+ # reject any local polices with empty policies array which means it should be deleted from aws
71
+ @backend_policies = (json["backend-policies"] || []).map do |backend|
72
+ Aws::ElasticLoadBalancing::Types::BackendServerDescription.new({
73
+ instance_port: backend["port"],
74
+ policy_names: backend["policies"]
75
+ })
76
+ end.reject { |backend| backend.policy_names.empty? }
77
+
78
+ @security_groups = json["security-groups"] || []
79
+ @internal = json["internal"] || false
80
+ @tags = json["tags"] || {}
81
+ @manage_instances = json["manage-instances"] || false
82
+ @health_check = if json["health-check"] then HealthCheckConfig.new(json["health-check"]) end
83
+ @cross_zone = json["cross-zone"] || false
84
+ @access_log = if json["access-log"] then AccessLogConfig.new(json["access-log"]) else false end
85
+ @connection_draining = json["connection-draining"] || false
86
+ @idle_timeout = json["idle-timeout"]
87
+ end
88
+ end
89
+
90
+ # Public: Returns the vpc id for the load balancer config using the first subnet
91
+ def vpc_id
92
+ first_subnet = @subnets.first
93
+ first_subnet.vpc_id if first_subnet
94
+ end
95
+
96
+ # Public: Get the config as a prettified JSON string.
97
+ #
98
+ # Returns the JSON string
99
+ def pretty_json
100
+ JSON.pretty_generate({
101
+ "listeners" => {
102
+ "includes" => [],
103
+ "inlines" => @listeners.map(&:to_hash)
104
+ },
105
+ "subnets" => @subnets.map { |s| s.name || s.subnet_id },
106
+ "security-groups" => @security_groups,
107
+ "internal" => @internal,
108
+ "tags" => @tags,
109
+ "manage-instances" => @manage_instances,
110
+ "health-check" => @health_check.to_hash,
111
+ "backend-policies" => @backend_policies.map do |backend_policy|
112
+ {
113
+ "port" => backend_policy.instance_port,
114
+ "policies" => backend_policy.policy_names
115
+ }
116
+ end,
117
+ "cross-zone" => @cross_zone,
118
+ "access-log" => if @access_log then @access_log.to_hash else @access_log end,
119
+ "connection-draining" => @connection_draining,
120
+ "idle-timeout" => @idle_timeout,
121
+ })
122
+ end
123
+
124
+ # Public: populates the fields of a LoadBalancerConfig from AWS config
125
+ #
126
+ # aws_elb - the elb
127
+ def populate!(aws_elb, aws_tags, aws_attributes)
128
+ @listeners = aws_elb.listener_descriptions.map do |l|
129
+ config = ListenerConfig.new
130
+ config.populate!(l)
131
+ config
132
+ end
133
+ @subnets = aws_elb.subnets.map { |subnet_id| EC2::id_subnets[subnet_id] }
134
+ @security_groups = aws_elb.security_groups.map do |sg_id|
135
+ SecurityGroups::id_security_groups[sg_id].group_name
136
+ end
137
+ @internal = aws_elb.scheme == "internal"
138
+ @tags = Hash[aws_tags.map do |tag|
139
+ [tag.key, tag.value]
140
+ end]
141
+ @manage_instances = aws_elb.instances.map { |i| i.instance_id }
142
+ @health_check = HealthCheckConfig.new
143
+ @health_check.populate!(aws_elb.health_check)
144
+ @backend_policies = aws_elb.backend_server_descriptions
145
+ @cross_zone = aws_attributes.cross_zone_load_balancing.enabled
146
+ @access_log = AccessLogConfig.new
147
+ @access_log.populate!(aws_attributes.access_log)
148
+ @connection_draining = aws_attributes.connection_draining.enabled && aws_attributes.connection_draining.timeout
149
+ @idle_timeout = aws_attributes.connection_settings.idle_timeout
150
+ end
151
+
152
+ # Public: Produce an array of differences between this local configuration and the
153
+ # configuration in AWS
154
+ #
155
+ # aws - the AWS resource
156
+ #
157
+ # Returns an array of the LoadBalancerDiffs that were found
158
+ def diff(aws)
159
+ diffs = []
160
+
161
+ listener_diff = LoadBalancerDiff.listeners(aws.listener_descriptions, @listeners)
162
+ if listener_diff
163
+ diffs << listener_diff
164
+ end
165
+
166
+ aws_subnets = aws.subnets.map { |subnet_id| EC2::id_subnets[subnet_id] }
167
+ if @subnets.sort != aws_subnets.sort
168
+ diffs << LoadBalancerDiff.subnets(aws_subnets, @subnets)
169
+ end
170
+
171
+ named_aws_security_groups = aws.security_groups.map do |sg_id|
172
+ SecurityGroups::id_security_groups[sg_id].group_name
173
+ end
174
+ if @security_groups.sort != named_aws_security_groups.sort
175
+ diffs << LoadBalancerDiff.security_groups(named_aws_security_groups, @security_groups)
176
+ end
177
+
178
+ aws_internal = (aws.scheme == "internal")
179
+ if @internal != aws_internal
180
+ diffs << LoadBalancerDiff.internal(aws_internal, @internal)
181
+ end
182
+
183
+ aws_tags = Hash[ELB::elb_tags(@name).map { |tag| [tag.key, tag.value] }]
184
+ if @tags != aws_tags
185
+ diffs << LoadBalancerDiff.tags(aws_tags, @tags)
186
+ end
187
+
188
+ aws_instances = (aws.instances || []).map { |i| i.instance_id }
189
+ if (@manage_instances != false) && @manage_instances.sort != aws_instances.sort
190
+ diffs << LoadBalancerDiff.instances(aws_instances, @manage_instances)
191
+ end
192
+
193
+ aws_health_check = aws.health_check
194
+ health_diffs = @health_check.diff(aws_health_check)
195
+ if !health_diffs.empty?
196
+ diffs << LoadBalancerDiff.health_check(health_diffs)
197
+ end
198
+
199
+ aws_backend_policies = aws.backend_server_descriptions
200
+ if @backend_policies.sort != aws_backend_policies.sort
201
+ diffs << LoadBalancerDiff.backend_policies(aws_backend_policies, @backend_policies)
202
+ end
203
+
204
+ aws_attributes = ELB::elb_attributes(@name)
205
+
206
+ aws_cross_zone = (aws_attributes.cross_zone_load_balancing.enabled) rescue false
207
+ if @cross_zone != aws_cross_zone
208
+ diffs << LoadBalancerDiff.new(LoadBalancerChange::CROSS, aws_cross_zone, @cross_zone)
209
+ end
210
+
211
+ aws_access_log = aws_attributes.access_log
212
+ if @access_log == false
213
+ if aws_access_log.enabled == true
214
+ log_diffs = (AccessLogConfig.new).diff(aws_access_log)
215
+ diffs << LoadBalancerDiff.access_log(log_diffs)
216
+ end
217
+ else
218
+ log_diffs = @access_log.diff(aws_access_log)
219
+ if !log_diffs.empty?
220
+ diffs << LoadBalancerDiff.access_log(log_diffs)
221
+ end
222
+ end
223
+
224
+ aws_connection_draining = if aws_attributes.connection_draining.enabled then aws_attributes.connection_draining.timeout else false end
225
+ if @connection_draining != aws_connection_draining
226
+ diffs << LoadBalancerDiff.new(LoadBalancerChange::DRAINING, aws_connection_draining, @connection_draining)
227
+ end
228
+
229
+ aws_idle_timeout = aws_attributes.connection_settings.idle_timeout
230
+ if @idle_timeout != aws_idle_timeout
231
+ diffs << LoadBalancerDiff.new(LoadBalancerChange::IDLE, aws_idle_timeout, @idle_timeout)
232
+ end
233
+
234
+ diffs.flatten
235
+ end
236
+
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,265 @@
1
+ require "common/models/Diff"
2
+ require "common/models/ListChange"
3
+ require "elb/models/ListenerDiff"
4
+ require "util/Colors"
5
+
6
+ module Cumulus
7
+ module ELB
8
+ # Public: The types of changes that can be made to a load balancer
9
+ module LoadBalancerChange
10
+ include Common::DiffChange
11
+
12
+ LISTENERS = Common::DiffChange.next_change_id
13
+ SUBNETS = Common::DiffChange.next_change_id
14
+ SECURITY = Common::DiffChange.next_change_id
15
+ INTERNAL = Common::DiffChange.next_change_id
16
+ TAGS = Common::DiffChange.next_change_id
17
+ INSTANCES = Common::DiffChange.next_change_id
18
+ HEALTH = Common::DiffChange.next_change_id
19
+ BACKEND = Common::DiffChange.next_change_id
20
+ CROSS = Common::DiffChange.next_change_id
21
+ LOG = Common::DiffChange.next_change_id
22
+ DRAINING = Common::DiffChange.next_change_id
23
+ IDLE = Common::DiffChange.next_change_id
24
+ end
25
+
26
+ # Public: Represents a single difference between local configuration and
27
+ # an AWS Load Balancer.
28
+ class LoadBalancerDiff < Common::Diff
29
+ include LoadBalancerChange
30
+
31
+ attr_accessor :listeners
32
+ attr_accessor :subnets
33
+ attr_accessor :security_groups
34
+ attr_accessor :tags
35
+ attr_accessor :instances
36
+ attr_accessor :health_diffs
37
+ attr_accessor :backend_policies
38
+ attr_accessor :log_diffs
39
+
40
+ def self.listeners(aws, local)
41
+ # map listeners to load balancer port
42
+ aws_listeners = Hash[aws.map { |l| [l.listener.load_balancer_port, l] }]
43
+ local_listeners = Hash[local.map { |l| [l.load_balancer_port, l] }]
44
+
45
+ added_listeners = local_listeners.reject { |k, v| aws_listeners.has_key? k }
46
+ removed_listeners = aws_listeners.reject { |k, v| local_listeners.has_key? k }
47
+ modified_listeners = local_listeners.select { |k, v| aws_listeners.has_key? k }
48
+
49
+ added_diffs = Hash[added_listeners.map { |port, added| [port, ListenerDiff.added(added)] }]
50
+ removed_diffs = Hash[removed_listeners.map { |port, removed| [port, ListenerDiff.unmanaged(removed)] }]
51
+ modified_diffs = Hash[modified_listeners.map do |port, modified|
52
+ [port, modified.diff(aws_listeners[port])]
53
+ end].reject { |k, v| v.empty? }
54
+
55
+ if !added_diffs.empty? or !removed_diffs.empty? or !modified_diffs.empty?
56
+ diff = LoadBalancerDiff.new(LISTENERS, aws, local)
57
+ diff.listeners = Common::ListChange.new(added_diffs, removed_diffs, modified_diffs)
58
+ diff
59
+ end
60
+ end
61
+
62
+ def self.subnets(aws, local)
63
+ local_ids = local.map { |s| s.subnet_id }
64
+ aws_ids = aws.map { |s| s.subnet_id }
65
+
66
+ added = local.reject { |s| aws_ids.include? s.subnet_id }
67
+ removed = aws.reject { |s| local_ids.include? s.subnet_id }
68
+ diff = LoadBalancerDiff.new(SUBNETS, aws, local)
69
+ diff.subnets = Common::ListChange.new(added, removed)
70
+ diff
71
+ end
72
+
73
+ def self.security_groups(aws, local)
74
+ added = local - aws
75
+ removed = aws - local
76
+ diff = LoadBalancerDiff.new(SECURITY, aws, local)
77
+ diff.security_groups = Common::ListChange.new(added, removed)
78
+ diff
79
+ end
80
+
81
+ def self.internal(aws, local)
82
+ LoadBalancerDiff.new(INTERNAL, aws, local)
83
+ end
84
+
85
+ TagChange = Struct.new(:key, :aws, :local)
86
+ def self.tags(aws, local)
87
+ added = []
88
+ removed = []
89
+ modified = []
90
+
91
+ aws.each_pair do |key, val|
92
+ if local.has_key?(key)
93
+ if local[key] != val
94
+ modified << TagChange.new(key, val, local[key])
95
+ end
96
+ else
97
+ removed << TagChange.new(key, val, nil)
98
+ end
99
+ end
100
+
101
+ local.each_pair do |key, val|
102
+ if !aws.has_key?(key)
103
+ added << TagChange.new(key, nil, val)
104
+ end
105
+ end
106
+
107
+ diff = LoadBalancerDiff.new(TAGS, aws, local)
108
+ diff.tags = Common::ListChange.new(added, removed, modified)
109
+ diff
110
+ end
111
+
112
+ def self.instances(aws, local)
113
+ added = local - aws
114
+ removed = aws - local
115
+ diff = LoadBalancerDiff.new(INSTANCES, aws, local)
116
+ diff.instances = Common::ListChange.new(added, removed)
117
+ diff
118
+ end
119
+
120
+ def self.health_check(health_diffs)
121
+ diff = LoadBalancerDiff.new(HEALTH, nil, nil)
122
+ diff.health_diffs = health_diffs
123
+ diff
124
+ end
125
+
126
+ BackendChange = Struct.new(:port, :aws_policies, :local_policies)
127
+ def self.backend_policies(aws, local)
128
+ # map the aws and local policies to their ports
129
+ aws_backends = Hash[aws.map { |b| [b.instance_port, b.policy_names] }]
130
+ local_backends = Hash[local.map { |b| [b.instance_port, b.policy_names] }]
131
+
132
+ added = local_backends.reject { |port, _| aws_backends.has_key? port }.map do |port, policies|
133
+ BackendChange.new(port, nil, policies)
134
+ end
135
+ removed = aws_backends.reject { |port, _| local_backends.has_key? port }.map do |port, policies|
136
+ BackendChange.new(port, policies, nil)
137
+ end
138
+ modified = local_backends.reject { |port, _| !aws_backends.has_key? port }.map do |port, policies|
139
+ if aws_backends[port].sort != policies.sort
140
+ BackendChange.new(port, aws_backends[port], policies)
141
+ end
142
+ end.reject(&:nil?)
143
+
144
+ diff = LoadBalancerDiff.new(BACKEND, aws, local)
145
+ diff.backend_policies = Common::ListChange.new(added, removed, modified)
146
+ diff
147
+ end
148
+
149
+ def self.access_log(log_diffs)
150
+ diff = LoadBalancerDiff.new(LOG, nil, nil)
151
+ diff.log_diffs = log_diffs
152
+ diff
153
+ end
154
+
155
+ def asset_type
156
+ "Load Balancer"
157
+ end
158
+
159
+ def aws_name
160
+ @aws.load_balancer_name
161
+ end
162
+
163
+ def diff_string
164
+ case @type
165
+ when LISTENERS
166
+ [
167
+ "listeners:",
168
+ @listeners.removed.map { |_, diff| "\t#{diff}" },
169
+ @listeners.added.map { |_, diff| "\t#{diff}" },
170
+ @listeners.modified.map do |port, diffs|
171
+ [
172
+ "\tListener for port #{port}:",
173
+ diffs.map do |diff|
174
+ diff.to_s.lines.map { |l| "\t\t#{l}".chomp("\n") }
175
+ end
176
+ ].join("\n")
177
+ end
178
+ ].flatten.join("\n")
179
+ when SUBNETS
180
+ [
181
+ "subnets:",
182
+ @subnets.removed.map { |s| Colors.removed("\t#{s.subnet_id} (#{s.name})") },
183
+ @subnets.added.map { |s| Colors.added("\t#{s.subnet_id} (#{s.name})") },
184
+ ].flatten.join("\n")
185
+ when SECURITY
186
+ [
187
+ "security groups:",
188
+ @security_groups.removed.map { |s| Colors.removed("\t#{s}") },
189
+ @security_groups.added.map { |s| Colors.added("\t#{s}") },
190
+ ].flatten.join("\n")
191
+ when INTERNAL
192
+ [
193
+ "internal:",
194
+ Colors.aws_changes("\tAWS - #{aws}"),
195
+ Colors.local_changes("\tLocal - #{local}"),
196
+ ].join("\n")
197
+ when TAGS
198
+ [
199
+ "tags:",
200
+ @tags.removed.map { |t| Colors.removed("\t#{t.key}: #{t.aws}") },
201
+ @tags.added.map { |t| Colors.added("\t#{t.key}: #{t.local}") },
202
+ @tags.modified.map do |t|
203
+ [
204
+ "\t#{t.key}:",
205
+ Colors.aws_changes("(AWS) #{t.aws}"),
206
+ Colors.local_changes("(Local) #{t.local}")
207
+ ].join(" ")
208
+ end
209
+ ].flatten.join("\n")
210
+ when INSTANCES
211
+ [
212
+ "managed instances:",
213
+ @instances.removed.map { |i| Colors.removed("\t#{i}") },
214
+ @instances.added.map { |i| Colors.added("\t#{i}") },
215
+ ].flatten.join("\n")
216
+ when HEALTH
217
+ [
218
+ "health check:",
219
+ @health_diffs.map do |d|
220
+ d.to_s.lines.map { |l| "\t#{l}".chomp("\n") }
221
+ end
222
+ ].join("\n")
223
+ when BACKEND
224
+ [
225
+ "backend policies:",
226
+ @backend_policies.removed.map { |bc| Colors.removed("\tinstance port #{bc.port}: #{bc.aws_policies.join(" ")}") },
227
+ @backend_policies.added.map { |bc| Colors.added("\tinstance port #{bc.port}: #{bc.local_policies.join(" ")}") },
228
+ @backend_policies.modified.map do |bc|
229
+ [
230
+ "\tinstance port #{bc.port}:",
231
+ (bc.aws_policies - bc.local_policies).map { |p| Colors.removed("#{p}") },
232
+ (bc.local_policies - bc.aws_policies).map { |p| Colors.added("#{p}") },
233
+ ].flatten.join(" ")
234
+ end
235
+ ].flatten.join("\n")
236
+ when CROSS
237
+ [
238
+ "cross zone load balancing:",
239
+ Colors.aws_changes("\tAWS - #{aws}"),
240
+ Colors.local_changes("\tLocal - #{local}"),
241
+ ].flatten.join("\n")
242
+ when LOG
243
+ [
244
+ "access log:",
245
+ @log_diffs.map do |d|
246
+ d.to_s.lines.map { |l| "\t#{l}".chomp("\n") }
247
+ end
248
+ ].join("\n")
249
+ when DRAINING
250
+ [
251
+ "connection draining:",
252
+ Colors.aws_changes("\tAWS - #{aws}"),
253
+ Colors.local_changes("\tLocal - #{local}"),
254
+ ].join("\n")
255
+ when IDLE
256
+ [
257
+ "idle timeout:",
258
+ Colors.aws_changes("\tAWS - #{aws}"),
259
+ Colors.local_changes("\tLocal - #{local}"),
260
+ ].join("\n")
261
+ end
262
+ end
263
+ end
264
+ end
265
+ end