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

Ability to set lifecycle and encryption configuration for buckets. #530

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2743,6 +2743,16 @@ The name of the bucket to managed.

A JSON parsable string of the policy to apply to the bucket.

##### `lifecycle_configuration`

A JSON parsable string of the lifecycle configuration to apply to the bucket.
More https://docs.amazonaws.cn/sdk-for-ruby/v3/api/Aws/S3/Client.html#put_bucket_lifecycle_configuration-instance_method

##### `encryption_configuration`

A JSON parsable string of the encryption configuration to apply to the bucket.
More https://docs.amazonaws.cn/sdk-for-ruby/v3/api/Aws/S3/Client.html#put_bucket_encryption-instance_method

#### Type: sqs_queue

##### `name`
Expand Down
70 changes: 70 additions & 0 deletions lib/puppet/provider/s3_bucket/v2.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ def self.instances
Puppet.debug("An error occurred reading the policy on S3 bucket #{s3_bucket.name}: " + e.message)
end

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

begin
results = s3_client.get_bucket_encryption({bucket: s3_bucket.name})
data[:encryption_configuration] = JSON.pretty_generate(camelize_stringify_keys(results.server_side_encryption_configuration.to_h))
rescue Exception => e
Puppet.debug("An error occurred reading the encryption configuration on S3 bucket #{s3_bucket.name}: " + e.message)
end

new(data)
end
bucket_list.reject {|b| b.nil? }
Expand Down Expand Up @@ -61,4 +75,60 @@ def policy=(value)
})
end

def lifecycle_configuration=(value)
Puppet.debug('Replacing bucket lifecycle configuration')
s3_client.put_bucket_lifecycle_configuration({
bucket: @property_hash[:name],
lifecycle_configuration: underscore_symbolarize_keys(JSON.parse(value))
})
end

def encryption_configuration=(value)
Puppet.debug('Replacing bucket encryption configuration')
s3_client.put_bucket_encryption({
bucket: @property_hash[:name],
server_side_encryption_configuration: underscore_symbolarize_keys(JSON.parse(value))
})
end

end

private

def underscore_symbolarize_keys(obj)
return obj.reduce({}) do |acc, (k, v)|
acc.tap { |m| m[underscore(k).to_sym] = underscore_symbolarize_keys(v) }
end if obj.is_a? Hash

return obj.reduce([]) do |acc, v|
acc << underscore_symbolarize_keys(v); acc
end if obj.is_a? Array

obj
end

def camelize_stringify_keys(obj)
return obj.reduce({}) do |acc, (k, v)|
acc.tap { |m| m[camelize(k.to_s)] = camelize_stringify_keys(v) }
end if obj.is_a? Hash

return obj.reduce([]) do |acc, v|
acc << camelize_stringify_keys(v); acc
end if obj.is_a? Array

obj
end

def underscore(str)
str.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end

def camelize(str)
return "ID" if str == "id"
return "SSEAlgorithm" if str == "sse_algorithm"
str.split(/_/).map(&:capitalize).join
end
43 changes: 40 additions & 3 deletions lib/puppet/type/s3_bucket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,55 @@
newproperty(:policy) do
desc 'The policy document JSON string to apply'
validate do |value|
fail Puppet::Error, 'Policy documents must be JSON strings' unless value.is_a? String
fail Puppet::Error, 'Policy documents must be JSON strings' unless is_valid_json?(value)
end

munge do |value|
begin
data = JSON.parse(value)
JSON.pretty_generate(data)
JSON.pretty_generate(JSON.parse(value))
rescue
fail('Policy string is not valid JSON')
end
end
end

newproperty(:lifecycle_configuration) do
desc 'The lifecycle configuration document JSON string to apply'
validate do |value|
fail Puppet::Error, 'Lifecycle configuration documents must be JSON strings' unless is_valid_json?(value)
end

munge do |value|
begin
JSON.pretty_generate(JSON.parse(value))
rescue
fail('Lifecycle configuration string is not valid JSON')
end
end
end

newproperty(:encryption_configuration) do
desc 'The bucket encryption document JSON string to apply'
validate do |value|
fail Puppet::Error, 'Bucket encryption documents must be JSON strings' unless is_valid_json?(value)
end

munge do |value|
begin
JSON.pretty_generate(JSON.parse(value))
rescue
fail('Bucket encryption string is not valid JSON')
end
end
end

end

private

def is_valid_json?(string)
!!JSON.parse(string)
rescue JSON::ParserError => _e
false
end

37 changes: 35 additions & 2 deletions spec/unit/type/s3_bucket_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,19 @@
:ensure,
:creation_date,
:policy,
:lifecycle_configuration,
]
end

let :valid_attributes do
{
name: 'name',
policy: '{}',
encryption_configuration: '{}',
lifecycle_configuration: '{}'
}
end

it 'should have expected properties' do
properties.each do |property|
expect(type_class.properties.map(&:name)).to be_include(property)
Expand All @@ -42,9 +52,32 @@
}.to raise_error(Puppet::Error, /Empty bucket names are not allowed/)
end

context 'with a valid name' do
context 'with a valid parameters' do
it 'should create a valid instance' do
type_class.new({ name: 'name' })
type_class.new(valid_attributes)
end

[:policy, :encryption_configuration, :lifecycle_configuration].each do |param|
it "should create a valid instance without optional :#{param}" do
type_class.new(valid_attributes.reject! { |k, _v| k == param })
end

it "should require non-blank #{param}" do
expect {
type_class.new(valid_attributes.merge({ param => '' }))
}.to raise_error(Puppet::Error)
end

it "should fail if string is not a valid JSON #{param}" do
expect {
type_class.new(valid_attributes.merge({ param => '<xml>Hi</xml>' }))
}.to raise_error(Puppet::Error)
end

it "should accept any valid JSON #{param}" do
type_class.new(valid_attributes.merge({ param => '{ "hello": "world!" }' }))
end

end
end

Expand Down