summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaire McQuin <mcquin@users.noreply.github.com>2015-08-27 09:48:36 -0700
committerClaire McQuin <mcquin@users.noreply.github.com>2015-08-27 09:48:36 -0700
commitffd9a0a0485718846381559946c8b38af7e46c70 (patch)
tree59454d1a4c0e93bf6ac34478e4fff8c6a5fb0bb0
parent0c7303f9cd3ab997bfe174c2741c4d1714ee15bb (diff)
parent79327e416679e74aaf4d57998882950396666edf (diff)
downloadohai-ffd9a0a0485718846381559946c8b38af7e46c70.tar.gz
Merge pull request #613 from chef/mcquin/ohai-config/plugin-config
Plugin configuration
-rw-r--r--DOC_CHANGES.md48
-rw-r--r--lib/ohai/config.rb3
-rw-r--r--lib/ohai/dsl/plugin/versionvii.rb41
-rw-r--r--lib/ohai/exception.rb1
-rw-r--r--lib/ohai/plugin_config.rb46
-rw-r--r--spec/unit/config_spec.rb28
-rw-r--r--spec/unit/dsl/plugin_spec.rb73
-rw-r--r--spec/unit/plugin_config_spec.rb118
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