summaryrefslogtreecommitdiff
path: root/lib/chef/resource/alternatives.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/chef/resource/alternatives.rb')
-rw-r--r--lib/chef/resource/alternatives.rb149
1 files changed, 149 insertions, 0 deletions
diff --git a/lib/chef/resource/alternatives.rb b/lib/chef/resource/alternatives.rb
new file mode 100644
index 0000000000..a2f08ad864
--- /dev/null
+++ b/lib/chef/resource/alternatives.rb
@@ -0,0 +1,149 @@
+#
+# Copyright:: 2020, Chef Software Inc.
+# Copyright:: 2016-2020, Virender Khatri
+#
+# License:: Apache License, Version 2.0
+#
+# 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.
+#
+
+require_relative "../resource"
+
+class Chef
+ class Resource
+ class Alternatives < Chef::Resource
+ unified_mode true
+
+ provides(:alternatives) { true }
+
+ description "The alternatives resource allows for configuration of command alternatives in Linux using the alternatives or update-alternatives packages."
+ introduced "16.0"
+
+ property :link_name, String, name_property: true
+ property :link, String, default: lazy { |n| "/usr/bin/#{n.link_name}" }
+ property :path, String
+ property :priority, [String, Integer], coerce: proc { |n| n.to_i }
+
+ def define_resource_requirements
+ requirements.assert(:install) do |a|
+ a.assertion do
+ !new_resource.priority.nil?
+ end
+
+ a.failure_message("Could not set alternatives for #{new_resource.link_name}, you must provide the :priority property")
+ end
+
+ requirements.assert(:install, :set, :remove) do |a|
+ a.assertion do
+ !new_resource.path.nil?
+ end
+
+ a.failure_message("Could not set alternatives for #{new_resource.link_name}, you must provide the :path property")
+ end
+
+ requirements.assert(:install, :set, :remove) do |a|
+ a.assertion do
+ ::File.exist?(new_resource.path)
+ end
+
+ a.whyrun("Assuming file #{new_resource.path} already exists or was created already")
+ a.failure_message("Could not set alternatives for #{new_resource.link_name}, missing #{new_resource.path}")
+ end
+ end
+
+ action :install do
+ if path_priority != new_resource.priority
+ converge_by("adding alternative #{new_resource.link} #{new_resource.link_name} #{new_resource.path} #{new_resource.priority}") do
+ output = shell_out(alternatives_cmd, "--install", new_resource.link, new_resource.link_name, new_resource.path, new_resource.priority)
+ unless output.exitstatus == 0
+ raise "failed to add alternative #{new_resource.link} #{new_resource.link_name} #{new_resource.path} #{new_resource.priority}"
+ end
+ end
+ end
+ end
+
+ action :set do
+ if current_path != new_resource.path
+ converge_by("setting alternative #{new_resource.link_name} #{new_resource.path}") do
+ output = shell_out(alternatives_cmd, "--set", new_resource.link_name, new_resource.path)
+ unless output.exitstatus == 0
+ raise "failed to set alternative #{new_resource.link_name} #{new_resource.path} \n #{output.stdout.strip}"
+ end
+ end
+ end
+ end
+
+ action :remove do
+ if path_exists?
+ converge_by("removing alternative #{new_resource.link_name} #{new_resource.path}") do
+ shell_out(alternatives_cmd, "--remove", new_resource.link_name, new_resource.path)
+ end
+ end
+ end
+
+ action :auto do
+ converge_by("setting auto alternative #{new_resource.link_name}") do
+ shell_out(alternatives_cmd, "--auto", new_resource.link_name)
+ end
+ end
+
+ action :refresh do
+ converge_by("refreshing alternative #{new_resource.link_name}") do
+ shell_out(alternatives_cmd, "--refresh", new_resource.link_name)
+ end
+ end
+
+ action_class do
+ #
+ # @return [String] The appropriate alternatives command based on the platform
+ #
+ def alternatives_cmd
+ if debian?
+ "update-alternatives"
+ else
+ "alternatives"
+ end
+ end
+
+ #
+ # @return [Integer] The current path priority for the link_name alternative
+ #
+ def path_priority
+ # https://rubular.com/r/IcUlEU0mSNaMm3
+ escaped_path = Regexp.new(Regexp.escape("#{new_resource.path} - priority ") + "(.*)")
+ match = shell_out(alternatives_cmd, "--display", new_resource.link_name).stdout.match(escaped_path)
+
+ match.nil? ? nil : match[1].to_i
+ end
+
+ #
+ # @return [String] The current path for the link_name alternative
+ #
+ def current_path
+ # https://rubular.com/r/ylsuvzUtquRPqc
+ match = shell_out(alternatives_cmd, "--display", new_resource.link_name).stdout.match(/link currently points to (.*)/)
+ match[1]
+ end
+
+ #
+ # @return [Boolean] does the path exist for the link_name alternative
+ #
+ def path_exists?
+ # https://rubular.com/r/ogvDdq8h2IKRff
+ escaped_path = Regexp.new(Regexp.escape("#{new_resource.path} - priority"))
+ shell_out(alternatives_cmd, "--display", new_resource.link_name).stdout.match?(escaped_path)
+ end
+ end
+ end
+ end
+end