diff options
author | Thom May <thom@chef.io> | 2017-04-04 13:56:54 +0100 |
---|---|---|
committer | Thom May <thom@chef.io> | 2017-04-04 14:01:44 +0100 |
commit | 35cf4e57a6d0c44547d0a0ecd69ea64eba33bf38 (patch) | |
tree | 0139d401ce22594e2aa5845c1c9f4151e1c0584c | |
parent | 6c7c5e9de89ab127ce3375240c55f8a3c494566a (diff) | |
download | chef-35cf4e57a6d0c44547d0a0ecd69ea64eba33bf38.tar.gz |
RFC 59: Load Ohai plugins
This adds a new phase in the compilation of the run context, and bubbles
up the ohai object from the client to the run_context.
Signed-off-by: Thom May <thom@chef.io>
-rw-r--r-- | Gemfile | 4 | ||||
-rw-r--r-- | Gemfile.lock | 17 | ||||
-rw-r--r-- | chef-config/lib/chef-config/config.rb | 4 | ||||
-rw-r--r-- | lib/chef/client.rb | 2 | ||||
-rw-r--r-- | lib/chef/event_dispatch/base.rb | 16 | ||||
-rw-r--r-- | lib/chef/node.rb | 5 | ||||
-rw-r--r-- | lib/chef/policy_builder/dynamic.rb | 10 | ||||
-rw-r--r-- | lib/chef/policy_builder/expand_node_object.rb | 10 | ||||
-rw-r--r-- | lib/chef/policy_builder/policyfile.rb | 10 | ||||
-rw-r--r-- | lib/chef/run_context.rb | 5 | ||||
-rw-r--r-- | lib/chef/run_context/cookbook_compiler.rb | 30 | ||||
-rw-r--r-- | spec/functional/resource/base.rb | 2 | ||||
-rw-r--r-- | spec/integration/client/client_spec.rb | 33 |
13 files changed, 122 insertions, 26 deletions
@@ -12,12 +12,12 @@ source "https://rubygems.org" gem "chef", path: "." # tracking master of ohai for chef-13.0 development, this should be able to be deleted after release -gem "ohai", git: "https://github.com/chef/ohai.git" +gem "ohai", git: "https://github.com/chef/ohai.git", branch: "tm/load_additional_plugins" gem "chef-config", path: File.expand_path("../chef-config", __FILE__) if File.exist?(File.expand_path("../chef-config", __FILE__)) gem "rake" gem "bundler" -gem "cheffish", "~> 13" # required for rspec tests +gem "cheffish", "~> 13", git: "https://github.com/chef/cheffish.git", branch: "tm/ohai_run_context"# required for rspec tests group(:omnibus_package) do gem "appbundler" diff --git a/Gemfile.lock b/Gemfile.lock index 8d9447bee3..e6c353ef23 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -15,6 +15,15 @@ GIT rspec_junit_formatter (~> 0.2) GIT + remote: https://github.com/chef/cheffish.git + revision: d088e7a10b4289cfb1410b92388e8bc5972a6be2 + branch: tm/ohai_run_context + specs: + cheffish (13.0.0) + chef-zero (~> 13.0) + net-ssh + +GIT remote: https://github.com/chef/chefstyle.git revision: b2bf89dd11270e169fd2315495c98095d4a19090 branch: master @@ -37,7 +46,8 @@ GIT GIT remote: https://github.com/chef/ohai.git - revision: 58296dc0035e4f94a7b7cdc1db01887a3c3c1e30 + revision: 0b4cab6d491a5b1e52995a65e0039c6fa1ba8e9f + branch: tm/load_additional_plugins specs: ohai (13.0.0) chef-config (>= 12.5.0.alpha.1, < 14) @@ -228,9 +238,6 @@ GEM mixlib-log (~> 1.3) rack (~> 2.0) uuidtools (~> 2.1) - cheffish (13.0.0) - chef-zero (~> 13.0) - net-ssh chefspec (5.4.0) chef (>= 12.0) fauxhai (~> 3.6) @@ -571,7 +578,7 @@ DEPENDENCIES chef! chef-config! chef-sugar - cheffish (~> 13) + cheffish (~> 13)! chefspec chefstyle! cucumber (>= 2.4.0) diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb index 9bffb66eca..7e66bae981 100644 --- a/chef-config/lib/chef-config/config.rb +++ b/chef-config/lib/chef-config/config.rb @@ -450,6 +450,10 @@ module ChefConfig # most of our testing scenarios) default :minimal_ohai, false + # When consuming Ohai plugins from cookbook segments, we place those plugins in this directory. + # Subsequent chef client runs will wipe and re-populate the directory to ensure cleanliness + default(:ohai_segment_plugin_path) { PathHelper.join(config_dir, "ohai", "cookbook_plugins") } + ### # Policyfile Settings # diff --git a/lib/chef/client.rb b/lib/chef/client.rb index b219fdfdd6..af3a7566bb 100644 --- a/lib/chef/client.rb +++ b/lib/chef/client.rb @@ -522,7 +522,7 @@ class Chef # @api private # def policy_builder - @policy_builder ||= Chef::PolicyBuilder::Dynamic.new(node_name, ohai.data, json_attribs, override_runlist, events) + @policy_builder ||= Chef::PolicyBuilder::Dynamic.new(node_name, ohai, json_attribs, override_runlist, events) end # diff --git a/lib/chef/event_dispatch/base.rb b/lib/chef/event_dispatch/base.rb index 926bbe24b5..caad03df49 100644 --- a/lib/chef/event_dispatch/base.rb +++ b/lib/chef/event_dispatch/base.rb @@ -179,6 +179,22 @@ class Chef def library_load_complete end + # Called when an ohai plugin file loading starts + def ohai_plugin_load_start(file_count) + end + + # Called when an ohai plugin file has been loaded + def ohai_plugin_file_loaded(path) + end + + # Called when an ohai plugin file has an error on load. + def ohai_plugin_file_load_failed(path, exception) + end + + # Called when an ohai plugin file loading has finished + def ohai_plugin_load_complete + end + # Called when LWRP loading starts def lwrp_load_start(lwrp_file_count) end diff --git a/lib/chef/node.rb b/lib/chef/node.rb index 92bdb5887b..59958beb9a 100644 --- a/lib/chef/node.rb +++ b/lib/chef/node.rb @@ -329,7 +329,6 @@ class Chef def consume_external_attrs(ohai_data, json_cli_attrs) Chef::Log.debug("Extracting run list from JSON attributes provided on command line") consume_attributes(json_cli_attrs) - self.automatic_attrs = ohai_data platform, version = Chef::Platform.find_platform_and_version(self) @@ -338,6 +337,10 @@ class Chef automatic[:platform_version] = version end + def consume_ohai_data(ohai_data) + self.automatic_attrs = Chef::Mixin::DeepMerge.merge(automatic_attrs, ohai_data) + end + # Consumes the combined run_list and other attributes in +attrs+ def consume_attributes(attrs) normal_attrs_to_merge = consume_run_list(attrs) diff --git a/lib/chef/policy_builder/dynamic.rb b/lib/chef/policy_builder/dynamic.rb index 5b6bc40f9e..929202ab26 100644 --- a/lib/chef/policy_builder/dynamic.rb +++ b/lib/chef/policy_builder/dynamic.rb @@ -35,16 +35,16 @@ class Chef attr_reader :node attr_reader :node_name - attr_reader :ohai_data + attr_reader :ohai attr_reader :json_attribs attr_reader :override_runlist attr_reader :events - def initialize(node_name, ohai_data, json_attribs, override_runlist, events) + def initialize(node_name, ohai, json_attribs, override_runlist, events) @implementation = nil + @ohai = ohai @node_name = node_name - @ohai_data = ohai_data @json_attribs = json_attribs @override_runlist = override_runlist @events = events @@ -152,9 +152,9 @@ class Chef policyfile_attribs_in_node_json? || node_has_policyfile_attrs?(node) || policyfile_compat_mode_config? - @implementation = Policyfile.new(node_name, ohai_data, json_attribs, override_runlist, events) + @implementation = Policyfile.new(node_name, ohai, json_attribs, override_runlist, events) else - @implementation = ExpandNodeObject.new(node_name, ohai_data, json_attribs, override_runlist, events) + @implementation = ExpandNodeObject.new(node_name, ohai, json_attribs, override_runlist, events) end end diff --git a/lib/chef/policy_builder/expand_node_object.rb b/lib/chef/policy_builder/expand_node_object.rb index 26f39e8b73..835b7ab412 100644 --- a/lib/chef/policy_builder/expand_node_object.rb +++ b/lib/chef/policy_builder/expand_node_object.rb @@ -41,15 +41,15 @@ class Chef attr_reader :events attr_reader :node attr_reader :node_name - attr_reader :ohai_data + attr_reader :ohai attr_reader :json_attribs attr_reader :override_runlist attr_reader :run_context attr_reader :run_list_expansion - def initialize(node_name, ohai_data, json_attribs, override_runlist, events) + def initialize(node_name, ohai, json_attribs, override_runlist, events) @node_name = node_name - @ohai_data = ohai_data + @ohai = ohai @json_attribs = json_attribs @override_runlist = override_runlist @events = events @@ -77,7 +77,7 @@ class Chef cookbook_collection.validate! cookbook_collection.install_gems(events) - run_context = Chef::RunContext.new(node, cookbook_collection, @events) + run_context = Chef::RunContext.new(node, cookbook_collection, @events, ohai) else Chef::Cookbook::FileVendor.fetch_from_remote(api_service) cookbook_hash = sync_cookbooks @@ -85,7 +85,7 @@ class Chef cookbook_collection.validate! cookbook_collection.install_gems(events) - run_context = Chef::RunContext.new(node, cookbook_collection, @events) + run_context = Chef::RunContext.new(node, cookbook_collection, @events, ohai) end # TODO: this is really obviously not the place for this diff --git a/lib/chef/policy_builder/policyfile.rb b/lib/chef/policy_builder/policyfile.rb index f84e1dc68e..92dd012688 100644 --- a/lib/chef/policy_builder/policyfile.rb +++ b/lib/chef/policy_builder/policyfile.rb @@ -56,13 +56,13 @@ class Chef attr_reader :events attr_reader :node attr_reader :node_name - attr_reader :ohai_data + attr_reader :ohai attr_reader :json_attribs attr_reader :run_context - def initialize(node_name, ohai_data, json_attribs, override_runlist, events) + def initialize(node_name, ohai, json_attribs, override_runlist, events) @node_name = node_name - @ohai_data = ohai_data + @ohai = ohai @json_attribs = json_attribs @events = events @@ -128,7 +128,7 @@ class Chef # determine which versions of cookbooks to use. node.reset_defaults_and_overrides - node.consume_external_attrs(ohai_data, json_attribs) + node.consume_external_attrs(ohai.data, json_attribs) expand_run_list apply_policyfile_attributes @@ -155,7 +155,7 @@ class Chef cookbook_collection.validate! cookbook_collection.install_gems(events) - run_context = Chef::RunContext.new(node, cookbook_collection, events) + run_context = Chef::RunContext.new(node, cookbook_collection, events, ohai) setup_chef_class(run_context) diff --git a/lib/chef/run_context.rb b/lib/chef/run_context.rb index a606585e80..0d78f66fe6 100644 --- a/lib/chef/run_context.rb +++ b/lib/chef/run_context.rb @@ -149,6 +149,7 @@ class Chef # attr_reader :delayed_actions + attr_reader :ohai # Creates a new Chef::RunContext object and populates its fields. This object gets # used by the Chef Server to generate a fully compiled recipe list for a node. # @@ -158,10 +159,11 @@ class Chef # @param events [EventDispatch::Dispatcher] The event dispatcher for this # run. # - def initialize(node, cookbook_collection, events) + def initialize(node, cookbook_collection, events, ohai) @node = node @cookbook_collection = cookbook_collection @events = events + @ohai = ohai node.run_context = self node.set_cookbook_attribute @@ -603,6 +605,7 @@ ERROR_MESSAGE loaded_recipes loaded_recipes_hash node + ohai open_stream reboot_info reboot_info= diff --git a/lib/chef/run_context/cookbook_compiler.rb b/lib/chef/run_context/cookbook_compiler.rb index 94635be03d..6adee1c109 100644 --- a/lib/chef/run_context/cookbook_compiler.rb +++ b/lib/chef/run_context/cookbook_compiler.rb @@ -57,6 +57,7 @@ class Chef # Run the compile phase of the chef run. Loads files in the following order: # * Libraries + # * Ohai Plugins # * Attributes # * LWRPs # * Resource Definitions @@ -69,6 +70,7 @@ class Chef # #cookbook_order for more information. def compile compile_libraries + install_ohai_plugins compile_attributes compile_lwrps compile_resource_definitions @@ -101,6 +103,21 @@ class Chef @events.library_load_complete end + # Install ohai plugins and ensure that ones not associated with a cookbook + # are properly removed. + def install_ohai_plugins + @events.ohai_plugin_load_start(count_files_by_segment(:ohai)) + FileUtils.rm_rf(Chef::Config[:ohai_segment_plugin_path]) + cookbook_order.each do |cookbook| + install_ohai_plugins_from_cookbook(cookbook) + end + + @run_context.ohai.run_additional_plugins(Chef::Config[:ohai_segment_plugin_path]) + node.consume_ohai_data(@run_context.ohai.data) + + @events.ohai_plugin_load_complete + end + # Loads attributes files from cookbooks. Attributes files are loaded # according to #cookbook_order; within a cookbook, +default.rb+ is loaded # first, then the remaining attributes files in lexical sort order. @@ -185,6 +202,19 @@ class Chef raise end + def install_ohai_plugins_from_cookbook(cookbook_name) + target = Chef::Config[:ohai_segment_plugin_path] + files_in_cookbook_by_segment(cookbook_name, :ohai).each do |filename| + next unless File.extname(filename) == ".rb" + + target_name = File.join(target, cookbook_name.to_s, File.basename(filename)) + Chef::Log.debug "Installing ohai file: #{filename} from #{cookbook_name} to #{target_name}" + + FileUtils.mkdir_p(File.dirname(target_name)) + FileUtils.cp(filename, target_name) + end + end + def load_libraries_from_cookbook(cookbook_name) files_in_cookbook_by_segment(cookbook_name, :libraries).each do |filename| next unless File.extname(filename) == ".rb" diff --git a/spec/functional/resource/base.rb b/spec/functional/resource/base.rb index 38175e81c0..8b9dfa8b2f 100644 --- a/spec/functional/resource/base.rb +++ b/spec/functional/resource/base.rb @@ -23,6 +23,6 @@ def run_context node.default[:platform_version] = ohai[:platform_version] node.default[:os] = ohai[:os] events = Chef::EventDispatch::Dispatcher.new - Chef::RunContext.new(node, {}, events) + Chef::RunContext.new(node, {}, events, Ohai::System.new) end end diff --git a/spec/integration/client/client_spec.rb b/spec/integration/client/client_spec.rb index 2a31638c0f..1cd74a6fd1 100644 --- a/spec/integration/client/client_spec.rb +++ b/spec/integration/client/client_spec.rb @@ -465,6 +465,39 @@ end end end + when_the_repository "has a cookbook with an ohai plugin" do + before do + file "cookbooks/x/recipes/default.rb", <<-RECIPE +file #{path_to('tempfile.txt').inspect} do + content node["english"]["version"] +end + RECIPE + + file "cookbooks/x/ohai/english.rb", <<-OHAI + Ohai.plugin(:English) do + provides 'english' + + collect_data do + english Mash.new + english[:version] = "2014" + end + end + OHAI + + file "config/client.rb", <<EOM +local_mode true +cookbook_path "#{path_to('cookbooks')}" +EOM + end + + it "should run the ohai plugin" do + result = shell_out("#{chef_client} -l debug -c \"#{path_to('config/client.rb')}\" -o 'x::default' --no-fork", :cwd => chef_dir) + result.error! + + expect(IO.read(path_to("tempfile.txt"))).to eq("2014") + end + end + # Fails on appveyor, but works locally on windows and on windows hosts in Ci. context "when using recipe-url", :skip_appveyor do before(:each) do |