puppet-swift/lib/puppet/provider/swift_storage_policy/ruby.rb

236 lines
8.6 KiB
Ruby

# provider for swift_storage_policy resource.
#
Puppet::Type.type(:swift_storage_policy).provide(:ruby) do
mk_resource_methods
# Policy indexes must be unique, the storage policy resource name is its ID.
# Storage policy section headings in swift.conf are of the format "storage-policy:<policy ID>
def policy_title
"storage-policy:#{name}"
end
def create
@property_flush[:ensure] = :present
end
def destroy
@property_flush[:ensure] = :absent
end
def exists?
# If a storage policy exists if it is ensured absent and is also found in swift.conf.
if (resource[:ensure] == :absent) &&
(self.class.storage_policies.include? policy_title)
return true
end
if self.class.storage_policies.include? policy_title
# Return false if settings are removed from swift.conf that do not exist in the puppet resource.
# This resource will then update swift.conf in flush.
return false if remove_storage_policy_settings?
end
@property_hash[:ensure] == :present
end
def flush
# flush is called when policy state in swift.conf does not match what is defined in puppet.
# get all resource settings and store in @property_flush for use in write_policy
# @property_flush is the state the policy should be in.
# @property_hash is the state of the policy in swift.conf
self.class.policy_settings.each do |property_name, _|
@property_flush[property_name] = resource[property_name]
end
# If this policy is set to absent, call write_policy to remove it from swift.conf.
if @property_flush[:ensure] == :absent
write_policy
return
end
# At this point, this is a new policy to write to disk. Or this is a policy
# containing a setting that needs to be updated on disk.
# Write this policy unless:
# - a policy on disk already has this same policy_name or aliases.
# or a policy default setting conflict is found.
if !self.class.instances.empty?
write_policy unless policy_names_conflict? ||
default_policy_defined?
else
write_policy
end
@property_hash = self.class.storage_policy_properties(policy_title)
end
# A hash of property_name => setting_name. property_name used to access
# resource properties. setting_name used in swift.conf storage policy setting.
def self.policy_settings
settings_hash = { policy_name: 'name',
aliases: 'aliases',
policy_type: 'policy_type',
deprecated: 'deprecated',
default: 'default',
ec_type: 'ec_type',
ec_num_data_fragments: 'ec_num_data_fragments',
ec_num_parity_fragments: 'ec_num_parity_fragments',
ec_object_segment_size: 'ec_object_segment_size' }
settings_hash
end
# Read storage policies from disk found in swift.conf
def self.storage_policies
policies = []
config.section_names.each do |section_name|
policies.push(section_name) if section_name.start_with?('storage-policy')
end
policies.sort
policies
end
# Read storage policy settings and values found swift.conf
def self.storage_policy_properties(policy)
policy_properties = {}
policy_properties[:provider] = :ruby
policy_properties[:name] = policy.split(':')[1]
policy_properties[:ensure] = :present
policy_settings.each do |property_name, setting_name|
unless config.get_value(policy, setting_name).nil?
policy_properties[property_name] = config.get_value(policy, setting_name)
end
end
policy_properties
end
def write_policy
if @property_flush[:ensure] == :absent
remove_storage_policy_section
return
end
self.class.policy_settings.each do |property_name, setting_name|
unless @property_flush[property_name].nil?
config.set_value(policy_title, setting_name, @property_flush[property_name])
end
end
config.save
@config = nil
end
# Removes the entire storage policy section header and settings for this instance.
# TODO push a 'remove_section' method into puppet inifile module for the ini_file util.
def remove_storage_policy_section
# Get all settings for this storage policy section and remove them.
@sections = config.instance_variable_get(:@sections_hash)
@sections[policy_title].instance_variable_get(:@existing_settings).each do |setting, _|
config.remove_setting(policy_title, setting)
end
# ini_file tracks an array of section names 'section_names' and a hash of sections 'sections_hash'
# get array of section names and delete this storage policy from it.
@section_names = config.instance_variable_get(:@section_names)
@section_names.delete(policy_title)
# delete the entire section from the sections_hash then save swift.conf
@sections.delete(policy_title)
config.save
end
# Check for storage policy settings found in swift.conf that are not defined
# in puppet and should be removed from the policy. Return True if settings
# were removed. Removing a setting from a policy declaration will remove that
# setting from swift.conf
def remove_storage_policy_settings?
settings_removed = false
# If storage policy settings are found in swift.conf that are not defined,
# remove the setting line.
self.class.storage_policy_properties(policy_title).each do |key, value|
next unless @resource[key] != value
config.remove_setting(policy_title, key.to_s.delete(':'))
config.save
settings_removed = true
end
@config = nil
settings_removed
end
# Compare current policy alias against existing storage policies in swift.conf
# Duplicate alias are not allowed.
def policy_names_conflict?
self.class.instances.each do |policy|
next if policy.policy_title.eql? "storage-policy:#{name}"
# Split policy aliases into an array and add policy name.
# Split resource aliases into an array and add resource policy_name.
# If any intersecting elements exist raise an error alerting on the
# attempt to set a duplicate name/alias.
policy_names = policy.policy_name.split
unless policy.aliases == :absent
policy_names = policy.aliases.split(', ').concat policy.policy_name.split
end
resource_names = resource[:policy_name].split
unless resource[:aliases].nil?
resource_names = resource[:aliases].split(', ').concat resource[:policy_name].split
end
alias_intersection = policy_names & resource_names
next if alias_intersection.empty?
raise Puppet::Error, "Swift_storage_policy[#{resource[:name]}] trying "\
"to set a duplicate name/alias:#{alias_intersection},"\
"this name/alias exists in #{policy.policy_title}\n"
end
false
end
# Check storage policy default settings across resources to verify that:
# - If any policies are defined, exactly one policy must be declared default.
# - Only one policy can be declared the default.
def default_policy_defined?
self.class.instances.each do |policy|
# Don't compare this instance with its copy found on disk.
next if (policy.policy_title.eql? "storage-policy:#{name}") ||
(policy.default == 'false')
case resource[:default]
when 'true'
raise Puppet::Error, "Swift_storage_policy[#{resource[:name]}] can "\
'not set default = true. '\
"default=true already set in a policy #{policy.policy_title}\n"
when 'false'
return false
end
end
return unless resource[:default] == 'false'
raise Puppet::Error, 'All storage policies have set default = false.. '\
'exactly one policy must be declared default = true'
end
def self.instances
storage_policies.collect do |policy|
policy_properties = storage_policy_properties(policy)
new(policy_properties)
end
end
def self.prefetch(resources)
instances.each do |prov|
if resource = resources[prov.name]
resource.provider = prov
end
end
end
def initialize(value = {})
super(value)
@property_flush = {}
end
private
def self.get_swift_conf_file
if File.exists? '/etc/swift/swift.conf'
file = '/etc/swift/swift.conf'
else
file = '/etc/swift/swift.conf'
end
file
end
def config
self.class.config
end
def self.config
@config ||= Puppet::Util::IniFile.new(get_swift_conf_file)
end
end