diff options
author | markgibbons <mark.gibbons@nordstrom.com> | 2017-02-06 07:45:14 -0800 |
---|---|---|
committer | markgibbons <mark.gibbons@nordstrom.com> | 2017-02-06 07:45:14 -0800 |
commit | 87e4d14ccb06053cf2837f5df1f629ae37f6e956 (patch) | |
tree | c320961ca9d052a39c852c102d12ff2a30b68f17 /lib/chef/provider | |
parent | 86713023f8c1f2f0ccc4c96aeb7e43c4ffb10aeb (diff) | |
parent | 58f73322224ecbb363468b81e9169a344ee3f5cf (diff) | |
download | chef-87e4d14ccb06053cf2837f5df1f629ae37f6e956.tar.gz |
Merge branch 'master' of https://github.com/chef/chef into smf_recursive_dependencies
Diffstat (limited to 'lib/chef/provider')
60 files changed, 1485 insertions, 844 deletions
diff --git a/lib/chef/provider/directory.rb b/lib/chef/provider/directory.rb index 619ab5d8b6..1cacc3fcb9 100644 --- a/lib/chef/provider/directory.rb +++ b/lib/chef/provider/directory.rb @@ -138,7 +138,7 @@ class Chef end do_acl_changes do_selinux(true) - load_resource_attributes_from_file(@new_resource) + load_resource_attributes_from_file(@new_resource) unless Chef::Config[:why_run] end def action_delete diff --git a/lib/chef/provider/dsc_resource.rb b/lib/chef/provider/dsc_resource.rb index 0f25065925..026d2ef104 100644 --- a/lib/chef/provider/dsc_resource.rb +++ b/lib/chef/provider/dsc_resource.rb @@ -29,6 +29,7 @@ class Chef super @new_resource = new_resource @module_name = new_resource.module_name + @module_version = new_resource.module_version @reboot_resource = nil end @@ -65,6 +66,13 @@ class Chef a.whyrun err + ["Assuming a previous resource sets the RefreshMode."] a.block_action! end + requirements.assert(:run) do |a| + a.assertion { module_usage_valid? } + err = ["module_name must be supplied along with module_version."] + a.failure_message Chef::Exceptions::DSCModuleNameMissing, + err + a.block_action! + end end protected @@ -92,6 +100,10 @@ class Chef Chef::Platform.supports_refresh_mode_enabled?(node) end + def module_usage_valid? + !(!@module_name && @module_version) + end + def generate_description @converge_description end @@ -148,10 +160,14 @@ class Chef end end + def module_info_object + @module_version.nil? ? module_name : "@{ModuleName='#{module_name}';ModuleVersion='#{@module_version}'}" + end + def invoke_resource(method, output_format = :object) properties = translate_type(@new_resource.properties) switches = "-Method #{method} -Name #{@new_resource.resource}"\ - " -Property #{properties} -Module #{module_name} -Verbose" + " -Property #{properties} -Module #{module_info_object} -Verbose" cmdlet = Chef::Util::Powershell::Cmdlet.new( node, "Invoke-DscResource #{switches}", diff --git a/lib/chef/provider/env/windows.rb b/lib/chef/provider/env/windows.rb index a68c8276e0..a217590af5 100644 --- a/lib/chef/provider/env/windows.rb +++ b/lib/chef/provider/env/windows.rb @@ -36,7 +36,7 @@ class Chef obj.variablevalue = @new_resource.value obj.put_ value = @new_resource.value - value = expand_path(value) if @new_resource.key_name.casecmp("PATH").zero? + value = expand_path(value) if @new_resource.key_name.casecmp("PATH") == 0 ENV[@new_resource.key_name] = value broadcast_env_change end diff --git a/lib/chef/provider/file.rb b/lib/chef/provider/file.rb index 84bb4d1c94..f77986fa03 100644 --- a/lib/chef/provider/file.rb +++ b/lib/chef/provider/file.rb @@ -154,7 +154,7 @@ class Chef do_contents_changes do_acl_changes do_selinux - load_resource_attributes_from_file(@new_resource) + load_resource_attributes_from_file(@new_resource) unless Chef::Config[:why_run] end def action_create_if_missing diff --git a/lib/chef/provider/git.rb b/lib/chef/provider/git.rb index d051bb1d92..a5c5e0d267 100644 --- a/lib/chef/provider/git.rb +++ b/lib/chef/provider/git.rb @@ -65,7 +65,7 @@ class Chef # this can't be recovered from in why-run mode, because nothing that # we do in the course of a run is likely to create a valid target_revision # if we can't resolve it up front. - a.assertion { target_revision != nil } + a.assertion { !target_revision.nil? } a.failure_message Chef::Exceptions::UnresolvableGitReference, "Unable to parse SHA reference for '#{@new_resource.revision}' in repository '#{@new_resource.repository}'. " + "Verify your (case-sensitive) repository URL and revision.\n" + diff --git a/lib/chef/provider/group.rb b/lib/chef/provider/group.rb index 8936bd2031..6751052ae4 100644 --- a/lib/chef/provider/group.rb +++ b/lib/chef/provider/group.rb @@ -39,38 +39,38 @@ class Chef end def load_current_resource - @current_resource = Chef::Resource::Group.new(@new_resource.name) - @current_resource.group_name(@new_resource.group_name) + @current_resource = Chef::Resource::Group.new(new_resource.name) + current_resource.group_name(new_resource.group_name) group_info = nil begin - group_info = Etc.getgrnam(@new_resource.group_name) - rescue ArgumentError => e + group_info = Etc.getgrnam(new_resource.group_name) + rescue ArgumentError @group_exists = false - Chef::Log.debug("#{@new_resource} group does not exist") + Chef::Log.debug("#{new_resource} group does not exist") end if group_info - @new_resource.gid(group_info.gid) unless @new_resource.gid - @current_resource.gid(group_info.gid) - @current_resource.members(group_info.mem) + new_resource.gid(group_info.gid) unless new_resource.gid + current_resource.gid(group_info.gid) + current_resource.members(group_info.mem) end - @current_resource + current_resource end def define_resource_requirements requirements.assert(:modify) do |a| a.assertion { @group_exists } - a.failure_message(Chef::Exceptions::Group, "Cannot modify #{@new_resource} - group does not exist!") - a.whyrun("Group #{@new_resource} does not exist. Unless it would have been created earlier in this run, this attempt to modify it would fail.") + a.failure_message(Chef::Exceptions::Group, "Cannot modify #{new_resource} - group does not exist!") + a.whyrun("Group #{new_resource} does not exist. Unless it would have been created earlier in this run, this attempt to modify it would fail.") end requirements.assert(:all_actions) do |a| # Make sure that the resource doesn't contain any common # user names in the members and exclude_members properties. - if !@new_resource.members.nil? && !@new_resource.excluded_members.nil? - common_members = @new_resource.members & @new_resource.excluded_members + if !new_resource.members.nil? && !new_resource.excluded_members.nil? + common_members = new_resource.members & new_resource.excluded_members a.assertion { common_members.empty? } a.failure_message(Chef::Exceptions::ConflictingMembersInGroup, "Attempting to both add and remove users from a group: '#{common_members.join(', ')}'") # No why-run alternative @@ -86,41 +86,39 @@ class Chef # <false>:: If a change is not required def compare_group @change_desc = [ ] - if @new_resource.gid.to_s != @current_resource.gid.to_s - @change_desc << "change gid #{@current_resource.gid} to #{@new_resource.gid}" + if new_resource.gid.to_s != current_resource.gid.to_s + @change_desc << "change gid #{current_resource.gid} to #{new_resource.gid}" end - if @new_resource.append + if new_resource.append missing_members = [] - @new_resource.members.each do |member| + new_resource.members.each do |member| next if has_current_group_member?(member) validate_member!(member) missing_members << member end - if missing_members.length > 0 - @change_desc << "add missing member(s): #{missing_members.join(", ")}" + unless missing_members.empty? + @change_desc << "add missing member(s): #{missing_members.join(', ')}" end members_to_be_removed = [] - @new_resource.excluded_members.each do |member| + new_resource.excluded_members.each do |member| if has_current_group_member?(member) members_to_be_removed << member end end - if members_to_be_removed.length > 0 - @change_desc << "remove existing member(s): #{members_to_be_removed.join(", ")}" - end - else - if @new_resource.members != @current_resource.members - @change_desc << "replace group members with new list of members" + unless members_to_be_removed.empty? + @change_desc << "remove existing member(s): #{members_to_be_removed.join(', ')}" end + elsif new_resource.members != current_resource.members + @change_desc << "replace group members with new list of members" end !@change_desc.empty? end def has_current_group_member?(member) - @current_resource.members.include?(member) + current_resource.members.include?(member) end def validate_member!(member) @@ -132,44 +130,41 @@ class Chef def action_create case @group_exists when false - converge_by("create group #{@new_resource.group_name}") do + converge_by("create group #{new_resource.group_name}") do create_group - Chef::Log.info("#{@new_resource} created") + Chef::Log.info("#{new_resource} created") end else if compare_group - converge_by(["alter group #{@new_resource.group_name}"] + change_desc) do + converge_by(["alter group #{new_resource.group_name}"] + change_desc) do manage_group - Chef::Log.info("#{@new_resource} altered") + Chef::Log.info("#{new_resource} altered") end end end end def action_remove - if @group_exists - converge_by("remove group #{@new_resource.group_name}") do - remove_group - Chef::Log.info("#{@new_resource} removed") - end + return unless @group_exists + converge_by("remove group #{new_resource.group_name}") do + remove_group + Chef::Log.info("#{new_resource} removed") end end def action_manage - if @group_exists && compare_group - converge_by(["manage group #{@new_resource.group_name}"] + change_desc) do - manage_group - Chef::Log.info("#{@new_resource} managed") - end + return unless @group_exists && compare_group + converge_by(["manage group #{new_resource.group_name}"] + change_desc) do + manage_group + Chef::Log.info("#{new_resource} managed") end end def action_modify - if compare_group - converge_by(["modify group #{@new_resource.group_name}"] + change_desc) do - manage_group - Chef::Log.info("#{@new_resource} modified") - end + return unless compare_group + converge_by(["modify group #{new_resource.group_name}"] + change_desc) do + manage_group + Chef::Log.info("#{new_resource} modified") end end diff --git a/lib/chef/provider/group/aix.rb b/lib/chef/provider/group/aix.rb index 4a02d5ef8c..2db6dc32a7 100644 --- a/lib/chef/provider/group/aix.rb +++ b/lib/chef/provider/group/aix.rb @@ -17,7 +17,6 @@ # require "chef/provider/group/groupadd" -require "chef/mixin/shell_out" class Chef class Provider @@ -33,48 +32,42 @@ class Chef end def create_group - command = "mkgroup" - command << set_options << " #{@new_resource.group_name}" - run_command(:command => command) + shell_out_compact!("mkgroup", set_options, new_resource.group_name) modify_group_members end def manage_group - command = "chgroup" options = set_options - #Usage: chgroup [-R load_module] "attr=value" ... group if options.size > 0 - command << options << " #{@new_resource.group_name}" - run_command(:command => command) + shell_out_compact!("chgroup", options, new_resource.group_name) end modify_group_members end def remove_group - run_command(:command => "rmgroup #{@new_resource.group_name}") + shell_out_compact!("rmgroup", new_resource.group_name) end def add_member(member) - shell_out!("chgrpmem -m + #{member} #{@new_resource.group_name}") + shell_out_compact!("chgrpmem", "-m", "+", member, new_resource.group_name) end def set_members(members) return if members.empty? - shell_out!("chgrpmem -m = #{members.join(',')} #{@new_resource.group_name}") + shell_out_compact!("chgrpmem", "-m", "=", members.join(","), new_resource.group_name) end def remove_member(member) - shell_out!("chgrpmem -m - #{member} #{@new_resource.group_name}") + shell_out_compact!("chgrpmem", "-m", "-", member, new_resource.group_name) end def set_options - opts = "" - { :gid => "id" }.sort { |a, b| a[0] <=> b[0] }.each do |field, option| - if @current_resource.send(field) != @new_resource.send(field) - if @new_resource.send(field) - Chef::Log.debug("#{@new_resource} setting #{field} to #{@new_resource.send(field)}") - opts << " '#{option}=#{@new_resource.send(field)}'" - end + opts = [] + { gid: "id" }.sort { |a, b| a[0] <=> b[0] }.each do |field, option| + next unless current_resource.send(field) != new_resource.send(field) + if new_resource.send(field) + Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field)}") + opts << "#{option}=#{new_resource.send(field)}" end end opts diff --git a/lib/chef/provider/group/dscl.rb b/lib/chef/provider/group/dscl.rb index 00b4ce2b93..71e42b36ba 100644 --- a/lib/chef/provider/group/dscl.rb +++ b/lib/chef/provider/group/dscl.rb @@ -24,12 +24,15 @@ class Chef provides :group, os: "darwin" def dscl(*args) - host = "." - stdout_result = ""; stderr_result = ""; cmd = "dscl #{host} -#{args.join(' ')}" - status = shell_out(cmd) + argdup = args.dup + cmd = argdup.shift + shellcmd = [ "dscl", ".", "-#{cmd}", argdup ] + status = shell_out_compact(shellcmd) + stdout_result = "" + stderr_result = "" status.stdout.each_line { |line| stdout_result << line } status.stderr.each_line { |line| stderr_result << line } - return [cmd, status, stdout_result, stderr_result] + [shellcmd.flatten.compact.join(" "), status, stdout_result, stderr_result] end def safe_dscl(*args) @@ -37,18 +40,18 @@ class Chef return "" if ( args.first =~ /^delete/ ) && ( result[1].exitstatus != 0 ) raise(Chef::Exceptions::Group, "dscl error: #{result.inspect}") unless result[1].exitstatus == 0 raise(Chef::Exceptions::Group, "dscl error: #{result.inspect}") if result[2] =~ /No such key: / - return result[2] + result[2] end def load_current_resource - @current_resource = Chef::Resource::Group.new(@new_resource.name) - @current_resource.group_name(@new_resource.group_name) + @current_resource = Chef::Resource::Group.new(new_resource.name) + current_resource.group_name(new_resource.group_name) group_info = nil begin - group_info = safe_dscl("read /Groups/#{@new_resource.group_name}") + group_info = safe_dscl("read", "/Groups/#{new_resource.group_name}") rescue Chef::Exceptions::Group @group_exists = false - Chef::Log.debug("#{@new_resource} group does not exist") + Chef::Log.debug("#{new_resource} group does not exist") end if group_info @@ -57,21 +60,21 @@ class Chef val.strip! if val case key.downcase when "primarygroupid" - @new_resource.gid(val) unless @new_resource.gid - @current_resource.gid(val) + new_resource.gid(val) unless new_resource.gid + current_resource.gid(val) when "groupmembership" - @current_resource.members(val.split(" ")) + current_resource.members(val.split(" ")) end end end - @current_resource + current_resource end # get a free GID greater than 200 def get_free_gid(search_limit = 1000) gid = nil; next_gid_guess = 200 - groups_gids = safe_dscl("list /Groups gid") + groups_gids = safe_dscl("list", "/Groups", "gid") while next_gid_guess < search_limit + 200 if groups_gids =~ Regexp.new("#{Regexp.escape(next_gid_guess.to_s)}\n") next_gid_guess += 1 @@ -80,51 +83,51 @@ class Chef break end end - return gid || raise("gid not found. Exhausted. Searched #{search_limit} times") + gid || raise("gid not found. Exhausted. Searched #{search_limit} times") end def gid_used?(gid) return false unless gid - groups_gids = safe_dscl("list /Groups gid") - !! ( groups_gids =~ Regexp.new("#{Regexp.escape(gid.to_s)}\n") ) + groups_gids = safe_dscl("list", "/Groups", "gid") + !!( groups_gids =~ Regexp.new("#{Regexp.escape(gid.to_s)}\n") ) end def set_gid - @new_resource.gid(get_free_gid) if [nil, ""].include? @new_resource.gid - raise(Chef::Exceptions::Group, "gid is already in use") if gid_used?(@new_resource.gid) - safe_dscl("create /Groups/#{@new_resource.group_name} PrimaryGroupID #{@new_resource.gid}") + new_resource.gid(get_free_gid) if [nil, ""].include? new_resource.gid + raise(Chef::Exceptions::Group, "gid is already in use") if gid_used?(new_resource.gid) + safe_dscl("create", "/Groups/#{new_resource.group_name}", "PrimaryGroupID", new_resource.gid) end def set_members # First reset the memberships if the append is not set - unless @new_resource.append - Chef::Log.debug("#{@new_resource} removing group members #{@current_resource.members.join(' ')}") unless @current_resource.members.empty? - safe_dscl("create /Groups/#{@new_resource.group_name} GroupMembers ''") # clear guid list - safe_dscl("create /Groups/#{@new_resource.group_name} GroupMembership ''") # clear user list - @current_resource.members([ ]) + unless new_resource.append + Chef::Log.debug("#{new_resource} removing group members #{current_resource.members.join(' ')}") unless current_resource.members.empty? + safe_dscl("create", "/Groups/#{new_resource.group_name}", "GroupMembers", "") # clear guid list + safe_dscl("create", "/Groups/#{new_resource.group_name}", "GroupMembership", "") # clear user list + current_resource.members([ ]) end # Add any members that need to be added - if @new_resource.members && !@new_resource.members.empty? + if new_resource.members && !new_resource.members.empty? members_to_be_added = [ ] - @new_resource.members.each do |member| - members_to_be_added << member if !@current_resource.members.include?(member) + new_resource.members.each do |member| + members_to_be_added << member unless current_resource.members.include?(member) end unless members_to_be_added.empty? - Chef::Log.debug("#{@new_resource} setting group members #{members_to_be_added.join(', ')}") - safe_dscl("append /Groups/#{@new_resource.group_name} GroupMembership #{members_to_be_added.join(' ')}") + Chef::Log.debug("#{new_resource} setting group members #{members_to_be_added.join(', ')}") + safe_dscl("append", "/Groups/#{new_resource.group_name}", "GroupMembership", *members_to_be_added) end end # Remove any members that need to be removed - if @new_resource.excluded_members && !@new_resource.excluded_members.empty? + if new_resource.excluded_members && !new_resource.excluded_members.empty? members_to_be_removed = [ ] - @new_resource.excluded_members.each do |member| - members_to_be_removed << member if @current_resource.members.include?(member) + new_resource.excluded_members.each do |member| + members_to_be_removed << member if current_resource.members.include?(member) end unless members_to_be_removed.empty? - Chef::Log.debug("#{@new_resource} removing group members #{members_to_be_removed.join(', ')}") - safe_dscl("delete /Groups/#{@new_resource.group_name} GroupMembership #{members_to_be_removed.join(' ')}") + Chef::Log.debug("#{new_resource} removing group members #{members_to_be_removed.join(', ')}") + safe_dscl("delete", "/Groups/#{new_resource.group_name}", "GroupMembership", *members_to_be_removed) end end end @@ -132,8 +135,8 @@ class Chef def define_resource_requirements super requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?("/usr/bin/dscl") } - a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/dscl for #{@new_resource.name}" + a.assertion { ::File.exist?("/usr/bin/dscl") } + a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/dscl for #{new_resource.name}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end end @@ -145,24 +148,24 @@ class Chef end def manage_group - if @new_resource.group_name && (@current_resource.group_name != @new_resource.group_name) + if new_resource.group_name && (current_resource.group_name != new_resource.group_name) dscl_create_group end - if @new_resource.gid && (@current_resource.gid != @new_resource.gid) + if new_resource.gid && (current_resource.gid != new_resource.gid) set_gid end - if @new_resource.members || @new_resource.excluded_members + if new_resource.members || new_resource.excluded_members set_members end end def dscl_create_group - safe_dscl("create /Groups/#{@new_resource.group_name}") - safe_dscl("create /Groups/#{@new_resource.group_name} Password '*'") + safe_dscl("create", "/Groups/#{new_resource.group_name}") + safe_dscl("create", "/Groups/#{new_resource.group_name}", "Password", "*") end def remove_group - safe_dscl("delete /Groups/#{@new_resource.group_name}") + safe_dscl("delete", "/Groups/#{new_resource.group_name}") end end end diff --git a/lib/chef/provider/group/gpasswd.rb b/lib/chef/provider/group/gpasswd.rb index dcf526b211..d8aff10d5b 100644 --- a/lib/chef/provider/group/gpasswd.rb +++ b/lib/chef/provider/group/gpasswd.rb @@ -31,26 +31,26 @@ class Chef def define_resource_requirements super requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?("/usr/bin/gpasswd") } - a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/gpasswd for #{@new_resource}" + a.assertion { ::File.exist?("/usr/bin/gpasswd") } + a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/bin/gpasswd for #{new_resource}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end end def set_members(members) - unless members.empty? - shell_out!("gpasswd -M #{members.join(',')} #{@new_resource.group_name}") + if members.empty? + shell_out_compact!("gpasswd", "-M", "", new_resource.group_name) else - shell_out!("gpasswd -M \"\" #{@new_resource.group_name}") + shell_out_compact!("gpasswd", "-M", members.join(","), new_resource.group_name) end end def add_member(member) - shell_out!("gpasswd -a #{member} #{@new_resource.group_name}") + shell_out_compact!("gpasswd", "-a", member, new_resource.group_name) end def remove_member(member) - shell_out!("gpasswd -d #{member} #{@new_resource.group_name}") + shell_out_compact!("gpasswd", "-d", member, new_resource.group_name) end end end diff --git a/lib/chef/provider/group/groupadd.rb b/lib/chef/provider/group/groupadd.rb index 162875f9f1..f73c3b3be9 100644 --- a/lib/chef/provider/group/groupadd.rb +++ b/lib/chef/provider/group/groupadd.rb @@ -35,8 +35,8 @@ class Chef super required_binaries.each do |required_binary| requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?(required_binary) } - a.failure_message Chef::Exceptions::Group, "Could not find binary #{required_binary} for #{@new_resource}" + a.assertion { ::File.exist?(required_binary) } + a.failure_message Chef::Exceptions::Group, "Could not find binary #{required_binary} for #{new_resource}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end end @@ -44,54 +44,49 @@ class Chef # Create the group def create_group - command = "groupadd" - command << set_options - command << groupadd_options - run_command(:command => command) + shell_out_compact!("groupadd", set_options, groupadd_options) modify_group_members end # Manage the group when it already exists def manage_group - command = "groupmod" - command << set_options - run_command(:command => command) + shell_out_compact!("groupmod", set_options) modify_group_members end # Remove the group def remove_group - run_command(:command => "groupdel #{@new_resource.group_name}") + shell_out_compact!("groupdel", new_resource.group_name) end def modify_group_members - if @new_resource.append - if @new_resource.members && !@new_resource.members.empty? + if new_resource.append + if new_resource.members && !new_resource.members.empty? members_to_be_added = [ ] - @new_resource.members.each do |member| - members_to_be_added << member if !@current_resource.members.include?(member) + new_resource.members.each do |member| + members_to_be_added << member unless current_resource.members.include?(member) end members_to_be_added.each do |member| - Chef::Log.debug("#{@new_resource} appending member #{member} to group #{@new_resource.group_name}") + Chef::Log.debug("#{new_resource} appending member #{member} to group #{new_resource.group_name}") add_member(member) end end - if @new_resource.excluded_members && !@new_resource.excluded_members.empty? + if new_resource.excluded_members && !new_resource.excluded_members.empty? members_to_be_removed = [ ] - @new_resource.excluded_members.each do |member| - members_to_be_removed << member if @current_resource.members.include?(member) + new_resource.excluded_members.each do |member| + members_to_be_removed << member if current_resource.members.include?(member) end members_to_be_removed.each do |member| - Chef::Log.debug("#{@new_resource} removing member #{member} from group #{@new_resource.group_name}") + Chef::Log.debug("#{new_resource} removing member #{member} from group #{new_resource.group_name}") remove_member(member) end end else - members_description = @new_resource.members.empty? ? "none" : @new_resource.members.join(", ") - Chef::Log.debug("#{@new_resource} setting group members to: #{members_description}") - set_members(@new_resource.members) + members_description = new_resource.members.empty? ? "none" : new_resource.members.join(", ") + Chef::Log.debug("#{new_resource} setting group members to: #{members_description}") + set_members(new_resource.members) end end @@ -112,23 +107,23 @@ class Chef # ==== Returns # <string>:: A string containing the option and then the quoted value def set_options - opts = "" - { :gid => "-g" }.sort { |a, b| a[0] <=> b[0] }.each do |field, option| - if @current_resource.send(field) != @new_resource.send(field) - if @new_resource.send(field) - opts << " #{option} '#{@new_resource.send(field)}'" - Chef::Log.debug("#{@new_resource} set #{field} to #{@new_resource.send(field)}") - end - end + opts = [] + { gid: "-g" }.sort { |a, b| a[0] <=> b[0] }.each do |field, option| + next unless current_resource.send(field) != new_resource.send(field) + next unless new_resource.send(field) + opts << option + opts << new_resource.send(field) + Chef::Log.debug("#{new_resource} set #{field} to #{new_resource.send(field)}") end - opts << " #{@new_resource.group_name}" + opts << new_resource.group_name + opts end def groupadd_options - opts = "" + opts = [] # Solaris doesn't support system groups. - opts << " -r" if @new_resource.system && !node.platform?("solaris2") - opts << " -o" if @new_resource.non_unique + opts << "-r" if new_resource.system && !node.platform?("solaris2") + opts << "-o" if new_resource.non_unique opts end diff --git a/lib/chef/provider/group/groupmod.rb b/lib/chef/provider/group/groupmod.rb index 295d3b3425..01581e4863 100644 --- a/lib/chef/provider/group/groupmod.rb +++ b/lib/chef/provider/group/groupmod.rb @@ -26,28 +26,26 @@ class Chef def load_current_resource super %w{group user}.each do |binary| - raise Chef::Exceptions::Group, "Could not find binary /usr/sbin/#{binary} for #{@new_resource}" unless ::File.exists?("/usr/sbin/#{binary}") + raise Chef::Exceptions::Group, "Could not find binary /usr/sbin/#{binary} for #{new_resource}" unless ::File.exist?("/usr/sbin/#{binary}") end end # Create the group def create_group - command = "group add" - command << set_options - shell_out!(command) + shell_out_compact!("group", "add", set_options) - add_group_members(@new_resource.members) + add_group_members(new_resource.members) end # Manage the group when it already exists def manage_group - if @new_resource.append + if new_resource.append members_to_be_added = [ ] - if @new_resource.excluded_members && !@new_resource.excluded_members.empty? + if new_resource.excluded_members && !new_resource.excluded_members.empty? # First find out if any member needs to be removed members_to_be_removed = [ ] - @new_resource.excluded_members.each do |member| - members_to_be_removed << member if @current_resource.members.include?(member) + new_resource.excluded_members.each do |member| + members_to_be_removed << member if current_resource.members.include?(member) end unless members_to_be_removed.empty? @@ -56,39 +54,39 @@ class Chef # Capture the members we need to add in # members_to_be_added to be added later on. - @current_resource.members.each do |member| + current_resource.members.each do |member| members_to_be_added << member unless members_to_be_removed.include?(member) end end end - if @new_resource.members && !@new_resource.members.empty? - @new_resource.members.each do |member| - members_to_be_added << member if !@current_resource.members.include?(member) + if new_resource.members && !new_resource.members.empty? + new_resource.members.each do |member| + members_to_be_added << member unless current_resource.members.include?(member) end end - Chef::Log.debug("#{@new_resource} not changing group members, the group has no members to add") if members_to_be_added.empty? + Chef::Log.debug("#{new_resource} not changing group members, the group has no members to add") if members_to_be_added.empty? add_group_members(members_to_be_added) else # We are resetting the members of a group so use the same trick reset_group_membership - Chef::Log.debug("#{@new_resource} setting group members to: none") if @new_resource.members.empty? - add_group_members(@new_resource.members) + Chef::Log.debug("#{new_resource} setting group members to: none") if new_resource.members.empty? + add_group_members(new_resource.members) end end # Remove the group def remove_group - shell_out!("group del #{@new_resource.group_name}") + shell_out_compact!("group", "del", new_resource.group_name) end # Adds a list of usernames to the group using `user mod` def add_group_members(members) - Chef::Log.debug("#{@new_resource} adding members #{members.join(', ')}") if !members.empty? + Chef::Log.debug("#{new_resource} adding members #{members.join(', ')}") unless members.empty? members.each do |user| - shell_out!("user mod -G #{@new_resource.group_name} #{user}") + shell_out_compact!("user", "mod", "-G", new_resource.group_name, user) end end @@ -96,15 +94,11 @@ class Chef # "<name>_bak", create a new group with the same GID and # "<name>", then set correct members on that group def reset_group_membership - rename = "group mod -n #{@new_resource.group_name}_bak #{@new_resource.group_name}" - shell_out!(rename) + shell_out_compact!("group", "mod", "-n", "#{new_resource.group_name}_bak", new_resource.group_name) - create = "group add" - create << set_options(:overwrite_gid => true) - shell_out!(create) + shell_out_compact!("group", "add", set_options(overwrite_gid: true)) - remove = "group del #{@new_resource.group_name}_bak" - shell_out!(remove) + shell_out_compact!("group", "del", "#{new_resource.group_name}_bak") end # Little bit of magic as per Adam's useradd provider to pull and assign the command line flags @@ -112,14 +106,15 @@ class Chef # ==== Returns # <string>:: A string containing the option and then the quoted value def set_options(overwrite_gid = false) - opts = "" - if overwrite_gid || @new_resource.gid && (@current_resource.gid != @new_resource.gid) - opts << " -g '#{@new_resource.gid}'" + opts = [] + if overwrite_gid || new_resource.gid && (current_resource.gid != new_resource.gid) + opts << "-g" + opts << new_resource.gid end if overwrite_gid - opts << " -o" + opts << "-o" end - opts << " #{@new_resource.group_name}" + opts << new_resource.group_name opts end end diff --git a/lib/chef/provider/group/pw.rb b/lib/chef/provider/group/pw.rb index 4fd78b6b31..115ccf3714 100644 --- a/lib/chef/provider/group/pw.rb +++ b/lib/chef/provider/group/pw.rb @@ -30,46 +30,42 @@ class Chef super requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?("/usr/sbin/pw") } - a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/pw for #{@new_resource}" + a.assertion { ::File.exist?("/usr/sbin/pw") } + a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/pw for #{new_resource}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end end # Create the group def create_group - command = "pw groupadd" - command << set_options - - unless @new_resource.members.empty? + command = [ "pw", "groupadd", set_options ] + unless new_resource.members.empty? # pw group[add|mod] -M is used to set the full membership list on a # new or existing group. Because pw groupadd does not support the -m # and -d options used by manage_group, we treat group creation as a # special case and use -M. - Chef::Log.debug("#{@new_resource} setting group members: #{@new_resource.members.join(',')}") - command += " -M #{@new_resource.members.join(',')}" + Chef::Log.debug("#{new_resource} setting group members: #{new_resource.members.join(',')}") + command += [ "-M", new_resource.members.join(",") ] end - run_command(:command => command) + shell_out_compact!(command) end # Manage the group when it already exists def manage_group - command = "pw groupmod" - command << set_options member_options = set_members_options if member_options.empty? - run_command(:command => command) + shell_out_compact!("pw", "groupmod", set_options) else member_options.each do |option| - run_command(:command => command + option) + shell_out_compact!("pw", "groupmod", set_options, option) end end end # Remove the group def remove_group - run_command(:command => "pw groupdel #{@new_resource.group_name}") + shell_out_compact!("pw", "groupdel", new_resource.group_name) end # Little bit of magic as per Adam's useradd provider to pull and assign the command line flags @@ -77,10 +73,11 @@ class Chef # ==== Returns # <string>:: A string containing the option and then the quoted value def set_options - opts = " #{@new_resource.group_name}" - if @new_resource.gid && (@current_resource.gid != @new_resource.gid) - Chef::Log.debug("#{@new_resource}: current gid (#{@current_resource.gid}) doesnt match target gid (#{@new_resource.gid}), changing it") - opts << " -g '#{@new_resource.gid}'" + opts = [ new_resource.group_name ] + if new_resource.gid && (current_resource.gid != new_resource.gid) + Chef::Log.debug("#{new_resource}: current gid (#{current_resource.gid}) doesnt match target gid (#{new_resource.gid}), changing it") + opts << "-g" + opts << new_resource.gid end opts end @@ -91,26 +88,26 @@ class Chef members_to_be_added = [ ] members_to_be_removed = [ ] - if @new_resource.append + if new_resource.append # Append is set so we will only add members given in the # members list and remove members given in the # excluded_members list. - if @new_resource.members && !@new_resource.members.empty? - @new_resource.members.each do |member| - members_to_be_added << member if !@current_resource.members.include?(member) + if new_resource.members && !new_resource.members.empty? + new_resource.members.each do |member| + members_to_be_added << member unless current_resource.members.include?(member) end end - if @new_resource.excluded_members && !@new_resource.excluded_members.empty? - @new_resource.excluded_members.each do |member| - members_to_be_removed << member if @current_resource.members.include?(member) + if new_resource.excluded_members && !new_resource.excluded_members.empty? + new_resource.excluded_members.each do |member| + members_to_be_removed << member if current_resource.members.include?(member) end end else # Append is not set so we're resetting the membership of # the group to the given members. - members_to_be_added = @new_resource.members.dup - @current_resource.members.each do |member| + members_to_be_added = new_resource.members.dup + current_resource.members.each do |member| # No need to re-add a member if it's present in the new # list of members if members_to_be_added.include? member @@ -122,13 +119,13 @@ class Chef end unless members_to_be_added.empty? - Chef::Log.debug("#{@new_resource} adding group members: #{members_to_be_added.join(',')}") - opts << " -m #{members_to_be_added.join(',')}" + Chef::Log.debug("#{new_resource} adding group members: #{members_to_be_added.join(',')}") + opts << [ "-m", members_to_be_added.join(",") ] end unless members_to_be_removed.empty? - Chef::Log.debug("#{@new_resource} removing group members: #{members_to_be_removed.join(',')}") - opts << " -d #{members_to_be_removed.join(',')}" + Chef::Log.debug("#{new_resource} removing group members: #{members_to_be_removed.join(',')}") + opts << [ "-d", members_to_be_removed.join(",") ] end opts diff --git a/lib/chef/provider/group/suse.rb b/lib/chef/provider/group/suse.rb index 71336f9311..0790d2c2d9 100644 --- a/lib/chef/provider/group/suse.rb +++ b/lib/chef/provider/group/suse.rb @@ -33,21 +33,21 @@ class Chef def define_resource_requirements super requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?("/usr/sbin/groupmod") } - a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/groupmod for #{@new_resource.name}" + a.assertion { ::File.exist?("/usr/sbin/groupmod") } + a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/groupmod for #{new_resource.name}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end requirements.assert(:create, :manage, :modify) do |a| a.assertion do begin - to_add(@new_resource.members).all? { |member| Etc.getpwnam(member) } + to_add(new_resource.members).all? { |member| Etc.getpwnam(member) } rescue false end end - a.failure_message Chef::Exceptions::Group, "Could not add users #{to_add(@new_resource.members).join(", ")} to #{@new_resource.group_name}: one of these users does not exist" - a.whyrun "Could not find one of these users: #{to_add(@new_resource.members).join(", ")}. Assuming it will be created by a prior step" + a.failure_message Chef::Exceptions::Group, "Could not add users #{to_add(new_resource.members).join(', ')} to #{new_resource.group_name}: one of these users does not exist" + a.whyrun "Could not find one of these users: #{to_add(new_resource.members).join(', ')}. Assuming it will be created by a prior step" end end @@ -62,19 +62,19 @@ class Chef end def to_add(members) - members - @current_resource.members + members - current_resource.members end def add_member(member) - shell_out!("groupmod -A #{member} #{@new_resource.group_name}") + shell_out_compact!("groupmod", "-A", member, new_resource.group_name) end def to_remove(members) - @current_resource.members - members + current_resource.members - members end def remove_member(member) - shell_out!("groupmod -R #{member} #{@new_resource.group_name}") + shell_out_compact!("groupmod", "-R", member, new_resource.group_name) end end diff --git a/lib/chef/provider/group/usermod.rb b/lib/chef/provider/group/usermod.rb index bef4b667a2..3874f7b4de 100644 --- a/lib/chef/provider/group/usermod.rb +++ b/lib/chef/provider/group/usermod.rb @@ -34,19 +34,19 @@ class Chef super requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?("/usr/sbin/usermod") } - a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/usermod for #{@new_resource}" + a.assertion { ::File.exist?("/usr/sbin/usermod") } + a.failure_message Chef::Exceptions::Group, "Could not find binary /usr/sbin/usermod for #{new_resource}" # No whyrun alternative: this component should be available in the base install of any given system that uses it end requirements.assert(:modify, :manage) do |a| - a.assertion { @new_resource.members.empty? || @new_resource.append } + a.assertion { new_resource.members.empty? || new_resource.append } a.failure_message Chef::Exceptions::Group, "setting group members directly is not supported by #{self}, must set append true in group" # No whyrun alternative - this action is simply not supported. end requirements.assert(:all_actions) do |a| - a.assertion { @new_resource.excluded_members.empty? } + a.assertion { new_resource.excluded_members.empty? } a.failure_message Chef::Exceptions::Group, "excluded_members is not supported by #{self}" # No whyrun alternative - this action is simply not supported. end @@ -57,17 +57,16 @@ class Chef # This provider only supports adding members with # append. Only if the action is create we will go # ahead and add members. - if @new_resource.action.include?(:create) - members.each do |member| - add_member(member) - end - else + unless new_resource.action.include?(:create) raise Chef::Exceptions::UnsupportedAction, "Setting members directly is not supported by #{self}" end + members.each do |member| + add_member(member) + end end def add_member(member) - shell_out!("usermod #{append_flags} #{@new_resource.group_name} #{member}") + shell_out_compact!("usermod", append_flags, new_resource.group_name, member) end def remove_member(member) @@ -81,7 +80,7 @@ class Chef when "openbsd", "netbsd", "aix", "solaris2", "smartos", "omnios" "-G" when "solaris", "suse", "opensuse" - "-a -G" + [ "-a", "-G" ] end end diff --git a/lib/chef/provider/group/windows.rb b/lib/chef/provider/group/windows.rb index 5873e42a6b..c0026bf368 100644 --- a/lib/chef/provider/group/windows.rb +++ b/lib/chef/provider/group/windows.rb @@ -30,26 +30,26 @@ class Chef def initialize(new_resource, run_context) super - @net_group = Chef::Util::Windows::NetGroup.new(@new_resource.group_name) + @net_group = Chef::Util::Windows::NetGroup.new(new_resource.group_name) end def load_current_resource - @current_resource = Chef::Resource::Group.new(@new_resource.name) - @current_resource.group_name(@new_resource.group_name) + @current_resource = Chef::Resource::Group.new(new_resource.name) + current_resource.group_name(new_resource.group_name) members = nil begin members = @net_group.local_get_members - rescue => e + rescue @group_exists = false - Chef::Log.debug("#{@new_resource} group does not exist") + Chef::Log.debug("#{new_resource} group does not exist") end if members - @current_resource.members(members) + current_resource.members(members) end - @current_resource + current_resource end def create_group @@ -58,10 +58,10 @@ class Chef end def manage_group - if @new_resource.append + if new_resource.append members_to_be_added = [ ] - @new_resource.members.each do |member| - members_to_be_added << member if ! has_current_group_member?(member) && validate_member!(member) + new_resource.members.each do |member| + members_to_be_added << member if !has_current_group_member?(member) && validate_member!(member) end # local_add_members will raise ERROR_MEMBER_IN_ALIAS if a @@ -69,19 +69,19 @@ class Chef @net_group.local_add_members(members_to_be_added) unless members_to_be_added.empty? members_to_be_removed = [ ] - @new_resource.excluded_members.each do |member| - member_sid = lookup_account_name(member) + new_resource.excluded_members.each do |member| + lookup_account_name(member) members_to_be_removed << member if has_current_group_member?(member) end @net_group.local_delete_members(members_to_be_removed) unless members_to_be_removed.empty? else - @net_group.local_set_members(@new_resource.members) + @net_group.local_set_members(new_resource.members) end end def has_current_group_member?(member) member_sid = lookup_account_name(member) - @current_resource.members.include?(member_sid) + current_resource.members.include?(member_sid) end def remove_group @@ -97,12 +97,10 @@ class Chef end def lookup_account_name(account_name) - begin - Chef::ReservedNames::Win32::Security.lookup_account_name(locally_qualified_name(account_name))[1].to_s - rescue Chef::Exceptions::Win32APIError - Chef::Log.warn("SID for '#{locally_qualified_name(account_name)}' could not be found") - "" - end + Chef::ReservedNames::Win32::Security.lookup_account_name(locally_qualified_name(account_name))[1].to_s + rescue Chef::Exceptions::Win32APIError + Chef::Log.warn("SID for '#{locally_qualified_name(account_name)}' could not be found") + "" end end diff --git a/lib/chef/provider/ifconfig.rb b/lib/chef/provider/ifconfig.rb index 4cfb257bb9..4f32baaadb 100644 --- a/lib/chef/provider/ifconfig.rb +++ b/lib/chef/provider/ifconfig.rb @@ -58,7 +58,7 @@ class Chef end def load_current_resource - @current_resource = Chef::Resource::Ifconfig.new(@new_resource.name) + @current_resource = Chef::Resource::Ifconfig.new(new_resource.name) @ifconfig_success = true @interfaces = {} @@ -69,27 +69,26 @@ class Chef @int_name = line[0..9].strip @interfaces[@int_name] = { "hwaddr" => (line =~ /(HWaddr)/ ? ($') : "nil").strip.chomp } else - @interfaces[@int_name]["inet_addr"] = (line =~ /inet addr:(\S+)/ ? ($1) : "nil") if line =~ /inet addr:/ - @interfaces[@int_name]["bcast"] = (line =~ /Bcast:(\S+)/ ? ($1) : "nil") if line =~ /Bcast:/ - @interfaces[@int_name]["mask"] = (line =~ /Mask:(\S+)/ ? ($1) : "nil") if line =~ /Mask:/ - @interfaces[@int_name]["mtu"] = (line =~ /MTU:(\S+)/ ? ($1) : "nil") if line =~ /MTU:/ - @interfaces[@int_name]["metric"] = (line =~ /Metric:(\S+)/ ? ($1) : "nil") if line =~ /Metric:/ + @interfaces[@int_name]["inet_addr"] = (line =~ /inet addr:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /inet addr:/ + @interfaces[@int_name]["bcast"] = (line =~ /Bcast:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /Bcast:/ + @interfaces[@int_name]["mask"] = (line =~ /Mask:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /Mask:/ + @interfaces[@int_name]["mtu"] = (line =~ /MTU:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /MTU:/ + @interfaces[@int_name]["metric"] = (line =~ /Metric:(\S+)/ ? Regexp.last_match(1) : "nil") if line =~ /Metric:/ end - if @interfaces.has_key?(@new_resource.device) - @interface = @interfaces.fetch(@new_resource.device) - - @current_resource.target(@new_resource.target) - @current_resource.device(@new_resource.device) - @current_resource.inet_addr(@interface["inet_addr"]) - @current_resource.hwaddr(@interface["hwaddr"]) - @current_resource.bcast(@interface["bcast"]) - @current_resource.mask(@interface["mask"]) - @current_resource.mtu(@interface["mtu"]) - @current_resource.metric(@interface["metric"]) - end + next unless @interfaces.key?(new_resource.device) + @interface = @interfaces.fetch(new_resource.device) + + current_resource.target(new_resource.target) + current_resource.device(new_resource.device) + current_resource.inet_addr(@interface["inet_addr"]) + current_resource.hwaddr(@interface["hwaddr"]) + current_resource.bcast(@interface["bcast"]) + current_resource.mask(@interface["mask"]) + current_resource.mtu(@interface["mtu"]) + current_resource.metric(@interface["metric"]) end - @current_resource + current_resource end def define_resource_requirements @@ -104,14 +103,12 @@ class Chef def action_add # check to see if load_current_resource found interface in ifconfig - unless @current_resource.inet_addr - unless @new_resource.device == loopback_device + unless current_resource.inet_addr + unless new_resource.device == loopback_device command = add_command - converge_by ("run #{command} to add #{@new_resource}") do - run_command( - :command => command - ) - Chef::Log.info("#{@new_resource} added") + converge_by("run #{command.join(' ')} to add #{new_resource}") do + shell_out_compact!(command) + Chef::Log.info("#{new_resource} added") end end end @@ -122,31 +119,25 @@ class Chef def action_enable # check to see if load_current_resource found ifconfig # enables, but does not manage config files - unless @current_resource.inet_addr - unless @new_resource.device == loopback_device - command = enable_command - converge_by ("run #{command} to enable #{@new_resource}") do - run_command( - :command => command - ) - Chef::Log.info("#{@new_resource} enabled") - end - end + return if current_resource.inet_addr + return if new_resource.device == loopback_device + command = enable_command + converge_by("run #{command.join(' ')} to enable #{new_resource}") do + shell_out_compact!(command) + Chef::Log.info("#{new_resource} enabled") end end def action_delete # check to see if load_current_resource found the interface - if @current_resource.device + if current_resource.device command = delete_command - converge_by ("run #{command} to delete #{@new_resource}") do - run_command( - :command => command - ) - Chef::Log.info("#{@new_resource} deleted") + converge_by("run #{command.join(' ')} to delete #{new_resource}") do + shell_out_compact!(command) + Chef::Log.info("#{new_resource} deleted") end else - Chef::Log.debug("#{@new_resource} does not exist - nothing to do") + Chef::Log.debug("#{new_resource} does not exist - nothing to do") end delete_config end @@ -154,21 +145,19 @@ class Chef def action_disable # check to see if load_current_resource found the interface # disables, but leaves config files in place. - if @current_resource.device + if current_resource.device command = disable_command - converge_by ("run #{command} to disable #{@new_resource}") do - run_command( - :command => command - ) - Chef::Log.info("#{@new_resource} disabled") + converge_by("run #{command.join(' ')} to disable #{new_resource}") do + shell_out_compact!(command) + Chef::Log.info("#{new_resource} disabled") end else - Chef::Log.debug("#{@new_resource} does not exist - nothing to do") + Chef::Log.debug("#{new_resource} does not exist - nothing to do") end end def can_generate_config? - ! @config_template.nil? && ! @config_path.nil? + !@config_template.nil? && !@config_path.nil? end def resource_for_config(path) @@ -182,40 +171,40 @@ class Chef config = resource_for_config(@config_path) config.content(template.result(b)) config.run_action(:create) - @new_resource.updated_by_last_action(true) if config.updated? + new_resource.updated_by_last_action(true) if config.updated? end def delete_config return unless can_generate_config? config = resource_for_config(@config_path) config.run_action(:delete) - @new_resource.updated_by_last_action(true) if config.updated? + new_resource.updated_by_last_action(true) if config.updated? end private def add_command - command = "ifconfig #{@new_resource.device} #{@new_resource.target}" - command << " netmask #{@new_resource.mask}" if @new_resource.mask - command << " metric #{@new_resource.metric}" if @new_resource.metric - command << " mtu #{@new_resource.mtu}" if @new_resource.mtu + command = [ "ifconfig", new_resource.device, new_resource.target ] + command += [ "netmask", new_resource.mask ] if new_resource.mask + command += [ "metric", new_resource.metric ] if new_resource.metric + command += [ "mtu", new_resource.mtu ] if new_resource.mtu command end def enable_command - command = "ifconfig #{@new_resource.device} #{@new_resource.target}" - command << " netmask #{@new_resource.mask}" if @new_resource.mask - command << " metric #{@new_resource.metric}" if @new_resource.metric - command << " mtu #{@new_resource.mtu}" if @new_resource.mtu + command = [ "ifconfig", new_resource.device, new_resource.target ] + command += [ "netmask", new_resource.mask ] if new_resource.mask + command += [ "metric", new_resource.metric ] if new_resource.metric + command += [ "mtu", new_resource.mtu ] if new_resource.mtu command end def disable_command - "ifconfig #{@new_resource.device} down" + [ "ifconfig", new_resource.device, "down" ] end def delete_command - "ifconfig #{@new_resource.device} down" + [ "ifconfig", new_resource.device, "down" ] end def loopback_device diff --git a/lib/chef/provider/ifconfig/aix.rb b/lib/chef/provider/ifconfig/aix.rb index 81164db304..788b609fcf 100644 --- a/lib/chef/provider/ifconfig/aix.rb +++ b/lib/chef/provider/ifconfig/aix.rb @@ -25,61 +25,56 @@ class Chef provides :ifconfig, platform: %w{aix} def load_current_resource - @current_resource = Chef::Resource::Ifconfig.new(@new_resource.name) + @current_resource = Chef::Resource::Ifconfig.new(new_resource.name) @interface_exists = false found_interface = false interface = {} - @status = shell_out("ifconfig -a") + @status = shell_out_compact("ifconfig", "-a") @status.stdout.each_line do |line| if !found_interface if line =~ /^(\S+):\sflags=(\S+)/ - # We have interface name, if this is the interface for @current_resource, load info else skip till next interface is found. - if $1 == @new_resource.device + # We have interface name, if this is the interface for current_resource, load info else skip till next interface is found. + if Regexp.last_match(1) == new_resource.device # Found interface found_interface = true @interface_exists = true - @current_resource.target(@new_resource.target) - @current_resource.device($1) - interface[:flags] = $2 - @current_resource.metric($1) if line =~ /metric\s(\S+)/ - end - end - else - # parse interface related information, stop when next interface is found. - if line =~ /^(\S+):\sflags=(\S+)/ - # we are done parsing interface info and hit another one, so stop. - found_interface = false - break - else - if found_interface - # read up interface info - @current_resource.inet_addr($1) if line =~ /inet\s(\S+)\s/ - @current_resource.bcast($1) if line =~ /broadcast\s(\S+)/ - @current_resource.mask(hex_to_dec_netmask($1)) if line =~ /netmask\s(\S+)\s/ + current_resource.target(new_resource.target) + current_resource.device(Regexp.last_match(1)) + interface[:flags] = Regexp.last_match(2) + current_resource.metric(Regexp.last_match(1)) if line =~ /metric\s(\S+)/ end end + elsif line =~ /^(\S+):\sflags=(\S+)/ + # we are done parsing interface info and hit another one, so stop. + found_interface = false + break + elsif found_interface + # read up interface info + current_resource.inet_addr(Regexp.last_match(1)) if line =~ /inet\s(\S+)\s/ + current_resource.bcast(Regexp.last_match(1)) if line =~ /broadcast\s(\S+)/ + current_resource.mask(hex_to_dec_netmask(Regexp.last_match(1))) if line =~ /netmask\s(\S+)\s/ end end - @current_resource + current_resource end private def add_command # ifconfig changes are temporary, chdev persist across reboots. - raise Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action" if @new_resource.metric - command = "chdev -l #{@new_resource.device} -a netaddr=#{@new_resource.name}" - command << " -a netmask=#{@new_resource.mask}" if @new_resource.mask - command << " -a mtu=#{@new_resource.mtu}" if @new_resource.mtu + raise Chef::Exceptions::Ifconfig, "interface metric attribute cannot be set for :add action" if new_resource.metric + command = [ "chdev", "-l", new_resource.device, "-a", "netaddr=#{new_resource.name}" ] + command += [ "-a", "netmask=#{new_resource.mask}" ] if new_resource.mask + command += [ "-a", "mtu=#{new_resource.mtu}" ] if new_resource.mtu command end def delete_command # ifconfig changes are temporary, chdev persist across reboots. - "chdev -l #{@new_resource.device} -a state=down" + [ "chdev", "-l", new_resource.device, "-a", "state=down" ] end def loopback_device diff --git a/lib/chef/provider/ifconfig/debian.rb b/lib/chef/provider/ifconfig/debian.rb index 872b0db152..369c222b7a 100644 --- a/lib/chef/provider/ifconfig/debian.rb +++ b/lib/chef/provider/ifconfig/debian.rb @@ -26,32 +26,32 @@ class Chef provides :ifconfig, platform: %w{ubuntu}, platform_version: ">= 11.10" provides :ifconfig, platform: %w{debian}, platform_version: ">= 7.0" - INTERFACES_FILE = "/etc/network/interfaces" - INTERFACES_DOT_D_DIR = "/etc/network/interfaces.d" + INTERFACES_FILE = "/etc/network/interfaces".freeze + INTERFACES_DOT_D_DIR = "/etc/network/interfaces.d".freeze def initialize(new_resource, run_context) super(new_resource, run_context) @config_template = %{ -<% if @new_resource.device %> -<% if @new_resource.onboot == "yes" %>auto <%= @new_resource.device %><% end %> -<% case @new_resource.bootproto +<% if new_resource.device %> +<% if new_resource.onboot == "yes" %>auto <%= new_resource.device %><% end %> +<% case new_resource.bootproto when "dhcp" %> -iface <%= @new_resource.device %> inet dhcp +iface <%= new_resource.device %> inet dhcp <% when "bootp" %> -iface <%= @new_resource.device %> inet bootp +iface <%= new_resource.device %> inet bootp <% else %> -iface <%= @new_resource.device %> inet static - <% if @new_resource.target %>address <%= @new_resource.target %><% end %> - <% if @new_resource.mask %>netmask <%= @new_resource.mask %><% end %> - <% if @new_resource.network %>network <%= @new_resource.network %><% end %> - <% if @new_resource.bcast %>broadcast <%= @new_resource.bcast %><% end %> - <% if @new_resource.metric %>metric <%= @new_resource.metric %><% end %> - <% if @new_resource.hwaddr %>hwaddress <%= @new_resource.hwaddr %><% end %> - <% if @new_resource.mtu %>mtu <%= @new_resource.mtu %><% end %> +iface <%= new_resource.device %> inet static + <% if new_resource.target %>address <%= new_resource.target %><% end %> + <% if new_resource.mask %>netmask <%= new_resource.mask %><% end %> + <% if new_resource.network %>network <%= new_resource.network %><% end %> + <% if new_resource.bcast %>broadcast <%= new_resource.bcast %><% end %> + <% if new_resource.metric %>metric <%= new_resource.metric %><% end %> + <% if new_resource.hwaddr %>hwaddress <%= new_resource.hwaddr %><% end %> + <% if new_resource.mtu %>mtu <%= new_resource.mtu %><% end %> <% end %> <% end %> } - @config_path = "#{INTERFACES_DOT_D_DIR}/ifcfg-#{@new_resource.device}" + @config_path = "#{INTERFACES_DOT_D_DIR}/ifcfg-#{new_resource.device}" end def generate_config @@ -69,12 +69,13 @@ iface <%= @new_resource.device %> inet static # roll our own file_edit resource, this will not get reported until we have a file_edit resource interfaces_dot_d_for_regexp = INTERFACES_DOT_D_DIR.gsub(/\./, '\.') # escape dots for the regexp regexp = %r{^\s*source\s+#{interfaces_dot_d_for_regexp}/\*\s*$} - unless ::File.exists?(INTERFACES_FILE) && regexp.match(IO.read(INTERFACES_FILE)) - converge_by("modifying #{INTERFACES_FILE} to source #{INTERFACES_DOT_D_DIR}") do - conf = Chef::Util::FileEdit.new(INTERFACES_FILE) - conf.insert_line_if_no_match(regexp, "source #{INTERFACES_DOT_D_DIR}/*") - conf.write_file - end + + return if ::File.exist?(INTERFACES_FILE) && regexp.match(IO.read(INTERFACES_FILE)) + + converge_by("modifying #{INTERFACES_FILE} to source #{INTERFACES_DOT_D_DIR}") do + conf = Chef::Util::FileEdit.new(INTERFACES_FILE) + conf.insert_line_if_no_match(regexp, "source #{INTERFACES_DOT_D_DIR}/*") + conf.write_file end end diff --git a/lib/chef/provider/ifconfig/redhat.rb b/lib/chef/provider/ifconfig/redhat.rb index 0c28e6407a..841e725b94 100644 --- a/lib/chef/provider/ifconfig/redhat.rb +++ b/lib/chef/provider/ifconfig/redhat.rb @@ -27,19 +27,19 @@ class Chef def initialize(new_resource, run_context) super(new_resource, run_context) @config_template = %{ -<% if @new_resource.device %>DEVICE=<%= @new_resource.device %><% end %> -<% if @new_resource.onboot == "yes" %>ONBOOT=<%= @new_resource.onboot %><% end %> -<% if @new_resource.bootproto %>BOOTPROTO=<%= @new_resource.bootproto %><% end %> -<% if @new_resource.target %>IPADDR=<%= @new_resource.target %><% end %> -<% if @new_resource.mask %>NETMASK=<%= @new_resource.mask %><% end %> -<% if @new_resource.network %>NETWORK=<%= @new_resource.network %><% end %> -<% if @new_resource.bcast %>BROADCAST=<%= @new_resource.bcast %><% end %> -<% if @new_resource.onparent %>ONPARENT=<%= @new_resource.onparent %><% end %> -<% if @new_resource.hwaddr %>HWADDR=<%= @new_resource.hwaddr %><% end %> -<% if @new_resource.metric %>METRIC=<%= @new_resource.metric %><% end %> -<% if @new_resource.mtu %>MTU=<%= @new_resource.mtu %><% end %> +<% if new_resource.device %>DEVICE=<%= new_resource.device %><% end %> +<% if new_resource.onboot == "yes" %>ONBOOT=<%= new_resource.onboot %><% end %> +<% if new_resource.bootproto %>BOOTPROTO=<%= new_resource.bootproto %><% end %> +<% if new_resource.target %>IPADDR=<%= new_resource.target %><% end %> +<% if new_resource.mask %>NETMASK=<%= new_resource.mask %><% end %> +<% if new_resource.network %>NETWORK=<%= new_resource.network %><% end %> +<% if new_resource.bcast %>BROADCAST=<%= new_resource.bcast %><% end %> +<% if new_resource.onparent %>ONPARENT=<%= new_resource.onparent %><% end %> +<% if new_resource.hwaddr %>HWADDR=<%= new_resource.hwaddr %><% end %> +<% if new_resource.metric %>METRIC=<%= new_resource.metric %><% end %> +<% if new_resource.mtu %>MTU=<%= new_resource.mtu %><% end %> } - @config_path = "/etc/sysconfig/network-scripts/ifcfg-#{@new_resource.device}" + @config_path = "/etc/sysconfig/network-scripts/ifcfg-#{new_resource.device}" end end diff --git a/lib/chef/provider/launchd.rb b/lib/chef/provider/launchd.rb index 0ec8d0cfe1..f3e0a00758 100644 --- a/lib/chef/provider/launchd.rb +++ b/lib/chef/provider/launchd.rb @@ -150,7 +150,7 @@ class Chef end def content - plist_hash = new_resource.hash || gen_hash + plist_hash = new_resource.plist_hash || gen_hash Plist::Emit.dump(plist_hash) unless plist_hash.nil? end diff --git a/lib/chef/provider/link.rb b/lib/chef/provider/link.rb index 16d30319b3..5add453072 100644 --- a/lib/chef/provider/link.rb +++ b/lib/chef/provider/link.rb @@ -121,6 +121,12 @@ class Chef file_class.symlink(canonicalize(@new_resource.to), @new_resource.target_file) Chef::Log.debug("#{@new_resource} created #{@new_resource.link_type} link from #{@new_resource.target_file} -> #{@new_resource.to}") Chef::Log.info("#{@new_resource} created") + # file_class.symlink will create the link with default access controls. + # This means that the access controls of the file could be different + # than those captured during the initial evaluation of current_resource. + # We need to re-evaluate the current_resource to ensure that the desired + # access controls are applied. + ScanAccessControl.new(@new_resource, @current_resource).set_all! end elsif @new_resource.link_type == :hard converge_by("create hard link at #{@new_resource.target_file} to #{@new_resource.to}") do diff --git a/lib/chef/provider/mount.rb b/lib/chef/provider/mount.rb index 9e9ee29bde..5168c93348 100644 --- a/lib/chef/provider/mount.rb +++ b/lib/chef/provider/mount.rb @@ -108,6 +108,8 @@ class Chef end end + alias :action_unmount :action_umount + # # Abstract Methods to be implemented by subclasses # diff --git a/lib/chef/provider/mount/mount.rb b/lib/chef/provider/mount/mount.rb index 07da6ac361..e00f3290fa 100644 --- a/lib/chef/provider/mount/mount.rb +++ b/lib/chef/provider/mount/mount.rb @@ -193,7 +193,7 @@ class Chef def device_should_exist? ( @new_resource.device != "none" ) && ( not network_device? ) && - ( not %w{ cgroup tmpfs fuse vboxsf }.include? @new_resource.fstype ) + ( not %w{ cgroup tmpfs fuse vboxsf zfs }.include? @new_resource.fstype ) end private @@ -210,7 +210,7 @@ class Chef end def device_real - if @real_device == nil + if @real_device.nil? if @new_resource.device_type == :device @real_device = @new_resource.device else diff --git a/lib/chef/provider/ohai.rb b/lib/chef/provider/ohai.rb index 6b5a605ed5..8f1939af6d 100644 --- a/lib/chef/provider/ohai.rb +++ b/lib/chef/provider/ohai.rb @@ -21,6 +21,8 @@ require "ohai" class Chef class Provider class Ohai < Chef::Provider + use_inline_resources + provides :ohai def whyrun_supported? @@ -31,7 +33,7 @@ class Chef true end - def action_reload + action :reload do converge_by("re-run ohai and merge results into node attributes") do ohai = ::Ohai::System.new @@ -39,9 +41,9 @@ class Chef # Otherwise it will only reload the specified plugin # Note that any changes to plugins, or new plugins placed on # the path are picked up by ohai. - ohai.all_plugins @new_resource.plugin + ohai.all_plugins new_resource.plugin node.automatic_attrs.merge! ohai.data - Chef::Log.info("#{@new_resource} reloaded") + Chef::Log.info("#{new_resource} reloaded") end end end diff --git a/lib/chef/provider/osx_profile.rb b/lib/chef/provider/osx_profile.rb index 69ecf2ddb9..a25ac9539f 100644 --- a/lib/chef/provider/osx_profile.rb +++ b/lib/chef/provider/osx_profile.rb @@ -44,8 +44,10 @@ class Chef ) @new_profile_hash = get_profile_hash(@new_resource.profile) - @new_profile_hash["PayloadUUID"] = - config_uuid(@new_profile_hash) if @new_profile_hash + if @new_profile_hash + @new_profile_hash["PayloadUUID"] = + config_uuid(@new_profile_hash) + end if @new_profile_hash @new_profile_identifier = @new_profile_hash["PayloadIdentifier"] diff --git a/lib/chef/provider/package.rb b/lib/chef/provider/package.rb index 048807dd05..f52614672a 100644 --- a/lib/chef/provider/package.rb +++ b/lib/chef/provider/package.rb @@ -37,6 +37,9 @@ class Chef subclass_directive :use_multipackage_api # subclasses declare this if they want sources (filenames) pulled from their package names subclass_directive :use_package_name_for_source + # keeps package_names_for_targets and versions_for_targets indexed the same as package_name at + # the cost of having the subclass needing to deal with nils + subclass_directive :allow_nils # # Hook that subclasses use to populate the candidate_version(s) @@ -56,7 +59,7 @@ class Chef def check_resource_semantics! # FIXME: this is not universally true and subclasses are needing to override this and no-ops it. It should be turned into # another "subclass_directive" and the apt and yum providers should declare that they need this behavior. - if new_resource.package_name.is_a?(Array) && new_resource.source != nil + if new_resource.package_name.is_a?(Array) && !new_resource.source.nil? raise Chef::Exceptions::InvalidResourceSpecification, "You may not specify both multipackage and source" end end @@ -196,7 +199,7 @@ class Chef end action :reconfig do - if @current_resource.version == nil + if @current_resource.version.nil? Chef::Log.debug("#{@new_resource} is NOT installed - nothing to do") return end @@ -390,9 +393,12 @@ class Chef def package_names_for_targets package_names_for_targets = [] target_version_array.each_with_index do |target_version, i| - next if target_version.nil? - package_name = package_name_array[i] - package_names_for_targets.push(package_name) + if !target_version.nil? + package_name = package_name_array[i] + package_names_for_targets.push(package_name) + else + package_names_for_targets.push(nil) if allow_nils? + end end multipackage? ? package_names_for_targets : package_names_for_targets[0] end @@ -407,8 +413,11 @@ class Chef def versions_for_targets versions_for_targets = [] target_version_array.each_with_index do |target_version, i| - next if target_version.nil? - versions_for_targets.push(target_version) + if !target_version.nil? + versions_for_targets.push(target_version) + else + versions_for_targets.push(nil) if allow_nils? + end end multipackage? ? versions_for_targets : versions_for_targets[0] end diff --git a/lib/chef/provider/package/aix.rb b/lib/chef/provider/package/aix.rb index 728f181055..12bf11ad0f 100644 --- a/lib/chef/provider/package/aix.rb +++ b/lib/chef/provider/package/aix.rb @@ -38,7 +38,7 @@ class Chef a.failure_message Chef::Exceptions::Package, "Source for package #{@new_resource.name} required for action install" end requirements.assert(:all_actions) do |a| - a.assertion { !@new_resource.source || @package_source_found } + a.assertion { !@new_resource.source || package_source_found? } a.failure_message Chef::Exceptions::Package, "Package #{@new_resource.name} not found: #{@new_resource.source}" a.whyrun "would assume #{@new_resource.source} would be have previously been made available" end @@ -48,24 +48,21 @@ class Chef @current_resource = Chef::Resource::Package.new(@new_resource.name) @current_resource.package_name(@new_resource.package_name) - if @new_resource.source - @package_source_found = ::File.exists?(@new_resource.source) - if @package_source_found - Chef::Log.debug("#{@new_resource} checking pkg status") - ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}") - ret.stdout.each_line do |line| - case line - when /:#{@new_resource.package_name}:/ - fields = line.split(":") - @new_resource.version(fields[2]) - when /^#{@new_resource.package_name}:/ - Chef::Log.warn("You are installing a bff package by product name. For idempotent installs, please install individual filesets") - fields = line.split(":") - @new_resource.version(fields[2]) - end + if package_source_found? + Chef::Log.debug("#{@new_resource} checking pkg status") + ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}") + ret.stdout.each_line do |line| + case line + when /:#{@new_resource.package_name}:/ + fields = line.split(":") + @new_resource.version(fields[2]) + when /^#{@new_resource.package_name}:/ + Chef::Log.warn("You are installing a bff package by product name. For idempotent installs, please install individual filesets") + fields = line.split(":") + @new_resource.version(fields[2]) end - raise Chef::Exceptions::Package, "package source #{@new_resource.source} does not provide package #{@new_resource.package_name}" unless @new_resource.version end + raise Chef::Exceptions::Package, "package source #{@new_resource.source} does not provide package #{@new_resource.package_name}" unless @new_resource.version end Chef::Log.debug("#{@new_resource} checking install state") @@ -88,18 +85,20 @@ class Chef def candidate_version return @candidate_version if @candidate_version - ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}") - ret.stdout.each_line do |line| - case line - when /\w:#{Regexp.escape(@new_resource.package_name)}:(.*)/ - fields = line.split(":") - @candidate_version = fields[2] - @new_resource.version(fields[2]) - Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}") + if package_source_found? + ret = shell_out_with_timeout("installp -L -d #{@new_resource.source}") + ret.stdout.each_line do |line| + case line + when /\w:#{Regexp.escape(@new_resource.package_name)}:(.*)/ + fields = line.split(":") + @candidate_version = fields[2] + @new_resource.version(fields[2]) + Chef::Log.debug("#{@new_resource} setting install candidate version to #{@candidate_version}") + end + end + unless ret.exitstatus == 0 + raise Chef::Exceptions::Package, "installp -L -d #{@new_resource.source} - #{ret.format_for_exception}!" end - end - unless ret.exitstatus == 0 - raise Chef::Exceptions::Package, "installp -L -d #{@new_resource.source} - #{ret.format_for_exception}!" end @candidate_version end @@ -134,6 +133,10 @@ class Chef end end + def package_source_found? + @package_source_found ||= @new_resource.source && ::File.exists?(@new_resource.source) + end + end end end diff --git a/lib/chef/provider/package/cab.rb b/lib/chef/provider/package/cab.rb index 4e2054fbc2..a281100f8b 100644 --- a/lib/chef/provider/package/cab.rb +++ b/lib/chef/provider/package/cab.rb @@ -19,40 +19,70 @@ require "chef/provider/package" require "chef/resource/cab_package" require "chef/mixin/shell_out" +require "chef/mixin/uris" +require "chef/mixin/checksum" class Chef class Provider class Package class Cab < Chef::Provider::Package + use_inline_resources include Chef::Mixin::ShellOut + include Chef::Mixin::Uris + include Chef::Mixin::Checksum provides :cab_package, os: "windows" def load_current_resource @current_resource = Chef::Resource::CabPackage.new(new_resource.name) - current_resource.source(new_resource.source) + current_resource.source(cab_file_source) new_resource.version(package_version) current_resource.version(installed_version) current_resource end + def cab_file_source + @cab_file_source ||= uri_scheme?(new_resource.source) ? download_source_file : new_resource.source + end + + def download_source_file + source_resource.run_action(:create) + Chef::Log.debug("#{new_resource} fetched source file to #{source_resource.path}") + source_resource.path + end + + def source_resource + @source_resource ||= declare_resource(:remote_file, new_resource.name) do + path default_download_cache_path + source new_resource.source + backup false + end + end + + def default_download_cache_path + uri = ::URI.parse(new_resource.source) + filename = ::File.basename(::URI.unescape(uri.path)) + file_cache_dir = Chef::FileCache.create_cache_path("package/") + Chef::Util::PathHelper.cleanpath("#{file_cache_dir}/#{filename}") + end + def install_package(name, version) - dism_command("/Add-Package /PackagePath:\"#{@new_resource.source}\"") + dism_command("/Add-Package /PackagePath:\"#{cab_file_source}\"") end def remove_package(name, version) - dism_command("/Remove-Package /PackagePath:\"#{@new_resource.source}\"") + dism_command("/Remove-Package /PackagePath:\"#{cab_file_source}\"") end def dism_command(command) - shellout = Mixlib::ShellOut.new("dism.exe /Online #{command} /NoRestart", { :timeout => @new_resource.timeout }) + shellout = Mixlib::ShellOut.new("dism.exe /Online /English #{command} /NoRestart", { :timeout => @new_resource.timeout }) with_os_architecture(nil) do shellout.run_command end end def installed_version - stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{@new_resource.source}\"").stdout + stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{cab_file_source}\"").stdout package_info = parse_dism_get_package_info(stdout) # e.g. Package_for_KB2975719~31bf3856ad364e35~amd64~~6.3.1.8 package = split_package_identity(package_info["package_information"]["package_identity"]) @@ -71,8 +101,8 @@ class Chef end def package_version - Chef::Log.debug("#{@new_resource} getting product version for package at #{@new_resource.source}") - stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{@new_resource.source}\"").stdout + Chef::Log.debug("#{@new_resource} getting product version for package at #{cab_file_source}") + stdout = dism_command("/Get-PackageInfo /PackagePath:\"#{cab_file_source}\"").stdout find_version(stdout) end diff --git a/lib/chef/provider/package/chocolatey.rb b/lib/chef/provider/package/chocolatey.rb index 36bc170590..02a196fa8c 100644 --- a/lib/chef/provider/package/chocolatey.rb +++ b/lib/chef/provider/package/chocolatey.rb @@ -84,7 +84,7 @@ EOS # choco does not support installing multiple packages with version pins name_has_versions.each do |name, version| - choco_command("install -y -version", version, cmd_args, name) + choco_command("install -y --version", version, cmd_args, name) end # but we can do all the ones without version pins at once @@ -106,7 +106,7 @@ EOS # choco does not support installing multiple packages with version pins name_has_versions.each do |name, version| - choco_command("upgrade -y -version", version, cmd_args, name) + choco_command("upgrade -y --version", version, cmd_args, name) end # but we can do all the ones without version pins at once @@ -169,7 +169,7 @@ EOS # @param args [String] variable number of string arguments # @return [Mixlib::ShellOut] object returned from shell_out! def choco_command(*args) - shell_out_with_timeout!(args_to_string(choco_exe, *args)) + shell_out_with_timeout!(args_to_string(choco_exe, *args), { :returns => new_resource.returns }) end # Use the available_packages Hash helper to create an array suitable for @@ -236,6 +236,7 @@ EOS available[name] = desired_name_versions[name] || raw[name] end end + @available_packages end # Installed packages in chocolatey as a Hash of names mapped to versions @@ -244,6 +245,7 @@ EOS # @return [Hash] name-to-version mapping of installed packages def installed_packages @installed_packages ||= Hash[*parse_list_output("list -l -r").flatten] + @installed_packages end # Helper to convert choco.exe list output to a Hash diff --git a/lib/chef/provider/package/dnf.rb b/lib/chef/provider/package/dnf.rb new file mode 100644 index 0000000000..bf6aa2438f --- /dev/null +++ b/lib/chef/provider/package/dnf.rb @@ -0,0 +1,183 @@ +# +# Copyright:: Copyright 2016, Chef Software, Inc. +# 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 "chef/provider/package" +require "chef/resource/dnf_package" +require "chef/mixin/which" +require "chef/mixin/get_source_from_package" +require "chef/provider/package/dnf/python_helper" +require "chef/provider/package/dnf/version" + +class Chef + class Provider + class Package + class Dnf < Chef::Provider::Package + extend Chef::Mixin::Which + include Chef::Mixin::GetSourceFromPackage + + allow_nils + use_multipackage_api + use_package_name_for_source + + provides :package, platform_family: %w{rhel fedora} do + which("dnf") + end + + provides :dnf_package, os: "linux" + + # + # Most of the magic in this class happens in the python helper script. The ruby side of this + # provider knows only enough to translate Chef-style new_resource name+package+version into + # a request to the python side. The python side is then responsible for knowing everything + # about RPMs and what is installed and what is available. The ruby side of this class should + # remain a lightweight translation layer to translate Chef requests into RPC requests to + # python. This class knows nothing about how to compare RPM versions, and does not maintain + # any cached state of installed/available versions and should be kept that way. + # + def python_helper + @python_helper ||= PythonHelper.instance + end + + def load_current_resource + flushcache if new_resource.flush_cache[:before] + + @current_resource = Chef::Resource::DnfPackage.new(new_resource.name) + current_resource.package_name(new_resource.package_name) + current_resource.version(get_current_versions) + + current_resource + end + + def define_resource_requirements + requirements.assert(:install, :upgrade, :remove, :purge) do |a| + a.assertion { !new_resource.source || ::File.exist?(new_resource.source) } + a.failure_message Chef::Exceptions::Package, "Package #{new_resource.package_name} not found: #{new_resource.source}" + a.whyrun "assuming #{new_resource.source} would have previously been created" + end + + super + end + + def candidate_version + package_name_array.each_with_index.map do |pkg, i| + available_version(i).version_with_arch + end + end + + def get_current_versions + package_name_array.each_with_index.map do |pkg, i| + installed_version(i).version_with_arch + end + end + + def install_package(names, versions) + if new_resource.source + dnf(new_resource.options, "-y install", new_resource.source) + else + resolved_names = names.each_with_index.map { |name, i| available_version(i).to_s unless name.nil? } + dnf(new_resource.options, "-y install", resolved_names) + end + flushcache + end + + # dnf upgrade does not work on uninstalled packaged, while install will upgrade + alias_method :upgrade_package, :install_package + + def remove_package(names, versions) + resolved_names = names.each_with_index.map { |name, i| installed_version(i).to_s unless name.nil? } + dnf(new_resource.options, "-y remove", resolved_names) + flushcache + end + + alias_method :purge_package, :remove_package + + action :flush_cache do + flushcache + end + + private + + def resolve_source_to_version_obj + shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{EPOCH} %{VERSION} %{RELEASE} %{ARCH}\n' #{new_resource.source}").stdout.each_line do |line| + # this is another case of committing the sin of doing some lightweight mangling of RPM versions in ruby -- but the output of the rpm command + # does not match what the dnf library accepts. + case line + when /^(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)$/ + return Version.new($1, "#{$2 == "(none)" ? "0" : $2}:#{$3}-#{$4}", $5) + end + end + end + + # @returns Array<Version> + def available_version(index) + @available_version ||= [] + + if new_resource.source + @available_version[index] ||= resolve_source_to_version_obj + else + @available_version[index] ||= python_helper.query(:whatavailable, package_name_array[index], safe_version_array[index], safe_arch_array[index]) + end + + @available_version[index] + end + + # @returns Array<Version> + def installed_version(index) + @installed_version ||= [] + if new_resource.source + @installed_version[index] ||= python_helper.query(:whatinstalled, available_version(index).name, safe_version_array[index], safe_arch_array[index]) + else + @installed_version[index] ||= python_helper.query(:whatinstalled, package_name_array[index], safe_version_array[index], safe_arch_array[index]) + end + @installed_version[index] + end + + # cache flushing is accomplished by simply restarting the python helper. this produces a roughly + # 15% hit to the runtime of installing/removing/upgrading packages. correctly using multipackage + # array installs (and the multipackage cookbook) can produce 600% improvements in runtime. + def flushcache + python_helper.restart + end + + def dnf(*args) + shell_out_with_timeout!(a_to_s("dnf", *args)) + end + + def safe_version_array + if new_resource.version.is_a?(Array) + new_resource.version + elsif new_resource.version.nil? + package_name_array.map { nil } + else + [ new_resource.version ] + end + end + + def safe_arch_array + if new_resource.arch.is_a?(Array) + new_resource.arch + elsif new_resource.arch.nil? + package_name_array.map { nil } + else + [ new_resource.arch ] + end + end + + end + end + end +end diff --git a/lib/chef/provider/package/dnf/dnf_helper.py b/lib/chef/provider/package/dnf/dnf_helper.py new file mode 100644 index 0000000000..236b967710 --- /dev/null +++ b/lib/chef/provider/package/dnf/dnf_helper.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4 + +import sys +import dnf +import hawkey +import signal +import os +import json + +base = None + +def get_sack(): + global base + if base is None: + base = dnf.Base() + base.read_all_repos() + base.fill_sack() + return base.sack + +# FIXME: leaks memory and does not work +def flushcache(): + try: + os.remove('/var/cache/dnf/@System.solv') + except OSError: + pass + get_sack().load_system_repo(build_cache=True) + +def query(command): + sack = get_sack() + + subj = dnf.subject.Subject(command['provides']) + q = subj.get_best_query(sack, with_provides=True) + + if command['action'] == "whatinstalled": + q = q.installed() + + if command['action'] == "whatavailable": + q = q.available() + + if 'epoch' in command: + q = q.filterm(epoch=int(command['epoch'])) + if 'version' in command: + q = q.filterm(version__glob=command['version']) + if 'release' in command: + q = q.filterm(release__glob=command['release']) + + if 'arch' in command: + q = q.filterm(arch__glob=command['arch']) + + # only apply the default arch query filter if it returns something + archq = q.filter(arch=[ 'noarch', hawkey.detect_arch() ]) + if len(archq.run()) > 0: + q = archq + + pkgs = dnf.query.latest_limit_pkgs(q, 1) + + if not pkgs: + sys.stdout.write('{} nil nil\n'.format(command['provides'].split().pop(0))) + else: + # make sure we picked the package with the highest version + pkgs.sort + pkg = pkgs.pop() + sys.stdout.write('{} {}:{}-{} {}\n'.format(pkg.name, pkg.epoch, pkg.version, pkg.release, pkg.arch)) + +# the design of this helper is that it should try to be 'brittle' and fail hard and exit in order +# to keep process tables clean. additional error handling should probably be added to the retry loop +# on the ruby side. +def exit_handler(signal, frame): + sys.exit(0) + +signal.signal(signal.SIGINT, exit_handler) +signal.signal(signal.SIGHUP, exit_handler) +signal.signal(signal.SIGPIPE, exit_handler) +signal.signal(signal.SIGCHLD, exit_handler) + +while 1: + # kill self if we get orphaned (tragic) + ppid = os.getppid() + if ppid == 1: + sys.exit(0) + line = sys.stdin.readline() + command = json.loads(line) + if command['action'] == "whatinstalled": + query(command) + elif command['action'] == "whatavailable": + query(command) + elif command['action'] == "flushcache": + flushcache() + else: + raise RuntimeError("bad command") diff --git a/lib/chef/provider/package/dnf/python_helper.rb b/lib/chef/provider/package/dnf/python_helper.rb new file mode 100644 index 0000000000..466114b339 --- /dev/null +++ b/lib/chef/provider/package/dnf/python_helper.rb @@ -0,0 +1,120 @@ +# +# Copyright:: Copyright 2016, Chef Software, Inc. +# 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 "chef/provider/package/dnf/version" +require "timeout" + +class Chef + class Provider + class Package + class Dnf < Chef::Provider::Package + class PythonHelper + include Singleton + extend Chef::Mixin::Which + + attr_accessor :stdin + attr_accessor :stdout + attr_accessor :stderr + attr_accessor :wait_thr + + DNF_HELPER = ::File.expand_path(::File.join(::File.dirname(__FILE__), "dnf_helper.py")).freeze + DNF_COMMAND = "#{which("python3")} #{DNF_HELPER}" + + def start + ENV["PYTHONUNBUFFERED"] = "1" + @stdin, @stdout, @stderr, @wait_thr = Open3.popen3(DNF_COMMAND) + end + + def reap + unless wait_thr.nil? + Process.kill("KILL", wait_thr.pid) rescue nil + stdin.close unless stdin.nil? + stdout.close unless stdout.nil? + stderr.close unless stderr.nil? + wait_thr.value # this calls waitpit() + end + end + + def check + start if stdin.nil? + end + + # i couldn't figure out how to decompose an evr on the python side, it seems reasonably + # painless to do it in ruby (generally massaging nevras in the ruby side is HIGHLY + # discouraged -- this is an "every rule has an exception" exception -- any additional + # functionality should probably trigger moving this regexp logic into python) + def add_version(hash, version) + epoch = nil + if version =~ /(\S+):(\S+)/ + epoch, version = $1, $2 + end + if version =~ /(\S+)-(\S+)/ + version, release = $1, $2 + end + hash["epoch"] = epoch unless epoch.nil? + hash["release"] = release unless release.nil? + hash["version"] = version + end + + def build_query(action, provides, version, arch) + hash = { "action" => action } + hash["provides"] = provides + add_version(hash, version) unless version.nil? + hash["arch" ] = arch unless arch.nil? + FFI_Yajl::Encoder.encode(hash) + end + + def parse_response(output) + array = output.split.map { |x| x == "nil" ? nil : x } + array.each_slice(3).map { |x| Version.new(*x) }.first + end + + # @returns Array<Version> + def query(action, provides, version = nil, arch = nil) + with_helper do + json = build_query(action, provides, version, arch) + Chef::Log.debug "sending '#{json}' to python helper" + stdin.syswrite json + "\n" + output = stdout.sysread(4096).chomp + Chef::Log.debug "got '#{output}' from python helper" + version = parse_response(output) + Chef::Log.debug "parsed #{version} from python helper" + version + end + end + + def restart + reap + start + end + + def with_helper + max_retries ||= 5 + Timeout.timeout(600) do + check + yield + end + rescue EOFError, Errno::EPIPE, Timeout::Error, Errno::ESRCH => e + raise e unless ( max_retries -= 1 ) > 0 + restart + retry + end + end + end + end + end +end diff --git a/lib/chef/provider/package/dnf/version.rb b/lib/chef/provider/package/dnf/version.rb new file mode 100644 index 0000000000..b326913c3a --- /dev/null +++ b/lib/chef/provider/package/dnf/version.rb @@ -0,0 +1,56 @@ +# +# Copyright:: Copyright 2016, Chef Software, Inc. +# 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. +# + +class Chef + class Provider + class Package + class Dnf < Chef::Provider::Package + + # helper class to assist in passing around name/version/arch triples + class Version + attr_accessor :name + attr_accessor :version + attr_accessor :arch + + def initialize(name, version, arch) + @name = name + @version = version + @arch = arch + end + + def to_s + "#{name}-#{version}.#{arch}" + end + + def version_with_arch + "#{version}.#{arch}" unless version.nil? + end + + def matches_name_and_arch?(other) + other.version == version && other.arch == arch + end + + def ==(other) + name == other.name && version == other.version && arch == other.arch + end + + alias_method :eql?, :== + end + end + end + end +end diff --git a/lib/chef/provider/package/easy_install.rb b/lib/chef/provider/package/easy_install.rb index 989f2ab9d2..a9c6e2a792 100644 --- a/lib/chef/provider/package/easy_install.rb +++ b/lib/chef/provider/package/easy_install.rb @@ -112,7 +112,7 @@ class Chef end def install_package(name, version) - Chef.log_deprecation("The easy_install package provider is deprecated and will be removed in Chef 13.") + Chef.deprecated(:easy_install, "The easy_install package provider is deprecated and will be removed in Chef 13.") run_command(:command => "#{easy_install_binary_path}#{expand_options(@new_resource.options)} \"#{name}==#{version}\"") end @@ -121,8 +121,8 @@ class Chef end def remove_package(name, version) - Chef.log_deprecation("The easy_install package provider is deprecated and will be removed in Chef 13.") - run_command(:command => "#{easy_install_binary_path }#{expand_options(@new_resource.options)} -m #{name}") + Chef.deprecated(:easy_install, "The easy_install package provider is deprecated and will be removed in Chef 13.") + run_command(:command => "#{easy_install_binary_path}#{expand_options(@new_resource.options)} -m #{name}") end def purge_package(name, version) diff --git a/lib/chef/provider/package/freebsd/base.rb b/lib/chef/provider/package/freebsd/base.rb index 7104a71f70..0996a38c75 100644 --- a/lib/chef/provider/package/freebsd/base.rb +++ b/lib/chef/provider/package/freebsd/base.rb @@ -58,7 +58,7 @@ class Chef def makefile_variable_value(variable, dir = nil) options = dir ? { :cwd => dir } : {} make_v = shell_out_with_timeout!("make -V #{variable}", options.merge!(:env => nil, :returns => [0, 1])) - make_v.exitstatus.zero? ? make_v.stdout.strip.split($\).first : nil # $\ is the line separator, i.e. newline. + make_v.exitstatus == 0 ? make_v.stdout.strip.split($\).first : nil # $\ is the line separator, i.e. newline. end end diff --git a/lib/chef/provider/package/freebsd/pkgng.rb b/lib/chef/provider/package/freebsd/pkgng.rb index de7bea6387..56e87f6be9 100644 --- a/lib/chef/provider/package/freebsd/pkgng.rb +++ b/lib/chef/provider/package/freebsd/pkgng.rb @@ -64,7 +64,7 @@ class Chef end pkg_query = shell_out_with_timeout!("pkg rquery#{expand_options(options)} '%v' #{@new_resource.package_name}", :env => nil) - pkg_query.exitstatus.zero? ? pkg_query.stdout.strip.split(/\n/).last : nil + pkg_query.exitstatus == 0 ? pkg_query.stdout.strip.split(/\n/).last : nil end def repo_regex diff --git a/lib/chef/provider/package/ips.rb b/lib/chef/provider/package/ips.rb index 85053d47f2..bc5b9fff77 100644 --- a/lib/chef/provider/package/ips.rb +++ b/lib/chef/provider/package/ips.rb @@ -74,7 +74,7 @@ class Chef else normal_command end - shell_out_with_timeout(command) + shell_out_with_timeout!(command) end def upgrade_package(name, version) diff --git a/lib/chef/provider/package/msu.rb b/lib/chef/provider/package/msu.rb new file mode 100644 index 0000000000..3146ecb04d --- /dev/null +++ b/lib/chef/provider/package/msu.rb @@ -0,0 +1,162 @@ +# +# Author:: Nimisha Sharad (<nimisha.sharad@msystechnologies.com>) +# Copyright:: Copyright 2015-2016, Chef Software, Inc. +# 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. +# + +# msu_package leverages cab_package +# The contents of msu file are extracted, which contains one or more cab files. +# The extracted cab files are installed using Chef::Resource::Package::CabPackage +# Reference: https://support.microsoft.com/en-in/kb/934307 +require "chef/provider/package" +require "chef/resource/msu_package" +require "chef/mixin/shell_out" +require "chef/provider/package/cab" +require "chef/util/path_helper" +require "chef/mixin/uris" +require "chef/mixin/checksum" + +class Chef + class Provider + class Package + class Msu < Chef::Provider::Package + use_inline_resources + include Chef::Mixin::ShellOut + include Chef::Mixin::Uris + include Chef::Mixin::Checksum + + provides :msu_package, os: "windows" + + def load_current_resource + @current_resource = Chef::Resource::MsuPackage.new(new_resource.name) + + # download file if source is a url + msu_file = uri_scheme?(new_resource.source) ? download_source_file : @new_resource.source + + # temp directory where the contents of msu file get extracted + @temp_directory = Dir.mktmpdir("chef") + extract_msu_contents(msu_file, @temp_directory) + @cab_files = read_cab_files_from_xml(@temp_directory) + + unless @cab_files.empty? + current_resource.version(get_current_versions) + else + raise Chef::Exceptions::Package, "Corrupt MSU package: MSU package XML does not contain any cab file" + end + current_resource + end + + def get_current_versions + @cab_files.map do |cabfile| + cab_pkg = get_cab_package(cabfile) + cab_pkg.installed_version + end + end + + def get_candidate_versions + @cab_files.map do |cabfile| + cab_pkg = get_cab_package(cabfile) + cab_pkg.package_version + end + end + + def candidate_version + @candidate_version ||= get_candidate_versions + end + + def get_cab_package(cab_file) + cab_resource = @new_resource + cab_resource.source = cab_file + cab_pkg = Chef::Provider::Package::Cab.new(cab_resource, nil) + end + + def download_source_file + source_resource.run_action(:create) + Chef::Log.debug("#{new_resource} fetched source file to #{source_resource.path}") + source_resource.path + end + + def source_resource + @source_resource ||= declare_resource(:remote_file, new_resource.name) do + path default_download_cache_path + source new_resource.source + checksum new_resource.checksum + backup false + end + end + + def default_download_cache_path + uri = ::URI.parse(new_resource.source) + filename = ::File.basename(::URI.unescape(uri.path)) + file_cache_dir = Chef::FileCache.create_cache_path("package/") + Chef::Util::PathHelper.cleanpath("#{file_cache_dir}/#{filename}") + end + + def install_package(name, version) + #use cab_package resource to install the extracted cab packages + @cab_files.each do |cab_file| + declare_resource(:cab_package, @new_resource.name) do + source cab_file + action :install + end + end + end + + def remove_package(name, version) + #use cab_package provider to remove the extracted cab packages + @cab_files.each do |cab_file| + declare_resource(:cab_package, @new_resource.name) do + source cab_file + action :remove + end + end + end + + def extract_msu_contents(msu_file, destination) + with_os_architecture(nil) do + shell_out_with_timeout!("#{ENV['SYSTEMROOT']}\\system32\\expand.exe -f:* #{msu_file} #{destination}") + end + end + + # msu package can contain multiple cab files + # Reading cab files from xml to ensure the order of installation in case of multiple cab files + def read_cab_files_from_xml(msu_dir) + # get the file with .xml extension + xml_files = Dir.glob("#{msu_dir}/*.xml") + cab_files = [] + + if xml_files.empty? + raise Chef::Exceptions::Package, "Corrupt MSU package: MSU package doesn't contain any xml file" + else + # msu package contains only single xml file. So using xml_files.first is sufficient + doc = ::File.open("#{xml_files.first}") { |f| REXML::Document.new f } + locations = doc.elements.each("unattend/servicing/package/source") { |element| puts element.attributes["location"] } + locations.each do |loc| + cab_files << msu_dir + "/" + loc.attribute("location").value.split("\\")[1] + end + + cab_files + end + cab_files + end + + def cleanup_after_converge + # delete the temp directory where the contents of msu file are extracted + FileUtils.rm_rf(@temp_directory) if Dir.exists?(@temp_directory) + end + end + end + end +end diff --git a/lib/chef/provider/package/powershell.rb b/lib/chef/provider/package/powershell.rb index 5206b5b696..caeda6d412 100644 --- a/lib/chef/provider/package/powershell.rb +++ b/lib/chef/provider/package/powershell.rb @@ -60,7 +60,7 @@ class Chef # Removes the package for the version passed and if no version is passed, then all installed versions of the package are removed def remove_package(names, versions) names.each_with_index do |name, index| - if versions && versions[index] != nil + if versions && !versions[index].nil? powershell_out( "Uninstall-Package '#{name}' -Force -ForceBootstrap -RequiredVersion #{versions[index]}", { :timeout => @new_resource.timeout }) else version = "0" @@ -78,7 +78,7 @@ class Chef def build_candidate_versions versions = [] new_resource.package_name.each_with_index do |name, index| - if new_resource.version && new_resource.version[index] != nil + if new_resource.version && !new_resource.version[index].nil? version = powershell_out("(Find-Package '#{name}' -RequiredVersion #{new_resource.version[index]} -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => @new_resource.timeout }).stdout.strip() else version = powershell_out("(Find-Package '#{name}' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => @new_resource.timeout }).stdout.strip() @@ -95,7 +95,7 @@ class Chef def build_current_versions version_list = [] new_resource.package_name.each_with_index do |name, index| - if new_resource.version && new_resource.version[index] != nil + if new_resource.version && !new_resource.version[index].nil? version = powershell_out("(Get-Package -Name '#{name}' -RequiredVersion #{new_resource.version[index]} -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => @new_resource.timeout }).stdout.strip() else version = powershell_out("(Get-Package -Name '#{name}' -ForceBootstrap -Force | select version | Format-Table -HideTableHeaders | Out-String).Trim()", { :timeout => @new_resource.timeout }).stdout.strip() diff --git a/lib/chef/provider/package/windows.rb b/lib/chef/provider/package/windows.rb index b11bcf5192..504d5d394a 100644 --- a/lib/chef/provider/package/windows.rb +++ b/lib/chef/provider/package/windows.rb @@ -262,7 +262,7 @@ class Chef if source_location.nil? inferred_registry_type == :msi else - ::File.extname(source_location).casecmp(".msi").zero? + ::File.extname(source_location).casecmp(".msi") == 0 end end end diff --git a/lib/chef/provider/package/yum.rb b/lib/chef/provider/package/yum.rb index 022fdcae09..8b7d7a5083 100644 --- a/lib/chef/provider/package/yum.rb +++ b/lib/chef/provider/package/yum.rb @@ -197,7 +197,7 @@ class Chef Chef::Log.debug("#{@new_resource} checking rpm status") shell_out_with_timeout!("rpm -qp --queryformat '%{NAME} %{VERSION}-%{RELEASE}\n' #{@new_resource.source}", :timeout => Chef::Config[:yum_timeout]).stdout.each_line do |line| case line - when /([\w\d_.-]+)\s([\w\d_.-]+)/ + when /^(\S+)\s(\S+)$/ @current_resource.package_name($1) @new_resource.version($2) end diff --git a/lib/chef/provider/package/zypper.rb b/lib/chef/provider/package/zypper.rb index edad45c3e4..6965052723 100644 --- a/lib/chef/provider/package/zypper.rb +++ b/lib/chef/provider/package/zypper.rb @@ -144,7 +144,7 @@ class Chef end end - def gpg_checks() + def gpg_checks case Chef::Config[:zypper_check_gpg] when true "" diff --git a/lib/chef/provider/route.rb b/lib/chef/provider/route.rb index 64c89aac6d..5e20fdf11e 100644 --- a/lib/chef/provider/route.rb +++ b/lib/chef/provider/route.rb @@ -21,209 +21,211 @@ require "chef/mixin/command" require "chef/provider" require "ipaddr" -class Chef::Provider::Route < Chef::Provider - include Chef::Mixin::Command - - provides :route - - attr_accessor :is_running - - MASK = { "0.0.0.0" => "0", - "128.0.0.0" => "1", - "192.0.0.0" => "2", - "224.0.0.0" => "3", - "240.0.0.0" => "4", - "248.0.0.0" => "5", - "252.0.0.0" => "6", - "254.0.0.0" => "7", - "255.0.0.0" => "8", - "255.128.0.0" => "9", - "255.192.0.0" => "10", - "255.224.0.0" => "11", - "255.240.0.0" => "12", - "255.248.0.0" => "13", - "255.252.0.0" => "14", - "255.254.0.0" => "15", - "255.255.0.0" => "16", - "255.255.128.0" => "17", - "255.255.192.0" => "18", - "255.255.224.0" => "19", - "255.255.240.0" => "20", - "255.255.248.0" => "21", - "255.255.252.0" => "22", - "255.255.254.0" => "23", - "255.255.255.0" => "24", - "255.255.255.128" => "25", - "255.255.255.192" => "26", - "255.255.255.224" => "27", - "255.255.255.240" => "28", - "255.255.255.248" => "29", - "255.255.255.252" => "30", - "255.255.255.254" => "31", - "255.255.255.255" => "32" } - - def hex2ip(hex_data) - # Cleanup hex data - hex_ip = hex_data.to_s.downcase.gsub(/[^0-9a-f]/, "") - - # Check hex data format (IP is a 32bit integer, so should be 8 chars long) - return nil if hex_ip.length != hex_data.length || hex_ip.length != 8 - - # Extract octets from hex data - octets = hex_ip.scan(/../).reverse.collect { |octet| [octet].pack("H2").unpack("C").first } - - # Validate IP - ip = octets.join(".") - begin - IPAddr.new(ip, Socket::AF_INET).to_s - rescue ArgumentError - Chef::Log.debug("Invalid IP address data: hex=#{hex_ip}, ip=#{ip}") - return nil - end - end - - def whyrun_supported? - true - end +class Chef + class Provider + class Route < Chef::Provider + include Chef::Mixin::Command + + provides :route + + attr_accessor :is_running + + MASK = { "0.0.0.0" => "0", + "128.0.0.0" => "1", + "192.0.0.0" => "2", + "224.0.0.0" => "3", + "240.0.0.0" => "4", + "248.0.0.0" => "5", + "252.0.0.0" => "6", + "254.0.0.0" => "7", + "255.0.0.0" => "8", + "255.128.0.0" => "9", + "255.192.0.0" => "10", + "255.224.0.0" => "11", + "255.240.0.0" => "12", + "255.248.0.0" => "13", + "255.252.0.0" => "14", + "255.254.0.0" => "15", + "255.255.0.0" => "16", + "255.255.128.0" => "17", + "255.255.192.0" => "18", + "255.255.224.0" => "19", + "255.255.240.0" => "20", + "255.255.248.0" => "21", + "255.255.252.0" => "22", + "255.255.254.0" => "23", + "255.255.255.0" => "24", + "255.255.255.128" => "25", + "255.255.255.192" => "26", + "255.255.255.224" => "27", + "255.255.255.240" => "28", + "255.255.255.248" => "29", + "255.255.255.252" => "30", + "255.255.255.254" => "31", + "255.255.255.255" => "32" }.freeze + + def hex2ip(hex_data) + # Cleanup hex data + hex_ip = hex_data.to_s.downcase.gsub(/[^0-9a-f]/, "") + + # Check hex data format (IP is a 32bit integer, so should be 8 chars long) + return nil if hex_ip.length != hex_data.length || hex_ip.length != 8 + + # Extract octets from hex data + octets = hex_ip.scan(/../).reverse.collect { |octet| [octet].pack("H2").unpack("C").first } + + # Validate IP + ip = octets.join(".") + begin + IPAddr.new(ip, Socket::AF_INET).to_s + rescue ArgumentError + Chef::Log.debug("Invalid IP address data: hex=#{hex_ip}, ip=#{ip}") + return nil + end + end - def load_current_resource - self.is_running = false + def whyrun_supported? + true + end - # cidr or quad dot mask - if @new_resource.netmask - new_ip = IPAddr.new("#{@new_resource.target}/#{@new_resource.netmask}") - else - new_ip = IPAddr.new(@new_resource.target) - end + def load_current_resource + self.is_running = false + + # cidr or quad dot mask + new_ip = if new_resource.netmask + IPAddr.new("#{new_resource.target}/#{new_resource.netmask}") + else + IPAddr.new(new_resource.target) + end + + # For linux, we use /proc/net/route file to read proc table info + return if node[:os] != "linux" + + route_file = ::File.open("/proc/net/route", "r") + + # Read all routes + while (line = route_file.gets) + # Get all the fields for a route + _, destination, gateway, _, _, _, _, mask = line.split + + # Convert hex-encoded values to quad-dotted notation (e.g. 0064A8C0 => 192.168.100.0) + destination = hex2ip(destination) + gateway = hex2ip(gateway) + mask = hex2ip(mask) + + # Skip formatting lines (header, etc) + next unless destination && gateway && mask + Chef::Log.debug("#{new_resource} system has route: dest=#{destination} mask=#{mask} gw=#{gateway}") + + # check if what were trying to configure is already there + # use an ipaddr object with ip/mask this way we can have + # a new resource be in cidr format (i don't feel like + # expanding bitmask by hand. + # + running_ip = IPAddr.new("#{destination}/#{mask}") + Chef::Log.debug("#{new_resource} new ip: #{new_ip.inspect} running ip: #{running_ip.inspect}") + self.is_running = true if running_ip == new_ip && gateway == new_resource.gateway + end - # For linux, we use /proc/net/route file to read proc table info - if node[:os] == "linux" - route_file = ::File.open("/proc/net/route", "r") - - # Read all routes - while (line = route_file.gets) - # Get all the fields for a route - iface, destination, gateway, flags, refcnt, use, metric, mask, mtu, window, irtt = line.split - - # Convert hex-encoded values to quad-dotted notation (e.g. 0064A8C0 => 192.168.100.0) - destination = hex2ip(destination) - gateway = hex2ip(gateway) - mask = hex2ip(mask) - - # Skip formatting lines (header, etc) - next unless destination && gateway && mask - Chef::Log.debug("#{@new_resource} system has route: dest=#{destination} mask=#{mask} gw=#{gateway}") - - # check if what were trying to configure is already there - # use an ipaddr object with ip/mask this way we can have - # a new resource be in cidr format (i don't feel like - # expanding bitmask by hand. - # - running_ip = IPAddr.new("#{destination}/#{mask}") - Chef::Log.debug("#{@new_resource} new ip: #{new_ip.inspect} running ip: #{running_ip.inspect}") - self.is_running = true if running_ip == new_ip && gateway == @new_resource.gateway + route_file.close end - route_file.close - end - end + def action_add + # check to see if load_current_resource found the route + if is_running + Chef::Log.debug("#{new_resource} route already active - nothing to do") + else + command = generate_command(:add) + converge_by("run #{command.join(' ')} to add route") do + shell_out_compact!(command) + Chef::Log.info("#{new_resource} added") + end + end - def action_add - # check to see if load_current_resource found the route - if is_running - Chef::Log.debug("#{@new_resource} route already active - nothing to do") - else - command = generate_command(:add) - converge_by ("run #{ command } to add route") do - run_command( :command => command ) - Chef::Log.info("#{@new_resource} added") + # for now we always write the file (ugly but its what it is) + generate_config end - end - #for now we always write the file (ugly but its what it is) - generate_config - end + def action_delete + if is_running + command = generate_command(:delete) + converge_by("run #{command.join(' ')} to delete route ") do + shell_out_compact!(command) + Chef::Log.info("#{new_resource} removed") + end + else + Chef::Log.debug("#{new_resource} route does not exist - nothing to do") + end - def action_delete - if is_running - command = generate_command(:delete) - converge_by ("run #{ command } to delete route ") do - run_command( :command => command ) - Chef::Log.info("#{@new_resource} removed") + # for now we always write the file (ugly but its what it is) + generate_config end - else - Chef::Log.debug("#{@new_resource} route does not exist - nothing to do") - end - - #for now we always write the file (ugly but its what it is) - generate_config - end - def generate_config - conf = Hash.new - case node[:platform] - when "centos", "redhat", "fedora" - # walk the collection - run_context.resource_collection.each do |resource| - if resource.is_a? Chef::Resource::Route - # default to eth0 - if resource.device - dev = resource.device - else - dev = "eth0" + def generate_config + conf = {} + case node[:platform] + when "centos", "redhat", "fedora" + # walk the collection + run_context.resource_collection.each do |resource| + next unless resource.is_a? Chef::Resource::Route + # default to eth0 + dev = if resource.device + resource.device + else + "eth0" + end + + conf[dev] = "" if conf[dev].nil? + case @action + when :add + conf[dev] << config_file_contents(:add, target: resource.target, netmask: resource.netmask, gateway: resource.gateway) if resource.action == [:add] + when :delete + # need to do this for the case when the last route on an int + # is removed + conf[dev] << config_file_contents(:delete) + end end - - conf[dev] = String.new if conf[dev].nil? - case @action - when :add - conf[dev] << config_file_contents(:add, :target => resource.target, :netmask => resource.netmask, :gateway => resource.gateway) if resource.action == [:add] - when :delete - # need to do this for the case when the last route on an int - # is removed - conf[dev] << config_file_contents(:delete) + conf.each do |k, v| + network_file_name = "/etc/sysconfig/network-scripts/route-#{k}" + converge_by("write route route.#{k}\n#{conf[k]} to #{network_file_name}") do + network_file = ::File.new(network_file_name, "w") + network_file.puts(conf[k]) + Chef::Log.debug("#{new_resource} writing route.#{k}\n#{conf[k]}") + network_file.close + end end end end - conf.each do |k, v| - network_file_name = "/etc/sysconfig/network-scripts/route-#{k}" - converge_by ("write route route.#{k}\n#{conf[k]} to #{ network_file_name }") do - network_file = ::File.new(network_file_name, "w") - network_file.puts(conf[k]) - Chef::Log.debug("#{@new_resource} writing route.#{k}\n#{conf[k]}") - network_file.close + + def generate_command(action) + target = new_resource.target + target = "#{target}/#{MASK[new_resource.netmask.to_s]}" if new_resource.netmask + + case action + when :add + command = [ "ip", "route", "replace", target ] + command += [ "via", new_resource.gateway ] if new_resource.gateway + command += [ "dev", new_resource.device ] if new_resource.device + when :delete + command = [ "ip", "route", "delete", target ] + command += [ "via", new_resource.gateway ] if new_resource.gateway end - end - end - end - def generate_command(action) - common_route_items = "" - common_route_items << "/#{MASK[@new_resource.netmask.to_s]}" if @new_resource.netmask - common_route_items << " via #{@new_resource.gateway} " if @new_resource.gateway - - case action - when :add - command = "ip route replace #{@new_resource.target}" - command << common_route_items - command << " dev #{@new_resource.device} " if @new_resource.device - when :delete - command = "ip route delete #{@new_resource.target}" - command << common_route_items - end + command + end - return command - end + def config_file_contents(action, options = {}) + content = "" + case action + when :add + content << (options[:target]).to_s + content << "/#{MASK[options[:netmask].to_s]}" if options[:netmask] + content << " via #{options[:gateway]}" if options[:gateway] + content << "\n" + end - def config_file_contents(action, options = {}) - content = "" - case action - when :add - content << "#{options[:target]}" - content << "/#{options[:netmask]}" if options[:netmask] - content << " via #{options[:gateway]}" if options[:gateway] - content << "\n" + content + end end - - return content end end diff --git a/lib/chef/provider/service/arch.rb b/lib/chef/provider/service/arch.rb index 2fd32e37aa..e34227036a 100644 --- a/lib/chef/provider/service/arch.rb +++ b/lib/chef/provider/service/arch.rb @@ -66,7 +66,7 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init end end - def enable_service() + def enable_service new_daemons = [] entries = daemons @@ -92,7 +92,7 @@ class Chef::Provider::Service::Arch < Chef::Provider::Service::Init end end - def disable_service() + def disable_service new_daemons = [] entries = daemons diff --git a/lib/chef/provider/service/freebsd.rb b/lib/chef/provider/service/freebsd.rb index 76d8c1d17b..9746dfdef0 100644 --- a/lib/chef/provider/service/freebsd.rb +++ b/lib/chef/provider/service/freebsd.rb @@ -74,7 +74,7 @@ class Chef end requirements.assert(:start, :enable, :reload, :restart) do |a| - a.assertion { service_enable_variable_name != nil } + a.assertion { !service_enable_variable_name.nil? } a.failure_message Chef::Exceptions::Service, "Could not find the service name in #{init_command} and rcvar" # No recovery in whyrun mode - the init file is present but not correct. end diff --git a/lib/chef/provider/service/gentoo.rb b/lib/chef/provider/service/gentoo.rb index 8fb6d1f9af..7bb57113ac 100644 --- a/lib/chef/provider/service/gentoo.rb +++ b/lib/chef/provider/service/gentoo.rb @@ -61,11 +61,11 @@ class Chef::Provider::Service::Gentoo < Chef::Provider::Service::Init end end - def enable_service() + def enable_service shell_out!("/sbin/rc-update add #{@new_resource.service_name} default") end - def disable_service() + def disable_service shell_out!("/sbin/rc-update del #{@new_resource.service_name} default") end end diff --git a/lib/chef/provider/service/insserv.rb b/lib/chef/provider/service/insserv.rb index 76b2ee7477..c3dca10495 100644 --- a/lib/chef/provider/service/insserv.rb +++ b/lib/chef/provider/service/insserv.rb @@ -45,12 +45,12 @@ class Chef current_resource end - def enable_service() + def enable_service shell_out!("/sbin/insserv -r -f #{new_resource.service_name}") shell_out!("/sbin/insserv -d -f #{new_resource.service_name}") end - def disable_service() + def disable_service shell_out!("/sbin/insserv -r -f #{new_resource.service_name}") end end diff --git a/lib/chef/provider/service/macosx.rb b/lib/chef/provider/service/macosx.rb index 648cd9748b..4056b72649 100644 --- a/lib/chef/provider/service/macosx.rb +++ b/lib/chef/provider/service/macosx.rb @@ -181,7 +181,7 @@ class Chef end def set_service_status - return if @plist == nil || @service_label.to_s.empty? + return if @plist.nil? || @service_label.to_s.empty? cmd = "launchctl list #{@service_label}" res = shell_out_as_user(cmd) @@ -197,7 +197,7 @@ class Chef case line.downcase when /\s+\"pid\"\s+=\s+(\d+).*/ pid = $1 - @current_resource.running(!pid.to_i.zero?) + @current_resource.running(pid.to_i != 0) Chef::Log.debug("Current PID for #{@service_label} is #{pid}") end end diff --git a/lib/chef/provider/service/openbsd.rb b/lib/chef/provider/service/openbsd.rb index c60bbf170c..780337e1b6 100644 --- a/lib/chef/provider/service/openbsd.rb +++ b/lib/chef/provider/service/openbsd.rb @@ -72,7 +72,7 @@ class Chef end requirements.assert(:start, :enable, :reload, :restart) do |a| - a.assertion { init_command && builtin_service_enable_variable_name != nil } + a.assertion { init_command && !builtin_service_enable_variable_name.nil? } a.failure_message Chef::Exceptions::Service, "Could not find the service name in #{init_command} and rcvar" # No recovery in whyrun mode - the init file is present but not correct. end diff --git a/lib/chef/provider/service/redhat.rb b/lib/chef/provider/service/redhat.rb index 200a2d3400..21ab678706 100644 --- a/lib/chef/provider/service/redhat.rb +++ b/lib/chef/provider/service/redhat.rb @@ -109,7 +109,7 @@ class Chef (run_levels.nil? || run_levels.empty?) ? "" : "--level #{run_levels.join('')} " end - def enable_service() + def enable_service unless run_levels.nil? || run_levels.empty? disable_levels = current_run_levels - run_levels shell_out! "/sbin/chkconfig --level #{disable_levels.join('')} #{new_resource.service_name} off" unless disable_levels.empty? @@ -117,7 +117,7 @@ class Chef shell_out! "/sbin/chkconfig #{levels}#{new_resource.service_name} on" end - def disable_service() + def disable_service shell_out! "/sbin/chkconfig #{levels}#{new_resource.service_name} off" end end diff --git a/lib/chef/provider/support/yum_repo.erb b/lib/chef/provider/support/yum_repo.erb index 7d9a2d09e2..6f1325573d 100644 --- a/lib/chef/provider/support/yum_repo.erb +++ b/lib/chef/provider/support/yum_repo.erb @@ -4,8 +4,13 @@ [<%= @config.repositoryid %>] name=<%= @config.description %> <% if @config.baseurl %> -baseurl=<%= @config.baseurl %> -<% end %> +baseurl=<%= case @config.baseurl + when Array + @config.baseurl.join("\n") + else + @config.baseurl + end %> +<% end -%> <% if @config.cost %> cost=<%= @config.cost %> <% end %> @@ -24,7 +29,9 @@ exclude=<%= @config.exclude %> failovermethod=<%= @config.failovermethod %> <% end %> <% if @config.fastestmirror_enabled %> -fastestmirror_enabled=<%= @config.fastestmirror_enabled %> +fastestmirror_enabled=1 +<% else %> +fastestmirror_enabled=0 <% end %> <% if @config.gpgcheck %> gpgcheck=1 diff --git a/lib/chef/provider/systemd_unit.rb b/lib/chef/provider/systemd_unit.rb index a656fbbf80..5175dc6be9 100644 --- a/lib/chef/provider/systemd_unit.rb +++ b/lib/chef/provider/systemd_unit.rb @@ -20,6 +20,7 @@ require "chef/provider" require "chef/mixin/which" require "chef/mixin/shell_out" require "chef/resource/file" +require "chef/resource/file/verification/systemd_unit" require "iniparse" class Chef @@ -193,6 +194,7 @@ class Chef f.group "root" f.mode "0644" f.content new_resource.to_ini + f.verify :systemd_unit end.run_action(action) end diff --git a/lib/chef/provider/user.rb b/lib/chef/provider/user.rb index 4b05ac8f5e..de94871a87 100644 --- a/lib/chef/provider/user.rb +++ b/lib/chef/provider/user.rb @@ -39,7 +39,7 @@ class Chef if @new_resource.gid.is_a? String @new_resource.gid(Etc.getgrnam(@new_resource.gid).gid) end - rescue ArgumentError => e + rescue ArgumentError @group_name_resolved = false end @@ -53,7 +53,7 @@ class Chef begin user_info = Etc.getpwnam(@new_resource.username) - rescue ArgumentError => e + rescue ArgumentError @user_exists = false Chef::Log.debug("#{@new_resource} user does not exist") user_info = nil @@ -97,7 +97,7 @@ class Chef requirements.assert(:all_actions) do |a| a.assertion { @shadow_lib_ok } a.failure_message Chef::Exceptions::MissingLibrary, "You must have ruby-shadow installed for password support!" - a.whyrun "ruby-shadow is not installed. Attempts to set user password will cause failure. Assuming that this gem will have been previously installed." + + a.whyrun "ruby-shadow is not installed. Attempts to set user password will cause failure. Assuming that this gem will have been previously installed." \ "Note that user update converge may report false-positive on the basis of mismatched password. " end requirements.assert(:modify, :lock, :unlock) do |a| @@ -137,34 +137,31 @@ class Chef end def action_remove - if @user_exists - converge_by("remove user #{@new_resource.username}") do - remove_user - Chef::Log.info("#{@new_resource} removed") - end + return unless @user_exists + converge_by("remove user #{@new_resource.username}") do + remove_user + Chef::Log.info("#{@new_resource} removed") end end def action_manage - if @user_exists && compare_user - converge_by("manage user #{@new_resource.username}") do - manage_user - Chef::Log.info("#{@new_resource} managed") - end + return unless @user_exists && compare_user + converge_by("manage user #{@new_resource.username}") do + manage_user + Chef::Log.info("#{@new_resource} managed") end end def action_modify - if compare_user - converge_by("modify user #{@new_resource.username}") do - manage_user - Chef::Log.info("#{@new_resource} modified") - end + return unless compare_user + converge_by("modify user #{@new_resource.username}") do + manage_user + Chef::Log.info("#{@new_resource} modified") end end def action_lock - if check_lock() == false + if check_lock == false converge_by("lock the user #{@new_resource.username}") do lock_user Chef::Log.info("#{@new_resource} locked") @@ -175,7 +172,7 @@ class Chef end def action_unlock - if check_lock() == true + if check_lock == true converge_by("unlock user #{@new_resource.username}") do unlock_user Chef::Log.info("#{@new_resource} unlocked") diff --git a/lib/chef/provider/user/aix.rb b/lib/chef/provider/user/aix.rb index 8ac229ae4d..0e81c76bbc 100644 --- a/lib/chef/provider/user/aix.rb +++ b/lib/chef/provider/user/aix.rb @@ -23,7 +23,7 @@ class Chef provides :user, os: "aix" provides :aix_user - UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]] + UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]].freeze def create_user super @@ -44,53 +44,52 @@ class Chef end def check_lock - lock_info = shell_out!("lsuser -a account_locked #{new_resource.username}") + lock_info = shell_out_compact!("lsuser", "-a", "account_locked", new_resource.username) if whyrun_mode? && passwd_s.stdout.empty? && lock_info.stderr.match(/does not exist/) # if we're in whyrun mode and the user is not yet created we assume it would be return false end - raise Chef::Exceptions::User, "Cannot determine if #{@new_resource} is locked!" if lock_info.stdout.empty? + raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if lock_info.stdout.empty? status = /\S+\s+account_locked=(\S+)/.match(lock_info.stdout) - if status && status[1] == "true" - @locked = true - else - @locked = false - end + @locked = + if status && status[1] == "true" + true + else + false + end @locked end def lock_user - shell_out!("chuser account_locked=true #{new_resource.username}") + shell_out_compact!("chuser", "account_locked=true", new_resource.username) end def unlock_user - shell_out!("chuser account_locked=false #{new_resource.username}") + shell_out_compact!("chuser", "account_locked=false", new_resource.username) end private def add_password - if @current_resource.password != @new_resource.password && @new_resource.password - Chef::Log.debug("#{@new_resource.username} setting password to #{@new_resource.password}") - command = "echo '#{@new_resource.username}:#{@new_resource.password}' | chpasswd -e" - shell_out!(command) - end + return unless current_resource.password != new_resource.password && new_resource.password + Chef::Log.debug("#{new_resource.username} setting password to #{new_resource.password}") + command = "echo '#{new_resource.username}:#{new_resource.password}' | chpasswd -e" + shell_out!(command) end # Aix specific handling to update users home directory. def manage_home + return unless updating_home? && managing_home_dir? # -m option does not work on aix, so move dir. - if updating_home? && managing_home_dir? - universal_options.delete("-m") - if ::File.directory?(@current_resource.home) - Chef::Log.debug("Changing users home directory from #{@current_resource.home} to #{new_resource.home}") - shell_out!("mv #{@current_resource.home} #{new_resource.home}") - else - Chef::Log.debug("Creating users home directory #{new_resource.home}") - shell_out!("mkdir -p #{new_resource.home}") - end + universal_options.delete("-m") + if ::File.directory?(current_resource.home) + Chef::Log.debug("Changing users home directory from #{current_resource.home} to #{new_resource.home}") + FileUtils.mv current_resource.home, new_resource.home + else + Chef::Log.debug("Creating users home directory #{new_resource.home}") + FileUtils.mkdir_p new_resource.home end end diff --git a/lib/chef/provider/user/dscl.rb b/lib/chef/provider/user/dscl.rb index 16d60ba116..2302a874e2 100644 --- a/lib/chef/provider/user/dscl.rb +++ b/lib/chef/provider/user/dscl.rb @@ -65,12 +65,12 @@ class Chef end requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?("/usr/bin/dscl") } + a.assertion { ::File.exist?("/usr/bin/dscl") } a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/dscl' on the system for #{new_resource}!") end requirements.assert(:all_actions) do |a| - a.assertion { ::File.exists?("/usr/bin/plutil") } + a.assertion { ::File.exist?("/usr/bin/plutil") } a.failure_message(Chef::Exceptions::User, "Cannot find binary '/usr/bin/plutil' on the system for #{new_resource}!") end @@ -199,7 +199,7 @@ user password using shadow hash.") # Create a user using dscl # def dscl_create_user - run_dscl("create /Users/#{new_resource.username}") + run_dscl("create", "/Users/#{new_resource.username}") end # @@ -208,7 +208,7 @@ user password using shadow hash.") # def dscl_create_comment comment = new_resource.comment || new_resource.username - run_dscl("create /Users/#{new_resource.username} RealName '#{comment}'") + run_dscl("create", "/Users/#{new_resource.username}", "RealName", comment) end # @@ -224,7 +224,7 @@ user password using shadow hash.") raise(Chef::Exceptions::RequestedUIDUnavailable, "uid #{new_resource.uid} is already in use") end - run_dscl("create /Users/#{new_resource.username} UniqueID #{new_resource.uid}") + run_dscl("create", "/Users/#{new_resource.username}", "UniqueID", new_resource.uid) end # @@ -235,7 +235,7 @@ user password using shadow hash.") uid = nil base_uid = new_resource.system ? 200 : 500 next_uid_guess = base_uid - users_uids = run_dscl("list /Users uid") + users_uids = run_dscl("list", "/Users", "uid") while next_uid_guess < search_limit + base_uid if users_uids =~ Regexp.new("#{Regexp.escape(next_uid_guess.to_s)}\n") next_uid_guess += 1 @@ -244,7 +244,7 @@ user password using shadow hash.") break end end - return uid || raise("uid not found. Exhausted. Searched #{search_limit} times") + uid || raise("uid not found. Exhausted. Searched #{search_limit} times") end # @@ -252,18 +252,18 @@ user password using shadow hash.") # def uid_used?(uid) return false unless uid - users_uids = run_dscl("list /Users uid").split("\n") - uid_map = users_uids.inject({}) do |tmap, tuid| + users_uids = run_dscl("list", "/Users", "uid").split("\n") + uid_map = users_uids.each_with_object({}) do |tuid, tmap| x = tuid.split tmap[x[1]] = x[0] tmap end if uid_map[uid.to_s] - unless uid_map[uid.to_s] == new_resource.username.to_s + unless uid_map[uid.to_s] == new_resource.username return true end end - return false + false end # @@ -277,14 +277,14 @@ user password using shadow hash.") new_resource.gid(STAFF_GROUP_ID) elsif !new_resource.gid.to_s.match(/^\d+$/) begin - possible_gid = run_dscl("read /Groups/#{new_resource.gid} PrimaryGroupID").split(" ").last - rescue Chef::Exceptions::DsclCommandFailed => e - raise Chef::Exceptions::GroupIDNotFound.new("Group not found for #{new_resource.gid} when creating user #{new_resource.username}") + possible_gid = run_dscl("read", "/Groups/#{new_resource.gid}", "PrimaryGroupID").split(" ").last + rescue Chef::Exceptions::DsclCommandFailed + raise Chef::Exceptions::GroupIDNotFound, "Group not found for #{new_resource.gid} when creating user #{new_resource.username}" end # XXX: mutates the new resource new_resource.gid(possible_gid) if possible_gid && possible_gid.match(/^\d+$/) end - run_dscl("create /Users/#{new_resource.username} PrimaryGroupID '#{new_resource.gid}'") + run_dscl("create", "/Users/#{new_resource.username}", "PrimaryGroupID", new_resource.gid) end # @@ -293,7 +293,7 @@ user password using shadow hash.") # def dscl_set_home if new_resource.home.nil? || new_resource.home.empty? - run_dscl("delete /Users/#{new_resource.username} NFSHomeDirectory") + run_dscl("delete", "/Users/#{new_resource.username}", "NFSHomeDirectory") return end @@ -308,7 +308,7 @@ user password using shadow hash.") move_home end end - run_dscl("create /Users/#{new_resource.username} NFSHomeDirectory '#{new_resource.home}'") + run_dscl("create", "/Users/#{new_resource.username}", "NFSHomeDirectory", new_resource.home) end def validate_home_dir_specification! @@ -318,17 +318,17 @@ user password using shadow hash.") end def current_home_exists? - ::File.exist?("#{current_resource.home}") + ::File.exist?(current_resource.home) end def new_home_exists? - ::File.exist?("#{new_resource.home}") + ::File.exist?(new_resource.home) end def ditto_home skel = "/System/Library/User Template/English.lproj" - raise(Chef::Exceptions::User, "can't find skel at: #{skel}") unless ::File.exists?(skel) - shell_out! "ditto '#{skel}' '#{new_resource.home}'" + raise(Chef::Exceptions::User, "can't find skel at: #{skel}") unless ::File.exist?(skel) + shell_out_compact!("ditto", skel, new_resource.home) ::FileUtils.chown_R(new_resource.username, new_resource.gid.to_s, new_resource.home) end @@ -338,7 +338,7 @@ user password using shadow hash.") src = current_resource.home FileUtils.mkdir_p(new_resource.home) files = ::Dir.glob("#{Chef::Util::PathHelper.escape_glob_dir(src)}/*", ::File::FNM_DOTMATCH) - ["#{src}/.", "#{src}/.."] - ::FileUtils.mv(files, new_resource.home, :force => true) + ::FileUtils.mv(files, new_resource.home, force: true) ::FileUtils.rmdir(src) ::FileUtils.chown_R(new_resource.username, new_resource.gid.to_s, new_resource.home) end @@ -347,10 +347,10 @@ user password using shadow hash.") # Sets the shell for the user using dscl. # def dscl_set_shell - if new_resource.shell || ::File.exists?("#{new_resource.shell}") - run_dscl("create /Users/#{new_resource.username} UserShell '#{new_resource.shell}'") + if new_resource.shell + run_dscl("create", "/Users/#{new_resource.username}", "UserShell", new_resource.shell) else - run_dscl("create /Users/#{new_resource.username} UserShell '/usr/bin/false'") + run_dscl("create", "/Users/#{new_resource.username}", "UserShell", "/usr/bin/false") end end @@ -367,9 +367,8 @@ user password using shadow hash.") # Shadow info is saved as binary plist. Convert the info to binary plist. shadow_info_binary = StringIO.new - command = Mixlib::ShellOut.new("plutil -convert binary1 -o - -", - :input => shadow_info.to_plist, :live_stream => shadow_info_binary) - command.run_command + shell_out_compact("plutil", "-convert", "binary1", "-o", "-", "-", + input: shadow_info.to_plist, live_stream: shadow_info_binary) if user_info.nil? # User is just created. read_user_info() will read the fresh information @@ -401,7 +400,7 @@ user password using shadow hash.") # Create a random 4 byte salt salt = OpenSSL::Random.random_bytes(4) encoded_password = OpenSSL::Digest::SHA512.hexdigest(salt + new_resource.password) - hash_value = salt.unpack("H*").first + encoded_password + salt.unpack("H*").first + encoded_password end shadow_info["SALTED-SHA512"] = StringIO.new @@ -449,21 +448,21 @@ user password using shadow hash.") end # Remove the user from its groups - run_dscl("list /Groups").each_line do |group| + run_dscl("list", "/Groups").each_line do |group| if member_of_group?(group.chomp) - run_dscl("delete /Groups/#{group.chomp} GroupMembership '#{new_resource.username}'") + run_dscl("delete", "/Groups/#{group.chomp}", "GroupMembership", new_resource.username) end end # Remove user account - run_dscl("delete /Users/#{new_resource.username}") + run_dscl("delete", "/Users/#{new_resource.username}") end # # Locks the user. # def lock_user - run_dscl("append /Users/#{new_resource.username} AuthenticationAuthority ';DisabledUser;'") + run_dscl("append", "/Users/#{new_resource.username}", "AuthenticationAuthority", ";DisabledUser;") end # @@ -471,7 +470,7 @@ user password using shadow hash.") # def unlock_user auth_string = authentication_authority.gsub(/AuthenticationAuthority: /, "").gsub(/;DisabledUser;/, "").strip - run_dscl("create /Users/#{new_resource.username} AuthenticationAuthority '#{auth_string}'") + run_dscl("create", "/Users/#{new_resource.username}", "AuthenticationAuthority", auth_string) end # @@ -489,7 +488,7 @@ user password using shadow hash.") # This is the interface base User provider requires to provide idempotency. # def check_lock - return @locked = locked? + @locked = locked? end # @@ -501,11 +500,11 @@ user password using shadow hash.") # given attribute. # def diverged?(parameter) - parameter_updated?(parameter) && (not new_resource.send(parameter).nil?) + parameter_updated?(parameter) && !new_resource.send(parameter).nil? end def parameter_updated?(parameter) - not (new_resource.send(parameter) == current_resource.send(parameter)) + !(new_resource.send(parameter) == current_resource.send(parameter)) end # @@ -551,7 +550,7 @@ user password using shadow hash.") def member_of_group?(group_name) membership_info = "" begin - membership_info = run_dscl("read /Groups/#{group_name}") + membership_info = run_dscl("read", "/Groups/#{group_name}") rescue Chef::Exceptions::DsclCommandFailed # Raised if the group doesn't contain any members end @@ -568,14 +567,14 @@ user password using shadow hash.") # A simple map of Chef's terms to DSCL's terms. DSCL_PROPERTY_MAP = { - :uid => "uid", - :gid => "gid", - :home => "home", - :shell => "shell", - :comment => "realname", - :password => "passwd", - :auth_authority => "authentication_authority", - :shadow_hash => "ShadowHashData", + uid: "uid", + gid: "gid", + home: "home", + shell: "shell", + comment: "realname", + password: "passwd", + auth_authority: "authentication_authority", + shadow_hash: "ShadowHashData", }.freeze # Directory where the user plist files are stored for versions 10.7 and above @@ -590,11 +589,11 @@ user password using shadow hash.") # We flush the cache here in order to make sure that we read fresh information # for the user. - shell_out("dscacheutil '-flushcache'") + shell_out_compact("dscacheutil", "-flushcache") # FIXME: this is MacOS version dependent begin user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist" - user_plist_info = run_plutil("convert xml1 -o - #{user_plist_file}") + user_plist_info = run_plutil("convert", "xml1", "-o", "-", user_plist_file) user_info = Plist.parse_xml(user_plist_info) rescue Chef::Exceptions::PlistUtilCommandFailed end @@ -609,7 +608,7 @@ user password using shadow hash.") def save_user_info(user_info) user_plist_file = "#{USER_PLIST_DIRECTORY}/#{new_resource.username}.plist" Plist::Emit.save_plist(user_info, user_plist_file) - run_plutil("convert binary1 #{user_plist_file}") + run_plutil("convert", "binary1", user_plist_file) end # @@ -658,7 +657,9 @@ user password using shadow hash.") end def run_dscl(*args) - result = shell_out("dscl . -#{args.join(' ')}") + argdup = args.dup + cmd = argdup.shift + result = shell_out_compact("dscl", ".", "-#{cmd}", argdup) return "" if ( args.first =~ /^delete/ ) && ( result.exitstatus != 0 ) raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") unless result.exitstatus == 0 raise(Chef::Exceptions::DsclCommandFailed, "dscl error: #{result.inspect}") if result.stdout =~ /No such key: / @@ -666,17 +667,19 @@ user password using shadow hash.") end def run_plutil(*args) - result = shell_out("plutil -#{args.join(' ')}") + argdup = args.dup + cmd = argdup.shift + result = shell_out_compact("plutil", "-#{cmd}", argdup) raise(Chef::Exceptions::PlistUtilCommandFailed, "plutil error: #{result.inspect}") unless result.exitstatus == 0 if result.stdout.encoding == Encoding::ASCII_8BIT - result.stdout.encode("utf-8", "binary", :undef => :replace, :invalid => :replace, :replace => "?") + result.stdout.encode("utf-8", "binary", undef: :replace, invalid: :replace, replace: "?") else result.stdout end end def convert_binary_plist_to_xml(binary_plist_string) - Mixlib::ShellOut.new("plutil -convert xml1 -o - -", :input => binary_plist_string).run_command.stdout + shell_out_compact("plutil", "-convert", "xml1", "-o", "-", "-", input: binary_plist_string).stdout end def convert_to_binary(string) diff --git a/lib/chef/provider/user/linux.rb b/lib/chef/provider/user/linux.rb index 968cf771e4..445421ad38 100644 --- a/lib/chef/provider/user/linux.rb +++ b/lib/chef/provider/user/linux.rb @@ -24,23 +24,23 @@ class Chef provides :user, os: "linux" def create_user - shell_out!(*clean_array("useradd", universal_options, useradd_options, new_resource.username)) + shell_out_compact!("useradd", universal_options, useradd_options, new_resource.username) end def manage_user - shell_out!(*clean_array("usermod", universal_options, usermod_options, new_resource.username)) + shell_out_compact!("usermod", universal_options, usermod_options, new_resource.username) end def remove_user - shell_out!(*clean_array("userdel", userdel_options, new_resource.username)) + shell_out_compact!("userdel", userdel_options, new_resource.username) end def lock_user - shell_out!(*clean_array("usermod", "-L", new_resource.username)) + shell_out_compact!("usermod", "-L", new_resource.username) end def unlock_user - shell_out!(*clean_array("usermod", "-U", new_resource.username)) + shell_out_compact!("usermod", "-U", new_resource.username) end # common to usermod and useradd @@ -69,11 +69,11 @@ class Chef def useradd_options opts = [] opts << "-r" if new_resource.system - if managing_home_dir? - opts << "-m" - else - opts << "-M" - end + opts << if managing_home_dir? + "-m" + else + "-M" + end opts end @@ -97,15 +97,12 @@ class Chef def check_lock # there's an old bug in rhel (https://bugzilla.redhat.com/show_bug.cgi?id=578534) # which means that both 0 and 1 can be success. - passwd_s = shell_out("passwd", "-S", new_resource.username, returns: [ 0, 1 ]) + passwd_s = shell_out_compact("passwd", "-S", new_resource.username, returns: [ 0, 1 ]) # checking "does not exist" has to come before exit code handling since centos and ubuntu differ in exit codes if passwd_s.stderr =~ /does not exist/ - if whyrun_mode? - return false - else - raise Chef::Exceptions::User, "User #{new_resource.username} does not exist when checking lock status for #{new_resource}" - end + return false if whyrun_mode? + raise Chef::Exceptions::User, "User #{new_resource.username} does not exist when checking lock status for #{new_resource}" end # now raise if we didn't get a 0 or 1 (see above) diff --git a/lib/chef/provider/user/pw.rb b/lib/chef/provider/user/pw.rb index b210374eb9..42d862a983 100644 --- a/lib/chef/provider/user/pw.rb +++ b/lib/chef/provider/user/pw.rb @@ -27,49 +27,45 @@ class Chef def load_current_resource super - raise Chef::Exceptions::User, "Could not find binary /usr/sbin/pw for #{@new_resource}" unless ::File.exists?("/usr/sbin/pw") + raise Chef::Exceptions::User, "Could not find binary /usr/sbin/pw for #{new_resource}" unless ::File.exist?("/usr/sbin/pw") end def create_user - command = "pw useradd" - command << set_options - run_command(:command => command) + shell_out_compact!("pw", "useradd", set_options) modify_password end def manage_user - command = "pw usermod" - command << set_options - run_command(:command => command) + shell_out_compact!("pw", "usermod", set_options) modify_password end def remove_user - command = "pw userdel #{@new_resource.username}" - command << " -r" if managing_home_dir? - run_command(:command => command) + command = [ "pw", "userdel", new_resource.username ] + command << "-r" if managing_home_dir? + shell_out_compact!(command) end def check_lock - case @current_resource.password - when /^\*LOCKED\*/ - @locked = true - else - @locked = false - end + @locked = case current_resource.password + when /^\*LOCKED\*/ + true + else + false + end @locked end def lock_user - run_command(:command => "pw lock #{@new_resource.username}") + shell_out_compact!("pw", "lock", new_resource.username) end def unlock_user - run_command(:command => "pw unlock #{@new_resource.username}") + shell_out_compact!("pw", "unlock", new_resource.username) end def set_options - opts = " #{@new_resource.username}" + opts = [ new_resource.username ] field_list = { "comment" => "-c", @@ -80,26 +76,26 @@ class Chef } field_list.sort { |a, b| a[0] <=> b[0] }.each do |field, option| field_symbol = field.to_sym - if @current_resource.send(field_symbol) != @new_resource.send(field_symbol) - if @new_resource.send(field_symbol) - Chef::Log.debug("#{@new_resource} setting #{field} to #{@new_resource.send(field_symbol)}") - opts << " #{option} '#{@new_resource.send(field_symbol)}'" - end + next unless current_resource.send(field_symbol) != new_resource.send(field_symbol) + if new_resource.send(field_symbol) + Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field_symbol)}") + opts << option + opts << new_resource.send(field_symbol) end end if managing_home_dir? - Chef::Log.debug("#{@new_resource} is managing the users home directory") - opts << " -m" + Chef::Log.debug("#{new_resource} is managing the users home directory") + opts << "-m" end opts end def modify_password - if (not @new_resource.password.nil?) && (@current_resource.password != @new_resource.password) + if !new_resource.password.nil? && (current_resource.password != new_resource.password) Chef::Log.debug("#{new_resource} updating password") - command = "pw usermod #{@new_resource.username} -H 0" - status = popen4(command, :waitlast => true) do |pid, stdin, stdout, stderr| - stdin.puts "#{@new_resource.password}" + command = "pw usermod #{new_resource.username} -H 0" + status = popen4(command, waitlast: true) do |pid, stdin, stdout, stderr| + stdin.puts new_resource.password.to_s end unless status.exitstatus == 0 diff --git a/lib/chef/provider/user/solaris.rb b/lib/chef/provider/user/solaris.rb index 7aa0ceb93a..4e772312ae 100644 --- a/lib/chef/provider/user/solaris.rb +++ b/lib/chef/provider/user/solaris.rb @@ -26,7 +26,7 @@ class Chef class Solaris < Chef::Provider::User::Useradd provides :solaris_user provides :user, os: %w{omnios solaris2} - UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]] + UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:shell, "-s"], [:uid, "-u"]].freeze attr_writer :password_file @@ -46,22 +46,22 @@ class Chef end def check_lock - user = IO.read(@password_file).match(/^#{Regexp.escape(@new_resource.username)}:([^:]*):/) + user = IO.read(@password_file).match(/^#{Regexp.escape(new_resource.username)}:([^:]*):/) # If we're in whyrun mode, and the user is not created, we assume it will be return false if whyrun_mode? && user.nil? - raise Chef::Exceptions::User, "Cannot determine if #{@new_resource} is locked!" if user.nil? + raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if user.nil? @locked = user[1].start_with?("*LK*") end def lock_user - shell_out!("passwd", "-l", new_resource.username) + shell_out_compact!("passwd", "-l", new_resource.username) end def unlock_user - shell_out!("passwd", "-u", new_resource.username) + shell_out_compact!("passwd", "-u", new_resource.username) end private @@ -82,10 +82,9 @@ class Chef end def manage_password - if @current_resource.password != @new_resource.password && @new_resource.password - Chef::Log.debug("#{@new_resource} setting password to #{@new_resource.password}") - write_shadow_file - end + return unless current_resource.password != new_resource.password && new_resource.password + Chef::Log.debug("#{new_resource} setting password to #{new_resource.password}") + write_shadow_file end def write_shadow_file @@ -93,7 +92,7 @@ class Chef ::File.open(@password_file) do |shadow_file| shadow_file.each do |entry| user = entry.split(":").first - if user == @new_resource.username + if user == new_resource.username buffer.write(updated_password(entry)) else buffer.write(entry) @@ -104,7 +103,7 @@ class Chef # FIXME: mostly duplicates code with file provider deploying a file s = ::File.stat(@password_file) - mode = s.mode & 07777 + mode = s.mode & 0o7777 uid = s.uid gid = s.gid @@ -116,7 +115,7 @@ class Chef def updated_password(entry) fields = entry.split(":") - fields[1] = @new_resource.password + fields[1] = new_resource.password fields[2] = days_since_epoch fields.join(":") end diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb index 35a106b0b6..cf6f4e727f 100644 --- a/lib/chef/provider/user/useradd.rb +++ b/lib/chef/provider/user/useradd.rb @@ -23,25 +23,25 @@ class Chef class Provider class User class Useradd < Chef::Provider::User - # MAJOR XXX: this should become the base class of all Useradd providers instead of the linux implementation + # the linux version of this has been forked off, this is the base class now of solaris and AIX and should be abandoned + # and those provider should be rewritten like the linux version. - UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]] + UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]].freeze def create_user command = compile_command("useradd") do |useradd| useradd.concat(universal_options) useradd.concat(useradd_options) end - shell_out!(*command) + shell_out_compact!(command) end def manage_user - unless universal_options.empty? - command = compile_command("usermod") do |u| - u.concat(universal_options) - end - shell_out!(*command) + return if universal_options.empty? + command = compile_command("usermod") do |u| + u.concat(universal_options) end + shell_out_compact!(command) end def remove_user @@ -49,19 +49,19 @@ class Chef command << "-r" if managing_home_dir? command << "-f" if new_resource.force command << new_resource.username - shell_out!(*command) + shell_out_compact!(command) end def check_lock # we can get an exit code of 1 even when it's successful on # rhel/centos (redhat bug 578534). See additional error checks below. - passwd_s = shell_out!("passwd", "-S", new_resource.username, :returns => [0, 1]) + passwd_s = shell_out_compact!("passwd", "-S", new_resource.username, returns: [0, 1]) if whyrun_mode? && passwd_s.stdout.empty? && passwd_s.stderr.match(/does not exist/) # if we're in whyrun mode and the user is not yet created we assume it would be return false end - raise Chef::Exceptions::User, "Cannot determine if #{@new_resource} is locked!" if passwd_s.stdout.empty? + raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if passwd_s.stdout.empty? status_line = passwd_s.stdout.split(" ") case status_line[1] @@ -76,7 +76,7 @@ class Chef unless passwd_s.exitstatus == 0 raise_lock_error = false if %w{redhat centos}.include?(node[:platform]) - passwd_version_check = shell_out!("rpm -q passwd") + passwd_version_check = shell_out_compact!("rpm", "-q", "passwd") passwd_version = passwd_version_check.stdout.chomp unless passwd_version == "passwd-0.73-1" @@ -93,11 +93,11 @@ class Chef end def lock_user - shell_out!("usermod", "-L", new_resource.username) + shell_out_compact!("usermod", "-L", new_resource.username) end def unlock_user - shell_out!("usermod", "-U", new_resource.username) + shell_out_compact!("usermod", "-U", new_resource.username) end def compile_command(base_command) @@ -130,12 +130,10 @@ class Chef end def update_options(field, option, opts) - if @current_resource.send(field).to_s != new_resource.send(field).to_s - if new_resource.send(field) - Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field)}") - opts << option << new_resource.send(field).to_s - end - end + return unless current_resource.send(field).to_s != new_resource.send(field).to_s + return unless new_resource.send(field) + Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field)}") + opts << option << new_resource.send(field).to_s end def useradd_options @@ -150,8 +148,8 @@ class Chef # Pathname#cleanpath does a better job than ::File::expand_path (on both unix and windows) # ::File.expand_path("///tmp") == ::File.expand_path("/tmp") => false # ::File.expand_path("\\tmp") => "C:/tmp" - return true if @current_resource.home.nil? && new_resource.home - new_resource.home && Pathname.new(@current_resource.home).cleanpath != Pathname.new(new_resource.home).cleanpath + return true if current_resource.home.nil? && new_resource.home + new_resource.home && Pathname.new(current_resource.home).cleanpath != Pathname.new(new_resource.home).cleanpath end end diff --git a/lib/chef/provider/user/windows.rb b/lib/chef/provider/user/windows.rb index b086a1e32b..0afa8fa14a 100644 --- a/lib/chef/provider/user/windows.rb +++ b/lib/chef/provider/user/windows.rb @@ -31,31 +31,30 @@ class Chef def initialize(new_resource, run_context) super - @net_user = Chef::Util::Windows::NetUser.new(@new_resource.username) + @net_user = Chef::Util::Windows::NetUser.new(new_resource.username) end def load_current_resource - if @new_resource.gid + if new_resource.gid Chef::Log.warn("The 'gid' attribute is not implemented by the Windows platform. Please use the 'group' resource to assign a user to a group.") end - @current_resource = Chef::Resource::User.new(@new_resource.name) - @current_resource.username(@new_resource.username) - user_info = nil + @current_resource = Chef::Resource::User.new(new_resource.name) + current_resource.username(new_resource.username) begin user_info = @net_user.get_info - @current_resource.uid(user_info[:user_id]) - @current_resource.comment(user_info[:full_name]) - @current_resource.home(user_info[:home_dir]) - @current_resource.shell(user_info[:script_path]) + current_resource.uid(user_info[:user_id]) + current_resource.comment(user_info[:full_name]) + current_resource.home(user_info[:home_dir]) + current_resource.shell(user_info[:script_path]) rescue Chef::Exceptions::UserIDNotFound => e # e.message should be "The user name could not be found" but checking for that could cause a localization bug @user_exists = false - Chef::Log.debug("#{@new_resource} does not exist (#{e.message})") + Chef::Log.debug("#{new_resource} does not exist (#{e.message})") end - @current_resource + current_resource end # Check to see if the user needs any changes @@ -64,12 +63,12 @@ class Chef # <true>:: If a change is required # <false>:: If the users are identical def compare_user - unless @net_user.validate_credentials(@new_resource.password) - Chef::Log.debug("#{@new_resource} password has changed") + unless @net_user.validate_credentials(new_resource.password) + Chef::Log.debug("#{new_resource} password has changed") return true end [ :uid, :comment, :home, :shell ].any? do |user_attrib| - !@new_resource.send(user_attrib).nil? && @new_resource.send(user_attrib) != @current_resource.send(user_attrib) + !new_resource.send(user_attrib).nil? && new_resource.send(user_attrib) != current_resource.send(user_attrib) end end @@ -98,7 +97,7 @@ class Chef end def set_options - opts = { :name => @new_resource.username } + opts = { name: new_resource.username } field_list = { "comment" => "full_name", @@ -110,14 +109,12 @@ class Chef field_list.sort { |a, b| a[0] <=> b[0] }.each do |field, option| field_symbol = field.to_sym - if @current_resource.send(field_symbol) != @new_resource.send(field_symbol) - if @new_resource.send(field_symbol) - unless field_symbol == :password - Chef::Log.debug("#{@new_resource} setting #{field} to #{@new_resource.send(field_symbol)}") - end - opts[option.to_sym] = @new_resource.send(field_symbol) - end + next unless current_resource.send(field_symbol) != new_resource.send(field_symbol) + next unless new_resource.send(field_symbol) + unless field_symbol == :password + Chef::Log.debug("#{new_resource} setting #{field} to #{new_resource.send(field_symbol)}") end + opts[option.to_sym] = new_resource.send(field_symbol) end opts end |