diff options
-rw-r--r-- | chef-config/lib/chef-config/config.rb | 6 | ||||
-rw-r--r-- | lib/chef/client.rb | 23 | ||||
-rw-r--r-- | lib/chef/data_collector/messages/helpers.rb | 2 | ||||
-rw-r--r-- | lib/chef/node.rb | 1 | ||||
-rw-r--r-- | spec/support/shared/context/client.rb | 1 | ||||
-rw-r--r-- | spec/support/shared/examples/client.rb | 50 | ||||
-rw-r--r-- | spec/unit/client_spec.rb | 1 | ||||
-rw-r--r-- | spec/unit/data_collector/messages/helpers_spec.rb | 9 | ||||
-rw-r--r-- | spec/unit/node_spec.rb | 8 |
9 files changed, 99 insertions, 2 deletions
diff --git a/chef-config/lib/chef-config/config.rb b/chef-config/lib/chef-config/config.rb index 9d11ba9dc4..c467d88f80 100644 --- a/chef-config/lib/chef-config/config.rb +++ b/chef-config/lib/chef-config/config.rb @@ -712,6 +712,12 @@ module ChefConfig # The selected profile when using credentials. default :profile, nil + default :chef_guid_path do + PathHelper.join(config_dir, "chef_guid") + end + + default :chef_guid, nil + # knife configuration data config_context :knife do # XXX: none of these default values are applied to knife (and would create a backcompat diff --git a/lib/chef/client.rb b/lib/chef/client.rb index 6ff2d78ee6..3efaf6f4cf 100644 --- a/lib/chef/client.rb +++ b/lib/chef/client.rb @@ -256,6 +256,8 @@ class Chef enforce_path_sanity run_ohai + generate_guid + register unless Chef::Config[:solo_legacy_mode] register_data_collector_reporter @@ -994,6 +996,27 @@ class Chef Chef::ReservedNames::Win32::Security.has_admin_privileges? end + # Ensure that we have a GUID for this node + # If we've got the proper configuration, we'll simply set that. + # If we're registed with the data collector, we'll migrate that UUID into our configuration and use that + # Otherwise, we'll create a new GUID and save it + def generate_guid + Chef::Config[:chef_guid] ||= + if File.exists?(Chef::Config[:chef_guid_path]) + File.read(Chef::Config[:chef_guid_path]) + else + uuid = UUIDFetcher.node_uuid + File.open(Chef::Config[:chef_guid_path], "w+") do |fh| + fh.write(uuid) + end + uuid + end + end + + class UUIDFetcher + extend Chef::DataCollector::Messages::Helpers + end + # Register the data collector reporter to send event information to the # data collector server def register_data_collector_reporter diff --git a/lib/chef/data_collector/messages/helpers.rb b/lib/chef/data_collector/messages/helpers.rb index e451db2c63..e4eda5ebb2 100644 --- a/lib/chef/data_collector/messages/helpers.rb +++ b/lib/chef/data_collector/messages/helpers.rb @@ -106,7 +106,7 @@ class Chef # @return [String] UUID for the node # def node_uuid - read_node_uuid || generate_node_uuid + Chef::Config[:chef_guid] || read_node_uuid || generate_node_uuid end # diff --git a/lib/chef/node.rb b/lib/chef/node.rb index 496bfedc15..977c2d5e92 100644 --- a/lib/chef/node.rb +++ b/lib/chef/node.rb @@ -330,6 +330,7 @@ class Chef Chef::Log.debug("Platform is #{platform} version #{version}") automatic[:platform] = platform automatic[:platform_version] = version + automatic[:chef_guid] = Chef::Config[:chef_guid] automatic[:name] = name automatic[:chef_environment] = chef_environment end diff --git a/spec/support/shared/context/client.rb b/spec/support/shared/context/client.rb index 19ce82fa15..d92ab3d999 100644 --- a/spec/support/shared/context/client.rb +++ b/spec/support/shared/context/client.rb @@ -162,6 +162,7 @@ shared_context "a client run" do Chef::Config[:cache_path] = windows? ? 'C:\chef' : "/var/chef" Chef::Config[:why_run] = false Chef::Config[:audit_mode] = :enabled + Chef::Config[:chef_guid] = "default-guid" stub_const("Chef::Client::STDOUT_FD", stdout) stub_const("Chef::Client::STDERR_FD", stderr) diff --git a/spec/support/shared/examples/client.rb b/spec/support/shared/examples/client.rb index 3c13cd767e..8ad9f6189a 100644 --- a/spec/support/shared/examples/client.rb +++ b/spec/support/shared/examples/client.rb @@ -14,6 +14,56 @@ shared_examples "a completed run" do expect(node.automatic_attrs[:platform]).to eq(platform) expect(node.automatic_attrs[:platform_version]).to eq(platform_version) end + + describe "setting node GUID" do + let(:chef_guid_path) { "/tmp/chef_guid" } + let(:chef_guid) { "test-test-test" } + let(:metadata_file) { "data_collector_metadata.json" } + let(:metadata_path) { Pathname.new(File.join(Chef::Config[:file_cache_path], metadata_file)).cleanpath.to_s } + let(:file) { instance_double(File) } + + before do + Chef::Config[:chef_guid_path] = chef_guid_path + Chef::Config[:chef_guid] = nil + end + + it "loads from the config" do + expect(File).to receive(:exists?).with(chef_guid_path).and_return(true) + expect(File).to receive(:read).with(chef_guid_path).and_return(chef_guid) + client.run + expect(Chef::Config[:chef_guid]).to eql(chef_guid) + expect(node.automatic_attrs[:chef_guid]).to eql(chef_guid) + end + + it "loads from the data collector config" do + expect(File).to receive(:exists?).with(chef_guid_path).and_return(false) + expect(Chef::FileCache).to receive(:load).with(metadata_file).and_return("{\"node_uuid\": \"#{chef_guid}\"}") + + expect(File).to receive(:open).with(chef_guid_path, "w+").and_yield(file) + expect(file).to receive(:write).with(chef_guid) + + client.run + expect(Chef::Config[:chef_guid]).to eql(chef_guid) + expect(node.automatic_attrs[:chef_guid]).to eql(chef_guid) + end + + it "creates a new one" do + expect(File).to receive(:exists?).with(chef_guid_path).and_return(false) + expect(File).to receive(:exists?).with(metadata_path).and_return(false) + + expect(SecureRandom).to receive(:uuid).and_return(chef_guid).at_least(:once) + + # we'll try and write the generated UUID to the data collector too, and that's ok + allow(File).to receive(:open).with(metadata_path, "w", 420) + + expect(File).to receive(:open).with(chef_guid_path, "w+").and_yield(file) + expect(file).to receive(:write).with(chef_guid) + + client.run + expect(Chef::Config[:chef_guid]).to eql(chef_guid) + expect(node.automatic_attrs[:chef_guid]).to eql(chef_guid) + end + end end shared_examples "a completed run with audit failure" do diff --git a/spec/unit/client_spec.rb b/spec/unit/client_spec.rb index 2aff7b2a71..3b974e7b2a 100644 --- a/spec/unit/client_spec.rb +++ b/spec/unit/client_spec.rb @@ -560,7 +560,6 @@ EOM expect { client.node_name }.to raise_error(Chef::Exceptions::CannotDetermineNodeName) end end - end describe "always attempt to run handlers" do diff --git a/spec/unit/data_collector/messages/helpers_spec.rb b/spec/unit/data_collector/messages/helpers_spec.rb index a241bda699..a2c6753003 100644 --- a/spec/unit/data_collector/messages/helpers_spec.rb +++ b/spec/unit/data_collector/messages/helpers_spec.rb @@ -124,8 +124,16 @@ describe Chef::DataCollector::Messages::Helpers do end describe "#node_uuid" do + context "when the node UUID is available in Chef::Config" do + it "returns the configured value" do + Chef::Config[:chef_guid] = "configured_uuid" + expect(TestMessage.node_uuid).to eq("configured_uuid") + end + end + context "when the node UUID can be read" do it "returns the read-in node UUID" do + Chef::Config[:chef_guid] = nil allow(TestMessage).to receive(:read_node_uuid).and_return("read_uuid") expect(TestMessage.node_uuid).to eq("read_uuid") end @@ -133,6 +141,7 @@ describe Chef::DataCollector::Messages::Helpers do context "when the node UUID cannot be read" do it "generated a new node UUID" do + Chef::Config[:chef_guid] = nil allow(TestMessage).to receive(:read_node_uuid).and_return(nil) allow(TestMessage).to receive(:generate_node_uuid).and_return("generated_uuid") expect(TestMessage.node_uuid).to eq("generated_uuid") diff --git a/spec/unit/node_spec.rb b/spec/unit/node_spec.rb index df85b79fc5..c9f3d7d1d2 100644 --- a/spec/unit/node_spec.rb +++ b/spec/unit/node_spec.rb @@ -953,6 +953,14 @@ describe Chef::Node do expect(node.automatic_attrs[:platform_version]).to eq("23.42") end + it "sets the chef guid attribute correctly" do + guid = Chef::Config[:chef_guid] + Chef::Config[:chef_guid] = "test-guid-guid" + node.consume_external_attrs(@ohai_data, {}) + expect(node.automatic_attrs[:chef_guid]).to eq("test-guid-guid") + Chef::Config[:chef_guid] = guid + end + it "consumes the run list from provided json attributes" do node.consume_external_attrs(@ohai_data, { "run_list" => ["recipe[unicorn]"] }) expect(node.run_list).to eq(["recipe[unicorn]"]) |