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,80 @@
1
+ require "json"
2
+
3
+ module Cumulus
4
+ module Common
5
+ # Public: A module that handles loading all the 4 configuration files and
6
+ # creating objects from them.
7
+ module BaseLoader
8
+ # Internal: Load the resources in a directory, handling each file with the
9
+ # function passed in.
10
+ #
11
+ # dir - the directory to load resources from
12
+ # json - indicates if the resources are in json format
13
+ # individual_loader - the function that loads a resource from each file name
14
+ #
15
+ # Returns an array of resources
16
+ def self.resources(dir, json = true, &individual_loader)
17
+ Dir.entries(dir)
18
+ .reject { |f| f == "." or f == ".." or File.directory?(File.join(dir, f)) }
19
+ .map { |f| resource(f, dir, json, &individual_loader) }.reject(&:nil?)
20
+ end
21
+
22
+ # Internal: Load the resource, passing the parsed JSON to the function passed
23
+ # in
24
+ #
25
+ # file - the name of the file to load
26
+ # dir - the directory the file is located in
27
+ # json - indicates if the resources are in json format
28
+ # loader - the function that will handle the read json
29
+ def self.resource(file, dir, json = true, &loader)
30
+ name = file.end_with?(".json") ? file[0...-5] : file
31
+
32
+ begin
33
+ contents = load_file(file, dir)
34
+ loader.call(
35
+ name,
36
+ if json then JSON.parse(contents) else contents end
37
+ )
38
+ rescue => e
39
+ puts "Unable to load resource #{file}: #{e}"
40
+ nil
41
+ end
42
+ end
43
+
44
+ # Internal: Load the template, apply variables, and pass the parsed JSON to
45
+ # the function passed in
46
+ #
47
+ # file - the name of the file to load
48
+ # dir - the directory the file is located in
49
+ # vars - the variables to apply to the template
50
+ # loader - the function that will handle the read json
51
+ def self.template(file, dir, vars, &loader)
52
+ template = load_file(file, dir)
53
+ vars.each do |key, value|
54
+ template.gsub!("{{#{key}}}", "#{value}")
55
+ end
56
+ json = JSON.parse(template)
57
+
58
+ loader.call(nil, json)
59
+ end
60
+
61
+ # Internal: Load a file. Will check if a file exists by the name passed in, or
62
+ # with a .json extension.
63
+ #
64
+ # file - the name of the file to load
65
+ # dir - the directory the file is located in
66
+ #
67
+ # Returns the contents of the file
68
+ def self.load_file(file, dir)
69
+ path = File.join(dir, file)
70
+ if File.exist?(path)
71
+ File.read(path)
72
+ elsif File.exist?("#{path}.json")
73
+ File.read("#{path}.json")
74
+ else
75
+ throw "File does not exist: #{path}"
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,148 @@
1
+ require "common/models/Diff"
2
+ require "util/Colors"
3
+ require "util/StatusCodes"
4
+
5
+ module Cumulus
6
+ module Common
7
+ # Public: Base class for AWS resource manager classes.
8
+ #
9
+ # Classes that extend this class should provide the following methods:
10
+ #
11
+ # resource_name - return the resource name type (ie "Autoscaling Group", "Security Group", etc)
12
+ # local_resources - return a Hash of local resource name to local resource config object
13
+ # aws_resources - return a Hash of aws resource name to aws resource object
14
+ # diff_resource - a function that will produce an array of differences between the local resource
15
+ # passed in and the aws resource passed in
16
+ # unmanaged_diff - return the correct type of diff from an AWS resource
17
+ # added_diff - return the correct type of diff from a local configuration object
18
+ # create - given a local configuration, create the AWS resource
19
+ # update - given a local configuration and an array of diffs, update the AWS resource
20
+ #
21
+ # Additionally, the following instance variables can be set to change the behavior of the manager:
22
+ #
23
+ # create_asset - if true, the asset will be created, if false, a warning will be printed about
24
+ # the asset not being created
25
+ class Manager
26
+ def initialize
27
+ @migration_root = "generated"
28
+ @create_asset = true
29
+ end
30
+
31
+ # Public: Print a diff between local configuration and configuration in AWS
32
+ def diff
33
+ each_difference(local_resources, true) { |key, diffs| print_difference(key, diffs) }
34
+ end
35
+
36
+ # Public: Print the diff between local configuration and AWS for a single resource
37
+ #
38
+ # name - the name of the resource to diff
39
+ def diff_one(name)
40
+ each_difference(filter_local(name), false) { |key, diffs| print_difference(key, diffs) }
41
+ end
42
+
43
+ # Public: Print out the names of all resources managed by Cumulus
44
+ def list
45
+ puts local_resources.map { |key, l| l.name }.join(" ")
46
+ end
47
+
48
+ # Public: Sync local configuration to AWS
49
+ def sync
50
+ each_difference(local_resources, true) { |key, diffs| sync_difference(key, diffs) }
51
+ end
52
+
53
+ # Public: Sync local configuration to AWS for a single resource
54
+ #
55
+ # name - the name of the resource to sync
56
+ def sync_one(name)
57
+ each_difference(filter_local(name), false) { |key, diffs| sync_difference(key, diffs) }
58
+ end
59
+
60
+ # Public: Select local resources based on name
61
+ def filter_local(name)
62
+ local_resources.reject { |key, l| l.name != name }
63
+ end
64
+
65
+ private
66
+
67
+ # Internal: Loop through the differences between local configuration and AWS
68
+ #
69
+ # locals - the local configurations to compare against
70
+ # include_unmanaged - whether to include unmanaged resources in the list of changes
71
+ # f - a function that will be passed the name of the resource and an array of
72
+ # diffs
73
+ def each_difference(locals, include_unmanaged, &f)
74
+
75
+ unmanaged = if include_unmanaged
76
+ Hash[aws_resources.map do |key, resource|
77
+ [key, [unmanaged_diff(resource)]] if !locals.include?(key)
78
+ end.compact]
79
+ else
80
+ {}
81
+ end
82
+
83
+ managed = Hash[locals.map do |key, resource|
84
+ if !aws_resources.include?(key)
85
+ [key, [added_diff(resource)]]
86
+ else
87
+ [key, diff_resource(resource, aws_resources[key])]
88
+ end
89
+ end]
90
+
91
+ combined = unmanaged.merge(managed)
92
+ sorted_keys = combined.keys.sort
93
+ sorted_keys.each do |key|
94
+ f.call(key, combined[key])
95
+ end
96
+ end
97
+
98
+ # Internal: Print differences.
99
+ #
100
+ # key - the name of the resource to print
101
+ # diffs - the differences between local configuration and AWS
102
+ def print_difference(key, diffs)
103
+ if diffs.size > 0
104
+
105
+ if diffs.reject(&:info_only).size > 0
106
+ StatusCodes::set_status(StatusCodes::DIFFS)
107
+ end
108
+
109
+ if diffs.size == 1 and (diffs[0].type == DiffChange::ADD or
110
+ diffs[0].type == DiffChange::UNMANAGED)
111
+ puts diffs[0]
112
+ else
113
+ puts "#{resource_name} #{local_resources[key].name} has the following changes:"
114
+ diffs.each do |diff|
115
+ diff_string = diff.to_s.lines.map { |s| "\t#{s}" }.join
116
+ puts diff_string
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ # Internal: Sync differences.
123
+ #
124
+ # key - the name of the resource to sync
125
+ # diffs - the differences between local configuration and AWS
126
+ def sync_difference(key, diffs)
127
+ if diffs.size > 0
128
+
129
+ StatusCodes::set_status(StatusCodes::SYNC_DIFFS)
130
+
131
+ if diffs[0].type == DiffChange::UNMANAGED
132
+ puts diffs[0]
133
+ elsif diffs[0].type == DiffChange::ADD
134
+ if @create_asset
135
+ puts Colors.added("creating #{local_resources[key].name}...")
136
+ create(local_resources[key])
137
+ else
138
+ puts "not creating #{local_resources[key].name}..."
139
+ end
140
+ else
141
+ puts Colors.blue("updating #{local_resources[key].name}...")
142
+ update(local_resources[key], diffs)
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,114 @@
1
+ require "util/Colors"
2
+
3
+ module Cumulus
4
+ module Common
5
+ # Public: The types of changes common to all Diffs
6
+ module DiffChange
7
+ @@current = 0
8
+
9
+ # Public: Produce the next id for a change type. Use this to avoid id
10
+ # collisions.
11
+ #
12
+ # Returns the new id
13
+ def self.next_change_id
14
+ @@current += 1
15
+ @@current
16
+ end
17
+
18
+ ADD = next_change_id
19
+ UNMANAGED = next_change_id
20
+ MODIFIED = next_change_id
21
+ end
22
+
23
+ # Public: The base class for all Diff classes.
24
+ #
25
+ # To extend this class, do the following:
26
+ #
27
+ # 1. Provide a `diff_string` method. This method will be called if the default
28
+ # to_s method cannot produce a result.
29
+ # 2. Provide a `asset_type` method. This method should return the string type of
30
+ # asset for which this is a diff.
31
+ # 3. Provide an `aws_name` method. This method should give back the string name
32
+ # of the aws asset.
33
+ # 4. (Optional) Replace the existing `local_name` method. This method produces the string name
34
+ # of the local asset. Defaults to `name` on the local asset.
35
+ class Diff
36
+ include DiffChange
37
+
38
+ attr_reader :aws, :local, :type
39
+ attr_accessor :changes, :info_only
40
+
41
+ # Public: Static method that will produce an "unmanaged" diff
42
+ #
43
+ # aws - the aws resource that is unmanaged
44
+ #
45
+ # Returns the diff
46
+ def self.unmanaged(aws)
47
+ self.new(UNMANAGED, aws)
48
+ end
49
+
50
+ # Public: Static method that will produce an "added" diff
51
+ #
52
+ # local - the local configuration that is added
53
+ #
54
+ # Returns the diff
55
+ def self.added(local)
56
+ self.new(ADD, nil, local)
57
+ end
58
+
59
+ # Public: Static method that will produce a "modified" diff
60
+ #
61
+ # local - the local configuration
62
+ # aws - the aws resource
63
+ # changes - an object describing what was modified
64
+ def self.modified(aws, local, changes)
65
+ self.new(MODIFIED, aws, local, changes)
66
+ end
67
+
68
+ # Public: Constructor
69
+ #
70
+ # type - the type of the difference
71
+ # aws - the aws resource that's different (defaults to nil)
72
+ # local - the local resource that's difference (defaults to nil)
73
+ # changes - an object to describe what changed in a MODIFIED diff (defaults to nil)
74
+ def initialize(type, aws = nil, local = nil, changes = nil)
75
+ @aws = aws
76
+ @local = local
77
+ @type = type
78
+ @changes = changes
79
+ @info_only = false
80
+ end
81
+
82
+ def to_s
83
+ case @type
84
+ when ADD
85
+ Colors.added("#{asset_type} #{local_name} #{add_string}")
86
+ when UNMANAGED
87
+ Colors.unmanaged("#{asset_type} #{aws_name} #{unmanaged_string}")
88
+ else
89
+ diff_string
90
+ end
91
+ end
92
+
93
+ # Public: A method that produces the string that describes what will be done with new assets.
94
+ # This can be overridden for the case that the ADD case doesn't create the asset.
95
+ #
96
+ # Returns the string describing the action that will be taken.
97
+ def add_string
98
+ "will be created."
99
+ end
100
+
101
+ # Public: A method that produces the string that describes what will be done with unmanaged
102
+ # assets. This can be overriden for the case that the UNMANAGED case does not ignore the asset.
103
+ #
104
+ # Returns the string describing the action that will be taken
105
+ def unmanaged_string
106
+ "is not managed by Cumulus."
107
+ end
108
+
109
+ def local_name
110
+ @local.name
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,21 @@
1
+ module Cumulus
2
+ module Common
3
+ ListChange = Struct.new(:added, :removed, :modified) do
4
+ # Public: Creates a ListChange from aws and local arrays with simple types
5
+ # where the ListChange only has added and removed
6
+ def self.simple_list_diff(aws, local)
7
+ added = local - aws
8
+ removed = aws - local
9
+
10
+ if !added.empty? or !removed.empty?
11
+ ListChange.new(added, removed, nil)
12
+ end
13
+ end
14
+
15
+ # Public: Returns true if all of added, removed, and modified are either nil or empty
16
+ def empty?
17
+ (self.added.nil? or self.added.empty?) and (self.removed.nil? or self.removed.empty?) and (self.modified.nil? or self.modified.empty?)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,55 @@
1
+ module Cumulus
2
+ module Common
3
+ # Public: A module to be mixed in to Diff classes that have tags
4
+ module TagsDiff
5
+ # Public: Get the diff string for tag differences
6
+ #
7
+ # Returns the string to display
8
+ def tags_diff_string
9
+ lines = ["Tags:"]
10
+ lines << tags_to_remove.map { |k, v| "\t#{Colors.removed("#{k} => #{v}")}" }
11
+ lines << tags_to_add.map { |k, v| "\t#{Colors.added("#{k} => #{v}")}" }
12
+ lines.flatten.join("\n")
13
+ end
14
+
15
+ # Public: Get the tags that are in AWS that are not in local configuration
16
+ #
17
+ # Returns a hash of tags
18
+ def tags_to_remove
19
+ aws_tags.reject { |t, v| local_tags.include?(t) and local_tags[t] == v }
20
+ end
21
+
22
+ # Public: Get the tags that are in local configuration but not in AWS
23
+ #
24
+ # Returns a hash of tags
25
+ def tags_to_add
26
+ local_tags.reject { |t, v| aws_tags.include?(t) and aws_tags[t] == v }
27
+ end
28
+
29
+ private
30
+
31
+ # Internal: Override this method if the tags are not found on the tags attribute
32
+ # of the local object
33
+ #
34
+ # Returns the tags
35
+ def local_tags
36
+ @local.tags
37
+ end
38
+
39
+ # Internal: Get the tags in AWS as a hash of key to value
40
+ #
41
+ # Returns a hash of tags
42
+ def aws_tags
43
+ @aws_tags ||= Hash[aws_tags_list.map { |tag| [tag.key, tag.value] }]
44
+ end
45
+
46
+ # Internal: Override this method if tags are not found on the tags attribute of
47
+ # the aws object.
48
+ #
49
+ # Returns the tags
50
+ def aws_tags_list
51
+ @aws.tags
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,17 @@
1
+ module Cumulus
2
+ module Common
3
+ class UTCTimeSource
4
+
5
+ # Make now always return now in UTC
6
+ def now
7
+ Time.now.utc
8
+ end
9
+
10
+ # Make local always use utc time
11
+ def local(*args)
12
+ Time.utc(*args)
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,365 @@
1
+ require "json"
2
+ require "aws-sdk"
3
+
4
+ module Cumulus
5
+ # Public: A module that contains helper methods for the configuration classes.
6
+ #
7
+ # When mixing in this module, make sure your class has a @node instance variable
8
+ # for what node in the json it expect to get config from, ie. "s3" or "iam"
9
+ module Config
10
+ @@json = nil
11
+ @@conf_dir = nil
12
+
13
+ class << self
14
+ def json
15
+ @@json
16
+ end
17
+
18
+ def json=(value)
19
+ @@json = value
20
+ end
21
+
22
+ def conf_dir
23
+ @@conf_dir
24
+ end
25
+
26
+ def conf_dir=(value)
27
+ @@conf_dir = value
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ # Internal: Take a path relative to the project root and turn it into an
34
+ # absolute path
35
+ #
36
+ # relative_path - The String path from `conf_dir` to the desired file
37
+ #
38
+ # Returns the absolute path as a String
39
+ def absolute_path(relative_path)
40
+ if relative_path.start_with?("/")
41
+ relative_path
42
+ else
43
+ File.join(@@conf_dir, relative_path)
44
+ end
45
+ end
46
+
47
+ # Internal: Handle any KeyErrors that occur while getting a configuration value
48
+ # by printing out a message describing the missing key and exiting.
49
+ #
50
+ # key - the full key to get ex. `s3.buckets.directory`
51
+ # allow_missing - if true we will return nil for missing values instead of exiting
52
+ # handler - a block that will do additional processing on the key. If nil,
53
+ # the value is returned as is.
54
+ #
55
+ # Returns the configuration value if successful
56
+ def conf(key, allow_missing = false, &handler)
57
+ value = nil
58
+ key.split(".").each do |part|
59
+ if value
60
+ value = value.fetch(part)
61
+ else
62
+ value = @@json.fetch(part)
63
+ end
64
+ end
65
+
66
+ if handler
67
+ handler.call(value)
68
+ else
69
+ value
70
+ end
71
+ rescue KeyError => e
72
+ puts "Your configuration file is missing $.#{key}."
73
+ if allow_missing
74
+ nil
75
+ else
76
+ exit
77
+ end
78
+ end
79
+
80
+ end
81
+
82
+ # Public: Contains the configuration values set in the configuration.json file.
83
+ # Provides a Singleton that can be accessed throughout the application.
84
+ class Configuration
85
+ include Config
86
+
87
+ attr_reader :colors_enabled
88
+ attr_reader :iam, :autoscaling, :route53, :s3, :security, :cloudfront, :elb, :vpc, :kinesis, :sqs, :ec2
89
+ attr_reader :client
90
+
91
+ # Internal: Constructor. Sets up the `instance` variable, which is the access
92
+ # point for the Singleton.
93
+ #
94
+ # conf_dir - The String path to the directory the configuration can be found in
95
+ # profile - The String profile name that will be used to make AWS API calls
96
+ # assume_role - The ARN of the role to assume when making AWS API calls
97
+ # autoscaling_force_size
98
+ # - Determines whether autoscaling should use configured values for
99
+ # min/max/desired group size
100
+ def initialize(conf_dir, profile, assume_role, autoscaling_force_size)
101
+ Config.conf_dir = conf_dir;
102
+ Config.json = JSON.parse(File.read(absolute_path("configuration.json")))
103
+ @colors_enabled = conf "colors-enabled"
104
+ @iam = IamConfig.new
105
+ @autoscaling = AutoScalingConfig.new(autoscaling_force_size)
106
+ @route53 = Route53Config.new
107
+ @security = SecurityConfig.new
108
+ @cloudfront = CloudFrontConfig.new
109
+ @s3 = S3Config.new
110
+ @elb = ELBConfig.new
111
+ @vpc = VpcConfig.new
112
+ @kinesis = KinesisConfig.new
113
+ @sqs = SQSConfig.new
114
+ @ec2 = EC2Config.new
115
+
116
+ region = conf "region"
117
+ credentials = if assume_role
118
+ Aws::AssumeRoleCredentials.new(
119
+ client: Aws::STS::Client.new(profile: profile, region: region),
120
+ role_arn: assume_role,
121
+ role_session_name: "#{region}-#{@profile}"
122
+ )
123
+ end
124
+
125
+ @client = {
126
+ :region => region,
127
+ :profile => profile,
128
+ :credentials => credentials,
129
+ }.reject { |_, v| v.nil? }
130
+ end
131
+
132
+ class << self
133
+ # Public: Initialize the Configuration Singleton. Must be called before any
134
+ # access to `Configuration.instance` is used.
135
+ #
136
+ # conf_dir - The String path to the directory the configuration can be found in
137
+ # profile - The String profile name that will be used to make AWS API calls
138
+ # assume_role - The ARN of the role to assume when making AWS API calls
139
+ # autoscaling_force_size
140
+ # - Determines whether autoscaling should use configured values for
141
+ # min/max/desired group size
142
+ def init(conf_dir, profile, assume_role, autoscaling_force_size)
143
+ instance = new(conf_dir, profile, assume_role, autoscaling_force_size)
144
+ @@instance = instance
145
+ end
146
+
147
+ # Public: The Singleton instance of Configuration.
148
+ #
149
+ # Returns the Configuration instance.
150
+ def instance
151
+ @@instance
152
+ end
153
+
154
+ private :new
155
+ end
156
+
157
+ # Public: Inner class that contains IAM configuration options
158
+ class IamConfig
159
+ include Config
160
+
161
+ attr_reader :groups_directory
162
+ attr_reader :policy_document_directory
163
+ attr_reader :policy_prefix
164
+ attr_reader :policy_suffix
165
+ attr_reader :policy_version
166
+ attr_reader :roles_directory
167
+ attr_reader :static_policy_directory
168
+ attr_reader :template_policy_directory
169
+ attr_reader :users_directory
170
+
171
+ # Public: Constructor.
172
+ def initialize
173
+ @groups_directory = absolute_path "iam/groups"
174
+ @policy_document_directory = absolute_path "iam/roles/policy-documents"
175
+ @policy_prefix = conf "iam.policies.prefix"
176
+ @policy_suffix = conf "iam.policies.suffix"
177
+ @policy_version = conf "iam.policies.version"
178
+ @roles_directory = absolute_path "iam/roles"
179
+ @static_policy_directory = absolute_path "iam/policies/static"
180
+ @template_policy_directory = absolute_path "iam/policies/template"
181
+ @users_directory = absolute_path "iam/users"
182
+ end
183
+ end
184
+
185
+ # Public: Inner class that contains AutoScaling configuration options
186
+ class AutoScalingConfig
187
+ include Config
188
+
189
+ attr_reader :groups_directory
190
+ attr_reader :override_launch_config_on_sync
191
+ attr_reader :static_policy_directory
192
+ attr_reader :template_policy_directory
193
+ attr_reader :force_size
194
+
195
+ # Public: Constructor.
196
+ def initialize(force_size = false)
197
+ @groups_directory = absolute_path "autoscaling/groups"
198
+ @override_launch_config_on_sync = conf "autoscaling.groups.override-launch-config-on-sync"
199
+ @static_policy_directory = absolute_path "autoscaling/policies/static"
200
+ @template_policy_directory = absolute_path "autoscaling/policies/templates"
201
+ @force_size = force_size
202
+ end
203
+
204
+ end
205
+
206
+ # Public: Inner class that contains Route53 configuration options
207
+ class Route53Config
208
+ include Config
209
+
210
+ attr_reader :includes_directory
211
+ attr_reader :print_all_ignored
212
+ attr_reader :zones_directory
213
+
214
+ # Public: Constructor
215
+ def initialize
216
+ @includes_directory = absolute_path "route53/includes"
217
+ @print_all_ignored = conf "route53.print-all-ignored"
218
+ @zones_directory = absolute_path "route53/zones"
219
+ end
220
+ end
221
+
222
+ # Public: Inner class that contains S3 configuration options
223
+ class S3Config
224
+ include Config
225
+
226
+ attr_reader :buckets_directory
227
+ attr_reader :cors_directory
228
+ attr_reader :policies_directory
229
+ attr_reader :print_progress
230
+
231
+ # Public: Constructor
232
+ def initialize
233
+ @node = "s3"
234
+ @buckets_directory = absolute_path "s3/buckets"
235
+ @cors_directory = absolute_path "s3/cors"
236
+ @policies_directory = absolute_path "s3/policies"
237
+ @print_progress = conf "s3.print-progress"
238
+ end
239
+ end
240
+
241
+ # Public: Inner class that contains Security Group configuration options
242
+ class SecurityConfig
243
+ include Config
244
+
245
+ attr_reader :groups_directory
246
+ attr_reader :rules_directory
247
+ attr_reader :outbound_default_all_allowed
248
+ attr_reader :subnet_files
249
+
250
+ # Public: Constructor.
251
+ def initialize
252
+ @groups_directory = absolute_path "security-groups/groups"
253
+ @rules_directory = absolute_path "security-groups/rules"
254
+ @outbound_default_all_allowed = conf "security.outbound-default-all-allowed"
255
+ @subnet_files = conf("security.subnet-files", true) { |paths| paths.map{ |p| absolute_path(p) } }
256
+
257
+ if !@subnet_files
258
+ default_file = absolute_path("security-groups/subnets.json")
259
+ @subnet_files = [default_file]
260
+ puts "Using default subnets file at #{default_file}"
261
+ end
262
+
263
+ end
264
+
265
+ end
266
+
267
+ # Public: Inner class that contains cloudfront configuration options
268
+ class CloudFrontConfig
269
+ include Config
270
+
271
+ attr_reader :distributions_directory
272
+ attr_reader :invalidations_directory
273
+
274
+ def initialize
275
+ @distributions_directory = absolute_path "cloudfront/distributions"
276
+ @invalidations_directory = absolute_path "cloudfront/invalidations"
277
+ end
278
+ end
279
+
280
+ # Public: Inner class that contains elb configuration options
281
+ class ELBConfig
282
+ include Config
283
+
284
+ attr_reader :load_balancers_directory
285
+ attr_reader :listeners_directory
286
+ attr_reader :policies_directory
287
+
288
+ def initialize
289
+ @load_balancers_directory = absolute_path "elb/load-balancers"
290
+ @listeners_directory = absolute_path "elb/listeners"
291
+ @policies_directory = absolute_path "elb/policies"
292
+ end
293
+ end
294
+
295
+ # Public: Inner class that contains vpc configuration options
296
+ class VpcConfig
297
+ include Config
298
+
299
+ attr_reader :vpcs_directory
300
+ attr_reader :subnets_directory
301
+ attr_reader :route_tables_directory
302
+ attr_reader :policies_directory
303
+ attr_reader :network_acls_directory
304
+
305
+ def initialize
306
+ @vpcs_directory = absolute_path "vpc/vpcs"
307
+ @subnets_directory = absolute_path "vpc/subnets"
308
+ @route_tables_directory = absolute_path "vpc/route-tables"
309
+ @policies_directory = absolute_path "vpc/policies"
310
+ @network_acls_directory = absolute_path "vpc/network-acls"
311
+ end
312
+ end
313
+
314
+ # Public: Inner class that contains kinesis configuration options
315
+ class KinesisConfig
316
+ include Config
317
+
318
+ attr_reader :directory
319
+
320
+ def initialize
321
+ @directory = absolute_path "kinesis"
322
+ end
323
+
324
+ end
325
+
326
+ # Public: Inner class that contains SQS configuration options
327
+ class SQSConfig
328
+ include Config
329
+
330
+ attr_reader :queues_directory
331
+ attr_reader :policies_directory
332
+
333
+ def initialize
334
+ @queues_directory = absolute_path "sqs/queues"
335
+ @policies_directory = absolute_path "sqs/policies"
336
+ end
337
+ end
338
+
339
+ # Public: Inner class that contains EC2 configuration options
340
+ class EC2Config
341
+ include Config
342
+
343
+ attr_reader :ebs_directory
344
+ attr_reader :instances_directory
345
+ attr_reader :ignore_unmanaged_instances
346
+ attr_reader :user_data_directory
347
+ attr_reader :default_image_id
348
+ attr_reader :volume_mount_base
349
+ attr_reader :volume_mount_start
350
+ attr_reader :volume_mount_end
351
+
352
+ def initialize
353
+ @ebs_directory = absolute_path "ec2/ebs"
354
+ @instances_directory = absolute_path "ec2/instances"
355
+ @user_data_directory = absolute_path "ec2/user-data-scripts"
356
+ @ignore_unmanaged_instances = conf "ec2.instances.ignore-unmanaged"
357
+ @default_image_id = conf "ec2.instances.default-image-id"
358
+ @volume_mount_base = conf "ec2.instances.volume-mounting.base"
359
+ @volume_mount_start = conf "ec2.instances.volume-mounting.start"
360
+ @volume_mount_end = conf "ec2.instances.volume-mounting.end"
361
+ end
362
+ end
363
+
364
+ end
365
+ end