diff options
author | Tim Smith <tsmith84@gmail.com> | 2020-09-03 12:24:15 -0700 |
---|---|---|
committer | Tim Smith <tsmith84@gmail.com> | 2020-09-03 12:25:17 -0700 |
commit | ea2d90df45816835eeb753aa4ec0d14583f45e4b (patch) | |
tree | 7ea5f342a3b4a55ed50fb635e07fab2ff12bbbb6 | |
parent | fb4197f19f60740780c35f4ff37adbd493fdb2dc (diff) | |
download | chef-ea2d90df45816835eeb753aa4ec0d14583f45e4b.tar.gz |
chef_client_systemd_timer: Add the ability to set CPUQuota on the chef-client unit
This allows us to set a quota like 50% on everything handled by the chef-client including all the sub-processes like ohai or inspec. I looked at using systemd's nice functionality since that would give us a unified property for all the *nix processes, but that only applies to the chef-client process itself. This is much more powerful and gives users what user's probably really want which is "chef and all its stuff should not consume all the CPU on my host".
Signed-off-by: Tim Smith <tsmith@chef.io>
-rw-r--r-- | kitchen-tests/cookbooks/end_to_end/recipes/linux.rb | 1 | ||||
-rw-r--r-- | lib/chef/resource/chef_client_systemd_timer.rb | 7 | ||||
-rw-r--r-- | spec/unit/resource/chef_client_systemd_timer_spec.rb | 37 |
3 files changed, 44 insertions, 1 deletions
diff --git a/kitchen-tests/cookbooks/end_to_end/recipes/linux.rb b/kitchen-tests/cookbooks/end_to_end/recipes/linux.rb index ba1f5e84f7..95051bcdb6 100644 --- a/kitchen-tests/cookbooks/end_to_end/recipes/linux.rb +++ b/kitchen-tests/cookbooks/end_to_end/recipes/linux.rb @@ -100,6 +100,7 @@ end chef_client_systemd_timer "Run chef-client as a systemd timer" do interval "1hr" + cpu_quote 50 only_if { systemd? } end diff --git a/lib/chef/resource/chef_client_systemd_timer.rb b/lib/chef/resource/chef_client_systemd_timer.rb index fa59798009..e050714a4f 100644 --- a/lib/chef/resource/chef_client_systemd_timer.rb +++ b/lib/chef/resource/chef_client_systemd_timer.rb @@ -98,6 +98,12 @@ class Chef description: "A Hash containing additional arbitrary environment variables under which the systemd timer will be run in the form of `({'ENV_VARIABLE' => 'VALUE'})`.", default: lazy { {} } + property :cpu_quota, [Integer, String], + description: "The systemd CPUQuota to run the #{Chef::Dist::CLIENT} process with. This is a percentage value of the total CPU time available on the system.", + introduced: "16.5", + coerce: proc { |x| Integer(x) }, + callbacks: { "should be an Integer between 1 and 100" => proc { |v| v > 0 && v <= 100 } } + action :add do systemd_unit "#{new_resource.job_name}.service" do content service_content @@ -171,6 +177,7 @@ class Chef } unit["Service"]["ConditionACPower"] = "true" unless new_resource.run_on_battery + unit["Service"]["CPUQuota"] = new_resource.cpu_quota if new_resource.cpu_quota unit["Service"]["Environment"] = new_resource.environment.collect { |k, v| "\"#{k}=#{v}\"" } unless new_resource.environment.empty? unit end diff --git a/spec/unit/resource/chef_client_systemd_timer_spec.rb b/spec/unit/resource/chef_client_systemd_timer_spec.rb index 1866060530..c3d69fcae0 100644 --- a/spec/unit/resource/chef_client_systemd_timer_spec.rb +++ b/spec/unit/resource/chef_client_systemd_timer_spec.rb @@ -33,6 +33,12 @@ describe Chef::Resource::ChefClientSystemdTimer do expect(resource.user).to eql("root") end + it "validates the cpu_quota property input" do + expect { resource.cpu_quota(0) }.to raise_error(Chef::Exceptions::ValidationFailed) + expect { resource.cpu_quota(101) }.to raise_error(Chef::Exceptions::ValidationFailed) + expect { resource.cpu_quota(50) }.not_to raise_error + end + it "builds a default value for chef_binary_path dist values" do expect(resource.chef_binary_path).to eql("/opt/chef/bin/chef-client") end @@ -70,4 +76,33 @@ describe Chef::Resource::ChefClientSystemdTimer do expect(provider.chef_client_cmd).to eql("/opt/chef/bin/chef-client --chef-license accept -c #{root_path}") end end -end + + describe "#service_content" do + it "does not set ConditionACPower if run_on_battery property is set to true (the default)" do + expect(provider.service_content["Service"]).not_to have_key("ConditionACPower") + end + + it "sets ConditionACPower if run_on_battery property is set to false" do + resource.run_on_battery false + expect(provider.service_content["Service"]["ConditionACPower"]).to eq("true") + end + + it "does not set Environment if environment property is empty" do + expect(provider.service_content["Service"]).not_to have_key("Environment") + end + + it "sets Environment if environment property is set" do + resource.environment({ "foo" => "bar" }) + expect(provider.service_content["Service"]["Environment"]).to eq(["\"foo=bar\""]) + end + + it "does not set CPUQuota if cpu_quota property is not set" do + expect(provider.service_content["Service"]).not_to have_key("CPUQuota") + end + + it "sets CPUQuota if cpu_quota property is set" do + resource.cpu_quota 50 + expect(provider.service_content["Service"]["CPUQuota"]).to eq(50) + end + end +end
\ No newline at end of file |