Merge "Support image property protections configuration"

This commit is contained in:
Zuul 2024-01-09 06:06:07 +00:00 committed by Gerrit Code Review
commit 4a3666c103
9 changed files with 366 additions and 0 deletions

View File

@ -0,0 +1,8 @@
Puppet::Type.type(:glance_property_protections_config).provide(
:ini_setting,
:parent => Puppet::Type.type(:openstack_config).provider(:ini_setting)
) do
def self.file_path
'/etc/glance/property-protections.conf'
end
end

View File

@ -0,0 +1,27 @@
Puppet::Type.newtype(:glance_property_protections_config) do
ensurable
newparam(:name, :namevar => true) do
desc 'Section/setting name to manage from property-protections.conf'
newvalues(/\S+\/\S+/)
end
newparam(:ensure_absent_val) do
desc 'A value that is specified as the value property will behave as if ensure => absent was specified'
defaultto('<SERVICE DEFAULT>')
end
autorequire(:anchor) do
['glance::install::end']
end
newproperty(:value) do
desc 'The value of the setting to be defined.'
munge do |value|
value = value.to_s.strip
value.capitalize! if value =~ /^(true|false)$/i
value
end
end
end

View File

@ -50,6 +50,7 @@ class glance::deps {
Anchor['glance::config::begin'] -> Glance_image_import_config<||> ~> Anchor['glance::config::end']
Anchor['glance::config::begin'] -> Glance_swift_config<||> ~> Anchor['glance::config::end']
Anchor['glance::config::begin'] -> Glance_rootwrap_config<||> ~> Anchor['glance::config::end']
Anchor['glance::config::begin'] -> Glance_property_protections_config<||> ~> Anchor['glance::config::end']
# glance-cache.conf is used by CLI commands so service restart is not needed
Anchor['glance::config::begin'] -> Glance_cache_config<||> -> Anchor['glance::config::end']

View File

@ -0,0 +1,78 @@
# == Class: glance::property_protection
#
# Configure property protection
#
# === Parameters
#
# [*property_protection_rule_format*]
# (Optional) Rule format for property protection.
# Defaults to undef
#
# [*rules*]
# (Optional) Property protection rules
# Defaults to undef
#
# [*purge_config*]
# (Optional) Whether to set only the specified config options
# in the property protections config.
# Defaults to false.
#
class glance::property_protection(
Optional[Enum['roles', 'policies']] $property_protection_rule_format = undef,
Hash[String[1], Hash] $rules = {},
Boolean $purge_config = false,
) {
include glance::deps
include glance::params
resources { 'glance_property_protections_config':
purge => $purge_config,
}
case $property_protection_rule_format {
'roles', 'policies': {
glance_api_config {
'DEFAULT/property_protection_file': value => '/etc/glance/property-protections.conf';
'DEFAULT/property_protection_rule_format': value => $property_protection_rule_format;
}
# NOTE(tkajinam): property-protections.conf is not installed by
# the packages so create the file in advance.
file { '/etc/glance/property-protections.conf':
ensure => 'file',
owner => 'root',
group => $::glance::params::group,
mode => '0640',
require => Anchor['glance::config::begin'],
notify => Anchor['glance::config::end'],
}
$rules.each |$key, $value| {
$value_override = $value['value'] ? {
undef => {},
default => {'value' => join(any2array($value['value']), ',')},
}
create_resources(
'glance_property_protections_config',
{ $key => merge($value, $value_override)}
)
}
File['/etc/glance/property-protections.conf'] -> Glance_property_protections_config<||>
}
default: {
glance_api_config {
'DEFAULT/property_protection_file': value => $facts['os_service_default'];
'DEFAULT/property_protection_rule_format': value => $facts['os_service_default'];
}
file { '/etc/glance/property-protections.conf':
ensure => absent,
require => Anchor['glance::config::begin'],
notify => Anchor['glance::config::end'],
}
}
}
}

View File

@ -0,0 +1,5 @@
---
features:
- |
The new ``glance::property_protections`` class has been added. This class
allows configuration of the image property protections feature.

View File

@ -14,6 +14,7 @@ describe 'basic glance config resource' do
File <||> -> Glance_swift_config <||>
File <||> -> Glance_api_paste_ini <||>
File <||> -> Glance_rootwrap_config <||>
File <||> -> Glance_property_protections_config <||>
file { '/etc/glance' :
ensure => directory,
@ -33,6 +34,9 @@ describe 'basic glance config resource' do
file { '/etc/glance/rootwrap.conf' :
ensure => file,
}
file { '/etc/glance/property-protections.conf' :
ensure => file,
}
glance_api_config { 'DEFAULT/thisshouldexist' :
value => 'foo',
@ -154,6 +158,24 @@ describe 'basic glance config resource' do
value => 'toto',
ensure_absent_val => 'toto',
}
glance_property_protections_config { 'DEFAULT/thisshouldexist' :
value => 'foo',
}
glance_property_protections_config { 'DEFAULT/thisshouldnotexist' :
value => '<SERVICE DEFAULT>',
}
glance_property_protections_config { 'DEFAULT/thisshouldexist2' :
value => '<SERVICE DEFAULT>',
ensure_absent_val => 'toto',
}
glance_property_protections_config { 'DEFAULT/thisshouldnotexist2' :
value => 'toto',
ensure_absent_val => 'toto',
}
EOS
@ -232,5 +254,16 @@ describe 'basic glance config resource' do
it { is_expected.not_to match /thisshouldnotexist/ }
end
end
describe file('/etc/glance/property-protections.conf') do
it { is_expected.to exist }
it { is_expected.to contain('thisshouldexist=foo') }
it { is_expected.to contain('thisshouldexist2=<SERVICE DEFAULT>') }
describe '#content' do
subject { super().content }
it { is_expected.not_to match /thisshouldnotexist/ }
end
end
end
end

View File

@ -0,0 +1,109 @@
require 'spec_helper'
describe 'glance::property_protection' do
shared_examples 'glance::property_protection' do
context 'with defaults' do
it 'configures the property protection parameters' do
is_expected.to contain_glance_api_config('DEFAULT/property_protection_file')
.with_value('<SERVICE DEFAULT>')
is_expected.to contain_glance_api_config('DEFAULT/property_protection_rule_format')
.with_value('<SERVICE DEFAULT>')
end
it 'shoul remove the property protection config file' do
is_expected.to contain_file('/etc/glance/property-protections.conf').with(
:ensure => 'absent',
)
end
end
context 'with parameters (policies format)' do
let :params do
{
:property_protection_rule_format => 'policies',
:rules => {
'^x_.*/create' => { 'value' => 'default' },
'^x_.*/read' => { 'value' => 'default' },
'^x_.*/update' => { 'value' => 'default' },
'^x_.*/delete' => { 'value' => 'default' },
}
}
end
it 'configures the property protection parameters' do
is_expected.to contain_glance_api_config('DEFAULT/property_protection_file')
.with_value('/etc/glance/property-protections.conf')
is_expected.to contain_glance_api_config('DEFAULT/property_protection_rule_format')
.with_value('policies')
end
it 'should configure the property protection config file' do
is_expected.to contain_file('/etc/glance/property-protections.conf').with(
:ensure => 'file',
:owner => 'root',
:group => 'glance',
:mode => '0640',
)
is_expected.to contain_glance_property_protections_config('^x_.*/create')
.with_value('default')
is_expected.to contain_glance_property_protections_config('^x_.*/read')
.with_value('default')
is_expected.to contain_glance_property_protections_config('^x_.*/update')
.with_value('default')
is_expected.to contain_glance_property_protections_config('^x_.*/delete')
.with_value('default')
end
end
context 'with parameters (roles format)' do
let :params do
{
:property_protection_rule_format => 'roles',
:rules => {
'^x_.*/create' => { 'value' => ['admin', 'member', '_member_'] },
'^x_.*/read' => { 'value' => ['admin', 'member', '_member_'] },
'^x_.*/update' => { 'value' => ['admin', 'member', '_member_'] },
'^x_.*/delete' => { 'value' => ['admin', 'member', '_member_'] },
}
}
end
it 'configures the property protection parameters' do
is_expected.to contain_glance_api_config('DEFAULT/property_protection_file')
.with_value('/etc/glance/property-protections.conf')
is_expected.to contain_glance_api_config('DEFAULT/property_protection_rule_format')
.with_value('roles')
end
it 'should configure the property protection config file' do
is_expected.to contain_file('/etc/glance/property-protections.conf').with(
:ensure => 'file',
:owner => 'root',
:group => 'glance',
:mode => '0640',
)
is_expected.to contain_glance_property_protections_config('^x_.*/create')
.with_value('admin,member,_member_')
is_expected.to contain_glance_property_protections_config('^x_.*/read')
.with_value('admin,member,_member_')
is_expected.to contain_glance_property_protections_config('^x_.*/update')
.with_value('admin,member,_member_')
is_expected.to contain_glance_property_protections_config('^x_.*/delete')
.with_value('admin,member,_member_')
end
end
end
on_supported_os({
:supported_os => OSDefaults.get_supported_os
}).each do |os,facts|
context "on #{os}" do
let (:facts) do
facts.merge!(OSDefaults.get_facts())
end
it_behaves_like 'glance::property_protection'
end
end
end

View File

@ -0,0 +1,41 @@
require 'spec_helper'
provider_class = Puppet::Type.type(:glance_property_protections_config).provider(:ini_setting)
describe provider_class do
it 'should default to the default setting when no other one is specified' do
resource = Puppet::Type::Glance_property_protections_config.new(
{:name => 'DEFAULT/foo', :value => 'bar'}
)
provider = provider_class.new(resource)
expect(provider.section).to eq('DEFAULT')
expect(provider.setting).to eq('foo')
end
it 'should allow setting to be set explicitly' do
resource = Puppet::Type::Glance_property_protections_config.new(
{:name => 'dude/foo', :value => 'bar'}
)
provider = provider_class.new(resource)
expect(provider.section).to eq('dude')
expect(provider.setting).to eq('foo')
end
it 'should ensure absent when <SERVICE DEFAULT> is specified as a value' do
resource = Puppet::Type::Glance_property_protections_config.new(
{:name => 'dude/foo', :value => '<SERVICE DEFAULT>'}
)
provider = provider_class.new(resource)
provider.exists?
expect(resource[:ensure]).to eq :absent
end
it 'should ensure absent when value matches ensure_absent_val' do
resource = Puppet::Type::Glance_property_protections_config.new(
{:name => 'dude/foo', :value => 'foo', :ensure_absent_val => 'foo' }
)
provider = provider_class.new(resource)
provider.exists?
expect(resource[:ensure]).to eq :absent
end
end

View File

@ -0,0 +1,64 @@
require 'puppet'
require 'puppet/type/glance_property_protections_config'
describe 'Puppet::Type.type(:glance_property_protections_config)' do
before :each do
@glance_property_protections_config = Puppet::Type.type(:glance_property_protections_config).new(:name => 'DEFAULT/foo', :value => 'bar')
end
it 'should require a name' do
expect {
Puppet::Type.type(:glance_property_protections_config).new({})
}.to raise_error(Puppet::Error, 'Title or name must be provided')
end
it 'should not expect a name with whitespace' do
expect {
Puppet::Type.type(:glance_property_protections_config).new(:name => 'f oo')
}.to raise_error(Puppet::Error, /Parameter name failed/)
end
it 'should fail when there is no section' do
expect {
Puppet::Type.type(:glance_property_protections_config).new(:name => 'foo')
}.to raise_error(Puppet::Error, /Parameter name failed/)
end
it 'should not require a value when ensure is absent' do
Puppet::Type.type(:glance_property_protections_config).new(:name => 'DEFAULT/foo', :ensure => :absent)
end
it 'should accept a valid value' do
@glance_property_protections_config[:value] = 'bar'
expect(@glance_property_protections_config[:value]).to eq('bar')
end
it 'should accept a value with whitespace' do
@glance_property_protections_config[:value] = 'b ar'
expect(@glance_property_protections_config[:value]).to eq('b ar')
end
it 'should accept valid ensure values' do
@glance_property_protections_config[:ensure] = :present
expect(@glance_property_protections_config[:ensure]).to eq(:present)
@glance_property_protections_config[:ensure] = :absent
expect(@glance_property_protections_config[:ensure]).to eq(:absent)
end
it 'should not accept invalid ensure values' do
expect {
@glance_property_protections_config[:ensure] = :latest
}.to raise_error(Puppet::Error, /Invalid value/)
end
it 'should autorequire the package that install the file' do
catalog = Puppet::Resource::Catalog.new
anchor = Puppet::Type.type(:anchor).new(:name => 'glance::install::end')
catalog.add_resource anchor, @glance_property_protections_config
dependency = @glance_property_protections_config.autorequire
expect(dependency.size).to eq(1)
expect(dependency[0].target).to eq(@glance_property_protections_config)
expect(dependency[0].source).to eq(anchor)
end
end