lucid-cumulus 0.11.0

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 +11 -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/lib/autoscaling/AutoScaling.rb +40 -0
  12. data/lib/autoscaling/loader/Loader.rb +56 -0
  13. data/lib/autoscaling/manager/Manager.rb +360 -0
  14. data/lib/autoscaling/models/AlarmConfig.rb +165 -0
  15. data/lib/autoscaling/models/AlarmDiff.rb +172 -0
  16. data/lib/autoscaling/models/AutoScalingDiff.rb +178 -0
  17. data/lib/autoscaling/models/GroupConfig.rb +330 -0
  18. data/lib/autoscaling/models/PolicyConfig.rb +135 -0
  19. data/lib/autoscaling/models/PolicyDiff.rb +73 -0
  20. data/lib/autoscaling/models/ScheduledActionDiff.rb +53 -0
  21. data/lib/autoscaling/models/ScheduledConfig.rb +96 -0
  22. data/lib/aws_extensions/ec2/DhcpOptions.rb +41 -0
  23. data/lib/aws_extensions/ec2/Instance.rb +29 -0
  24. data/lib/aws_extensions/ec2/NetworkAcl.rb +25 -0
  25. data/lib/aws_extensions/ec2/NetworkInterface.rb +14 -0
  26. data/lib/aws_extensions/ec2/RouteTable.rb +26 -0
  27. data/lib/aws_extensions/ec2/SecurityGroup.rb +16 -0
  28. data/lib/aws_extensions/ec2/Subnet.rb +28 -0
  29. data/lib/aws_extensions/ec2/Volume.rb +24 -0
  30. data/lib/aws_extensions/ec2/Vpc.rb +14 -0
  31. data/lib/aws_extensions/ec2/VpcEndpoint.rb +11 -0
  32. data/lib/aws_extensions/elb/BackendServerDescription.rb +12 -0
  33. data/lib/aws_extensions/elb/PolicyDescription.rb +14 -0
  34. data/lib/aws_extensions/kinesis/StreamDescription.rb +12 -0
  35. data/lib/aws_extensions/route53/AliasTarget.rb +21 -0
  36. data/lib/aws_extensions/s3/Bucket.rb +33 -0
  37. data/lib/aws_extensions/s3/BucketAcl.rb +28 -0
  38. data/lib/aws_extensions/s3/BucketCors.rb +17 -0
  39. data/lib/aws_extensions/s3/BucketLifecycle.rb +21 -0
  40. data/lib/aws_extensions/s3/BucketLogging.rb +18 -0
  41. data/lib/aws_extensions/s3/BucketNotification.rb +23 -0
  42. data/lib/aws_extensions/s3/BucketPolicy.rb +18 -0
  43. data/lib/aws_extensions/s3/BucketTagging.rb +15 -0
  44. data/lib/aws_extensions/s3/BucketVersioning.rb +14 -0
  45. data/lib/aws_extensions/s3/BucketWebsite.rb +49 -0
  46. data/lib/aws_extensions/s3/CORSRule.rb +27 -0
  47. data/lib/aws_extensions/s3/ReplicationConfiguration.rb +22 -0
  48. data/lib/cloudfront/CloudFront.rb +83 -0
  49. data/lib/cloudfront/loader/Loader.rb +31 -0
  50. data/lib/cloudfront/manager/Manager.rb +183 -0
  51. data/lib/cloudfront/models/CacheBehaviorConfig.rb +237 -0
  52. data/lib/cloudfront/models/CacheBehaviorDiff.rb +211 -0
  53. data/lib/cloudfront/models/CustomOriginConfig.rb +51 -0
  54. data/lib/cloudfront/models/CustomOriginDiff.rb +74 -0
  55. data/lib/cloudfront/models/DistributionConfig.rb +183 -0
  56. data/lib/cloudfront/models/DistributionDiff.rb +131 -0
  57. data/lib/cloudfront/models/InvalidationConfig.rb +37 -0
  58. data/lib/cloudfront/models/OriginConfig.rb +144 -0
  59. data/lib/cloudfront/models/OriginDiff.rb +86 -0
  60. data/lib/cloudfront/models/OriginSslProtocols.rb +28 -0
  61. data/lib/cloudfront/models/OriginSslProtocolsDiff.rb +39 -0
  62. data/lib/common/BaseLoader.rb +80 -0
  63. data/lib/common/manager/Manager.rb +148 -0
  64. data/lib/common/models/Diff.rb +114 -0
  65. data/lib/common/models/ListChange.rb +21 -0
  66. data/lib/common/models/TagsDiff.rb +55 -0
  67. data/lib/common/models/UTCTimeSource.rb +17 -0
  68. data/lib/conf/Configuration.rb +365 -0
  69. data/lib/ec2/EC2.rb +503 -0
  70. data/lib/ec2/IPProtocolMapping.rb +165 -0
  71. data/lib/ec2/loaders/EbsLoader.rb +19 -0
  72. data/lib/ec2/loaders/InstanceLoader.rb +32 -0
  73. data/lib/ec2/managers/EbsManager.rb +176 -0
  74. data/lib/ec2/managers/InstanceManager.rb +509 -0
  75. data/lib/ec2/models/EbsGroupConfig.rb +133 -0
  76. data/lib/ec2/models/EbsGroupDiff.rb +48 -0
  77. data/lib/ec2/models/InstanceConfig.rb +202 -0
  78. data/lib/ec2/models/InstanceDiff.rb +95 -0
  79. data/lib/elb/ELB.rb +148 -0
  80. data/lib/elb/loader/Loader.rb +65 -0
  81. data/lib/elb/manager/Manager.rb +581 -0
  82. data/lib/elb/models/AccessLogConfig.rb +82 -0
  83. data/lib/elb/models/AccessLogDiff.rb +47 -0
  84. data/lib/elb/models/HealthCheckConfig.rb +91 -0
  85. data/lib/elb/models/HealthCheckDiff.rb +50 -0
  86. data/lib/elb/models/ListenerConfig.rb +99 -0
  87. data/lib/elb/models/ListenerDiff.rb +91 -0
  88. data/lib/elb/models/LoadBalancerConfig.rb +239 -0
  89. data/lib/elb/models/LoadBalancerDiff.rb +265 -0
  90. data/lib/iam/IAM.rb +36 -0
  91. data/lib/iam/loader/Loader.rb +117 -0
  92. data/lib/iam/manager/IamGroups.rb +98 -0
  93. data/lib/iam/manager/IamResource.rb +288 -0
  94. data/lib/iam/manager/IamRoles.rb +112 -0
  95. data/lib/iam/manager/IamUsers.rb +54 -0
  96. data/lib/iam/manager/Manager.rb +29 -0
  97. data/lib/iam/migration/AssumeRoleUnifier.rb +34 -0
  98. data/lib/iam/migration/PolicyUnifier.rb +90 -0
  99. data/lib/iam/models/GroupConfig.rb +40 -0
  100. data/lib/iam/models/IamDiff.rb +132 -0
  101. data/lib/iam/models/PolicyConfig.rb +67 -0
  102. data/lib/iam/models/ResourceWithPolicy.rb +208 -0
  103. data/lib/iam/models/RoleConfig.rb +53 -0
  104. data/lib/iam/models/StatementConfig.rb +35 -0
  105. data/lib/iam/models/UserConfig.rb +21 -0
  106. data/lib/kinesis/Kinesis.rb +94 -0
  107. data/lib/kinesis/loader/Loader.rb +19 -0
  108. data/lib/kinesis/manager/Manager.rb +206 -0
  109. data/lib/kinesis/models/StreamConfig.rb +75 -0
  110. data/lib/kinesis/models/StreamDiff.rb +58 -0
  111. data/lib/lambda/Lambda.rb +41 -0
  112. data/lib/route53/loader/Loader.rb +32 -0
  113. data/lib/route53/manager/Manager.rb +241 -0
  114. data/lib/route53/models/AliasTarget.rb +86 -0
  115. data/lib/route53/models/RecordConfig.rb +178 -0
  116. data/lib/route53/models/RecordDiff.rb +140 -0
  117. data/lib/route53/models/Vpc.rb +24 -0
  118. data/lib/route53/models/ZoneConfig.rb +156 -0
  119. data/lib/route53/models/ZoneDiff.rb +118 -0
  120. data/lib/s3/S3.rb +89 -0
  121. data/lib/s3/loader/Loader.rb +66 -0
  122. data/lib/s3/manager/Manager.rb +296 -0
  123. data/lib/s3/models/BucketConfig.rb +321 -0
  124. data/lib/s3/models/BucketDiff.rb +167 -0
  125. data/lib/s3/models/GrantConfig.rb +189 -0
  126. data/lib/s3/models/GrantDiff.rb +50 -0
  127. data/lib/s3/models/LifecycleConfig.rb +142 -0
  128. data/lib/s3/models/LifecycleDiff.rb +46 -0
  129. data/lib/s3/models/LoggingConfig.rb +81 -0
  130. data/lib/s3/models/NotificationConfig.rb +157 -0
  131. data/lib/s3/models/NotificationDiff.rb +62 -0
  132. data/lib/s3/models/ReplicationConfig.rb +133 -0
  133. data/lib/s3/models/ReplicationDiff.rb +60 -0
  134. data/lib/s3/models/WebsiteConfig.rb +107 -0
  135. data/lib/security/SecurityGroups.rb +39 -0
  136. data/lib/security/loader/Loader.rb +94 -0
  137. data/lib/security/manager/Manager.rb +246 -0
  138. data/lib/security/models/RuleConfig.rb +161 -0
  139. data/lib/security/models/RuleDiff.rb +72 -0
  140. data/lib/security/models/RuleMigration.rb +127 -0
  141. data/lib/security/models/SecurityGroupConfig.rb +172 -0
  142. data/lib/security/models/SecurityGroupDiff.rb +112 -0
  143. data/lib/sns/SNS.rb +40 -0
  144. data/lib/sqs/SQS.rb +62 -0
  145. data/lib/sqs/loader/Loader.rb +34 -0
  146. data/lib/sqs/manager/Manager.rb +128 -0
  147. data/lib/sqs/models/DeadLetterConfig.rb +70 -0
  148. data/lib/sqs/models/DeadLetterDiff.rb +35 -0
  149. data/lib/sqs/models/QueueConfig.rb +115 -0
  150. data/lib/sqs/models/QueueDiff.rb +89 -0
  151. data/lib/util/Colors.rb +111 -0
  152. data/lib/util/StatusCodes.rb +51 -0
  153. data/lib/vpc/loader/Loader.rb +73 -0
  154. data/lib/vpc/manager/Manager.rb +954 -0
  155. data/lib/vpc/models/AclEntryConfig.rb +150 -0
  156. data/lib/vpc/models/AclEntryDiff.rb +54 -0
  157. data/lib/vpc/models/DhcpConfig.rb +100 -0
  158. data/lib/vpc/models/DhcpDiff.rb +90 -0
  159. data/lib/vpc/models/EndpointConfig.rb +76 -0
  160. data/lib/vpc/models/EndpointDiff.rb +69 -0
  161. data/lib/vpc/models/NetworkAclConfig.rb +87 -0
  162. data/lib/vpc/models/NetworkAclDiff.rb +116 -0
  163. data/lib/vpc/models/RouteConfig.rb +82 -0
  164. data/lib/vpc/models/RouteDiff.rb +50 -0
  165. data/lib/vpc/models/RouteTableConfig.rb +92 -0
  166. data/lib/vpc/models/RouteTableDiff.rb +101 -0
  167. data/lib/vpc/models/SubnetConfig.rb +113 -0
  168. data/lib/vpc/models/SubnetDiff.rb +78 -0
  169. data/lib/vpc/models/VpcConfig.rb +173 -0
  170. data/lib/vpc/models/VpcDiff.rb +315 -0
  171. data/lucid-cumulus.gemspec +20 -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