diff options
author | Claire McQuin <mcquin@users.noreply.github.com> | 2015-08-27 09:48:36 -0700 |
---|---|---|
committer | Claire McQuin <mcquin@users.noreply.github.com> | 2015-08-27 09:48:36 -0700 |
commit | ffd9a0a0485718846381559946c8b38af7e46c70 (patch) | |
tree | 59454d1a4c0e93bf6ac34478e4fff8c6a5fb0bb0 | |
parent | 0c7303f9cd3ab997bfe174c2741c4d1714ee15bb (diff) | |
parent | 79327e416679e74aaf4d57998882950396666edf (diff) | |
download | ohai-ffd9a0a0485718846381559946c8b38af7e46c70.tar.gz |
Merge pull request #613 from chef/mcquin/ohai-config/plugin-config
Plugin configuration
-rw-r--r-- | DOC_CHANGES.md | 48 | ||||
-rw-r--r-- | lib/ohai/config.rb | 3 | ||||
-rw-r--r-- | lib/ohai/dsl/plugin/versionvii.rb | 41 | ||||
-rw-r--r-- | lib/ohai/exception.rb | 1 | ||||
-rw-r--r-- | lib/ohai/plugin_config.rb | 46 | ||||
-rw-r--r-- | spec/unit/config_spec.rb | 28 | ||||
-rw-r--r-- | spec/unit/dsl/plugin_spec.rb | 73 | ||||
-rw-r--r-- | spec/unit/plugin_config_spec.rb | 118 |
8 files changed, 358 insertions, 0 deletions
diff --git a/DOC_CHANGES.md b/DOC_CHANGES.md index 81f2c59f..a2d980fc 100644 --- a/DOC_CHANGES.md +++ b/DOC_CHANGES.md @@ -46,3 +46,51 @@ plugin on Linux and OS X. device name. ** `by_mount` similar to the above but indexed by mountpoint. Won't include unmounted filesystems, of course. + +## Configure plugins with ohai.plugin +Add the `ohai.plugin` setting to [Ohai Settings](https://docs.chef.io/config_rb_client.html#ohai-settings): + +> Some plugins support configuration. Configure a plugin using the snake-case +name of the plugin consuming the setting. The snake-case name and any +configuration options are required to be Symbols. + +> Currently, the only way to detect whether or not a plugin supports +configuration is to read the source. Ohai plugins which ship with Chef live in +the plugin directory on [GitHub](https://github.com/chef/ohai/tree/master/lib/ohai). + +> Plugins access configuration options using the `configuration` DSL method. +Each Symbol passed to `configuration` represents a level in that plugin's +configuration Hash. If the `:Foo` plugin accesses `configuration(:bar)` you could add +`ohai.plugin[:foo][:bar] = config_value` to your configuration file. If the `:Foo2` +plugin accesses `configuration(:bar, :baz)`, you could configure it with `ohai.plugin[:foo_2][:bar] = { :baz => config_value }`. + +Add a snippet on plugin configuration to [Custom Plugins](https://docs.chef.io/ohai.html#custom-plugins): + +> ```ruby +Ohai.plugin(:Name) do + # ... + collect_data do + if configuration(option, *options) + # ... + end + if configuration(option, *options) == value + # ... + end + end +end +``` +* `configuration(option, *options)` accesses this plugin's configuration settings. + +Add a subsection on plugin configuration to [Ohai DSL Methods](https://docs.chef.io/ohai.html#dsl-ohai-methods): + +> Access plugin configuration settings within a `collect_data` block using the +`configuration` method. `configuration` takes one or more Symbols as the option +or path to the option accessed. +> +> Examples: +> * In the `collect_data` block of `:FooPlugin`, `configuration(:option)` accesses +`Ohai.config[:plugin][:foo_plugin][:option]`, which can be set by `ohai.plugin[:foo_plugin][:option] = value` in a user's configuration file. +> * In the `collect_data` block of `:FooPlugin`, `configuration(:option, :suboption)` +accesses `Ohai.config[:plugin][:foo_plugin][:option][:suboption]`, which can be +set by `ohai.plugin[:foo_plugin][:option] = { :suboption => value }` in a user's +configuration file. diff --git a/lib/ohai/config.rb b/lib/ohai/config.rb index fa0cc8e9..8dea7f98 100644 --- a/lib/ohai/config.rb +++ b/lib/ohai/config.rb @@ -18,7 +18,9 @@ # require 'chef-config/config' +require 'ohai/exception' require 'ohai/log' +require 'ohai/plugin_config' module Ohai Config = ChefConfig::Config @@ -93,6 +95,7 @@ module Ohai default :hints_path, Ohai::Config.default_hints_path default :log_level, :auto default :log_location, STDERR + default :plugin, Ohai::PluginConfig.new { |h, k| h[k] = Ohai::PluginConfig.new } default :plugin_path, Ohai::Config.default_plugin_path end diff --git a/lib/ohai/dsl/plugin/versionvii.rb b/lib/ohai/dsl/plugin/versionvii.rb index fdf7fd7c..2e24322b 100644 --- a/lib/ohai/dsl/plugin/versionvii.rb +++ b/lib/ohai/dsl/plugin/versionvii.rb @@ -100,6 +100,47 @@ module Ohai def require_plugin(*args) Ohai::Log.warn("[UNSUPPORTED OPERATION] \'require_plugin\' is no longer supported. Please use \'depends\' instead.\nIgnoring plugin(s) #{args.join(", ")}") end + + def configuration(option, *options) + return nil if plugin_config.nil? || !plugin_config.key?(option) + value = plugin_config[option] + options.each do |opt| + return nil unless value.key?(opt) + value = value[opt] + end + value + end + + private + def plugin_config + @plugin_config ||= fetch_plugin_config + end + + def fetch_plugin_config + # DMI => ["DMI"] + # Memory => ["", "Memory"] + # NetworkListeners => ["", "Network", "", "Listeners"] + # SSHHostKey => ["SSH", "Host", "", "Key"] + parts = self.name.to_s.split(/([A-Z][a-z]+)/) + # ["DMI"] => ["DMI"] + # ["", "Memory"] => ["Memory"] + # ["", "Network", "", "Listeners"] => ["Network", "Listeners"] + # ["SSH", "Host", "", "Key"] => ["SSH", "Host", "Key"] + parts.delete_if { |part| part.empty? } + # ["DMI"] => :dmi + # ["Memory"] => :memory + # ["Network", "Listeners"] => :network_listeners + # ["SSH", "Host", "Key"] => :ssh_host_key + snake_case_name = parts.map { |part| part.downcase }.join("_").to_sym + + # Plugin names in config hashes are auto-vivified, so we check with + # key? to avoid falsely instantiating a configuration hash. + if Ohai.config[:plugin].key?(snake_case_name) + Ohai.config[:plugin][snake_case_name] + else + nil + end + end end end end diff --git a/lib/ohai/exception.rb b/lib/ohai/exception.rb index b40273d2..446d6e2b 100644 --- a/lib/ohai/exception.rb +++ b/lib/ohai/exception.rb @@ -28,5 +28,6 @@ module Ohai class DependencyCycle < Error; end class DependencyNotFound < Error; end class AttributeSyntaxError < Error; end + class PluginConfigError < Error; end end end diff --git a/lib/ohai/plugin_config.rb b/lib/ohai/plugin_config.rb new file mode 100644 index 00000000..65d651cc --- /dev/null +++ b/lib/ohai/plugin_config.rb @@ -0,0 +1,46 @@ +# +# Copyright:: Copyright (c) 2015 Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require 'ohai/exception' + +module Ohai + class PluginConfig < Hash + + def []=(key, value_or_hash) + enforce_symbol(key) + enforce_symbol_keys(value_or_hash) if value_or_hash.is_a?(Hash) + super(key, value_or_hash) + end + + private + + def enforce_symbol(key) + unless key.is_a?(Symbol) + msg = "Expected Symbol, got #{key.inspect}" + raise Ohai::Exceptions::PluginConfigError, msg + end + end + + def enforce_symbol_keys(hash) + hash.each do |key, value| + enforce_symbol(key) + enforce_symbol_keys(value) if value.is_a?(Hash) + end + end + + end +end diff --git a/spec/unit/config_spec.rb b/spec/unit/config_spec.rb index 52538cab..70dd356a 100644 --- a/spec/unit/config_spec.rb +++ b/spec/unit/config_spec.rb @@ -90,6 +90,34 @@ RSpec.describe Ohai::Config do end end + describe "config_context :ohai" do + describe "option :plugin" do + it "gets configured with a value" do + Ohai::Config.ohai[:plugin][:foo] = true + expect(Ohai::Config.ohai[:plugin]).to have_key(:foo) + expect(Ohai::Config.ohai[:plugin][:foo]).to be true + end + + it "gets configured with a Hash" do + value = { :bar => true, :baz => true } + Ohai::Config.ohai[:plugin][:foo] = value + expect(Ohai::Config.ohai[:plugin]).to have_key(:foo) + expect(Ohai::Config.ohai[:plugin][:foo]).to eq(value) + end + + it "raises an error if the plugin name is not a symbol" do + expect { Ohai::Config.ohai[:plugin]["foo"] = false }. + to raise_error(Ohai::Exceptions::PluginConfigError, /Expected Symbol/) + end + + it "raises an error if the value Hash has non-Symbol key" do + value = { :bar => true, "baz" => true } + expect { Ohai::Config.ohai[:plugin][:foo] = value }. + to raise_error(Ohai::Exceptions::PluginConfigError, /Expected Symbol/) + end + end + end + describe "::merge_deprecated_config" do before(:each) do allow(Ohai::Log).to receive(:warn) diff --git a/spec/unit/dsl/plugin_spec.rb b/spec/unit/dsl/plugin_spec.rb index dc4c1681..fa2a7379 100644 --- a/spec/unit/dsl/plugin_spec.rb +++ b/spec/unit/dsl/plugin_spec.rb @@ -293,6 +293,79 @@ describe Ohai::DSL::Plugin::VersionVII do end end + describe "#configuration" do + let(:plugin) do + klass = Ohai.plugin(camel_name) { } + klass.new({}) + end + + shared_examples_for "plugin config lookup" do + it "returns the configuration option value" do + Ohai.config[:plugin][snake_name][:foo] = true + expect(plugin.configuration(:foo)).to eq(true) + end + end + + describe "a plugin named Abc" do + let(:camel_name) { :Abc } + let(:snake_name) { :abc } + + it "returns nil when the plugin is not configured" do + expect(plugin.configuration(:foo)).to eq(nil) + end + + it "does not auto-vivify an un-configured plugin" do + plugin.configuration(:foo) + expect(Ohai.config[:plugin]).to_not have_key(:test) + end + + it "returns nil when the option is not configured" do + Ohai.config[:plugin][snake_name][:foo] = true + expect(plugin.configuration(:bar)).to eq(nil) + end + + it "returns nil when the suboption is not configured" do + Ohai.config[:plugin][snake_name][:foo] = { } + expect(plugin.configuration(:foo, :bar)).to eq(nil) + end + + include_examples "plugin config lookup" + + it "returns the configuration sub-option value" do + Ohai.config[:plugin][snake_name][:foo] = { :bar => true } + expect(plugin.configuration(:foo, :bar)).to eq(true) + end + end + + describe "a plugin named ABC" do + let(:camel_name) { :ABC } + let(:snake_name) { :abc } + + include_examples "plugin config lookup" + end + + describe "a plugin named Abc2" do + let(:camel_name) { :Abc2 } + let(:snake_name) { :abc_2 } + + include_examples "plugin config lookup" + end + + describe "a plugin named AbcAbc" do + let(:camel_name) { :AbcXyz } + let(:snake_name) { :abc_xyz } + + include_examples "plugin config lookup" + end + + describe "a plugin named ABCLmnoXyz" do + let(:camel_name) { :ABCLmnoXyz } + let(:snake_name) { :abc_lmno_xyz } + + include_examples "plugin config lookup" + end + end + it_behaves_like "Ohai::DSL::Plugin" do let(:ohai) { Ohai::System.new } let(:plugin) { Ohai::DSL::Plugin::VersionVII.new(ohai.data) } diff --git a/spec/unit/plugin_config_spec.rb b/spec/unit/plugin_config_spec.rb new file mode 100644 index 00000000..21ea5308 --- /dev/null +++ b/spec/unit/plugin_config_spec.rb @@ -0,0 +1,118 @@ +# +# Copyright:: Copyright (c) 2015 Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +require_relative '../spec_helper' + +require 'ohai/plugin_config' + +describe "Ohai::PluginConfig" do + + describe "#[]=" do + + let(:plugin_config) { Ohai::PluginConfig.new } + + shared_examples_for "success" do + + it "sets the value" do + plugin_config[key] = value + expect(plugin_config).to have_key(key) + expect(plugin_config[key]).to eq(value) + end + + end + + shared_examples_for "failure" do + + it "raises an error" do + expect { plugin_config[key] = value }. + to raise_error(Ohai::Exceptions::PluginConfigError, /Expected Symbol/) + end + + end + + describe "when the key is a Symbol" do + + let(:key) { :foo } + + describe "when the value is a Hash" do + + describe "when all Hash keys are symbols" do + + let(:value) { + { + :bar0 => true, + :bar1 => [ :baz0, :baz1, :baz2 ], + :bar2 => { :qux0 => true, :qux1 => false } + } + } + + include_examples "success" + + end + + describe "when some top-level Hash key is not a symbol" do + + let(:value) { + { + :bar0 => true, + "bar1" => [ :baz0, :baz1, :baz2 ], + :bar2 => { :qux0 => true, :qux1 => false } + } + } + + include_examples "failure" + + end + + describe "when some nested Hash key is not a symbol" do + + let(:value) { + { + :bar0 => true, + :bar1 => [ :baz0, :baz1, :baz2 ], + :bar2 => { :qux0 => true, "qux1" => false } + } + } + + include_examples "failure" + + end + + end + + describe "when the value is not a Hash" do + + let(:value) { true } + + include_examples "success" + + end + + end + + describe "when the key is not a Symbol" do + + let(:key) { "foo" } + let(:value) { false } + + include_examples "failure" + + end + + end + +end |