From e493f8acf9fe40baadf4fcd4e1176afa6264d768 Mon Sep 17 00:00:00 2001 From: Max Martin Date: Thu, 7 Apr 2011 16:17:04 -0700 Subject: (#6856) Copy dangling symlinks with 'links => manage' File resource. When copying symlinks with 'links => manage', there is no need to examine the content of the link target, since the link is supposed to be copied as-is. Skip copying this value to the resource from the metadata (source), since the content will be nil in the dangling symlink case. Paired-with: Jacob Helwig --- lib/puppet/type/file/source.rb | 1 + spec/unit/type/file/source_spec.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb index 6dda7957c..6ebec51fe 100755 --- a/lib/puppet/type/file/source.rb +++ b/lib/puppet/type/file/source.rb @@ -114,6 +114,7 @@ module Puppet param_name = (metadata_method == :checksum) ? :content : metadata_method next if metadata_method == :owner and !Puppet.features.root? next if metadata_method == :checksum and metadata.ftype == "directory" + next if metadata_method == :checksum and metadata.ftype == "link" and metadata.links == :manage if resource[param_name].nil? or resource[param_name] == :absent resource[param_name] = metadata.send(metadata_method) diff --git a/spec/unit/type/file/source_spec.rb b/spec/unit/type/file/source_spec.rb index 00cc2f235..6e04fa2a5 100755 --- a/spec/unit/type/file/source_spec.rb +++ b/spec/unit/type/file/source_spec.rb @@ -187,6 +187,7 @@ describe Puppet::Type.type(:file).attrclass(:source) do describe "and the source is a link" do it "should set the target to the link destination" do @metadata.stubs(:ftype).returns "link" + @metadata.stubs(:links).returns "manage" @resource.stubs(:[]) @resource.stubs(:[]=) -- cgit From 54b9f5d9afcb102b33f7f604eb6da15d8b75f6e9 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Thu, 24 Mar 2011 03:22:20 +1100 Subject: (#6818) Stop from getting Rails 3 named_scope deprecation warning We want our Rails models in Puppet to work under Rails 2 or 3, but we don't want the deprecation warnings since we can't control what version of Rails the client is running. DEPRECATION WARNING: Base.named_scope has been deprecated, please use Base.scope instead Reviewed-by: Nick Lewis --- lib/puppet/rails/inventory_node.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/puppet/rails/inventory_node.rb b/lib/puppet/rails/inventory_node.rb index 52f8621a4..da7e61040 100644 --- a/lib/puppet/rails/inventory_node.rb +++ b/lib/puppet/rails/inventory_node.rb @@ -3,6 +3,11 @@ require 'puppet/rails/inventory_fact' class Puppet::Rails::InventoryNode < ::ActiveRecord::Base has_many :facts, :class_name => "Puppet::Rails::InventoryFact", :foreign_key => :node_id, :dependent => :delete_all + if Puppet::Util.activerecord_version >= 3.0 + # Prevents "DEPRECATION WARNING: Base.named_scope has been deprecated, please use Base.scope instead" + ActiveRecord::NamedScope::ClassMethods.module_eval { alias :named_scope :scope } + end + named_scope :has_fact_with_value, lambda { |name,value| { :conditions => ["inventory_facts.name = ? AND inventory_facts.value = ?", name, value], -- cgit From 4b73d41be6436e3eb92d86340aed08dbce1f63cf Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Fri, 8 Apr 2011 16:06:31 -0700 Subject: maint: Fix sporadic sqlite error ActiveRecord::StatementInvalid: SQLite3::IOException: disk I/O error This happened if you ran these tests in the following order since Rails wasn't disconnecting between tests. rspec spec/unit/indirector/facts/inventory_active_record_spec.rb spec/unit/indirector/node/active_record_spec.rb Paired-with: Nick Lewis --- spec/unit/indirector/facts/inventory_active_record_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/unit/indirector/facts/inventory_active_record_spec.rb b/spec/unit/indirector/facts/inventory_active_record_spec.rb index 9558abde2..538aa5f47 100644 --- a/spec/unit/indirector/facts/inventory_active_record_spec.rb +++ b/spec/unit/indirector/facts/inventory_active_record_spec.rb @@ -29,6 +29,7 @@ describe "Puppet::Node::Facts::InventoryActiveRecord", :if => (Puppet.features.r after :each do Puppet::Rails.teardown + ActiveRecord::Base.remove_connection end describe "#save" do -- cgit From 23c9663d2142b9c674257fd47952d5e58c8ca7a7 Mon Sep 17 00:00:00 2001 From: Matt Robinson Date: Fri, 8 Apr 2011 16:05:41 -0700 Subject: maint: Fix sqlite3 require to really be optional You need to specifically rescue LoadError if you want requires to be optional. Paired-with: Nick Lewis --- spec/unit/indirector/facts/inventory_active_record_spec.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/unit/indirector/facts/inventory_active_record_spec.rb b/spec/unit/indirector/facts/inventory_active_record_spec.rb index 538aa5f47..022150c76 100644 --- a/spec/unit/indirector/facts/inventory_active_record_spec.rb +++ b/spec/unit/indirector/facts/inventory_active_record_spec.rb @@ -1,7 +1,10 @@ #!/usr/bin/env ruby require File.dirname(__FILE__) + '/../../../spec_helper' -require 'sqlite3' rescue nil +begin + require 'sqlite3' +rescue LoadError +end require 'tempfile' require 'puppet/rails' -- cgit From bb19dea3912610c652d55c1de00c8e8e9f7698b5 Mon Sep 17 00:00:00 2001 From: Ben Hughes Date: Fri, 8 Apr 2011 11:33:45 +1000 Subject: (#7018) explain internals better in service provider documentation Add explicit reasoning for hasstatus in the documentation with certain "virtual" services. Just to clear up why notify => Service["something_virtual"] requires hasstatus defining for it to function. --- lib/puppet/type/service.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index 0d09c3d5d..8387dd52d 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -97,7 +97,10 @@ module Puppet `status` parameter). If you do not specify anything, then the service name will be - looked for in the process table." + looked for in the process table. Be aware that 'virtual' init + scripts such as networking, that don't have something in the + process table need this functionality to be used with + notify/require trigger actions." newvalues(:true, :false) end -- cgit From b7f4ff7c17f1314fab08662c7082500ecfc1e5a8 Mon Sep 17 00:00:00 2001 From: nfagerlund Date: Mon, 11 Apr 2011 16:01:08 -0700 Subject: (#7018) Give more context on the service type's assumptions. Wording tweaks. Refactoring the @doc string for clarity. --- lib/puppet/type/service.rb | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index 8387dd52d..3658e2837 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -8,19 +8,24 @@ module Puppet newtype(:service) do @doc = "Manage running services. Service support unfortunately varies - widely by platform -- some platforms have very little if any + widely by platform --- some platforms have very little if any concept of a running service, and some have a very codified and powerful concept. Puppet's service support will generally be able - to make up for any inherent shortcomings (e.g., if there is no + to do the right thing regardless (e.g., if there is no 'status' command, then Puppet will look in the process table for a command matching the service name), but the more information you - can provide the better behaviour you will get. Or, you can just - use a platform that has very good service support. + can provide, the better behaviour you will get. In particular, any + virtual services that don't have a predictable entry in the process table + (for example, `network` on Red Hat/CentOS systems) will manifest odd + behavior on restarts if you don't specify `hasstatus` or a `status` + command. Note that if a `service` receives an event from another resource, the service will get restarted. The actual command to restart the - service depends on the platform. You can provide a special command - for restarting with the `restart` attribute." + service depends on the platform. You can provide an explicit command + for restarting with the `restart` attribute, or use the init script's + restart command with the `hasrestart` attribute; if you do neither, + the service's stop and start commands will be used." feature :refreshable, "The provider can restart the service.", :methods => [:restart] @@ -93,14 +98,14 @@ module Puppet that a large number of init scripts on different platforms do not support any kind of status command; thus, you must specify manually whether the service you are running has such a - command (or you can specify a specific command using the - `status` parameter). - - If you do not specify anything, then the service name will be - looked for in the process table. Be aware that 'virtual' init - scripts such as networking, that don't have something in the - process table need this functionality to be used with - notify/require trigger actions." + command. Alternately, you can provide a specific command using the + `status` attribute. + + If you specify neither of these, then Puppet will look for the + service name in the process table. Be aware that 'virtual' init + scripts such as networking will respond poorly to refresh events + (via notify and subscribe relationships) if you don't override + this default behavior." newvalues(:true, :false) end -- cgit From 65c4e14621786e51c6eb3621098abbbadd7aa89d Mon Sep 17 00:00:00 2001 From: James Turnbull Date: Thu, 14 Apr 2011 02:05:10 +1000 Subject: Fixed #7082 - Added system support for groups --- lib/puppet/provider/group/groupadd.rb | 3 +++ lib/puppet/type/group.rb | 12 +++++++++++- spec/unit/provider/group/groupadd_spec.rb | 12 +++++++++++- spec/unit/type/group_spec.rb | 9 ++++++++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/lib/puppet/provider/group/groupadd.rb b/lib/puppet/provider/group/groupadd.rb index 82ed4c0c7..bcc08d9f7 100644 --- a/lib/puppet/provider/group/groupadd.rb +++ b/lib/puppet/provider/group/groupadd.rb @@ -9,6 +9,8 @@ Puppet::Type.type(:group).provide :groupadd, :parent => Puppet::Provider::NameSe commands :add => "groupadd", :delete => "groupdel", :modify => "groupmod" + has_feature :system_groups + verify :gid, "GID must be an integer" do |value| value.is_a? Integer end @@ -21,6 +23,7 @@ Puppet::Type.type(:group).provide :groupadd, :parent => Puppet::Provider::NameSe end end cmd << "-o" if @resource.allowdupe? + cmd << "-r" if @resource.system? cmd << @resource[:name] cmd diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb index cde1cfd65..066bd49df 100755 --- a/lib/puppet/type/group.rb +++ b/lib/puppet/type/group.rb @@ -1,4 +1,3 @@ - require 'etc' require 'facter' @@ -15,6 +14,9 @@ module Puppet feature :manages_members, "For directories where membership is an attribute of groups not users." + feature :system_groups, + "The provider allows you to create system groups with lower GIDs." + ensurable do desc "Create or remove the group." @@ -95,5 +97,13 @@ module Puppet defaultto false end + + newparam(:system, :boolean => true) do + desc "Whether the group is a system group with lower GID." + + newvalues(:true, :false) + + defaultto false + end end end diff --git a/spec/unit/provider/group/groupadd_spec.rb b/spec/unit/provider/group/groupadd_spec.rb index 33d9acd98..65cc887e4 100755 --- a/spec/unit/provider/group/groupadd_spec.rb +++ b/spec/unit/provider/group/groupadd_spec.rb @@ -10,10 +10,10 @@ describe provider_class do @provider = provider_class.new(@resource) end - # #1360 it "should add -o when allowdupe is enabled and the group is being created" do @resource.stubs(:should).returns "fakeval" @resource.stubs(:[]).returns "fakeval" + @resource.stubs(:system?).returns true @resource.expects(:allowdupe?).returns true @provider.expects(:execute).with { |args| args.include?("-o") } @@ -28,4 +28,14 @@ describe provider_class do @provider.gid = 150 end + + it "should add -r when system is enabled and the group is being created" do + @resource.stubs(:should).returns "fakeval" + @resource.stubs(:[]).returns "fakeval" + @resource.expects(:system?).returns true + @resource.stubs(:allowdupe?).returns true + @provider.expects(:execute).with { |args| args.include?("-r") } + + @provider.create + end end diff --git a/spec/unit/type/group_spec.rb b/spec/unit/type/group_spec.rb index b41ce71a0..e373dac6e 100755 --- a/spec/unit/type/group_spec.rb +++ b/spec/unit/type/group_spec.rb @@ -16,6 +16,10 @@ describe Puppet::Type.type(:group) do @class.defaultprovider.ancestors.should be_include(Puppet::Provider) end + it "should have a system_groups feature" do + @class.provider_feature(:system_groups).should_not be_nil + end + describe "when validating attributes" do [:name, :allowdupe].each do |param| it "should have a #{param} parameter" do @@ -38,11 +42,14 @@ describe Puppet::Type.type(:group) do end end - # #1407 - we need to declare the allowdupe param as boolean. it "should have a boolean method for determining if duplicates are allowed" do @class.new(:name => "foo").methods.should be_include("allowdupe?") end + it "should have a boolean method for determining if system groups are allowed" do + @class.new(:name => "foo").methods.should be_include("system?") + end + it "should call 'create' to create the group" do group = @class.new(:name => "foo", :ensure => :present) group.provider.expects(:create) -- cgit From 8b7444dc5cebd73c5494a7908101bda3213f5711 Mon Sep 17 00:00:00 2001 From: Nigel Kersten Date: Sun, 13 Mar 2011 15:05:58 -0700 Subject: (#2331) Remove darwinports pkg provider, replace with rewritten macports provider * Employs port -q installed, much faster than port list installed * Handles upgrades correctly now * Makes use of internal port revision for ensure => latest upgrades * Versionable, now works with ensure => specified_version * Does not handle port variants at all yet. * Does not allow manual specification of revision, only version * Test coverage expanded using newer syntax Paired-With: Daniel Pittman --- lib/puppet/provider/package/darwinport.rb | 86 -------------------- lib/puppet/provider/package/macports.rb | 106 ++++++++++++++++++++++++ spec/unit/provider/package/macports_spec.rb | 122 ++++++++++++++++++++++++++++ 3 files changed, 228 insertions(+), 86 deletions(-) delete mode 100755 lib/puppet/provider/package/darwinport.rb create mode 100755 lib/puppet/provider/package/macports.rb create mode 100755 spec/unit/provider/package/macports_spec.rb diff --git a/lib/puppet/provider/package/darwinport.rb b/lib/puppet/provider/package/darwinport.rb deleted file mode 100755 index c5f9ba28f..000000000 --- a/lib/puppet/provider/package/darwinport.rb +++ /dev/null @@ -1,86 +0,0 @@ -require 'puppet/provider/package' - -Puppet::Type.type(:package).provide :darwinport, :parent => Puppet::Provider::Package do - desc "Package management using DarwinPorts on OS X." - - confine :operatingsystem => :darwin - commands :port => "/opt/local/bin/port" - - def self.eachpkgashash - # list out all of the packages - open("| #{command(:port)} list installed") { |process| - regex = %r{(\S+)\s+@(\S+)\s+(\S+)} - fields = [:name, :ensure, :location] - hash = {} - - # now turn each returned line into a package object - process.each { |line| - hash.clear - - if match = regex.match(line) - fields.zip(match.captures) { |field,value| - hash[field] = value - } - - hash.delete :location - hash[:provider] = self.name - yield hash.dup - else - raise Puppet::DevError, - "Failed to match dpkg line #{line}" - end - } - } - end - - def self.instances - packages = [] - - eachpkgashash do |hash| - packages << new(hash) - end - - packages - end - - def install - should = @resource.should(:ensure) - - # Seems like you can always say 'upgrade' - output = port "upgrade", @resource[:name] - if output =~ /^Error: No port/ - raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}" - end - end - - def query - version = nil - self.class.eachpkgashash do |hash| - return hash if hash[:name] == @resource[:name] - end - - nil - end - - def latest - info = port :search, "^#{@resource[:name]}$" - - if $CHILD_STATUS != 0 or info =~ /^Error/ - return nil - end - - ary = info.split(/\s+/) - version = ary[2].sub(/^@/, '') - - version - end - - def uninstall - port :uninstall, @resource[:name] - end - - def update - install - end -end - diff --git a/lib/puppet/provider/package/macports.rb b/lib/puppet/provider/package/macports.rb new file mode 100755 index 000000000..c43eb72f3 --- /dev/null +++ b/lib/puppet/provider/package/macports.rb @@ -0,0 +1,106 @@ +require 'puppet/provider/package' + +Puppet::Type.type(:package).provide :macports, :parent => Puppet::Provider::Package do + desc "Package management using MacPorts on OS X. + + Supports MacPorts versions and revisions, but not variants. + Variant preferences may be specified using the MacPorts variants.conf file + http://guide.macports.org/chunked/internals.configuration-files.html#internals.configuration-files.variants-conf + + When specifying a version in the Puppet DSL, only specify the version, not the revision + Revisions are only used internally for ensuring the latest version/revision of a port. + " + + confine :operatingsystem => :darwin + commands :port => "/opt/local/bin/port" + + has_feature :installable + has_feature :uninstallable + has_feature :upgradeable + has_feature :versionable + + + def self.parse_installed_query_line(line) + regex = /(\S+)\s+@(\S+)_(\S+)\s+\(active\)/ + fields = [:name, :ensure, :revision] + hash_from_line(line, regex, fields) + end + + def self.parse_info_query_line(line) + regex = /(\S+)\s+(\S+)/ + fields = [:version, :revision] + hash_from_line(line, regex, fields) + end + + def self.hash_from_line(line, regex, fields) + hash = {} + if match = regex.match(line) + fields.zip(match.captures) { |field, value| + hash[field] = value + } + hash[:provider] = self.name + return hash + end + nil + end + + def self.instances + packages = [] + port("-q", :installed).each do |line| + if hash = parse_installed_query_line(line) + packages << new(hash) + end + end + packages + end + + def install + should = @resource.should(:ensure) + if [:latest, :installed, :present].include?(should) + output = port("-q", :install, @resource[:name]) + else + output = port("-q", :install, @resource[:name], "@#{should}") + end + # MacPorts now correctly exits non-zero with appropriate errors in + # situations where a port cannot be found or installed. + end + + def query + return self.class.parse_installed_query_line(port("-q", :installed, @resource[:name])) + end + + def latest + # We need both the version and the revision to be confident + # we've got the latest revision of a specific version + # Note we're still not doing anything with variants here. + info_line = port("-q", :info, "--line", "--version", "--revision", @resource[:name]) + return nil if info_line == "" + + if newest = self.class.parse_info_query_line(info_line) + current = query + # We're doing some fiddling behind the scenes here to cope with updated revisions. + # If we're already at the latest version/revision, then just return the version + # so the current and desired values match. Otherwise return version and revision + # to trigger an upgrade to the latest revision. + if newest[:version] == current[:ensure] and newest[:revision] == current[:revision] + return current[:ensure] + else + return "#{newest[:version]}_#{newest[:revision]}" + end + end + nil + end + + def uninstall + port("-q", :uninstall, @resource[:name]) + end + + def update + if query[:name] == @resource[:name] # 'port upgrade' cannot install new ports + port("-q", :upgrade, @resource[:name]) + else + install + end + end +end + diff --git a/spec/unit/provider/package/macports_spec.rb b/spec/unit/provider/package/macports_spec.rb new file mode 100755 index 000000000..7d1acd537 --- /dev/null +++ b/spec/unit/provider/package/macports_spec.rb @@ -0,0 +1,122 @@ +require 'spec_helper' + +provider_class = Puppet::Type.type(:package).provider(:macports) + +describe provider_class do + let :resource_name do + "foo" + end + + let :resource do + Puppet::Type.type(:package).new(:name => resource_name, :provider => :macports) + end + + let :provider do + prov = resource.provider + prov.expects(:execute).never + prov + end + + let :current_hash do + {:name => resource_name, :ensure => "1.2.3", :revision => "1", :provider => :macports} + end + + describe "provider features" do + subject { provider } + + it { should be_installable } + it { should be_uninstallable } + it { should be_upgradeable } + it { should be_versionable } + end + + describe "when listing all instances" do + it "should call port -q installed" do + provider_class.expects(:port).with("-q", :installed).returns("") + provider_class.instances + end + + it "should create instances from active ports" do + provider_class.expects(:port).returns("foo @1.234.5_2 (active)") + provider_class.instances.size.should == 1 + end + + it "should ignore ports that aren't activated" do + provider_class.expects(:port).returns("foo @1.234.5_2") + provider_class.instances.size.should == 0 + end + end + + describe "when installing" do + it "should not specify a version when ensure is set to latest" do + resource[:ensure] = :latest + provider.expects(:port).with { |flag, method, name, version| + version.should be_nil + } + provider.install + end + + it "should not specify a version when ensure is set to present" do + resource[:ensure] = :present + provider.expects(:port).with { |flag, method, name, version| + version.should be_nil + } + provider.install + end + + it "should specify a version when ensure is set to a version" do + resource[:ensure] = "1.2.3" + provider.expects(:port).with { |flag, method, name, version| + version.should be + } + provider.install + end + end + + describe "when querying for the latest version" do + let :new_info_line do + "1.2.3 2" + end + let :infoargs do + ["-q", :info, "--line", "--version", "--revision", resource_name] + end + + it "should return nil when the package cannot be found" do + resource[:name] = resource_name + provider.expects(:port).returns("") + provider.latest.should == nil + end + + it "should return the current version if the installed port has the same revision" do + current_hash[:revision] = "2" + provider.expects(:port).with(*infoargs).returns(new_info_line) + provider.expects(:query).returns(current_hash) + provider.latest.should == current_hash[:ensure] + end + + it "should return the new version_revision if the installed port has a lower revision" do + current_hash[:revision] = "1" + provider.expects(:port).with(*infoargs).returns(new_info_line) + provider.expects(:query).returns(current_hash) + provider.latest.should == "1.2.3_2" + end + end + + describe "when updating a port" do + it "should execute port upgrade if the port is installed" do + resource[:name] = resource_name + resource[:ensure] = :present + provider.expects(:query).returns(current_hash) + provider.expects(:port).with("-q", :upgrade, resource_name) + provider.update + end + + it "should execute port install if the port is not installed" do + resource[:name] = resource_name + resource[:ensure] = :present + provider.expects(:query).returns("") + provider.expects(:port).with("-q", :install, resource_name) + provider.update + end + end +end -- cgit