From 21a1a909ffe0819c884c58da7298b49df9099f70 Mon Sep 17 00:00:00 2001 From: Tim Smith Date: Tue, 12 Jun 2018 18:44:23 -0700 Subject: Add chocolatey_config and chocolatey_source resources Allow a user to fully manage chocolatey and get it setup for airgapped environments using chef out of the box. Signed-off-by: Tim Smith --- lib/chef/resource/chocolatey_config.rb | 83 ++++++++++++++++++++++++++++++++ lib/chef/resource/chocolatey_source.rb | 88 ++++++++++++++++++++++++++++++++++ lib/chef/resources.rb | 2 + 3 files changed, 173 insertions(+) create mode 100644 lib/chef/resource/chocolatey_config.rb create mode 100644 lib/chef/resource/chocolatey_source.rb (limited to 'lib') diff --git a/lib/chef/resource/chocolatey_config.rb b/lib/chef/resource/chocolatey_config.rb new file mode 100644 index 0000000000..87ba3af66d --- /dev/null +++ b/lib/chef/resource/chocolatey_config.rb @@ -0,0 +1,83 @@ +# +# Copyright:: 2018, Chef Software, Inc. +# +# 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. +# + +class Chef + class Resource + class ChocolateyConfig < Chef::Resource + preview_resource true + resource_name :chocolatey_config + + description "Use the chocolatey_config resource to add or remove Chocolatey configuration keys." + introduced "14.3" + + property :config_key, String, name_property: true, + description: "The name of the config. We'll use the resource's name if this isn't provided." + + property :value, String, + description: "The value to set." + + load_current_value do + current_val = fetch_config_element(config_key) + current_value_does_not_exist! if current_val.nil? + + config_key config_key + value current_val + end + + # @param [String] id the config name + # @return [String] the element's value field + def fetch_config_element(id) + require "rexml/document" + config_file = 'C:\ProgramData\chocolatey\config\chocolatey.config' + raise "Could not find the Chocolatey config at #{config_file}!" unless ::File.exist?(config_file) + + contents = REXML::Document.new(::File.read(config_file)) + data = REXML::XPath.first(contents, "//config/add[@key=\"#{id}\"]") + data ? data.attribute("value").to_s : nil # REXML just returns nil if it can't find anything so avoid an undefined method error + end + + action :set do + description "Sets a Chocolatey config value." + + raise "#{new_resource}: When adding a Chocolatey config you must pass the 'value' property!" unless new_resource.value + + converge_if_changed do + shell_out!(choco_cmd("set")) + end + end + + action :unset do + description "Unsets a Chocolatey config value." + + if current_resource + converge_by("unset Chocolatey config '#{new_resource.config_key}'") do + shell_out!(choco_cmd("unset")) + end + end + end + + action_class do + # @param [String] action the name of the action to perform + # @return [String] the choco config command string + def choco_cmd(action) + cmd = "C:\\ProgramData\\chocolatey\\bin\\choco config #{action} --name #{new_resource.config_key}" + cmd << " --value #{new_resource.value}" if action == "set" + cmd + end + end + end + end +end diff --git a/lib/chef/resource/chocolatey_source.rb b/lib/chef/resource/chocolatey_source.rb new file mode 100644 index 0000000000..9308a07587 --- /dev/null +++ b/lib/chef/resource/chocolatey_source.rb @@ -0,0 +1,88 @@ +# +# Copyright:: 2018, Chef Software, Inc. +# +# 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. +# + +class Chef + class Resource + class ChocolateySource < Chef::Resource + preview_resource true + resource_name :chocolatey_source + + description "Use the chocolatey_source resource to add or remove Chocolatey sources." + introduced "14.3" + + property :source_name, String, name_property: true + property :source, String + property :bypass_proxy, [TrueClass, FalseClass], default: false + property :priority, Integer, default: 0 + + load_current_value do + element = fetch_source_element(source_name) + current_value_does_not_exist! if element.nil? + + source_name element["id"] + source element["value"] + bypass_proxy element["bypassProxy"] == "true" + priority element["priority"].to_i + end + + # @param [String] id the source name + # @return [REXML::Attributes] finds the source element with the + def fetch_source_element(id) + require "rexml/document" + + config_file = 'C:\ProgramData\chocolatey\config\chocolatey.config' + raise "Could not find the Chocolatey config at #{config_file}!" unless ::File.exist?(config_file) + + config_contents = REXML::Document.new(::File.read(config_file)) + data = REXML::XPath.first(config_contents, "//sources/source[@id=\"#{id}\"]") + data ? data.attributes : nil # REXML just returns nil if it can't find anything so avoid an undefined method error + end + + action :add do + description "Adds a Chocolatey source." + + raise "#{new_resource}: When adding a Chocolatey source you must pass the 'source' property!" unless new_resource.source + + converge_if_changed do + shell_out!(choco_cmd("add")) + end + end + + action :remove do + description "Removes a Chocolatey source." + + if current_resource + converge_by("remove Chocolatey source '#{new_resource.source_name}'") do + shell_out!(choco_cmd("remove")) + end + end + end + + action_class do + # @param [String] action the name of the action to perform + # @return [String] the choco source command string + def choco_cmd(action) + cmd = "C:\\ProgramData\\chocolatey\\bin\\choco source #{action} -n \"#{new_resource.source_name}\"" + if action == "add" + cmd << " -s #{new_resource.source} --priority=#{new_resource.priority}" + cmd << " --bypassproxy" if new_resource.bypass_proxy + end + cmd + end + end + end + end +end diff --git a/lib/chef/resources.rb b/lib/chef/resources.rb index b21f2fe6f7..c13a01c352 100644 --- a/lib/chef/resources.rb +++ b/lib/chef/resources.rb @@ -27,7 +27,9 @@ require "chef/resource/build_essential" require "chef/resource/cookbook_file" require "chef/resource/chef_gem" require "chef/resource/chef_handler" +require "chef/resource/chocolatey_config" require "chef/resource/chocolatey_package" +require "chef/resource/chocolatey_source" require "chef/resource/cron" require "chef/resource/csh" require "chef/resource/directory" -- cgit v1.2.1