summaryrefslogtreecommitdiffstats
path: root/lib/puppet
diff options
context:
space:
mode:
authorLuke Kanies <luke@madstop.com>2008-03-31 23:56:09 -0500
committerLuke Kanies <luke@madstop.com>2008-03-31 23:56:09 -0500
commit88dc49cb7b0efe757c92ce28c807b91335acb07a (patch)
tree13fe4561f1f524f97a8bb2c1ff84c1ef981d0241 /lib/puppet
parent4165edaeb71ee2883b1bb85ff39a52d5628b259f (diff)
parenta8592f1009040ebf30a98268610915cc33bb3f63 (diff)
downloadpuppet-88dc49cb7b0efe757c92ce28c807b91335acb07a.tar.gz
puppet-88dc49cb7b0efe757c92ce28c807b91335acb07a.tar.xz
puppet-88dc49cb7b0efe757c92ce28c807b91335acb07a.zip
Merge branch 'master' into master_no_global_resources
Conflicts: lib/puppet/node/catalog.rb lib/puppet/type/pfile.rb lib/puppet/type/pfilebucket.rb lib/puppet/util/filetype.rb spec/unit/node/catalog.rb spec/unit/other/transbucket.rb spec/unit/ral/provider/mount/parsed.rb spec/unit/ral/types/file.rb spec/unit/ral/types/interface.rb spec/unit/ral/types/mount.rb spec/unit/ral/types/package.rb spec/unit/ral/types/schedule.rb spec/unit/ral/types/service.rb test/language/compile.rb test/language/lexer.rb test/language/snippets.rb test/lib/puppettest.rb test/ral/types/basic.rb test/ral/types/cron.rb test/ral/types/exec.rb test/ral/types/file.rb test/ral/types/file/target.rb test/ral/types/filebucket.rb test/ral/types/fileignoresource.rb test/ral/types/filesources.rb test/ral/types/group.rb test/ral/types/host.rb test/ral/types/parameter.rb test/ral/types/sshkey.rb test/ral/types/tidy.rb test/ral/types/user.rb test/ral/types/yumrepo.rb
Diffstat (limited to 'lib/puppet')
-rw-r--r--lib/puppet/defaults.rb25
-rw-r--r--lib/puppet/dsl.rb88
-rw-r--r--lib/puppet/file_serving/configuration/parser.rb6
-rw-r--r--lib/puppet/file_serving/file_base.rb19
-rw-r--r--lib/puppet/file_serving/metadata.rb40
-rw-r--r--lib/puppet/indirector/facts/facter.rb3
-rw-r--r--lib/puppet/indirector/indirection.rb2
-rw-r--r--lib/puppet/indirector/node/exec.rb9
-rw-r--r--lib/puppet/indirector/node/ldap.rb12
-rw-r--r--lib/puppet/indirector/node/plain.rb7
-rw-r--r--lib/puppet/indirector/report/processor.rb3
-rw-r--r--lib/puppet/indirector/terminus.rb1
-rw-r--r--lib/puppet/indirector/yaml.rb10
-rw-r--r--lib/puppet/metatype/closure.rb4
-rw-r--r--lib/puppet/metatype/evaluation.rb41
-rw-r--r--lib/puppet/metatype/metaparams.rb8
-rw-r--r--lib/puppet/metatype/providers.rb11
-rw-r--r--lib/puppet/network.rb3
-rwxr-xr-xlib/puppet/network/authstore.rb3
-rw-r--r--lib/puppet/network/client.rb12
-rw-r--r--lib/puppet/network/client/master.rb37
-rwxr-xr-xlib/puppet/network/handler/fileserver.rb116
-rw-r--r--lib/puppet/network/handler/master.rb2
-rwxr-xr-xlib/puppet/network/handler/report.rb3
-rw-r--r--lib/puppet/network/http/mongrel/rest.rb6
-rw-r--r--lib/puppet/network/http/webrick/rest.rb8
-rw-r--r--lib/puppet/network/http_pool.rb26
-rw-r--r--lib/puppet/network/http_server/mongrel.rb8
-rw-r--r--lib/puppet/network/http_server/webrick.rb7
-rw-r--r--lib/puppet/network/server.rb2
-rw-r--r--lib/puppet/network/xmlrpc/client.rb13
-rw-r--r--lib/puppet/node.rb2
-rw-r--r--lib/puppet/node/catalog.rb93
-rw-r--r--lib/puppet/node/environment.rb3
-rw-r--r--lib/puppet/parser/ast.rb76
-rw-r--r--lib/puppet/parser/ast/astarray.rb29
-rw-r--r--lib/puppet/parser/ast/caseopt.rb8
-rw-r--r--lib/puppet/parser/ast/casestatement.rb9
-rw-r--r--lib/puppet/parser/ast/collection.rb8
-rw-r--r--lib/puppet/parser/ast/collexpr.rb8
-rw-r--r--lib/puppet/parser/ast/definition.rb307
-rw-r--r--lib/puppet/parser/ast/else.rb5
-rw-r--r--lib/puppet/parser/ast/function.rb13
-rw-r--r--lib/puppet/parser/ast/hostclass.rb125
-rw-r--r--lib/puppet/parser/ast/ifstatement.rb9
-rw-r--r--lib/puppet/parser/ast/leaf.rb12
-rw-r--r--lib/puppet/parser/ast/node.rb84
-rw-r--r--lib/puppet/parser/ast/resource.rb12
-rw-r--r--lib/puppet/parser/ast/resource_defaults.rb6
-rw-r--r--lib/puppet/parser/ast/resource_override.rb10
-rw-r--r--lib/puppet/parser/ast/resource_reference.rb6
-rw-r--r--lib/puppet/parser/ast/resourceparam.rb6
-rw-r--r--lib/puppet/parser/ast/selector.rb11
-rw-r--r--lib/puppet/parser/ast/tag.rb6
-rw-r--r--lib/puppet/parser/ast/vardef.rb7
-rw-r--r--lib/puppet/parser/collector.rb10
-rw-r--r--lib/puppet/parser/compiler.rb (renamed from lib/puppet/parser/compile.rb)168
-rw-r--r--lib/puppet/parser/functions.rb6
-rw-r--r--lib/puppet/parser/grammar.ra4
-rw-r--r--lib/puppet/parser/interpreter.rb55
-rw-r--r--lib/puppet/parser/lexer.rb673
-rw-r--r--lib/puppet/parser/parser.rb9
-rw-r--r--lib/puppet/parser/parser_support.rb30
-rw-r--r--lib/puppet/parser/resource.rb89
-rw-r--r--lib/puppet/parser/resource/param.rb2
-rw-r--r--lib/puppet/parser/resource/reference.rb10
-rw-r--r--lib/puppet/parser/scope.rb19
-rw-r--r--lib/puppet/parser/templatewrapper.rb2
-rw-r--r--lib/puppet/pgraph.rb43
-rw-r--r--lib/puppet/provider/interface/redhat.rb130
-rwxr-xr-xlib/puppet/provider/mailalias/aliases.rb5
-rw-r--r--lib/puppet/provider/nameservice/directoryservice.rb13
-rwxr-xr-xlib/puppet/provider/package/fink.rb2
-rwxr-xr-xlib/puppet/provider/package/gem.rb14
-rwxr-xr-xlib/puppet/provider/package/openbsd.rb14
-rw-r--r--lib/puppet/provider/package/pkgdmg.rb7
-rw-r--r--lib/puppet/provider/package/portage.rb16
-rwxr-xr-xlib/puppet/provider/package/ports.rb3
-rw-r--r--lib/puppet/provider/package/yumhelper.py14
-rwxr-xr-xlib/puppet/provider/service/debian.rb3
-rw-r--r--lib/puppet/provider/service/gentoo.rb4
-rwxr-xr-xlib/puppet/provider/service/init.rb2
-rwxr-xr-xlib/puppet/provider/sshkey/parsed.rb2
-rw-r--r--lib/puppet/provider/user/useradd.rb4
-rw-r--r--lib/puppet/provider/zone/solaris.rb3
-rw-r--r--lib/puppet/rails.rb4
-rw-r--r--lib/puppet/rails/database/001_add_created_at_to_all_tables.rb17
-rw-r--r--lib/puppet/rails/external/tagging/README4
-rw-r--r--lib/puppet/rails/external/tagging/acts_as_taggable.rb62
-rw-r--r--lib/puppet/rails/external/tagging/init.rb5
-rw-r--r--lib/puppet/rails/external/tagging/tag.rb50
-rw-r--r--lib/puppet/rails/external/tagging/tagging.rb12
-rw-r--r--lib/puppet/rails/fact_value.rb4
-rw-r--r--lib/puppet/rails/host.rb3
-rw-r--r--lib/puppet/rails/param_value.rb4
-rw-r--r--lib/puppet/rails/puppet_class.rb6
-rw-r--r--lib/puppet/rails/resource_tag.rb4
-rw-r--r--lib/puppet/rails/source_file.rb5
-rw-r--r--lib/puppet/reference/node_source.rb9
-rw-r--r--lib/puppet/reference/report.rb21
-rw-r--r--lib/puppet/reports/tagmail.rb15
-rw-r--r--lib/puppet/resource_reference.rb5
-rw-r--r--lib/puppet/simple_graph.rb23
-rwxr-xr-xlib/puppet/sslcertificates.rb2
-rw-r--r--lib/puppet/sslcertificates/ca.rb36
-rw-r--r--lib/puppet/transaction.rb11
-rw-r--r--lib/puppet/transportable.rb48
-rw-r--r--lib/puppet/type.rb15
-rwxr-xr-xlib/puppet/type/cron.rb18
-rwxr-xr-xlib/puppet/type/exec.rb35
-rw-r--r--lib/puppet/type/file.rb (renamed from lib/puppet/type/pfile.rb)146
-rwxr-xr-xlib/puppet/type/file/checksum.rb274
-rwxr-xr-xlib/puppet/type/file/content.rb (renamed from lib/puppet/type/pfile/content.rb)25
-rwxr-xr-xlib/puppet/type/file/ensure.rb (renamed from lib/puppet/type/pfile/ensure.rb)23
-rwxr-xr-xlib/puppet/type/file/group.rb (renamed from lib/puppet/type/pfile/group.rb)0
-rwxr-xr-xlib/puppet/type/file/mode.rb (renamed from lib/puppet/type/pfile/mode.rb)0
-rwxr-xr-xlib/puppet/type/file/owner.rb (renamed from lib/puppet/type/pfile/owner.rb)0
-rwxr-xr-xlib/puppet/type/file/source.rb (renamed from lib/puppet/type/pfile/source.rb)82
-rw-r--r--lib/puppet/type/file/target.rb (renamed from lib/puppet/type/pfile/target.rb)0
-rwxr-xr-xlib/puppet/type/file/type.rb (renamed from lib/puppet/type/pfile/type.rb)0
-rwxr-xr-xlib/puppet/type/filebucket.rb (renamed from lib/puppet/type/pfilebucket.rb)0
-rwxr-xr-xlib/puppet/type/host.rb16
-rwxr-xr-xlib/puppet/type/mailalias.rb2
-rw-r--r--lib/puppet/type/package.rb14
-rwxr-xr-xlib/puppet/type/pfile/checksum.rb326
-rw-r--r--lib/puppet/type/service.rb13
-rwxr-xr-xlib/puppet/type/sshkey.rb6
-rwxr-xr-xlib/puppet/type/tidy.rb2
-rw-r--r--lib/puppet/util.rb3
-rw-r--r--lib/puppet/util/autoload.rb10
-rw-r--r--lib/puppet/util/checksums.rb64
-rw-r--r--lib/puppet/util/constant_inflector.rb15
-rw-r--r--lib/puppet/util/diff.rb4
-rw-r--r--lib/puppet/util/fileparsing.rb3
-rwxr-xr-xlib/puppet/util/filetype.rb10
-rw-r--r--lib/puppet/util/graph.rb2
-rw-r--r--lib/puppet/util/settings.rb268
-rw-r--r--lib/puppet/util/tagging.rb40
138 files changed, 2179 insertions, 2333 deletions
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index a95023895..0f01c2ee2 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -66,7 +66,11 @@ module Puppet
:owner => "root",
:desc => "Where SSL certificates are kept."
},
- :rundir => { :default => rundir,
+ :rundir => {
+ :default => rundir,
+ :mode => 01777,
+ :owner => "$user",
+ :group => "$group",
:desc => "Where Puppet PID files are kept."
},
:genconfig => [false,
@@ -136,8 +140,6 @@ module Puppet
:show_diff => [false, "Whether to print a contextual diff when files are being replaced. The diff
is printed on stdout, so this option is meaningless unless you are running Puppet interactively.
This feature currently requires the ``diff/lcs`` Ruby library."],
- :yamldir => {:default => "$vardir/yaml", :owner => "$user", :group => "$user", :mode => "750",
- :desc => "The directory in which YAML data is stored, usually in a subdirectory."},
:daemonize => { :default => true,
:desc => "Send the process into the background. This is the default.",
:short => "D"
@@ -228,7 +230,7 @@ module Puppet
:owner => "$user",
:group => "$group",
:mode => 0664,
- :desc => "The certificate revocation list (CRL) for the CA. Set this to 'none' if you do not want to use a CRL."
+ :desc => "The certificate revocation list (CRL) for the CA. Set this to 'false' if you do not want to use a CRL."
},
:caprivatedir => { :default => "$cadir/private",
:owner => "$user",
@@ -256,6 +258,7 @@ module Puppet
:serial => { :default => "$cadir/serial",
:owner => "$user",
:group => "$group",
+ :mode => 0600,
:desc => "Where the serial number for certificates is stored."
},
:autosign => { :default => "$confdir/autosign.conf",
@@ -324,8 +327,8 @@ module Puppet
:masterport => [8140, "Which port puppetmasterd listens on."],
:parseonly => [false, "Just check the syntax of the manifests."],
:node_name => ["cert", "How the puppetmaster determines the client's identity
- and sets the 'hostname' fact for use in the manifest, in particular
- for determining which 'node' statement applies to the client.
+ and sets the 'hostname', 'fqdn' and 'domain' facts for use in the manifest,
+ in particular for determining which 'node' statement applies to the client.
Possible values are 'cert' (use the subject's CN in the client's
certificate) and 'facter' (use the hostname that the client
reported in its facts)"],
@@ -343,11 +346,15 @@ module Puppet
:ssl_client_header => ["HTTP_X_CLIENT_DN", "The header containing an authenticated
client's SSL DN. Only used with Mongrel. This header must be set by the proxy
to the authenticated client's SSL DN (e.g., ``/CN=puppet.reductivelabs.com``).
- See the `UsingMongrel`:trac: wiki page for more information."],
+ See http://reductivelabs.com/puppet/trac/wiki/UsingMongrel for more information."],
:ssl_client_verify_header => ["HTTP_X_CLIENT_VERIFY", "The header containing the status
message of the client verification. Only used with Mongrel. This header must be set by the proxy
to 'SUCCESS' if the client successfully authenticated, and anything else otherwise.
- See the `UsingMongrel`:trac: wiki page for more information."]
+ See http://reductivelabs.com/puppet/trac/wiki/UsingMongrel for more information."],
+ # To make sure this directory is created before we try to use it on the server, we need
+ # it to be in the server section (#1138).
+ :yamldir => {:default => "$vardir/yaml", :owner => "$user", :group => "$user", :mode => "750",
+ :desc => "The directory in which YAML data is stored, usually in a subdirectory."}
)
self.setdefaults(:puppetd,
@@ -597,7 +604,7 @@ module Puppet
setdefaults(:ldap,
:ldapnodes => [false,
"Whether to search for node configurations in LDAP. See
- `LdapNodes`:trac: for more information."],
+ http://reductivelabs.com/puppet/trac/wiki/LdapNodes/ for more information."],
:ldapssl => [false,
"Whether SSL should be used when searching for nodes.
Defaults to false because SSL usually requires certificates
diff --git a/lib/puppet/dsl.rb b/lib/puppet/dsl.rb
index 4fbce556c..966feaf9b 100644
--- a/lib/puppet/dsl.rb
+++ b/lib/puppet/dsl.rb
@@ -46,58 +46,56 @@
#
# apply
-module Puppet
- # Provide the actual commands for acting like a language.
- module DSL
- def aspect(name, options = {}, &block)
- Puppet::Aspect.new(name, options, &block)
- end
+require 'puppet'
- def acquire(*names)
- names.each do |name|
- if aspect = Puppet::Aspect[name]
- unless aspect.evaluated?
- aspect.evaluate
- end
- else
- raise "Could not find aspect %s" % name
+# Provide the actual commands for acting like a language.
+module Puppet::DSL
+ def aspect(name, options = {}, &block)
+ Puppet::DSL::Aspect.new(name, options, &block)
+ end
+
+ def acquire(*names)
+ names.each do |name|
+ if aspect = Puppet::DSL::Aspect[name]
+ unless aspect.evaluated?
+ aspect.evaluate
end
+ else
+ raise "Could not find aspect %s" % name
end
end
+ end
- def apply
- bucket = export()
- catalog = bucket.to_catalog
- catalog.apply
- end
+ def apply
+ bucket = export()
+ catalog = bucket.to_catalog
+ catalog.apply
+ end
- def export
- objects = Puppet::Aspect.collect do |name, aspect|
- if aspect.evaluated?
- aspect.export
- end
- end.reject { |a| a.nil? }.flatten.collect do |obj|
- obj.to_trans
+ def export
+ objects = Puppet::DSL::Aspect.collect do |name, aspect|
+ if aspect.evaluated?
+ aspect.export
end
- bucket = Puppet::TransBucket.new(objects)
- bucket.name = "top"
- bucket.type = "class"
-
- return bucket
+ end.reject { |a| a.nil? }.flatten.collect do |obj|
+ obj.to_trans
end
+ bucket = Puppet::TransBucket.new(objects)
+ bucket.name = "top"
+ bucket.type = "class"
- def init
- unless Process.uid == 0
- Puppet[:confdir] = File.expand_path("~/.puppet")
- Puppet[:vardir] = File.expand_path("~/.puppet/var")
- end
- Puppet[:user] = Process.uid
- Puppet[:group] = Process.gid
- Puppet::Util::Log.newdestination(:console)
- Puppet::Util::Log.level = :info
- end
+ return bucket
+ end
- private
+ def init
+ unless Process.uid == 0
+ Puppet[:confdir] = File.expand_path("~/.puppet")
+ Puppet[:vardir] = File.expand_path("~/.puppet/var")
+ end
+ Puppet[:user] = Process.uid
+ Puppet[:group] = Process.gid
+ Puppet::Util::Log.newdestination(:console)
+ Puppet::Util::Log.level = :info
end
class Aspect
@@ -224,10 +222,10 @@ module Puppet
end
def newresource(type, name, params = {})
- if self.is_a?(Puppet::Aspect)
+ if self.is_a?(Puppet::DSL::Aspect)
source = self
else
- source = Puppet::Aspect[:main]
+ source = Puppet::DSL::Aspect[:main]
end
unless obj = @@objects[type][name]
obj = Resource.new :title => name, :type => type.name,
@@ -262,7 +260,7 @@ module Puppet
env = nil
end
@node.parameters = Facter.to_hash
- @compile = Puppet::Parser::Compile.new(@node, @interp.send(:parser, env))
+ @compile = Puppet::Parser::Compiler.new(@node, @interp.send(:parser, env))
@scope = @compile.topscope
end
@scope
diff --git a/lib/puppet/file_serving/configuration/parser.rb b/lib/puppet/file_serving/configuration/parser.rb
index 707c3f9b1..cda6889d4 100644
--- a/lib/puppet/file_serving/configuration/parser.rb
+++ b/lib/puppet/file_serving/configuration/parser.rb
@@ -62,7 +62,8 @@ class Puppet::FileServing::Configuration::Parser < Puppet::Util::LoadedFile
# Allow a given pattern access to a mount.
def allow(mount, value)
- value.split(/\s*,\s*/).each { |val|
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = value.split(/\s*,\s*/).each { |val|
begin
mount.info "allowing %s access" % val
mount.allow(val)
@@ -75,7 +76,8 @@ class Puppet::FileServing::Configuration::Parser < Puppet::Util::LoadedFile
# Deny a given pattern access to a mount.
def deny(mount, value)
- value.split(/\s*,\s*/).each { |val|
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = value.split(/\s*,\s*/).each { |val|
begin
mount.info "denying %s access" % val
mount.deny(val)
diff --git a/lib/puppet/file_serving/file_base.rb b/lib/puppet/file_serving/file_base.rb
index 7f169d1ea..e87d683aa 100644
--- a/lib/puppet/file_serving/file_base.rb
+++ b/lib/puppet/file_serving/file_base.rb
@@ -9,16 +9,28 @@ require 'puppet/file_serving'
class Puppet::FileServing::FileBase
attr_accessor :key
+ # Does our file exist?
+ def exist?
+ begin
+ stat
+ return true
+ rescue => detail
+ return false
+ end
+ end
+
# Return the full path to our file. Fails if there's no path set.
def full_path
raise(ArgumentError, "You must set a path to get a file's path") unless self.path
- relative_path ? File.join(path, relative_path) : path
+ if relative_path.nil? or relative_path == ""
+ path
+ else
+ File.join(path, relative_path)
+ end
end
def initialize(key, options = {})
- raise ArgumentError.new("Files must not be fully qualified") if path =~ /^#{::File::SEPARATOR}/
-
@key = key
@links = :manage
@@ -34,6 +46,7 @@ class Puppet::FileServing::FileBase
# Determine how we deal with links.
attr_reader :links
def links=(value)
+ value = :manage if value == :ignore
raise(ArgumentError, ":links can only be set to :manage or :follow") unless [:manage, :follow].include?(value)
@links = value
end
diff --git a/lib/puppet/file_serving/metadata.rb b/lib/puppet/file_serving/metadata.rb
index e26e75844..56712122c 100644
--- a/lib/puppet/file_serving/metadata.rb
+++ b/lib/puppet/file_serving/metadata.rb
@@ -28,6 +28,25 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::FileBase
attr_reader :path, :owner, :group, :mode, :checksum_type, :checksum, :ftype, :destination
+ PARAM_ORDER = [:mode, :ftype, :owner, :group]
+
+ def attributes_with_tabs
+ desc = []
+ PARAM_ORDER.each { |check|
+ check = :ftype if check == :type
+ desc << send(check)
+ }
+
+ case ftype
+ when "file", "directory": desc << checksum
+ when "link": desc << @destination
+ else
+ raise ArgumentError, "Cannot manage files of type %s" % ftype
+ end
+
+ return desc.join("\t")
+ end
+
def checksum_type=(type)
raise(ArgumentError, "Unsupported checksum type %s" % type) unless respond_to?("%s_file" % type)
@@ -45,13 +64,19 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::FileBase
@ftype = stat.ftype
- # Set the octal mode, but as a string.
- @mode = "%o" % (stat.mode & 007777)
+ # We have to mask the mode, yay.
+ @mode = stat.mode & 007777
- if stat.ftype == "symlink"
+ case stat.ftype
+ when "file":
+ @checksum = ("{%s}" % @checksum_type) + send("%s_file" % @checksum_type, real_path)
+ when "directory": # Always just timestamp the directory.
+ sumtype = @checksum_type.to_s =~ /time/ ? @checksum_type : "ctime"
+ @checksum = ("{%s}" % sumtype) + send("%s_file" % sumtype, path).to_s
+ when "link":
@destination = File.readlink(real_path)
else
- @checksum = get_checksum(real_path)
+ raise ArgumentError, "Cannot manage files of type %s" % stat.ftype
end
end
@@ -59,11 +84,4 @@ class Puppet::FileServing::Metadata < Puppet::FileServing::FileBase
@checksum_type = "md5"
super
end
-
- private
-
- # Retrieve our checksum.
- def get_checksum(path)
- ("{%s}" % @checksum_type) + send("%s_file" % @checksum_type, path)
- end
end
diff --git a/lib/puppet/indirector/facts/facter.rb b/lib/puppet/indirector/facts/facter.rb
index 5b9a7b3c0..a8c47e3bf 100644
--- a/lib/puppet/indirector/facts/facter.rb
+++ b/lib/puppet/indirector/facts/facter.rb
@@ -23,7 +23,8 @@ class Puppet::Node::Facts::Facter < Puppet::Indirector::Code
end
def self.loadfacts
- Puppet[:factpath].split(":").each do |dir|
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet[:factpath].split(":").each do |dir|
loaddir(dir, "fact")
end
end
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
index 129676e9c..d47433c60 100644
--- a/lib/puppet/indirector/indirection.rb
+++ b/lib/puppet/indirector/indirection.rb
@@ -162,7 +162,7 @@ class Puppet::Indirector::Indirection
# See if our instance is in the cache and up to date.
if cache? and cache.has_most_recent?(key, terminus(terminus_name).version(key))
- Puppet.info "Using cached %s %s" % [self.name, key]
+ Puppet.debug "Using cached %s %s" % [self.name, key]
return cache.find(key, *args)
end
diff --git a/lib/puppet/indirector/node/exec.rb b/lib/puppet/indirector/node/exec.rb
index ed76bce94..dcfc625b2 100644
--- a/lib/puppet/indirector/node/exec.rb
+++ b/lib/puppet/indirector/node/exec.rb
@@ -24,13 +24,20 @@ class Puppet::Node::Exec < Puppet::Indirector::Exec
return create_node(name, result)
end
+ # Use the version of the facts, since we assume that's the main thing
+ # that changes. If someone wants their own way of defining version,
+ # they can easily provide their own, um, version of this class.
+ def version(name)
+ Puppet::Node::Facts.version(name)
+ end
+
private
# Turn our outputted objects into a Puppet::Node instance.
def create_node(name, result)
node = Puppet::Node.new(name)
set = false
- [:parameters, :classes].each do |param|
+ [:parameters, :classes, :environment].each do |param|
if value = result[param]
node.send(param.to_s + "=", value)
set = true
diff --git a/lib/puppet/indirector/node/ldap.rb b/lib/puppet/indirector/node/ldap.rb
index dd11f4e9b..73b5cdd70 100644
--- a/lib/puppet/indirector/node/ldap.rb
+++ b/lib/puppet/indirector/node/ldap.rb
@@ -7,7 +7,8 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap
# The attributes that Puppet class information is stored in.
def class_attributes
- Puppet[:ldapclassattrs].split(/\s*,\s*/)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet[:ldapclassattrs].split(/\s*,\s*/)
end
# Look for our node in ldap.
@@ -36,11 +37,14 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap
information[:parameters][param] = value unless information[:parameters].include?(param)
end
+ information[:environment] ||= parent_info[:environment]
+
parent = parent_info[:parent]
end
node.classes = information[:classes].uniq unless information[:classes].empty?
node.parameters = information[:parameters] unless information[:parameters].empty?
+ node.environment = information[:environment] if information[:environment]
node.fact_merge
return node
@@ -87,6 +91,8 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap
hash
end
+ result[:environment] = result[:parameters]["environment"] if result[:parameters]["environment"]
+
return result
end
@@ -117,4 +123,8 @@ class Puppet::Node::Ldap < Puppet::Indirector::Ldap
end
filter
end
+
+ def version(name)
+ Puppet::Node::Facts.version(name)
+ end
end
diff --git a/lib/puppet/indirector/node/plain.rb b/lib/puppet/indirector/node/plain.rb
index d60cc3aa5..8058563e6 100644
--- a/lib/puppet/indirector/node/plain.rb
+++ b/lib/puppet/indirector/node/plain.rb
@@ -16,4 +16,11 @@ class Puppet::Node::Plain < Puppet::Indirector::Plain
node.fact_merge
node
end
+
+ # Use the version of the facts, since we assume that's the main thing
+ # that changes. If someone wants their own way of defining version,
+ # they can easily provide their own, um, version of this class.
+ def version(name)
+ Puppet::Node::Facts.version(name)
+ end
end
diff --git a/lib/puppet/indirector/report/processor.rb b/lib/puppet/indirector/report/processor.rb
index fd1bc413a..fa2b7f36b 100644
--- a/lib/puppet/indirector/report/processor.rb
+++ b/lib/puppet/indirector/report/processor.rb
@@ -45,6 +45,7 @@ class Puppet::Transaction::Report::Processor < Puppet::Indirector::Code
# Handle the parsing of the reports attribute.
def reports
- Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
end
end
diff --git a/lib/puppet/indirector/terminus.rb b/lib/puppet/indirector/terminus.rb
index a0623b284..3015c8a37 100644
--- a/lib/puppet/indirector/terminus.rb
+++ b/lib/puppet/indirector/terminus.rb
@@ -66,6 +66,7 @@ class Puppet::Indirector::Terminus
subclass.terminus_type = self.name
# Our subclass is specifically associated with an indirection.
+ raise("Invalid name %s" % longname) unless names.length > 0
indirection_name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_" + i.downcase }.intern
if indirection_name == "" or indirection_name.nil?
diff --git a/lib/puppet/indirector/yaml.rb b/lib/puppet/indirector/yaml.rb
index 16816d941..4dd29159e 100644
--- a/lib/puppet/indirector/yaml.rb
+++ b/lib/puppet/indirector/yaml.rb
@@ -2,11 +2,6 @@ require 'puppet/indirector/terminus'
# The base class for YAML indirection termini.
class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
- def initialize
- # Make sure our base directory exists.
- Puppet.settings.use(:yaml)
- end
-
# Read a given name's file in and convert it from YAML.
def find(name)
raise ArgumentError.new("You must specify the name of the object to retrieve") unless name
@@ -40,6 +35,11 @@ class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
end
end
+ def version(name)
+ return nil unless FileTest.exist?(path(name))
+ return File.stat(path(name)).mtime
+ end
+
private
def from_yaml(text)
diff --git a/lib/puppet/metatype/closure.rb b/lib/puppet/metatype/closure.rb
index 259854411..673a2359d 100644
--- a/lib/puppet/metatype/closure.rb
+++ b/lib/puppet/metatype/closure.rb
@@ -20,6 +20,10 @@ class Puppet::Type
end
end
+ def isomorphic?
+ self.class.isomorphic?
+ end
+
# is the instance a managed instance? A 'yes' here means that
# the instance was created from the language, vs. being created
# in order resolve other questions, such as finding a package
diff --git a/lib/puppet/metatype/evaluation.rb b/lib/puppet/metatype/evaluation.rb
index b3b6570b2..ff1eddb55 100644
--- a/lib/puppet/metatype/evaluation.rb
+++ b/lib/puppet/metatype/evaluation.rb
@@ -4,6 +4,11 @@ class Puppet::Type
# This returns any changes resulting from testing, thus 'collect' rather
# than 'each'.
def evaluate
+ if self.provider.is_a?(Puppet::Provider)
+ unless provider.class.suitable?
+ raise Puppet::Error, "Provider %s is not functional on this platform" % provider.class.name
+ end
+ end
#Puppet.err "Evaluating %s" % self.path.join(":")
unless defined? @evalcount
self.err "No evalcount defined on '%s' of type '%s'" %
@@ -108,7 +113,11 @@ class Puppet::Type
# Are we running in noop mode?
def noop?
- @noop || Puppet[:noop]
+ if defined?(@noop)
+ @noop
+ else
+ Puppet[:noop]
+ end
end
def noop
@@ -121,30 +130,23 @@ class Puppet::Type
# the other properties matter.
changes = []
ensureparam = @parameters[:ensure]
- if @parameters.include?(:ensure) && !currentvalues.include?(ensureparam)
+
+ # This allows resource types to have 'ensure' be a parameter, which allows them to
+ # just pass the parameter on to other generated resources.
+ ensureparam = nil unless ensureparam.is_a?(Puppet::Property)
+ if ensureparam && !currentvalues.include?(ensureparam)
raise Puppet::DevError, "Parameter ensure defined but missing from current values"
end
- if @parameters.include?(:ensure) and ! ensureparam.insync?(currentvalues[ensureparam])
-# self.info "ensuring %s from %s" %
-# [@parameters[:ensure].should, @parameters[:ensure].is]
+
+ if ensureparam and ! ensureparam.insync?(currentvalues[ensureparam])
changes << Puppet::PropertyChange.new(ensureparam, currentvalues[ensureparam])
# Else, if the 'ensure' property is correctly absent, then do
# nothing
- elsif @parameters.include?(:ensure) and currentvalues[ensureparam] == :absent
- # self.info "Object is correctly absent"
+ elsif ensureparam and currentvalues[ensureparam] == :absent
return []
else
-# if @parameters.include?(:ensure)
-# self.info "ensure: Is: %s, Should: %s" %
-# [@parameters[:ensure].is, @parameters[:ensure].should]
-# else
-# self.info "no ensure property"
-# end
changes = properties().find_all { |property|
- unless currentvalues.include?(property)
- raise Puppet::DevError, "Property %s does not have a current value",
- [property.name]
- end
+ currentvalues[property] ||= :absent
! property.insync?(currentvalues[property])
}.collect { |property|
Puppet::PropertyChange.new(property, currentvalues[property])
@@ -152,10 +154,7 @@ class Puppet::Type
end
if Puppet[:debug] and changes.length > 0
- self.debug("Changing " + changes.collect { |ch|
- ch.property.name
- }.join(",")
- )
+ self.debug("Changing " + changes.collect { |ch| ch.property.name }.join(","))
end
changes
diff --git a/lib/puppet/metatype/metaparams.rb b/lib/puppet/metatype/metaparams.rb
index 9e4cb089c..bf64d3a93 100644
--- a/lib/puppet/metatype/metaparams.rb
+++ b/lib/puppet/metatype/metaparams.rb
@@ -255,7 +255,7 @@ class Puppet::Type
@value.each do |value|
unless @resource.catalog.resource(*value)
description = self.class.direction == :in ? "dependency" : "dependent"
- raise Puppet::Error, "Could not find #{description} %s[%s]" % [value[0].to_s.capitalize, value[1]]
+ fail Puppet::Error, "Could not find #{description} %s[%s] for %s" % [value[0].to_s.capitalize, value[1], resource.ref]
end
end
end
@@ -373,7 +373,7 @@ class Puppet::Type
}
service { nagios:
running => true,
- subscribe => file[nagconf]
+ subscribe => File[nagconf]
}
}
@@ -390,7 +390,7 @@ class Puppet::Type
file { "/var/nagios/configuration":
source => "...",
recurse => true,
- before => exec["nagios-rebuid"]
+ before => Exec["nagios-rebuid"]
}
exec { "nagios-rebuild":
@@ -408,7 +408,7 @@ class Puppet::Type
file { "/etc/sshd_config":
source => "....",
- notify => service[sshd]
+ notify => Service[sshd]
}
service { sshd:
diff --git a/lib/puppet/metatype/providers.rb b/lib/puppet/metatype/providers.rb
index c302d9928..6308f7e54 100644
--- a/lib/puppet/metatype/providers.rb
+++ b/lib/puppet/metatype/providers.rb
@@ -188,15 +188,8 @@ class Puppet::Type
provider_class = provider_class.class.name
end
- if provider = @resource.class.provider(provider_class)
- unless provider.suitable?
- raise ArgumentError,
- "Provider '%s' is not functional on this platform" %
- [provider_class]
- end
- else
- raise ArgumentError, "Invalid %s provider '%s'" %
- [@resource.class.name, provider_class]
+ unless provider = @resource.class.provider(provider_class)
+ raise ArgumentError, "Invalid %s provider '%s'" % [@resource.class.name, provider_class]
end
end
diff --git a/lib/puppet/network.rb b/lib/puppet/network.rb
new file mode 100644
index 000000000..8993b8869
--- /dev/null
+++ b/lib/puppet/network.rb
@@ -0,0 +1,3 @@
+# Just a stub, so we can correctly scope other classes.
+module Puppet::Network # :nodoc:
+end
diff --git a/lib/puppet/network/authstore.rb b/lib/puppet/network/authstore.rb
index c16bef32f..cb1fdc57d 100755
--- a/lib/puppet/network/authstore.rb
+++ b/lib/puppet/network/authstore.rb
@@ -235,7 +235,8 @@ module Puppet
# Convert the name to a common pattern.
def munge_name(name)
- name.downcase.split(".").reverse
+ # LAK:NOTE http://snurl.com/21zf8 [groups_google_com]
+ x = name.downcase.split(".").reverse
end
# Parse our input pattern and figure out what kind of allowal
diff --git a/lib/puppet/network/client.rb b/lib/puppet/network/client.rb
index 283436e95..478883959 100644
--- a/lib/puppet/network/client.rb
+++ b/lib/puppet/network/client.rb
@@ -7,6 +7,8 @@ require 'puppet/util/subclass_loader'
require 'puppet/util/methodhelper'
require 'puppet/sslcertificates/support'
+require 'puppet/network/handler'
+
require 'net/http'
# Some versions of ruby don't have this method defined, which basically causes
@@ -94,10 +96,9 @@ class Puppet::Network::Client
self.read_cert
# We have to start the HTTP connection manually before we start
- # sending it requests or keep-alive won't work.
- if @driver.respond_to? :start
- @driver.start
- end
+ # sending it requests or keep-alive won't work. Note that with #1010,
+ # we don't currently actually want keep-alive.
+ @driver.start if @driver.respond_to? :start and Puppet::Network::HttpPool.keep_alive?
@local = false
elsif hash.include?(driverparam)
@@ -107,8 +108,7 @@ class Puppet::Network::Client
end
@local = true
else
- raise Puppet::Network::ClientError, "%s must be passed a Server or %s" %
- [self.class, driverparam]
+ raise Puppet::Network::ClientError, "%s must be passed a Server or %s" % [self.class, driverparam]
end
end
diff --git a/lib/puppet/network/client/master.rb b/lib/puppet/network/client/master.rb
index a920afec6..4c7fa5f5b 100644
--- a/lib/puppet/network/client/master.rb
+++ b/lib/puppet/network/client/master.rb
@@ -26,28 +26,32 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
down = Puppet[:downcasefacts]
- facts = {}
- Facter.each { |name,fact|
+ facts = Facter.to_hash.inject({}) do |newhash, array|
+ name, fact = array
if down
- facts[name] = fact.to_s.downcase
+ newhash[name] = fact.to_s.downcase
else
- facts[name] = fact.to_s
+ newhash[name] = fact.to_s
end
- }
+ newhash
+ end
# Add our client version to the list of facts, so people can use it
# in their manifests
facts["clientversion"] = Puppet.version.to_s
# And add our environment as a fact.
- facts["environment"] = Puppet[:environment]
-
+ unless facts.include?("environment")
+ facts["environment"] = Puppet[:environment]
+ end
+
facts
end
# Return the list of dynamic facts as an array of symbols
def self.dynamic_facts
- Puppet.settings[:dynamicfacts].split(/\s*,\s*/).collect { |fact| fact.downcase }
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet.settings[:dynamicfacts].split(/\s*,\s*/).collect { |fact| fact.downcase }
end
# Cache the config
@@ -316,7 +320,8 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
:group => Process.gid,
:purge => true,
:force => true,
- :backup => false
+ :backup => false,
+ :noop => false
}
if args[:ignore]
@@ -327,9 +332,6 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
Puppet.info "Retrieving #{args[:name]}s"
- noop = Puppet[:noop]
- Puppet[:noop] = false
-
files = []
begin
Timeout::timeout(self.timeout) do
@@ -351,14 +353,6 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
downconfig.clear
return files
- ensure
- # I can't imagine why this is necessary, but apparently at last one person has had problems with noop
- # being nil here.
- if noop.nil?
- Puppet[:noop] = false
- else
- Puppet[:noop] = noop
- end
end
# Retrieve facts from the central server.
@@ -431,7 +425,8 @@ class Puppet::Network::Client::Master < Puppet::Network::Client
end
def self.loadfacts
- Puppet[:factpath].split(":").each do |dir|
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet[:factpath].split(":").each do |dir|
loaddir(dir, "fact")
end
end
diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb
index 3ee4721f3..183979429 100755
--- a/lib/puppet/network/handler/fileserver.rb
+++ b/lib/puppet/network/handler/fileserver.rb
@@ -5,6 +5,9 @@ require 'cgi'
require 'delegate'
require 'sync'
+require 'puppet/file_serving'
+require 'puppet/file_serving/metadata'
+
class Puppet::Network::Handler
AuthStoreError = Puppet::AuthStoreError
class FileServerError < Puppet::Error; end
@@ -59,40 +62,27 @@ class Puppet::Network::Handler
# Describe a given file. This returns all of the manageable aspects
# of that file.
- def describe(url, links = :ignore, client = nil, clientip = nil)
+ def describe(url, links = :follow, client = nil, clientip = nil)
links = links.intern if links.is_a? String
- if links == :manage
- raise Puppet::Network::Handler::FileServerError, "Cannot currently copy links"
- end
-
mount, path = convert(url, client, clientip)
- if client
- mount.debug "Describing %s for %s" % [url, client]
- end
+ mount.debug("Describing %s for %s" % [url, client]) if client
- obj = nil
- unless obj = mount.getfileobject(path, links, client)
+ # use the mount to resolve the path for us.
+ metadata = Puppet::FileServing::Metadata.new(url, :path => mount.file_path(path, client), :links => links)
+
+ return "" unless metadata.exist?
+
+ begin
+ metadata.collect_attributes
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err detail
return ""
end
- currentvalues = mount.check(obj)
-
- desc = []
- CHECKPARAMS.each { |check|
- if value = currentvalues[check]
- desc << value
- else
- if check == "checksum" and currentvalues[:type] == "file"
- mount.notice "File %s does not have data for %s" %
- [obj.name, check]
- end
- desc << nil
- end
- }
-
- return desc.join("\t")
+ return metadata.attributes_with_tabs
end
# Create a new fileserving module.
@@ -140,26 +130,18 @@ class Puppet::Network::Handler
def list(url, links = :ignore, recurse = false, ignore = false, client = nil, clientip = nil)
mount, path = convert(url, client, clientip)
- if client
- mount.debug "Listing %s for %s" % [url, client]
- end
+ mount.debug "Listing %s for %s" % [url, client] if client
- obj = nil
- unless mount.path_exists?(path, client)
- return ""
- end
+ return "" unless mount.path_exists?(path, client)
desc = mount.list(path, recurse, ignore, client)
if desc.length == 0
- mount.notice "Got no information on //%s/%s" %
- [mount, path]
+ mount.notice "Got no information on //%s/%s" % [mount, path]
return ""
end
-
- desc.collect { |sub|
- sub.join("\t")
- }.join("\n")
+
+ desc.collect { |sub| sub.join("\t") }.join("\n")
end
def local?
@@ -213,12 +195,7 @@ class Puppet::Network::Handler
return ""
end
- str = nil
- if links == :manage
- raise Puppet::Error, "Cannot copy links yet."
- else
- str = mount.read_file(path, client)
- end
+ str = mount.read_file(path, client)
if @local
return str
@@ -452,55 +429,6 @@ class Puppet::Network::Handler
Puppet::Util.logmethods(self, true)
- def getfileobject(dir, links, client = nil)
- unless path_exists?(dir, client)
- self.debug "File source %s does not exist" % dir
- return nil
- end
-
- return fileobj(dir, links, client)
- end
-
- # Run 'retrieve' on a file. This gets the actual parameters, so
- # we can pass them to the client.
- def check(obj)
- # Retrieval is enough here, because we don't want to cache
- # any information in the state file, and we don't want to generate
- # any state changes or anything. We don't even need to sync
- # the checksum, because we're always going to hit the disk
- # directly.
-
- # We're now caching file data, using the LoadedFile to check the
- # disk no more frequently than the :filetimeout.
- path = obj[:path]
- sync = sync(path)
- unless data = @@files[path]
- data = {}
- sync.synchronize(Sync::EX) do
- @@files[path] = data
- data[:loaded_obj] = Puppet::Util::LoadedFile.new(path)
- data[:values] = properties(obj)
- return data[:values]
- end
- end
-
- changed = nil
- sync.synchronize(Sync::SH) do
- changed = data[:loaded_obj].changed?
- end
-
- if changed
- sync.synchronize(Sync::EX) do
- data[:values] = properties(obj)
- return data[:values]
- end
- else
- sync.synchronize(Sync::SH) do
- return data[:values]
- end
- end
- end
-
# Create a map for a specific client.
def clientmap(client)
{
diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb
index 8d84fe8b8..dabfaca50 100644
--- a/lib/puppet/network/handler/master.rb
+++ b/lib/puppet/network/handler/master.rb
@@ -82,6 +82,8 @@ class Puppet::Network::Handler
if Puppet[:node_name] == 'cert'
if name
client = name
+ facts["fqdn"] = client
+ facts["hostname"], facts["domain"] = client.split('.', 2)
end
if ip
clientip = ip
diff --git a/lib/puppet/network/handler/report.rb b/lib/puppet/network/handler/report.rb
index 8ddeed9f6..b92b77ea5 100755
--- a/lib/puppet/network/handler/report.rb
+++ b/lib/puppet/network/handler/report.rb
@@ -79,7 +79,8 @@ class Puppet::Network::Handler
# Handle the parsing of the reports attribute.
def reports
- Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
end
end
end
diff --git a/lib/puppet/network/http/mongrel/rest.rb b/lib/puppet/network/http/mongrel/rest.rb
index db63613ab..6c24e360c 100644
--- a/lib/puppet/network/http/mongrel/rest.rb
+++ b/lib/puppet/network/http/mongrel/rest.rb
@@ -14,11 +14,13 @@ class Puppet::Network::HTTP::MongrelREST < Puppet::Network::HTTP::Handler
end
def path(request)
- '/' + request.params[Mongrel::Const::REQUEST_PATH].split('/')[1]
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = '/' + request.params[Mongrel::Const::REQUEST_PATH].split('/')[1]
end
def request_key(request)
- request.params[Mongrel::Const::REQUEST_PATH].split('/')[2]
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = request.params[Mongrel::Const::REQUEST_PATH].split('/')[2]
end
def body(request)
diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/network/http/webrick/rest.rb
index dd0c84d61..8cda079e2 100644
--- a/lib/puppet/network/http/webrick/rest.rb
+++ b/lib/puppet/network/http/webrick/rest.rb
@@ -19,11 +19,13 @@ class Puppet::Network::HTTP::WEBrickREST < Puppet::Network::HTTP::Handler
end
def path(request)
- '/' + request.path.split('/')[1]
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = '/' + request.path.split('/')[1]
end
def request_key(request)
- request.path.split('/')[2]
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = request.path.split('/')[2]
end
def body(request)
@@ -38,4 +40,4 @@ class Puppet::Network::HTTP::WEBrickREST < Puppet::Network::HTTP::Handler
response.status = status
response.body = result
end
-end \ No newline at end of file
+end
diff --git a/lib/puppet/network/http_pool.rb b/lib/puppet/network/http_pool.rb
index 99f09a90c..9d37f2eeb 100644
--- a/lib/puppet/network/http_pool.rb
+++ b/lib/puppet/network/http_pool.rb
@@ -1,8 +1,20 @@
require 'puppet/sslcertificates/support'
require 'net/https'
+module Puppet::Network
+end
+
# Manage Net::HTTP instances for keep-alive.
module Puppet::Network::HttpPool
+ # 2008/03/23
+ # LAK:WARNING: Enabling this has a high propability of
+ # causing corrupt files and who knows what else. See #1010.
+ HTTP_KEEP_ALIVE = false
+
+ def self.keep_alive?
+ HTTP_KEEP_ALIVE
+ end
+
# This handles reading in the key and such-like.
extend Puppet::SSLCertificates::Support
@http_cache = {}
@@ -53,12 +65,14 @@ module Puppet::Network::HttpPool
# Return our cached instance if we've got a cache, as long as we're not
# resetting the instance.
- return @http_cache[key] if ! reset and @http_cache[key]
+ if keep_alive?
+ return @http_cache[key] if ! reset and @http_cache[key]
- # Clean up old connections if we have them.
- if http = @http_cache[key]
- @http_cache.delete(key)
- http.finish if http.started?
+ # Clean up old connections if we have them.
+ if http = @http_cache[key]
+ @http_cache.delete(key)
+ http.finish if http.started?
+ end
end
args = [host, port]
@@ -85,7 +99,7 @@ module Puppet::Network::HttpPool
cert_setup(http)
- @http_cache[key] = http
+ @http_cache[key] = http if keep_alive?
return http
end
diff --git a/lib/puppet/network/http_server/mongrel.rb b/lib/puppet/network/http_server/mongrel.rb
index d6e21b189..6b2325d29 100644
--- a/lib/puppet/network/http_server/mongrel.rb
+++ b/lib/puppet/network/http_server/mongrel.rb
@@ -33,6 +33,7 @@ require 'xmlrpc/server'
require 'puppet/network/xmlrpc/server'
require 'puppet/network/http_server'
require 'puppet/network/client_request'
+require 'puppet/network/handler'
require 'puppet/daemon'
require 'resolv'
@@ -127,7 +128,12 @@ module Puppet::Network
client = dn_matchdata[1].to_str
valid = (params[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
else
- client = Resolv.getname(ip)
+ begin
+ client = Resolv.getname(ip)
+ rescue => detail
+ Puppet.err "Could not resolve %s: %s" % [ip, detail]
+ client = "unknown"
+ end
valid = false
end
diff --git a/lib/puppet/network/http_server/webrick.rb b/lib/puppet/network/http_server/webrick.rb
index 3c9f72e17..568b4e798 100644
--- a/lib/puppet/network/http_server/webrick.rb
+++ b/lib/puppet/network/http_server/webrick.rb
@@ -8,6 +8,7 @@ require 'puppet/sslcertificates/support'
require 'puppet/network/xmlrpc/webrick_servlet'
require 'puppet/network/http_server'
require 'puppet/network/client'
+require 'puppet/network/handler'
module Puppet
class ServerError < RuntimeError; end
@@ -22,12 +23,12 @@ module Puppet
# with them, with flags appropriate for checking client
# certificates for revocation
def x509store
- if Puppet[:cacrl] == 'none'
+ if Puppet[:cacrl] == 'false'
# No CRL, no store needed
return nil
end
unless File.exist?(Puppet[:cacrl])
- raise Puppet::Error, "Could not find CRL; set 'cacrl' to 'none' to disable CRL usage"
+ raise Puppet::Error, "Could not find CRL; set 'cacrl' to 'false' to disable CRL usage"
end
crl = OpenSSL::X509::CRL.new(File.read(Puppet[:cacrl]))
store = OpenSSL::X509::Store.new
@@ -133,7 +134,7 @@ module Puppet
handlers.collect { |handler, args|
hclass = nil
- unless hclass = Handler.handler(handler)
+ unless hclass = Puppet::Network::Handler.handler(handler)
raise ServerError, "Invalid handler %s" % handler
end
hclass.new(args)
diff --git a/lib/puppet/network/server.rb b/lib/puppet/network/server.rb
index 50e3bd686..f2c8dc18c 100644
--- a/lib/puppet/network/server.rb
+++ b/lib/puppet/network/server.rb
@@ -1,3 +1,5 @@
+require 'puppet/network/http'
+
class Puppet::Network::Server
attr_reader :server_type, :protocols, :address, :port
diff --git a/lib/puppet/network/xmlrpc/client.rb b/lib/puppet/network/xmlrpc/client.rb
index 27bb3dc5e..f6a5e8db6 100644
--- a/lib/puppet/network/xmlrpc/client.rb
+++ b/lib/puppet/network/xmlrpc/client.rb
@@ -90,6 +90,13 @@ module Puppet::Network
@clients[handler] || self.mkclient(handler)
end
+ def http
+ unless @http
+ @http = Puppet::Network::HttpPool.http_instance(@host, @port, true)
+ end
+ @http
+ end
+
def initialize(hash = {})
hash[:Path] ||= "/RPC2"
hash[:Server] ||= Puppet[:server]
@@ -125,7 +132,11 @@ module Puppet::Network
end
def start
- @http.start unless @http.started?
+ begin
+ @http.start unless @http.started?
+ rescue => detail
+ Puppet.err "Could not connect to server: %s" % detail
+ end
end
def local
diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb
index c0628ecdc..252ab961e 100644
--- a/lib/puppet/node.rb
+++ b/lib/puppet/node.rb
@@ -161,5 +161,7 @@ class Puppet::Node
params.each do |name, value|
@parameters[name] = value unless @parameters.include?(name)
end
+
+ @parameters["environment"] ||= self.environment if self.environment
end
end
diff --git a/lib/puppet/node/catalog.rb b/lib/puppet/node/catalog.rb
index ff41031e1..77e845368 100644
--- a/lib/puppet/node/catalog.rb
+++ b/lib/puppet/node/catalog.rb
@@ -1,4 +1,8 @@
require 'puppet/indirector'
+require 'puppet/pgraph'
+require 'puppet/transaction'
+
+require 'puppet/util/tagging'
# This class models a node catalog. It is the thing
# meant to be passed from server to client, and it contains all
@@ -8,6 +12,8 @@ class Puppet::Node::Catalog < Puppet::PGraph
extend Puppet::Indirector
indirects :catalog, :terminus_class => :compiler
+ include Puppet::Util::Tagging
+
# The host name this is a catalog for.
attr_accessor :name
@@ -58,28 +64,32 @@ class Puppet::Node::Catalog < Puppet::PGraph
raise ArgumentError, "Can only add objects that respond to :ref"
end
+ fail_unless_unique(resource)
+
ref = resource.ref
- if @resource_table.include?(ref)
- raise ArgumentError, "Resource %s is already defined" % ref
- else
- @resource_table[ref] = resource
- end
- if resource.is_a?(Puppet::Type) and resource.class.isomorphic? and resource.title != resource.ref and resource.title != resource[:name]
- self.alias(resource, resource[:name])
+ @resource_table[ref] = resource
+
+ # If the name and title differ, set up an alias
+ #self.alias(resource, resource.name) if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.name != resource.title
+ if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.name != resource.title
+ self.alias(resource, resource.name) if resource.isomorphic?
end
- resource.catalog = self unless is_relationship_graph
- add_vertex!(resource)
+
+ resource.catalog = self if resource.respond_to?(:catalog=) and ! is_relationship_graph
+
+ add_vertex(resource)
end
end
# Create an alias for a resource.
def alias(resource, name)
+ #set $1
resource.ref =~ /^(.+)\[/
newref = "%s[%s]" % [$1 || resource.class.name, name]
- if res = @resource_table[newref]
- return if res == resource
+ if existing = @resource_table[newref]
+ return if existing == resource
raise(ArgumentError, "Cannot alias %s to %s; resource %s already exists" % [resource.ref, name, newref])
end
@resource_table[newref] = resource
@@ -275,7 +285,6 @@ class Puppet::Node::Catalog < Puppet::PGraph
super()
@name = name if name
@extraction_format ||= :transportable
- @tags = []
@classes = []
@resource_table = {}
@transient_resources = []
@@ -320,9 +329,9 @@ class Puppet::Node::Catalog < Puppet::PGraph
# First create the dependency graph
self.vertices.each do |vertex|
- @relationship_graph.add_vertex! vertex
+ @relationship_graph.add_vertex vertex
vertex.builddepends.each do |edge|
- @relationship_graph.add_edge!(edge)
+ @relationship_graph.add_edge(edge)
end
end
@@ -332,7 +341,7 @@ class Puppet::Node::Catalog < Puppet::PGraph
unless @relationship_graph.edge?(edge.source, edge.target) # don't let automatic relationships conflict with manual ones.
unless @relationship_graph.edge?(edge.target, edge.source)
vertex.debug "Autorequiring %s" % [edge.source]
- @relationship_graph.add_edge!(edge)
+ @relationship_graph.add_edge(edge)
else
vertex.debug "Skipping automatic relationship with %s" % (edge.source == vertex ? edge.target : edge.source)
end
@@ -388,25 +397,6 @@ class Puppet::Node::Catalog < Puppet::PGraph
@resource_table.keys
end
- # Add a tag.
- def tag(*names)
- names.each do |name|
- name = name.to_s
- @tags << name unless @tags.include?(name)
- if name.include?("::")
- name.split("::").each do |sub|
- @tags << sub unless @tags.include?(sub)
- end
- end
- end
- nil
- end
-
- # Return the list of tags.
- def tags
- @tags.dup
- end
-
# Convert our catalog into a RAL catalog.
def to_ral
to_catalog :to_type
@@ -454,6 +444,28 @@ class Puppet::Node::Catalog < Puppet::PGraph
end
end
+ # Verify that the given resource isn't defined elsewhere.
+ def fail_unless_unique(resource)
+ # Short-curcuit the common case,
+ return unless existing_resource = @resource_table[resource.ref]
+
+ # Either it's a defined type, which are never
+ # isomorphic, or it's a non-isomorphic type, so
+ # we should throw an exception.
+ msg = "Duplicate definition: %s is already defined" % resource.ref
+
+ if existing_resource.file and existing_resource.line
+ msg << " in file %s at line %s" %
+ [existing_resource.file, existing_resource.line]
+ end
+
+ if resource.line or resource.file
+ msg << "; cannot redefine"
+ end
+
+ raise ArgumentError.new(msg)
+ end
+
# An abstracted method for converting one catalog into another type of catalog.
# This pretty much just converts all of the resources from one class to another, using
# a conversion method.
@@ -464,6 +476,15 @@ class Puppet::Node::Catalog < Puppet::PGraph
vertices.each do |resource|
next if resource.respond_to?(:virtual?) and resource.virtual?
+ #This is hackity hack for 1094
+ #Aliases aren't working in the ral catalog because the current instance of the resource
+ #has a reference to the catalog being converted. . . So, give it a reference to the new one
+ #problem solved. . .
+ if resource.is_a?(Puppet::TransObject)
+ resource = resource.dup
+ resource.catalog = result
+ end
+
newres = resource.send(convert)
# We can't guarantee that resources don't munge their names
@@ -488,12 +509,12 @@ class Puppet::Node::Catalog < Puppet::PGraph
raise Puppet::DevError, "Could not find resource %s when converting %s resources" % [edge.target.ref, message]
end
- result.add_edge!(source, target, edge.label)
+ result.add_edge(source, target, edge.label)
end
map.clear
- result.add_class *self.classes
+ result.add_class(*self.classes)
result.tag(*self.tags)
return result
diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb
index 2a314803f..343720a62 100644
--- a/lib/puppet/node/environment.rb
+++ b/lib/puppet/node/environment.rb
@@ -4,7 +4,8 @@ class Puppet::Node::Environment
# Return the list of valid environments. Just looks them up in
# the settings.
def self.valid
- Puppet.settings.value(:environments).split(",").collect { |e| e.to_sym }
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet.settings.value(:environments).split(",").collect { |e| e.to_sym }
end
# Is the provided environment valid?
diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb
index 14b686e2f..c9bd7c9e8 100644
--- a/lib/puppet/parser/ast.rb
+++ b/lib/puppet/parser/ast.rb
@@ -14,30 +14,6 @@ class Puppet::Parser::AST
include Puppet::Util::MethodHelper
attr_accessor :line, :file, :parent, :scope
- # Just used for 'tree', which is only used in debugging.
- @@pink = ""
- @@green = ""
- @@yellow = ""
- @@slate = ""
- @@reset = ""
-
- # Just used for 'tree', which is only used in debugging.
- @@indent = " " * 4
- @@indline = @@pink + ("-" * 4) + @@reset
- @@midline = @@slate + ("-" * 4) + @@reset
-
- @@settypes = {}
-
- # Just used for 'tree', which is only used in debugging.
- def AST.indention
- return @@indent * @@indention
- end
-
- # Just used for 'tree', which is only used in debugging.
- def AST.midline
- return @@midline
- end
-
# Does this ast object set something? If so, it gets evaluated first.
def self.settor?
if defined? @settor
@@ -47,16 +23,12 @@ class Puppet::Parser::AST
end
end
- # Evaluate the current object. Basically just iterates across all
+ # Evaluate the current object. Just a stub method, since the subclass
+ # should override this method.
# of the contained children and evaluates them in turn, returning a
# list of all of the collected values, rejecting nil values
- def evaluate(args)
- #Puppet.debug("Evaluating ast %s" % @name)
- value = self.collect { |obj|
- obj.safeevaluate(args)
- }.reject { |obj|
- obj.nil?
- }
+ def evaluate(*options)
+ raise Puppet::DevError, "Did not override #evaluate in %s" % self.class
end
# Throw a parse error.
@@ -75,11 +47,11 @@ class Puppet::Parser::AST
# correctly handles errors. It is critical to use this method because
# it can enable you to catch the error where it happens, rather than
# much higher up the stack.
- def safeevaluate(options)
+ def safeevaluate(*options)
# We duplicate code here, rather than using exceptwrap, because this
# is called so many times during parsing.
begin
- return self.evaluate(options)
+ return self.evaluate(*options)
rescue Puppet::Error => detail
raise adderrorcontext(detail)
rescue => detail
@@ -90,14 +62,6 @@ class Puppet::Parser::AST
end
end
- # Again, just used for printing out the parse tree.
- def typewrap(string)
- #return self.class.to_s.sub(/.+::/,'') +
- #"(" + @@green + string.to_s + @@reset + ")"
- return @@green + string.to_s + @@reset +
- "(" + self.class.to_s.sub(/.+::/,'') + ")"
- end
-
# Initialize the object. Requires a hash as the argument, and
# takes each of the parameters of the hash and calls the settor
# method for them. This is probably pretty inefficient and should
@@ -107,13 +71,27 @@ class Puppet::Parser::AST
@line = nil
set_options(args)
end
- #---------------------------------------------------------------
- # Now autoload everything.
- @autoloader = Puppet::Util::Autoload.new(self,
- "puppet/parser/ast"
- )
- @autoloader.loadall
end
+# And include all of the AST subclasses.
+require 'puppet/parser/ast/astarray'
+require 'puppet/parser/ast/branch'
+require 'puppet/parser/ast/caseopt'
+require 'puppet/parser/ast/casestatement'
+require 'puppet/parser/ast/collection'
+require 'puppet/parser/ast/collexpr'
+require 'puppet/parser/ast/definition'
+require 'puppet/parser/ast/else'
+require 'puppet/parser/ast/function'
+require 'puppet/parser/ast/hostclass'
+require 'puppet/parser/ast/ifstatement'
require 'puppet/parser/ast/leaf'
-
+require 'puppet/parser/ast/node'
+require 'puppet/parser/ast/resource'
+require 'puppet/parser/ast/resource_defaults'
+require 'puppet/parser/ast/resource_override'
+require 'puppet/parser/ast/resource_reference'
+require 'puppet/parser/ast/resourceparam'
+require 'puppet/parser/ast/selector'
+require 'puppet/parser/ast/tag'
+require 'puppet/parser/ast/vardef'
diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb
index 5f1e838d0..8f09aa922 100644
--- a/lib/puppet/parser/ast/astarray.rb
+++ b/lib/puppet/parser/ast/astarray.rb
@@ -15,18 +15,7 @@ class Puppet::Parser::AST
end
# Evaluate our children.
- def evaluate(hash)
- scope = hash[:scope]
- rets = nil
- # We basically always operate declaratively, and when we
- # do we need to evaluate the settor-like statements first. This
- # is basically variable and type-default declarations.
- # This is such a stupid hack. I've no real idea how to make a
- # "real" declarative language, so I hack it so it looks like
- # one, yay.
- settors = []
- others = []
-
+ def evaluate(scope)
# Make a new array, so we don't have to deal with the details of
# flattening and such
items = []
@@ -35,23 +24,15 @@ class Puppet::Parser::AST
@children.each { |child|
if child.instance_of?(AST::ASTArray)
child.each do |ac|
- if ac.class.settor?
- settors << ac
- else
- others << ac
- end
+ items << ac
end
else
- if child.class.settor?
- settors << child
- else
- others << child
- end
+ items << child
end
}
- rets = [settors, others].flatten.collect { |child|
- child.safeevaluate(:scope => scope)
+ rets = items.flatten.collect { |child|
+ child.safeevaluate(scope)
}
return rets.reject { |o| o.nil? }
end
diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb
index d1d9d0e9c..824bde853 100644
--- a/lib/puppet/parser/ast/caseopt.rb
+++ b/lib/puppet/parser/ast/caseopt.rb
@@ -44,17 +44,17 @@ class Puppet::Parser::AST
def eachvalue(scope)
if @value.is_a?(AST::ASTArray)
@value.each { |subval|
- yield subval.evaluate(:scope => scope)
+ yield subval.safeevaluate(scope)
}
else
- yield @value.evaluate(:scope => scope)
+ yield @value.safeevaluate(scope)
end
end
# Evaluate the actual statements; this only gets called if
# our option matched.
- def evaluate(hash)
- return @statements.safeevaluate(hash)
+ def evaluate(scope)
+ return @statements.safeevaluate(scope)
end
end
end
diff --git a/lib/puppet/parser/ast/casestatement.rb b/lib/puppet/parser/ast/casestatement.rb
index 3c6f9c7e2..aa03090de 100644
--- a/lib/puppet/parser/ast/casestatement.rb
+++ b/lib/puppet/parser/ast/casestatement.rb
@@ -8,9 +8,8 @@ class Puppet::Parser::AST
# Short-curcuit evaluation. Return the value of the statements for
# the first option that matches.
- def evaluate(hash)
- scope = hash[:scope]
- value = @test.safeevaluate(:scope => scope)
+ def evaluate(scope)
+ value = @test.safeevaluate(scope)
sensitive = Puppet[:casesensitive]
value = value.downcase if ! sensitive and value.respond_to?(:downcase)
@@ -30,7 +29,7 @@ class Puppet::Parser::AST
if found
# we found a matching option
- retvalue = option.safeevaluate(:scope => scope)
+ retvalue = option.safeevaluate(scope)
break
end
@@ -42,7 +41,7 @@ class Puppet::Parser::AST
# Unless we found something, look for the default.
unless found
if default
- retvalue = default.safeevaluate(:scope => scope)
+ retvalue = default.safeevaluate(scope)
else
Puppet.debug "No true answers and no default"
retvalue = nil
diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb
index e05977a47..9e795a33c 100644
--- a/lib/puppet/parser/ast/collection.rb
+++ b/lib/puppet/parser/ast/collection.rb
@@ -9,18 +9,16 @@ class Collection < AST::Branch
attr_accessor :type, :query, :form
# We return an object that does a late-binding evaluation.
- def evaluate(hash)
- scope = hash[:scope]
-
+ def evaluate(scope)
if self.query
- str, code = self.query.safeevaluate :scope => scope
+ str, code = self.query.safeevaluate scope
else
str = code = nil
end
newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form)
- scope.compile.add_collection(newcoll)
+ scope.compiler.add_collection(newcoll)
newcoll
end
diff --git a/lib/puppet/parser/ast/collexpr.rb b/lib/puppet/parser/ast/collexpr.rb
index 4a96d9c61..3e13d9400 100644
--- a/lib/puppet/parser/ast/collexpr.rb
+++ b/lib/puppet/parser/ast/collexpr.rb
@@ -9,9 +9,7 @@ class CollExpr < AST::Branch
attr_accessor :test1, :test2, :oper, :form, :type, :parens
# We return an object that does a late-binding evaluation.
- def evaluate(hash)
- scope = hash[:scope]
-
+ def evaluate(scope)
# Make sure our contained expressions have all the info they need.
[@test1, @test2].each do |t|
if t.is_a?(self.class)
@@ -21,8 +19,8 @@ class CollExpr < AST::Branch
end
# The code is only used for virtual lookups
- str1, code1 = @test1.safeevaluate :scope => scope
- str2, code2 = @test2.safeevaluate :scope => scope
+ str1, code1 = @test1.safeevaluate scope
+ str2, code2 = @test2.safeevaluate scope
# First build up the virtual code.
# If we're a conjunction operator, then we're calling code. I did
diff --git a/lib/puppet/parser/ast/definition.rb b/lib/puppet/parser/ast/definition.rb
index 3d6d6188c..0c65c702c 100644
--- a/lib/puppet/parser/ast/definition.rb
+++ b/lib/puppet/parser/ast/definition.rb
@@ -1,155 +1,145 @@
require 'puppet/parser/ast/branch'
-class Puppet::Parser::AST
- # Evaluate the stored parse tree for a given component. This will
- # receive the arguments passed to the component and also the type and
- # name of the component.
- class Definition < AST::Branch
- include Puppet::Util
- include Puppet::Util::Warnings
- include Puppet::Util::MethodHelper
- class << self
- attr_accessor :name
- end
+require 'puppet/util/warnings'
- # The class name
- @name = :definition
+# The AST class for defined types, which is also the base class
+# nodes and classes.
+class Puppet::Parser::AST::Definition < Puppet::Parser::AST::Branch
+ include Puppet::Util::Warnings
+ class << self
+ attr_accessor :name
+ end
- attr_accessor :classname, :arguments, :code, :scope, :keyword
- attr_accessor :exported, :namespace, :parser, :virtual
+ # The class name
+ @name = :definition
- # These are retrieved when looking up the superclass
- attr_accessor :name
+ attr_accessor :classname, :arguments, :code, :scope, :keyword
+ attr_accessor :exported, :namespace, :parser, :virtual, :name
- attr_reader :parentclass
+ attr_reader :parentclass
- def child_of?(klass)
- false
- end
+ def child_of?(klass)
+ false
+ end
- def evaluate(options)
- origscope = options[:scope]
- resource = options[:resource]
+ # Create a resource that knows how to evaluate our actual code.
+ def evaluate(scope)
+ resource = Puppet::Parser::Resource.new(:type => self.class.name, :title => self.classname, :scope => scope, :source => scope.source)
- # Create a new scope.
- scope = subscope(origscope, resource)
+ scope.catalog.tag(*resource.tags)
- # Additionally, add a tag for whatever kind of class
- # we are
- if @classname != "" and ! @classname.nil?
- @classname.split(/::/).each { |tag| scope.resource.tag(tag) }
- end
+ scope.compiler.add_resource(scope, resource)
- [resource.name, resource.title].each do |str|
- unless str.nil? or str =~ /[^\w]/ or str == ""
- scope.resource.tag(str)
- end
- end
+ return resource
+ end
- set_resource_parameters(scope, resource)
+ # Now evaluate the code associated with this class or definition.
+ def evaluate_code(resource)
+ # Create a new scope.
+ scope = subscope(resource.scope, resource)
- if self.code
- return self.code.safeevaluate(:scope => scope)
- else
- return nil
- end
+ set_resource_parameters(scope, resource)
+
+ if self.code
+ return self.code.safeevaluate(scope)
+ else
+ return nil
end
+ end
- def initialize(hash = {})
- @arguments = nil
- @parentclass = nil
- super
+ def initialize(hash = {})
+ @arguments = nil
+ @parentclass = nil
+ super
- # Convert the arguments to a hash for ease of later use.
- if @arguments
- unless @arguments.is_a? Array
- @arguments = [@arguments]
- end
- oldargs = @arguments
- @arguments = {}
- oldargs.each do |arg, val|
- @arguments[arg] = val
- end
- else
- @arguments = {}
+ # Convert the arguments to a hash for ease of later use.
+ if @arguments
+ unless @arguments.is_a? Array
+ @arguments = [@arguments]
end
-
- # Deal with metaparams in the argument list.
- @arguments.each do |arg, defvalue|
- next unless Puppet::Type.metaparamclass(arg)
- if defvalue
- warnonce "%s is a metaparam; this value will inherit to all contained resources" % arg
- else
- raise Puppet::ParseError, "%s is a metaparameter; please choose another parameter name in the %s definition" % [arg, self.classname]
- end
+ oldargs = @arguments
+ @arguments = {}
+ oldargs.each do |arg, val|
+ @arguments[arg] = val
end
+ else
+ @arguments = {}
end
- def find_parentclass
- @parser.findclass(namespace, parentclass)
+ # Deal with metaparams in the argument list.
+ @arguments.each do |arg, defvalue|
+ next unless Puppet::Type.metaparamclass(arg)
+ if defvalue
+ warnonce "%s is a metaparam; this value will inherit to all contained resources" % arg
+ else
+ raise Puppet::ParseError, "%s is a metaparameter; please choose another parameter name in the %s definition" % [arg, self.classname]
+ end
end
+ end
- # Set our parent class, with a little check to avoid some potential
- # weirdness.
- def parentclass=(name)
- if name == self.classname
- parsefail "Parent classes must have dissimilar names"
- end
+ def find_parentclass
+ @parser.findclass(namespace, parentclass)
+ end
- @parentclass = name
+ # Set our parent class, with a little check to avoid some potential
+ # weirdness.
+ def parentclass=(name)
+ if name == self.classname
+ parsefail "Parent classes must have dissimilar names"
end
- # Hunt down our class object.
- def parentobj
- if @parentclass
- # Cache our result, since it should never change.
- unless defined?(@parentobj)
- unless tmp = find_parentclass
- parsefail "Could not find %s %s" % [self.class.name, @parentclass]
- end
+ @parentclass = name
+ end
- if tmp == self
- parsefail "Parent classes must have dissimilar names"
- end
+ # Hunt down our class object.
+ def parentobj
+ return nil unless @parentclass
- @parentobj = tmp
- end
- @parentobj
- else
- nil
+ # Cache our result, since it should never change.
+ unless defined?(@parentobj)
+ unless tmp = find_parentclass
+ parsefail "Could not find %s parent %s" % [self.class.name, @parentclass]
end
+
+ if tmp == self
+ parsefail "Parent classes must have dissimilar names"
+ end
+
+ @parentobj = tmp
end
+ @parentobj
+ end
- # Create a new subscope in which to evaluate our code.
- def subscope(scope, resource)
- args = {
- :resource => resource,
- :keyword => self.keyword,
- :namespace => self.namespace,
- :source => self
- }
+ # Create a new subscope in which to evaluate our code.
+ def subscope(scope, resource)
+ args = {
+ :resource => resource,
+ :keyword => self.keyword,
+ :namespace => self.namespace,
+ :source => self
+ }
- oldscope = scope
- scope = scope.newscope(args)
- scope.source = self
+ oldscope = scope
+ scope = scope.newscope(args)
+ scope.source = self
- return scope
- end
+ return scope
+ end
- def to_s
- classname
- end
+ def to_s
+ classname
+ end
- # Check whether a given argument is valid. Searches up through
- # any parent classes that might exist.
- def validattr?(param)
- param = param.to_s
+ # Check whether a given argument is valid. Searches up through
+ # any parent classes that might exist.
+ def validattr?(param)
+ param = param.to_s
- if @arguments.include?(param)
- # It's a valid arg for us
- return true
- elsif param == "name"
- return true
+ if @arguments.include?(param)
+ # It's a valid arg for us
+ return true
+ elsif param == "name"
+ return true
# elsif defined? @parentclass and @parentclass
# # Else, check any existing parent
# if parent = @scope.lookuptype(@parentclass) and parent != []
@@ -160,53 +150,52 @@ class Puppet::Parser::AST
# raise Puppet::Error, "Could not find parent class %s" %
# @parentclass
# end
- elsif Puppet::Type.metaparam?(param)
- return true
- else
- # Or just return false
- return false
- end
+ elsif Puppet::Type.metaparam?(param)
+ return true
+ else
+ # Or just return false
+ return false
end
+ end
- private
-
- # Set any arguments passed by the resource as variables in the scope.
- def set_resource_parameters(scope, resource)
- args = symbolize_options(resource.to_hash || {})
-
- # Verify that all required arguments are either present or
- # have been provided with defaults.
- if self.arguments
- self.arguments.each { |arg, default|
- arg = symbolize(arg)
- unless args.include?(arg)
- if defined? default and ! default.nil?
- default = default.safeevaluate :scope => scope
- args[arg] = default
- #Puppet.debug "Got default %s for %s in %s" %
- # [default.inspect, arg.inspect, @name.inspect]
- else
- parsefail "Must pass %s to %s of type %s" %
- [arg, resource.title, @classname]
- end
+ private
+
+ # Set any arguments passed by the resource as variables in the scope.
+ def set_resource_parameters(scope, resource)
+ args = symbolize_options(resource.to_hash || {})
+
+ # Verify that all required arguments are either present or
+ # have been provided with defaults.
+ if self.arguments
+ self.arguments.each { |arg, default|
+ arg = arg.to_sym
+ unless args.include?(arg)
+ if defined? default and ! default.nil?
+ default = default.safeevaluate scope
+ args[arg] = default
+ #Puppet.debug "Got default %s for %s in %s" %
+ # [default.inspect, arg.inspect, @name.inspect]
+ else
+ parsefail "Must pass %s to %s of type %s" %
+ [arg, resource.title, @classname]
end
- }
- end
-
- # Set each of the provided arguments as variables in the
- # definition's scope.
- args.each { |arg,value|
- unless validattr?(arg)
- parsefail "%s does not accept attribute %s" % [@classname, arg]
- end
-
- exceptwrap do
- scope.setvar(arg.to_s, args[arg])
end
}
-
- scope.setvar("title", resource.title) unless args.include? :title
- scope.setvar("name", resource.name) unless args.include? :name
end
+
+ # Set each of the provided arguments as variables in the
+ # definition's scope.
+ args.each { |arg,value|
+ unless validattr?(arg)
+ parsefail "%s does not accept attribute %s" % [@classname, arg]
+ end
+
+ exceptwrap do
+ scope.setvar(arg.to_s, args[arg])
+ end
+ }
+
+ scope.setvar("title", resource.title) unless args.include? :title
+ scope.setvar("name", resource.name) unless args.include? :name
end
end
diff --git a/lib/puppet/parser/ast/else.rb b/lib/puppet/parser/ast/else.rb
index e76051372..affac625d 100644
--- a/lib/puppet/parser/ast/else.rb
+++ b/lib/puppet/parser/ast/else.rb
@@ -12,9 +12,8 @@ class Puppet::Parser::AST
# Evaluate the actual statements; this only gets called if
# our test was true matched.
- def evaluate(hash)
- scope = hash[:scope]
- return @statements.safeevaluate(:scope => scope)
+ def evaluate(scope)
+ return @statements.safeevaluate(scope)
end
end
end
diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb
index 0cd1fff62..63d7c7abf 100644
--- a/lib/puppet/parser/ast/function.rb
+++ b/lib/puppet/parser/ast/function.rb
@@ -7,18 +7,11 @@ class Puppet::Parser::AST
@settor = true
- def evaluate(hash)
+ def evaluate(scope)
# We don't need to evaluate the name, because it's plaintext
+ args = @arguments.safeevaluate(scope)
- # Just evaluate the arguments
- scope = hash[:scope]
-
- args = @arguments.safeevaluate(:scope => scope)
-
- #exceptwrap :message => "Failed to execute %s" % @name,
- # :type => Puppet::ParseError do
- return scope.send("function_" + @name, args)
- #end
+ return scope.send("function_" + @name, args)
end
def initialize(hash)
diff --git a/lib/puppet/parser/ast/hostclass.rb b/lib/puppet/parser/ast/hostclass.rb
index 63900d0e3..7f89f8151 100644
--- a/lib/puppet/parser/ast/hostclass.rb
+++ b/lib/puppet/parser/ast/hostclass.rb
@@ -1,80 +1,87 @@
require 'puppet/parser/ast/definition'
-class Puppet::Parser::AST
- # The code associated with a class. This is different from definitions
- # in that each class is a singleton -- only one will exist for a given
- # node.
- class HostClass < AST::Definition
- @name = :class
+# The code associated with a class. This is different from definitions
+# in that each class is a singleton -- only one will exist for a given
+# node.
+class Puppet::Parser::AST::HostClass < Puppet::Parser::AST::Definition
+ @name = :class
- # Are we a child of the passed class? Do a recursive search up our
- # parentage tree to figure it out.
- def child_of?(klass)
- return false unless self.parentclass
+ # Are we a child of the passed class? Do a recursive search up our
+ # parentage tree to figure it out.
+ def child_of?(klass)
+ return false unless self.parentclass
- if klass == self.parentobj
- return true
- else
- return self.parentobj.child_of?(klass)
- end
+ if klass == self.parentobj
+ return true
+ else
+ return self.parentobj.child_of?(klass)
end
+ end
- # Evaluate the code associated with this class.
- def evaluate(options)
- scope = options[:scope]
- raise(ArgumentError, "Classes require resources") unless options[:resource]
- # Verify that we haven't already been evaluated. This is
- # what provides the singleton aspect.
- if existing_scope = scope.compile.class_scope(self)
- Puppet.debug "Class '%s' already evaluated; not evaluating again" % (classname == "" ? "main" : classname)
- return nil
- end
+ # Make sure our parent class has been evaluated, if we have one.
+ def evaluate(scope)
+ if parentclass and ! scope.catalog.resource(self.class.name, parentclass)
+ parent_resource = parentobj.evaluate(scope)
+ end
- scope.compile.catalog.tag(self.classname)
+ # Do nothing if the resource already exists; this makes sure we don't
+ # get multiple copies of the class resource, which helps provide the
+ # singleton nature of classes.
+ if resource = scope.catalog.resource(self.class.name, self.classname)
+ return resource
+ end
- pnames = nil
- if pklass = self.parentobj
- pklass.safeevaluate :scope => scope, :resource => options[:resource]
+ super
+ end
- scope = parent_scope(scope, pklass)
- pnames = scope.namespaces
- end
+ # Evaluate the code associated with this class.
+ def evaluate_code(resource)
+ scope = resource.scope
+ # Verify that we haven't already been evaluated. This is
+ # what provides the singleton aspect.
+ if existing_scope = scope.compiler.class_scope(self)
+ Puppet.debug "Class '%s' already evaluated; not evaluating again" % (classname == "" ? "main" : classname)
+ return nil
+ end
- # Don't create a subscope for the top-level class, since it already
- # has its own scope.
- unless options[:resource].title == :main
- scope = subscope(scope, options[:resource])
- end
+ pnames = nil
+ if pklass = self.parentobj
+ parent_resource = resource.scope.compiler.catalog.resource(self.class.name, pklass.classname)
+ # This shouldn't evaluate if the class has already been evaluated.
+ pklass.evaluate_code(parent_resource)
- if pnames
- pnames.each do |ns|
- scope.add_namespace(ns)
- end
- end
+ scope = parent_scope(scope, pklass)
+ pnames = scope.namespaces
+ end
- # Set the class before we do anything else, so that it's set
- # during the evaluation and can be inspected.
- scope.compile.class_set(self.classname, scope)
+ # Don't create a subscope for the top-level class, since it already
+ # has its own scope.
+ scope = subscope(scope, resource) unless resource.title == :main
- # Now evaluate our code, yo.
- if self.code
- return self.code.evaluate(:scope => scope)
- else
- return nil
+ # Add the parent scope namespaces to our own.
+ if pnames
+ pnames.each do |ns|
+ scope.add_namespace(ns)
end
end
- def initialize(options)
- @parentclass = nil
- super
+ # Set the class before we evaluate the code, so that it's set during
+ # the evaluation and can be inspected.
+ scope.compiler.class_set(self.classname, scope)
+
+ # Now evaluate our code, yo.
+ if self.code
+ return self.code.safeevaluate(scope)
+ else
+ return nil
end
+ end
- def parent_scope(scope, klass)
- if s = scope.compile.class_scope(klass)
- return s
- else
- raise Puppet::DevError, "Could not find scope for %s" % klass.classname
- end
+ def parent_scope(scope, klass)
+ if s = scope.compiler.class_scope(klass)
+ return s
+ else
+ raise Puppet::DevError, "Could not find scope for %s" % klass.classname
end
end
end
diff --git a/lib/puppet/parser/ast/ifstatement.rb b/lib/puppet/parser/ast/ifstatement.rb
index 66a07b01f..afa2cd572 100644
--- a/lib/puppet/parser/ast/ifstatement.rb
+++ b/lib/puppet/parser/ast/ifstatement.rb
@@ -12,15 +12,14 @@ class Puppet::Parser::AST
# Short-curcuit evaluation. If we're true, evaluate our statements,
# else if there's an 'else' setting, evaluate it.
# the first option that matches.
- def evaluate(hash)
- scope = hash[:scope]
- value = @test.safeevaluate(:scope => scope)
+ def evaluate(scope)
+ value = @test.safeevaluate(scope)
if Puppet::Parser::Scope.true?(value)
- return @statements.safeevaluate(:scope => scope)
+ return @statements.safeevaluate(scope)
else
if defined? @else
- return @else.safeevaluate(:scope => scope)
+ return @else.safeevaluate(scope)
else
return nil
end
diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb
index 225253061..c545c1e47 100644
--- a/lib/puppet/parser/ast/leaf.rb
+++ b/lib/puppet/parser/ast/leaf.rb
@@ -6,7 +6,7 @@ class Puppet::Parser::AST
attr_accessor :value, :type
# Return our value.
- def evaluate(hash)
+ def evaluate(scope)
return @value
end
@@ -35,14 +35,14 @@ class Puppet::Parser::AST
class String < AST::Leaf
# Interpolate the string looking for variables, and then return
# the result.
- def evaluate(hash)
- return hash[:scope].strinterp(@value, @file, @line)
+ def evaluate(scope)
+ return scope.strinterp(@value, @file, @line)
end
end
# An uninterpreted string.
class FlatString < AST::Leaf
- def evaluate(hash)
+ def evaluate(scope)
return @value
end
end
@@ -81,9 +81,9 @@ class Puppet::Parser::AST
class Variable < Name
# Looks up the value of the object in the scope tree (does
# not include syntactical constructs, like '$' and '{}').
- def evaluate(hash)
+ def evaluate(scope)
parsewrap do
- return hash[:scope].lookupvar(@value)
+ return scope.lookupvar(@value)
end
end
end
diff --git a/lib/puppet/parser/ast/node.rb b/lib/puppet/parser/ast/node.rb
index a296e43ba..2bf6c1882 100644
--- a/lib/puppet/parser/ast/node.rb
+++ b/lib/puppet/parser/ast/node.rb
@@ -1,67 +1,35 @@
require 'puppet/parser/ast/hostclass'
-class Puppet::Parser::AST
- # The specific code associated with a host. Nodes are annoyingly unlike
- # other objects. That's just the way it is, at least for now.
- class Node < AST::HostClass
- @name = :node
- attr_accessor :name
-
- def evaluate(options)
- scope = options[:scope]
-
- #pscope = if ! Puppet[:lexical] or options[:asparent]
- # @scope
- #else
- # origscope
- #end
-
- # We don't have to worry about the declarativeness of node parentage,
- # because the entry point is always a single node definition.
- if parent = self.parentobj
- scope = parent.safeevaluate :scope => scope, :resource => options[:resource]
- end
-
- scope = scope.newscope(
- :resource => options[:resource],
- :keyword => @keyword,
- :source => self,
- :namespace => "" # nodes are always in ""
- )
-
- # Mark our node name as a class, too, but strip it of the domain
- # name. Make the mark before we evaluate the code, so that it is
- # marked within the code itself.
- scope.compile.class_set(self.classname, scope)
-
- # And then evaluate our code if we have any
- if self.code
- @code.safeevaluate(:scope => scope)
- end
-
- return scope
+# The specific code associated with a host. Nodes are annoyingly unlike
+# other objects. That's just the way it is, at least for now.
+class Puppet::Parser::AST::Node < Puppet::Parser::AST::HostClass
+ @name = :node
+
+ def initialize(options)
+ @parentclass = nil
+ super
+
+ # Do some validation on the node name
+ if @name =~ /[^-\w.]/
+ raise Puppet::ParseError, "Invalid node name %s" % @name
end
+ end
- def initialize(options)
- @parentclass = nil
- super
+ def namespace
+ ""
+ end
- # Do some validation on the node name
- if @name =~ /[^-\w.]/
- raise Puppet::ParseError, "Invalid node name %s" % @name
- end
- end
+ # Make sure node scopes are marked as such.
+ def subscope(*args)
+ scope = super
+ scope.nodescope = true
+ scope
+ end
- # Make sure node scopes are marked as such.
- def subscope(*args)
- scope = super
- scope.nodescope = true
- end
+ private
- private
- # Search for the object matching our parent class.
- def find_parentclass
- @parser.findnode(parentclass)
- end
+ # Search for the object matching our parent class.
+ def find_parentclass
+ @parser.findnode(parentclass)
end
end
diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb
index c53ab0a68..8a60522a3 100644
--- a/lib/puppet/parser/ast/resource.rb
+++ b/lib/puppet/parser/ast/resource.rb
@@ -9,15 +9,13 @@ class Resource < AST::ResourceReference
# Does not actually return an object; instead sets an object
# in the current scope.
- def evaluate(options)
- scope = options[:scope]
-
+ def evaluate(scope)
# Evaluate all of the specified params.
paramobjects = @params.collect { |param|
- param.safeevaluate(:scope => scope)
+ param.safeevaluate(scope)
}
- objtitles = @title.safeevaluate(:scope => scope)
+ objtitles = @title.safeevaluate(scope)
# it's easier to always use an array, even for only one name
unless objtitles.is_a?(Array)
@@ -50,10 +48,10 @@ class Resource < AST::ResourceReference
:scope => scope
)
- # And then store the resource in the compile.
+ # And then store the resource in the compiler.
# At some point, we need to switch all of this to return
# objects instead of storing them like this.
- scope.compile.store_resource(scope, obj)
+ scope.compiler.add_resource(scope, obj)
obj
end
}.reject { |obj| obj.nil? }
diff --git a/lib/puppet/parser/ast/resource_defaults.rb b/lib/puppet/parser/ast/resource_defaults.rb
index 8f9c1b8df..4856f0594 100644
--- a/lib/puppet/parser/ast/resource_defaults.rb
+++ b/lib/puppet/parser/ast/resource_defaults.rb
@@ -8,13 +8,11 @@ class Puppet::Parser::AST
# As opposed to ResourceDef, this stores each default for the given
# object type.
- def evaluate(hash)
- scope = hash[:scope]
-
+ def evaluate(scope)
# Use a resource reference to canonize the type
ref = Puppet::ResourceReference.new(@type, "whatever")
type = ref.type
- params = @params.safeevaluate(:scope => scope)
+ params = @params.safeevaluate(scope)
parsewrap do
scope.setdefaults(type, params)
diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb
index 46c930902..f9464acda 100644
--- a/lib/puppet/parser/ast/resource_override.rb
+++ b/lib/puppet/parser/ast/resource_override.rb
@@ -17,17 +17,15 @@ class Puppet::Parser::AST
# Does not actually return an object; instead sets an object
# in the current scope.
- def evaluate(hash)
- scope = hash[:scope]
-
+ def evaluate(scope)
# Get our object reference.
- object = @object.safeevaluate(:scope => scope)
+ object = @object.safeevaluate(scope)
hash = {}
# Evaluate all of the specified params.
params = @params.collect { |param|
- param.safeevaluate(:scope => scope)
+ param.safeevaluate(scope)
}
# Now we just create a normal resource, but we call a very different
@@ -44,7 +42,7 @@ class Puppet::Parser::AST
# Now we tell the scope that it's an override, and it behaves as
# necessary.
- scope.compile.store_override(obj)
+ scope.compiler.add_override(obj)
obj
end
diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb
index b06ea17be..4bb41165a 100644
--- a/lib/puppet/parser/ast/resource_reference.rb
+++ b/lib/puppet/parser/ast/resource_reference.rb
@@ -22,10 +22,8 @@ class Puppet::Parser::AST
# Evaluate our object, but just return a simple array of the type
# and name.
- def evaluate(hash)
- scope = hash[:scope]
-
- title = @title.safeevaluate(:scope => scope)
+ def evaluate(scope)
+ title = @title.safeevaluate(scope)
if @type.to_s.downcase == "class"
objtype = "class"
title = qualified_class(scope, title)
diff --git a/lib/puppet/parser/ast/resourceparam.rb b/lib/puppet/parser/ast/resourceparam.rb
index 8b1e7b367..c552a7ee5 100644
--- a/lib/puppet/parser/ast/resourceparam.rb
+++ b/lib/puppet/parser/ast/resourceparam.rb
@@ -10,12 +10,10 @@ class Puppet::Parser::AST
end
# Return the parameter and the value.
- def evaluate(hash)
- scope = hash[:scope]
-
+ def evaluate(scope)
return Puppet::Parser::Resource::Param.new(
:name => @param,
- :value => @value.safeevaluate(:scope => scope),
+ :value => @value.safeevaluate(scope),
:source => scope.source, :line => self.line, :file => self.file,
:add => self.add
)
diff --git a/lib/puppet/parser/ast/selector.rb b/lib/puppet/parser/ast/selector.rb
index d363ab7e4..399d405a3 100644
--- a/lib/puppet/parser/ast/selector.rb
+++ b/lib/puppet/parser/ast/selector.rb
@@ -11,13 +11,12 @@ class Puppet::Parser::AST
end
# Find the value that corresponds with the test.
- def evaluate(hash)
- scope = hash[:scope]
+ def evaluate(scope)
retvalue = nil
found = nil
# Get our parameter.
- paramvalue = @param.safeevaluate(:scope => scope)
+ paramvalue = @param.safeevaluate(scope)
sensitive = Puppet[:casesensitive]
@@ -33,13 +32,13 @@ class Puppet::Parser::AST
# Then look for a match in the options.
@values.each { |obj|
- param = obj.param.safeevaluate(:scope => scope)
+ param = obj.param.safeevaluate(scope)
if ! sensitive && param.respond_to?(:downcase)
param = param.downcase
end
if param == paramvalue
# we found a matching option
- retvalue = obj.value.safeevaluate(:scope => scope)
+ retvalue = obj.value.safeevaluate(scope)
found = true
break
elsif obj.param.is_a?(Default)
@@ -51,7 +50,7 @@ class Puppet::Parser::AST
# Unless we found something, look for the default.
unless found
if default
- retvalue = default.value.safeevaluate(:scope => scope)
+ retvalue = default.value.safeevaluate(scope)
else
self.fail Puppet::ParseError,
"No matching value for selector param '%s'" % paramvalue
diff --git a/lib/puppet/parser/ast/tag.rb b/lib/puppet/parser/ast/tag.rb
index e2882d2f0..2909504a7 100644
--- a/lib/puppet/parser/ast/tag.rb
+++ b/lib/puppet/parser/ast/tag.rb
@@ -8,10 +8,8 @@ class Puppet::Parser::AST
@name = :class
attr_accessor :type
- def evaluate(hash)
- scope = hash[:scope]
-
- types = @type.safeevaluate(:scope => scope)
+ def evaluate(scope)
+ types = @type.safeevaluate(scope)
types = [types] unless types.is_a? Array
diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb
index 1e7f874bc..ee79159d7 100644
--- a/lib/puppet/parser/ast/vardef.rb
+++ b/lib/puppet/parser/ast/vardef.rb
@@ -9,10 +9,9 @@ class Puppet::Parser::AST
# Look up our name and value, and store them appropriately. The
# lexer strips off the syntax stuff like '$'.
- def evaluate(hash)
- scope = hash[:scope]
- name = @name.safeevaluate(:scope => scope)
- value = @value.safeevaluate(:scope => scope)
+ def evaluate(scope)
+ name = @name.safeevaluate(scope)
+ value = @value.safeevaluate(scope)
parsewrap do
scope.setvar(name,value, @file, @line)
diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb
index b8165a84f..2699dc6e1 100644
--- a/lib/puppet/parser/collector.rb
+++ b/lib/puppet/parser/collector.rb
@@ -51,7 +51,7 @@ class Puppet::Parser::Collector
search = "(exported=? AND restype=?)"
values = [true, @type]
- search += " AND (?)" and values << @equery if @equery
+ search += " AND (%s)" % @equery if @equery
# We're going to collect objects from rails, but we don't want any
# objects from this host.
@@ -118,20 +118,20 @@ class Puppet::Parser::Collector
# If there are no more resources to find, delete this from the list
# of collections.
if @resources.empty?
- @scope.compile.delete_collection(self)
+ @scope.compiler.delete_collection(self)
end
return result
end
- # Collect just virtual objects, from our local compile.
+ # Collect just virtual objects, from our local compiler.
def collect_virtual(exported = false)
if exported
method = :exported?
else
method = :virtual?
end
- scope.compile.resources.find_all do |resource|
+ scope.compiler.resources.find_all do |resource|
resource.type == @type and resource.send(method) and match?(resource)
end
end
@@ -150,7 +150,7 @@ class Puppet::Parser::Collector
resource.exported = false
- scope.compile.store_resource(scope, resource)
+ scope.compiler.add_resource(scope, resource)
return resource
end
diff --git a/lib/puppet/parser/compile.rb b/lib/puppet/parser/compiler.rb
index f76103a28..8fba41121 100644
--- a/lib/puppet/parser/compile.rb
+++ b/lib/puppet/parser/compiler.rb
@@ -7,7 +7,7 @@ require 'puppet/util/errors'
# Maintain a graph of scopes, along with a bunch of data
# about the individual catalog we're compiling.
-class Puppet::Parser::Compile
+class Puppet::Parser::Compiler
include Puppet::Util
include Puppet::Util::Errors
attr_reader :parser, :node, :facts, :collections, :catalog, :node_scope
@@ -17,6 +17,29 @@ class Puppet::Parser::Compile
@collections << coll
end
+ # Store a resource override.
+ def add_override(override)
+ # If possible, merge the override in immediately.
+ if resource = @catalog.resource(override.ref)
+ resource.merge(override)
+ else
+ # Otherwise, store the override for later; these
+ # get evaluated in Resource#finish.
+ @resource_overrides[override.ref] << override
+ end
+ end
+
+ # Store a resource in our resource table.
+ def add_resource(scope, resource)
+ # Note that this will fail if the resource is not unique.
+ @catalog.add_resource(resource)
+
+ # And in the resource graph. At some point, this might supercede
+ # the global resource table, but the table is a lot faster
+ # so it makes sense to maintain for now.
+ @catalog.add_edge(scope.resource, resource)
+ end
+
# Do we use nodes found in the code, vs. the external node sources?
def ast_nodes?
parser.nodes.length > 0
@@ -26,10 +49,10 @@ class Puppet::Parser::Compile
# the scope in which it was evaluated, so that we can look it up later.
def class_set(name, scope)
if existing = @class_scopes[name]
- if existing.nodescope? or scope.nodescope?
+ if existing.nodescope? != scope.nodescope?
raise Puppet::ParseError, "Cannot have classes, nodes, or definitions with the same name"
else
- raise Puppet::DevError, "Somehow evaluated the same class twice"
+ raise Puppet::DevError, "Somehow evaluated %s %s twice" % [ existing.nodescope? ? "node" : "class", name]
end
end
@class_scopes[name] = scope
@@ -54,7 +77,7 @@ class Puppet::Parser::Compile
return @catalog.classes
end
- # Compile our catalog. This mostly revolves around finding and evaluating classes.
+ # Compiler our catalog. This mostly revolves around finding and evaluating classes.
# This is the main entry into our catalog.
def compile
# Set the client's parameters into the top scope.
@@ -68,10 +91,10 @@ class Puppet::Parser::Compile
evaluate_generators()
- fail_on_unevaluated()
-
finish()
+ fail_on_unevaluated()
+
if Puppet[:storeconfigs]
store()
end
@@ -84,11 +107,6 @@ class Puppet::Parser::Compile
@collections.delete(coll) if @collections.include?(coll)
end
- # LAK:FIXME There are no tests for this.
- def delete_resource(resource)
- @resource_table.delete(resource.ref) if @resource_table.include?(resource.ref)
- end
-
# Return the node's environment.
def environment
unless defined? @environment
@@ -120,16 +138,11 @@ class Puppet::Parser::Compile
if klass = scope.findclass(name)
found << name and next if class_scope(klass)
- # Create a resource to model this class, and then add it to the list
- # of resources.
- resource = Puppet::Parser::Resource.new(:type => "class", :title => klass.classname, :scope => scope, :source => scope.source)
-
- store_resource(scope, resource)
+ resource = klass.evaluate(scope)
# If they've disabled lazy evaluation (which the :include function does),
# then evaluate our resource immediately.
resource.evaluate unless lazy_evaluate
- @catalog.tag(klass.classname)
found << name
else
Puppet.info "Could not find class %s for %s" % [name, node.name]
@@ -140,10 +153,8 @@ class Puppet::Parser::Compile
end
# Return a resource by either its ref or its type and title.
- def findresource(string, name = nil)
- string = "%s[%s]" % [string.capitalize, name] if name
-
- @resource_table[string]
+ def findresource(*args)
+ @catalog.resource(*args)
end
# Set up our compile. We require a parser
@@ -158,7 +169,7 @@ class Puppet::Parser::Compile
begin
send(param.to_s + "=", value)
rescue NoMethodError
- raise ArgumentError, "Compile objects do not accept %s" % param
+ raise ArgumentError, "Compiler objects do not accept %s" % param
end
end
@@ -171,10 +182,10 @@ class Puppet::Parser::Compile
# its parent to the graph.
def newscope(parent, options = {})
parent ||= topscope
- options[:compile] = self
+ options[:compiler] = self
options[:parser] ||= self.parser
scope = Puppet::Parser::Scope.new(options)
- @scope_graph.add_edge!(parent, scope)
+ @scope_graph.add_edge(parent, scope)
scope
end
@@ -195,35 +206,7 @@ class Puppet::Parser::Compile
# Return a list of all resources.
def resources
- @resource_table.values
- end
-
- # Store a resource override.
- def store_override(override)
- override.override = true
-
- # If possible, merge the override in immediately.
- if resource = @resource_table[override.ref]
- resource.merge(override)
- else
- # Otherwise, store the override for later; these
- # get evaluated in Resource#finish.
- @resource_overrides[override.ref] << override
- end
- end
-
- # Store a resource in our resource table.
- def store_resource(scope, resource)
- # This might throw an exception
- verify_uniqueness(resource)
-
- # Store it in the global table.
- @resource_table[resource.ref] = resource
-
- # And in the resource graph. At some point, this might supercede
- # the global resource table, but the table is a lot faster
- # so it makes sense to maintain for now.
- @catalog.add_edge!(scope.resource, resource)
+ @catalog.vertices
end
# The top scope is usually the top-level scope, but if we're using AST nodes,
@@ -250,9 +233,7 @@ class Puppet::Parser::Compile
# Create a resource to model this node, and then add it to the list
# of resources.
- resource = Puppet::Parser::Resource.new(:type => "node", :title => astnode.classname, :scope => topscope, :source => topscope.source)
- store_resource(topscope, resource)
- @catalog.tag(astnode.classname)
+ resource = astnode.evaluate(topscope)
resource.evaluate
@@ -285,11 +266,15 @@ class Puppet::Parser::Compile
def evaluate_definitions
exceptwrap do
if ary = unevaluated_resources
+ evaluated = false
ary.each do |resource|
- resource.evaluate
+ if not resource.virtual?
+ resource.evaluate
+ evaluated = true
+ end
end
# If we evaluated, let the loop know.
- return true
+ return evaluated
else
return false
end
@@ -309,6 +294,9 @@ class Puppet::Parser::Compile
done = false if evaluate_collections
done = false if evaluate_definitions
break if done
+
+ count += 1
+
if count > 1000
raise Puppet::ParseError, "Somehow looped more than 1000 times while evaluating host catalog"
end
@@ -322,9 +310,7 @@ class Puppet::Parser::Compile
@main_resource = Puppet::Parser::Resource.new(:type => "class", :title => :main, :scope => @topscope, :source => @main)
@topscope.resource = @main_resource
- @catalog.add_vertex!(@main_resource)
-
- @resource_table["Class[main]"] = @main_resource
+ @catalog.add_resource(@main_resource)
@main_resource.evaluate
end
@@ -380,14 +366,27 @@ class Puppet::Parser::Compile
# Make sure all of our resources and such have done any last work
# necessary.
def finish
- @resource_table.each { |name, resource| resource.finish if resource.respond_to?(:finish) }
+ @catalog.vertices.each do |resource|
+ # Add in any resource overrides.
+ if overrides = resource_overrides(resource)
+ overrides.each do |over|
+ resource.merge(over)
+ end
+
+ # Remove the overrides, so that the configuration knows there
+ # are none left.
+ overrides.clear
+ end
+
+ resource.finish if resource.respond_to?(:finish)
+ end
end
# Initialize the top-level scope, class, and resource.
def init_main
# Create our initial scope and a resource that will evaluate main.
- @topscope = Puppet::Parser::Scope.new(:compile => self, :parser => self.parser)
- @scope_graph.add_vertex!(@topscope)
+ @topscope = Puppet::Parser::Scope.new(:compiler => self, :parser => self.parser)
+ @scope_graph.add_vertex(@topscope)
end
# Set up all of our internal variables.
@@ -396,9 +395,6 @@ class Puppet::Parser::Compile
# be used by top scopes and node scopes.
@class_scopes = {}
- # The table for all defined resources.
- @resource_table = {}
-
# The list of objects that will available for export.
@exported_resources = {}
@@ -412,9 +408,6 @@ class Puppet::Parser::Compile
# but they each refer back to the scope that created them.
@collections = []
- # A list of tags we've generated; most class names.
- @tags = []
-
# A graph for maintaining scope relationships.
@scope_graph = Puppet::SimpleGraph.new
@@ -443,7 +436,7 @@ class Puppet::Parser::Compile
# We used to have hooks here for forking and saving, but I don't
# think it's worth retaining at this point.
- store_to_active_record(@node, @resource_table.values)
+ store_to_active_record(@node, @catalog.vertices)
end
# Do the actual storage.
@@ -466,9 +459,7 @@ class Puppet::Parser::Compile
# Return an array of all of the unevaluated resources. These will be definitions,
# which need to get evaluated into native resources.
def unevaluated_resources
- ary = @resource_table.find_all do |name, object|
- ! object.builtin? and ! object.evaluated?
- end.collect { |name, object| object }
+ ary = @catalog.vertices.reject { |resource| resource.builtin? or resource.evaluated? }
if ary.empty?
return nil
@@ -476,33 +467,4 @@ class Puppet::Parser::Compile
return ary
end
end
-
- # Verify that the given resource isn't defined elsewhere.
- def verify_uniqueness(resource)
- # Short-curcuit the common case,
- unless existing_resource = @resource_table[resource.ref]
- return true
- end
-
- if typeclass = Puppet::Type.type(resource.type) and ! typeclass.isomorphic?
- Puppet.info "Allowing duplicate %s" % typeclass.name
- return true
- end
-
- # Either it's a defined type, which are never
- # isomorphic, or it's a non-isomorphic type, so
- # we should throw an exception.
- msg = "Duplicate definition: %s is already defined" % resource.ref
-
- if existing_resource.file and existing_resource.line
- msg << " in file %s at line %s" %
- [existing_resource.file, existing_resource.line]
- end
-
- if resource.line or resource.file
- msg << "; cannot redefine"
- end
-
- raise Puppet::ParseError.new(msg)
- end
end
diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb
index 34b38b809..e0b60e161 100644
--- a/lib/puppet/parser/functions.rb
+++ b/lib/puppet/parser/functions.rb
@@ -111,7 +111,7 @@ module Functions
vals = [vals] unless vals.is_a?(Array)
# The 'false' disables lazy evaluation.
- klasses = compile.evaluate_classes(vals, self, false)
+ klasses = compiler.evaluate_classes(vals, self, false)
missing = vals.find_all do |klass|
! klasses.include?(klass)
@@ -146,7 +146,7 @@ module Functions
tells you whether the current container is tagged with the specified tags.
The tags are ANDed, so that all of the specified tags must be included for
the function to return true.") do |vals|
- configtags = compile.catalog.tags
+ configtags = compiler.catalog.tags
resourcetags = resource.tags
retval = true
@@ -235,7 +235,7 @@ module Functions
vals = [vals] unless vals.is_a?(Array)
coll.resources = vals
- compile.add_collection(coll)
+ compiler.add_collection(coll)
end
newfunction(:search, :doc => "Add another namespace for this class to search.
diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra
index 0fd644b3a..484efe83c 100644
--- a/lib/puppet/parser/grammar.ra
+++ b/lib/puppet/parser/grammar.ra
@@ -151,7 +151,7 @@ resourceoverride: resourceref LBRACE anyparams endcomma RBRACE {
virtualresource: at resource {
type = val[0]
- if type == :exported and ! Puppet[:storeconfigs]
+ if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly]
error "You cannot collect without storeconfigs being set"
end
@@ -192,7 +192,7 @@ collection: classref collectrhand {
else
args[:form] = val[1]
end
- if args[:form] == :exported and ! Puppet[:storeconfigs]
+ if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly]
error "You cannot collect exported resources without storeconfigs being set"
end
result = ast AST::Collection, args
diff --git a/lib/puppet/parser/interpreter.rb b/lib/puppet/parser/interpreter.rb
index e29e19944..f27c1c5c8 100644
--- a/lib/puppet/parser/interpreter.rb
+++ b/lib/puppet/parser/interpreter.rb
@@ -3,7 +3,7 @@ require 'timeout'
require 'puppet/rails'
require 'puppet/util/methodhelper'
require 'puppet/parser/parser'
-require 'puppet/parser/compile'
+require 'puppet/parser/compiler'
require 'puppet/parser/scope'
# The interpreter is a very simple entry-point class that
@@ -24,8 +24,13 @@ class Puppet::Parser::Interpreter
# evaluate our whole tree
def compile(node)
- raise Puppet::ParseError, "Could not parse configuration; cannot compile" unless env_parser = parser(node.environment)
- return Puppet::Parser::Compile.new(node, env_parser).compile
+ raise Puppet::ParseError, "Could not parse configuration; cannot compile on node %s" % node.name unless env_parser = parser(node.environment)
+ begin
+ return Puppet::Parser::Compiler.new(node, env_parser).compile
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, detail.to_s + " on node %s" % node.name
+ end
end
# create our interpreter
@@ -42,6 +47,30 @@ class Puppet::Parser::Interpreter
@parsers = {}
end
+ # Return the parser for a specific environment.
+ def parser(environment)
+ if ! @parsers[environment] or @parsers[environment].reparse?
+ # This will throw an exception if it does not succeed. We only
+ # want to get rid of the old parser if we successfully create a new
+ # one.
+ begin
+ tmp = create_parser(environment)
+ @parsers[environment].clear if @parsers[environment]
+ @parsers[environment] = tmp
+ rescue => detail
+ # If a parser already exists, than assume that we logged the
+ # exception elsewhere and reuse the parser. If one doesn't
+ # exist, then reraise.
+ if @parsers[environment]
+ Puppet.err detail
+ else
+ raise detail
+ end
+ end
+ end
+ @parsers[environment]
+ end
+
private
# Create a new parser object and pre-parse the configuration.
@@ -67,24 +96,4 @@ class Puppet::Parser::Interpreter
raise error
end
end
-
- # Return the parser for a specific environment.
- def parser(environment)
- if ! @parsers[environment] or @parsers[environment].reparse?
- # This will throw an exception if it does not succeed. We only
- # want to get rid of the old parser if we successfully create a new
- # one.
- begin
- tmp = create_parser(environment)
- @parsers[environment].clear if @parsers[environment]
- @parsers[environment] = tmp
- rescue => detail
- # If a parser already exists, than assume that we logged the
- # exception elsewhere and reuse the parser. If one doesn't
- # exist, then reraise.
- raise detail unless @parsers[environment]
- end
- end
- @parsers[environment]
- end
end
diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb
index 086d82c09..51026ea1b 100644
--- a/lib/puppet/parser/lexer.rb
+++ b/lib/puppet/parser/lexer.rb
@@ -1,4 +1,3 @@
-
# the scanner/lexer
require 'strscan'
@@ -7,326 +6,436 @@ require 'puppet'
module Puppet
class LexError < RuntimeError; end
- module Parser
- #---------------------------------------------------------------
- class Lexer
- attr_reader :line, :last, :file
-
- attr_accessor :indefine
-
- #%r{\w+} => :WORD,
- @@tokens = {
- %r{#.*} => :COMMENT,
- %r{\[} => :LBRACK,
- %r{\]} => :RBRACK,
- %r{\{} => :LBRACE,
- %r{\}} => :RBRACE,
- %r{\(} => :LPAREN,
- %r{\)} => :RPAREN,
- %r{\"} => :DQUOTE,
- %r{\n} => :RETURN,
- %r{\'} => :SQUOTE,
- %r{=} => :EQUALS,
- %r{==} => :ISEQUAL,
- %r{>=} => :GREATEREQUAL,
- %r{>} => :GREATERTHAN,
- %r{<} => :LESSTHAN,
- %r{<=} => :LESSEQUAL,
- %r{!=} => :NOTEQUAL,
- %r{!} => :NOT,
- %r{,} => :COMMA,
- %r{\.} => :DOT,
- %r{:} => :COLON,
- %r{@} => :AT,
- %r{<<\|} => :LLCOLLECT,
- %r{\|>>} => :RRCOLLECT,
- %r{<\|} => :LCOLLECT,
- %r{\|>} => :RCOLLECT,
- %r{;} => :SEMIC,
- %r{\?} => :QMARK,
- %r{\\} => :BACKSLASH,
- %r{=>} => :FARROW,
- %r{\+>} => :PARROW,
- %r{[a-z][-\w]*} => :NAME,
- %r{([a-z][-\w]*::)+[a-z][-\w]*} => :CLASSNAME,
- %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF,
- %r{[0-9]+} => :NUMBER,
- %r{\$(\w*::)*\w+} => :VARIABLE
- }
-
- @@pairs = {
- "{" => "}",
- "(" => ")",
- "[" => "]",
- "<|" => "|>",
- "<<|" => "|>>"
- }
-
- @@reverse_pairs = @@pairs.inject({}) { |hash, pair| hash[pair[1]] = pair[0]; hash }
-
- @@keywords = {
- "case" => :CASE,
- "class" => :CLASS,
- "default" => :DEFAULT,
- "define" => :DEFINE,
- "false" => :BOOLEAN,
- "import" => :IMPORT,
- "if" => :IF,
- "elsif" => :ELSIF,
- "else" => :ELSE,
- "inherits" => :INHERITS,
- "node" => :NODE,
- "true" => :BOOLEAN,
- "and" => :AND,
- "or" => :OR,
- "undef" => :UNDEF
- }
-
- def clear
- initvars
- end
+end
- def expected
- if @expected.empty?
- nil
- else
- token = @expected[-1]
- @@tokens.each do |value, name|
- if token == name
- return value
- end
- end
- return token
- end
- end
+module Puppet::Parser; end
- # scan the whole file
- # basically just used for testing
- def fullscan
- array = []
-
- self.scan { |token,str|
- # Ignore any definition nesting problems
- @indefine = false
- #Puppet.debug("got token '%s' => '%s'" % [token,str])
- if token.nil?
- return array
- else
- array.push([token,str])
- end
- }
- return array
+class Puppet::Parser::Lexer
+ attr_reader :last, :file
+
+ attr_accessor :line, :indefine
+
+ # Our base token class.
+ class Token
+ attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text
+
+ def initialize(regex, name)
+ if regex.is_a?(String)
+ @name, @string = name, regex
+ @regex = Regexp.new(Regexp.escape(@string))
+ else
+ @name, @regex = name, regex
end
+ end
- # this is probably pretty damned inefficient...
- # it'd be nice not to have to load the whole file first...
- def file=(file)
- @file = file
- @line = 1
- File.open(file) { |of|
- str = ""
- of.each { |line| str += line }
- @scanner = StringScanner.new(str)
- }
+ def skip?
+ self.skip
+ end
+
+ def to_s
+ if self.string
+ @string
+ else
+ @name.to_s
end
+ end
+ end
- def indefine?
- if defined? @indefine
- @indefine
- else
- false
- end
+ # Maintain a list of tokens.
+ class TokenList
+ attr_reader :regex_tokens, :string_tokens
+
+ def [](name)
+ @tokens[name]
+ end
+
+ # Create a new token.
+ def add_token(name, regex, options = {}, &block)
+ token = Token.new(regex, name)
+ raise(ArgumentError, "Token %s already exists" % name) if @tokens.include?(name)
+ @tokens[token.name] = token
+ if token.string
+ @string_tokens << token
+ @tokens_by_string[token.string] = token
+ else
+ @regex_tokens << token
end
- def initialize
- initvars()
+ options.each do |name, option|
+ token.send(name.to_s + "=", option)
end
- def initvars
- @line = 1
- @last = ""
- @lasttoken = nil
- @scanner = nil
- @file = nil
- # AAARRGGGG! okay, regexes in ruby are bloody annoying
- # no one else has "\n" =~ /\s/
- @skip = %r{[ \t]+}
+ token.meta_def(:convert, &block) if block_given?
+
+ token
+ end
- @namestack = []
- @indefine = false
+ def initialize
+ @tokens = {}
+ @regex_tokens = []
+ @string_tokens = []
+ @tokens_by_string = {}
+ end
- @expected = []
- end
+ # Look up a token by its value, rather than name.
+ def lookup(string)
+ @tokens_by_string[string]
+ end
- # Go up one in the namespace.
- def namepop
- @namestack.pop
+ # Define more tokens.
+ def add_tokens(hash)
+ hash.each do |regex, name|
+ add_token(name, regex)
end
+ end
- # Collect the current namespace.
- def namespace
- @namestack.join("::")
+ # Sort our tokens by length, so we know once we match, we're done.
+ # This helps us avoid the O(n^2) nature of token matching.
+ def sort_tokens
+ @string_tokens.sort! { |a, b| b.string.length <=> a.string.length }
+ end
+ end
+
+ TOKENS = TokenList.new
+ TOKENS.add_tokens(
+ '[' => :LBRACK,
+ ']' => :RBRACK,
+ '{' => :LBRACE,
+ '}' => :RBRACE,
+ '(' => :LPAREN,
+ ')' => :RPAREN,
+ '=' => :EQUALS,
+ '==' => :ISEQUAL,
+ '>=' => :GREATEREQUAL,
+ '>' => :GREATERTHAN,
+ '<' => :LESSTHAN,
+ '<=' => :LESSEQUAL,
+ '!=' => :NOTEQUAL,
+ '!' => :NOT,
+ ',' => :COMMA,
+ '.' => :DOT,
+ ':' => :COLON,
+ '@' => :AT,
+ '<<|' => :LLCOLLECT,
+ '|>>' => :RRCOLLECT,
+ '<|' => :LCOLLECT,
+ '|>' => :RCOLLECT,
+ ';' => :SEMIC,
+ '?' => :QMARK,
+ '\\' => :BACKSLASH,
+ '=>' => :FARROW,
+ '+>' => :PARROW,
+ %r{([a-z][-\w]*::)+[a-z][-\w]*} => :CLASSNAME,
+ %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF
+ )
+
+ TOKENS.add_tokens "Whatever" => :DQTEXT, "Nomatter" => :SQTEXT, "alsonomatter" => :BOOLEAN
+
+ TOKENS.add_token :NAME, %r{[a-z][-\w]*} do |lexer, value|
+ string_token = self
+ # we're looking for keywords here
+ if tmp = KEYWORDS.lookup(value)
+ string_token = tmp
+ if [:TRUE, :FALSE].include?(string_token.name)
+ value = eval(value)
+ string_token = TOKENS[:BOOLEAN]
end
+ end
+ [string_token, value]
+ end
+
+ TOKENS.add_token :NUMBER, %r{[0-9]+} do |lexer, value|
+ [TOKENS[:NAME], value]
+ end
+
+ TOKENS.add_token :COMMENT, %r{#.*}, :skip => true
+
+ TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true
+
+ TOKENS.add_token :SQUOTE, "'" do |lexer, value|
+ value = lexer.slurpstring(value)
+ [TOKENS[:SQTEXT], value]
+ end
+
+ TOKENS.add_token :DQUOTE, '"' do |lexer, value|
+ value = lexer.slurpstring(value)
+ [TOKENS[:DQTEXT], value]
+ end
+
+ TOKENS.add_token :VARIABLE, %r{\$(\w*::)*\w+} do |lexer, value|
+ value = value.sub(/^\$/, '')
+ [self, value]
+ end
+
+ TOKENS.sort_tokens
+
+ @@pairs = {
+ "{" => "}",
+ "(" => ")",
+ "[" => "]",
+ "<|" => "|>",
+ "<<|" => "|>>"
+ }
+
+ KEYWORDS = TokenList.new
+
+ KEYWORDS.add_tokens(
+ "case" => :CASE,
+ "class" => :CLASS,
+ "default" => :DEFAULT,
+ "define" => :DEFINE,
+ "import" => :IMPORT,
+ "if" => :IF,
+ "elsif" => :ELSIF,
+ "else" => :ELSE,
+ "inherits" => :INHERITS,
+ "node" => :NODE,
+ "and" => :AND,
+ "or" => :OR,
+ "undef" => :UNDEF,
+ "false" => :FALSE,
+ "true" => :TRUE
+ )
+
+ def clear
+ initvars
+ end
+
+ def expected
+ return nil if @expected.empty?
+ name = @expected[-1]
+ raise "Could not find expected token %s" % name unless token = TOKENS.lookup(name)
+
+ return token
+ end
+
+ # scan the whole file
+ # basically just used for testing
+ def fullscan
+ array = []
+
+ self.scan { |token, str|
+ # Ignore any definition nesting problems
+ @indefine = false
+ array.push([token,str])
+ }
+ return array
+ end
+
+ # this is probably pretty damned inefficient...
+ # it'd be nice not to have to load the whole file first...
+ def file=(file)
+ @file = file
+ @line = 1
+ File.open(file) { |of|
+ str = ""
+ of.each { |line| str += line }
+ @scanner = StringScanner.new(str)
+ }
+ end
- # This value might have :: in it, but we don't care -- it'll be
- # handled normally when joining, and when popping we want to pop
- # this full value, however long the namespace is.
- def namestack(value)
- @namestack << value
+ def find_string_token
+ matched_token = value = nil
+
+ # We know our longest string token is three chars, so try each size in turn
+ # until we either match or run out of chars. This way our worst-case is three
+ # tries, where it is otherwise the number of string chars we have. Also,
+ # the lookups are optimized hash lookups, instead of regex scans.
+ [3, 2, 1].each do |i|
+ str = @scanner.peek(i)
+ if matched_token = TOKENS.lookup(str)
+ value = @scanner.scan(matched_token.regex)
+ break
end
+ end
+
+ return matched_token, value
+ end
- def rest
- @scanner.rest
+ # Find the next token that matches a regex. We look for these first.
+ def find_regex_token
+ @regex += 1
+ matched_token = nil
+ value = ""
+ length = 0
+
+ # I tried optimizing based on the first char, but it had
+ # a slightly negative affect and was a good bit more complicated.
+ TOKENS.regex_tokens.each do |token|
+ next unless match_length = @scanner.match?(token.regex)
+
+ # We've found a longer match
+ if match_length > length
+ value = @scanner.scan(token.regex)
+ length = value.length
+ matched_token = token
end
+ end
- # this is the heart of the lexer
- def scan
- #Puppet.debug("entering scan")
- if @scanner.nil?
- raise TypeError.new("Invalid or empty string")
- end
+ return matched_token, value
+ end
- @scanner.skip(@skip)
- until @scanner.eos? do
- yielded = false
- sendbreak = false # gah, this is a nasty hack
- stoken = nil
- sregex = nil
- value = ""
-
- # first find out which type of token we've got
- @@tokens.each { |regex,token|
- # we're just checking, which doesn't advance the scan
- # pointer
- tmp = @scanner.check(regex)
- if tmp.nil?
- #puppet.debug("did not match %s to '%s'" %
- # [regex,@scanner.rest])
- next
- end
-
- # find the longest match
- if tmp.length > value.length
- value = tmp
- stoken = token
- sregex = regex
- else
- # we've already got a longer match
- next
- end
- }
-
- # error out if we didn't match anything at all
- if stoken.nil?
- nword = nil
- if @scanner.rest =~ /^(\S+)/
- nword = $1
- elsif@scanner.rest =~ /^(\s+)/
- nword = $1
- else
- nword = @scanner.rest
- end
- raise "Could not match '%s'" % nword
- end
+ # Find the next token, returning the string and the token.
+ def find_token
+ @find += 1
+ matched_token, value = find_regex_token
- value = @scanner.scan(sregex)
+ unless matched_token
+ matched_token, value = find_string_token
+ end
- if value == ""
- raise "Didn't match regex on token %s" % stoken
- end
+ return matched_token, value
+ end
- # token-specific operations
- # if this gets much more complicated, it should
- # be moved up to where the tokens themselves are defined
- # which will get me about 75% of the way to a lexer generator
- ptoken = stoken
- case stoken
- when :NAME then
- wtoken = stoken
- # we're looking for keywords here
- if @@keywords.include?(value)
- wtoken = @@keywords[value]
- #Puppet.debug("token '%s'" % wtoken)
- if wtoken == :BOOLEAN
- value = eval(value)
- end
- end
- ptoken = wtoken
- when :NUMBER then
- ptoken = :NAME
- when :COMMENT then
- # just throw comments away
- next
- when :RETURN then
- @line += 1
- @scanner.skip(@skip)
- next
- when :SQUOTE then
- #Puppet.debug("searching '%s' after '%s'" % [self.rest,value])
- value = self.slurpstring(value)
- ptoken = :SQTEXT
- #Puppet.debug("got string '%s' => '%s'" % [:DQTEXT,value])
- when :DQUOTE then
- value = self.slurpstring(value)
- ptoken = :DQTEXT
- when :VARIABLE then
- value = value.sub(/^\$/, '')
- end
+ def indefine?
+ if defined? @indefine
+ @indefine
+ else
+ false
+ end
+ end
- if match = @@pairs[value] and ptoken != :DQUOTE and ptoken != :SQUOTE
- @expected << match
- elsif exp = @expected[-1] and exp == value and ptoken != :DQUOTE and ptoken != :SQUOTE
- @expected.pop
- end
+ def initialize
+ @find = 0
+ @regex = 0
+ initvars()
+ end
- yield [ptoken, value]
+ def initvars
+ @line = 1
+ @previous_token = nil
+ @scanner = nil
+ @file = nil
+ # AAARRGGGG! okay, regexes in ruby are bloody annoying
+ # no one else has "\n" =~ /\s/
+ @skip = %r{[ \t]+}
+
+ @namestack = []
+ @indefine = false
+ @expected = []
+ end
- if @lasttoken == :CLASS
- namestack(value)
- end
+ # Make any necessary changes to the token and/or value.
+ def munge_token(token, value)
+ @line += 1 if token.incr_line
- if @lasttoken == :DEFINE
- if indefine?
- msg = "Cannot nest definition %s inside %s" % [value, @indefine]
- self.indefine = false
- raise Puppet::ParseError, msg
- end
+ skip() if token.skip_text
- @indefine = value
- end
+ return if token.skip
- @last = value
- @lasttoken = ptoken
+ token, value = token.convert(self, value) if token.respond_to?(:convert)
- @scanner.skip(@skip)
- end
- @scanner = nil
- yield [false,false]
- end
+ return unless token
+
+ return token, value
+ end
+
+ # Go up one in the namespace.
+ def namepop
+ @namestack.pop
+ end
- # we've encountered an opening quote...
- # slurp in the rest of the string and return it
- def slurpstring(quote)
- # we search for the next quote that isn't preceded by a
- # backslash; the caret is there to match empty strings
- str = @scanner.scan_until(/([^\\]|^)#{quote}/)
- if str.nil?
- raise Puppet::LexError.new("Unclosed quote after '%s' in '%s'" %
- [self.last,self.rest])
+ # Collect the current namespace.
+ def namespace
+ @namestack.join("::")
+ end
+
+ # This value might have :: in it, but we don't care -- it'll be
+ # handled normally when joining, and when popping we want to pop
+ # this full value, however long the namespace is.
+ def namestack(value)
+ @namestack << value
+ end
+
+ def rest
+ @scanner.rest
+ end
+
+ # this is the heart of the lexer
+ def scan
+ #Puppet.debug("entering scan")
+ raise Puppet::LexError.new("Invalid or empty string") unless @scanner
+
+ # Skip any initial whitespace.
+ skip()
+
+ until @scanner.eos? do
+ yielded = false
+ matched_token, value = find_token
+
+ # error out if we didn't match anything at all
+ if matched_token.nil?
+ nword = nil
+ # Try to pull a 'word' out of the remaining string.
+ if @scanner.rest =~ /^(\S+)/
+ nword = $1
+ elsif @scanner.rest =~ /^(\s+)/
+ nword = $1
else
- str.sub!(/#{quote}\Z/,"")
- str.gsub!(/\\#{quote}/,quote)
+ nword = @scanner.rest
end
+ raise "Could not match '%s'" % nword
+ end
- return str
+ final_token, value = munge_token(matched_token, value)
+
+ next unless final_token
+
+ if match = @@pairs[value] and final_token.name != :DQUOTE and final_token.name != :SQUOTE
+ @expected << match
+ elsif exp = @expected[-1] and exp == value and final_token.name != :DQUOTE and final_token.name != :SQUOTE
+ @expected.pop
end
- # just parse a string, not a whole file
- def string=(string)
- @scanner = StringScanner.new(string)
+ yield [final_token.name, value]
+
+ if @previous_token
+ namestack(value) if @previous_token.name == :CLASS
+
+ if @previous_token.name == :DEFINE
+ if indefine?
+ msg = "Cannot nest definition %s inside %s" % [value, @indefine]
+ self.indefine = false
+ raise Puppet::ParseError, msg
+ end
+
+ @indefine = value
+ end
end
+
+ @previous_token = final_token
+ skip()
end
- #---------------------------------------------------------------
+ @scanner = nil
+
+ # This indicates that we're done parsing.
+ yield [false,false]
+ end
+
+ # Skip any skipchars in our remaining string.
+ def skip
+ @scanner.skip(@skip)
end
-end
+ # we've encountered an opening quote...
+ # slurp in the rest of the string and return it
+ def slurpstring(quote)
+ # we search for the next quote that isn't preceded by a
+ # backslash; the caret is there to match empty strings
+ str = @scanner.scan_until(/([^\\]|^)#{quote}/)
+ if str.nil?
+ raise Puppet::LexError.new("Unclosed quote after '%s' in '%s'" %
+ [self.last,self.rest])
+ else
+ str.sub!(/#{quote}\Z/,"")
+ str.gsub!(/\\#{quote}/,quote)
+ end
+
+ return str
+ end
+
+ # just parse a string, not a whole file
+ def string=(string)
+ @scanner = StringScanner.new(string)
+ end
+end
diff --git a/lib/puppet/parser/parser.rb b/lib/puppet/parser/parser.rb
index c3279d4e7..e27a209fc 100644
--- a/lib/puppet/parser/parser.rb
+++ b/lib/puppet/parser/parser.rb
@@ -29,7 +29,7 @@ module Puppet
class Parser < Racc::Parser
-module_eval <<'..end grammar.ra modeval..id9134b179f4', 'grammar.ra', 638
+module_eval <<'..end grammar.ra modeval..idfef5d70c9f', 'grammar.ra', 638
# It got too annoying having code in a file that needs to be compiled.
require 'puppet/parser/parser_support'
@@ -39,8 +39,9 @@ require 'puppet/parser/parser_support'
# mode: ruby
# End:
+# $Id$
-..end grammar.ra modeval..id9134b179f4
+..end grammar.ra modeval..idfef5d70c9f
##### racc 1.4.5 generates ###
@@ -956,7 +957,7 @@ module_eval <<'.,.,', 'grammar.ra', 174
def _reduce_38( val, _values, result )
type = val[0]
- if type == :exported and ! Puppet[:storeconfigs]
+ if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly]
error "You cannot collect without storeconfigs being set"
end
@@ -1009,7 +1010,7 @@ module_eval <<'.,.,', 'grammar.ra', 199
else
args[:form] = val[1]
end
- if args[:form] == :exported and ! Puppet[:storeconfigs]
+ if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly]
error "You cannot collect exported resources without storeconfigs being set"
end
result = ast AST::Collection, args
diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb
index acf3c9f7c..b86a4792b 100644
--- a/lib/puppet/parser/parser_support.rb
+++ b/lib/puppet/parser/parser_support.rb
@@ -47,11 +47,8 @@ class Puppet::Parser::Parser
# Create an AST object, and automatically add the file and line information if
# available.
- def ast(klass, hash = nil)
- hash ||= {}
- unless hash.include?(:line)
- hash[:line] = @lexer.line
- end
+ def ast(klass, hash = {})
+ hash[:line] = @lexer.line unless hash.include?(:line)
unless hash.include?(:file)
if file = @lexer.file
@@ -126,13 +123,17 @@ class Puppet::Parser::Parser
def fqfind(namespace, name, table)
namespace = namespace.downcase
name = name.to_s.downcase
+
+ # If our classname is fully qualified or we have no namespace,
+ # just try directly for the class, and return either way.
if name =~ /^::/ or namespace == ""
classname = name.sub(/^::/, '')
- unless table[classname]
- self.load(classname)
- end
+ self.load(classname) unless table[classname]
return table[classname]
end
+
+ # Else, build our namespace up piece by piece, checking
+ # for the class in each namespace.
ary = namespace.split("::")
while ary.length > 0
@@ -180,7 +181,7 @@ class Puppet::Parser::Parser
"in file #{@lexer.file} at line #{@lexer.line}"
)
end
- files = Puppet::Module::find_manifests(pat, :cwd => dir)
+ files = Puppet::Module::find_manifests(pat, :cwd => dir, :environment => @environment)
if files.size == 0
raise Puppet::ImportError.new("No file(s) found for import " +
"of '#{pat}'")
@@ -224,7 +225,6 @@ class Puppet::Parser::Parser
return false if classname == ""
filename = classname.gsub("::", File::SEPARATOR)
- loaded = false
# First try to load the top-level module
mod = filename.scan(/^[\w-]+/).shift
unless @loaded.include?(mod)
@@ -232,24 +232,24 @@ class Puppet::Parser::Parser
begin
import(mod)
Puppet.info "Autoloaded module %s" % mod
- loaded = true
rescue Puppet::ImportError => detail
# We couldn't load the module
end
end
- unless filename == mod and ! @loaded.include?(mod)
- @loaded << mod
+ return true if classes.include?(classname)
+
+ unless @loaded.include?(filename)
+ @loaded << filename
# Then the individual file
begin
import(filename)
Puppet.info "Autoloaded file %s from module %s" % [filename, mod]
- loaded = true
rescue Puppet::ImportError => detail
# We couldn't load the file
end
end
- return loaded
+ return classes.include?(classname)
end
# Split an fq name into a namespace and name
diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb
index 3f346166e..4b48ff6cf 100644
--- a/lib/puppet/parser/resource.rb
+++ b/lib/puppet/parser/resource.rb
@@ -3,18 +3,18 @@
class Puppet::Parser::Resource
require 'puppet/parser/resource/param'
require 'puppet/parser/resource/reference'
+ require 'puppet/util/tagging'
include Puppet::Util
include Puppet::Util::MethodHelper
include Puppet::Util::Errors
include Puppet::Util::Logging
+ include Puppet::Util::Tagging
attr_accessor :source, :line, :file, :scope, :rails_id
attr_accessor :virtual, :override, :translated
attr_reader :exported, :evaluated, :params
- attr_writer :tags
-
# Determine whether the provided parameter name is a relationship parameter.
def self.relationship_parameter?(name)
unless defined?(@relationship_names)
@@ -58,8 +58,7 @@ class Puppet::Parser::Resource
def evaluate
if klass = @ref.definedtype
finish()
- scope.compile.delete_resource(self)
- return klass.evaluate(:scope => scope, :resource => self)
+ return klass.evaluate_code(self)
elsif builtin?
devfail "Cannot evaluate a builtin type"
else
@@ -83,12 +82,19 @@ class Puppet::Parser::Resource
# Do any finishing work on this object, called before evaluation or
# before storage/translation.
def finish
- add_overrides()
+ return if finished?
+ @finished = true
add_defaults()
add_metaparams()
+ add_scope_tags()
validate()
end
+ # Has this resource already been finished?
+ def finished?
+ defined?(@finished) and @finished
+ end
+
def initialize(options)
# Set all of the options we can.
options.each do |option, value|
@@ -130,12 +136,16 @@ class Puppet::Parser::Resource
raise ArgumentError, "Resources do not accept %s" % options.keys.collect { |k| k.to_s }.join(", ")
end
- @tags = []
tag(@ref.type)
- tag(@ref.title) if @ref.title.to_s =~ /^[-\w]+$/
+ tag(@ref.title) if valid_tag?(@ref.title.to_s)
+ end
- if scope.resource
- @tags += scope.resource.tags
+ # Is this resource modeling an isomorphic resource type?
+ def isomorphic?
+ if builtin?
+ return @ref.builtintype.isomorphic?
+ else
+ return true
end
end
@@ -223,21 +233,18 @@ class Puppet::Parser::Resource
@ref.to_s
end
- # Add a tag to our current list. These tags will be added to all
- # of the objects contained in this scope.
- def tag(*ary)
- ary.collect { |tag| tag.to_s.downcase }.collect { |tag| tag.split("::") }.flatten.each do |tag|
- unless tag =~ /^\w[-\w]*$/
- fail Puppet::ParseError, "Invalid tag %s" % tag.inspect
- end
- unless @tags.include?(tag)
- @tags << tag
- end
+ # Define a parameter in our resource.
+ def set_parameter(param, value = nil)
+ if value
+ param = Puppet::Parser::Resource::Param.new(
+ :name => param, :value => value, :source => self.source
+ )
+ elsif ! param.is_a?(Puppet::Parser::Resource::Param)
+ raise ArgumentError, "Must pass a parameter or all necessary values"
end
- end
- def tags
- @tags.dup
+ # And store it in our parameter hash.
+ @params[param.name] = param
end
def to_hash
@@ -260,6 +267,8 @@ class Puppet::Parser::Resource
# Handle file specially
db_resource.file = self.file
+ db_resource.save
+
@params.each { |name, param|
param.to_rails(db_resource)
}
@@ -336,7 +345,7 @@ class Puppet::Parser::Resource
unless @params.include?(name)
self.debug "Adding default for %s" % name
- @params[name] = param
+ @params[name] = param.dup
end
end
end
@@ -361,16 +370,9 @@ class Puppet::Parser::Resource
end
end
- # Add any overrides for this object.
- def add_overrides
- if overrides = scope.compile.resource_overrides(self)
- overrides.each do |over|
- self.merge(over)
- end
-
- # Remove the overrides, so that the configuration knows there
- # are none left.
- overrides.clear
+ def add_scope_tags
+ if scope_resource = scope.resource
+ tag(*scope_resource.tags)
end
end
@@ -382,11 +384,8 @@ class Puppet::Parser::Resource
# The parameter is already set. Fail if they're not allowed to override it.
unless param.source.child_of?(current.source)
- if Puppet[:trace]
- puts caller
- end
- msg = "Parameter '%s' is already set on %s" %
- [param.name, self.to_s]
+ puts caller if Puppet[:trace]
+ msg = "Parameter '%s' is already set on %s" % [param.name, self.to_s]
if current.source.to_s != ""
msg += " by %s" % current.source
end
@@ -438,20 +437,6 @@ class Puppet::Parser::Resource
end
end
- # Define a parameter in our resource.
- def set_parameter(param, value = nil)
- if value
- param = Puppet::Parser::Resource::Param.new(
- :name => param, :value => value, :source => self.source
- )
- elsif ! param.is_a?(Puppet::Parser::Resource::Param)
- raise ArgumentError, "Must pass a parameter or all necessary values"
- end
-
- # And store it in our parameter hash.
- @params[param.name] = param
- end
-
# Make sure the resource's parameters are all valid for the type.
def validate
@params.each do |name, param|
diff --git a/lib/puppet/parser/resource/param.rb b/lib/puppet/parser/resource/param.rb
index 9352311d6..9dd3f26d2 100644
--- a/lib/puppet/parser/resource/param.rb
+++ b/lib/puppet/parser/resource/param.rb
@@ -12,7 +12,7 @@ class Puppet::Parser::Resource::Param
end
def inspect
- "#<#{self.class} @name => #{self.name}, @value => #{self.value}, @source => #{self.source.name}>"
+ "#<#{self.class} @name => #{name}, @value => #{value}, @source => #{source.name}>"
end
def line_to_i
diff --git a/lib/puppet/parser/resource/reference.rb b/lib/puppet/parser/resource/reference.rb
index 6e70d23b7..c59748049 100644
--- a/lib/puppet/parser/resource/reference.rb
+++ b/lib/puppet/parser/resource/reference.rb
@@ -37,10 +37,14 @@ class Puppet::Parser::Resource::Reference < Puppet::ResourceReference
if self.title == :main
tmp = @scope.findclass("")
else
- tmp = @scope.findclass(self.title)
+ unless tmp = @scope.findclass(self.title)
+ fail Puppet::ParseError, "Could not find class '%s'" % self.title
+ end
end
when "Node": # look for node definitions
- tmp = @scope.parser.nodes[self.title]
+ unless tmp = @scope.parser.nodes[self.title]
+ fail Puppet::ParseError, "Could not find node '%s'" % self.title
+ end
else # normal definitions
# We have to swap these variables around so the errors are right.
tmp = @scope.finddefine(self.type)
@@ -49,7 +53,7 @@ class Puppet::Parser::Resource::Reference < Puppet::ResourceReference
if tmp
@definedtype = tmp
else
- fail Puppet::ParseError, "Could not find resource '%s'" % self
+ fail Puppet::ParseError, "Could not find resource type '%s'" % self.type
end
end
diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb
index 028414cc0..a6e43e7b3 100644
--- a/lib/puppet/parser/scope.rb
+++ b/lib/puppet/parser/scope.rb
@@ -17,15 +17,20 @@ class Puppet::Parser::Scope
include Puppet::Util::Errors
attr_accessor :parent, :level, :parser, :source, :resource
attr_accessor :base, :keyword, :nodescope
- attr_accessor :top, :translated, :compile
+ attr_accessor :top, :translated, :compiler
+
+ # A demeterific shortcut to the catalog.
+ def catalog
+ compiler.catalog
+ end
# Proxy accessors
def host
- @compile.node.name
+ @compiler.node.name
end
def interpreter
- @compile.interpreter
+ @compiler.interpreter
end
# Is the value true? This allows us to control the definition of truth
@@ -72,7 +77,7 @@ class Puppet::Parser::Scope
end
def findresource(string, name = nil)
- compile.findresource(string, name)
+ compiler.findresource(string, name)
end
# Initialize our new scope. Defaults to having no parent.
@@ -147,7 +152,7 @@ class Puppet::Parser::Scope
unless klass
raise Puppet::ParseError, "Could not find class %s" % klassname
end
- unless kscope = compile.class_scope(klass)
+ unless kscope = compiler.class_scope(klass)
raise Puppet::ParseError, "Class %s has not been evaluated so its variables cannot be referenced" % klass.classname
end
return kscope.lookupvar(shortname, usestring)
@@ -184,7 +189,7 @@ class Puppet::Parser::Scope
# Create a new scope and set these options.
def newscope(options = {})
- compile.newscope(self, options)
+ compiler.newscope(self, options)
end
# Is this class for a node? This is used to make sure that
@@ -199,7 +204,7 @@ class Puppet::Parser::Scope
# than doing lots of queries.
def parent
unless defined?(@parent)
- @parent = compile.parent(self)
+ @parent = compiler.parent(self)
end
@parent
end
diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb
index 13823d483..7a8f74156 100644
--- a/lib/puppet/parser/templatewrapper.rb
+++ b/lib/puppet/parser/templatewrapper.rb
@@ -7,7 +7,7 @@ class Puppet::Parser::TemplateWrapper
def initialize(scope, file)
@scope = scope
- @file = Puppet::Module::find_template(file, @scope.compile.environment)
+ @file = Puppet::Module::find_template(file, @scope.compiler.environment)
unless FileTest.exists?(@file)
raise Puppet::ParseError,
diff --git a/lib/puppet/pgraph.rb b/lib/puppet/pgraph.rb
index 54b815b45..3bcc2ced0 100644
--- a/lib/puppet/pgraph.rb
+++ b/lib/puppet/pgraph.rb
@@ -7,38 +7,18 @@ require 'puppet/simple_graph'
# This class subclasses a graph class in order to handle relationships
# among resources.
class Puppet::PGraph < Puppet::SimpleGraph
- # This is the type used for splicing.
- attr_accessor :container_type
-
include Puppet::Util
- def add_edge!(*args)
+ def add_edge(*args)
@reversal = nil
super
end
- def add_vertex!(*args)
+ def add_vertex(*args)
@reversal = nil
super
end
- # Make sure whichever edge has a label keeps the label
- def copy_label(source, target, label)
- # 'require' relationships will not have a label,
- # and all 'subscribe' relationships have the same
- # label, at least for now.
-
- # Labels default to {}, so we can't just test for nil.
- newlabel = label || {}
- oldlabel = edge_label(source, target) || {}
- if ! newlabel.empty? and oldlabel.empty?
- edge_label_set(source, target, label)
- # We should probably check to see if the labels both exist
- # and don't match, but we'd just throw an error which the user
- # couldn't do anyting about.
- end
- end
-
# Which resources a given resource depends upon.
def dependents(resource)
tree_from_vertex(resource).keys
@@ -57,11 +37,6 @@ class Puppet::PGraph < Puppet::SimpleGraph
@reversal.tree_from_vertex(resource, :out).keys
end
- # Override this method to use our class instead.
- def edge_class()
- Puppet::Relationship
- end
-
# Determine all of the leaf nodes below a given vertex.
def leaves(vertex, direction = :out)
tree = tree_from_vertex(vertex, direction)
@@ -123,23 +98,11 @@ class Puppet::PGraph < Puppet::SimpleGraph
t = edge.target
end
- # We don't want to add multiple copies of the
- # same edge, but we *do* want to make sure we
- # keep labels around.
- # XXX This will *not* work when we support multiple
- # types of labels, and only works now because
- # you can only do simple subscriptions.
- if edge?(s, t)
- copy_label(s, t, edge.label)
- next
- end
- add_edge!(s, t, edge.label)
+ add_edge(s, t, edge.label)
end
# Now get rid of the edge, so remove_vertex! works correctly.
remove_edge!(edge)
- Puppet.debug "%s: %s => %s: %s" % [container,
- edge.source, edge.target, edge?(edge.source, edge.target)]
end
end
remove_vertex!(container)
diff --git a/lib/puppet/provider/interface/redhat.rb b/lib/puppet/provider/interface/redhat.rb
index aa217620e..4a9fcb491 100644
--- a/lib/puppet/provider/interface/redhat.rb
+++ b/lib/puppet/provider/interface/redhat.rb
@@ -5,7 +5,7 @@ Puppet::Type.type(:interface).provide(:redhat) do
desc "Manage network interfaces on Red Hat operating systems. This provider
parses and generates configuration files in ``/etc/sysconfig/network-scripts``."
- INTERFACE_DIR = "/etc/sysconfig/network-scripts"
+ INTERFACE_DIR = "/etc/sysconfig/network-scripts"
confine :exists => INTERFACE_DIR
defaultfor :operatingsystem => [:fedora, :centos, :redhat]
@@ -43,52 +43,52 @@ NETMASK=<%= self.netmask %>
BROADCAST=
LOOPBACKDUMMY
- # maximum number of dummy interfaces
- @max_dummies = 10
+ # maximum number of dummy interfaces
+ @max_dummies = 10
- # maximum number of aliases per interface
- @max_aliases_per_iface = 10
+ # maximum number of aliases per interface
+ @max_aliases_per_iface = 10
- @@dummies = []
- @@aliases = Hash.new { |hash, key| hash[key] = [] }
+ @@dummies = []
+ @@aliases = Hash.new { |hash, key| hash[key] = [] }
- # calculate which dummy interfaces are currently already in
- # use prior to needing to call self.next_dummy later on.
- def self.instances
- # parse all of the config files at once
- Dir.glob("%s/ifcfg-*" % INTERFACE_DIR).collect do |file|
- record = parse(file)
+ # calculate which dummy interfaces are currently already in
+ # use prior to needing to call self.next_dummy later on.
+ def self.instances
+ # parse all of the config files at once
+ Dir.glob("%s/ifcfg-*" % INTERFACE_DIR).collect do |file|
+ record = parse(file)
- # store the existing dummy interfaces
+ # store the existing dummy interfaces
@@dummies << record[:ifnum] if (record[:interface_type] == :dummy and ! @@dummies.include?(record[:ifnum]))
@@aliases[record[:interface]] << record[:ifnum] if record[:interface_type] == :alias
new(record)
- end
- end
-
- # return the next avaliable dummy interface number, in the case where
- # ifnum is not manually specified
- def self.next_dummy
- @max_dummies.times do |i|
- unless @@dummies.include?(i.to_s)
- @@dummies << i.to_s
- return i.to_s
- end
- end
- end
-
- # return the next available alias on a given interface, in the case
- # where ifnum if not manually specified
- def self.next_alias(interface)
- @max_aliases_per_iface.times do |i|
- unless @@aliases[interface].include?(i.to_s)
- @@aliases[interface] << i.to_s
- return i.to_s
- end
- end
- end
+ end
+ end
+
+ # return the next avaliable dummy interface number, in the case where
+ # ifnum is not manually specified
+ def self.next_dummy
+ @max_dummies.times do |i|
+ unless @@dummies.include?(i.to_s)
+ @@dummies << i.to_s
+ return i.to_s
+ end
+ end
+ end
+
+ # return the next available alias on a given interface, in the case
+ # where ifnum if not manually specified
+ def self.next_alias(interface)
+ @max_aliases_per_iface.times do |i|
+ unless @@aliases[interface].include?(i.to_s)
+ @@aliases[interface] << i.to_s
+ return i.to_s
+ end
+ end
+ end
# base the ifnum, for dummy / loopback interface in linux
# on the last octect of the IP address
@@ -139,14 +139,14 @@ LOOPBACKDUMMY
# on whether we are adding an alias to a real interface, or a loopback
# address (also dummy) on linux. For linux it's quite involved, and we
# will use an ERB template
- def generate
+ def generate
itype = self.interface_type == :alias ? :alias : :normal
self.class.template(itype).result(binding)
- end
+ end
# Where should the file be written out?
- # This defaults to INTERFACE_DIR/ifcfg-<namevar>, but can have a
- # more symbolic name by setting interface_desc in the type.
+ # This defaults to INTERFACE_DIR/ifcfg-<namevar>, but can have a
+ # more symbolic name by setting interface_desc in the type.
def file_path
if resource and val = resource[:interface_desc]
desc = val
@@ -185,16 +185,16 @@ LOOPBACKDUMMY
end
end
- # create the device name, so this based on the IP, and interface + type
- def device
- case @resource.should(:interface_type)
- when :loopback
- @property_hash[:ifnum] ||= self.class.next_dummy
- return "dummy" + @property_hash[:ifnum]
- when :alias
- @property_hash[:ifnum] ||= self.class.next_alias(@resource[:interface])
- return @resource[:interface] + ":" + @property_hash[:ifnum]
- end
+ # create the device name, so this based on the IP, and interface + type
+ def device
+ case @resource.should(:interface_type)
+ when :loopback
+ @property_hash[:ifnum] ||= self.class.next_dummy
+ return "dummy" + @property_hash[:ifnum]
+ when :alias
+ @property_hash[:ifnum] ||= self.class.next_alias(@resource[:interface])
+ return @resource[:interface] + ":" + @property_hash[:ifnum]
+ end
end
# Set the name to our ip address.
@@ -202,19 +202,19 @@ LOOPBACKDUMMY
@property_hash[:name] = value
end
- # whether the device is to be brought up on boot or not. converts
- # the true / false of the type, into yes / no values respectively
- # writing out the ifcfg-* files
- def on_boot
- case @property_hash[:onboot].to_s
- when "true"
- return "yes"
- when "false"
- return "no"
- else
- return "neither"
- end
- end
+ # whether the device is to be brought up on boot or not. converts
+ # the true / false of the type, into yes / no values respectively
+ # writing out the ifcfg-* files
+ def on_boot
+ case @property_hash[:onboot].to_s
+ when "true"
+ return "yes"
+ when "false"
+ return "no"
+ else
+ return "neither"
+ end
+ end
# Mark whether the interface should be started on boot.
def on_boot=(value)
diff --git a/lib/puppet/provider/mailalias/aliases.rb b/lib/puppet/provider/mailalias/aliases.rb
index 85dec29cc..8b5c45617 100755
--- a/lib/puppet/provider/mailalias/aliases.rb
+++ b/lib/puppet/provider/mailalias/aliases.rb
@@ -10,7 +10,10 @@ Puppet::Type.type(:mailalias).provide(:aliases,
record_line :aliases, :fields => %w{name recipient}, :separator => /\s*:\s*/, :block_eval => :instance do
def post_parse(record)
- record[:recipient] = record[:recipient].split(/\s*,\s*/).collect { |d| d.gsub(/^['"]|['"]$/, '') }
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ # It's not sufficient to assign to an existing hash.
+ recipient = record[:recipient].split(/\s*,\s*/).collect { |d| d.gsub(/^['"]|['"]$/, '') }
+ record[:recipient] = recipient
record
end
diff --git a/lib/puppet/provider/nameservice/directoryservice.rb b/lib/puppet/provider/nameservice/directoryservice.rb
index b2ccfbd4e..e2e68b2ca 100644
--- a/lib/puppet/provider/nameservice/directoryservice.rb
+++ b/lib/puppet/provider/nameservice/directoryservice.rb
@@ -139,10 +139,12 @@ class DirectoryService < Puppet::Provider::NameService
dscl_output.split("\n").each do |line|
# JJM: Split the attribute name and the list of values.
ds_attribute, ds_values_string = line.split(':')
+
+ # Split sets the values to nil if there's nothing after the :
+ ds_values_string ||= ""
# JJM: skip this attribute line if the Puppet::Type doesn't care about it.
- next unless (@@ds_to_ns_attribute_map.keys.include?(ds_attribute) \
- and type_properties.include? @@ds_to_ns_attribute_map[ds_attribute])
+ next unless (@@ds_to_ns_attribute_map.keys.include?(ds_attribute) and type_properties.include? @@ds_to_ns_attribute_map[ds_attribute])
# JJM: We asked dscl to output url encoded values so we're able
# to machine parse on whitespace. We need to urldecode:
@@ -178,11 +180,8 @@ class DirectoryService < Puppet::Provider::NameService
# This method spits out proper DSCL commands for us.
# We EXPECT name to be @resource[:name] when called from an instance object.
- # JJM: With dscl, the domain "/" is always the default local domain.
- # The domain /Search will search all domains, and you may
- # get at specific domains with /LDAPv3/server1.foobar.com,
- # /LDAPv3/server2.foobar.com, etc...
- command_vector = [ command(:dscl), "-url", "/" ]
+ # There are two ways to specify paths in 10.5. See man dscl.
+ command_vector = [ command(:dscl), "-url", "." ]
# JJM: The actual action to perform. See "man dscl"
# Common actiosn: -create, -delete, -merge, -append, -passwd
command_vector << ds_action
diff --git a/lib/puppet/provider/package/fink.rb b/lib/puppet/provider/package/fink.rb
index e0933df08..030e1a347 100755
--- a/lib/puppet/provider/package/fink.rb
+++ b/lib/puppet/provider/package/fink.rb
@@ -9,8 +9,6 @@ Puppet::Type.type(:package).provide :fink, :parent => :dpkg, :source => :dpkg do
commands :aptcache => "/sw/bin/apt-cache"
commands :dpkgquery => "/sw/bin/dpkg-query"
- defaultfor :operatingsystem => :darwin
-
has_feature :versionable
# A derivative of DPKG; this is how most people actually manage
diff --git a/lib/puppet/provider/package/gem.rb b/lib/puppet/provider/package/gem.rb
index 6e777a735..bb09bc5b0 100755
--- a/lib/puppet/provider/package/gem.rb
+++ b/lib/puppet/provider/package/gem.rb
@@ -23,14 +23,14 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
end
begin
- list = execute(command).split("\n\n").collect do |set|
+ list = execute(command).split("\n").collect do |set|
if gemhash = gemsplit(set)
gemhash[:provider] = :gem
gemhash
else
nil
end
- end.reject { |p| p.nil? }
+ end.compact
rescue Puppet::ExecutionFailure => detail
raise Puppet::Error, "Could not list gems: %s" % detail
end
@@ -44,8 +44,8 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
def self.gemsplit(desc)
case desc
- when /^\*\*\*/: return nil
- when /^(\S+)\s+\((.+)\)\n/
+ when /^\*\*\*/, /^\s*$/, /^\s+/; return nil
+ when /^(\S+)\s+\((.+)\)/
name = $1
version = $2.split(/,\s*/)[0]
return {
@@ -78,7 +78,11 @@ Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package d
command << @resource[:name]
end
- gemcmd(*command)
+ output = gemcmd(*command)
+ # Apparently some stupid gem versions don't exit non-0 on failure
+ if output.include?("ERROR")
+ self.fail "Could not install: %s" % output.chomp
+ end
end
def latest
diff --git a/lib/puppet/provider/package/openbsd.rb b/lib/puppet/provider/package/openbsd.rb
index ce69dd432..af590eb4d 100755
--- a/lib/puppet/provider/package/openbsd.rb
+++ b/lib/puppet/provider/package/openbsd.rb
@@ -2,6 +2,7 @@ require 'puppet/provider/package'
# Packaging on OpenBSD. Doesn't work anywhere else that I know of.
Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Package do
+ include Puppet::Util::Execution
desc "OpenBSD's form of ``pkg_add`` support."
commands :pkginfo => "pkg_info", :pkgadd => "pkg_add", :pkgdelete => "pkg_delete"
@@ -58,7 +59,14 @@ Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Packa
"You must specify a package source for BSD packages"
end
- pkgadd @resource[:source]
+ if @resource[:source] =~ /\/$/
+ withenv :PKG_PATH => @resource[:source] do
+ pkgadd @resource[:name]
+ end
+ else
+ pkgadd @resource[:source]
+ end
+
end
def query
@@ -66,8 +74,8 @@ Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Packa
info = pkginfo @resource[:name]
# Search for the version info
- if info =~ /Information for #{@resource[:name]}-(\S+)/
- hash[:ensure] = $1
+ if info =~ /Information for (inst:)?#{@resource[:name]}-(\S+)/
+ hash[:ensure] = $2
else
return nil
end
diff --git a/lib/puppet/provider/package/pkgdmg.rb b/lib/puppet/provider/package/pkgdmg.rb
index 2020b6b56..2614d0950 100644
--- a/lib/puppet/provider/package/pkgdmg.rb
+++ b/lib/puppet/provider/package/pkgdmg.rb
@@ -145,11 +145,8 @@ file system and not via a URL method."
begin
open(cached_source) do |dmg|
xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-noidme", "-mountrandom", "/tmp", dmg.path
- ptable = Plist::parse_xml xml_str
- # JJM Filter out all mount-paths into a single array, discard the rest.
- mounts = ptable['system-entities'].collect { |entity|
- entity['mount-point']
- }.select { |mountloc|; mountloc }
+ # JJM THIS IS A HORRIBLE HACK (Well, actually it's not so bad...)
+ mounts = xml_str.scan(/<string>(\/tmp.*?)<\/string>/)[0]
begin
mounts.each do |fspath|
Dir.entries(fspath).select { |f|
diff --git a/lib/puppet/provider/package/portage.rb b/lib/puppet/provider/package/portage.rb
index 03274a78d..f795d0302 100644
--- a/lib/puppet/provider/package/portage.rb
+++ b/lib/puppet/provider/package/portage.rb
@@ -10,8 +10,8 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa
defaultfor :operatingsystem => :gentoo
def self.instances
- result_format = /(\S+) (\S+) \[([^\[]*)(\[[^\]]*\])?\] \[[^0-9]*([^\s:\[]*)(\[[^\]]*\])?(:\S*)?\] ([\S]*) (.*)/
- result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :overlay, :slot, :vendor, :description]
+ result_format = /(\S+) (\S+) \[(?:([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\([^\)]+\))?(?:\[([^\]]+)\])?[ ]*)*\] \[(?:(?:\{M\})?(?:\([~*]+\))?([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\(([^\)]+)\))?(?:![mf])*(?:\[([^\]]+)\])?)?\] ([\S]*) (.*)/
+ result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :slot, :overlay, :vendor, :description]
search_format = "{installedversionsshort}<category> <name> [<installedversionsshort>] [<best>] <homepage> <description>{}"
@@ -39,7 +39,7 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa
return packages
rescue Puppet::ExecutionFailure => detail
- raise Puppet::PackageError.new(detail)
+ raise Puppet::Error.new(detail)
end
end
@@ -67,8 +67,8 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa
end
def query
- result_format = /(\S+) (\S+) \[([^\[]*)(\[[^\]]*\])?\] \[[^0-9]*([^\s:\[]*)(\[[^\]]*\])?(:\S*)?\] ([\S]*) (.*)/
- result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :overlay, :slot, :vendor, :description]
+ result_format = /(\S+) (\S+) \[(?:([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\([^\)]+\))?(?:\[([^\]]+)\])?[ ]*)*\] \[(?:(?:\{M\})?(?:\([~*]+\))?([0-9.a-zA-Z]+(?:_(?:alpha|beta|pre|rc|p)[0-9]*)*(?:-r[0-9]*)?)(?:\(([^\)]+)\))?(?:![mf])*(?:\[([^\]]+)\])?)?\] ([\S]*) (.*)/
+ result_fields = [:category, :name, :ensure, :ensure_overlay, :version_available, :slot, :overlay, :vendor, :description]
search_field = @resource[:category] ? "--category-name" : "--name"
search_value = package_name
@@ -99,14 +99,14 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa
case packages.size
when 0
not_found_value = "%s/%s" % [@resource[:category] ? @resource[:category] : "<unspecified category>", @resource[:name]]
- raise Puppet::PackageError.new("No package found with the specified name [#{not_found_value}]")
+ raise Puppet::Error.new("No package found with the specified name [#{not_found_value}]")
when 1
return packages[0]
else
- raise Puppet::PackageError.new("More than one package with the specified name [#{search_value}], please use the category parameter to disambiguate")
+ raise Puppet::Error.new("More than one package with the specified name [#{search_value}], please use the category parameter to disambiguate")
end
rescue Puppet::ExecutionFailure => detail
- raise Puppet::PackageError.new(detail)
+ raise Puppet::Error.new(detail)
end
end
diff --git a/lib/puppet/provider/package/ports.rb b/lib/puppet/provider/package/ports.rb
index 8c7f79e0a..1cff30039 100755
--- a/lib/puppet/provider/package/ports.rb
+++ b/lib/puppet/provider/package/ports.rb
@@ -1,6 +1,5 @@
Puppet::Type.type(:package).provide :ports, :parent => :freebsd, :source => :freebsd do
- desc "Support for FreeBSD's ports. Again, this still mixes packages
- and ports."
+ desc "Support for FreeBSD's ports. Again, this still mixes packages and ports."
commands :portupgrade => "/usr/local/sbin/portupgrade",
:portversion => "/usr/local/sbin/portversion",
diff --git a/lib/puppet/provider/package/yumhelper.py b/lib/puppet/provider/package/yumhelper.py
index 1142401b9..962b96ce4 100644
--- a/lib/puppet/provider/package/yumhelper.py
+++ b/lib/puppet/provider/package/yumhelper.py
@@ -13,8 +13,7 @@ OVERRIDE_OPTS = {
'logfile': '/dev/null'
}
-def pkg_lists():
- my = yum.YumBase()
+def pkg_lists(my):
my.doConfigSetup()
for k in OVERRIDE_OPTS.keys():
@@ -28,10 +27,13 @@ def pkg_lists():
return my.doPackageLists('updates')
try:
- ypl = pkg_lists()
+ try:
+ my = yum.YumBase()
+ ypl = pkg_lists(my)
+ for pkg in ypl.updates:
+ print "_pkg %s %s %s %s %s" % (pkg.name, pkg.epoch, pkg.version, pkg.release, pkg.arch)
+ finally:
+ my.closeRpmDB()
except IOError, e:
print "_err IOError %d %s" % (e.errno, e)
sys.exit(1)
-
-for pkg in ypl.updates:
- print "_pkg %s %s %s %s %s" % (pkg.name, pkg.epoch, pkg.version, pkg.release, pkg.arch)
diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb
index 233242a1c..f0f6fe1ef 100755
--- a/lib/puppet/provider/service/debian.rb
+++ b/lib/puppet/provider/service/debian.rb
@@ -14,6 +14,7 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do
# Remove the symlinks
def disable
update "-f", @resource[:name], "remove"
+ update @resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", "."
end
def enabled?
@@ -29,7 +30,7 @@ Puppet::Type.type(:service).provide :debian, :parent => :init do
end
def enable
+ update "-f", @resource[:name], "remove"
update @resource[:name], "defaults"
end
end
-
diff --git a/lib/puppet/provider/service/gentoo.rb b/lib/puppet/provider/service/gentoo.rb
index 2dcc3e9c1..adbee6970 100644
--- a/lib/puppet/provider/service/gentoo.rb
+++ b/lib/puppet/provider/service/gentoo.rb
@@ -8,6 +8,10 @@ Puppet::Type.type(:service).provide :gentoo, :parent => :init do
defaultfor :operatingsystem => :gentoo
+ def self.defpath
+ superclass.defpath
+ end
+
def disable
begin
output = update :del, @resource[:name], :default
diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb
index d9919f58c..274c334a3 100755
--- a/lib/puppet/provider/service/init.rb
+++ b/lib/puppet/provider/service/init.rb
@@ -110,7 +110,7 @@ Puppet::Type.type(:service).provide :init, :parent => :base do
# we just return that; otherwise, we return false, which causes it to
# fallback to other mechanisms.
def statuscmd
- if @resource[:hasstatus]
+ if @resource[:hasstatus] == :true
return [self.initscript, :status]
else
return false
diff --git a/lib/puppet/provider/sshkey/parsed.rb b/lib/puppet/provider/sshkey/parsed.rb
index cb1010c5b..6f7d98f56 100755
--- a/lib/puppet/provider/sshkey/parsed.rb
+++ b/lib/puppet/provider/sshkey/parsed.rb
@@ -12,6 +12,8 @@ Puppet::Type.type(:sshkey).provide(:parsed,
:default_target => known,
:filetype => :flat
) do
+ desc "Parse and generate host-wide known hosts files for SSH."
+
text_line :comment, :match => /^#/
text_line :blank, :match => /^\s+/
diff --git a/lib/puppet/provider/user/useradd.rb b/lib/puppet/provider/user/useradd.rb
index c2476203a..e64601ee0 100644
--- a/lib/puppet/provider/user/useradd.rb
+++ b/lib/puppet/provider/user/useradd.rb
@@ -1,7 +1,7 @@
require 'puppet/provider/nameservice/objectadd'
Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameService::ObjectAdd do
- desc "User management via ``useradd`` and its ilk. Note that you'll have to install the ``Shadow Password`` library to manage user passwords."
+ desc "User management via ``useradd`` and its ilk. Note that you will need to install the ``Shadow Password`` Ruby library often known as ruby-libshadow to manage user passwords."
commands :add => "useradd", :delete => "userdel", :modify => "usermod"
@@ -19,7 +19,7 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
has_features :manages_homedir, :allows_duplicates
- if Puppet.features.libshadow? and (Facter.value(:kernel) == "Linux")
+ if Puppet.features.libshadow?
has_feature :manages_passwords
end
diff --git a/lib/puppet/provider/zone/solaris.rb b/lib/puppet/provider/zone/solaris.rb
index dd8698b92..be2dd97f9 100644
--- a/lib/puppet/provider/zone/solaris.rb
+++ b/lib/puppet/provider/zone/solaris.rb
@@ -26,7 +26,8 @@ Puppet::Type.type(:zone).provide(:solaris) do
end
def self.instances
- adm(:list, "-cp").split("\n").collect do |line|
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = adm(:list, "-cp").split("\n").collect do |line|
new(line2hash(line))
end
end
diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb
index a1192bf20..a021c773a 100644
--- a/lib/puppet/rails.rb
+++ b/lib/puppet/rails.rb
@@ -91,6 +91,10 @@ module Puppet::Rails
raise Puppet::Error, "Could not find Puppet::Rails database dir"
end
+ unless ActiveRecord::Base.connection.tables.include?("resources")
+ raise Puppet::Error, "Database has problems, can't migrate."
+ end
+
Puppet.notice "Migrating"
begin
diff --git a/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb b/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb
new file mode 100644
index 000000000..71ee6aeed
--- /dev/null
+++ b/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb
@@ -0,0 +1,17 @@
+class AddCreatedAtToAllTables < ActiveRecord::Migration
+ def self.up
+ ActiveRecord::Base.connection.tables.each do |t|
+ unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at")
+ add_column t.to_s, :created_at, :datetime
+ end
+ end
+ end
+
+ def self.down
+ ActiveRecord::Base.connection.tables.each do |t|
+ unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at")
+ remove_column t.to_s, :created_at
+ end
+ end
+ end
+end
diff --git a/lib/puppet/rails/external/tagging/README b/lib/puppet/rails/external/tagging/README
deleted file mode 100644
index 8d2f90822..000000000
--- a/lib/puppet/rails/external/tagging/README
+++ /dev/null
@@ -1,4 +0,0 @@
-Acts As Taggable
-=================
-
-Allows for tags to be added to multiple classes. \ No newline at end of file
diff --git a/lib/puppet/rails/external/tagging/acts_as_taggable.rb b/lib/puppet/rails/external/tagging/acts_as_taggable.rb
deleted file mode 100644
index 7fd7f6b12..000000000
--- a/lib/puppet/rails/external/tagging/acts_as_taggable.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-module ActiveRecord
- module Acts #:nodoc:
- module Taggable #:nodoc:
- def self.included(base)
- base.extend(ClassMethods)
- end
-
- module ClassMethods
- def acts_as_taggable(options = {})
- write_inheritable_attribute(:acts_as_taggable_options, {
- :taggable_type => ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s,
- :from => options[:from]
- })
-
- class_inheritable_reader :acts_as_taggable_options
-
- has_many :taggings, :as => :taggable, :dependent => :destroy
- has_many :tags, :through => :taggings
-
- include ActiveRecord::Acts::Taggable::InstanceMethods
- extend ActiveRecord::Acts::Taggable::SingletonMethods
- end
- end
-
- module SingletonMethods
- def find_tagged_with(list)
- find_by_sql([
- "SELECT #{table_name}.* FROM #{table_name}, tags, taggings " +
- "WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
- "AND taggings.taggable_type = ? " +
- "AND taggings.tag_id = tags.id AND tags.name IN (?)",
- acts_as_taggable_options[:taggable_type], list
- ])
- end
- def tags(options = {})
- options.merge!(:taggable_type => self.to_s)
- Tag.tags(options)
- end
- end
-
- module InstanceMethods
- def tag_with(list)
- Tag.transaction do
- taggings.destroy_all
-
- Tag.parse(list).each do |name|
- if acts_as_taggable_options[:from]
- send(acts_as_taggable_options[:from]).tags.find_or_create_by_name(name).on(self)
- else
- Tag.find_or_create_by_name(name).on(self)
- end
- end
- end
- end
-
- def tag_list
- tags.collect { |tag| tag.name.include?(" ") ? "'#{tag.name}'" : tag.name }.join(" ")
- end
- end
- end
- end
-end
diff --git a/lib/puppet/rails/external/tagging/init.rb b/lib/puppet/rails/external/tagging/init.rb
deleted file mode 100644
index 5069d8040..000000000
--- a/lib/puppet/rails/external/tagging/init.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require 'puppet/rails/external/tagging/acts_as_taggable'
-ActiveRecord::Base.send(:include, ActiveRecord::Acts::Taggable)
-
-require 'puppet/rails/external/tagging/tagging'
-require 'puppet/rails/external/tagging/tag'
diff --git a/lib/puppet/rails/external/tagging/tag.rb b/lib/puppet/rails/external/tagging/tag.rb
deleted file mode 100644
index c6bf4ca78..000000000
--- a/lib/puppet/rails/external/tagging/tag.rb
+++ /dev/null
@@ -1,50 +0,0 @@
-class Tag < ActiveRecord::Base
- has_many :taggings
-
- def self.tags(options = {})
- query = "select tags.id, name, count(*) as count"
- query << " from taggings, tags"
- query << " where tags.id = tag_id"
- query << " group by tag_id"
- query << " order by #{options[:order]}" if options[:order] != nil
- query << " limit #{options[:limit]}" if options[:limit] != nil
- tags = Tag.find_by_sql(query)
- end
-
- def self.parse(list)
- tag_names = []
-
- # first, pull out the quoted tags
- list.gsub!(/\"(.*?)\"\s*/ ) { tag_names << $1; "" }
-
- # then, replace all commas with a space
- list.gsub!(/,/, " ")
-
- # then, get whatever's left
- tag_names.concat list.split(/\s/)
-
- # strip whitespace from the names
- tag_names = tag_names.map { |t| t.strip }
-
- # delete any blank tag names
- tag_names = tag_names.delete_if { |t| t.empty? }
-
- return tag_names
- end
-
- def tagged
- @tagged ||= taggings.collect { |tagging| tagging.taggable }
- end
-
- def on(taggable)
- taggings.build :taggable => taggable
- end
-
- def ==(comparison_object)
- super || name == comparison_object.to_s
- end
-
- def to_s
- name
- end
-end
diff --git a/lib/puppet/rails/external/tagging/tagging.rb b/lib/puppet/rails/external/tagging/tagging.rb
deleted file mode 100644
index e06e88a14..000000000
--- a/lib/puppet/rails/external/tagging/tagging.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class Tagging < ActiveRecord::Base
- belongs_to :tag
- belongs_to :taggable, :polymorphic => true
-
- def self.tagged_class(taggable)
- ActiveRecord::Base.send(:class_name_of_active_record_descendant, taggable.class).to_s
- end
-
- def self.find_taggable(tagged_class, tagged_id)
- tagged_class.constantize.find(tagged_id)
- end
-end \ No newline at end of file
diff --git a/lib/puppet/rails/fact_value.rb b/lib/puppet/rails/fact_value.rb
index 0eb70be72..b53591d7e 100644
--- a/lib/puppet/rails/fact_value.rb
+++ b/lib/puppet/rails/fact_value.rb
@@ -1,6 +1,10 @@
class Puppet::Rails::FactValue < ActiveRecord::Base
belongs_to :fact_name
belongs_to :host
+
+ def to_label
+ "#{self.fact_name.name}"
+ end
end
# $Id: fact_value.rb 1952 2006-12-19 05:47:57Z luke $
diff --git a/lib/puppet/rails/host.rb b/lib/puppet/rails/host.rb
index 72898fd97..626edaa88 100644
--- a/lib/puppet/rails/host.rb
+++ b/lib/puppet/rails/host.rb
@@ -11,8 +11,7 @@ class Puppet::Rails::Host < ActiveRecord::Base
has_many :fact_values, :dependent => :destroy
has_many :fact_names, :through => :fact_values
- belongs_to :puppet_classes
- has_many :source_files
+ belongs_to :source_file
has_many :resources,
:include => :param_values,
:dependent => :destroy
diff --git a/lib/puppet/rails/param_value.rb b/lib/puppet/rails/param_value.rb
index 02c29c540..fc00a43d4 100644
--- a/lib/puppet/rails/param_value.rb
+++ b/lib/puppet/rails/param_value.rb
@@ -20,5 +20,9 @@ class Puppet::Rails::ParamValue < ActiveRecord::Base
self[:value] = val
end
end
+
+ def to_label
+ "#{self.param_name.name}"
+ end
end
diff --git a/lib/puppet/rails/puppet_class.rb b/lib/puppet/rails/puppet_class.rb
deleted file mode 100644
index 35cef8974..000000000
--- a/lib/puppet/rails/puppet_class.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-class Puppet::Rails::PuppetClass < ActiveRecord::Base
- has_many :resources
- has_many :source_files
- has_many :hosts
-end
-
diff --git a/lib/puppet/rails/resource_tag.rb b/lib/puppet/rails/resource_tag.rb
index d06711877..f9694e082 100644
--- a/lib/puppet/rails/resource_tag.rb
+++ b/lib/puppet/rails/resource_tag.rb
@@ -1,4 +1,8 @@
class Puppet::Rails::ResourceTag < ActiveRecord::Base
belongs_to :puppet_tag
belongs_to :resource
+
+ def to_label
+ "#{self.puppet_tag.name}"
+ end
end
diff --git a/lib/puppet/rails/source_file.rb b/lib/puppet/rails/source_file.rb
index 51d1b1fb5..3ccf87ac6 100644
--- a/lib/puppet/rails/source_file.rb
+++ b/lib/puppet/rails/source_file.rb
@@ -1,5 +1,8 @@
class Puppet::Rails::SourceFile < ActiveRecord::Base
has_one :host
- has_one :puppet_class
has_one :resource
+
+ def to_label
+ "#{self.filename}"
+ end
end
diff --git a/lib/puppet/reference/node_source.rb b/lib/puppet/reference/node_source.rb
deleted file mode 100644
index 29a01f850..000000000
--- a/lib/puppet/reference/node_source.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require 'puppet/node'
-
-noderef = Puppet::Util::Reference.newreference :node_source, :doc => "Sources of node configuration information" do
- Puppet::Network::Handler.node.docs
-end
-
-noderef.header = "
-Nodes can be searched for in different locations. This document describes those different locations.
-"
diff --git a/lib/puppet/reference/report.rb b/lib/puppet/reference/report.rb
deleted file mode 100644
index a8086f8bc..000000000
--- a/lib/puppet/reference/report.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-report = Puppet::Util::Reference.newreference :report, :doc => "All available transaction reports" do
- Puppet::Network::Handler.report.reportdocs
-end
-
-report.header = "
-Puppet clients can report back to the server after each transaction. This
-transaction report is sent as a YAML dump of the
-``Puppet::Transaction::Report`` class and includes every log message that was
-generated during the transaction along with as many metrics as Puppet knows how
-to collect. See `ReportsAndReporting Reports and Reporting`:trac:
-for more information on how to use reports.
-
-Currently, clients default to not sending in reports; you can enable reporting
-by setting the ``report`` parameter to true.
-
-To use a report, set the ``reports`` parameter on the server; multiple
-reports must be comma-separated. You can also specify ``none`` to disable
-reports entirely.
-
-Puppet provides multiple report handlers that will process client reports:
-"
diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb
index a2c973f8f..102647c66 100644
--- a/lib/puppet/reports/tagmail.rb
+++ b/lib/puppet/reports/tagmail.rb
@@ -28,10 +28,12 @@ Puppet::Reports.register_report(:tagmail) do
This will send all messages to ``me@domain.com``, and all messages from
webservers that are not also from mailservers to ``httpadmins@domain.com``.
- "
+ If you are using anti-spam controls, such as grey-listing, on your mail
+ server you should whitelist the sending email (controlled by ``reportform``
+ configuration option) to ensure your email is not discarded as spam.
+ "
- Puppet.settings.use(:tagmail)
# Find all matching messages.
def match(taglists)
@@ -127,7 +129,14 @@ Puppet::Reports.register_report(:tagmail) do
Net::SMTP.start(Puppet[:smtpserver]) do |smtp|
reports.each do |emails, messages|
Puppet.info "Sending report to %s" % emails.join(", ")
- smtp.send_message(messages, Puppet[:reportfrom], *emails)
+ smtp.open_message_stream(Puppet[:reportfrom], *emails) do |p|
+ p.puts "From: #{Puppet[:reportfrom]}"
+ p.puts "Subject: Puppet Report for %s" % self.host
+ p.puts "To: " + emails.join(", ")
+ p.puts "Date: " + Time.now.rfc2822
+ p.puts
+ p.puts messages
+ end
end
end
rescue => detail
diff --git a/lib/puppet/resource_reference.rb b/lib/puppet/resource_reference.rb
index 8af17918a..12b9f54a9 100644
--- a/lib/puppet/resource_reference.rb
+++ b/lib/puppet/resource_reference.rb
@@ -29,7 +29,7 @@ class Puppet::ResourceReference
# If the title has square brackets, treat it like a reference and
# set things appropriately; else, just set it.
def title=(value)
- if value =~ /^(.+)\[(.+)\]$/
+ if value =~ /^([^\[\]]+)\[(.+)\]$/
self.type = $1
@title = $2
else
@@ -42,7 +42,8 @@ class Puppet::ResourceReference
if value.nil? or value.to_s.downcase == "component"
@type = "Class"
else
- @type = value.to_s.split("::").collect { |s| s.capitalize }.join("::")
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = @type = value.to_s.split("::").collect { |s| s.capitalize }.join("::")
end
end
diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb
index 11542ad53..48f393f77 100644
--- a/lib/puppet/simple_graph.rb
+++ b/lib/puppet/simple_graph.rb
@@ -51,10 +51,12 @@ class Puppet::SimpleGraph
# Create methods for returning the degree and edges.
[:in, :out].each do |direction|
- define_method("%s_degree" % direction) do
- @adjacencies[direction].length
- end
-
+ # LAK:NOTE If you decide to create methods for directly
+ # testing the degree, you'll have to get the values and flatten
+ # the results -- you might have duplicate edges, which can give
+ # a false impression of what the degree is. That's just
+ # as expensive as just getting the edge list, so I've decided
+ # to only add this method.
define_method("%s_edges" % direction) do
@adjacencies[direction].values.flatten
end
@@ -100,10 +102,10 @@ class Puppet::SimpleGraph
# Return a reversed version of this graph.
def reversal
result = self.class.new
- vertices.each { |vertex| result.add_vertex!(vertex) }
+ vertices.each { |vertex| result.add_vertex(vertex) }
edges.each do |edge|
newedge = edge.class.new(edge.target, edge.source, edge.label)
- result.add_edge!(newedge)
+ result.add_edge(newedge)
end
result
end
@@ -126,8 +128,9 @@ class Puppet::SimpleGraph
# Collect each of our vertices, with the number of in-edges each has.
@vertices.each do |name, wrapper|
- zeros << wrapper if wrapper.in_degree == 0
- degree[wrapper.vertex] = wrapper.in_edges
+ edges = wrapper.in_edges
+ zeros << wrapper if edges.length == 0
+ degree[wrapper.vertex] = edges
end
# Iterate over each 0-degree vertex, decrementing the degree of
@@ -150,7 +153,7 @@ class Puppet::SimpleGraph
end
# Add a new vertex to the graph.
- def add_vertex!(vertex)
+ def add_vertex(vertex)
return false if vertex?(vertex)
setup_vertex(vertex)
true # don't return the VertexWrapper instance.
@@ -176,7 +179,7 @@ class Puppet::SimpleGraph
# Add a new edge. The graph user has to create the edge instance,
# since they have to specify what kind of edge it is.
- def add_edge!(source, target = nil, label = nil)
+ def add_edge(source, target = nil, label = nil)
if target
edge = Puppet::Relationship.new(source, target, label)
else
diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb
index bd0ce8c92..0c579d0ad 100755
--- a/lib/puppet/sslcertificates.rb
+++ b/lib/puppet/sslcertificates.rb
@@ -72,7 +72,7 @@ module Puppet::SSLCertificates
subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
end
key_usage = %w{digitalSignature keyEncipherment}
- ext_key_usage = %w{serverAuth clientAuth}
+ ext_key_usage = %w{serverAuth clientAuth emailProtection}
when :ocsp:
basic_constraint = "CA:FALSE"
key_usage = %w{nonRepudiation digitalSignature}
diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb
index a3edd2cb4..7386318f4 100644
--- a/lib/puppet/sslcertificates/ca.rb
+++ b/lib/puppet/sslcertificates/ca.rb
@@ -194,8 +194,8 @@ class Puppet::SSLCertificates::CA
# Revoke the certificate with serial number SERIAL issued by this
# CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons
def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
- if @config[:cacrl] == 'none'
- raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'none'"
+ if @config[:cacrl] == 'false'
+ raise Puppet::Error, "Revocation requires a CRL, but ca_crl is set to 'false'"
end
time = Time.now
revoked = OpenSSL::X509::Revoked.new
@@ -238,33 +238,6 @@ class Puppet::SSLCertificates::CA
}
end
- # Create an exclusive lock for reading and writing, and do the
- # writing in a tmp file.
- def readwritelock(file, mode = 0600)
- tmpfile = file + ".tmp"
- sync = Sync.new
- unless FileTest.directory?(File.dirname(tmpfile))
- raise Puppet::DevError, "Cannot create %s; directory %s does not exist" %
- [file, File.dirname(file)]
- end
- sync.synchronize(Sync::EX) do
- File.open(file, "r+", mode) do |rf|
- rf.lock_exclusive do
- File.open(tmpfile, "w", mode) do |tf|
- yield tf
- end
- begin
- File.rename(tmpfile, file)
- rescue => detail
- Puppet.err "Could not rename %s to %s: %s" %
- [file, tmpfile, detail]
- end
- end
- end
- end
- end
-
-
# Sign a given certificate request.
def sign(csr)
unless csr.is_a?(OpenSSL::X509::Request)
@@ -278,9 +251,8 @@ class Puppet::SSLCertificates::CA
end
serial = nil
- readwritelock(@config[:serial]) { |f|
+ Puppet.settings.readwritelock(:serial) { |f|
serial = File.read(@config[:serial]).chomp.hex
-
# increment the serial
f << "%04X" % (serial + 1)
}
@@ -372,7 +344,7 @@ class Puppet::SSLCertificates::CA
@crl = OpenSSL::X509::CRL.new(
File.read(@config[:cacrl])
)
- elsif @config[:cacrl] == 'none'
+ elsif @config[:cacrl] == 'false'
@crl = nil
else
# Create new CRL
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index b5fbf2b0a..d4bc42100 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -15,8 +15,6 @@ class Transaction
# The list of events generated in this transaction.
attr_reader :events
- attr_writer :tags
-
include Puppet::Util
# Add some additional times for reporting
@@ -173,7 +171,7 @@ class Transaction
relationship_graph.add_resource(gen_child) unless relationship_graph.resource(gen_child.ref)
unless relationship_graph.edge?(edge[1], edge[0])
- relationship_graph.add_edge!(*edge)
+ relationship_graph.add_edge(*edge)
else
resource.debug "Skipping automatic relationship to %s" % gen_child
end
@@ -424,7 +422,7 @@ class Transaction
# Should we ignore tags?
def ignore_tags?
- ! @catalog.host_config?
+ ! (@catalog.host_config? or Puppet[:name] == "puppet")
end
# this should only be called by a Puppet::Type::Component resource now
@@ -636,6 +634,11 @@ class Transaction
@tags
end
+
+ def tags=(tags)
+ tags = [tags] unless tags.is_a?(Array)
+ @tags = tags
+ end
# Is this resource tagged appropriately?
def missing_tags?(resource)
diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb
index c1d68a881..3ad084b3b 100644
--- a/lib/puppet/transportable.rb
+++ b/lib/puppet/transportable.rb
@@ -83,14 +83,11 @@ module Puppet
end
def to_type
- retobj = nil
if typeklass = Puppet::Type.type(self.type)
return typeklass.create(self)
else
return to_component
end
-
- return retobj
end
end
@@ -179,28 +176,39 @@ module Puppet
end
# Create a resource graph from our structure.
- def to_catalog
- catalog = Puppet::Node::Catalog.new(Facter.value("hostname")) do |config|
- delver = proc do |obj|
- obj.catalog = config
- unless container = config.resource(obj.to_ref)
- container = obj.to_type
- config.add_resource container
+ def to_catalog(clear_on_failure = true)
+ catalog = Puppet::Node::Catalog.new(Facter.value("hostname"))
+
+ # This should really use the 'delve' method, but this
+ # whole class is going away relatively soon, hopefully,
+ # so it's not worth it.
+ delver = proc do |obj|
+ obj.catalog = catalog
+ unless container = catalog.resource(obj.to_ref)
+ container = obj.to_type
+ catalog.add_resource container
+ end
+ obj.each do |child|
+ child.catalog = catalog
+ unless resource = catalog.resource(child.to_ref)
+ resource = child.to_type
+ catalog.add_resource resource
end
- obj.each do |child|
- child.catalog = config
- unless resource = config.resource(child.to_ref)
- next unless resource = child.to_type
- config.add_resource resource
- end
- config.add_edge!(container, resource)
- if child.is_a?(self.class)
- delver.call(child)
- end
+
+ catalog.add_edge(container, resource)
+ if child.is_a?(self.class)
+ delver.call(child)
end
end
+ end
+ begin
delver.call(self)
+ catalog.finalize
+ rescue => detail
+ # This is important until we lose the global resource references.
+ catalog.clear if (clear_on_failure)
+ raise
end
return catalog
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index c7a6f4e40..7deb25fff 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -155,8 +155,6 @@ class Type
@parameters = {}
end
- # set defalts
- @noop = false
# keeping stats for the total number of changes, and how many were
# completely sync'ed
# this isn't really sufficient either, because it adds lots of special
@@ -257,10 +255,7 @@ class Type
rescue ArgumentError, Puppet::Error, TypeError
raise
rescue => detail
- error = Puppet::DevError.new(
- "Could not set %s on %s: %s" %
- [attr, self.class.name, detail]
- )
+ error = Puppet::DevError.new( "Could not set %s on %s: %s" % [attr, self.class.name, detail])
error.set_backtrace(detail.backtrace)
raise error
end
@@ -422,10 +417,6 @@ end
require 'puppet/propertychange'
require 'puppet/provider'
-require 'puppet/type/component'
-require 'puppet/type/pfile'
-require 'puppet/type/pfilebucket'
-require 'puppet/type/tidy'
-
-
+# Always load these types.
+require 'puppet/type/component'
diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb
index 17cb1667f..c46a7c83b 100755
--- a/lib/puppet/type/cron.rb
+++ b/lib/puppet/type/cron.rb
@@ -23,6 +23,24 @@ Puppet::Type.newtype(:cron) do
hour => 2,
minute => 0
}
+
+ Note that all cron values can be specified as an array of values::
+
+ cron { logrotate:
+ command => \"/usr/sbin/logrotate\",
+ user => root,
+ hour => [2, 4]
+ }
+
+ Or using ranges, or the step syntax ``*/2`` (although there's no guarantee that
+ your ``cron`` daemon supports it)::
+
+ cron { logrotate:
+ command => \"/usr/sbin/logrotate\",
+ user => root,
+ hour => ['2-4'],
+ minute => '*/10'
+ }
"
ensurable
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index 5bb3158c4..d7c3a8a39 100755
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@ -211,10 +211,7 @@ module Puppet
log the output when the command reports an error. Values are
**true**, *false*, *on_failure*, and any legal log level."
- values = [:true, :false, :on_failure]
- # And all of the log levels
- Puppet::Util::Log.eachlevel { |level| values << level }
- newvalues(*values)
+ newvalues(:true, :false, :on_failure)
end
newparam(:refresh) do
@@ -229,6 +226,15 @@ module Puppet
end
newparam(:env) do
+ desc "This parameter is deprecated. Use 'environment' instead."
+
+ munge do |value|
+ warning "'env' is deprecated on exec; use 'environment' instead."
+ resource[:environment] = value
+ end
+ end
+
+ newparam(:environment) do
desc "Any additional environment variables you want to set for a
command. Note that if you use this to set PATH, it will override
the ``path`` attribute. Multiple environment variables should be
@@ -279,7 +285,7 @@ module Puppet
# Rebuild the database, but only when the file changes
exec { newaliases:
path => [\"/usr/bin\", \"/usr/sbin\"],
- subscribe => file[\"/etc/aliases\"],
+ subscribe => File[\"/etc/aliases\"],
refreshonly => true
}
@@ -384,6 +390,11 @@ module Puppet
Note that this command follows the same rules as the main command,
which is to say that it must be fully qualified if the path is not set.
+
+ Also note that onlyif can take an array as its value, eg:
+ onlyif => [\"test -f /tmp/file1\", \"test -f /tmp/file2\"]
+
+ This will only run the exec if /all/ conditions in the array return true.
"
validate do |cmds|
@@ -554,32 +565,32 @@ module Puppet
begin
# Do our chdir
Dir.chdir(dir) do
- env = {}
+ environment = {}
if self[:path]
- env[:PATH] = self[:path].join(":")
+ environment[:PATH] = self[:path].join(":")
end
- if envlist = self[:env]
+ if envlist = self[:environment]
envlist = [envlist] unless envlist.is_a? Array
envlist.each do |setting|
if setting =~ /^(\w+)=((.|\n)+)$/
name = $1
value = $2
- if env.include? name
+ if environment.include? name
warning(
"Overriding environment setting '%s' with '%s'" %
[name, value]
)
end
- env[name] = value
+ environment[name] = value
else
- warning "Cannot understand env setting %s" % setting.inspect
+ warning "Cannot understand environment setting %s" % setting.inspect
end
end
end
- withenv env do
+ withenv environment do
Timeout::timeout(self[:timeout]) do
output, status = Puppet::Util::SUIDManager.run_and_capture(
[command], self[:user], self[:group]
diff --git a/lib/puppet/type/pfile.rb b/lib/puppet/type/file.rb
index c8e63b5ba..7b9233736 100644
--- a/lib/puppet/type/pfile.rb
+++ b/lib/puppet/type/file.rb
@@ -5,10 +5,12 @@ require 'uri'
require 'fileutils'
require 'puppet/network/handler'
require 'puppet/util/diff'
+require 'puppet/util/checksums'
module Puppet
newtype(:file) do
include Puppet::Util::MethodHelper
+ include Puppet::Util::Checksums
@doc = "Manages local files, including setting ownership and
permissions, creation of both files and directories, and
retrieving entire files from remote servers. As Puppet matures, it
@@ -172,11 +174,9 @@ module Puppet
recursion), and ``follow`` will manage the file to which the
link points."
- newvalues(:follow, :manage, :ignore)
+ newvalues(:follow, :manage)
- # :ignore and :manage behave equivalently on local files,
- # but don't copy remote links
- defaultto :ignore
+ defaultto :manage
end
newparam(:purge, :boolean => true) do
@@ -633,7 +633,6 @@ module Puppet
# :file.
return nil unless child = catalog.create_implicit_resource(self.class.name, args)
rescue => detail
- puts detail.backtrace
self.notice "Cannot manage: %s" % [detail]
return nil
end
@@ -641,7 +640,7 @@ module Puppet
# LAK:FIXME This shouldn't be necessary, but as long as we're
# modeling the relationship graph specifically, it is.
- catalog.relationship_graph.add_edge! self, child
+ catalog.relationship_graph.add_edge self, child
return child
end
@@ -760,11 +759,8 @@ module Puppet
begin
File.unlink(newfile)
rescue => detail
- if Puppet[:trace]
- puts detail.backtrace
- end
- self.err "Could not remove old backup: %s" %
- detail
+ puts detail.backtrace if Puppet[:trace]
+ self.err "Could not remove old backup: %s" % detail
return false
end
end
@@ -776,13 +772,14 @@ module Puppet
self.fail "Could not back up; will not replace" unless handlebackup
- return if s.ftype.to_s == should.to_s unless should.to_s == "link"
+ unless should.to_s == "link"
+ return if s.ftype.to_s == should.to_s
+ end
case s.ftype
when "directory":
if self[:force] == :true
- debug "Removing existing directory for replacement with %s" %
- should
+ debug "Removing existing directory for replacement with %s" % should
FileUtils.rmtree(self[:path])
else
notice "Not removing directory; use 'force' to override"
@@ -966,7 +963,7 @@ module Puppet
end
def uri2obj(source)
- sourceobj = FileSource.new
+ sourceobj = Puppet::Type::File::FileSource.new
path = nil
unless source
devfail "Got a nil source"
@@ -1022,54 +1019,38 @@ module Puppet
return [sourceobj, path.sub(/\/\//, '/')]
end
- # Write out the file. We open the file correctly, with all of the
- # uid and mode and such, and then yield the file handle for actual
- # writing.
- def write(property, usetmp = true)
- mode = self.should(:mode)
+ # Write out the file. Requires the content to be written,
+ # the property name for logging, and the checksum for validation.
+ def write(content, property, checksum = nil)
+ if validate = validate_checksum?
+ # Use the appropriate checksum type -- md5, md5lite, etc.
+ sumtype = property(:checksum).checktype
+ checksum ||= "{#{sumtype}}" + property(:checksum).send(sumtype, content)
+ end
remove_existing(:file)
- # The temporary file
- path = nil
- if usetmp
- path = self[:path] + ".puppettmp"
- else
- path = self[:path]
- end
-
- # As the correct user and group
- write_if_writable(File.dirname(path)) do
- f = nil
- # Open our file with the correct modes
- if mode
- Puppet::Util.withumask(000) do
- f = File.open(path,
- File::CREAT|File::WRONLY|File::TRUNC, mode)
- end
- else
- f = File.open(path, File::CREAT|File::WRONLY|File::TRUNC)
- end
+ use_temporary_file = (content.length != 0)
+ path = self[:path]
+ path += ".puppettmp" if use_temporary_file
- # Yield it
- yield f
+ mode = self.should(:mode) # might be nil
+ umask = mode ? 000 : 022
- f.flush
- f.close
+ Puppet::Util.withumask(umask) do
+ File.open(path, File::CREAT|File::WRONLY|File::TRUNC, mode) { |f| f.print content }
end
# And put our new file in place
- if usetmp
+ if use_temporary_file # This is only not true when our file is empty.
begin
+ fail_if_checksum_is_wrong(path, checksum) if validate
File.rename(path, self[:path])
rescue => detail
- self.err "Could not rename tmp %s for replacing: %s" %
- [self[:path], detail]
+ self.err "Could not rename tmp %s for replacing: %s" % [self[:path], detail]
ensure
# Make sure the created file gets removed
- if FileTest.exists?(path)
- File.unlink(path)
- end
+ File.unlink(path) if FileTest.exists?(path)
end
end
@@ -1077,32 +1058,35 @@ module Puppet
property_fix
# And then update our checksum, so the next run doesn't find it.
- # FIXME This is extra work, because it's going to read the whole
- # file back in again.
- self.setchecksum
-
+ self.setchecksum(checksum)
end
-
- # Run the block as the specified user if the dir is writeable, else
- # run it as root (or the current user).
- def write_if_writable(dir)
- yield
- # We're getting different behaviors from different versions of ruby, so...
- # asroot = true
- # Puppet::Util::SUIDManager.asuser(asuser(), self.should(:group)) do
- # if FileTest.writable?(dir)
- # asroot = false
- # yield
- # end
- # end
- #
- # if asroot
- # yield
- # end
+
+ # Should we validate the checksum of the file we're writing?
+ def validate_checksum?
+ if sumparam = @parameters[:checksum]
+ return sumparam.checktype.to_s !~ /time/
+ else
+ return false
+ end
end
private
+ # Make sure the file we wrote out is what we think it is.
+ def fail_if_checksum_is_wrong(path, checksum)
+ if checksum =~ /^\{(\w+)\}.+/
+ sumtype = $1
+ else
+ # This shouldn't happen, but if it happens to, it's nicer
+ # to just use a default sumtype than fail.
+ sumtype = "md5"
+ end
+ newsum = property(:checksum).getsum(sumtype, path)
+ return if newsum == checksum
+
+ self.fail "File written to disk did not match checksum; discarding changes (%s vs %s)" % [checksum, newsum]
+ end
+
# Override the parent method, because we don't want to generate changes
# when the file is missing and there is no 'ensure' state.
def propertychanges(currentvalues)
@@ -1139,20 +1123,20 @@ module Puppet
# the filesource class can't include the path, because the path
# changes for every file instance
- class FileSource
+ class ::Puppet::Type::File::FileSource
attr_accessor :mount, :root, :server, :local
end
# We put all of the properties in separate files, because there are so many
# of them. The order these are loaded is important, because it determines
# the order they are in the property lit.
- require 'puppet/type/pfile/checksum'
- require 'puppet/type/pfile/content' # can create the file
- require 'puppet/type/pfile/source' # can create the file
- require 'puppet/type/pfile/target' # creates a different type of file
- require 'puppet/type/pfile/ensure' # can create the file
- require 'puppet/type/pfile/owner'
- require 'puppet/type/pfile/group'
- require 'puppet/type/pfile/mode'
- require 'puppet/type/pfile/type'
+ require 'puppet/type/file/checksum'
+ require 'puppet/type/file/content' # can create the file
+ require 'puppet/type/file/source' # can create the file
+ require 'puppet/type/file/target' # creates a different type of file
+ require 'puppet/type/file/ensure' # can create the file
+ require 'puppet/type/file/owner'
+ require 'puppet/type/file/group'
+ require 'puppet/type/file/mode'
+ require 'puppet/type/file/type'
end
diff --git a/lib/puppet/type/file/checksum.rb b/lib/puppet/type/file/checksum.rb
new file mode 100755
index 000000000..3be147cb7
--- /dev/null
+++ b/lib/puppet/type/file/checksum.rb
@@ -0,0 +1,274 @@
+require 'puppet/util/checksums'
+
+# Keep a copy of the file checksums, and notify when they change. This
+# property never actually modifies the system, it only notices when the system
+# changes on its own.
+Puppet::Type.type(:file).newproperty(:checksum) do
+ include Puppet::Util::Checksums
+
+ desc "How to check whether a file has changed. This state is used internally
+ for file copying, but it can also be used to monitor files somewhat
+ like Tripwire without managing the file contents in any way. You can
+ specify that a file's checksum should be monitored and then subscribe to
+ the file from another object and receive events to signify
+ checksum changes, for instance."
+
+ @event = :file_changed
+
+ @unmanaged = true
+
+ @validtypes = %w{md5 md5lite timestamp mtime time}
+
+ def self.validtype?(type)
+ @validtypes.include?(type)
+ end
+
+ @validtypes.each do |ctype|
+ newvalue(ctype) do
+ handlesum()
+ end
+ end
+
+ str = @validtypes.join("|")
+
+ # This is here because Puppet sets this internally, using
+ # {md5}......
+ newvalue(/^\{#{str}\}/) do
+ handlesum()
+ end
+
+ newvalue(:nosum) do
+ # nothing
+ :nochange
+ end
+
+ # If they pass us a sum type, behave normally, but if they pass
+ # us a sum type + sum, stick the sum in the cache.
+ munge do |value|
+ if value =~ /^\{(\w+)\}(.+)$/
+ type = symbolize($1)
+ sum = $2
+ cache(type, sum)
+ return type
+ else
+ if FileTest.directory?(@resource[:path])
+ return :time
+ else
+ return symbolize(value)
+ end
+ end
+ end
+
+ # Store the checksum in the data cache, or retrieve it if only the
+ # sum type is provided.
+ def cache(type, sum = nil)
+ unless type
+ raise ArgumentError, "A type must be specified to cache a checksum"
+ end
+ type = symbolize(type)
+ type = :mtime if type == :timestamp
+ type = :ctime if type == :time
+
+ unless state = @resource.cached(:checksums)
+ self.debug "Initializing checksum hash"
+ state = {}
+ @resource.cache(:checksums, state)
+ end
+
+ if sum
+ unless sum =~ /\{\w+\}/
+ sum = "{%s}%s" % [type, sum]
+ end
+ state[type] = sum
+ else
+ return state[type]
+ end
+ end
+
+ # Because source and content and whomever else need to set the checksum
+ # and do the updating, we provide a simple mechanism for doing so.
+ def checksum=(value)
+ munge(@should)
+ self.updatesum(value)
+ end
+
+ def checktype
+ self.should || :md5
+ end
+
+ # Checksums need to invert how changes are printed.
+ def change_to_s(currentvalue, newvalue)
+ begin
+ if currentvalue == :absent
+ return "defined '%s' as '%s'" %
+ [self.name, self.currentsum]
+ elsif newvalue == :absent
+ return "undefined %s from '%s'" %
+ [self.name, self.is_to_s(currentvalue)]
+ else
+ if defined? @cached and @cached
+ return "%s changed '%s' to '%s'" %
+ [self.name, @cached, self.is_to_s(currentvalue)]
+ else
+ return "%s changed '%s' to '%s'" %
+ [self.name, self.currentsum, self.is_to_s(currentvalue)]
+ end
+ end
+ rescue Puppet::Error, Puppet::DevError
+ raise
+ rescue => detail
+ raise Puppet::DevError, "Could not convert change %s to string: %s" %
+ [self.name, detail]
+ end
+ end
+
+ def currentsum
+ cache(checktype())
+ end
+
+ # Retrieve the cached sum
+ def getcachedsum
+ hash = nil
+ unless hash = @resource.cached(:checksums)
+ hash = {}
+ @resource.cache(:checksums, hash)
+ end
+
+ sumtype = self.should
+
+ if hash.include?(sumtype)
+ #self.notice "Found checksum %s for %s" %
+ # [hash[sumtype] ,@resource[:path]]
+ sum = hash[sumtype]
+
+ unless sum =~ /^\{\w+\}/
+ sum = "{%s}%s" % [sumtype, sum]
+ end
+ return sum
+ elsif hash.empty?
+ #self.notice "Could not find sum of type %s" % sumtype
+ return :nosum
+ else
+ #self.notice "Found checksum for %s but not of type %s" %
+ # [@resource[:path],sumtype]
+ return :nosum
+ end
+ end
+
+ # Calculate the sum from disk.
+ def getsum(checktype, file = nil)
+ sum = ""
+
+ checktype = :mtime if checktype == :timestamp
+ checktype = :ctime if checktype == :time
+
+ file ||= @resource[:path]
+
+ return nil unless FileTest.exist?(file)
+
+ if ! FileTest.file?(file)
+ checktype = :mtime
+ end
+ method = checktype.to_s + "_file"
+
+ self.fail("Invalid checksum type %s" % checktype) unless respond_to?(method)
+
+ return "{%s}%s" % [checktype, send(method, file)]
+ end
+
+ # At this point, we don't actually modify the system, we modify
+ # the stored state to reflect the current state, and then kick
+ # off an event to mark any changes.
+ def handlesum
+ currentvalue = self.retrieve
+ if currentvalue.nil?
+ raise Puppet::Error, "Checksum state for %s is somehow nil" %
+ @resource.title
+ end
+
+ if self.insync?(currentvalue)
+ self.debug "Checksum is already in sync"
+ return nil
+ end
+ # If we still can't retrieve a checksum, it means that
+ # the file still doesn't exist
+ if currentvalue == :absent
+ # if they're copying, then we won't worry about the file
+ # not existing yet
+ unless @resource.property(:source)
+ self.warning("File %s does not exist -- cannot checksum" % @resource[:path])
+ end
+ return nil
+ end
+
+ # If the sums are different, then return an event.
+ if self.updatesum(currentvalue)
+ return :file_changed
+ else
+ return nil
+ end
+ end
+
+ def insync?(currentvalue)
+ @should = [checktype()]
+ if cache(checktype())
+ return currentvalue == currentsum()
+ else
+ # If there's no cached sum, then we don't want to generate
+ # an event.
+ return true
+ end
+ end
+
+ # Even though they can specify multiple checksums, the insync?
+ # mechanism can really only test against one, so we'll just retrieve
+ # the first specified sum type.
+ def retrieve(usecache = false)
+ # When the 'source' is retrieving, it passes "true" here so
+ # that we aren't reading the file twice in quick succession, yo.
+ currentvalue = currentsum()
+ return currentvalue if usecache and currentvalue
+
+ stat = nil
+ return :absent unless stat = @resource.stat
+
+ if stat.ftype == "link" and @resource[:links] != :follow
+ self.debug "Not checksumming symlink"
+ # @resource.delete(:checksum)
+ return currentvalue
+ end
+
+ # Just use the first allowed check type
+ currentvalue = getsum(checktype())
+
+ # If there is no sum defined, then store the current value
+ # into the cache, so that we're not marked as being
+ # out of sync. We don't want to generate an event the first
+ # time we get a sum.
+ self.updatesum(currentvalue) unless cache(checktype())
+
+ # @resource.debug "checksum state is %s" % self.is
+ return currentvalue
+ end
+
+ # Store the new sum to the state db.
+ def updatesum(newvalue)
+ result = false
+
+ # if we're replacing, vs. updating
+ if sum = cache(checktype())
+ return false if newvalue == sum
+
+ self.debug "Replacing %s checksum %s with %s" % [@resource.title, sum, newvalue]
+ result = true
+ else
+ @resource.debug "Creating checksum %s" % newvalue
+ result = false
+ end
+
+ # Cache the sum so the log message can be right if possible.
+ @cached = sum
+ cache(checktype(), newvalue)
+ return result
+ end
+end
diff --git a/lib/puppet/type/pfile/content.rb b/lib/puppet/type/file/content.rb
index 6dcda0aa6..1eb1423aa 100755
--- a/lib/puppet/type/pfile/content.rb
+++ b/lib/puppet/type/file/content.rb
@@ -1,5 +1,5 @@
module Puppet
- Puppet.type(:file).newproperty(:content) do
+ Puppet::Type.type(:file).newproperty(:content) do
include Puppet::Util::Diff
desc "Specify the contents of a file as a string. Newlines, tabs, and
@@ -47,23 +47,13 @@ module Puppet
return result
end
- # We should probably take advantage of existing md5 sums if they're there,
- # but I really don't feel like dealing with the complexity right now.
def retrieve
- stat = nil
- unless stat = @resource.stat
- return :absent
- end
+ return :absent unless stat = @resource.stat
- if stat.ftype == "link" and @resource[:links] == :ignore
- return self.should
- end
+ return self.should if stat.ftype == "link" and @resource[:links] == :ignore
# Don't even try to manage the content on directories
- if stat.ftype == "directory" and @resource[:links] == :ignore
- @resource.delete(:content)
- return nil
- end
+ return nil if stat.ftype == "directory"
begin
currentvalue = File.read(@resource[:path])
@@ -74,12 +64,17 @@ module Puppet
end
end
+ # Make sure we're also managing the checksum property.
+ def should=(value)
+ super
+ @resource.newattr(:checksum) unless @resource.property(:checksum)
+ end
# Just write our content out to disk.
def sync
return_event = @resource.stat ? :file_changed : :file_created
- @resource.write(:content) { |f| f.print self.should }
+ @resource.write(self.should, :content)
return return_event
end
diff --git a/lib/puppet/type/pfile/ensure.rb b/lib/puppet/type/file/ensure.rb
index 0a6f73d95..0d2171216 100755
--- a/lib/puppet/type/pfile/ensure.rb
+++ b/lib/puppet/type/file/ensure.rb
@@ -46,7 +46,7 @@ module Puppet
if property = (@resource.property(:content) || @resource.property(:source))
property.sync
else
- @resource.write(false) { |f| f.flush }
+ @resource.write("", :ensure)
mode = @resource.should(:mode)
end
return :file_created
@@ -67,14 +67,12 @@ module Puppet
"Cannot create %s; parent directory %s does not exist" %
[@resource[:path], parent]
end
- @resource.write_if_writable(parent) do
- if mode
- Puppet::Util.withumask(000) do
- Dir.mkdir(@resource[:path],mode)
- end
- else
- Dir.mkdir(@resource[:path])
+ if mode
+ Puppet::Util.withumask(000) do
+ Dir.mkdir(@resource[:path],mode)
end
+ else
+ Dir.mkdir(@resource[:path])
end
@resource.send(:property_fix)
@resource.setchecksum
@@ -101,9 +99,13 @@ module Puppet
munge do |value|
value = super(value)
+ # It doesn't make sense to try to manage links unless, well,
+ # we're managing links.
+ resource[:links] = :manage if value == :link
return value if value.is_a? Symbol
@resource[:target] = value
+ resource[:links] = :manage
return :link
end
@@ -136,6 +138,11 @@ module Puppet
# We have to treat :present specially, because it works with any
# type of file.
def insync?(currentvalue)
+ if property = @resource.property(:source) and ! property.described?
+ warning "No specified sources exist"
+ return true
+ end
+
if self.should == :present
if currentvalue.nil? or currentvalue == :absent
return false
diff --git a/lib/puppet/type/pfile/group.rb b/lib/puppet/type/file/group.rb
index 5f7caf342..5f7caf342 100755
--- a/lib/puppet/type/pfile/group.rb
+++ b/lib/puppet/type/file/group.rb
diff --git a/lib/puppet/type/pfile/mode.rb b/lib/puppet/type/file/mode.rb
index 8674e0a88..8674e0a88 100755
--- a/lib/puppet/type/pfile/mode.rb
+++ b/lib/puppet/type/file/mode.rb
diff --git a/lib/puppet/type/pfile/owner.rb b/lib/puppet/type/file/owner.rb
index 6f9bbd6a2..6f9bbd6a2 100755
--- a/lib/puppet/type/pfile/owner.rb
+++ b/lib/puppet/type/file/owner.rb
diff --git a/lib/puppet/type/pfile/source.rb b/lib/puppet/type/file/source.rb
index 1849d5a61..1b0dd3141 100755
--- a/lib/puppet/type/pfile/source.rb
+++ b/lib/puppet/type/file/source.rb
@@ -101,15 +101,17 @@ module Puppet
begin
desc = server.describe(path, @resource[:links])
rescue Puppet::Network::XMLRPCClientError => detail
- self.err "Could not describe %s: %s" %
- [path, detail]
+ self.err "Could not describe %s: %s" % [path, detail]
return nil
end
+ return nil if desc == ""
+
+ # Collect everything except the checksum
+ values = desc.split("\t")
+ other = values.pop
args = {}
- pinparams.zip(
- desc.split("\t")
- ).each { |param, value|
+ pinparams.zip(values).each { |param, value|
if value =~ /^[0-9]+$/
value = value.to_i
end
@@ -118,16 +120,19 @@ module Puppet
end
}
- # we can't manage ownership as root, so don't even try
- unless Puppet::Util::SUIDManager.uid == 0
- args.delete(:owner)
+ # Now decide whether we're doing checksums or symlinks
+ if args[:type] == "link"
+ args[:target] = other
+ else
+ args[:checksum] = other
end
- if args.empty? or (args[:type] == "link" and @resource[:links] == :ignore)
- return nil
- else
- return args
+ # we can't manage ownership unless we're root, so don't even try
+ unless Puppet::Util::SUIDManager.uid == 0
+ args.delete(:owner)
end
+
+ return args
end
# Have we successfully described the remote source?
@@ -138,10 +143,10 @@ module Puppet
# Use the info we get from describe() to check if we're in sync.
def insync?(currentvalue)
unless described?
- info "No specified sources exist"
+ warning "No specified sources exist"
return true
end
-
+
if currentvalue == :nocopy
return true
end
@@ -163,7 +168,7 @@ module Puppet
# Diff the contents if they ask it. This is quite annoying -- we need to do this in
# 'insync?' because they might be in noop mode, but we don't want to do the file
- # retrieval twice, so we cache the value annoyingly.
+ # retrieval twice, so we cache the value.
if ! result and Puppet[:show_diff] and File.exists?(@resource[:path]) and ! @stats[:_diffed]
@stats[:_remote_content] = get_remote_content
string_file_diff(@resource[:path], @stats[:_remote_content])
@@ -173,7 +178,7 @@ module Puppet
end
def pinparams
- Puppet::Network::Handler.handler(:fileserver).params
+ [:mode, :type, :owner, :group]
end
# This basically calls describe() on our file, and then sets all
@@ -202,14 +207,11 @@ module Puppet
end
case @stats[:type]
- when "directory", "file":
- unless @resource.deleting?
- @resource[:ensure] = @stats[:type]
- end
+ when "directory", "file", "link":
+ @resource[:ensure] = @stats[:type] unless @resource.deleting?
else
self.info @stats.inspect
- self.err "Cannot use files of type %s as sources" %
- @stats[:type]
+ self.err "Cannot use files of type %s as sources" % @stats[:type]
return :nocopy
end
@@ -221,11 +223,9 @@ module Puppet
# was the stat already specified, or should the value
# be inherited from the source?
- unless @resource.argument?(stat)
- @resource[stat] = value
- end
+ @resource[stat] = value unless @resource.argument?(stat)
}
-
+
return @stats[:checksum]
end
@@ -241,9 +241,7 @@ module Puppet
checks.delete(:checksum)
@resource[:check] = checks
- unless @resource.property(:checksum)
- @resource[:checksum] = :md5
- end
+ @resource[:checksum] = :md5 unless @resource.property(:checksum)
end
def sync
@@ -251,7 +249,7 @@ module Puppet
exists = File.exists?(@resource[:path])
- @resource.write(:source) { |f| f.print contents }
+ @resource.write(contents, :source, @stats[:checksum])
if exists
return :file_changed
@@ -261,34 +259,22 @@ module Puppet
end
private
+
def get_remote_content
- unless @stats[:type] == "file"
- #if @stats[:type] == "directory"
- #[@resource.name, @should.inspect]
- #end
- raise Puppet::DevError, "Got told to copy non-file %s" %
- @resource[:path]
- end
+ raise Puppet::DevError, "Got told to copy non-file %s" % @resource[:path] unless @stats[:type] == "file"
sourceobj, path = @resource.uri2obj(@source)
begin
contents = sourceobj.server.retrieve(path, @resource[:links])
- rescue Puppet::Network::XMLRPCClientError => detail
- self.err "Could not retrieve %s: %s" %
- [path, detail]
- return nil
+ rescue => detail
+ self.fail "Could not retrieve %s: %s" % [path, detail]
end
- # FIXME It's stupid that this isn't taken care of in the
- # protocol.
- unless sourceobj.server.local
- contents = CGI.unescape(contents)
- end
+ contents = CGI.unescape(contents) unless sourceobj.server.local
if contents == ""
- self.notice "Could not retrieve contents for %s" %
- @source
+ self.notice "Could not retrieve contents for %s" % @source
end
return contents
diff --git a/lib/puppet/type/pfile/target.rb b/lib/puppet/type/file/target.rb
index a0e5dc401..a0e5dc401 100644
--- a/lib/puppet/type/pfile/target.rb
+++ b/lib/puppet/type/file/target.rb
diff --git a/lib/puppet/type/pfile/type.rb b/lib/puppet/type/file/type.rb
index 65539795b..65539795b 100755
--- a/lib/puppet/type/pfile/type.rb
+++ b/lib/puppet/type/file/type.rb
diff --git a/lib/puppet/type/pfilebucket.rb b/lib/puppet/type/filebucket.rb
index 872bded4e..872bded4e 100755
--- a/lib/puppet/type/pfilebucket.rb
+++ b/lib/puppet/type/filebucket.rb
diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb
index be5c2ed72..53365bf40 100755
--- a/lib/puppet/type/host.rb
+++ b/lib/puppet/type/host.rb
@@ -4,6 +4,13 @@ module Puppet
newproperty(:ip) do
desc "The host's IP address, IPv4 or IPv6."
+
+ validate do |value|
+ unless value =~ /((([0-9a-fA-F]+:){7}[0-9a-fA-F]+)|(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?::(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?)|((25[0-5]|2[0-4][\d]|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})/
+ raise Puppet::Error, "Invalid IP address"
+ end
+ end
+
end
newproperty(:alias) do
@@ -78,6 +85,15 @@ module Puppet
desc "The host name."
isnamevar
+
+ validate do |value|
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = value.split('.').each do |hostpart|
+ unless hostpart =~ /^([\d\w]+|[\d\w][\d\w\-]+[\d\w])$/
+ raise Puppet::Error, "Invalid host name"
+ end
+ end
+ end
end
@doc = "Installs and manages host entries. For most systems, these
diff --git a/lib/puppet/type/mailalias.rb b/lib/puppet/type/mailalias.rb
index 92f609267..50ca26ef6 100755
--- a/lib/puppet/type/mailalias.rb
+++ b/lib/puppet/type/mailalias.rb
@@ -9,7 +9,7 @@ module Puppet
end
newproperty(:recipient, :array_matching => :all) do
- desc "Where email should should be sent. Multiple values
+ desc "Where email should be sent. Multiple values
should be specified as an array."
def is_to_s(value)
diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb
index 9173eaa1c..f004f7c42 100644
--- a/lib/puppet/type/package.rb
+++ b/lib/puppet/type/package.rb
@@ -176,7 +176,7 @@ module Puppet
a common name to packages::
# In the 'openssl' class
- $ssl = $operationgsystem ? {
+ $ssl = $operatingsystem ? {
solaris => SMCossl,
default => openssl
}
@@ -190,7 +190,7 @@ module Puppet
. etc. .
- $ssh = $operationgsystem ? {
+ $ssh = $operatingsystem ? {
solaris => SMCossh,
default => openssh
}
@@ -200,7 +200,7 @@ module Puppet
package { $ssh:
ensure => installed,
alias => openssh,
- require => package[openssl]
+ require => Package[openssl]
}
"
@@ -211,14 +211,6 @@ module Puppet
desc "Where to find the actual package. This must be a local file
(or on a network file system) or a URL that your specific
packaging type understands; Puppet will not retrieve files for you."
-
- validate do |value|
- unless value =~ /^#{File::SEPARATOR}/ or value =~ /\w+:\/\//
- self.fail(
- "Package sources must be fully qualified files or URLs, depending on the platform."
- )
- end
- end
end
newparam(:instance) do
desc "A read-only parameter set by the package."
diff --git a/lib/puppet/type/pfile/checksum.rb b/lib/puppet/type/pfile/checksum.rb
deleted file mode 100755
index 08f48ea21..000000000
--- a/lib/puppet/type/pfile/checksum.rb
+++ /dev/null
@@ -1,326 +0,0 @@
-# Keep a copy of the file checksums, and notify when they change.
-
-# This state never actually modifies the system, it only notices when the system
-# changes on its own.
-module Puppet
- Puppet.type(:file).newproperty(:checksum) do
- desc "How to check whether a file has changed. This state is used internally
- for file copying, but it can also be used to monitor files somewhat
- like Tripwire without managing the file contents in any way. You can
- specify that a file's checksum should be monitored and then subscribe to
- the file from another object and receive events to signify
- checksum changes, for instance."
-
- @event = :file_changed
-
- @unmanaged = true
-
- @validtypes = %w{md5 md5lite timestamp mtime time}
-
- def self.validtype?(type)
- @validtypes.include?(type)
- end
-
- @validtypes.each do |ctype|
- newvalue(ctype) do
- handlesum()
- end
- end
-
- str = @validtypes.join("|")
-
- # This is here because Puppet sets this internally, using
- # {md5}......
- newvalue(/^\{#{str}\}/) do
- handlesum()
- end
-
- newvalue(:nosum) do
- # nothing
- :nochange
- end
-
- # If they pass us a sum type, behave normally, but if they pass
- # us a sum type + sum, stick the sum in the cache.
- munge do |value|
- if value =~ /^\{(\w+)\}(.+)$/
- type = symbolize($1)
- sum = $2
- cache(type, sum)
- return type
- else
- if FileTest.directory?(@resource[:path])
- return :time
- else
- return symbolize(value)
- end
- end
- end
-
- # Store the checksum in the data cache, or retrieve it if only the
- # sum type is provided.
- def cache(type, sum = nil)
- unless type
- raise ArgumentError, "A type must be specified to cache a checksum"
- end
- type = symbolize(type)
- unless state = @resource.cached(:checksums)
- self.debug "Initializing checksum hash"
- state = {}
- @resource.cache(:checksums, state)
- end
-
- if sum
- unless sum =~ /\{\w+\}/
- sum = "{%s}%s" % [type, sum]
- end
- state[type] = sum
- else
- return state[type]
- end
- end
-
- # Because source and content and whomever else need to set the checksum
- # and do the updating, we provide a simple mechanism for doing so.
- def checksum=(value)
- munge(@should)
- self.updatesum(value)
- end
-
- def checktype
- self.should || :md5
- end
-
- # Checksums need to invert how changes are printed.
- def change_to_s(currentvalue, newvalue)
- begin
- if currentvalue == :absent
- return "defined '%s' as '%s'" %
- [self.name, self.currentsum]
- elsif newvalue == :absent
- return "undefined %s from '%s'" %
- [self.name, self.is_to_s(currentvalue)]
- else
- if defined? @cached and @cached
- return "%s changed '%s' to '%s'" %
- [self.name, @cached, self.is_to_s(currentvalue)]
- else
- return "%s changed '%s' to '%s'" %
- [self.name, self.currentsum, self.is_to_s(currentvalue)]
- end
- end
- rescue Puppet::Error, Puppet::DevError
- raise
- rescue => detail
- raise Puppet::DevError, "Could not convert change %s to string: %s" %
- [self.name, detail]
- end
- end
-
- def currentsum
- #"{%s}%s" % [self.should, cache(self.should)]
- cache(checktype())
- end
-
- # Retrieve the cached sum
- def getcachedsum
- hash = nil
- unless hash = @resource.cached(:checksums)
- hash = {}
- @resource.cache(:checksums, hash)
- end
-
- sumtype = self.should
-
- if hash.include?(sumtype)
- #self.notice "Found checksum %s for %s" %
- # [hash[sumtype] ,@resource[:path]]
- sum = hash[sumtype]
-
- unless sum =~ /^\{\w+\}/
- sum = "{%s}%s" % [sumtype, sum]
- end
- return sum
- elsif hash.empty?
- #self.notice "Could not find sum of type %s" % sumtype
- return :nosum
- else
- #self.notice "Found checksum for %s but not of type %s" %
- # [@resource[:path],sumtype]
- return :nosum
- end
- end
-
- # Calculate the sum from disk.
- def getsum(checktype)
- sum = ""
-
- checktype = checktype.intern if checktype.is_a? String
- case checktype
- when :md5, :md5lite:
- if ! FileTest.file?(@resource[:path])
- @resource.debug "Cannot MD5 sum %s; using mtime" %
- [@resource.stat.ftype]
- sum = @resource.stat.mtime.to_s
- else
- begin
- File.open(@resource[:path]) { |file|
- hashfunc = Digest::MD5.new
- while (!file.eof)
- readBuf = file.read(512)
- hashfunc.update(readBuf)
- if checktype == :md5lite then
- break
- end
- end
- sum = hashfunc.hexdigest
- }
- rescue Errno::EACCES => detail
- self.notice "Cannot checksum %s: permission denied" %
- @resource[:path]
- @resource.delete(self.class.name)
- rescue => detail
- self.notice "Cannot checksum: %s" %
- detail
- @resource.delete(self.class.name)
- end
- end
- when :timestamp, :mtime:
- sum = @resource.stat.mtime.to_s
- #sum = File.stat(@resource[:path]).mtime.to_s
- when :time:
- sum = @resource.stat.ctime.to_s
- #sum = File.stat(@resource[:path]).ctime.to_s
- else
- raise Puppet::Error, "Invalid sum type %s" % checktype
- end
-
- return "{#{checktype}}" + sum.to_s
- end
-
- # At this point, we don't actually modify the system, we modify
- # the stored state to reflect the current state, and then kick
- # off an event to mark any changes.
- def handlesum
- currentvalue = self.retrieve
- if currentvalue.nil?
- raise Puppet::Error, "Checksum state for %s is somehow nil" %
- @resource.title
- end
-
- if self.insync?(currentvalue)
- self.debug "Checksum is already in sync"
- return nil
- end
- # @resource.debug "%s(%s): after refresh, is '%s'" %
- # [self.class.name,@resource.name,@is]
-
- # If we still can't retrieve a checksum, it means that
- # the file still doesn't exist
- if currentvalue == :absent
- # if they're copying, then we won't worry about the file
- # not existing yet
- unless @resource.property(:source)
- self.warning("File %s does not exist -- cannot checksum" %
- @resource[:path]
- )
- end
- return nil
- end
-
- # If the sums are different, then return an event.
- if self.updatesum(currentvalue)
- return :file_changed
- else
- return nil
- end
- end
-
- def insync?(currentvalue)
- @should = [checktype()]
- if cache(checktype())
- return currentvalue == currentsum()
- else
- # If there's no cached sum, then we don't want to generate
- # an event.
- return true
- end
- end
-
- # Even though they can specify multiple checksums, the insync?
- # mechanism can really only test against one, so we'll just retrieve
- # the first specified sum type.
- def retrieve(usecache = false)
- # When the 'source' is retrieving, it passes "true" here so
- # that we aren't reading the file twice in quick succession, yo.
- currentvalue = currentsum()
- if usecache and currentvalue
- return currentvalue
- end
-
- stat = nil
- unless stat = @resource.stat
- return :absent
- end
-
- if stat.ftype == "link" and @resource[:links] != :follow
- self.debug "Not checksumming symlink"
- # @resource.delete(:checksum)
- return currentvalue
- end
-
- # Just use the first allowed check type
- currentvalue = getsum(checktype())
-
- # If there is no sum defined, then store the current value
- # into the cache, so that we're not marked as being
- # out of sync. We don't want to generate an event the first
- # time we get a sum.
- unless cache(checktype())
- # FIXME we should support an updatechecksums-like mechanism
- self.updatesum(currentvalue)
- end
-
- # @resource.debug "checksum state is %s" % self.is
- return currentvalue
- end
-
- # Store the new sum to the state db.
- def updatesum(newvalue)
- result = false
-
- if newvalue.is_a?(Symbol)
- raise Puppet::Error, "%s has invalid checksum" % @resource.title
- end
-
- # if we're replacing, vs. updating
- if sum = cache(checktype())
- # unless defined? @should
- # raise Puppet::Error.new(
- # ("@should is not initialized for %s, even though we " +
- # "found a checksum") % @resource[:path]
- # )
- # end
-
- if newvalue == sum
- return false
- end
-
- self.debug "Replacing %s checksum %s with %s" %
- [@resource.title, sum, newvalue]
- # @resource.debug "currentvalue: %s; @should: %s" %
- # [newvalue,@should]
- result = true
- else
- @resource.debug "Creating checksum %s" % newvalue
- result = false
- end
-
- # Cache the sum so the log message can be right if possible.
- @cached = sum
- cache(checktype(), newvalue)
- return result
- end
- end
-end
-
diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb
index c41a7883b..560d81bae 100644
--- a/lib/puppet/type/service.rb
+++ b/lib/puppet/type/service.rb
@@ -28,6 +28,8 @@ module Puppet
feature :enableable, "The provider can enable and disable the service",
:methods => [:disable, :enable, :enabled?]
+ feature :controllable, "The provider uses a control variable."
+
newproperty(:enable, :required_features => :enableable) do
desc "Whether a service should be enabled to start at boot.
This property behaves quite differently depending on the platform;
@@ -111,7 +113,9 @@ module Puppet
munge do |value|
value = [value] unless value.is_a?(Array)
- paths = value.flatten.collect { |p| p.split(":") }.flatten.find_all do |path|
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ # It affects stand-alone blocks, too.
+ paths = value.flatten.collect { |p| x = p.split(":") }.flatten.find_all do |path|
if FileTest.directory?(path)
true
else
@@ -163,6 +167,13 @@ module Puppet
desc "Specify a *stop* command manually."
end
+ newparam(:control) do
+ desc "The control variable used to manage services (originally for HP-UX).
+ Defaults to the upcased service name plus ``START`` replacing dots with
+ underscores, for those providers that support the ``controllable`` feature."
+ defaultto { resource.name.gsub(".","_").upcase + "_START" if resource.provider.controllable? }
+ end
+
newparam :hasrestart do
desc "Specify that an init script has a ``restart`` option. Otherwise,
the init script's ``stop`` and ``start`` methods are used."
diff --git a/lib/puppet/type/sshkey.rb b/lib/puppet/type/sshkey.rb
index bf4b0aac8..c2bdd39e3 100755
--- a/lib/puppet/type/sshkey.rb
+++ b/lib/puppet/type/sshkey.rb
@@ -53,14 +53,14 @@ module Puppet
end
newparam(:name) do
- desc "The host name."
+ desc "The host name that the key is associated with."
isnamevar
end
newproperty(:target) do
- desc "The file in which to store the mount table. Only used by
- those providers that write to disk (i.e., not NetInfo)."
+ desc "The file in which to store the ssh key. Only used by
+ the ``parsed`` provider."
defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
@resource.class.defaultprovider.default_target
diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb
index dacf037ac..fe8bde9ab 100755
--- a/lib/puppet/type/tidy.rb
+++ b/lib/puppet/type/tidy.rb
@@ -1,5 +1,5 @@
module Puppet
- newtype(:tidy, Puppet.type(:file)) do
+ newtype(:tidy, :parent => Puppet.type(:file)) do
@doc = "Remove unwanted files based on specific criteria. Multiple
criteria are OR'd together, so a file that is too large but is not
old enough will still get tidied."
diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb
index 2e83a08e9..560afe10b 100644
--- a/lib/puppet/util.rb
+++ b/lib/puppet/util.rb
@@ -226,7 +226,8 @@ module Util
return nil
end
else
- ENV['PATH'].split(":").each do |dir|
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = ENV['PATH'].split(":").each do |dir|
if FileTest.exists? File.join(dir, bin)
return File.join(dir, bin)
end
diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb
index a52575522..535d9ef2e 100644
--- a/lib/puppet/util/autoload.rb
+++ b/lib/puppet/util/autoload.rb
@@ -1,6 +1,9 @@
+require 'puppet/util/warnings'
+
# Autoload paths, either based on names or all at once.
class Puppet::Util::Autoload
include Puppet::Util
+ include Puppet::Util::Warnings
@autoloaders = {}
@loaded = []
@@ -109,9 +112,8 @@ class Puppet::Util::Autoload
Dir.glob("#{dir}/*.rb").each do |file|
name = File.basename(file).sub(".rb", '').intern
next if loaded?(name)
- rubypath = File.join(@path, name.to_s)
begin
- Kernel.require rubypath
+ Kernel.require file
loaded(name, file)
rescue => detail
if Puppet[:trace]
@@ -123,8 +125,6 @@ class Puppet::Util::Autoload
end
end
- private
-
# Yield each subdir in turn.
def eachdir
searchpath.each do |dir|
@@ -137,7 +137,7 @@ class Puppet::Util::Autoload
def searchpath
# JJM: Search for optional lib directories in each module bundle.
module_lib_dirs = Puppet[:modulepath].split(":").collect do |d|
- Dir.glob("%s/*/lib" % d).select do |f|
+ Dir.glob("%s/*/{plugins,lib}" % d).select do |f|
FileTest.directory?(f)
end
end.flatten
diff --git a/lib/puppet/util/checksums.rb b/lib/puppet/util/checksums.rb
index 6f6ea59b5..15d2eadd1 100644
--- a/lib/puppet/util/checksums.rb
+++ b/lib/puppet/util/checksums.rb
@@ -1,37 +1,75 @@
+# A stand-alone module for calculating checksums
+# in a generic way.
module Puppet::Util::Checksums
+ # Calculate a checksum using Digest::MD5.
def md5(content)
require 'digest/md5'
Digest::MD5.hexdigest(content)
end
- def md5_file(filename)
+ # Calculate a checksum of the first 500 chars of the content using Digest::MD5.
+ def md5lite(content)
+ md5(content[0..511])
+ end
+
+ # Calculate a checksum of a file's content using Digest::MD5.
+ def md5_file(filename, lite = false)
require 'digest/md5'
- incr_digest = Digest::MD5.new()
- File.open(filename, 'r') do |file|
- file.each_line do |line|
- incr_digest << line
- end
- end
+ digest = Digest::MD5.new()
+ return checksum_file(digest, filename, lite)
+ end
+
+ # Calculate a checksum of the first 500 chars of a file's content using Digest::MD5.
+ def md5lite_file(filename)
+ md5_file(filename, true)
+ end
- return incr_digest.hexdigest
+ # Return the :mtime timestamp of a file.
+ def mtime_file(filename)
+ File.stat(filename).send(:mtime)
end
+ # Calculate a checksum using Digest::SHA1.
def sha1(content)
require 'digest/sha1'
Digest::SHA1.hexdigest(content)
end
- def sha1_file(filename)
+ # Calculate a checksum of the first 500 chars of the content using Digest::SHA1.
+ def sha1lite(content)
+ sha1(content[0..511])
+ end
+
+ # Calculate a checksum of a file's content using Digest::SHA1.
+ def sha1_file(filename, lite = false)
require 'digest/sha1'
- incr_digest = Digest::SHA1.new()
+ digest = Digest::SHA1.new()
+ return checksum_file(digest, filename, lite)
+ end
+
+ # Calculate a checksum of the first 500 chars of a file's content using Digest::SHA1.
+ def sha1lite_file(filename)
+ sha1_file(filename, true)
+ end
+
+ # Return the :ctime of a file.
+ def ctime_file(filename)
+ File.stat(filename).send(:ctime)
+ end
+
+ private
+
+ # Perform an incremental checksum on a file.
+ def checksum_file(digest, filename, lite = false)
File.open(filename, 'r') do |file|
- file.each_line do |line|
- incr_digest << line
+ while content = file.read(512)
+ digest << content
+ break if lite
end
end
- return incr_digest.hexdigest
+ return digest.hexdigest
end
end
diff --git a/lib/puppet/util/constant_inflector.rb b/lib/puppet/util/constant_inflector.rb
new file mode 100644
index 000000000..eeeaa0632
--- /dev/null
+++ b/lib/puppet/util/constant_inflector.rb
@@ -0,0 +1,15 @@
+# Created on 2008-02-12
+# Copyright Luke Kanies
+
+# A common module for converting between constants and
+# file names.
+module Puppet::Util::ConstantInflector
+ def file2constant(file)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = file.split("/").collect { |name| name.capitalize }.join("::").gsub(/_+(.)/) { |term| $1.capitalize }
+ end
+
+ def constant2file(constant)
+ constant.to_s.gsub(/([a-z])([A-Z])/) { |term| $1 + "_" + $2 }.gsub("::", "/").downcase
+ end
+end
diff --git a/lib/puppet/util/diff.rb b/lib/puppet/util/diff.rb
index e6ff57108..f37ea0850 100644
--- a/lib/puppet/util/diff.rb
+++ b/lib/puppet/util/diff.rb
@@ -27,7 +27,7 @@ module Puppet::Util::Diff
output = ""
- diffs = Diff::LCS.diff(data_old, data_new)
+ diffs = ::Diff::LCS.diff(data_old, data_new)
return output if diffs.empty?
oldhunk = hunk = nil
@@ -35,7 +35,7 @@ module Puppet::Util::Diff
diffs.each do |piece|
begin
- hunk = Diff::LCS::Hunk.new(data_old, data_new, piece,
+ hunk = ::Diff::LCS::Hunk.new(data_old, data_new, piece,
context_lines,
file_length_difference)
file_length_difference = hunk.file_length_difference
diff --git a/lib/puppet/util/fileparsing.rb b/lib/puppet/util/fileparsing.rb
index 8e39719c8..23d02ea60 100644
--- a/lib/puppet/util/fileparsing.rb
+++ b/lib/puppet/util/fileparsing.rb
@@ -223,7 +223,8 @@ module Puppet::Util::FileParsing
# Split text into separate lines using the record separator.
def lines(text)
# Remove any trailing separators, and then split based on them
- text.sub(/#{self.line_separator}\Q/,'').split(self.line_separator)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = text.sub(/#{self.line_separator}\Q/,'').split(self.line_separator)
end
# Split a bunch of text into lines and then parse them individually.
diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb
index 95f48e10e..ae078fff4 100755
--- a/lib/puppet/util/filetype.rb
+++ b/lib/puppet/util/filetype.rb
@@ -106,8 +106,14 @@ class Puppet::Util::FileType
# Overwrite the file.
def write(text)
backup()
+
raise("Cannot create file %s in absent directory" % @path) unless FileTest.exist?(File.dirname(@path))
- File.open(@path, "w") { |f| f.print text; f.flush }
+
+ require "tempfile"
+ tf = Tempfile.new("puppet")
+ tf.print text; tf.flush
+ FileUtils.cp(tf.path, @path)
+ tf.close
end
end
@@ -168,7 +174,7 @@ class Puppet::Util::FileType
# Remove a specific @path's cron tab.
def remove
- if Facter.value("operatingsystem") == "FreeBSD"
+ if %w{Darwin FreeBSD}.include?(Facter.value("operatingsystem"))
%x{/bin/echo yes | #{cmdbase()} -r 2>/dev/null}
else
%x{#{cmdbase()} -r 2>/dev/null}
diff --git a/lib/puppet/util/graph.rb b/lib/puppet/util/graph.rb
index a9744578b..d1ef36f8e 100644
--- a/lib/puppet/util/graph.rb
+++ b/lib/puppet/util/graph.rb
@@ -16,7 +16,7 @@ module Puppet::Util::Graph
self.each do |child|
unless block_given? and ! yield(child)
- graph.add_edge!(self, child)
+ graph.add_edge(self, child)
if child.respond_to?(:to_graph)
child.to_graph(graph, &block)
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index b672d9564..089389a09 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -44,19 +44,6 @@ class Puppet::Util::Settings
return value
end
- # A simplified equality operator.
- # LAK: For some reason, this causes mocha to not be able to mock
- # the 'value' method, and it's not used anywhere.
-# def ==(other)
-# self.each { |myname, myobj|
-# unless other[myname] == value(myname)
-# return false
-# end
-# }
-#
-# return true
-# end
-
# Generate the list of valid arguments, in a format that GetoptLong can
# understand, and add them to the passed option list.
def addargs(options)
@@ -225,6 +212,9 @@ class Puppet::Util::Settings
# A central concept of a name.
@name = nil
+
+ # The list of sections we've used.
+ @used = []
end
# Return a given object's file metadata.
@@ -243,14 +233,7 @@ class Puppet::Util::Settings
# Make a directory with the appropriate user, group, and mode
def mkdir(default)
- obj = nil
- unless obj = @config[default]
- raise ArgumentError, "Unknown default %s" % default
- end
-
- unless obj.is_a? CFile
- raise ArgumentError, "Default %s is not a file" % default
- end
+ obj = get_config_file_default(default)
Puppet::Util::SUIDManager.asuser(obj.owner, obj.group) do
mode = obj.mode || 0750
@@ -329,94 +312,6 @@ class Puppet::Util::Settings
end
end
- # Parse the configuration file. As of May 2007, this is a backward-compatibility method and
- # will be deprecated soon.
- def old_parse(file)
- text = nil
-
- if file.is_a? Puppet::Util::LoadedFile
- @file = file
- else
- @file = Puppet::Util::LoadedFile.new(file)
- end
-
- # Don't create a timer for the old style parsing.
- # settimer()
-
- begin
- text = File.read(@file.file)
- rescue Errno::ENOENT
- raise Puppet::Error, "No such file %s" % file
- rescue Errno::EACCES
- raise Puppet::Error, "Permission denied to file %s" % file
- end
-
- @values = Hash.new { |names, name|
- names[name] = {}
- }
-
- # Get rid of the values set by the file, keeping cli values.
- self.clear(true)
-
- section = "puppet"
- metas = %w{owner group mode}
- values = Hash.new { |hash, key| hash[key] = {} }
- text.split(/\n/).each { |line|
- case line
- when /^\[(\w+)\]$/: section = $1 # Section names
- when /^\s*#/: next # Skip comments
- when /^\s*$/: next # Skip blanks
- when /^\s*(\w+)\s*=\s*(.+)$/: # settings
- var = $1.intern
- if var == :mode
- value = $2
- else
- value = munge_value($2)
- end
-
- # Only warn if we don't know what this config var is. This
- # prevents exceptions later on.
- unless @config.include?(var) or metas.include?(var.to_s)
- Puppet.warning "Discarded unknown configuration parameter %s" % var.inspect
- next # Skip this line.
- end
-
- # Mmm, "special" attributes
- if metas.include?(var.to_s)
- unless values.include?(section)
- values[section] = {}
- end
- values[section][var.to_s] = value
-
- # If the parameter is valid, then set it.
- if section == Puppet[:name] and @config.include?(var)
- #@config[var].value = value
- @values[:main][var] = value
- end
- next
- end
-
- # Don't override set parameters, since the file is parsed
- # after cli arguments are handled.
- unless @config.include?(var) and @config[var].setbycli
- Puppet.debug "%s: Setting %s to '%s'" % [section, var, value]
- @values[:main][var] = value
- end
- @config[var].section = symbolize(section)
-
- metas.each { |meta|
- if values[section][meta]
- if @config[var].respond_to?(meta + "=")
- @config[var].send(meta + "=", values[section][meta])
- end
- end
- }
- else
- raise Puppet::Error, "Could not match line %s" % line
- end
- }
- end
-
# Create a new element. The value is passed in because it's used to determine
# what kind of element we're creating, but the value itself might be either
# a default or a value, so we can't actually assign it.
@@ -509,19 +404,19 @@ class Puppet::Util::Settings
objects += add_user_resources(section, obj, done)
end
+ value = obj.value
+
# Only files are convertable to transportable resources.
- if obj.respond_to? :to_transportable
- next if value(obj.name) =~ /^\/dev/
- transobjects = obj.to_transportable
- transobjects = [transobjects] unless transobjects.is_a? Array
- transobjects.each do |trans|
- # transportable could return nil
- next unless trans
- unless done[:file].include? trans.name
- @created << trans.name
- objects << trans
- done[:file][trans.name] = trans
- end
+ next unless obj.respond_to? :to_transportable and transobjects = obj.to_transportable
+
+ transobjects = [transobjects] unless transobjects.is_a? Array
+ transobjects.each do |trans|
+ # transportable could return nil
+ next unless trans
+ unless done[:file].include? trans.name
+ @created << trans.name
+ objects << trans
+ done[:file][trans.name] = trans
end
end
end
@@ -670,23 +565,36 @@ Generated on #{Time.now}.
# you can 'use' a section as many times as you want.
def use(*sections)
@@sync.synchronize do # yay, thread-safe
- unless defined? @used
- @used = []
- end
+ sections = sections.reject { |s| @used.include?(s.to_sym) }
+
+ return if sections.empty?
bucket = to_transportable(*sections)
- config = bucket.to_catalog
- config.host_config = false
- config.apply do |transaction|
- if failures = transaction.any_failed?
- raise "Could not configure for running; got %s failure(s)" % failures
+ begin
+ catalog = bucket.to_catalog
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not create resources for managing Puppet's files and directories: %s" % detail
+
+ # We need some way to get rid of any resources created during the catalog creation
+ # but not cleaned up.
+ return
+ end
+
+ begin
+ catalog.host_config = false
+ catalog.apply do |transaction|
+ if failures = transaction.any_failed?
+ raise "Could not configure for running; got %s failure(s)" % failures
+ end
end
+ ensure
+ catalog.clear
end
- config.clear
sections.each { |s| @used << s }
- @used.uniq
+ @used.uniq!
end
end
@@ -737,49 +645,15 @@ Generated on #{Time.now}.
end
# Open a file with the appropriate user, group, and mode
- def write(default, *args)
- obj = nil
- unless obj = @config[default]
- raise ArgumentError, "Unknown default %s" % default
- end
-
- unless obj.is_a? CFile
- raise ArgumentError, "Default %s is not a file" % default
- end
-
- chown = nil
- if Puppet::Util::SUIDManager.uid == 0
- chown = [obj.owner, obj.group]
- else
- chown = [nil, nil]
- end
- Puppet::Util::SUIDManager.asuser(*chown) do
- mode = obj.mode || 0640
-
- if args.empty?
- args << "w"
- end
-
- args << mode
-
- File.open(value(obj.name), *args) do |file|
- yield file
- end
- end
+ def write(default, *args, &bloc)
+ obj = get_config_file_default(default)
+ writesub(default, value(obj.name), *args, &bloc)
end
# Open a non-default file under a default dir with the appropriate user,
# group, and mode
- def writesub(default, file, *args)
- obj = nil
- unless obj = @config[default]
- raise ArgumentError, "Unknown default %s" % default
- end
-
- unless obj.is_a? CFile
- raise ArgumentError, "Default %s is not a file" % default
- end
-
+ def writesub(default, file, *args, &bloc)
+ obj = get_config_file_default(default)
chown = nil
if Puppet::Util::SUIDManager.uid == 0
chown = [obj.owner, obj.group]
@@ -804,8 +678,51 @@ Generated on #{Time.now}.
end
end
+ def readwritelock(default, *args, &bloc)
+ file = value(get_config_file_default(default).name)
+ tmpfile = file + ".tmp"
+ sync = Sync.new
+ unless FileTest.directory?(File.dirname(tmpfile))
+ raise Puppet::DevError, "Cannot create %s; directory %s does not exist" %
+ [file, File.dirname(file)]
+ end
+
+ sync.synchronize(Sync::EX) do
+ File.open(file, "r+", 0600) do |rf|
+ rf.lock_exclusive do
+ if File.exist?(tmpfile)
+ raise Puppet::Error, ".tmp file already exists for %s; Aborting locked write. Check the .tmp file and delete if appropriate" %
+ [file]
+ end
+
+ writesub(default, tmpfile, *args, &bloc)
+
+ begin
+ File.rename(tmpfile, file)
+ rescue => detail
+ Puppet.err "Could not rename %s to %s: %s" %
+ [file, tmpfile, detail]
+ end
+ end
+ end
+ end
+ end
+
private
+ def get_config_file_default(default)
+ obj = nil
+ unless obj = @config[default]
+ raise ArgumentError, "Unknown default %s" % default
+ end
+
+ unless obj.is_a? CFile
+ raise ArgumentError, "Default %s is not a file" % default
+ end
+
+ return obj
+ end
+
# Create the transportable objects for users and groups.
def add_user_resources(section, obj, done)
resources = []
@@ -1124,7 +1041,7 @@ Generated on #{Time.now}.
# the variable 'dir', or adding a slash at the end.
def munge(value)
# If it's not a fully qualified path...
- if value.is_a?(String) and value !~ /^\$/ and value !~ /^\//
+ if value.is_a?(String) and value !~ /^\$/ and value !~ /^\// and value != 'false'
# Make it one
value = File.join(Dir.getwd, value)
end
@@ -1153,12 +1070,15 @@ Generated on #{Time.now}.
def to_transportable
type = self.type
return nil unless type
- path = @parent.value(self.name).split(File::SEPARATOR)
- path.shift # remove the leading nil
- objects = []
path = self.value
+ return nil unless path.is_a?(String)
+ return nil if path =~ /^\/dev/
+ return nil if Puppet::Type.type(:file)[path] # skip files that are in our global resource list.
+
+ objects = []
+
# Skip plain files that don't exist, since we won't be managing them anyway.
return nil unless self.name.to_s =~ /dir$/ or File.exist?(path) or self.create
obj = Puppet::TransObject.new(path, "file")
diff --git a/lib/puppet/util/tagging.rb b/lib/puppet/util/tagging.rb
new file mode 100644
index 000000000..e06e13a2c
--- /dev/null
+++ b/lib/puppet/util/tagging.rb
@@ -0,0 +1,40 @@
+# Created on 2008-01-19
+# Copyright Luke Kanies
+
+# A common module to handle tagging.
+module Puppet::Util::Tagging
+ # Add a tag to our current list. These tags will be added to all
+ # of the objects contained in this scope.
+ def tag(*ary)
+ @tags ||= []
+
+ qualified = []
+
+ ary.collect { |tag| tag.to_s.downcase }.each do |tag|
+ fail(Puppet::ParseError, "Invalid tag %s" % tag.inspect) unless valid_tag?(tag)
+ qualified << tag if tag.include?("::")
+ @tags << tag unless @tags.include?(tag)
+ end
+
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ qualified.collect { |name| x = name.split("::") }.flatten.each { |tag| @tags << tag unless @tags.include?(tag) }
+ end
+
+ # Are we tagged with the provided tag?
+ def tagged?(tag)
+ defined?(@tags) and @tags.include?(tag.to_s)
+ end
+
+ # Return a copy of the tag list, so someone can't ask for our tags
+ # and then modify them.
+ def tags
+ @tags ||= []
+ @tags.dup
+ end
+
+ private
+
+ def valid_tag?(tag)
+ tag =~ /^\w[-\w:.]*$/
+ end
+end