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.
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,72 @@
1
+ require "common/models/Diff"
2
+ require "util/Colors"
3
+
4
+ module Cumulus
5
+ module SecurityGroups
6
+ # Public: The types of changes that can be made to security group rules
7
+ module RuleChange
8
+ include Common::DiffChange
9
+
10
+ REMOVED = Common::DiffChange::next_change_id
11
+ end
12
+
13
+ # Public: Represents a single difference between local rule configuration and AWS
14
+ # configuration of security group rules
15
+ class RuleDiff < Common::Diff
16
+ include RuleChange
17
+
18
+ # Public: Static method that will produce a diff that contains an added rule
19
+ #
20
+ # local - the local configuration that was added
21
+ #
22
+ # Returns the diff
23
+ def RuleDiff.added(local)
24
+ RuleDiff.new(ADD, nil, local)
25
+ end
26
+
27
+ # Public: Static method that will produce a diff that contains a removed rule
28
+ #
29
+ # aws - the aws configuration that was removed
30
+ #
31
+ # Returns the diff
32
+ def RuleDiff.removed(aws)
33
+ RuleDiff.new(REMOVED, aws)
34
+ end
35
+
36
+ def to_s
37
+ case @type
38
+ when ADD
39
+ Colors.added("#{to_readable(local)}")
40
+ when REMOVED
41
+ Colors.removed("#{to_readable(aws)}")
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ # Internal: Produce a human readable string from a config hash
48
+ #
49
+ # config - the config to process
50
+ #
51
+ # Returns the human readable string
52
+ def to_readable(config)
53
+ # yes, for real, AWS returns the STRING "-1" if all protocols are allowed
54
+ protocol = if config.protocol == "-1" then "All" else config.protocol end
55
+ allowed = (config.security_groups + config.subnets).join(", ")
56
+
57
+ temp = "Allowed: #{allowed}, Protocol: #{protocol}, "
58
+ if protocol.downcase == "icmp"
59
+ temp << "Type: #{config.from}, Code: #{config.to}"
60
+ elsif config.from != config.to
61
+ temp << "Ports: #{config.from}-#{config.to}"
62
+ elsif config.from.nil?
63
+ temp << "Ports: All"
64
+ else
65
+ temp << "Port: #{config.from}"
66
+ end
67
+ temp
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,127 @@
1
+ module Cumulus
2
+ module SecurityGroups
3
+ # A class used to migrate RuleConfigs
4
+ class RuleMigration
5
+
6
+ attr_reader :ports
7
+ attr_reader :icmp_type
8
+ attr_reader :icmp_code
9
+ attr_reader :protocol
10
+ attr_reader :security_groups
11
+ attr_reader :subnets
12
+
13
+ # Public: Static method that will produce a RuleMigration from a RuleConfig
14
+ #
15
+ # rule_config - the RuleConfig to create from
16
+ #
17
+ # Returns the corresponding RuleMigration
18
+ def self.from_rule_config(rule_config)
19
+ ports = if (rule_config.from.nil? and rule_config.to.nil?) or rule_config.protocol == "icmp"
20
+ nil
21
+ else
22
+ if rule_config.from == rule_config.to
23
+ [rule_config.from]
24
+ else
25
+ ["#{rule_config.from}-#{rule_config.to}"]
26
+ end
27
+ end
28
+
29
+ icmp_type = if rule_config.protocol == "icmp" then rule_config.from end
30
+ icmp_code = if rule_config.protocol == "icmp" then rule_config.to end
31
+
32
+ # we're gonna replace any "0.0.0.0/0" with all to educate users on subnets.json
33
+ subnets = rule_config.subnets.map do |subnet|
34
+ if subnet == "0.0.0.0/0"
35
+ "all"
36
+ else
37
+ subnet
38
+ end
39
+ end
40
+
41
+ RuleMigration.new(
42
+ ports,
43
+ rule_config.protocol,
44
+ icmp_type,
45
+ icmp_code,
46
+ rule_config.security_groups,
47
+ subnets
48
+ )
49
+ end
50
+
51
+ # Public: Constructor.
52
+ #
53
+ # ports - an array of the ports to put into cumulus config, or nil for all
54
+ # protocol - the protocol for the rule
55
+ # icmp_type - if protocol is icmp, the icmp type
56
+ # icmp_code - if protocol is icmp, the icmp code
57
+ # security_groups - an array of security group names for the rule, or nil if there are no security groups
58
+ # subnets - an array of subnets to include in the rule, or nil if there are no subnets
59
+ def initialize(ports, protocol, icmp_type, icmp_code, security_groups, subnets)
60
+ @ports = ports
61
+ @protocol = protocol
62
+ @icmp_type = icmp_type
63
+ @icmp_code = icmp_code
64
+ @security_groups = security_groups
65
+ @subnets = subnets
66
+ end
67
+
68
+ # Public: Get the configuration as a hash for migration
69
+ #
70
+ # Returns the hash
71
+ def hash
72
+ {
73
+ "security-groups" => @security_groups,
74
+ "protocol" => @protocol,
75
+ "ports" => @ports,
76
+ "icmp-type" => @icmp_type,
77
+ "icmp-code" => @icmp_code,
78
+ "subnets" => @subnets,
79
+ }.reject { |k, v| v.nil? }
80
+ end
81
+
82
+ # Public: Combine two RuleMigrations by combining allowed entities (security group or subnet).
83
+ #
84
+ # other - the other RuleMigration to combine with this one
85
+ #
86
+ # Returns the a new RuleMigration with this RuleMigration's ports and protocol, and
87
+ # the allowed entities of both RuleMigrations concatenated together
88
+ def combine_allowed(other)
89
+ RuleMigration.new(
90
+ @ports,
91
+ @protocol,
92
+ @icmp_type,
93
+ @icmp_code,
94
+ @security_groups + other.security_groups,
95
+ @subnets + other.subnets
96
+ )
97
+ end
98
+
99
+ # Public: Combine two RuleMigrations by combining ports. If both of the RuleMigrations
100
+ # have nil ports, they will be combined, but if only one does, an array containing
101
+ # both RuleMigrations (unchanged) will be returned
102
+ #
103
+ # other - the other RuleMigration to combine with this one
104
+ #
105
+ # Returns a new RuleMigration with this RuleMigration's allowed entities and the combined port
106
+ # or an array of the two original RuleMigrations
107
+ def combine_ports(other)
108
+ # In this case, they should be identical, we just return self
109
+ if !@ports and !other.ports
110
+ self
111
+ # at this point we're guaranteed that if one of the ports is nil, the other is not
112
+ elsif @ports.nil? or other.ports.nil?
113
+ [self, other]
114
+ else
115
+ RuleMigration.new(
116
+ @ports + other.ports,
117
+ @protocol,
118
+ @icmp_type,
119
+ @icmp_code,
120
+ @security_groups,
121
+ @subnets
122
+ )
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,172 @@
1
+ require "conf/Configuration"
2
+ require "security/loader/Loader"
3
+ require "security/models/RuleConfig"
4
+ require "security/models/RuleDiff"
5
+ require "security/models/RuleMigration"
6
+ require "security/models/SecurityGroupDiff"
7
+
8
+ require "json"
9
+
10
+ module Cumulus
11
+ module SecurityGroups
12
+ # Public: An object representing configuration for a security group
13
+ class SecurityGroupConfig
14
+
15
+ attr_reader :description
16
+ attr_reader :includes
17
+ attr_reader :inbound
18
+ attr_reader :name
19
+ attr_reader :outbound
20
+ attr_reader :tags
21
+ attr_reader :vpc_id
22
+
23
+ # Public: Constructor.
24
+ #
25
+ # name - the name of the security group
26
+ # vpc_id - the id of the vpc the security group belongs in
27
+ # json - a hash containing the JSON configuration for the security group
28
+ def initialize(name, vpc_id, json = nil)
29
+ @name = name
30
+ @vpc_id = vpc_id
31
+ if !json.nil?
32
+ @description = if !json["description"].nil? then json["description"] else "" end
33
+ @tags = if !json["tags"].nil? then json["tags"] else {} end
34
+
35
+
36
+ includes = (json["rules"]["includes"] || []).map { |rule| Loader.rule(rule) }
37
+ inbound_includes = includes.reduce([]) { |sofar, inc| sofar + (inc["inbound"] || []) }.flatten.compact
38
+ outbound_includes = includes.reduce([]) { |sofar, inc| sofar + (inc["outbound"] || []) }.flatten.compact
39
+
40
+ combined_inbound = (json["rules"]["inbound"] || []) + inbound_includes
41
+ @inbound = combined_inbound.map(&RuleConfig.method(:expand_ports)).flatten
42
+
43
+ combined_outbound = (json["rules"]["outbound"] || []) + outbound_includes
44
+ @outbound = if !json["rules"]["outbound"].nil?
45
+ combined_outbound.map(&RuleConfig.method(:expand_ports)).flatten
46
+ else
47
+ if Configuration.instance.security.outbound_default_all_allowed
48
+ [RuleConfig.allow_all]
49
+ else
50
+ outbound_includes
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ # Public: Produce an array of the differences between this local configuration and the
57
+ # configuration in AWS
58
+ #
59
+ # aws - the aws resource
60
+ #
61
+ # Returns an array of the SecurityGroupDiffs that were found
62
+ def diff(aws)
63
+ diffs = []
64
+
65
+ if @description != aws.description
66
+ diffs << SecurityGroupDiff.new(SecurityGroupChange::DESCRIPTION, aws, self)
67
+ end
68
+
69
+ if @tags != Hash[aws.tags.map { |t| [t.key, t.value] }]
70
+ diffs << SecurityGroupDiff.new(SecurityGroupChange::TAGS, aws, self)
71
+ end
72
+
73
+ inbound_diffs = diff_rules(@inbound, aws.ip_permissions)
74
+ if !inbound_diffs.empty?
75
+ diffs << SecurityGroupDiff.inbound(aws, self, inbound_diffs)
76
+ end
77
+
78
+ outbound_diffs = diff_rules(@outbound, aws.ip_permissions_egress)
79
+ if !outbound_diffs.empty?
80
+ diffs << SecurityGroupDiff.outbound(aws, self, outbound_diffs)
81
+ end
82
+
83
+ diffs
84
+ end
85
+
86
+ # Public: Populate this SecurityGroupConfig from an AWS resource
87
+ #
88
+ # aws - the aws resource
89
+ def populate!(aws)
90
+ @vpc_id = aws.vpc_id
91
+ @description = aws.description
92
+ @tags = Hash[aws.tags.map { |t| [t.key, t.value] }]
93
+ @inbound = combine_rules(aws.ip_permissions.map { |rule| RuleConfig.from_aws(rule) })
94
+ @outbound = combine_rules(aws.ip_permissions_egress.map { |rule| RuleConfig.from_aws(rule) })
95
+ end
96
+
97
+ # Public: Get the config as a prettified JSON string.
98
+ #
99
+ # Returns the JSON string
100
+ def pretty_json
101
+ JSON.pretty_generate({
102
+ "description" => @description,
103
+ "tags" => @tags,
104
+ "rules" => {
105
+ "inbound" => @inbound.map(&:hash),
106
+ "outbound" => @outbound.map(&:hash),
107
+ }
108
+ }.reject { |k, v| v.nil? })
109
+ end
110
+
111
+ private
112
+
113
+ # Internal: Determine changes in rules
114
+ #
115
+ # local_rules - the rules defined locally
116
+ # aws_rules - the rules in AWS
117
+ #
118
+ # Returns an array of RuleDiffs that represent differences between local and AWS configuration
119
+ def diff_rules(local_rules, aws_rules)
120
+ diffs = []
121
+
122
+ # get the aws config into a format that mirrors cumulus so we can compare
123
+ aws = aws_rules.map do |rule|
124
+ RuleConfig.from_aws(rule)
125
+ end
126
+ aws_hashes = aws.flat_map(&:hash)
127
+ local_hashes = local_rules.flat_map(&:hash)
128
+
129
+ diffs << local_hashes.reject { |i| aws_hashes.include?(i) }.map { |l| RuleDiff.added(RuleConfig.new(l)) }
130
+ diffs << aws_hashes.reject { |a| local_hashes.include?(a) }.map { |a| RuleDiff.removed(RuleConfig.new(a)) }
131
+
132
+ diffs.flatten
133
+ end
134
+
135
+ # Internal: Combine rules that have the same ports and security groups to create the compact version
136
+ # used by cumulus config.
137
+ #
138
+ # rules - an array of the rules to combine
139
+ #
140
+ # Returns an array of compact rules
141
+ def combine_rules(rules)
142
+ # separate out icmp rules
143
+ all_rules = rules.map(&RuleMigration.method(:from_rule_config))
144
+ icmp_rules = all_rules.select { |rule| rule.protocol == "icmp" }
145
+
146
+ # first we find the ones that have the same protocol and port
147
+ other_rules = all_rules.reject { |rule| rule.protocol == "icmp" }.group_by do |rule|
148
+ [rule.protocol, rule.ports]
149
+ # next, we combine the matching rules together
150
+ end.flat_map do |_, matches|
151
+ if matches.size == 1
152
+ matches
153
+ else
154
+ matches[1..-1].inject(matches[0]) { |prev, cur| prev.combine_allowed(cur) }
155
+ end
156
+ # now, try to find ones that have the same groups of allowed entities and protocol
157
+ end.group_by do |rule|
158
+ [rule.protocol, rule.security_groups, rule.subnets]
159
+ # finally, we'll combine ports for the matches
160
+ end.flat_map do |_, matches|
161
+ if matches.size == 1
162
+ matches
163
+ else
164
+ matches[1..-1].inject(matches[0]) { |prev, cur| prev.combine_ports(cur) }
165
+ end
166
+ end
167
+
168
+ icmp_rules + other_rules
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,112 @@
1
+ require "common/models/Diff"
2
+ require "common/models/TagsDiff"
3
+ require "security/models/RuleDiff"
4
+ require "util/Colors"
5
+
6
+ module Cumulus
7
+ module SecurityGroups
8
+ # Public: The types of changes that can be made to security groups
9
+ module SecurityGroupChange
10
+ include Common::DiffChange
11
+
12
+ DESCRIPTION = Common::DiffChange::next_change_id
13
+ TAGS = Common::DiffChange::next_change_id
14
+ INBOUND = Common::DiffChange::next_change_id
15
+ OUTBOUND = Common::DiffChange::next_change_id
16
+ end
17
+
18
+ # Public: Represents a single difference between local configuration and AWS configuration
19
+ # of security groups
20
+ class SecurityGroupDiff < Common::Diff
21
+ include SecurityGroupChange
22
+ include Common::TagsDiff
23
+
24
+ attr_accessor :inbound_diffs
25
+ attr_accessor :outbound_diffs
26
+
27
+ # Public: Static method that will produce a diff that contains changes in inbound rules
28
+ #
29
+ # aws - the aws configuration
30
+ # local - the local configuration
31
+ # inbound_diffs - the differences in inbound rules
32
+ #
33
+ # Returns the diff
34
+ def SecurityGroupDiff.inbound(aws, local, inbound_diffs)
35
+ diff = SecurityGroupDiff.new(INBOUND, aws, local)
36
+ diff.inbound_diffs = inbound_diffs
37
+ diff
38
+ end
39
+
40
+ # Public: Static method that will produce a diff that contains changes in outbound rules
41
+ #
42
+ # aws - the aws configuration
43
+ # local - the local configuration
44
+ # outbound_diffs - the differences in outbound rules
45
+ #
46
+ # Returns the diff
47
+ def SecurityGroupDiff.outbound(aws, local, outbound_diffs)
48
+ diff = SecurityGroupDiff.new(OUTBOUND, aws, local)
49
+ diff.outbound_diffs = outbound_diffs
50
+ diff
51
+ end
52
+
53
+ def asset_type
54
+ "Security group"
55
+ end
56
+
57
+ def aws_name
58
+ @aws.vpc_group_name
59
+ end
60
+
61
+ def diff_string
62
+ case @type
63
+ when DESCRIPTION
64
+ [
65
+ "Description:",
66
+ Colors.aws_changes("\tAWS - #{@aws.description}"),
67
+ Colors.local_changes("\tLocal - #{@local.description}"),
68
+ "\tUnfortunately, AWS's SDK does not allow updating the description."
69
+ ].join("\n")
70
+ when INBOUND
71
+ lines = ["Inbound rules:"]
72
+ lines << inbound_diffs.map { |d| "\t#{d}" }
73
+ lines.flatten.join("\n")
74
+ when OUTBOUND
75
+ lines = ["Outbound rules:"]
76
+ lines << outbound_diffs.map { |d| "\t#{d}" }
77
+ lines.flatten.join("\n")
78
+ when TAGS
79
+ tags_diff_string
80
+ end
81
+ end
82
+
83
+ # Public: Get the inbound rules to add
84
+ #
85
+ # Returns the added rules
86
+ def added_inbounds
87
+ inbound_diffs.reject { |i| i.type == RuleChange::REMOVED }.map(&:local)
88
+ end
89
+
90
+ # Public: Get the inbound rules to remove
91
+ #
92
+ # Returns the removed rules
93
+ def removed_inbounds
94
+ inbound_diffs.reject { |i| i.type == RuleChange::ADD }.map(&:aws)
95
+ end
96
+
97
+ # Public: Get the outbound rules to add
98
+ #
99
+ # Returns the added rules
100
+ def added_outbounds
101
+ outbound_diffs.reject { |o| o.type == RuleChange::REMOVED }.map(&:local)
102
+ end
103
+
104
+ # Public: Get the outbound rules to remove
105
+ #
106
+ # Returns the removed rules
107
+ def removed_outbounds
108
+ outbound_diffs.reject { |o| o.type == RuleChange::ADD }.map(&:aws)
109
+ end
110
+ end
111
+ end
112
+ end