Permalink
Browse files

kdbmount: fix updating of plugins (ruby)

Now we carfully check which plugins are currenlty used for mounting
the config file and which plugins should really be used.
  • Loading branch information...
BernhardDenner committed Apr 27, 2017
1 parent 5bfcfbf commit b80dd265da85df131efc033127681c8631f54339
Showing with 159 additions and 50 deletions.
  1. +5 −2 README.md
  2. +94 −41 lib/puppet/provider/kdbmount/ruby.rb
  3. +60 −7 lib/puppet/type/kdbmount.rb
@@ -472,8 +472,11 @@ writing the configuration file.
* `add_recommended_plugins`: If set to true, Elektra will add recommended
plugins to the mounted backend configuration.
Recommended plugins are: sync
Default: false
Recommended plugins are defined by metadata of specified plugins. E.g. the
`hosts` plugins recommends `glob`, `error` and `network`. So, if mounting a
file with the `hosts` plugin and this parameter set to `true` all four
plugins will be used for mounting.
Default: true
Valid values are `true`, `false`, `yes`, `no`.
@@ -91,7 +91,7 @@ def file=(value)
perform_kdb_action backend_root do |mountconf|
if path_key.nil?
raise Puppet::Error.new "path key not found in backend config"
raise Puppet::Error, "path key not found in backend config"
end
path_key.value = @resource[:file]
@@ -122,6 +122,61 @@ def resolver=(value)
# puts "plugins: #{@resource[:plugins]}"
#end
def resolve_plugins(plugins)
result = {}
plugins.each do |plugin|
backend = Kdbtools::MountBackendBuilder.new
backend.add_plugin Kdbtools::PluginSpec.new(plugin)
backend.resolve_needs @resource[:add_recommended_plugins]
backend.to_add.each do |ps|
result[plugin] ||= []
result[plugin] << ps.name
result[plugin] << ps.refname if ps.name != ps.refname
end
end
return result
end
# convert the Puppet given :plugins value to a more suitable
# hash:
# pluginname => plugin config settings
#
# Puppet will give us an array of values, combining plugin names and
# config settings. e.g.
# ["ini", {"delimiter" => " ", "setting2" => "aa"}, "type"]
#
# e.g:
# ini => {
# delimiter => " "
# array => ""
# },
# type => { }
#
def convert_plugin_settings(plugins)
config = {}
cur_plugin = nil
if plugins.is_a? Array and plugins.size == 1 and plugins[0].is_a? Hash
# if we have a single array element and this is a Hash, user has passed
# a Hash object to plugins property
config = plugins[0]
elsif plugins.is_a? Array
plugins.each do |e|
if e.is_a? String
cur_plugin = e
config[e] = {}
elsif e.is_a? Hash
config[cur_plugin] = e
else
raise Puppet::Error, "invalid plugins configuration given"
end
end
end
return config
end
private
# get all active mountpoint
@@ -192,40 +247,6 @@ def self.get_mountoint_plugin_config(backend)
end
# convert the Puppet given :plugins value to a more suitable
# hash:
# pluginname => plugin config settings
#
# Puppet will give us an array of values, combining plugin names and
# config settings. e.g.
# ["ini", {"delimiter" => " ", "setting2" => "aa"}, "type"]
#
# e.g:
# ini => {
# delimiter => " "
# array => ""
# },
# type => { }
#
def convert_plugin_settings(plugins)
config = {}
cur_plugin = nil
if plugins.respond_to? :each
plugins.each do |e|
if e.is_a? String
cur_plugin = e
config[e] = {}
elsif e.is_a? Hash
config[cur_plugin] = e
else
Puppet::Error "invalid plugins configuration given"
end
end
end
return config
end
# helper function to modify Elektra key database
# helps to avoid multiple Kdb.open/close sequences
#
@@ -242,7 +263,7 @@ def perform_kdb_action path, &block
end
# create a new mount point and add it the the existing
# create a new mount point and add it to the existing
# mount config (fetched from system/elektra/mountpoints
# use with perform_kdb_action
#
@@ -267,13 +288,45 @@ def set_mount_backend_config(mountconf)
backend.need_plugin "storage"
#@resource.class.const_get(:RECOMMENDED_PLUGINS).each do |p|
# backend.recommend_plugin p
#end
plugins = convert_plugin_settings(@resource[:plugins])
plugins_to_mount = {}
# for each plugin get all dependent (and if req. recommended) plugins
resolved_plugins = resolve_plugins plugins.keys
plugins.each do |name, config|
# if user has specified a plugin configuration, we have to use this
# plugin for mounting
unless config.empty?
plugins_to_mount[name] = config
end
# check if this plugin would be added by any other plugin through
# dependency or recommends lists.
# If so do not explicetly for mounting, since this might lead to
# ordering or placement errors
use_plugin = true
resolved_plugins.each do |other, depends|
next if other == name
if depends.include? name
use_plugin = false
end
end
if use_plugin
plugins_to_mount[name] = config
end
end
all_used_plugins = resolved_plugins.values.flatten.uniq.sort
if plugins.keys.sort != all_used_plugins
Puppet.notice "#{@resource}: using additional plugins: #{(all_used_plugins - plugins.keys.sort)}"
end
#puts "should plugins: #{plugins}"
#puts "actually used: #{plugins_to_mount}"
plugin_config = convert_plugin_settings(@resource[:plugins])
# add user requested plugins
plugin_config.each do |p_name, p_config|
plugins_to_mount.each do |p_name, p_config|
ps = Kdbtools::PluginSpec.new p_name
p_config.each do |k, v|
ps.append_config Kdb::KeySet.new Kdb::Key.new("user/#{k}", value: v)
@@ -109,20 +109,73 @@
validate do |value|
if value.is_a? String
unless @resource.class.plugin_name_is_valid? value
raise ArgumentError, "'%s' is not a vlid plugin name" % value
raise ArgumentError, "'%s' is not a valid plugin name" % value
end
end
end
# this can't be done here, since we get each value at once for
# munge, thus one munge call for each array entry.
#munge do |plugins|
# # convert plugins array to a hash
#munge do |plugin|
#end
# TODO implement this to allow better plugins handling
#def insync?(value)
# puts "insync? #{value}"
# false
# customized insync? method to handle more complex cases.
# a plugin can have dependencies and can recommend other plugins, therefore
# during mounting a plugin, Elektra might add additional plugins. So the
# is and should in two subsequent runs might differ.
# This method checks,
# - if we have to add a newly specified plugin (not found in the current
# mounted plugin list)
# - if we really have to remove a plugin
# - if plugin config settings have changed
def insync?(is)
#puts "insync? is: #{is}, should #{should}"
return false unless provider.respond_to? :resolve_plugins
# convert to plugins-config Hash
my_is = provider.convert_plugin_settings is
my_should = provider.convert_plugin_settings should
# fist, check if all :should plugins are in :is plugins array
# so, is there a plugin missing?
return false if my_should.keys.any? { |p| not my_is.include? p }
# pass the :should plugins list to libelektra to get a list plugins that
# will be used when mounting is done with these
# (honores :add_recommended_plugins parameter)
resolved = provider.resolve_plugins my_should.keys
will_use_plugins = resolved.values.flatten.uniq
#puts "resolved: #{resolved}"
#puts "will_use_plugins: #{will_use_plugins}"
# now, check if plugins should be removed
# if we have mounted a plugin, which is not in the list of plugins which
# will be used when mounting with the :should plugins, we have to remove
# it
my_is.keys.each do |is_plugin|
return false unless will_use_plugins.include? is_plugin
end
# now do the reverse order, check if all will use are actually used
# (this is possible if someone switches :add_recommended_plugins
# from false to true)
will_use_plugins.each do |p|
return false unless my_is.include? p
end
# finally, check if some plugin configuration has changed
my_should.each do |plugin, config|
return false unless my_is.include? plugin
return false unless my_is[plugin] == config
end
true
end
# TODO: add nice formating messages when changing plugins
#def change_to_s(cur_value, new_value)
# return "changed: will_use_plugins: #{@will_use_plugins}"
#end
end

0 comments on commit b80dd26

Please sign in to comment.