diff options
author | Luke Kanies <luke@madstop.com> | 2005-07-28 19:28:26 +0000 |
---|---|---|
committer | Luke Kanies <luke@madstop.com> | 2005-07-28 19:28:26 +0000 |
commit | 952a76c676ea6cc90fe9260e855c0276f0e391ed (patch) | |
tree | ce591384483b14364c952dae09d7f13b8a481841 | |
parent | 54895daf480ae2f0e7d7e48c356feca9f2b0f691 (diff) | |
download | puppet-952a76c676ea6cc90fe9260e855c0276f0e391ed.tar.gz puppet-952a76c676ea6cc90fe9260e855c0276f0e391ed.tar.xz puppet-952a76c676ea6cc90fe9260e855c0276f0e391ed.zip |
working on documentation
git-svn-id: https://reductivelabs.com/svn/puppet/library/trunk@471 980ebf18-57e1-0310-9a29-db15c13687c0
-rwxr-xr-x | lib/puppet/type/exec.rb | 23 | ||||
-rw-r--r-- | lib/puppet/type/package.rb | 602 | ||||
-rw-r--r-- | lib/puppet/type/pfile.rb | 79 | ||||
-rw-r--r-- | lib/puppet/type/pprocess.rb | 21 | ||||
-rw-r--r-- | lib/puppet/type/service.rb | 18 | ||||
-rwxr-xr-x | lib/puppet/type/symlink.rb | 97 |
6 files changed, 389 insertions, 451 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,11 +7,300 @@ require 'puppet/fact' module Puppet class PackageError < Puppet::Error; end + + # 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) + + class << self + attr_reader :params + end + + @@types = Hash.new(false) + + 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 + + # whether a package is installed or not + def [](name) + return @packages[name] + 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) + else + 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 + + def retrieve + @packages.clear() + + @packages = self.list() + end + end + + PackagingType.new(:apt) { |type| + type.query = proc { |pkg| + 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" + fields = [:desired, :status, :error, :name, :version, :description] + + 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+(.+)$} + + # 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 + + line = lines[-1] + + 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 + + if hash[:error] != " " + raise Puppet::PackageError.new( + "Package %s, version %s is in error state: %s" % + [hash[:name], hash[:install], hash[:error]] + ) + 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 + 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 = {} + + 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 "failed to match dpkg line %s" % line + end + } + } + ENV["COLUMNS"] = oldcol + + return packages + } + + # we need package retrieval mechanisms before we can have package + # installation mechanisms... + type.install = proc { |pkg| + cmd = "apt-get install %s" % pkg + + Puppet.info "Executing %s" % cmd.inspect + output = %x{#{cmd} 2>&1} + + unless $? == 0 + raise Puppet::PackageError.new(output) + end + } + + type.remove = proc { |pkg| + cmd = "dpkg -r %s" % pkg.name + output = %x{#{cmd}} + if $? != 0 + raise Puppet::PackageError.new(output) + end + } + } + + PackagingType.new(:rpm) { |type| + 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("| rpm -q -a --qf '%{NAME} %{VERSION}\n'") { |process| + # our regex for matching dpkg output + regex = %r{^(\S+)\s+(\S+)} + fields = [:name, :install] + hash = {} + + # 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 "failed to match rpm line %s" % line + end + } + } + ENV["COLUMNS"] = oldcol + + 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 = "rpm -e %s" % pkg.name + output = %x{#{cmd}} + if $? != 0 + raise output + 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 + } + + # 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 + raise "Could not find %s" % name + end + when /\s+\d+.+/: + # nothing; we're ignoring the FILES info + 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 + end + } + } + class State class PackageInstalled < Puppet::State @name = :install - @doc = "boolean flag for defining the package to be installed" + @doc = "What state the package should be in. *true*/*false*/version" def retrieve unless defined? @is @@ -84,18 +373,22 @@ module Puppet :description ] - @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" + @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 @@ -328,289 +621,6 @@ module Puppet 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 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 - - @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 - 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 - - def retrieve - @packages.clear() - - @packages = self.list() - end - end - - PackagingType.new(:apt) { |type| - type.query = proc { |pkg| - 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" - fields = [:desired, :status, :error, :name, :version, :description] - - 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+(.+)$} - - # 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 - - line = lines[-1] - - 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 - - if hash[:error] != " " - raise Puppet::PackageError.new( - "Package %s, version %s is in error state: %s" % - [hash[:name], hash[:install], hash[:error]] - ) - 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 - 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 = {} - - 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 "failed to match dpkg line %s" % line - end - } - } - ENV["COLUMNS"] = oldcol - - return packages - } - - # we need package retrieval mechanisms before we can have package - # installation mechanisms... - type.install = proc { |pkg| - cmd = "apt-get install %s" % pkg - - Puppet.info "Executing %s" % cmd.inspect - output = %x{#{cmd} 2>&1} - - unless $? == 0 - raise Puppet::PackageError.new(output) - end - } - - type.remove = proc { |pkg| - cmd = "dpkg -r %s" % pkg.name - output = %x{#{cmd}} - if $? != 0 - raise Puppet::PackageError.new(output) - end - } - } - - PackagingType.new(:rpm) { |type| - 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("| rpm -q -a --qf '%{NAME} %{VERSION}\n'") { |process| - # our regex for matching dpkg output - regex = %r{^(\S+)\s+(\S+)} - fields = [:name, :install] - hash = {} - - # 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 "failed to match rpm line %s" % line - end - } - } - ENV["COLUMNS"] = oldcol - - 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 = "rpm -e %s" % pkg.name - output = %x{#{cmd}} - if $? != 0 - raise output - 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 - } - - # 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 - raise "Could not find %s" % name - end - when /\s+\d+.+/: - # nothing; we're ignoring the FILES info - 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 - 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 |