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,118 @@
1
+ require "conf/Configuration"
2
+ require "common/models/Diff"
3
+ require "route53/models/RecordDiff"
4
+ require "util/Colors"
5
+
6
+ module Cumulus
7
+ module Route53
8
+ # Public: The types of changes that can be made to zones
9
+ module ZoneChange
10
+ include Common::DiffChange
11
+
12
+ COMMENT = Common::DiffChange::next_change_id
13
+ DOMAIN = Common::DiffChange::next_change_id
14
+ PRIVATE = Common::DiffChange::next_change_id
15
+ RECORD = Common::DiffChange::next_change_id
16
+ VPC = Common::DiffChange::next_change_id
17
+ end
18
+
19
+ # Public: Represents a single difference between local configuration and AWS
20
+ # configuration of zones.
21
+ class ZoneDiff < Common::Diff
22
+ include ZoneChange
23
+
24
+ attr_accessor :changed_records
25
+
26
+ # Public: Static method that produces a diff representing changes in records
27
+ #
28
+ # changed_records - the RecordDiffs
29
+ # local - the local configuration for the zone
30
+ #
31
+ # Returns the diff
32
+ def self.records(changed_records, local)
33
+ diff = ZoneDiff.new(RECORD, nil, local)
34
+ diff.changed_records = changed_records
35
+ diff
36
+ end
37
+
38
+ def asset_type
39
+ "Zone"
40
+ end
41
+
42
+ def aws_name
43
+ access = if @aws.config.private_zone then "private" else "public" end
44
+ "#{@aws.name} (#{access})"
45
+ end
46
+
47
+ def add_string
48
+ "has been added locally, but must be created in AWS manually."
49
+ end
50
+
51
+ def diff_string
52
+ case @type
53
+ when COMMENT
54
+ [
55
+ "Comment:",
56
+ Colors.aws_changes("\tAWS - #{@aws.config.comment}"),
57
+ Colors.local_changes("\tLocal - #{@local.comment}")
58
+ ].join("\n")
59
+ when DOMAIN
60
+ [
61
+ "Domain: AWS - #{Colors.aws_changes(@aws.name)}, Local - #{Colors.local_changes(@local.domain)}",
62
+ "\tAWS doesn't allow you to change the domain for a zone."
63
+ ].join("\n")
64
+ when PRIVATE
65
+ [
66
+ "Private: AWS - #{Colors.aws_changes(@aws.config.private_zone)}, Local - #{Colors.local_changes(@local.private)}",
67
+ "\tAWS doesn't allow you to change whether a zone is private."
68
+ ].join("\n")
69
+ when RECORD
70
+ if Configuration.instance.route53.print_all_ignored
71
+ [
72
+ "Records:",
73
+ @changed_records.map { |r| "\t#{r}" }
74
+ ].flatten.join("\n")
75
+ else
76
+ [
77
+ "Records:",
78
+ @changed_records.reject { |r| r.type == RecordChange::IGNORED }.map { |r| "\t#{r}" },
79
+ "\tYour blacklist ignored #{@changed_records.select { |r| r.type == RecordChange::IGNORED }.size} records."
80
+ ].flatten.join("\n")
81
+ end
82
+ when VPC
83
+ [
84
+ "VPCs:",
85
+ added_vpc_ids.map { |vpc| Colors.added("\t#{vpc["id"]} | #{vpc["region"]}") },
86
+ removed_vpc_ids.map { |vpc| Colors.removed("\t#{vpc["id"]} | #{vpc["region"]}") }
87
+ ].flatten.join("\n")
88
+ end
89
+ end
90
+
91
+ # Public: Get the VPCs that have been added locally.
92
+ #
93
+ # Returns an array of vpc ids
94
+ def added_vpc_ids
95
+ @local.vpc - @aws.vpc
96
+ end
97
+
98
+ # Public: Get the VPCs that have been removed locally.
99
+ #
100
+ # Returns an array of vpc ids
101
+ def removed_vpc_ids
102
+ @aws.vpc - @local.vpc
103
+ end
104
+
105
+ # Public: Override the info_only attribute such that if this diff is a record diff and it
106
+ # contains only ignored record diffs, we return true.
107
+ #
108
+ # Returns whether or not this is an info only diff
109
+ def info_only
110
+ if @type == RECORD
111
+ @changed_records.all? { |r| r.type == RecordChange::IGNORED }
112
+ else
113
+ false
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,89 @@
1
+ require "conf/Configuration"
2
+
3
+ require "aws-sdk"
4
+
5
+ module Cumulus
6
+ module S3
7
+ class << self
8
+ def client(region = nil)
9
+ @clients ||= {}
10
+ if !region then region = "us-east-1" end
11
+ @clients[region] ||= Aws::S3::Client.new(Configuration.instance.client.merge({:force_path_style => true, :region => region}))
12
+ end
13
+
14
+ @@zone_ids = {
15
+ "ap-northeast-1" => "Z2M4EHUR26P7ZW",
16
+ "ap-southeast-1" => "Z3O0J2DXBE1FTB",
17
+ "ap-southeast-2" => "Z1WCIGYICN2BYD",
18
+ "eu-central-1" => "Z21DNDUVLTQW6Q",
19
+ "eu-west-1" => "Z1BKCTXD74EZPE",
20
+ "sa-east-1" => "Z7KQH4QJS55SO",
21
+ "us-east-1" => "Z3AQBSTGFYJSTF",
22
+ "us-gov-west-1" => "Z31GFT0UA1I2HV",
23
+ "us-west-1" => "Z2F56UZL2M1ACD",
24
+ "us-west-2" => "Z3BJ6K6RIION7M",
25
+ }
26
+
27
+ # Public: A mapping of region name to its hosted zone id. This mapping is needed because
28
+ # the S3 API doesn't expose the hosted ids, you have to get them at
29
+ # http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region.
30
+ def zone_ids
31
+ @@zone_ids
32
+ end
33
+
34
+ # Public: Static method that will get an S3 bucket from AWS by its name
35
+ #
36
+ # name - the name of the bucket to get
37
+ #
38
+ # Returns the Aws::S3::Types::Bucket by that name
39
+ def get_aws(name)
40
+ buckets.fetch(name)
41
+ rescue KeyError
42
+ puts "No S3 bucket named #{name}"
43
+ exit
44
+ end
45
+
46
+ # Public: Get the full data for a bucket. Lazily loads resources only once.
47
+ #
48
+ # bucket_name - the name of the bucket to get
49
+ #
50
+ # Returns the full bucket
51
+ def full_bucket(bucket_name)
52
+ @monkey_patched ||= monkey_patch_bucket
53
+ @full_buckets ||= Hash.new
54
+
55
+ bucket = buckets[bucket_name]
56
+ @full_buckets[bucket_name] ||= Aws::S3::Bucket.new(name: bucket_name, client: client(bucket.location))
57
+ end
58
+
59
+ # Public: Provide a mapping of S3 buckets to their names. Lazily loads resources.
60
+ #
61
+ # Returns the buckets mapped to their names
62
+ def buckets
63
+ @buckets ||= init_buckets
64
+ end
65
+
66
+ # Public: Refereshes the bucket list and full_buckets map
67
+ def refresh!
68
+ @buckets = init_buckets
69
+ @full_buckets = Hash.new
70
+ end
71
+
72
+ private
73
+
74
+ # Internal: Monkey patch Bucket so it can get its location
75
+ def monkey_patch_bucket
76
+ require "aws_extensions/s3/Bucket"
77
+ Aws::S3::Types::Bucket.send(:include, AwsExtensions::S3::Types::Bucket)
78
+ true
79
+ end
80
+
81
+ # Internal: Load the buckets and map them to their names.
82
+ #
83
+ # Returns the buckets mapped to their names
84
+ def init_buckets
85
+ Hash[client.list_buckets.buckets.map { |bucket| [bucket.name, bucket] }]
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,66 @@
1
+ require "common/BaseLoader"
2
+ require "conf/Configuration"
3
+ require "s3/models/BucketConfig"
4
+
5
+ require "aws-sdk"
6
+
7
+ module Cumulus
8
+ module S3
9
+ module Loader
10
+ include Common::BaseLoader
11
+
12
+ @@buckets_dir = Configuration.instance.s3.buckets_directory
13
+ @@cors_dir = Configuration.instance.s3.cors_directory
14
+ @@policies_dir = Configuration.instance.s3.policies_directory
15
+
16
+ # Public: Load all the bucket configurations a BucketConfig objects
17
+ #
18
+ # Returns an array of BucketConfigs
19
+ def self.buckets
20
+ Common::BaseLoader.resources(@@buckets_dir, &BucketConfig.method(:new))
21
+ end
22
+
23
+ # Public: Load a specific CORS policy by name, applying any variables.
24
+ #
25
+ # name - the name of the file to load
26
+ # vars - the variables to apply to the template
27
+ #
28
+ # Returns the CORS policy as a string
29
+ def self.cors_policy(name, vars)
30
+ Common::BaseLoader.template(
31
+ name,
32
+ @@cors_dir,
33
+ vars,
34
+ &proc do |n, json| json.map do |rule|
35
+ Aws::S3::Types::CORSRule.new({
36
+ allowed_headers: rule.fetch("headers"),
37
+ allowed_methods: rule.fetch("methods"),
38
+ allowed_origins: rule.fetch("origins"),
39
+ expose_headers: rule.fetch("exposed-headers"),
40
+ max_age_seconds: rule.fetch("max-age-seconds")
41
+ })
42
+ end
43
+ end
44
+ )
45
+ rescue KeyError
46
+ puts "CORS configuration #{name} does not contain all required keys."
47
+ exit
48
+ end
49
+
50
+ # Public: Load a specific bucket policy by name, applying any variables
51
+ #
52
+ # name - the name of the file to load
53
+ # vars - the variables to apply to the template
54
+ #
55
+ # Returns the bucket policy as a string
56
+ def self.bucket_policy(name, vars)
57
+ Common::BaseLoader.template(
58
+ name,
59
+ @@policies_dir,
60
+ vars,
61
+ &proc { |n, json| json.to_json }
62
+ )
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,296 @@
1
+ require "common/manager/Manager"
2
+ require "conf/Configuration"
3
+ require "s3/loader/Loader"
4
+ require "s3/models/BucketConfig"
5
+ require "s3/models/BucketDiff"
6
+ require "s3/S3"
7
+ require "util/Colors"
8
+
9
+ require "aws-sdk"
10
+
11
+ module Cumulus
12
+ module S3
13
+ class Manager < Common::Manager
14
+ def migrate
15
+ buckets_dir = "#{@migration_root}/buckets"
16
+ cors_dir = "#{@migration_root}/cors"
17
+ policy_dir = "#{@migration_root}/policies"
18
+
19
+ [@migration_root, buckets_dir, cors_dir, policy_dir].each do |dir|
20
+ if !Dir.exists?(dir)
21
+ Dir.mkdir(dir)
22
+ end
23
+ end
24
+
25
+ cors = {}
26
+ policies = {}
27
+
28
+ aws_resources.each_value do |resource|
29
+ puts "Processing #{resource.name}..."
30
+ full_aws = S3.full_bucket(resource.name)
31
+ config = BucketConfig.new(resource.name)
32
+ new_policy_key, new_cors_key = config.populate!(full_aws, cors, policies)
33
+
34
+ puts "Writing #{resource.name} configuration to file..."
35
+ if new_policy_key
36
+ File.open("#{policy_dir}/#{new_policy_key}.json", "w") { |f| f.write(policies[new_policy_key]) }
37
+ end
38
+ if new_cors_key
39
+ File.open("#{cors_dir}/#{new_cors_key}.json", "w") { |f| f.write(cors[new_cors_key]) }
40
+ end
41
+ File.open("#{buckets_dir}/#{resource.name}.json", "w") { |f| f.write(config.pretty_json) }
42
+ end
43
+ end
44
+
45
+ def resource_name
46
+ "Bucket"
47
+ end
48
+
49
+ def local_resources
50
+ Hash[Loader.buckets.map { |bucket| [bucket.name, bucket] }]
51
+ end
52
+
53
+ def aws_resources
54
+ S3.buckets
55
+ end
56
+
57
+ def unmanaged_diff(aws)
58
+ BucketDiff.unmanaged(aws)
59
+ end
60
+
61
+ def added_diff(local)
62
+ BucketDiff.added(local)
63
+ end
64
+
65
+ def diff_resource(local, aws)
66
+ if Configuration.instance.s3.print_progress
67
+ puts "checking for differences in #{local.name}"
68
+ end
69
+ full_aws = S3.full_bucket(aws.name)
70
+ local.diff(full_aws)
71
+ end
72
+
73
+ def create(local)
74
+ S3.client(local.region).create_bucket({
75
+ bucket: local.name,
76
+ create_bucket_configuration: if local.region != "us-east-1" then {
77
+ location_constraint: local.region
78
+ } end
79
+ })
80
+ S3.refresh!
81
+ update_policy(local.region, local.name, local.policy)
82
+ update_cors(local.region, local.name, local.cors)
83
+ update_grants(local.region, local.name, local.grants)
84
+ update_versioning(local.region, local.name, local.versioning)
85
+ update_logging(local.region, local.name, local.logging)
86
+ update_website(local.region, local.name, local.website)
87
+ update_lifecycle(local.region, local.name, local.lifecycle)
88
+ update_notifications(local.region, local.name, local.notifications)
89
+ update_replication(local.region, local.name, local.replication)
90
+ update_tags(local.region, local.name, local.tags) if !local.tags.empty?
91
+ end
92
+
93
+ def update(local, diffs)
94
+ diffs.each do |diff|
95
+ if diff.type == BucketChange::TAGS
96
+ puts Colors.blue("\tupdating tags...")
97
+ update_tags(diff.local.region, diff.local.name, diff.local.tags)
98
+ elsif diff.type == BucketChange::POLICY
99
+ puts Colors.blue("\tupdating policy...")
100
+ update_policy(diff.local.region, diff.local.name, diff.local.policy)
101
+ elsif diff.type == BucketChange::CORS
102
+ puts Colors.blue("\tupdating CORS rules...")
103
+ update_cors(diff.local.region, diff.local.name, diff.local.cors)
104
+ elsif diff.type == BucketChange::WEBSITE
105
+ puts Colors.blue("\tupdating S3 bucket website...")
106
+ update_website(diff.local.region, diff.local.name, diff.local.website)
107
+ elsif diff.type == BucketChange::LOGGING
108
+ puts Colors.blue("\tupdating S3 bucket logging..")
109
+ update_logging(diff.local.region, diff.local.name, diff.local.logging)
110
+ elsif diff.type == BucketChange::VERSIONING
111
+ puts Colors.blue("\tupdating versioning status...")
112
+ update_versioning(diff.local.region, diff.local.name, diff.local.versioning)
113
+ elsif diff.type == BucketChange::GRANTS
114
+ puts Colors.blue("\tupdating grants...")
115
+ update_grants(diff.local.region, diff.local.name, diff.local.grants)
116
+ elsif diff.type == BucketChange::LIFECYCLE
117
+ puts Colors.blue("\tupdating lifecycle...")
118
+ update_lifecycle(diff.local.region, diff.local.name, diff.local.lifecycle)
119
+ elsif diff.type == BucketChange::NOTIFICATIONS
120
+ puts Colors.blue("\tupdating notifications...")
121
+ update_notifications(diff.local.region, diff.local.name, diff.local.notifications)
122
+ elsif diff.type == BucketChange::REPLICATION
123
+ puts Colors.blue("\tupdating replication...")
124
+ update_replication(diff.local.region, diff.local.name, diff.local.replication)
125
+ end
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ # Internal: Update the tags for a bucket.
132
+ #
133
+ # region - the region of the bucket
134
+ # bucket_name - the name of the bucket
135
+ # tags - the tags that belong to the bucket
136
+ def update_tags(region, bucket_name, tags)
137
+ S3.client(region).put_bucket_tagging({
138
+ bucket: bucket_name,
139
+ tagging: {
140
+ tag_set: tags.map { |k, v| { key: k, value: v } }
141
+ }
142
+ })
143
+ end
144
+
145
+ # Internal: Update the policy for a bucket.
146
+ #
147
+ # region - the region of the bucket
148
+ # bucket_name - the name of the bucket
149
+ # policy - the policy to apply to the bucket
150
+ def update_policy(region, bucket_name, policy)
151
+ if policy
152
+ S3.client(region).put_bucket_policy({
153
+ bucket: bucket_name,
154
+ policy: policy
155
+ })
156
+ else
157
+ S3.client(region).delete_bucket_policy({
158
+ bucket: bucket_name
159
+ })
160
+ end
161
+ end
162
+
163
+ # Internal: Update the CORS rules for a bucket.
164
+ #
165
+ # region - the region of the bucket
166
+ # bucket_name - the name of the bucket
167
+ # cors - the cors rules for the bucket
168
+ def update_cors(region, bucket_name, cors)
169
+ if cors
170
+ S3.client(region).put_bucket_cors({
171
+ bucket: bucket_name,
172
+ cors_configuration: {
173
+ cors_rules: cors
174
+ }
175
+ })
176
+ else
177
+ S3.client(region).delete_bucket_cors({
178
+ bucket: bucket_name
179
+ })
180
+ end
181
+ end
182
+
183
+ # Internal: Update the bucket website configuration for the bucket.
184
+ #
185
+ # region - the region of the bucket
186
+ # bucket_name - the name of the bucket
187
+ # website - the website configuration for the bucket
188
+ def update_website(region, bucket_name, website)
189
+ if website
190
+ S3.client(region).put_bucket_website({
191
+ bucket: bucket_name,
192
+ website_configuration: website.to_aws
193
+ })
194
+ else
195
+ S3.client(region).delete_bucket_website({ bucket: bucket_name })
196
+ end
197
+ end
198
+
199
+ # Internal: Update the bucket logging configuration for the bucket.
200
+ #
201
+ # region - the region of the bucket
202
+ # bucket_name - the name of the bucket
203
+ # logging - the logging configuration for the bucket
204
+ def update_logging(region, bucket_name, logging)
205
+ S3.client(region).put_bucket_logging({
206
+ bucket: bucket_name,
207
+ bucket_logging_status: {
208
+ logging_enabled: (logging.to_aws rescue nil)
209
+ }
210
+ })
211
+ end
212
+
213
+ # Internal: Update the bucket versioning for the bucket.
214
+ #
215
+ # region - the region of the bucket
216
+ # bucket_name - the name of the bucket
217
+ # enabled - whether versioning should be enabled or not
218
+ def update_versioning(region, bucket_name, enabled)
219
+ S3.client(region).put_bucket_versioning({
220
+ bucket: bucket_name,
221
+ versioning_configuration: {
222
+ status: if enabled then "Enabled" else "Suspended" end
223
+ }
224
+ })
225
+ end
226
+
227
+ # Internal: Update the permission grants for the bucket.
228
+ #
229
+ # region - the region of the bucket
230
+ # bucket_name - the name of the bucket
231
+ # grants - the grants for the bucket
232
+ def update_grants(region, bucket_name, grants)
233
+ S3.client(region).put_bucket_acl({
234
+ bucket: bucket_name,
235
+ access_control_policy: {
236
+ grants: grants.values.map(&:to_aws).flatten,
237
+ owner: S3.full_bucket(bucket_name).acl.owner
238
+ }
239
+ })
240
+ end
241
+
242
+ # Internal: Update the lifecycle rules for the bucket.
243
+ #
244
+ # region - the region of the bucket
245
+ # bucket_name - the name of the bucket
246
+ # lifecycle - the lifecycle rules for the bucket
247
+ def update_lifecycle(region, bucket_name, lifecycle)
248
+ if lifecycle.empty?
249
+ S3.client(region).delete_bucket_lifecycle({
250
+ bucket: bucket_name
251
+ })
252
+ else
253
+ S3.client(region).put_bucket_lifecycle({
254
+ bucket: bucket_name,
255
+ lifecycle_configuration: {
256
+ rules: lifecycle.values.map(&:to_aws)
257
+ }
258
+ })
259
+ end
260
+ end
261
+
262
+ # Internal: Update the notification rules for the bucket.
263
+ #
264
+ # bucket_name - the name of the bucket
265
+ # notifications - the notification rules for the bucket
266
+ def update_notifications(region, bucket_name, notifications)
267
+ S3.client(region).put_bucket_notification_configuration({
268
+ bucket: bucket_name,
269
+ notification_configuration: {
270
+ topic_configurations: notifications.values.select { |n| n.type == "sns" }.map(&:to_aws),
271
+ queue_configurations: notifications.values.select { |n| n.type == "sqs" }.map(&:to_aws),
272
+ lambda_function_configurations: notifications.values.select { |n| n.type == "lambda" }.map(&:to_aws)
273
+ }
274
+ })
275
+ end
276
+
277
+ # Internal: Update the replication rules for the bucket.
278
+ #
279
+ # region - the region of the bucket
280
+ # bucket_name - the name of the bucket
281
+ # replication - the replication rules for the bucket
282
+ def update_replication(region, bucket_name, replication)
283
+ if replication
284
+ S3.client(region).put_bucket_replication({
285
+ bucket: bucket_name,
286
+ replication_configuration: replication.to_aws
287
+ })
288
+ else
289
+ S3.client(region).delete_bucket_replication({
290
+ bucket: bucket_name
291
+ })
292
+ end
293
+ end
294
+ end
295
+ end
296
+ end