From 952a76c676ea6cc90fe9260e855c0276f0e391ed Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 28 Jul 2005 19:28:26 +0000 Subject: working on documentation git-svn-id: https://reductivelabs.com/svn/puppet/library/trunk@471 980ebf18-57e1-0310-9a29-db15c13687c0 --- lib/puppet/type/exec.rb | 23 +- lib/puppet/type/package.rb | 998 ++++++++++++++++++++++---------------------- lib/puppet/type/pfile.rb | 79 ++-- lib/puppet/type/pprocess.rb | 21 +- lib/puppet/type/service.rb | 18 +- lib/puppet/type/symlink.rb | 97 +---- 6 files changed, 587 insertions(+), 649 deletions(-) diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb index 81b38450f..9a2ef8094 100755 --- a/lib/puppet/type/exec.rb +++ b/lib/puppet/type/exec.rb @@ -12,7 +12,8 @@ module Puppet class Returns < Puppet::State attr_reader :output - @doc = "..." + @doc = "The expected return code. An error will be returned if the + executed command returns something else." @name = :returns # because this command always runs, @@ -128,13 +129,19 @@ module Puppet :command ] - @paramdoc[:path] = "..." - @paramdoc[:user] = "..." - @paramdoc[:cwd] = "..." - @paramdoc[:refreshonly] = "..." - @paramdoc[:command] = "..." - - @doc = "Allows shell commands to be executed" + @paramdoc[:path] = "The search path used for command execution. + Commands must be fully qualified if no path is specified." + @paramdoc[:user] = "The user to run the command as. Currently + non-functional." + @paramdoc[:cwd] = "The directory from which to run the command. If + this directory does not exist, the command will fail." + @paramdoc[:refreshonly] = "The command should only be run as a + refresh mechanism for when a dependent object is changed." + @paramdoc[:command] = "The actual command to execute." + + @doc = "Executes external commands. It is critical that all commands + executed using this mechanism can be run multiple times without + harm." @name = :exec @namevar = :command diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb index 3805d3747..1e82138bb 100644 --- a/lib/puppet/type/package.rb +++ b/lib/puppet/type/package.rb @@ -7,610 +7,620 @@ require 'puppet/fact' module Puppet class PackageError < Puppet::Error; end - class State - class PackageInstalled < Puppet::State - @name = :install - @doc = "boolean flag for defining the package to be installed" + # packaging types are defined first so that we can retrieve the entire + # list for documentation extraction + class PackagingType + @params = [:list, :query, :remove, :install] + attr_writer(*@params) - def retrieve - unless defined? @is - @parent.retrieve - end + class << self + attr_reader :params + end - # if the only requirement is that it's installed, then settle - # for that - if @should == true - if @is - @is = true - end - end - end + @@types = Hash.new(false) - def should=(value) - # possible values are: true, false, and a version number - if value == true or value == false or value =~ /^[0-9]/ - @should = value - else - raise Puppet::Error.new( - "Invalid install value %s" % value - ) - end + def PackagingType.types + @@types.keys + end + + def PackagingType.[](name) + if @@types.include?(name) + return @@types[name] + else + Puppet.warning name.inspect + Puppet.warning @@types.keys.collect { |key| + key.inspect + }.join(" ") + return nil end + end - def sync - type = @parent.pkgtype - begin - if @should == false - type.remove(@parent) - else - type.install(@parent) - end - rescue => detail - raise Puppet::Error.new( - "Could not install package %s: %s" % [@parent.name, detail] - ) - end + # whether a package is installed or not + def [](name) + return @packages[name] + end - if @should == false - return :package_removed + @params.each { |method| + self.send(:define_method, method) { |pkg| + # retrieve the variable + var = eval("@" + method.id2name) + if var.is_a?(Proc) + var.call(pkg) else - return :package_installed + raise "only blocks are supported right now" end + } + } + + def initialize(name) + if block_given? + yield self end + + @packages = Hash.new(false) + @@types[name] = self end - end - class Type - # packages are complicated because each package format has completely - # different commands. We need some way to convert specific packages - # into the general package object... - class Package < Type - attr_reader :version, :pkgtype + def retrieve + @packages.clear() - @states = [ - Puppet::State::PackageInstalled - ] - @parameters = [ - :name, - :type, - :instance, - :status, - :version, - :category, - :platform, - :root, - :vendor, - :description - ] + @packages = self.list() + end + end - @paramdoc[:name] = "..." - @paramdoc[:type] = "..." - @paramdoc[:instance] = "..." - @paramdoc[:status] = "..." - @paramdoc[:version] = "..." - @paramdoc[:category] = "..." - @paramdoc[:platform] = "..." - @paramdoc[:root] = "..." - @paramdoc[:vendor] = "..." - @paramdoc[:description] = "..." - - @doc = "Allows control of package objects" - @name = :package - @namevar = :name - @listed = false + PackagingType.new(:apt) { |type| + type.query = proc { |pkg| + packages = [] - @allowedmethods = [:types] - @@types = nil + # dpkg only prints as many columns as you have available + # which means we don't get all of the info + # stupid stupid + oldcol = ENV["COLUMNS"] + ENV["COLUMNS"] = "500" + fields = [:desired, :status, :error, :name, :version, :description] - @@default = nil - @@platform = nil + hash = {} + # list out all of the packages + open("| dpkg -l %s 2>/dev/null" % pkg) { |process| + # our regex for matching dpkg output + regex = %r{^(.)(.)(.)\s(\S+)\s+(\S+)\s+(.+)$} - class << self - attr_reader :listed - end + # we only want the last line + lines = process.readlines + # we've got four header lines, so we should expect all of those + # plus our output + if lines.length < 5 + return nil + end - def self.clear - @listed = false - super - end + line = lines[-1] - def self.default - if @@default.nil? - self.init + if match = regex.match(line) + fields.zip(match.captures) { |field,value| + hash[field] = value + } + #packages.push Puppet::Type::Package.installedpkg(hash) + else + raise "failed to match dpkg line %s" % line end + } + ENV["COLUMNS"] = oldcol - return @@default + if hash[:error] != " " + raise Puppet::PackageError.new( + "Package %s, version %s is in error state: %s" % + [hash[:name], hash[:install], hash[:error]] + ) end - def self.defaulttype - return Puppet::PackagingType[self.default] + if hash[:status] == "i" + hash[:install] = hash[:version] + else + # this isn't really correct, but we'll settle for it for now + hash[:install] = nil end - def self.init - unless @@platform = Facter["operatingsystem"].value.downcase - raise Puppet::DevError( - "Must know platform for package management" - ) - end - case @@platform - when "sunos": @@default = :sunpkg - when "linux": - case Facter["distro"].value.downcase - when "gentoo": raise "No support for gentoo yet" - when "debian": @@default = :apt - when "redhat", "fedora": @@default = :rpm - else - #raise "No default type for " + Puppet::Fact["distro"] - Puppet.warning "Using rpm as default type for %s" % - Facter["distro"].value - @@default = :rpm - end - else - raise Puppet::Error.new( - "No default type for " + Puppet::Fact["operatingsystem"] - ) - end - end + return hash + } + type.list = proc { + packages = [] - def self.types(array) - unless array.is_a?(Array) - array = [array] - end - @@types = array - Puppet.debug "Types are %s" % array.join(" ") - end + # dpkg only prints as many columns as you have available + # which means we don't get all of the info + # stupid stupid + oldcol = ENV["COLUMNS"] + ENV["COLUMNS"] = "500" - def self.getpkglist - if @@types.nil? - if @@default.nil? - self.init - end - @@types = [@@default] - end + # list out all of the packages + open("| dpkg -l") { |process| + # our regex for matching dpkg output + regex = %r{^(\S+)\s+(\S+)\s+(\S+)\s+(.+)$} + fields = [:status, :name, :install, :description] + hash = {} - list = @@types.collect { |type| - if typeobj = Puppet::PackagingType[type] - # pull all of the objects - typeobj.list + 5.times { process.gets } # throw away the header + + # now turn each returned line into a package object + process.each { |line| + if match = regex.match(line) + hash.clear + + fields.zip(match.captures) { |field,value| + hash[field] = value + } + packages.push Puppet::Type::Package.installedpkg(hash) else - raise "Could not find package type '%s'" % type + raise "failed to match dpkg line %s" % line end - }.flatten - @listed = true - return list - end + } + } + ENV["COLUMNS"] = oldcol - def Package.installedpkg(hash) - # this is from code, so we don't have to do as much checking - name = hash[:name] - hash.delete(:name) + return packages + } - # if it already exists, modify the existing one - if object = Package[name] - states = {} - object.eachstate { |state| - Puppet.debug "Adding %s" % state.name.inspect - states[state.name] = state - } - hash.each { |var,value| - if states.include?(var) - Puppet.debug "%s is a set state" % var.inspect - states[var].is = value - else - Puppet.debug "%s is not a set state" % var.inspect - if object[var] and object[var] != value - Puppet.warning "Overriding %s => %s on %s with %s" % - [var,object[var],name,value] - end + # we need package retrieval mechanisms before we can have package + # installation mechanisms... + type.install = proc { |pkg| + cmd = "apt-get install %s" % pkg - #object.state(var).is = value + Puppet.info "Executing %s" % cmd.inspect + output = %x{#{cmd} 2>&1} - # swap the values if we're a state - if states.include?(var) - Puppet.debug "Swapping %s because it's a state" % var - states[var].is = value - states[var].should = nil - else - Puppet.debug "%s is not a state" % var.inspect - Puppet.debug "States are %s" % states.keys.collect { |st| - st.inspect - }.join(" ") - end - end - } - return object - else # just create it - obj = self.new(:name => name) - hash.each { |var,value| - obj.addis(var,value) - } - return obj - end + unless $? == 0 + raise Puppet::PackageError.new(output) end + } - def self.pkgtype(pkgtype) - if @typeary.length != @typehash.length - self.buildpkgtypehash - end - - return @typehash[pkgtype] + type.remove = proc { |pkg| + cmd = "dpkg -r %s" % pkg.name + output = %x{#{cmd}} + if $? != 0 + raise Puppet::PackageError.new(output) end + } + } - def addis(state,value) - if stateklass = self.class.validstate?(state) - @states[state] = stateklass.new(:parent => self) - @states[state].is = value - elsif self.class.validparameter?(state) - self[state] = value - else - raise Puppet::DevError.new("Invalid package state %s" % state) - end + PackagingType.new(:rpm) { |type| + type.list = proc { + packages = [] - end + # dpkg only prints as many columns as you have available + # which means we don't get all of the info + # stupid stupid + oldcol = ENV["COLUMNS"] + ENV["COLUMNS"] = "500" - # okay, there are two ways that a package could be created... - # either through the language, in which case the hash's values should - # be set in 'should', or through comparing against the system, in which - # case the hash's values should be set in 'is' - def initialize(hash) - unless hash.include?(:install) or hash.include?("install") - Puppet.debug "Defaulting to installing a package" - hash[:install] = true - end + # list out all of the packages + open("| rpm -q -a --qf '%{NAME} %{VERSION}\n'") { |process| + # our regex for matching dpkg output + regex = %r{^(\S+)\s+(\S+)} + fields = [:name, :install] + hash = {} - super + # now turn each returned line into a package object + process.each { |line| + if match = regex.match(line) + hash.clear - unless @parameters.include?(:type) - if @@default.nil? - self.class.init + fields.zip(match.captures) { |field,value| + hash[field] = value + } + packages.push Puppet::Type::Package.installedpkg(hash) + else + raise "failed to match rpm line %s" % line end - self[:type] = @@default - end - end + } + } + ENV["COLUMNS"] = oldcol - def retrieve - unless pkgtype = Puppet::PackagingType[@parameters[:type]] - raise Puppet::DevError.new( - "No support for type %s" % @parameters[:type] - ) - end + return packages + } - begin - hash = pkgtype.query(self) - rescue => error - Puppet.err "Cannot install %s: %s" % - [self.name, error.to_s] + # we need package retrieval mechanisms before we can have package + # installation mechanisms... + #type.install = proc { |pkg| + # raise "installation not implemented yet" + #} - @states.delete(:install) - end + type.remove = proc { |pkg| + cmd = "rpm -e %s" % pkg.name + output = %x{#{cmd}} + if $? != 0 + raise output + end + } + } - if hash.nil? - @states[:install].is = nil - end + PackagingType.new(:sunpkg) { |type| + type.list = proc { + packages = [] + hash = {} + names = { + "PKGINST" => :name, + "NAME" => nil, + "CATEGORY" => :category, + "ARCH" => :platform, + "VERSION" => :install, + "BASEDIR" => :root, + "HOTLINE" => nil, + "EMAIL" => nil, + "VENDOR" => :vendor, + "DESC" => :description, + "PSTAMP" => nil, + "INSTDATE" => nil, + "STATUS" => nil, + "FILES" => nil + } - hash.each { |name,value| - if self.class.validstate?(name) - if @states.include?(name) - @states[name].is = value + # list out all of the packages + open("| pkginfo -l") { |process| + # we're using the long listing, so each line is a separate piece + # of information + process.each { |line| + case line + when /^$/: + packages.push Puppet::Type::Package.installedpkg(hash) + hash.clear + when /\s*(\w+):\s+(.+)/: + name = $1 + value = $2 + if names.include?(name) + unless names[name].nil? + hash[names[name]] = value + end else - # silently ignore any returned states - # that we're not managing - # this is highly unlikely to happen - Puppet.info "%s missing state %s" % - [self.name, name] + raise "Could not find %s" % name end - elsif self.class.validparameter?(name) - self[name] = value - else - # silently ignore anything that's not a valid state - # or param + when /\s+\d+.+/: + # nothing; we're ignoring the FILES info end } + } + return packages + } - # now let them all handle things as necessary - @states.each { |name, state| - state.retrieve - } + # we need package retrieval mechanisms before we can have package + # installation mechanisms... + #type.install = proc { |pkg| + # raise "installation not implemented yet" + #} + + type.remove = proc { |pkg| + cmd = "pkgrm -n %s" % pkg.name + output = %x{#{cmd}} + if $? != 0 + raise output end + } + } - def paramtype=(typename) - @parameters[:type] = typename - pkgtype = nil + class State + class PackageInstalled < Puppet::State + @name = :install - unless pkgtype = Puppet::PackagingType[typename] - raise Puppet::Error.new( - "Could not find package type %s" % typename - ) + @doc = "What state the package should be in. *true*/*false*/version" + + def retrieve + unless defined? @is + @parent.retrieve end - @pkgtype = pkgtype + # if the only requirement is that it's installed, then settle + # for that + if @should == true + if @is + @is = true + end + end end - end # Puppet::Type::Package - end - - class PackagingType - @params = [:list, :query, :remove, :install] - attr_writer(*@params) - - class << self - attr_reader :params - end - @@types = Hash.new(false) + def should=(value) + # possible values are: true, false, and a version number + if value == true or value == false or value =~ /^[0-9]/ + @should = value + else + raise Puppet::Error.new( + "Invalid install value %s" % value + ) + end + end - def PackagingType.[](name) - if @@types.include?(name) - return @@types[name] - else - Puppet.warning name.inspect - Puppet.warning @@types.keys.collect { |key| - key.inspect - }.join(" ") - return nil - end - end - - # whether a package is installed or not - def [](name) - return @packages[name] - end + def sync + type = @parent.pkgtype + begin + if @should == false + type.remove(@parent) + else + type.install(@parent) + end + rescue => detail + raise Puppet::Error.new( + "Could not install package %s: %s" % [@parent.name, detail] + ) + end - @params.each { |method| - self.send(:define_method, method) { |pkg| - # retrieve the variable - var = eval("@" + method.id2name) - if var.is_a?(Proc) - var.call(pkg) + if @should == false + return :package_removed else - raise "only blocks are supported right now" + return :package_installed end - } - } - - def initialize(name) - if block_given? - yield self end - - @packages = Hash.new(false) - @@types[name] = self end + end - def retrieve - @packages.clear() + class Type + # packages are complicated because each package format has completely + # different commands. We need some way to convert specific packages + # into the general package object... + class Package < Type + attr_reader :version, :pkgtype - @packages = self.list() - end - end + @states = [ + Puppet::State::PackageInstalled + ] + @parameters = [ + :name, + :type, + :instance, + :status, + :version, + :category, + :platform, + :root, + :vendor, + :description + ] - PackagingType.new(:apt) { |type| - type.query = proc { |pkg| - packages = [] + @paramdoc[:name] = "The package name." + @paramdoc[:type] = "The package format. Currently supports " + + PackagingType.types.collect{|p| "*" + p.to_s + "*"}.join(",") + + "." + @paramdoc[:instance] = "A read-only parameter set by the package." + @paramdoc[:status] = "A read-only parameter set by the package." + @paramdoc[:version] = "A read-only parameter set by the package." + @paramdoc[:category] = "A read-only parameter set by the package." + @paramdoc[:platform] = "A read-only parameter set by the package." + @paramdoc[:root] = "A read-only parameter set by the package." + @paramdoc[:vendor] = "A read-only parameter set by the package." + @paramdoc[:description] = "A read-only parameter set by the package." + + @doc = "Manage packages. Eventually will support retrieving packages + from remote sources but currently only supports packaging + systems which can retrieve their own packages, like *apt*." + @name = :package + @namevar = :name + @listed = false - # dpkg only prints as many columns as you have available - # which means we don't get all of the info - # stupid stupid - oldcol = ENV["COLUMNS"] - ENV["COLUMNS"] = "500" - fields = [:desired, :status, :error, :name, :version, :description] + @allowedmethods = [:types] + @@types = nil - hash = {} - # list out all of the packages - open("| dpkg -l %s 2>/dev/null" % pkg) { |process| - # our regex for matching dpkg output - regex = %r{^(.)(.)(.)\s(\S+)\s+(\S+)\s+(.+)$} + @@default = nil + @@platform = nil - # we only want the last line - lines = process.readlines - # we've got four header lines, so we should expect all of those - # plus our output - if lines.length < 5 - return nil - end + class << self + attr_reader :listed + end - line = lines[-1] + def self.clear + @listed = false + super + end - if match = regex.match(line) - fields.zip(match.captures) { |field,value| - hash[field] = value - } - #packages.push Puppet::Type::Package.installedpkg(hash) - else - raise "failed to match dpkg line %s" % line + def self.default + if @@default.nil? + self.init end - } - ENV["COLUMNS"] = oldcol - if hash[:error] != " " - raise Puppet::PackageError.new( - "Package %s, version %s is in error state: %s" % - [hash[:name], hash[:install], hash[:error]] - ) + return @@default end - if hash[:status] == "i" - hash[:install] = hash[:version] - else - # this isn't really correct, but we'll settle for it for now - hash[:install] = nil + def self.defaulttype + return Puppet::PackagingType[self.default] end - return hash - } - type.list = proc { - packages = [] - - # dpkg only prints as many columns as you have available - # which means we don't get all of the info - # stupid stupid - oldcol = ENV["COLUMNS"] - ENV["COLUMNS"] = "500" - - # list out all of the packages - open("| dpkg -l") { |process| - # our regex for matching dpkg output - regex = %r{^(\S+)\s+(\S+)\s+(\S+)\s+(.+)$} - fields = [:status, :name, :install, :description] - hash = {} + def self.init + unless @@platform = Facter["operatingsystem"].value.downcase + raise Puppet::DevError( + "Must know platform for package management" + ) + end + case @@platform + when "sunos": @@default = :sunpkg + when "linux": + case Facter["distro"].value.downcase + when "gentoo": raise "No support for gentoo yet" + when "debian": @@default = :apt + when "redhat", "fedora": @@default = :rpm + else + #raise "No default type for " + Puppet::Fact["distro"] + Puppet.warning "Using rpm as default type for %s" % + Facter["distro"].value + @@default = :rpm + end + else + raise Puppet::Error.new( + "No default type for " + Puppet::Fact["operatingsystem"] + ) + end + end - 5.times { process.gets } # throw away the header + def self.types(array) + unless array.is_a?(Array) + array = [array] + end + @@types = array + Puppet.debug "Types are %s" % array.join(" ") + end - # now turn each returned line into a package object - process.each { |line| - if match = regex.match(line) - hash.clear + def self.getpkglist + if @@types.nil? + if @@default.nil? + self.init + end + @@types = [@@default] + end - fields.zip(match.captures) { |field,value| - hash[field] = value - } - packages.push Puppet::Type::Package.installedpkg(hash) + list = @@types.collect { |type| + if typeobj = Puppet::PackagingType[type] + # pull all of the objects + typeobj.list else - raise "failed to match dpkg line %s" % line + raise "Could not find package type '%s'" % type end - } - } - ENV["COLUMNS"] = oldcol + }.flatten + @listed = true + return list + end - return packages - } + def Package.installedpkg(hash) + # this is from code, so we don't have to do as much checking + name = hash[:name] + hash.delete(:name) - # we need package retrieval mechanisms before we can have package - # installation mechanisms... - type.install = proc { |pkg| - cmd = "apt-get install %s" % pkg + # if it already exists, modify the existing one + if object = Package[name] + states = {} + object.eachstate { |state| + Puppet.debug "Adding %s" % state.name.inspect + states[state.name] = state + } + hash.each { |var,value| + if states.include?(var) + Puppet.debug "%s is a set state" % var.inspect + states[var].is = value + else + Puppet.debug "%s is not a set state" % var.inspect + if object[var] and object[var] != value + Puppet.warning "Overriding %s => %s on %s with %s" % + [var,object[var],name,value] + end - Puppet.info "Executing %s" % cmd.inspect - output = %x{#{cmd} 2>&1} + #object.state(var).is = value - unless $? == 0 - raise Puppet::PackageError.new(output) + # swap the values if we're a state + if states.include?(var) + Puppet.debug "Swapping %s because it's a state" % var + states[var].is = value + states[var].should = nil + else + Puppet.debug "%s is not a state" % var.inspect + Puppet.debug "States are %s" % states.keys.collect { |st| + st.inspect + }.join(" ") + end + end + } + return object + else # just create it + obj = self.new(:name => name) + hash.each { |var,value| + obj.addis(var,value) + } + return obj + end end - } - type.remove = proc { |pkg| - cmd = "dpkg -r %s" % pkg.name - output = %x{#{cmd}} - if $? != 0 - raise Puppet::PackageError.new(output) + def self.pkgtype(pkgtype) + if @typeary.length != @typehash.length + self.buildpkgtypehash + end + + return @typehash[pkgtype] end - } - } - PackagingType.new(:rpm) { |type| - type.list = proc { - packages = [] + def addis(state,value) + if stateklass = self.class.validstate?(state) + @states[state] = stateklass.new(:parent => self) + @states[state].is = value + elsif self.class.validparameter?(state) + self[state] = value + else + raise Puppet::DevError.new("Invalid package state %s" % state) + end - # dpkg only prints as many columns as you have available - # which means we don't get all of the info - # stupid stupid - oldcol = ENV["COLUMNS"] - ENV["COLUMNS"] = "500" + end - # list out all of the packages - open("| rpm -q -a --qf '%{NAME} %{VERSION}\n'") { |process| - # our regex for matching dpkg output - regex = %r{^(\S+)\s+(\S+)} - fields = [:name, :install] - hash = {} + # okay, there are two ways that a package could be created... + # either through the language, in which case the hash's values should + # be set in 'should', or through comparing against the system, in which + # case the hash's values should be set in 'is' + def initialize(hash) + unless hash.include?(:install) or hash.include?("install") + Puppet.debug "Defaulting to installing a package" + hash[:install] = true + end - # now turn each returned line into a package object - process.each { |line| - if match = regex.match(line) - hash.clear + super - fields.zip(match.captures) { |field,value| - hash[field] = value - } - packages.push Puppet::Type::Package.installedpkg(hash) - else - raise "failed to match rpm line %s" % line + unless @parameters.include?(:type) + if @@default.nil? + self.class.init end - } - } - ENV["COLUMNS"] = oldcol + self[:type] = @@default + end + end - return packages - } + def retrieve + unless pkgtype = Puppet::PackagingType[@parameters[:type]] + raise Puppet::DevError.new( + "No support for type %s" % @parameters[:type] + ) + end - # we need package retrieval mechanisms before we can have package - # installation mechanisms... - #type.install = proc { |pkg| - # raise "installation not implemented yet" - #} + begin + hash = pkgtype.query(self) + rescue => error + Puppet.err "Cannot install %s: %s" % + [self.name, error.to_s] - type.remove = proc { |pkg| - cmd = "rpm -e %s" % pkg.name - output = %x{#{cmd}} - if $? != 0 - raise output - end - } - } + @states.delete(:install) + end - PackagingType.new(:sunpkg) { |type| - type.list = proc { - packages = [] - hash = {} - names = { - "PKGINST" => :name, - "NAME" => nil, - "CATEGORY" => :category, - "ARCH" => :platform, - "VERSION" => :install, - "BASEDIR" => :root, - "HOTLINE" => nil, - "EMAIL" => nil, - "VENDOR" => :vendor, - "DESC" => :description, - "PSTAMP" => nil, - "INSTDATE" => nil, - "STATUS" => nil, - "FILES" => nil - } + if hash.nil? + @states[:install].is = nil + end - # list out all of the packages - open("| pkginfo -l") { |process| - # we're using the long listing, so each line is a separate piece - # of information - process.each { |line| - case line - when /^$/: - packages.push Puppet::Type::Package.installedpkg(hash) - hash.clear - when /\s*(\w+):\s+(.+)/: - name = $1 - value = $2 - if names.include?(name) - unless names[name].nil? - hash[names[name]] = value - end + hash.each { |name,value| + if self.class.validstate?(name) + if @states.include?(name) + @states[name].is = value else - raise "Could not find %s" % name + # silently ignore any returned states + # that we're not managing + # this is highly unlikely to happen + Puppet.info "%s missing state %s" % + [self.name, name] end - when /\s+\d+.+/: - # nothing; we're ignoring the FILES info + elsif self.class.validparameter?(name) + self[name] = value + else + # silently ignore anything that's not a valid state + # or param end } - } - return packages - } - - # we need package retrieval mechanisms before we can have package - # installation mechanisms... - #type.install = proc { |pkg| - # raise "installation not implemented yet" - #} - type.remove = proc { |pkg| - cmd = "pkgrm -n %s" % pkg.name - output = %x{#{cmd}} - if $? != 0 - raise output + # now let them all handle things as necessary + @states.each { |name, state| + state.retrieve + } end - } - } + def paramtype=(typename) + @parameters[:type] = typename + pkgtype = nil + + unless pkgtype = Puppet::PackagingType[typename] + raise Puppet::Error.new( + "Could not find package type %s" % typename + ) + end + + @pkgtype = pkgtype + end + end # Puppet::Type::Package + end # this is how we retrieve packages class PackageSource attr_accessor :uri diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/pfile.rb index f22a0fe0f..8a9bd8bda 100644 --- a/lib/puppet/type/pfile.rb +++ b/lib/puppet/type/pfile.rb @@ -14,7 +14,8 @@ module Puppet class State class PFileCreate < Puppet::State require 'etc' - @doc = "boolean flag to create file if it doesn't already exist" + @doc = "Whether to create files that don't currently exist. + **false**/*true*/*file*/*directory*" @name = :create @event = :file_created @@ -86,7 +87,8 @@ module Puppet class PFileChecksum < Puppet::State attr_accessor :checktype - @doc = "String type of checksum used to validate file contents. Example: md5" + @doc = "How to check whether a file has changed. **md5**/*lite-md5*/ + *time*/*mtime*" @name = :checksum @event = :file_modified @@ -257,7 +259,8 @@ module Puppet class PFileUID < Puppet::State require 'etc' - @doc = "String owner of file" + @doc = "To whom the file should belong. Argument can be user name or + user ID." @name = :owner @event = :inode_changed @@ -376,7 +379,8 @@ module Puppet # I think MetaStates are the answer, but I'm not quite sure class PFileMode < Puppet::State require 'etc' - @doc = "Four digit mode setting: example 0755" + @doc = "Mode the file should be. Currently relatively limited: + you must specify the exact mode the file should be." @name = :mode @event = :inode_changed @@ -454,39 +458,10 @@ module Puppet end end - # not used until I can figure out how to solve the problem with - # metastates - class PFileSetUID < Puppet::State - require 'etc' - @doc = "Used to set UID" - @parent = Puppet::State::PFileMode - - @name = :setuid - @event = :inode_changed - - def <=>(other) - self.is <=> @parent.value[11] - end - - # this just doesn't seem right... - def sync - unless defined? @is or @is == -1 - @parent.stat(true) - self.retrieve - Puppet.debug "%s: should is '%s'" % [self.class.name,self.should] - end - tmp = 0 - if self.is == true - tmp = 1 - end - @parent.value[11] = tmp - return :inode_changed - end - end - class PFileGroup < Puppet::State require 'etc' - @doc = "String group of file" + @doc = "Which group should own the file. Argument can be either group + name or group ID." @name = :group @event = :inode_changed @@ -587,7 +562,10 @@ module Puppet class PFileCopy < Puppet::State attr_accessor :source, :local - @doc = "...to be documented..." + @doc = "Copy a file over the current file. Uses *checksum* to + determine when a file should be copied. This is largely a support + state for the *source* parameter, which is what should generally + be used instead of *copy*." @name = :copy def retrieve @@ -733,7 +711,8 @@ module Puppet class Type class PFile < Type attr_reader :params, :source, :srcbase - @doc = "Allows control of files" + @doc = "Manages local files, including setting ownership and + permissions, and allowing creation of both files and directories." # class instance variable #Puppet::State::PFileSource, @states = [ @@ -742,8 +721,7 @@ module Puppet Puppet::State::PFileCopy, Puppet::State::PFileUID, Puppet::State::PFileGroup, - Puppet::State::PFileMode, - Puppet::State::PFileSetUID + Puppet::State::PFileMode ] @parameters = [ @@ -754,12 +732,23 @@ module Puppet :source, :filebucket ] - @paramdoc[:path] = "..." - @paramdoc[:backup] = "..." - @paramdoc[:linkmaker] = "..." - @paramdoc[:recurse] = "..." - @paramdoc[:source] = "..." - @paramdoc[:filebucket] = "..." + @paramdoc[:path] = "The path to the file to manage. Must be fully + qualified." + @paramdoc[:backup] = "Whether files should be backed up before + being replaced. If a *filebucket* is specified, files will be + backed up there; else, they will be backed up in the same directory + with a *.puppet-bak* extension." + @paramdoc[:linkmaker] = "An internal parameter used by the *symlink* + type to do recursive link creation." + @paramdoc[:recurse] = "Whether and how deeply to do recursive + management. **false**/*true*/*inf*/*number*" + @paramdoc[:source] = "Where to retrieve the contents of the files. + Currently only supports local copying, but will eventually + support multiple protocols for copying. Arguments are specified + using either a full local path or using a URI (currently only + *file* is supported as a protocol)." + @paramdoc[:filebucket] = "A repository for backing up files, including + over the network. Currently non-functional." @name = :file @namevar = :path diff --git a/lib/puppet/type/pprocess.rb b/lib/puppet/type/pprocess.rb index fe9bb7c71..a49930754 100644 --- a/lib/puppet/type/pprocess.rb +++ b/lib/puppet/type/pprocess.rb @@ -6,7 +6,7 @@ module Puppet class State class PProcessRunning < State - @doc = "...to be documented..." + @doc = "Whether a process should be running. **true**/*false*" def retrieve running = 0 regex = Regexp.new(@params[:pattern]) @@ -63,14 +63,19 @@ module Puppet attr_reader :stat, :path @parameters = [:start, :stop, :user, :pattern, :binary, :arguments] @name = :process - @paramdoc[:start] = "...to be documented..." - @paramdoc[:stop] = "...to be documented..." - @paramdoc[:user] = "...to be documented..." - @paramdoc[:pattern] = "...to be documented..." - @paramdoc[:binary] = "...to be documented..." - @paramdoc[:arguments] = "...to be documented..." - @doc = "...to be documented..." + @paramdoc[:start] = "How to start the process. Must be a fully + qualified path." + @paramdoc[:stop] = "How to stop the process. Must be a fully + qualified path." + @paramdoc[:user] = "Which user to run the proces as." + @paramdoc[:pattern] = "The search pattern to use to determine + whether the process is currently running." + @paramdoc[:binary] = "The binary to actually execute." + @paramdoc[:arguments] = "The arguments to pass the binary." + + @doc = "**Disabled. Use *service* instead.** Manage running + processes." @namevar = :pattern diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index 48a19a154..4c49fe86d 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -11,7 +11,7 @@ module Puppet class State class ServiceRunning < State - @doc = "Boolean flag indicating if service should be running" + @doc = "Whether a service should be running. **true**/*false*" @name = :running #@event = :file_created @@ -102,19 +102,25 @@ module Puppet ] @parameters = [ :name, - :pattern, :path ] - @paramdoc[:name] = "..." - @paramdoc[:pattern] = "..." - @paramdoc[:path] = "..." + @paramdoc[:name] = "The name of the service to run. This name + is used to find the init script in the search path." + @paramdoc[:path] = "The search path for finding init scripts. + There is currently no default, but hopefully soon there will + be a reasonable default for all platforms." @functions = [ :setpath ] - @doc = "Allows control of services managed by the node" + @doc = "Manage running services. Rather than supporting managing + individual processes, puppet uses init scripts to simplify + specification of how to start, stop, or test processes. The + *path* parameter is provided to enable creation of multiple + init script directories, including supporting them for normal + users." @name = :service @namevar = :name diff --git a/lib/puppet/type/symlink.rb b/lib/puppet/type/symlink.rb index 4cbd67083..b293de606 100755 --- a/lib/puppet/type/symlink.rb +++ b/lib/puppet/type/symlink.rb @@ -10,95 +10,14 @@ module Puppet # okay, how do we deal with parameters that don't have operations # associated with them? class State - class PFileLink < Puppet::State - require 'etc' - attr_reader :link - - @doc = "... to be documented ..." - @name = :link - - # create the link - def self.create(file,link) - begin - Puppet.debug("Creating symlink '%s' to '%s'" % [file, link]) - unless File.symlink(file,link) - raise Puppet::Error.new( - "Could not create symlink '%s'" % link - ) - end - rescue => detail - raise Puppet::Error.new( - "Cannot create symlink '%s': %s" % [file,detail] - ) - end - end - - # remove an existing link - def self.remove(link) - if FileTest.symlink?(link) - Puppet.debug("Removing symlink '%s'" % link) - begin - File.unlink(link) - rescue - raise Puppet::Error.new( - "Failed to remove symlink '%s'" % link - ) - end - elsif FileTest.exists?(link) - error = Puppet::Error.new( - "Cannot remove normal file '%s'" % link) - raise error - else - Puppet.debug("Symlink '%s' does not exist" % link) - end - end - - def retrieve - if FileTest.symlink?(@link) - self.is = File.readlink(@link) - return - elsif FileTest.exists?(@link) - Puppet.err "Cannot replace %s with a link" % @link - @should = nil - @is = nil - else - self.is = nil - return - end - end - - # we know the link should exist, but it should also point back - # to us - def should=(link) - @link = link - @should = @parent[:path] - - # unless we're fully qualified or we've specifically allowed - # relative links. Relative links are currently disabled, until - # someone actually asks for them - #unless @should =~ /^\// or @parent[:relativelinks] - unless @should =~ /^\// - @should = File.expand_path @should - end - end - - # this is somewhat complicated, because it could exist and be - # a file - def sync - if @is - self.class.remove(@link) - end - self.class.create(@should,@link) - - return :link_created - end - end - class SymlinkTarget < Puppet::State require 'etc' attr_accessor :file - @doc = "String file and path name pointed at by link" + @doc = "Create a link to another file. Currently only symlinks + are supported, and attempts to replace normal files with + links will currently fail, while existing but incorrect symlinks + will be removed." @name = :target def create @@ -184,9 +103,11 @@ module Puppet :recurse ] - @paramdoc[:path] = "Path of sym link to create" - @paramdoc[:recurse] = "If target is dir, recurse and link dir contents." - @doc = "Symbolic link of name from path to a target" + @paramdoc[:path] = "Path of link to create." + @paramdoc[:recurse] = "If target is a directory, recursively create + directories (using *file*'s *source* parameter) and link all + contained files." + @doc = "Create symbolic links to existing files." @name = :symlink @namevar = :path -- cgit