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,36 @@
1
+ require "conf/Configuration"
2
+
3
+ require "aws-sdk"
4
+
5
+ module Cumulus
6
+ module IAM
7
+ class << self
8
+ @@client = Aws::IAM::Client.new(Configuration.instance.client)
9
+
10
+ # Public: Static method that will get the ARN of an IAM Role
11
+ #
12
+ # name - the name of the role to get
13
+ #
14
+ # Returns the String ARN or nil if there is no role
15
+ def get_role_arn(name)
16
+ @@client.get_role({
17
+ role_name: name
18
+ }).role.arn
19
+ rescue Aws::IAM::Errors::NoSuchEntity
20
+ nil
21
+ end
22
+
23
+ # Public: Get the instance profile arn for a role
24
+ #
25
+ # name - the name of the role
26
+ def get_instance_profile_arn(name)
27
+ @@client.get_instance_profile({
28
+ instance_profile_name: name
29
+ }).instance_profile.arn
30
+ rescue Aws::IAM::Errors::NoSuchEntity
31
+ nil
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,117 @@
1
+ require "conf/Configuration"
2
+ require "iam/models/GroupConfig"
3
+ require "iam/models/StatementConfig"
4
+ require "iam/models/RoleConfig"
5
+ require "iam/models/UserConfig"
6
+ require "common/BaseLoader"
7
+
8
+ require "json"
9
+
10
+ module Cumulus
11
+ module IAM
12
+ # Public: A module that handles loading all the json configuration files and
13
+ # creating objects from them.
14
+ module Loader
15
+ include Common::BaseLoader
16
+
17
+ @@group_loader = Proc.new { |name, json| GroupConfig.new(name, json) }
18
+ @@groups_dir = Configuration.instance.iam.groups_directory
19
+ @@role_loader = Proc.new { |name, json| RoleConfig.new(name, json) }
20
+ @@roles_dir = Configuration.instance.iam.roles_directory
21
+ @@user_loader = Proc.new { |name, json| UserConfig.new(name, json) }
22
+ @@users_dir = Configuration.instance.iam.users_directory
23
+ @@static_policy_dir = Configuration.instance.iam.static_policy_directory
24
+ @@template_dir = Configuration.instance.iam.template_policy_directory
25
+ @@policy_loader = Proc.new do |name, json|
26
+ if json.is_a?(Array)
27
+ json.map do |s|
28
+ StatementConfig.new(s)
29
+ end
30
+ else
31
+ StatementConfig.new(json)
32
+ end
33
+ end
34
+
35
+ # Public: Load all the roles defined in configuration.
36
+ #
37
+ # Returns an Array of RoleConfig objects defined by the roles configuration
38
+ # files.
39
+ def Loader.roles
40
+ Common::BaseLoader.resources(@@roles_dir, &@@role_loader)
41
+ end
42
+
43
+ # Public: Load a role defined in configuration
44
+ #
45
+ # file - the name of the role to load
46
+ #
47
+ # Returns a RoleConfig object defined by the role configuration files.
48
+ def Loader.role(file)
49
+ Common::BaseLoader.resource(file, @@roles_dir, &@@role_loader)
50
+ end
51
+
52
+ # Public: Load all the users defined in configuration.
53
+ #
54
+ # Returns an Array of UserConfig objects defined in user configuration files.
55
+ def Loader.users
56
+ Common::BaseLoader.resources(@@users_dir, &@@user_loader)
57
+ end
58
+
59
+ # Public: Load a user defined in configuration
60
+ #
61
+ # file - the file the user definition is found in
62
+ #
63
+ # Returns the UserConfig object defined by the file.
64
+ def Loader.user(file)
65
+ Common::BaseLoader.resource(file, @@users_dir, &@@user_loader)
66
+ end
67
+
68
+ # Public: Load all the groups defined in configuration.
69
+ #
70
+ # Returns an Array of GroupConfig objects defined by the groups configuration
71
+ # files.
72
+ def Loader.groups
73
+ Common::BaseLoader.resources(@@groups_dir, &@@group_loader)
74
+ end
75
+
76
+ # Public: Load a group defined in configuration
77
+ #
78
+ # file - the file the group definition is found in
79
+ #
80
+ # Returns the GroupConfig object defined by the file
81
+ def Loader.group(file)
82
+ Common::BaseLoader.resource(file, @@groups_dir, &@@group_loader)
83
+ end
84
+
85
+ # Public: Load in a static policy as StatementConfig object
86
+ #
87
+ # file - the String name of the static policy file to load
88
+ #
89
+ # Returns a StatementConfig object corresponding to the static policy
90
+ def Loader.static_policy(file)
91
+ Common::BaseLoader.resource(file, @@static_policy_dir, &@@policy_loader)
92
+ end
93
+
94
+ # Public: Load in a template policy, apply variables, and create a
95
+ # StatementConfig object from the result
96
+ #
97
+ # file - the String name of the template policy file to load
98
+ # variables - a Hash of variables to apply to the template
99
+ #
100
+ # Returns a StatementConfig object corresponding to the applied template policy
101
+ def Loader.template_policy(file, variables)
102
+ Common::BaseLoader.template(file, @@template_dir, variables, &@@policy_loader)
103
+ end
104
+
105
+ # Public: Load the JSON string that is a role's policy document from a file.
106
+ #
107
+ # file - the String name of the policy document file to load
108
+ #
109
+ # Returns the String contents of the policy document file
110
+ def Loader.policy_document(file)
111
+ policy_dir = Configuration.instance.iam.policy_document_directory
112
+ Common::BaseLoader.load_file(file, policy_dir)
113
+ end
114
+
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,98 @@
1
+ require "common/models/Diff"
2
+ require "iam/loader/Loader"
3
+ require "iam/models/IamDiff"
4
+ require "iam/manager/IamResource"
5
+ require "iam/models/GroupConfig"
6
+ require "util/Colors"
7
+
8
+ require "aws-sdk"
9
+
10
+ module Cumulus
11
+ module IAM
12
+ # Public: Manager class for IAM Groups
13
+ class IamGroups < IamResource
14
+
15
+ def initialize(iam)
16
+ super(iam)
17
+ @type = "group"
18
+ @migration_dir = "groups"
19
+ end
20
+
21
+ def local_resources
22
+ local = {}
23
+ Loader.groups.each do |group|
24
+ local[group.name] = group
25
+ end
26
+ local
27
+ end
28
+
29
+ def one_local(name)
30
+ Loader.group(name)
31
+ end
32
+
33
+ def aws_resources
34
+ @aws_groups ||= init_aws_groups
35
+ end
36
+
37
+ def init_aws_groups
38
+ @iam.list_groups().groups.map do |group|
39
+ Aws::IAM::Group.new(group.group_name, { :client => @iam })
40
+ end
41
+ end
42
+
43
+ def create(difference)
44
+ @iam.create_group({
45
+ :group_name => difference.local.name
46
+ })
47
+ resource = Aws::IAM::Group.new(difference.local.name, { :client => @iam })
48
+ add_users(resource, difference.local.users)
49
+ resource
50
+ end
51
+
52
+ def update(resource, diffs)
53
+ super(resource, diffs)
54
+
55
+ if diffs.size == 1 and diffs[0].type == Common::DiffChange::ADD
56
+ puts Colors.blue("\tadding users...")
57
+ add_users(resource, diffs[0].local.users)
58
+ else
59
+ diffs.each do |diff|
60
+ if diff.type == IamChange::USER
61
+ puts Colors.blue("\tupdating users...")
62
+ add_users(resource, diff.added_users)
63
+ diff.removed_users.each { |u| resource.remove_user({ :user_name => u }) }
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ def empty_config
70
+ GroupConfig.new
71
+ end
72
+
73
+ def migrate_additional(configs_to_aws)
74
+ configs_to_aws.map do |config, resource|
75
+ config.users = resource.users.map { |u| u.name }
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ # Internal: Add the users assigned to the group to the group, handling the
82
+ # case that the user doesn't exist
83
+ #
84
+ # resource - the aws group resource
85
+ # users - the users to add
86
+ def add_users(resource, users)
87
+ users.each do |u|
88
+ begin
89
+ resource.add_user({ :user_name => u })
90
+ rescue Aws::IAM::Errors::NoSuchEntity
91
+ puts Colors.red("\tNo such user #{u}!")
92
+ end
93
+ end
94
+ end
95
+
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,288 @@
1
+ require "common/models/Diff"
2
+ require "iam/migration/PolicyUnifier"
3
+ require "iam/models/IamDiff"
4
+ require "util/Colors"
5
+ require "util/StatusCodes"
6
+
7
+ require 'uri'
8
+
9
+ module Cumulus
10
+ module IAM
11
+ # Internal: Represents the manager of a type of IamResource. Base class for
12
+ # groups, roles, and users.
13
+ class IamResource
14
+ @@diff = Proc.new do |name, diffs|
15
+ if diffs.size > 0
16
+
17
+ if diffs.reject(&:info_only).size > 0
18
+ StatusCodes::set_status(StatusCodes::DIFFS)
19
+ end
20
+
21
+ if diffs.size == 1 and (diffs[0].type == Common::DiffChange::ADD or
22
+ diffs[0].type == Common::DiffChange::UNMANAGED)
23
+ puts diffs[0]
24
+ else
25
+ puts "#{name} has the following changes:"
26
+ diffs.each do |diff|
27
+ diff_string = diff.to_s.lines.map { |s| "\t#{s}" }.join
28
+ puts diff_string
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ # =====================================================
35
+ # Methods to be overridden
36
+ # =====================================================
37
+ # Public: Get the local resources
38
+ #
39
+ # Returns an array of resources
40
+ def local_resources
41
+ nil
42
+ end
43
+
44
+ # Public: Get one local resource
45
+ #
46
+ # name - the name of the resource to load
47
+ #
48
+ # Returns one local resource
49
+ def one_local(name)
50
+ nil
51
+ end
52
+
53
+ # Public: Get resources from AWS
54
+ #
55
+ # Returns an array of resources from AWS
56
+ def aws_resources
57
+ nil
58
+ end
59
+
60
+ # Public: Create a resource in AWS
61
+ #
62
+ # difference - the Diff object that contains the local differences
63
+ #
64
+ # Returns the created resource
65
+ def create(difference)
66
+ nil
67
+ end
68
+
69
+ # Public: Create an empty config object
70
+ #
71
+ # Returns the created config object
72
+ def empty_config
73
+ nil
74
+ end
75
+
76
+ # Public: When migrating, provide a config with any resource type specific
77
+ # data.
78
+ #
79
+ # configs_to_aws - an array of arrays where each inner array's first element
80
+ # is the configuration generated so far, and the second
81
+ # element is the corresponding aws resource
82
+ def migrate_additional(configs_to_aws)
83
+ end
84
+
85
+ # =====================================================
86
+ # End methods to be overridden
87
+ # =====================================================
88
+
89
+ # Public: Constructor
90
+ #
91
+ # iam - the IAM client to use
92
+ def initialize(iam)
93
+ @iam = iam
94
+ @migration_root = "generated"
95
+ end
96
+
97
+ # Public: Print out the diff between the local configuration and the IAMS
98
+ # in AWS
99
+ def diff
100
+ each_difference(local_resources, true, &@@diff)
101
+ end
102
+
103
+ # Public: Print out the diff between local configuration and AWS for one
104
+ # resource
105
+ #
106
+ # name - the name of the resource to diff
107
+ def diff_one(name)
108
+ each_difference({ name => one_local(name) }, false, &@@diff)
109
+ end
110
+
111
+ # Public: Print out a list of resources defined by local configuration.
112
+ def list
113
+ puts local_resources.map { |name, resource| name }.join(" ")
114
+ end
115
+
116
+ # Public: Sync the local configuration with the configuration in AWS. Will
117
+ # not delete resources that are not locally configured; also will not remove
118
+ # inline policies that are not locally configured.
119
+ def sync
120
+ each_difference(local_resources, true) { |name, diffs| sync_difference(name, diffs) }
121
+ end
122
+
123
+ # Public: Sync the local configuration for one resource with AWS
124
+ #
125
+ # name - the name of the resource to sync
126
+ def sync_one(name)
127
+ each_difference({ name => one_local(name) }, false) { |name, diffs| sync_difference(name, diffs) }
128
+ end
129
+
130
+ # Public: Migrate AWS IAMs to Cumulus configuration.
131
+ def migrate
132
+ assets = "#{@migration_root}/#{@migration_dir}"
133
+ policies_dir = "#{@migration_root}/policies"
134
+ statics_dir = "#{policies_dir}/static"
135
+
136
+ if !Dir.exists?(@migration_root)
137
+ Dir.mkdir(@migration_root)
138
+ end
139
+ if !Dir.exists?(assets)
140
+ Dir.mkdir(assets)
141
+ end
142
+ if !Dir.exists?(policies_dir)
143
+ Dir.mkdir(policies_dir)
144
+ end
145
+ if !Dir.exists?(statics_dir)
146
+ Dir.mkdir(statics_dir)
147
+ end
148
+
149
+ # generate the configuration objects. This MUST be done separate from
150
+ # writing to file, because the unifier will change the configuration objects
151
+ # as it finds ways to unify configured attributes.
152
+ policy_unifier = PolicyUnifier.new(statics_dir)
153
+ configs = aws_resources.map do |resource|
154
+ puts "Processing #{@type} #{resource.name}..."
155
+ config = empty_config
156
+ config.name = resource.name
157
+
158
+ config.attached_policies = resource.attached_policies.map { |p| p.arn }
159
+
160
+ resource.policies.each do |policy|
161
+ statements = JSON.parse(URI.decode(policy.policy_document))["Statement"]
162
+ statements.each { |statement| statement.delete("Sid") }
163
+ policy_unifier.unify(config, statements, policy.name)
164
+ end
165
+
166
+ [config, resource]
167
+ end
168
+
169
+ migrate_additional(configs)
170
+ configs = configs.map { |config, resource| config }
171
+
172
+ # write the configuration to file
173
+ puts "Writing configuration to file..."
174
+ configs.each do |config|
175
+ File.open("#{assets}/#{config.name}.json", 'w') { |f| f.write(config.json) }
176
+ end
177
+
178
+ puts "Done."
179
+ end
180
+
181
+ # Public: Update a resource in AWS
182
+ #
183
+ # resource - the resource to update
184
+ # diffs - the diff objects to be used when updating the resource
185
+ def update(resource, diffs)
186
+ if diffs.size == 1 and diffs[0].type == Common::DiffChange::ADD
187
+ if !diffs[0].local.policy.empty?
188
+ update_policy(resource, diffs[0].local.generated_policy_name, diffs[0].local.policy)
189
+ end
190
+ if !diffs[0].local.attached_policies.empty?
191
+ update_attached(resource, diffs[0].local.attached_policies, [])
192
+ end
193
+ else
194
+ diffs.each do |diff|
195
+ case diff.type
196
+ when IamChange::POLICY
197
+ update_policy(resource, diff.policy_name, diff.local)
198
+ when IamChange::ATTACHED
199
+ update_attached(resource, diff.attached, diff.detached)
200
+ when IamChange::ADDED_POLICY
201
+ update_policy(resource, diff.policy_name, diff.local)
202
+ when IamChange::UNMANAGED_POLICY
203
+ puts Colors.unmanaged("\t#{diff.policy_name} is not managed by Cumulus")
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ private
210
+
211
+ # Internal: Loop through the differences between local configuration and AWS
212
+ #
213
+ # locals - the local configurations to compare against
214
+ # include_unmanaged - whether to include unmanaged resources in the list of
215
+ # changes
216
+ # f - will be passed the name of the resource and an array of
217
+ # IamDiffs
218
+ def each_difference(locals, include_unmanaged, &f)
219
+ aws = Hash[aws_resources.map { |aws| [aws.name, aws] }]
220
+
221
+ if include_unmanaged
222
+ aws.each do |name, resource|
223
+ f.call(name, [IamDiff.unmanaged(resource)]) if !locals.include?(name)
224
+ end
225
+ end
226
+ locals.each do |name, resource|
227
+ if !aws.include?(name)
228
+ f.call(name, [IamDiff.added(resource)])
229
+ else
230
+ f.call(name, resource.diff(aws[name]))
231
+ end
232
+ end
233
+ end
234
+
235
+ # Internal: Sync differences
236
+ #
237
+ # name - the name of the resource to sync
238
+ # diffs - the differences between the configuration and AWS
239
+ def sync_difference(name, diffs)
240
+ aws = Hash[aws_resources.map { |aws| [aws.name, aws] }]
241
+ if diffs.size > 0
242
+ StatusCodes::set_status(StatusCodes::SYNC_DIFFS)
243
+
244
+ if diffs[0].type == Common::DiffChange::UNMANAGED
245
+ puts diffs[0]
246
+ elsif diffs[0].type == Common::DiffChange::ADD
247
+ puts Colors.added("creating #{name}...")
248
+ resource = create(diffs[0])
249
+ update(resource, diffs)
250
+ else
251
+ puts Colors.blue("updating #{name}...")
252
+ resource = aws[name]
253
+ update(resource, diffs)
254
+ end
255
+ end
256
+ end
257
+
258
+ # Internal: Update the generated policy
259
+ #
260
+ # resource - the AWS resource to update
261
+ # name - the name of the policy to update
262
+ # config - the policy config to use when updating
263
+ def update_policy(resource, name, config)
264
+ puts Colors.blue("\tupdating policy #{name}...")
265
+ policy = resource.policy(name)
266
+ if config.empty?
267
+ policy.delete()
268
+ else
269
+ policy.put({
270
+ :policy_document => config.as_pretty_json
271
+ })
272
+ end
273
+ end
274
+
275
+ # Internal: Update the attached policies
276
+ #
277
+ # resource - the AWS resource to update
278
+ # attach - the policy arns to attach
279
+ # detach - the policy arns to detach
280
+ def update_attached(resource, attach, detach)
281
+ puts Colors.blue("\tupdating attached policies...")
282
+ attach.each { |arn| resource.attach_policy({ :policy_arn => arn }) }
283
+ detach.each { |arn| resource.detach_policy({ :policy_arn => arn }) }
284
+ end
285
+
286
+ end
287
+ end
288
+ end