summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chef-config/lib/chef-config/config.rb6
-rw-r--r--lib/chef/client.rb23
-rw-r--r--lib/chef/data_collector/messages/helpers.rb2
-rw-r--r--lib/chef/node.rb1
-rw-r--r--spec/support/shared/context/client.rb1
-rw-r--r--spec/support/shared/examples/client.rb50
-rw-r--r--spec/unit/client_spec.rb1
-rw-r--r--spec/unit/data_collector/messages/helpers_spec.rb9
-rw-r--r--spec/unit/node_spec.rb8
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]"])