Skip to content
This repository was archived by the owner on Jun 5, 2020. It is now read-only.

Commit 99a69e9

Browse files
committed
Ability to set lifecycle and encryption configuration for buckets
Signed-off-by: Andrey Voronkov <[email protected]>
1 parent ddd5fb8 commit 99a69e9

File tree

4 files changed

+132
-15
lines changed

4 files changed

+132
-15
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2743,6 +2743,16 @@ The name of the bucket to managed.
27432743
27442744
A JSON parsable string of the policy to apply to the bucket.
27452745
2746+
##### `lifecycle_configuration`
2747+
2748+
A JSON parsable string of the lifecycle configuration to apply to the bucket.
2749+
More https://docs.amazonaws.cn/sdk-for-ruby/v3/api/Aws/S3/Client.html#put_bucket_lifecycle_configuration-instance_method
2750+
2751+
##### `encryption_configuration`
2752+
2753+
A JSON parsable string of the encryption configuration to apply to the bucket.
2754+
More https://docs.amazonaws.cn/sdk-for-ruby/v3/api/Aws/S3/Client.html#put_bucket_encryption-instance_method
2755+
27462756
#### Type: sqs_queue
27472757
27482758
##### `name`

lib/puppet/provider/s3_bucket/v2.rb

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,18 @@ def self.instances
2626

2727
begin
2828
results = s3_client.get_bucket_lifecycle_configuration({bucket: s3_bucket.name})
29-
data[:lifecycle_configuration] = { lifecycle_configuration: results.to_h }
29+
data[:lifecycle_configuration] = JSON.pretty_generate(camelize_stringify_keys(results.to_h))
3030
rescue Exception => e
3131
Puppet.debug("An error occurred reading the lifecycle configuration on S3 bucket #{s3_bucket.name}: " + e.message)
3232
end
3333

34+
begin
35+
results = s3_client.get_bucket_encryption({bucket: s3_bucket.name})
36+
data[:encryption_configuration] = JSON.pretty_generate(camelize_stringify_keys(results.server_side_encryption_configuration.to_h))
37+
rescue Exception => e
38+
Puppet.debug("An error occurred reading the encryption configuration on S3 bucket #{s3_bucket.name}: " + e.message)
39+
end
40+
3441
new(data)
3542
end
3643
bucket_list.reject {|b| b.nil? }
@@ -72,8 +79,56 @@ def lifecycle_configuration=(value)
7279
Puppet.debug('Replacing bucket lifecycle configuration')
7380
s3_client.put_bucket_lifecycle_configuration({
7481
bucket: @property_hash[:name],
75-
lifecycle_configuration: value[:lifecycle_configuration]
82+
lifecycle_configuration: underscore_symbolarize_keys(JSON.parse(value))
83+
})
84+
end
85+
86+
def encryption_configuration=(value)
87+
Puppet.debug('Replacing bucket encryption configuration')
88+
s3_client.put_bucket_encryption({
89+
bucket: @property_hash[:name],
90+
server_side_encryption_configuration: underscore_symbolarize_keys(JSON.parse(value))
7691
})
7792
end
7893

7994
end
95+
96+
private
97+
98+
def underscore_symbolarize_keys(obj)
99+
return obj.reduce({}) do |acc, (k, v)|
100+
acc.tap { |m| m[underscore(k).to_sym] = underscore_symbolarize_keys(v) }
101+
end if obj.is_a? Hash
102+
103+
return obj.reduce([]) do |acc, v|
104+
acc << underscore_symbolarize_keys(v); acc
105+
end if obj.is_a? Array
106+
107+
obj
108+
end
109+
110+
def camelize_stringify_keys(obj)
111+
return obj.reduce({}) do |acc, (k, v)|
112+
acc.tap { |m| m[camelize(k.to_s)] = camelize_stringify_keys(v) }
113+
end if obj.is_a? Hash
114+
115+
return obj.reduce([]) do |acc, v|
116+
acc << camelize_stringify_keys(v); acc
117+
end if obj.is_a? Array
118+
119+
obj
120+
end
121+
122+
def underscore(str)
123+
str.gsub(/::/, '/').
124+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
125+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
126+
tr("-", "_").
127+
downcase
128+
end
129+
130+
def camelize(str)
131+
return "ID" if str == "id"
132+
return "SSEAlgorithm" if str == "sse_algorithm"
133+
str.split(/_/).map(&:capitalize).join
134+
end

lib/puppet/type/s3_bucket.rb

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,11 @@
2121
end
2222

2323
munge do |value|
24-
JSON.pretty_generate(JSON.parse(value))
25-
rescue
26-
fail('Policy string is not valid JSON')
24+
begin
25+
JSON.pretty_generate(JSON.parse(value))
26+
rescue
27+
fail('Policy string is not valid JSON')
28+
end
2729
end
2830
end
2931

@@ -34,19 +36,36 @@
3436
end
3537

3638
munge do |value|
37-
JSON.pretty_generate(JSON.parse(value))
38-
rescue
39-
fail('Lifecycle configuration string is not valid JSON')
39+
begin
40+
JSON.pretty_generate(JSON.parse(value))
41+
rescue
42+
fail('Lifecycle configuration string is not valid JSON')
43+
end
4044
end
4145
end
4246

43-
private
47+
newproperty(:encryption_configuration) do
48+
desc 'The bucket encryption document JSON string to apply'
49+
validate do |value|
50+
fail Puppet::Error, 'Bucket encryption documents must be JSON strings' unless is_valid_json?(value)
51+
end
4452

45-
def is_valid_json?(string)
46-
!!JSON.parse(string)
47-
rescue JSON::ParserError => _e
48-
false
53+
munge do |value|
54+
begin
55+
JSON.pretty_generate(JSON.parse(value))
56+
rescue
57+
fail('Bucket encryption string is not valid JSON')
58+
end
4959
end
60+
end
5061

5162
end
5263

64+
private
65+
66+
def is_valid_json?(string)
67+
!!JSON.parse(string)
68+
rescue JSON::ParserError => _e
69+
false
70+
end
71+

spec/unit/type/s3_bucket_spec.rb

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,19 @@
1515
:ensure,
1616
:creation_date,
1717
:policy,
18+
:lifecycle_configuration,
1819
]
1920
end
2021

22+
let :valid_attributes do
23+
{
24+
name: 'name',
25+
policy: '{}',
26+
encryption_configuration: '{}',
27+
lifecycle_configuration: '{}'
28+
}
29+
end
30+
2131
it 'should have expected properties' do
2232
properties.each do |property|
2333
expect(type_class.properties.map(&:name)).to be_include(property)
@@ -42,9 +52,32 @@
4252
}.to raise_error(Puppet::Error, /Empty bucket names are not allowed/)
4353
end
4454

45-
context 'with a valid name' do
55+
context 'with a valid parameters' do
4656
it 'should create a valid instance' do
47-
type_class.new({ name: 'name' })
57+
type_class.new(valid_attributes)
58+
end
59+
60+
[:policy, :encryption_configuration, :lifecycle_configuration].each do |param|
61+
it "should create a valid instance without optional :#{param}" do
62+
type_class.new(valid_attributes.reject! { |k, _v| k == param })
63+
end
64+
65+
it "should require non-blank #{param}" do
66+
expect {
67+
type_class.new(valid_attributes.merge({ param => '' }))
68+
}.to raise_error(Puppet::Error)
69+
end
70+
71+
it "should fail if string is not a valid JSON #{param}" do
72+
expect {
73+
type_class.new(valid_attributes.merge({ param => '<xml>Hi</xml>' }))
74+
}.to raise_error(Puppet::Error)
75+
end
76+
77+
it "should accept any valid JSON #{param}" do
78+
type_class.new(valid_attributes.merge({ param => '{ "hello": "world!" }' }))
79+
end
80+
4881
end
4982
end
5083

0 commit comments

Comments
 (0)