puppet 0.24.5 → 0.24.6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of puppet might be problematic. Click here for more details.
- data/CHANGELOG +206 -0
- data/Rakefile +53 -0
- data/bin/filebucket +0 -0
- data/bin/puppet +32 -11
- data/bin/puppetca +1 -0
- data/bin/puppetd +0 -0
- data/bin/puppetdoc +0 -0
- data/bin/puppetmasterd +0 -0
- data/bin/puppetrun +16 -8
- data/bin/ralsh +0 -0
- data/conf/debian/rules +0 -0
- data/conf/gentoo/init.d/puppetmaster +0 -0
- data/conf/osx/PackageInfo.plist +36 -0
- data/conf/osx/createpackage.sh +167 -0
- data/conf/osx/preflight +12 -0
- data/conf/redhat/client.init +1 -1
- data/conf/redhat/puppet.spec +34 -6
- data/conf/redhat/server.init +42 -7
- data/conf/redhat/server.sysconfig +22 -0
- data/conf/solaris/smf/svc-puppetd +0 -0
- data/conf/solaris/smf/svc-puppetmasterd +0 -0
- data/examples/etc/init.d/sleeper +0 -0
- data/examples/mac_dscl.pp +0 -0
- data/examples/mac_dscl_revert.pp +0 -0
- data/examples/mac_netinfo.pp +0 -0
- data/examples/mac_pkgdmg.pp +0 -0
- data/ext/bin/sleeper +0 -0
- data/ext/module_puppet +0 -0
- data/ext/nagios/check_puppet.rb +0 -0
- data/ext/passenger/README +63 -0
- data/ext/passenger/apache2.conf +29 -0
- data/ext/passenger/config.ru +40 -0
- data/ext/puppet-test +0 -0
- data/ext/puppetlast +6 -31
- data/ext/puppetstoredconfigclean.rb +87 -0
- data/install.rb +75 -20
- data/lib/puppet.rb +1 -1
- data/lib/puppet/daemon.rb +0 -0
- data/lib/puppet/defaults.rb +3 -7
- data/lib/puppet/external/base64.rb +0 -0
- data/lib/puppet/external/nagios.rb +0 -0
- data/lib/puppet/external/nagios/base.rb +0 -0
- data/lib/puppet/file_serving/fileset.rb +2 -2
- data/lib/puppet/file_serving/metadata.rb +3 -3
- data/lib/puppet/indirector/facts/facter.rb +3 -2
- data/lib/puppet/indirector/yaml.rb +10 -1
- data/lib/puppet/module.rb +36 -12
- data/lib/puppet/network/authstore.rb +0 -0
- data/lib/puppet/network/client/master.rb +12 -11
- data/lib/puppet/network/handler/filebucket.rb +0 -0
- data/lib/puppet/network/handler/fileserver.rb +38 -46
- data/lib/puppet/network/handler/master.rb +1 -1
- data/lib/puppet/network/handler/report.rb +0 -0
- data/lib/puppet/network/handler/resource.rb +0 -0
- data/lib/puppet/network/handler/runner.rb +0 -0
- data/lib/puppet/network/http_server/rack.rb +148 -0
- data/lib/puppet/network/rights.rb +0 -0
- data/lib/puppet/network/xmlrpc/client.rb +5 -5
- data/lib/puppet/node.rb +5 -9
- data/lib/puppet/node/environment.rb +1 -17
- data/lib/puppet/node/facts.rb +0 -0
- data/lib/puppet/parameter.rb +1 -28
- data/lib/puppet/parser/ast.rb +6 -0
- data/lib/puppet/parser/ast/arithmetic_operator.rb +41 -0
- data/lib/puppet/parser/ast/boolean_operator.rb +48 -0
- data/lib/puppet/parser/ast/collexpr.rb +6 -1
- data/lib/puppet/parser/ast/comparison_operator.rb +37 -0
- data/lib/puppet/parser/ast/minus.rb +23 -0
- data/lib/puppet/parser/ast/nop.rb +11 -0
- data/lib/puppet/parser/ast/not.rb +19 -0
- data/lib/puppet/parser/ast/resource_override.rb +23 -16
- data/lib/puppet/parser/ast/resource_reference.rb +10 -6
- data/lib/puppet/parser/ast/vardef.rb +2 -2
- data/lib/puppet/parser/collector.rb +2 -1
- data/lib/puppet/parser/functions.rb +7 -217
- data/lib/puppet/parser/functions/defined.rb +27 -0
- data/lib/puppet/parser/functions/fail.rb +4 -0
- data/lib/puppet/parser/functions/file.rb +21 -0
- data/lib/puppet/parser/functions/fqdn_rand.rb +15 -0
- data/lib/puppet/parser/functions/generate.rb +35 -0
- data/lib/puppet/parser/functions/include.rb +26 -0
- data/lib/puppet/parser/functions/realize.rb +14 -0
- data/lib/puppet/parser/functions/search.rb +7 -0
- data/lib/puppet/parser/functions/sha1.rb +6 -0
- data/lib/puppet/parser/functions/tag.rb +6 -0
- data/lib/puppet/parser/functions/tagged.rb +18 -0
- data/lib/puppet/parser/functions/template.rb +22 -0
- data/lib/puppet/parser/lexer.rb +15 -5
- data/lib/puppet/parser/parser.rb +1073 -715
- data/lib/puppet/parser/parser_support.rb +18 -13
- data/lib/puppet/parser/resource.rb +1 -1
- data/lib/puppet/parser/resource/param.rb +10 -2
- data/lib/puppet/parser/scope.rb +63 -5
- data/lib/puppet/parser/templatewrapper.rb +61 -15
- data/lib/puppet/property.rb +7 -1
- data/lib/puppet/property/keyvalue.rb +96 -0
- data/lib/puppet/property/list.rb +78 -0
- data/lib/puppet/provider/confine.rb +1 -1
- data/lib/puppet/provider/confine/variable.rb +10 -1
- data/lib/puppet/provider/cron/crontab.rb +0 -0
- data/lib/puppet/provider/mailalias/aliases.rb +0 -0
- data/lib/puppet/provider/maillist/mailman.rb +0 -0
- data/lib/puppet/provider/mount/parsed.rb +0 -0
- data/lib/puppet/provider/nameservice.rb +24 -39
- data/lib/puppet/provider/nameservice/directoryservice.rb +12 -3
- data/lib/puppet/provider/nameservice/netinfo.rb +12 -2
- data/lib/puppet/provider/nameservice/objectadd.rb +1 -10
- data/lib/puppet/provider/package/appdmg.rb +1 -1
- data/lib/puppet/provider/package/apple.rb +0 -0
- data/lib/puppet/provider/package/apt.rb +14 -21
- data/lib/puppet/provider/package/aptitude.rb +0 -0
- data/lib/puppet/provider/package/blastwave.rb +2 -0
- data/lib/puppet/provider/package/darwinport.rb +0 -0
- data/lib/puppet/provider/package/dpkg.rb +33 -51
- data/lib/puppet/provider/package/fink.rb +1 -1
- data/lib/puppet/provider/package/freebsd.rb +0 -0
- data/lib/puppet/provider/package/gem.rb +0 -0
- data/lib/puppet/provider/package/hpux.rb +46 -0
- data/lib/puppet/provider/package/openbsd.rb +0 -0
- data/lib/puppet/provider/package/pkgdmg.rb +1 -1
- data/lib/puppet/provider/package/portage.rb +3 -1
- data/lib/puppet/provider/package/ports.rb +3 -3
- data/lib/puppet/provider/package/rpm.rb +8 -1
- data/lib/puppet/provider/package/rug.rb +2 -2
- data/lib/puppet/provider/package/sun.rb +2 -0
- data/lib/puppet/provider/package/sunfreeware.rb +3 -0
- data/lib/puppet/provider/package/yum.rb +24 -17
- data/lib/puppet/provider/package/yumhelper.py +92 -11
- data/lib/puppet/provider/parsedfile.rb +0 -0
- data/lib/puppet/provider/port/parsed.rb +0 -0
- data/lib/puppet/provider/selboolean/getsetsebool.rb +47 -0
- data/lib/puppet/provider/selmodule/semodule.rb +143 -0
- data/lib/puppet/provider/service/base.rb +0 -0
- data/lib/puppet/provider/service/daemontools.rb +154 -0
- data/lib/puppet/provider/service/debian.rb +1 -1
- data/lib/puppet/provider/service/freebsd.rb +2 -0
- data/lib/puppet/provider/service/gentoo.rb +2 -0
- data/lib/puppet/provider/service/init.rb +0 -0
- data/lib/puppet/provider/service/redhat.rb +1 -1
- data/lib/puppet/provider/service/runit.rb +93 -0
- data/lib/puppet/provider/service/smf.rb +2 -0
- data/lib/puppet/provider/ssh_authorized_key/parsed.rb +7 -1
- data/lib/puppet/provider/sshkey/parsed.rb +0 -0
- data/lib/puppet/provider/user/hpux.rb +30 -0
- data/lib/puppet/provider/user/user_role_add.rb +156 -0
- data/lib/puppet/provider/user/useradd.rb +23 -14
- data/lib/puppet/rails/database/002_remove_duplicated_index_on_all_tables.rb +17 -0
- data/lib/puppet/rails/database/schema.rb +0 -8
- data/lib/puppet/rails/resource.rb +6 -6
- data/lib/puppet/reference/configuration.rb +0 -7
- data/lib/puppet/reports.rb +0 -0
- data/lib/puppet/reports/rrdgraph.rb +3 -2
- data/lib/puppet/sslcertificates.rb +0 -0
- data/lib/puppet/sslcertificates/inventory.rb +3 -2
- data/lib/puppet/sslcertificates/support.rb +3 -0
- data/lib/puppet/transaction/report.rb +1 -7
- data/lib/puppet/transportable.rb +10 -7
- data/lib/puppet/type.rb +2110 -14
- data/lib/puppet/type/cron.rb +0 -0
- data/lib/puppet/type/exec.rb +0 -0
- data/lib/puppet/type/file.rb +12 -2
- data/lib/puppet/type/file/checksum.rb +4 -0
- data/lib/puppet/type/file/content.rb +0 -0
- data/lib/puppet/type/file/ensure.rb +0 -0
- data/lib/puppet/type/file/group.rb +30 -43
- data/lib/puppet/type/file/mode.rb +0 -0
- data/lib/puppet/type/file/owner.rb +0 -0
- data/lib/puppet/type/file/selcontext.rb +104 -0
- data/lib/puppet/type/file/source.rb +0 -0
- data/lib/puppet/type/file/type.rb +0 -0
- data/lib/puppet/type/filebucket.rb +0 -0
- data/lib/puppet/type/group.rb +0 -8
- data/lib/puppet/type/host.rb +0 -0
- data/lib/puppet/type/mailalias.rb +0 -0
- data/lib/puppet/type/maillist.rb +0 -0
- data/lib/puppet/type/mount.rb +0 -0
- data/lib/puppet/type/package.rb +2 -2
- data/lib/puppet/type/port.rb +0 -0
- data/lib/puppet/type/schedule.rb +0 -0
- data/lib/puppet/type/selboolean.rb +31 -0
- data/lib/puppet/type/selmodule.rb +54 -0
- data/lib/puppet/type/ssh_authorized_key.rb +3 -3
- data/lib/puppet/type/sshkey.rb +0 -0
- data/lib/puppet/type/tidy.rb +0 -0
- data/lib/puppet/type/user.rb +153 -137
- data/lib/puppet/type/yumrepo.rb +18 -2
- data/lib/puppet/type/zone.rb +5 -1
- data/lib/puppet/util.rb +7 -7
- data/lib/puppet/util/filetype.rb +7 -0
- data/lib/puppet/util/instance_loader.rb +0 -0
- data/lib/puppet/util/ldap/connection.rb +11 -1
- data/lib/puppet/util/ldap/manager.rb +1 -1
- data/lib/puppet/util/loadedfile.rb +0 -0
- data/lib/puppet/util/log.rb +42 -43
- data/lib/puppet/util/metric.rb +23 -9
- data/lib/puppet/util/posix.rb +69 -18
- data/lib/puppet/util/selinux.rb +139 -0
- data/lib/puppet/util/settings.rb +5 -7
- data/lib/puppet/util/user_attr.rb +21 -0
- data/test/certmgr/ca.rb +0 -0
- data/test/certmgr/certmgr.rb +0 -0
- data/test/certmgr/inventory.rb +0 -0
- data/test/certmgr/support.rb +0 -0
- data/test/data/providers/ssh_authorized_key/parsed/authorized_keys1 +3 -0
- data/test/data/snippets/append.pp +11 -0
- data/test/data/snippets/arithmetic_expression.pp +8 -0
- data/test/data/snippets/arraytrailingcomma.pp +3 -0
- data/test/data/snippets/emptyifelse.pp +9 -0
- data/test/data/snippets/funccomma.pp +5 -0
- data/test/data/snippets/ifexpression.rb +6 -0
- data/test/data/snippets/subclass_name_duplication.pp +0 -0
- data/test/executables/filebucket.rb +0 -0
- data/test/executables/puppetbin.rb +0 -0
- data/test/executables/puppetca.rb +0 -0
- data/test/executables/puppetd.rb +0 -0
- data/test/executables/puppetmasterd.rb +0 -0
- data/test/executables/puppetmodule.rb +0 -0
- data/test/language/ast.rb +0 -0
- data/test/language/ast/casestatement.rb +0 -0
- data/test/language/ast/resource.rb +0 -0
- data/test/language/ast/resource_reference.rb +0 -28
- data/test/language/ast/selector.rb +0 -0
- data/test/language/ast/variable.rb +0 -0
- data/test/language/functions.rb +91 -12
- data/test/language/parser.rb +21 -0
- data/test/language/resource.rb +0 -0
- data/test/language/scope.rb +28 -0
- data/test/language/snippets.rb +14 -0
- data/test/language/transportable.rb +0 -0
- data/test/lib/puppettest.rb +0 -0
- data/test/lib/puppettest/reporttesting.rb +0 -2
- data/test/lib/puppettest/runnable_test.rb +2 -0
- data/test/lib/puppettest/support/resources.rb +0 -0
- data/test/network/authconfig.rb +0 -0
- data/test/network/authorization.rb +0 -0
- data/test/network/authstore.rb +0 -0
- data/test/network/client/ca.rb +0 -0
- data/test/network/client/client.rb +0 -0
- data/test/network/client/dipper.rb +0 -0
- data/test/network/client/master.rb +2 -6
- data/test/network/client/resource.rb +0 -0
- data/test/network/client_request.rb +0 -0
- data/test/network/daemon.rb +0 -0
- data/test/network/handler/bucket.rb +0 -0
- data/test/network/handler/ca.rb +0 -0
- data/test/network/handler/fileserver.rb +8 -0
- data/test/network/handler/handler.rb +0 -0
- data/test/network/handler/master.rb +3 -1
- data/test/network/handler/report.rb +0 -0
- data/test/network/handler/resource.rb +0 -0
- data/test/network/handler/runner.rb +0 -0
- data/test/network/rights.rb +0 -0
- data/test/network/server/mongrel_test.rb +0 -0
- data/test/network/server/webrick.rb +0 -0
- data/test/network/xmlrpc/client.rb +0 -0
- data/test/network/xmlrpc/processor.rb +0 -0
- data/test/network/xmlrpc/server.rb +0 -0
- data/test/network/xmlrpc/webrick_servlet.rb +0 -0
- data/test/other/dsl.rb +0 -0
- data/test/other/events.rb +0 -0
- data/test/other/overrides.rb +0 -0
- data/test/other/provider.rb +0 -0
- data/test/other/puppet.rb +0 -0
- data/test/other/relationships.rb +0 -0
- data/test/other/report.rb +2 -4
- data/test/other/transactions.rb +1 -1
- data/test/puppet/conffiles.rb +0 -0
- data/test/puppet/defaults.rb +0 -0
- data/test/puppet/errortest.rb +0 -0
- data/test/puppet/tc_suidmanager.rb +0 -0
- data/test/rails/ast.rb +0 -0
- data/test/rails/configuration.rb +0 -0
- data/test/rails/host.rb +0 -0
- data/test/rails/rails.rb +0 -0
- data/test/rails/railsparameter.rb +0 -0
- data/test/rails/railsresource.rb +0 -0
- data/test/ral/manager/attributes.rb +0 -0
- data/test/ral/manager/instances.rb +0 -0
- data/test/ral/manager/manager.rb +0 -0
- data/test/ral/manager/provider.rb +0 -0
- data/test/ral/manager/type.rb +0 -0
- data/test/ral/providers/cron/crontab.rb +0 -0
- data/test/ral/providers/group.rb +14 -13
- data/test/ral/providers/host/netinfo.rb +0 -0
- data/test/ral/providers/host/parsed.rb +0 -0
- data/test/ral/providers/mailalias/aliases.rb +0 -0
- data/test/ral/providers/mount/netinfo.rb +0 -0
- data/test/ral/providers/nameservice.rb +0 -0
- data/test/ral/providers/package.rb +0 -31
- data/test/ral/providers/package/aptitude.rb +1 -2
- data/test/ral/providers/package/aptrpm.rb +2 -2
- data/test/ral/providers/parsedfile.rb +0 -0
- data/test/ral/providers/port/parsed.rb +0 -0
- data/test/ral/providers/provider.rb +0 -0
- data/test/ral/providers/service/base.rb +0 -0
- data/test/ral/providers/service/debian.rb +0 -0
- data/test/ral/providers/sshkey/parsed.rb +0 -0
- data/test/ral/providers/user.rb +8 -8
- data/test/ral/providers/user/useradd.rb +0 -0
- data/test/ral/type/basic.rb +0 -0
- data/test/ral/type/cron.rb +0 -0
- data/test/ral/type/exec.rb +0 -0
- data/test/ral/type/file.rb +0 -0
- data/test/ral/type/file/target.rb +0 -0
- data/test/ral/type/filebucket.rb +0 -0
- data/test/ral/type/fileignoresource.rb +0 -0
- data/test/ral/type/filesources.rb +1 -3
- data/test/ral/type/group.rb +0 -0
- data/test/ral/type/host.rb +0 -0
- data/test/ral/type/mailalias.rb +1 -2
- data/test/ral/type/parameter.rb +0 -0
- data/test/ral/type/port.rb +0 -0
- data/test/ral/type/property.rb +0 -0
- data/test/ral/type/resources.rb +0 -0
- data/test/ral/type/service.rb +0 -0
- data/test/ral/type/sshkey.rb +0 -0
- data/test/ral/type/tidy.rb +0 -0
- data/test/ral/type/user.rb +0 -50
- data/test/ral/type/yumrepo.rb +7 -1
- data/test/ral/type/zone.rb +0 -0
- data/test/test +0 -0
- data/test/util/autoload.rb +0 -0
- data/test/util/classgen.rb +0 -0
- data/test/util/execution.rb +0 -0
- data/test/util/features.rb +0 -0
- data/test/util/fileparsing.rb +0 -0
- data/test/util/filetype.rb +0 -0
- data/test/util/inifile.rb +0 -0
- data/test/util/instance_loader.rb +0 -0
- data/test/util/log.rb +0 -59
- data/test/util/metrics.rb +0 -0
- data/test/util/package.rb +0 -0
- data/test/util/pidlock.rb +0 -0
- data/test/util/settings.rb +0 -0
- data/test/util/storage.rb +0 -0
- data/test/util/subclass_loader.rb +0 -0
- data/test/util/utiltest.rb +0 -0
- metadata +54 -19
- data/lib/puppet/metatype/attributes.rb +0 -685
- data/lib/puppet/metatype/closure.rb +0 -49
- data/lib/puppet/metatype/container.rb +0 -50
- data/lib/puppet/metatype/evaluation.rb +0 -163
- data/lib/puppet/metatype/instances.rb +0 -305
- data/lib/puppet/metatype/metaparams.rb +0 -423
- data/lib/puppet/metatype/providers.rb +0 -247
- data/lib/puppet/metatype/relationships.rb +0 -115
- data/lib/puppet/metatype/schedules.rb +0 -33
- data/lib/puppet/metatype/tags.rb +0 -38
- data/lib/puppet/util/plist.rb +0 -23
- data/lib/puppet/util/plist/generator.rb +0 -225
- data/lib/puppet/util/plist/parser.rb +0 -226
- data/test/ral/providers/package/apt.rb +0 -169
- data/test/ral/providers/package/dpkg.rb +0 -64
- data/test/util/posixtest.rb +0 -169
@@ -23,8 +23,22 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
|
|
23
23
|
has_feature :manages_passwords
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
26
|
+
def check_allow_dup
|
27
|
+
@resource.allowdupe? ? ["-o"] : []
|
28
|
+
end
|
29
|
+
|
30
|
+
def check_manage_home
|
31
|
+
cmd = []
|
32
|
+
if @resource.managehome?
|
33
|
+
cmd << "-m"
|
34
|
+
elsif %w{Fedora RedHat}.include?(Facter.value("operatingsystem"))
|
35
|
+
cmd << "-M"
|
36
|
+
end
|
37
|
+
cmd
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_properties
|
41
|
+
cmd = []
|
28
42
|
Puppet::Type.type(:user).validproperties.each do |property|
|
29
43
|
next if property == :ensure
|
30
44
|
# the value needs to be quoted, mostly because -c might
|
@@ -33,20 +47,15 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ
|
|
33
47
|
cmd << flag(property) << value
|
34
48
|
end
|
35
49
|
end
|
50
|
+
cmd
|
51
|
+
end
|
36
52
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
cmd << "-m"
|
43
|
-
elsif %w{Fedora RedHat}.include?(Facter.value("operatingsystem"))
|
44
|
-
cmd << "-M"
|
45
|
-
end
|
46
|
-
|
53
|
+
def addcmd
|
54
|
+
cmd = [command(:add)]
|
55
|
+
cmd += add_properties
|
56
|
+
cmd += check_allow_dup
|
57
|
+
cmd += check_manage_home
|
47
58
|
cmd << @resource[:name]
|
48
|
-
|
49
|
-
cmd
|
50
59
|
end
|
51
60
|
|
52
61
|
# Retrieve the password using the Shadow Password library
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class RemoveDuplicatedIndexOnAllTables < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
ActiveRecord::Base.connection.tables.each do |t|
|
4
|
+
if ActiveRecord::Base.connection.indexes(t).collect {|c| c.columns}.include?("id")
|
5
|
+
remove_index t.to_s, :id
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down
|
11
|
+
ActiveRecord::Base.connection.tables.each do |t|
|
12
|
+
unless ActiveRecord::Base.connection.indexes(t).collect {|c| c.columns}.include?("id")
|
13
|
+
add_index t.to_s, :id, :integer => true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -16,7 +16,6 @@ class Puppet::Rails::Schema
|
|
16
16
|
t.column :updated_at, :datetime
|
17
17
|
t.column :created_at, :datetime
|
18
18
|
end
|
19
|
-
add_index :resources, :id, :integer => true
|
20
19
|
add_index :resources, :host_id, :integer => true
|
21
20
|
add_index :resources, :source_file_id, :integer => true
|
22
21
|
|
@@ -34,7 +33,6 @@ class Puppet::Rails::Schema
|
|
34
33
|
t.column :updated_at, :datetime
|
35
34
|
t.column :created_at, :datetime
|
36
35
|
end
|
37
|
-
add_index :source_files, :id, :integer => true
|
38
36
|
add_index :source_files, :filename
|
39
37
|
|
40
38
|
create_table :resource_tags do |t|
|
@@ -43,7 +41,6 @@ class Puppet::Rails::Schema
|
|
43
41
|
t.column :updated_at, :datetime
|
44
42
|
t.column :created_at, :datetime
|
45
43
|
end
|
46
|
-
add_index :resource_tags, :id, :integer => true
|
47
44
|
add_index :resource_tags, :resource_id, :integer => true
|
48
45
|
add_index :resource_tags, :puppet_tag_id, :integer => true
|
49
46
|
|
@@ -65,7 +62,6 @@ class Puppet::Rails::Schema
|
|
65
62
|
t.column :source_file_id, :integer
|
66
63
|
t.column :created_at, :datetime
|
67
64
|
end
|
68
|
-
add_index :hosts, :id, :integer => true
|
69
65
|
add_index :hosts, :source_file_id, :integer => true
|
70
66
|
add_index :hosts, :name
|
71
67
|
|
@@ -74,7 +70,6 @@ class Puppet::Rails::Schema
|
|
74
70
|
t.column :updated_at, :datetime
|
75
71
|
t.column :created_at, :datetime
|
76
72
|
end
|
77
|
-
add_index :fact_names, :id, :integer => true
|
78
73
|
add_index :fact_names, :name
|
79
74
|
|
80
75
|
create_table :fact_values do |t|
|
@@ -84,7 +79,6 @@ class Puppet::Rails::Schema
|
|
84
79
|
t.column :updated_at, :datetime
|
85
80
|
t.column :created_at, :datetime
|
86
81
|
end
|
87
|
-
add_index :fact_values, :id, :integer => true
|
88
82
|
add_index :fact_values, :fact_name_id, :integer => true
|
89
83
|
add_index :fact_values, :host_id, :integer => true
|
90
84
|
|
@@ -96,7 +90,6 @@ class Puppet::Rails::Schema
|
|
96
90
|
t.column :updated_at, :datetime
|
97
91
|
t.column :created_at, :datetime
|
98
92
|
end
|
99
|
-
add_index :param_values, :id, :integer => true
|
100
93
|
add_index :param_values, :param_name_id, :integer => true
|
101
94
|
add_index :param_values, :resource_id, :integer => true
|
102
95
|
|
@@ -105,7 +98,6 @@ class Puppet::Rails::Schema
|
|
105
98
|
t.column :updated_at, :datetime
|
106
99
|
t.column :created_at, :datetime
|
107
100
|
end
|
108
|
-
add_index :param_names, :id, :integer => true
|
109
101
|
add_index :param_names, :name
|
110
102
|
end
|
111
103
|
end
|
@@ -6,12 +6,12 @@ require 'puppet/util/rails/collection_merger'
|
|
6
6
|
class Puppet::Rails::Resource < ActiveRecord::Base
|
7
7
|
include Puppet::Util::CollectionMerger
|
8
8
|
|
9
|
-
has_many :param_values, :dependent => :destroy
|
10
|
-
has_many :param_names, :through => :param_values
|
9
|
+
has_many :param_values, :dependent => :destroy, :class_name => "Puppet::Rails::ParamValue"
|
10
|
+
has_many :param_names, :through => :param_values, :class_name => "Puppet::Rails::ParamName"
|
11
|
+
|
12
|
+
has_many :resource_tags, :dependent => :destroy, :class_name => "Puppet::Rails::ResourceTag"
|
13
|
+
has_many :puppet_tags, :through => :resource_tags, :class_name => "Puppet::Rails::PuppetTag"
|
11
14
|
|
12
|
-
has_many :resource_tags, :dependent => :destroy
|
13
|
-
has_many :puppet_tags, :through => :resource_tags
|
14
|
-
|
15
15
|
belongs_to :source_file
|
16
16
|
belongs_to :host
|
17
17
|
|
@@ -82,7 +82,7 @@ class Puppet::Rails::Resource < ActiveRecord::Base
|
|
82
82
|
end
|
83
83
|
|
84
84
|
def ref
|
85
|
-
"%s[%s]" % [self[:restype].capitalize, self[:title]]
|
85
|
+
"%s[%s]" % [self[:restype].split("::").collect { |s| s.capitalize }.join("::"), self[:title]]
|
86
86
|
end
|
87
87
|
|
88
88
|
# Convert our object to a resource. Do not retain whether the object
|
@@ -49,10 +49,6 @@ On The Command-Line
|
|
49
49
|
+++++++++++++++++++
|
50
50
|
Every Puppet executable (with the exception of ``puppetdoc``) accepts all of
|
51
51
|
the parameters below, but not all of the arguments make sense for every executable.
|
52
|
-
Each parameter has a section listed with it in parentheses; often, that section
|
53
|
-
will map to an executable (e.g., ``puppetd``), in which case it probably only
|
54
|
-
makes sense for that one executable. If ``main`` is listed as the section,
|
55
|
-
it is most likely an option that is valid for everyone.
|
56
52
|
|
57
53
|
I have tried to be as thorough as possible in the descriptions of the
|
58
54
|
arguments, so it should be obvious whether an argument is appropriate or not.
|
@@ -121,9 +117,6 @@ Note that this invocation will replace the contents of any pre-existing
|
|
121
117
|
`puppet.conf` file, so make a backup of your present config if it contains
|
122
118
|
valuable information.
|
123
119
|
|
124
|
-
All parameters will be under a single section heading matching the name of
|
125
|
-
the process used to generate the configuraiton ('puppetd', in this case).
|
126
|
-
|
127
120
|
Like the `--genconfig` argument, the executables also accept a `--genmanifest`
|
128
121
|
argument, which will generate a manifest that can be used to manage all of
|
129
122
|
Puppet's directories and files and prints it to standard output. This can
|
data/lib/puppet/reports.rb
CHANGED
File without changes
|
@@ -90,8 +90,9 @@ Puppet::Reports.register_report(:rrdgraph) do
|
|
90
90
|
of.puts "<html><head><title>Report graphs for %s</title></head><body>" %
|
91
91
|
host
|
92
92
|
files.each do |file|
|
93
|
-
of.puts "<a href='
|
94
|
-
File.basename(file)
|
93
|
+
of.puts "<a href='%s'>%s</a><br/>" %
|
94
|
+
[File.basename(file),
|
95
|
+
File.basename(file).sub(".html",'').capitalize]
|
95
96
|
end
|
96
97
|
of.puts "</body></html>"
|
97
98
|
end
|
File without changes
|
@@ -7,8 +7,9 @@ module Puppet::SSLCertificates
|
|
7
7
|
# If no inventory exists yet, build an inventory and list all the
|
8
8
|
# certificates that have been signed so far
|
9
9
|
def self.add(cert)
|
10
|
-
|
11
|
-
|
10
|
+
inited = false
|
11
|
+
if FileTest.exists?(Puppet[:cert_inventory])
|
12
|
+
inited = true
|
12
13
|
end
|
13
14
|
|
14
15
|
Puppet.settings.write(:cert_inventory, "a") do |f|
|
@@ -133,6 +133,9 @@ module Puppet::SSLCertificates::Support
|
|
133
133
|
#return nil unless FileTest.directory?(dir)
|
134
134
|
|
135
135
|
raise ArgumentError, "Tried to fix SSL files to a file containing uppercase" unless short.downcase == short
|
136
|
+
|
137
|
+
return false unless File.directory?(dir)
|
138
|
+
|
136
139
|
real_file = Dir.entries(dir).reject { |f| f =~ /^\./ }.find do |other|
|
137
140
|
other.downcase == short
|
138
141
|
end
|
@@ -25,13 +25,7 @@ class Puppet::Transaction::Report
|
|
25
25
|
hash[key] = []
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
hostname = Facter.value("hostname")
|
30
|
-
if !domain || domain.empty? then
|
31
|
-
@host = hostname
|
32
|
-
else
|
33
|
-
@host = [hostname, domain].join(".")
|
34
|
-
end
|
28
|
+
@host = Puppet[:certname]
|
35
29
|
end
|
36
30
|
|
37
31
|
def name
|
data/lib/puppet/transportable.rb
CHANGED
@@ -65,13 +65,16 @@ module Puppet
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def to_manifest
|
68
|
-
"
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
68
|
+
"%s { '%s':\n%s\n}" %
|
69
|
+
[self.type.to_s, self.name,
|
70
|
+
@params.collect { |p, v|
|
71
|
+
if v.is_a? Array
|
72
|
+
" #{p} => [\'#{v.join("','")}\']"
|
73
|
+
else
|
74
|
+
" #{p} => \'#{v}\'"
|
75
|
+
end
|
76
|
+
}.join(",\n")
|
77
|
+
]
|
75
78
|
end
|
76
79
|
|
77
80
|
def to_yaml_properties
|
data/lib/puppet/type.rb
CHANGED
@@ -20,20 +20,2116 @@ class Type
|
|
20
20
|
include Puppet::Util::LogPaths
|
21
21
|
include Puppet::Util::Logging
|
22
22
|
|
23
|
-
|
24
|
-
#
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
23
|
+
###############################
|
24
|
+
# Code related to resource type attributes.
|
25
|
+
class << self
|
26
|
+
include Puppet::Util::ClassGen
|
27
|
+
include Puppet::Util::Warnings
|
28
|
+
attr_reader :properties
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.states
|
32
|
+
warnonce "The states method is deprecated; use properties"
|
33
|
+
properties()
|
34
|
+
end
|
35
|
+
|
36
|
+
# All parameters, in the appropriate order. The namevar comes first,
|
37
|
+
# then the properties, then the params and metaparams in the order they
|
38
|
+
# were specified in the files.
|
39
|
+
def self.allattrs
|
40
|
+
# now get all of the arguments, in a specific order
|
41
|
+
# Cache this, since it gets called so many times
|
42
|
+
namevar = self.namevar
|
43
|
+
|
44
|
+
order = [namevar]
|
45
|
+
if self.parameters.include?(:provider)
|
46
|
+
order << :provider
|
47
|
+
end
|
48
|
+
order << [self.properties.collect { |property| property.name },
|
49
|
+
self.parameters - [:provider],
|
50
|
+
self.metaparams].flatten.reject { |param|
|
51
|
+
# we don't want our namevar in there multiple times
|
52
|
+
param == namevar
|
53
|
+
}
|
54
|
+
|
55
|
+
order.flatten!
|
56
|
+
|
57
|
+
return order
|
58
|
+
end
|
59
|
+
|
60
|
+
# Retrieve an attribute alias, if there is one.
|
61
|
+
def self.attr_alias(param)
|
62
|
+
@attr_aliases[symbolize(param)]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Create an alias to an existing attribute. This will cause the aliased
|
66
|
+
# attribute to be valid when setting and retrieving values on the instance.
|
67
|
+
def self.set_attr_alias(hash)
|
68
|
+
hash.each do |new, old|
|
69
|
+
@attr_aliases[symbolize(new)] = symbolize(old)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Find the class associated with any given attribute.
|
74
|
+
def self.attrclass(name)
|
75
|
+
@attrclasses ||= {}
|
76
|
+
|
77
|
+
# We cache the value, since this method gets called such a huge number
|
78
|
+
# of times (as in, hundreds of thousands in a given run).
|
79
|
+
unless @attrclasses.include?(name)
|
80
|
+
@attrclasses[name] = case self.attrtype(name)
|
81
|
+
when :property: @validproperties[name]
|
82
|
+
when :meta: @@metaparamhash[name]
|
83
|
+
when :param: @paramhash[name]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
@attrclasses[name]
|
87
|
+
end
|
88
|
+
|
89
|
+
# What type of parameter are we dealing with? Cache the results, because
|
90
|
+
# this method gets called so many times.
|
91
|
+
def self.attrtype(attr)
|
92
|
+
@attrtypes ||= {}
|
93
|
+
unless @attrtypes.include?(attr)
|
94
|
+
@attrtypes[attr] = case
|
95
|
+
when @validproperties.include?(attr): :property
|
96
|
+
when @paramhash.include?(attr): :param
|
97
|
+
when @@metaparamhash.include?(attr): :meta
|
98
|
+
else
|
99
|
+
raise Puppet::DevError,
|
100
|
+
"Invalid attribute '%s' for class '%s'" %
|
101
|
+
[attr, self.name]
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@attrtypes[attr]
|
106
|
+
end
|
107
|
+
|
108
|
+
# Copy an existing class parameter. This allows other types to avoid
|
109
|
+
# duplicating a parameter definition, and is mostly used by subclasses
|
110
|
+
# of the File class.
|
111
|
+
def self.copyparam(klass, name)
|
112
|
+
param = klass.attrclass(name)
|
113
|
+
|
114
|
+
unless param
|
115
|
+
raise Puppet::DevError, "Class %s has no param %s" % [klass, name]
|
116
|
+
end
|
117
|
+
@parameters << param
|
118
|
+
@parameters.each { |p| @paramhash[name] = p }
|
119
|
+
|
120
|
+
if param.isnamevar?
|
121
|
+
@namevar = param.name
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# A similar function but one that yields the class and type.
|
126
|
+
# This is mainly so that setdefaults doesn't call quite so many functions.
|
127
|
+
def self.eachattr(*ary)
|
128
|
+
if ary.empty?
|
129
|
+
ary = nil
|
130
|
+
end
|
131
|
+
|
132
|
+
# We have to do this in a specific order, so that defaults are
|
133
|
+
# created in that order (e.g., providers should be set up before
|
134
|
+
# anything else).
|
135
|
+
allattrs.each do |name|
|
136
|
+
next unless ary.nil? or ary.include?(name)
|
137
|
+
if obj = @properties.find { |p| p.name == name }
|
138
|
+
yield obj, :property
|
139
|
+
elsif obj = @parameters.find { |p| p.name == name }
|
140
|
+
yield obj, :param
|
141
|
+
elsif obj = @@metaparams.find { |p| p.name == name }
|
142
|
+
yield obj, :meta
|
143
|
+
else
|
144
|
+
raise Puppet::DevError, "Could not find parameter %s" % name
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.eachmetaparam
|
150
|
+
@@metaparams.each { |p| yield p.name }
|
151
|
+
end
|
152
|
+
|
153
|
+
# Create the 'ensure' class. This is a separate method so other types
|
154
|
+
# can easily call it and create their own 'ensure' values.
|
155
|
+
def self.ensurable(&block)
|
156
|
+
if block_given?
|
157
|
+
self.newproperty(:ensure, :parent => Puppet::Property::Ensure, &block)
|
158
|
+
else
|
159
|
+
self.newproperty(:ensure, :parent => Puppet::Property::Ensure) do
|
160
|
+
self.defaultvalues
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Should we add the 'ensure' property to this class?
|
166
|
+
def self.ensurable?
|
167
|
+
# If the class has all three of these methods defined, then it's
|
168
|
+
# ensurable.
|
169
|
+
ens = [:exists?, :create, :destroy].inject { |set, method|
|
170
|
+
set &&= self.public_method_defined?(method)
|
171
|
+
}
|
172
|
+
|
173
|
+
return ens
|
174
|
+
end
|
175
|
+
|
176
|
+
# Deal with any options passed into parameters.
|
177
|
+
def self.handle_param_options(name, options)
|
178
|
+
# If it's a boolean parameter, create a method to test the value easily
|
179
|
+
if options[:boolean]
|
180
|
+
define_method(name.to_s + "?") do
|
181
|
+
val = self[name]
|
182
|
+
if val == :true or val == true
|
183
|
+
return true
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
# If this param handles relationships, store that information
|
189
|
+
end
|
190
|
+
|
191
|
+
# Is the parameter in question a meta-parameter?
|
192
|
+
def self.metaparam?(param)
|
193
|
+
@@metaparamhash.include?(symbolize(param))
|
194
|
+
end
|
195
|
+
|
196
|
+
# Find the metaparameter class associated with a given metaparameter name.
|
197
|
+
def self.metaparamclass(name)
|
198
|
+
@@metaparamhash[symbolize(name)]
|
199
|
+
end
|
200
|
+
|
201
|
+
def self.metaparams
|
202
|
+
@@metaparams.collect { |param| param.name }
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.metaparamdoc(metaparam)
|
206
|
+
@@metaparamhash[metaparam].doc
|
207
|
+
end
|
208
|
+
|
209
|
+
# Create a new metaparam. Requires a block and a name, stores it in the
|
210
|
+
# @parameters array, and does some basic checking on it.
|
211
|
+
def self.newmetaparam(name, options = {}, &block)
|
212
|
+
@@metaparams ||= []
|
213
|
+
@@metaparamhash ||= {}
|
214
|
+
name = symbolize(name)
|
215
|
+
|
216
|
+
param = genclass(name,
|
217
|
+
:parent => options[:parent] || Puppet::Parameter,
|
218
|
+
:prefix => "MetaParam",
|
219
|
+
:hash => @@metaparamhash,
|
220
|
+
:array => @@metaparams,
|
221
|
+
:attributes => options[:attributes],
|
222
|
+
&block
|
223
|
+
)
|
224
|
+
|
225
|
+
# Grr.
|
226
|
+
if options[:required_features]
|
227
|
+
param.required_features = options[:required_features]
|
228
|
+
end
|
229
|
+
|
230
|
+
handle_param_options(name, options)
|
231
|
+
|
232
|
+
param.metaparam = true
|
233
|
+
|
234
|
+
return param
|
235
|
+
end
|
236
|
+
|
237
|
+
# Find the namevar
|
238
|
+
def self.namevar
|
239
|
+
unless defined? @namevar
|
240
|
+
params = @parameters.find_all { |param|
|
241
|
+
param.isnamevar? or param.name == :name
|
242
|
+
}
|
243
|
+
|
244
|
+
if params.length > 1
|
245
|
+
raise Puppet::DevError, "Found multiple namevars for %s" % self.name
|
246
|
+
elsif params.length == 1
|
247
|
+
@namevar = params[0].name
|
248
|
+
else
|
249
|
+
raise Puppet::DevError, "No namevar for %s" % self.name
|
250
|
+
end
|
251
|
+
end
|
252
|
+
@namevar
|
253
|
+
end
|
254
|
+
|
255
|
+
# Create a new parameter. Requires a block and a name, stores it in the
|
256
|
+
# @parameters array, and does some basic checking on it.
|
257
|
+
def self.newparam(name, options = {}, &block)
|
258
|
+
options[:attributes] ||= {}
|
259
|
+
param = genclass(name,
|
260
|
+
:parent => options[:parent] || Puppet::Parameter,
|
261
|
+
:attributes => options[:attributes],
|
262
|
+
:block => block,
|
263
|
+
:prefix => "Parameter",
|
264
|
+
:array => @parameters,
|
265
|
+
:hash => @paramhash
|
266
|
+
)
|
267
|
+
|
268
|
+
handle_param_options(name, options)
|
269
|
+
|
270
|
+
# Grr.
|
271
|
+
if options[:required_features]
|
272
|
+
param.required_features = options[:required_features]
|
273
|
+
end
|
274
|
+
|
275
|
+
param.isnamevar if options[:namevar]
|
276
|
+
|
277
|
+
# These might be enabled later.
|
278
|
+
# define_method(name) do
|
279
|
+
# @parameters[name].value
|
280
|
+
# end
|
281
|
+
#
|
282
|
+
# define_method(name.to_s + "=") do |value|
|
283
|
+
# newparam(param, value)
|
284
|
+
# end
|
285
|
+
|
286
|
+
if param.isnamevar?
|
287
|
+
@namevar = param.name
|
288
|
+
end
|
289
|
+
|
290
|
+
return param
|
291
|
+
end
|
292
|
+
|
293
|
+
def self.newstate(name, options = {}, &block)
|
294
|
+
Puppet.warning "newstate() has been deprecrated; use newproperty(%s)" %
|
295
|
+
name
|
296
|
+
newproperty(name, options, &block)
|
297
|
+
end
|
298
|
+
|
299
|
+
# Create a new property. The first parameter must be the name of the property;
|
300
|
+
# this is how users will refer to the property when creating new instances.
|
301
|
+
# The second parameter is a hash of options; the options are:
|
302
|
+
# * <tt>:parent</tt>: The parent class for the property. Defaults to Puppet::Property.
|
303
|
+
# * <tt>:retrieve</tt>: The method to call on the provider or @parent object (if
|
304
|
+
# the provider is not set) to retrieve the current value.
|
305
|
+
def self.newproperty(name, options = {}, &block)
|
306
|
+
name = symbolize(name)
|
307
|
+
|
308
|
+
# This is here for types that might still have the old method of defining
|
309
|
+
# a parent class.
|
310
|
+
unless options.is_a? Hash
|
311
|
+
raise Puppet::DevError,
|
312
|
+
"Options must be a hash, not %s" % options.inspect
|
313
|
+
end
|
314
|
+
|
315
|
+
if @validproperties.include?(name)
|
316
|
+
raise Puppet::DevError, "Class %s already has a property named %s" %
|
317
|
+
[self.name, name]
|
318
|
+
end
|
319
|
+
|
320
|
+
if parent = options[:parent]
|
321
|
+
options.delete(:parent)
|
322
|
+
else
|
323
|
+
parent = Puppet::Property
|
324
|
+
end
|
325
|
+
|
326
|
+
# We have to create our own, new block here because we want to define
|
327
|
+
# an initial :retrieve method, if told to, and then eval the passed
|
328
|
+
# block if available.
|
329
|
+
prop = genclass(name, :parent => parent, :hash => @validproperties, :attributes => options) do
|
330
|
+
# If they've passed a retrieve method, then override the retrieve
|
331
|
+
# method on the class.
|
332
|
+
if options[:retrieve]
|
333
|
+
define_method(:retrieve) do
|
334
|
+
provider.send(options[:retrieve])
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
if block
|
339
|
+
class_eval(&block)
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
# If it's the 'ensure' property, always put it first.
|
344
|
+
if name == :ensure
|
345
|
+
@properties.unshift prop
|
346
|
+
else
|
347
|
+
@properties << prop
|
348
|
+
end
|
349
|
+
|
350
|
+
# define_method(name) do
|
351
|
+
# @parameters[name].should
|
352
|
+
# end
|
353
|
+
#
|
354
|
+
# define_method(name.to_s + "=") do |value|
|
355
|
+
# newproperty(name, :should => value)
|
356
|
+
# end
|
357
|
+
|
358
|
+
return prop
|
359
|
+
end
|
360
|
+
|
361
|
+
def self.paramdoc(param)
|
362
|
+
@paramhash[param].doc
|
363
|
+
end
|
364
|
+
|
365
|
+
# Return the parameter names
|
366
|
+
def self.parameters
|
367
|
+
return [] unless defined? @parameters
|
368
|
+
@parameters.collect { |klass| klass.name }
|
369
|
+
end
|
370
|
+
|
371
|
+
# Find the parameter class associated with a given parameter name.
|
372
|
+
def self.paramclass(name)
|
373
|
+
@paramhash[name]
|
374
|
+
end
|
375
|
+
|
376
|
+
# Return the property class associated with a name
|
377
|
+
def self.propertybyname(name)
|
378
|
+
@validproperties[name]
|
379
|
+
end
|
380
|
+
|
381
|
+
def self.validattr?(name)
|
382
|
+
name = symbolize(name)
|
383
|
+
return true if name == :name
|
384
|
+
@validattrs ||= {}
|
385
|
+
|
386
|
+
unless @validattrs.include?(name)
|
387
|
+
if self.validproperty?(name) or self.validparameter?(name) or self.metaparam?(name)
|
388
|
+
@validattrs[name] = true
|
389
|
+
else
|
390
|
+
@validattrs[name] = false
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
@validattrs[name]
|
395
|
+
end
|
396
|
+
|
397
|
+
# does the name reflect a valid property?
|
398
|
+
def self.validproperty?(name)
|
399
|
+
name = symbolize(name)
|
400
|
+
if @validproperties.include?(name)
|
401
|
+
return @validproperties[name]
|
402
|
+
else
|
403
|
+
return false
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
# Return the list of validproperties
|
408
|
+
def self.validproperties
|
409
|
+
return {} unless defined? @parameters
|
410
|
+
|
411
|
+
return @validproperties.keys
|
412
|
+
end
|
413
|
+
|
414
|
+
# does the name reflect a valid parameter?
|
415
|
+
def self.validparameter?(name)
|
416
|
+
unless defined? @parameters
|
417
|
+
raise Puppet::DevError, "Class %s has not defined parameters" % self
|
418
|
+
end
|
419
|
+
if @paramhash.include?(name) or @@metaparamhash.include?(name)
|
420
|
+
return true
|
421
|
+
else
|
422
|
+
return false
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
# fix any namevar => param translations
|
427
|
+
def argclean(oldhash)
|
428
|
+
# This duplication is here because it might be a transobject.
|
429
|
+
hash = oldhash.dup.to_hash
|
430
|
+
|
431
|
+
if hash.include?(:resource)
|
432
|
+
hash.delete(:resource)
|
433
|
+
end
|
434
|
+
namevar = self.class.namevar
|
435
|
+
|
436
|
+
# Do a simple translation for those cases where they've passed :name
|
437
|
+
# but that's not our namevar
|
438
|
+
if hash.include? :name and namevar != :name
|
439
|
+
if hash.include? namevar
|
440
|
+
raise ArgumentError, "Cannot provide both name and %s" % namevar
|
441
|
+
end
|
442
|
+
hash[namevar] = hash[:name]
|
443
|
+
hash.delete(:name)
|
444
|
+
end
|
445
|
+
|
446
|
+
# Make sure we have a name, one way or another
|
447
|
+
unless hash.include? namevar
|
448
|
+
if defined? @title and @title
|
449
|
+
hash[namevar] = @title
|
450
|
+
else
|
451
|
+
raise Puppet::Error, "Was not passed a namevar or title"
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
return hash
|
456
|
+
end
|
457
|
+
|
458
|
+
# Return either the attribute alias or the attribute.
|
459
|
+
def attr_alias(name)
|
460
|
+
name = symbolize(name)
|
461
|
+
if synonym = self.class.attr_alias(name)
|
462
|
+
return synonym
|
463
|
+
else
|
464
|
+
return name
|
465
|
+
end
|
466
|
+
end
|
467
|
+
|
468
|
+
# Are we deleting this resource?
|
469
|
+
def deleting?
|
470
|
+
obj = @parameters[:ensure] and obj.should == :absent
|
471
|
+
end
|
472
|
+
|
473
|
+
# Create a new property if it is valid but doesn't exist
|
474
|
+
# Returns: true if a new parameter was added, false otherwise
|
475
|
+
def add_property_parameter(prop_name)
|
476
|
+
if self.class.validproperty?(prop_name) && !@parameters[prop_name]
|
477
|
+
self.newattr(prop_name)
|
478
|
+
return true
|
479
|
+
end
|
480
|
+
return false
|
481
|
+
end
|
482
|
+
|
483
|
+
# abstract accessing parameters and properties, and normalize
|
484
|
+
# access to always be symbols, not strings
|
485
|
+
# This returns a value, not an object. It returns the 'is'
|
486
|
+
# value, but you can also specifically return 'is' and 'should'
|
487
|
+
# values using 'object.is(:property)' or 'object.should(:property)'.
|
488
|
+
def [](name)
|
489
|
+
name = attr_alias(name)
|
490
|
+
|
491
|
+
unless self.class.validattr?(name)
|
492
|
+
raise TypeError.new("Invalid parameter %s(%s)" % [name, name.inspect])
|
493
|
+
end
|
494
|
+
|
495
|
+
if name == :name
|
496
|
+
name = self.class.namevar
|
497
|
+
end
|
498
|
+
|
499
|
+
if obj = @parameters[name]
|
500
|
+
# Note that if this is a property, then the value is the "should" value,
|
501
|
+
# not the current value.
|
502
|
+
obj.value
|
503
|
+
else
|
504
|
+
return nil
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
# Abstract setting parameters and properties, and normalize
|
509
|
+
# access to always be symbols, not strings. This sets the 'should'
|
510
|
+
# value on properties, and otherwise just sets the appropriate parameter.
|
511
|
+
def []=(name,value)
|
512
|
+
name = attr_alias(name)
|
513
|
+
|
514
|
+
unless self.class.validattr?(name)
|
515
|
+
raise TypeError.new("Invalid parameter %s" % [name])
|
516
|
+
end
|
517
|
+
|
518
|
+
if name == :name
|
519
|
+
name = self.class.namevar
|
520
|
+
end
|
521
|
+
if value.nil?
|
522
|
+
raise Puppet::Error.new("Got nil value for %s" % name)
|
523
|
+
end
|
524
|
+
|
525
|
+
if obj = @parameters[name]
|
526
|
+
obj.value = value
|
527
|
+
return nil
|
528
|
+
else
|
529
|
+
self.newattr(name, :value => value)
|
530
|
+
end
|
531
|
+
|
532
|
+
nil
|
533
|
+
end
|
534
|
+
|
535
|
+
# remove a property from the object; useful in testing or in cleanup
|
536
|
+
# when an error has been encountered
|
537
|
+
def delete(attr)
|
538
|
+
attr = symbolize(attr)
|
539
|
+
if @parameters.has_key?(attr)
|
540
|
+
@parameters.delete(attr)
|
541
|
+
else
|
542
|
+
raise Puppet::DevError.new("Undefined attribute '#{attr}' in #{self}")
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
# iterate across the existing properties
|
547
|
+
def eachproperty
|
548
|
+
# properties() is a private method
|
549
|
+
properties().each { |property|
|
550
|
+
yield property
|
551
|
+
}
|
552
|
+
end
|
553
|
+
|
554
|
+
# retrieve the 'should' value for a specified property
|
555
|
+
def should(name)
|
556
|
+
name = attr_alias(name)
|
557
|
+
if prop = @parameters[name] and prop.is_a?(Puppet::Property)
|
558
|
+
return prop.should
|
559
|
+
else
|
560
|
+
return nil
|
561
|
+
end
|
562
|
+
end
|
563
|
+
|
564
|
+
# Create the actual attribute instance. Requires either the attribute
|
565
|
+
# name or class as the first argument, then an optional hash of
|
566
|
+
# attributes to set during initialization.
|
567
|
+
def newattr(name, options = {})
|
568
|
+
if name.is_a?(Class)
|
569
|
+
klass = name
|
570
|
+
name = klass.name
|
571
|
+
end
|
572
|
+
|
573
|
+
unless klass = self.class.attrclass(name)
|
574
|
+
raise Puppet::Error, "Resource type %s does not support parameter %s" % [self.class.name, name]
|
575
|
+
end
|
576
|
+
|
577
|
+
if @parameters.include?(name)
|
578
|
+
raise Puppet::Error, "Parameter '%s' is already defined in %s" %
|
579
|
+
[name, self.ref]
|
580
|
+
end
|
581
|
+
|
582
|
+
if provider and ! provider.class.supports_parameter?(klass)
|
583
|
+
missing = klass.required_features.find_all { |f| ! provider.class.feature?(f) }
|
584
|
+
info "Provider %s does not support features %s; not managing attribute %s" % [provider.class.name, missing.join(", "), name]
|
585
|
+
return nil
|
586
|
+
end
|
587
|
+
|
588
|
+
# Add resource information at creation time, so it's available
|
589
|
+
# during validation.
|
590
|
+
options[:resource] = self
|
591
|
+
begin
|
592
|
+
# make sure the parameter doesn't have any errors
|
593
|
+
return @parameters[name] = klass.new(options)
|
594
|
+
rescue => detail
|
595
|
+
error = Puppet::Error.new("Parameter %s failed: %s" %
|
596
|
+
[name, detail])
|
597
|
+
error.set_backtrace(detail.backtrace)
|
598
|
+
raise error
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
# return the value of a parameter
|
603
|
+
def parameter(name)
|
604
|
+
unless name.is_a? Symbol
|
605
|
+
name = name.intern
|
606
|
+
end
|
607
|
+
return @parameters[name].value
|
608
|
+
end
|
609
|
+
|
610
|
+
# Is the named property defined?
|
611
|
+
def propertydefined?(name)
|
612
|
+
unless name.is_a? Symbol
|
613
|
+
name = name.intern
|
614
|
+
end
|
615
|
+
return @parameters.include?(name)
|
616
|
+
end
|
617
|
+
|
618
|
+
# return an actual type by name; to return the value, use 'inst[name]'
|
619
|
+
# FIXME this method should go away
|
620
|
+
def property(name)
|
621
|
+
if obj = @parameters[symbolize(name)] and obj.is_a?(Puppet::Property)
|
622
|
+
return obj
|
623
|
+
else
|
624
|
+
return nil
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
# def set(name, value)
|
629
|
+
# send(name.to_s + "=", value)
|
630
|
+
# end
|
631
|
+
#
|
632
|
+
# def get(name)
|
633
|
+
# send(name)
|
634
|
+
# end
|
635
|
+
|
636
|
+
# For any parameters or properties that have defaults and have not yet been
|
637
|
+
# set, set them now. This method can be handed a list of attributes,
|
638
|
+
# and if so it will only set defaults for those attributes.
|
639
|
+
def setdefaults(*ary)
|
640
|
+
#self.class.eachattr(*ary) { |klass, type|
|
641
|
+
self.class.eachattr(*ary) { |klass, type|
|
642
|
+
# not many attributes will have defaults defined, so we short-circuit
|
643
|
+
# those away
|
644
|
+
next unless klass.method_defined?(:default)
|
645
|
+
next if @parameters[klass.name]
|
646
|
+
|
647
|
+
next unless obj = self.newattr(klass)
|
648
|
+
|
649
|
+
# We have to check for nil values, not "truth", so we allow defaults
|
650
|
+
# to false.
|
651
|
+
value = obj.default and ! value.nil?
|
652
|
+
if ! value.nil?
|
653
|
+
obj.value = value
|
654
|
+
else
|
655
|
+
@parameters.delete(obj.name)
|
656
|
+
end
|
657
|
+
}
|
658
|
+
end
|
659
|
+
|
660
|
+
# Convert our object to a hash. This just includes properties.
|
661
|
+
def to_hash
|
662
|
+
rethash = {}
|
663
|
+
|
664
|
+
@parameters.each do |name, obj|
|
665
|
+
rethash[name] = obj.value
|
666
|
+
end
|
667
|
+
|
668
|
+
rethash
|
669
|
+
end
|
670
|
+
|
671
|
+
# Return a specific value for an attribute.
|
672
|
+
def value(name)
|
673
|
+
name = attr_alias(name)
|
674
|
+
|
675
|
+
if obj = @parameters[name] and obj.respond_to?(:value)
|
676
|
+
return obj.value
|
677
|
+
else
|
678
|
+
return nil
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
# Meta-parameter methods: These methods deal with the results
|
683
|
+
# of specifying metaparameters
|
684
|
+
|
685
|
+
private
|
686
|
+
|
687
|
+
# Return all of the property objects, in the order specified in the
|
688
|
+
# class.
|
689
|
+
def properties
|
690
|
+
#debug "%s has %s properties" % [self,@parameters.length]
|
691
|
+
props = self.class.properties.collect { |prop|
|
692
|
+
@parameters[prop.name]
|
693
|
+
}.find_all { |p|
|
694
|
+
! p.nil?
|
695
|
+
}.each do |prop|
|
696
|
+
unless prop.is_a?(Puppet::Property)
|
697
|
+
raise Puppet::DevError, "got a non-property %s(%s)" %
|
698
|
+
[prop.class, prop.class.name]
|
699
|
+
end
|
700
|
+
end
|
701
|
+
|
702
|
+
props
|
703
|
+
end
|
704
|
+
|
705
|
+
public
|
706
|
+
|
707
|
+
###############################
|
708
|
+
# Code related to the closure-like behaviour of the resource classes.
|
709
|
+
attr_writer :implicit
|
710
|
+
|
711
|
+
# Is this type's name isomorphic with the object? That is, if the
|
712
|
+
# name conflicts, does it necessarily mean that the objects conflict?
|
713
|
+
# Defaults to true.
|
714
|
+
def self.isomorphic?
|
715
|
+
if defined? @isomorphic
|
716
|
+
return @isomorphic
|
717
|
+
else
|
718
|
+
return true
|
719
|
+
end
|
720
|
+
end
|
721
|
+
|
722
|
+
def implicit?
|
723
|
+
if defined? @implicit and @implicit
|
724
|
+
return true
|
725
|
+
else
|
726
|
+
return false
|
727
|
+
end
|
728
|
+
end
|
729
|
+
|
730
|
+
def isomorphic?
|
731
|
+
self.class.isomorphic?
|
732
|
+
end
|
733
|
+
|
734
|
+
# is the instance a managed instance? A 'yes' here means that
|
735
|
+
# the instance was created from the language, vs. being created
|
736
|
+
# in order resolve other questions, such as finding a package
|
737
|
+
# in a list
|
738
|
+
def managed?
|
739
|
+
# Once an object is managed, it always stays managed; but an object
|
740
|
+
# that is listed as unmanaged might become managed later in the process,
|
741
|
+
# so we have to check that every time
|
742
|
+
if defined? @managed and @managed
|
743
|
+
return @managed
|
744
|
+
else
|
745
|
+
@managed = false
|
746
|
+
properties.each { |property|
|
747
|
+
s = property.should
|
748
|
+
if s and ! property.class.unmanaged
|
749
|
+
@managed = true
|
750
|
+
break
|
751
|
+
end
|
752
|
+
}
|
753
|
+
return @managed
|
754
|
+
end
|
755
|
+
end
|
756
|
+
|
757
|
+
###############################
|
758
|
+
# Code related to the container behaviour.
|
759
|
+
def self.depthfirst?
|
760
|
+
if defined? @depthfirst
|
761
|
+
return @depthfirst
|
762
|
+
else
|
763
|
+
return false
|
764
|
+
end
|
765
|
+
end
|
766
|
+
|
767
|
+
def depthfirst?
|
768
|
+
self.class.depthfirst?
|
769
|
+
end
|
770
|
+
|
771
|
+
# Add a hook for testing for recursion.
|
772
|
+
def parentof?(child)
|
773
|
+
if (self == child)
|
774
|
+
debug "parent is equal to child"
|
775
|
+
return true
|
776
|
+
elsif defined? @parent and @parent.parentof?(child)
|
777
|
+
debug "My parent is parent of child"
|
778
|
+
return true
|
779
|
+
else
|
780
|
+
return false
|
781
|
+
end
|
782
|
+
end
|
783
|
+
|
784
|
+
# Remove an object. The argument determines whether the object's
|
785
|
+
# subscriptions get eliminated, too.
|
786
|
+
def remove(rmdeps = true)
|
787
|
+
# This is hackish (mmm, cut and paste), but it works for now, and it's
|
788
|
+
# better than warnings.
|
789
|
+
@parameters.each do |name, obj|
|
790
|
+
obj.remove
|
791
|
+
end
|
792
|
+
@parameters.clear
|
793
|
+
self.class.delete(self)
|
794
|
+
|
795
|
+
@parent = nil
|
796
|
+
|
797
|
+
# Remove the reference to the provider.
|
798
|
+
if self.provider
|
799
|
+
@provider.clear
|
800
|
+
@provider = nil
|
801
|
+
end
|
802
|
+
end
|
803
|
+
|
804
|
+
###############################
|
805
|
+
# Code related to evaluating the resources.
|
806
|
+
|
807
|
+
# This method is responsible for collecting property changes we always
|
808
|
+
# descend into the children before we evaluate our current properties.
|
809
|
+
# This returns any changes resulting from testing, thus 'collect' rather
|
810
|
+
# than 'each'.
|
811
|
+
def evaluate
|
812
|
+
if self.provider.is_a?(Puppet::Provider)
|
813
|
+
unless provider.class.suitable?
|
814
|
+
raise Puppet::Error, "Provider %s is not functional on this platform" % provider.class.name
|
815
|
+
end
|
816
|
+
end
|
817
|
+
#Puppet.err "Evaluating %s" % self.path.join(":")
|
818
|
+
unless defined? @evalcount
|
819
|
+
self.err "No evalcount defined on '%s' of type '%s'" %
|
820
|
+
[self.title,self.class]
|
821
|
+
@evalcount = 0
|
822
|
+
end
|
823
|
+
@evalcount += 1
|
824
|
+
|
825
|
+
if p = self.provider and p.respond_to?(:prefetch)
|
826
|
+
p.prefetch
|
827
|
+
end
|
828
|
+
|
829
|
+
# this only operates on properties, not properties + children
|
830
|
+
# it's important that we call retrieve() on the type instance,
|
831
|
+
# not directly on the property, because it allows the type to override
|
832
|
+
# the method, like pfile does
|
833
|
+
currentvalues = self.retrieve
|
834
|
+
|
835
|
+
changes = propertychanges(currentvalues).flatten
|
836
|
+
|
837
|
+
# now record how many changes we've resulted in
|
838
|
+
if changes.length > 0
|
839
|
+
self.debug "%s change(s)" %
|
840
|
+
[changes.length]
|
841
|
+
end
|
842
|
+
|
843
|
+
# If we're in noop mode, we don't want to store the checked time,
|
844
|
+
# because it will result in the resource not getting scheduled if
|
845
|
+
# someone were to apply the catalog in non-noop mode.
|
846
|
+
# We're going to go ahead and record that we checked if there were
|
847
|
+
# no changes, since it's unlikely it will affect the scheduling.
|
848
|
+
noop = noop?
|
849
|
+
if ! noop or (noop && changes.length == 0)
|
850
|
+
self.cache(:checked, Time.now)
|
851
|
+
end
|
852
|
+
return changes.flatten
|
853
|
+
end
|
854
|
+
|
855
|
+
# Flush the provider, if it supports it. This is called by the
|
856
|
+
# transaction.
|
857
|
+
def flush
|
858
|
+
if self.provider and self.provider.respond_to?(:flush)
|
859
|
+
self.provider.flush
|
860
|
+
end
|
861
|
+
end
|
862
|
+
|
863
|
+
# if all contained objects are in sync, then we're in sync
|
864
|
+
# FIXME I don't think this is used on the type instances any more,
|
865
|
+
# it's really only used for testing
|
866
|
+
def insync?(is)
|
867
|
+
insync = true
|
868
|
+
|
869
|
+
if property = @parameters[:ensure]
|
870
|
+
unless is.include? property
|
871
|
+
raise Puppet::DevError,
|
872
|
+
"The is value is not in the is array for '%s'" %
|
873
|
+
[property.name]
|
874
|
+
end
|
875
|
+
ensureis = is[property]
|
876
|
+
if property.insync?(ensureis) and property.should == :absent
|
877
|
+
return true
|
878
|
+
end
|
879
|
+
end
|
880
|
+
|
881
|
+
properties.each { |property|
|
882
|
+
unless is.include? property
|
883
|
+
raise Puppet::DevError,
|
884
|
+
"The is value is not in the is array for '%s'" %
|
885
|
+
[property.name]
|
886
|
+
end
|
887
|
+
|
888
|
+
propis = is[property]
|
889
|
+
unless property.insync?(propis)
|
890
|
+
property.debug("Not in sync: %s vs %s" %
|
891
|
+
[propis.inspect, property.should.inspect])
|
892
|
+
insync = false
|
893
|
+
#else
|
894
|
+
# property.debug("In sync")
|
895
|
+
end
|
896
|
+
}
|
897
|
+
|
898
|
+
#self.debug("%s sync status is %s" % [self,insync])
|
899
|
+
return insync
|
900
|
+
end
|
901
|
+
|
902
|
+
# retrieve the current value of all contained properties
|
903
|
+
def retrieve
|
904
|
+
return currentpropvalues
|
905
|
+
end
|
906
|
+
|
907
|
+
# Get a hash of the current properties. Returns a hash with
|
908
|
+
# the actual property instance as the key and the current value
|
909
|
+
# as the, um, value.
|
910
|
+
def currentpropvalues
|
911
|
+
# It's important to use the 'properties' method here, as it follows the order
|
912
|
+
# in which they're defined in the class. It also guarantees that 'ensure'
|
913
|
+
# is the first property, which is important for skipping 'retrieve' on
|
914
|
+
# all the properties if the resource is absent.
|
915
|
+
ensure_state = false
|
916
|
+
return properties().inject({}) do | prophash, property|
|
917
|
+
if property.name == :ensure
|
918
|
+
ensure_state = property.retrieve
|
919
|
+
prophash[property] = ensure_state
|
920
|
+
else
|
921
|
+
if ensure_state == :absent
|
922
|
+
prophash[property] = :absent
|
923
|
+
else
|
924
|
+
prophash[property] = property.retrieve
|
925
|
+
end
|
926
|
+
end
|
927
|
+
prophash
|
928
|
+
end
|
929
|
+
end
|
930
|
+
|
931
|
+
# Are we running in noop mode?
|
932
|
+
def noop?
|
933
|
+
if defined?(@noop)
|
934
|
+
@noop
|
935
|
+
else
|
936
|
+
Puppet[:noop]
|
937
|
+
end
|
938
|
+
end
|
939
|
+
|
940
|
+
def noop
|
941
|
+
noop?
|
942
|
+
end
|
943
|
+
|
944
|
+
# Retrieve the changes associated with all of the properties.
|
945
|
+
def propertychanges(currentvalues)
|
946
|
+
# If we are changing the existence of the object, then none of
|
947
|
+
# the other properties matter.
|
948
|
+
changes = []
|
949
|
+
ensureparam = @parameters[:ensure]
|
950
|
+
|
951
|
+
# This allows resource types to have 'ensure' be a parameter, which allows them to
|
952
|
+
# just pass the parameter on to other generated resources.
|
953
|
+
ensureparam = nil unless ensureparam.is_a?(Puppet::Property)
|
954
|
+
if ensureparam && !currentvalues.include?(ensureparam)
|
955
|
+
raise Puppet::DevError, "Parameter ensure defined but missing from current values"
|
956
|
+
end
|
957
|
+
|
958
|
+
if ensureparam and ! ensureparam.insync?(currentvalues[ensureparam])
|
959
|
+
changes << Puppet::Transaction::Change.new(ensureparam, currentvalues[ensureparam])
|
960
|
+
# Else, if the 'ensure' property is correctly absent, then do
|
961
|
+
# nothing
|
962
|
+
elsif ensureparam and currentvalues[ensureparam] == :absent
|
963
|
+
return []
|
964
|
+
else
|
965
|
+
changes = properties().find_all { |property|
|
966
|
+
currentvalues[property] ||= :absent
|
967
|
+
! property.insync?(currentvalues[property])
|
968
|
+
}.collect { |property|
|
969
|
+
Puppet::Transaction::Change.new(property, currentvalues[property])
|
970
|
+
}
|
971
|
+
end
|
972
|
+
|
973
|
+
if Puppet[:debug] and changes.length > 0
|
974
|
+
self.debug("Changing " + changes.collect { |ch| ch.property.name }.join(","))
|
975
|
+
end
|
976
|
+
|
977
|
+
changes
|
978
|
+
end
|
979
|
+
|
980
|
+
###############################
|
981
|
+
# Code related to managing resource instances.
|
982
|
+
require 'puppet/transportable'
|
983
|
+
|
984
|
+
# Make 'new' private, so people have to use create instead.
|
985
|
+
class << self
|
986
|
+
private :new
|
987
|
+
end
|
988
|
+
|
989
|
+
# retrieve a named instance of the current type
|
990
|
+
def self.[](name)
|
991
|
+
@objects[name] || @aliases[name]
|
992
|
+
end
|
993
|
+
|
994
|
+
# add an instance by name to the class list of instances
|
995
|
+
def self.[]=(name,object)
|
996
|
+
newobj = nil
|
997
|
+
if object.is_a?(Puppet::Type)
|
998
|
+
newobj = object
|
999
|
+
else
|
1000
|
+
raise Puppet::DevError, "must pass a Puppet::Type object"
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
if exobj = @objects[name] and self.isomorphic?
|
1004
|
+
msg = "Object '%s[%s]' already exists" %
|
1005
|
+
[newobj.class.name, name]
|
1006
|
+
|
1007
|
+
if exobj.file and exobj.line
|
1008
|
+
msg += ("in file %s at line %s" %
|
1009
|
+
[object.file, object.line])
|
1010
|
+
end
|
1011
|
+
if object.file and object.line
|
1012
|
+
msg += ("and cannot be redefined in file %s at line %s" %
|
1013
|
+
[object.file, object.line])
|
1014
|
+
end
|
1015
|
+
error = Puppet::Error.new(msg)
|
1016
|
+
raise error
|
1017
|
+
else
|
1018
|
+
#Puppet.info("adding %s of type %s to class list" %
|
1019
|
+
# [name,object.class])
|
1020
|
+
@objects[name] = newobj
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
# Create an alias. We keep these in a separate hash so that we don't encounter
|
1025
|
+
# the objects multiple times when iterating over them.
|
1026
|
+
def self.alias(name, obj)
|
1027
|
+
if @objects.include?(name)
|
1028
|
+
unless @objects[name] == obj
|
1029
|
+
raise Puppet::Error.new(
|
1030
|
+
"Cannot create alias %s: object already exists" %
|
1031
|
+
[name]
|
1032
|
+
)
|
1033
|
+
end
|
1034
|
+
end
|
1035
|
+
|
1036
|
+
if @aliases.include?(name)
|
1037
|
+
unless @aliases[name] == obj
|
1038
|
+
raise Puppet::Error.new(
|
1039
|
+
"Object %s already has alias %s" %
|
1040
|
+
[@aliases[name].name, name]
|
1041
|
+
)
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
@aliases[name] = obj
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
# remove all of the instances of a single type
|
1049
|
+
def self.clear
|
1050
|
+
if defined? @objects
|
1051
|
+
@objects.each do |name, obj|
|
1052
|
+
obj.remove(true)
|
1053
|
+
end
|
1054
|
+
@objects.clear
|
1055
|
+
end
|
1056
|
+
if defined? @aliases
|
1057
|
+
@aliases.clear
|
1058
|
+
end
|
1059
|
+
end
|
1060
|
+
|
1061
|
+
# Force users to call this, so that we can merge objects if
|
1062
|
+
# necessary.
|
1063
|
+
def self.create(args)
|
1064
|
+
# Don't modify the original hash; instead, create a duplicate and modify it.
|
1065
|
+
# We have to dup and use the ! so that it stays a TransObject if it is
|
1066
|
+
# one.
|
1067
|
+
hash = args.dup
|
1068
|
+
symbolizehash!(hash)
|
1069
|
+
|
1070
|
+
# If we're the base class, then pass the info on appropriately
|
1071
|
+
if self == Puppet::Type
|
1072
|
+
type = nil
|
1073
|
+
if hash.is_a? Puppet::TransObject
|
1074
|
+
type = hash.type
|
1075
|
+
else
|
1076
|
+
# If we're using the type to determine object type, then delete it
|
1077
|
+
if type = hash[:type]
|
1078
|
+
hash.delete(:type)
|
1079
|
+
end
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
# If they've specified a type and called on the base, then
|
1083
|
+
# delegate to the subclass.
|
1084
|
+
if type
|
1085
|
+
if typeklass = self.type(type)
|
1086
|
+
return typeklass.create(hash)
|
1087
|
+
else
|
1088
|
+
raise Puppet::Error, "Unknown type %s" % type
|
1089
|
+
end
|
1090
|
+
else
|
1091
|
+
raise Puppet::Error, "No type found for %s" % hash.inspect
|
1092
|
+
end
|
1093
|
+
end
|
1094
|
+
|
1095
|
+
# Handle this new object being implicit
|
1096
|
+
implicit = hash[:implicit] || false
|
1097
|
+
if hash.include?(:implicit)
|
1098
|
+
hash.delete(:implicit)
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
name = nil
|
1102
|
+
unless hash.is_a? Puppet::TransObject
|
1103
|
+
hash = self.hash2trans(hash)
|
1104
|
+
end
|
1105
|
+
|
1106
|
+
# XXX This will have to change when transobjects change to using titles
|
1107
|
+
title = hash.name
|
1108
|
+
|
1109
|
+
# if the object already exists
|
1110
|
+
if self.isomorphic? and retobj = self[title]
|
1111
|
+
# if only one of our objects is implicit, then it's easy to see
|
1112
|
+
# who wins -- the non-implicit one.
|
1113
|
+
if retobj.implicit? and ! implicit
|
1114
|
+
Puppet.notice "Removing implicit %s" % retobj.title
|
1115
|
+
# Remove all of the objects, but do not remove their subscriptions.
|
1116
|
+
retobj.remove(false)
|
1117
|
+
|
1118
|
+
# now pass through and create the new object
|
1119
|
+
elsif implicit
|
1120
|
+
Puppet.debug "Ignoring implicit %s[%s]" % [self.name, title]
|
1121
|
+
return nil
|
1122
|
+
else
|
1123
|
+
raise Puppet::Error, "%s is already being managed" % retobj.ref
|
1124
|
+
end
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
# create it anew
|
1128
|
+
# if there's a failure, destroy the object if it got that far, but raise
|
1129
|
+
# the error.
|
1130
|
+
begin
|
1131
|
+
obj = new(hash)
|
1132
|
+
rescue => detail
|
1133
|
+
Puppet.err "Could not create %s: %s" % [title, detail.to_s]
|
1134
|
+
if obj
|
1135
|
+
obj.remove(true)
|
1136
|
+
elsif obj = self[title]
|
1137
|
+
obj.remove(true)
|
1138
|
+
end
|
1139
|
+
raise
|
1140
|
+
end
|
1141
|
+
|
1142
|
+
if implicit
|
1143
|
+
obj.implicit = true
|
1144
|
+
end
|
1145
|
+
|
1146
|
+
# Store the object by title
|
1147
|
+
self[obj.title] = obj
|
1148
|
+
|
1149
|
+
return obj
|
1150
|
+
end
|
1151
|
+
|
1152
|
+
# remove a specified object
|
1153
|
+
def self.delete(resource)
|
1154
|
+
return unless defined? @objects
|
1155
|
+
if @objects.include?(resource.title)
|
1156
|
+
@objects.delete(resource.title)
|
1157
|
+
end
|
1158
|
+
if @aliases.include?(resource.title)
|
1159
|
+
@aliases.delete(resource.title)
|
1160
|
+
end
|
1161
|
+
if @aliases.has_value?(resource)
|
1162
|
+
names = []
|
1163
|
+
@aliases.each do |name, otherres|
|
1164
|
+
if otherres == resource
|
1165
|
+
names << name
|
1166
|
+
end
|
1167
|
+
end
|
1168
|
+
names.each { |name| @aliases.delete(name) }
|
1169
|
+
end
|
1170
|
+
end
|
1171
|
+
|
1172
|
+
# iterate across each of the type's instances
|
1173
|
+
def self.each
|
1174
|
+
return unless defined? @objects
|
1175
|
+
@objects.each { |name,instance|
|
1176
|
+
yield instance
|
1177
|
+
}
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
# does the type have an object with the given name?
|
1181
|
+
def self.has_key?(name)
|
1182
|
+
return @objects.has_key?(name)
|
1183
|
+
end
|
1184
|
+
|
1185
|
+
# Convert a hash to a TransObject.
|
1186
|
+
def self.hash2trans(hash)
|
1187
|
+
title = nil
|
1188
|
+
if hash.include? :title
|
1189
|
+
title = hash[:title]
|
1190
|
+
hash.delete(:title)
|
1191
|
+
elsif hash.include? self.namevar
|
1192
|
+
title = hash[self.namevar]
|
1193
|
+
hash.delete(self.namevar)
|
1194
|
+
|
1195
|
+
if hash.include? :name
|
1196
|
+
raise ArgumentError, "Cannot provide both name and %s to %s" %
|
1197
|
+
[self.namevar, self.name]
|
1198
|
+
end
|
1199
|
+
elsif hash[:name]
|
1200
|
+
title = hash[:name]
|
1201
|
+
hash.delete :name
|
1202
|
+
end
|
1203
|
+
|
1204
|
+
if catalog = hash[:catalog]
|
1205
|
+
hash.delete(:catalog)
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
raise(Puppet::Error, "You must specify a title for objects of type %s" % self.to_s) unless title
|
1209
|
+
|
1210
|
+
if hash.include? :type
|
1211
|
+
unless self.validattr? :type
|
1212
|
+
hash.delete :type
|
1213
|
+
end
|
1214
|
+
end
|
1215
|
+
|
1216
|
+
# okay, now make a transobject out of hash
|
1217
|
+
begin
|
1218
|
+
trans = Puppet::TransObject.new(title, self.name.to_s)
|
1219
|
+
trans.catalog = catalog if catalog
|
1220
|
+
hash.each { |param, value|
|
1221
|
+
trans[param] = value
|
1222
|
+
}
|
1223
|
+
rescue => detail
|
1224
|
+
raise Puppet::Error, "Could not create %s: %s" %
|
1225
|
+
[name, detail]
|
1226
|
+
end
|
1227
|
+
|
1228
|
+
return trans
|
1229
|
+
end
|
1230
|
+
|
1231
|
+
# Retrieve all known instances. Either requires providers or must be overridden.
|
1232
|
+
def self.instances
|
1233
|
+
unless defined?(@providers) and ! @providers.empty?
|
1234
|
+
raise Puppet::DevError, "%s has no providers and has not overridden 'instances'" % self.name
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
# Put the default provider first, then the rest of the suitable providers.
|
1238
|
+
provider_instances = {}
|
1239
|
+
providers_by_source.collect do |provider|
|
1240
|
+
provider.instances.collect do |instance|
|
1241
|
+
# First try to get the resource if it already exists
|
1242
|
+
# Skip instances that map to a managed resource with a different provider
|
1243
|
+
next if resource = self[instance.name] and resource.provider.class != instance.class
|
1244
|
+
|
1245
|
+
# We always want to use the "first" provider instance we find, unless the resource
|
1246
|
+
# is already managed and has a different provider set
|
1247
|
+
if other = provider_instances[instance.name]
|
1248
|
+
Puppet.warning "%s %s found in both %s and %s; skipping the %s version" %
|
1249
|
+
[self.name.to_s.capitalize, instance.name, other.class.name, instance.class.name, instance.class.name]
|
1250
|
+
next
|
1251
|
+
end
|
1252
|
+
provider_instances[instance.name] = instance
|
1253
|
+
|
1254
|
+
if resource
|
1255
|
+
resource.provider = instance
|
1256
|
+
resource
|
1257
|
+
else
|
1258
|
+
create(:name => instance.name, :provider => instance, :check => :all)
|
1259
|
+
end
|
1260
|
+
end
|
1261
|
+
end.flatten.compact
|
1262
|
+
end
|
1263
|
+
|
1264
|
+
# Return a list of one suitable provider per source, with the default provider first.
|
1265
|
+
def self.providers_by_source
|
1266
|
+
# Put the default provider first, then the rest of the suitable providers.
|
1267
|
+
sources = []
|
1268
|
+
[defaultprovider, suitableprovider].flatten.uniq.collect do |provider|
|
1269
|
+
next if sources.include?(provider.source)
|
1270
|
+
|
1271
|
+
sources << provider.source
|
1272
|
+
provider
|
1273
|
+
end.compact
|
1274
|
+
end
|
1275
|
+
|
1276
|
+
# Create the path for logging and such.
|
1277
|
+
def pathbuilder
|
1278
|
+
if p = parent
|
1279
|
+
[p.pathbuilder, self.ref].flatten
|
1280
|
+
else
|
1281
|
+
[self.ref]
|
1282
|
+
end
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
###############################
|
1286
|
+
# Add all of the meta parameters.
|
1287
|
+
newmetaparam(:noop) do
|
1288
|
+
desc "Boolean flag indicating whether work should actually
|
1289
|
+
be done."
|
1290
|
+
|
1291
|
+
newvalues(:true, :false)
|
1292
|
+
munge do |value|
|
1293
|
+
case value
|
1294
|
+
when true, :true, "true": @resource.noop = true
|
1295
|
+
when false, :false, "false": @resource.noop = false
|
1296
|
+
end
|
1297
|
+
end
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
newmetaparam(:schedule) do
|
1301
|
+
desc "On what schedule the object should be managed. You must create a
|
1302
|
+
schedule object, and then reference the name of that object to use
|
1303
|
+
that for your schedule::
|
1304
|
+
|
1305
|
+
schedule { daily:
|
1306
|
+
period => daily,
|
1307
|
+
range => \"2-4\"
|
1308
|
+
}
|
1309
|
+
|
1310
|
+
exec { \"/usr/bin/apt-get update\":
|
1311
|
+
schedule => daily
|
1312
|
+
}
|
1313
|
+
|
1314
|
+
The creation of the schedule object does not need to appear in the
|
1315
|
+
configuration before objects that use it."
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
newmetaparam(:check) do
|
1319
|
+
desc "Propertys which should have their values retrieved
|
1320
|
+
but which should not actually be modified. This is currently used
|
1321
|
+
internally, but will eventually be used for querying, so that you
|
1322
|
+
could specify that you wanted to check the install state of all
|
1323
|
+
packages, and then query the Puppet client daemon to get reports
|
1324
|
+
on all packages."
|
1325
|
+
|
1326
|
+
munge do |args|
|
1327
|
+
# If they've specified all, collect all known properties
|
1328
|
+
if args == :all
|
1329
|
+
args = @resource.class.properties.find_all do |property|
|
1330
|
+
# Only get properties supported by our provider
|
1331
|
+
if @resource.provider
|
1332
|
+
@resource.provider.class.supports_parameter?(property)
|
1333
|
+
else
|
1334
|
+
true
|
1335
|
+
end
|
1336
|
+
end.collect do |property|
|
1337
|
+
property.name
|
1338
|
+
end
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
unless args.is_a?(Array)
|
1342
|
+
args = [args]
|
1343
|
+
end
|
1344
|
+
|
1345
|
+
unless defined? @resource
|
1346
|
+
self.devfail "No parent for %s, %s?" %
|
1347
|
+
[self.class, self.name]
|
1348
|
+
end
|
1349
|
+
|
1350
|
+
args.each { |property|
|
1351
|
+
unless property.is_a?(Symbol)
|
1352
|
+
property = property.intern
|
1353
|
+
end
|
1354
|
+
next if @resource.propertydefined?(property)
|
1355
|
+
|
1356
|
+
unless propertyklass = @resource.class.validproperty?(property)
|
1357
|
+
if @resource.class.validattr?(property)
|
1358
|
+
next
|
1359
|
+
else
|
1360
|
+
raise Puppet::Error, "%s is not a valid attribute for %s" %
|
1361
|
+
[property, self.class.name]
|
1362
|
+
end
|
1363
|
+
end
|
1364
|
+
next unless propertyklass.checkable?
|
1365
|
+
@resource.newattr(property)
|
1366
|
+
}
|
1367
|
+
end
|
1368
|
+
end
|
1369
|
+
|
1370
|
+
# We've got four relationship metaparameters, so this method is used
|
1371
|
+
# to reduce code duplication between them.
|
1372
|
+
def munge_relationship(param, values)
|
1373
|
+
# We need to support values passed in as an array or as a
|
1374
|
+
# resource reference.
|
1375
|
+
result = []
|
1376
|
+
|
1377
|
+
# 'values' could be an array or a reference. If it's an array,
|
1378
|
+
# it could be an array of references or an array of arrays.
|
1379
|
+
if values.is_a?(Puppet::Type)
|
1380
|
+
result << [values.class.name, values.title]
|
1381
|
+
else
|
1382
|
+
unless values.is_a?(Array)
|
1383
|
+
devfail "Relationships must be resource references"
|
1384
|
+
end
|
1385
|
+
if values[0].is_a?(String) or values[0].is_a?(Symbol)
|
1386
|
+
# we're a type/title array reference
|
1387
|
+
values[0] = symbolize(values[0])
|
1388
|
+
result << values
|
1389
|
+
else
|
1390
|
+
# we're an array of stuff
|
1391
|
+
values.each do |value|
|
1392
|
+
if value.is_a?(Puppet::Type)
|
1393
|
+
result << [value.class.name, value.title]
|
1394
|
+
elsif value.is_a?(Array)
|
1395
|
+
value[0] = symbolize(value[0])
|
1396
|
+
result << value
|
1397
|
+
else
|
1398
|
+
devfail "Invalid relationship %s" % value.inspect
|
1399
|
+
end
|
1400
|
+
end
|
1401
|
+
end
|
1402
|
+
end
|
1403
|
+
|
1404
|
+
if existing = self[param]
|
1405
|
+
result = existing + result
|
1406
|
+
end
|
1407
|
+
|
1408
|
+
result
|
1409
|
+
end
|
1410
|
+
|
1411
|
+
newmetaparam(:loglevel) do
|
1412
|
+
desc "Sets the level that information will be logged.
|
1413
|
+
The log levels have the biggest impact when logs are sent to
|
1414
|
+
syslog (which is currently the default)."
|
1415
|
+
defaultto :notice
|
1416
|
+
|
1417
|
+
newvalues(*Puppet::Util::Log.levels)
|
1418
|
+
newvalues(:verbose)
|
1419
|
+
|
1420
|
+
munge do |loglevel|
|
1421
|
+
val = super(loglevel)
|
1422
|
+
if val == :verbose
|
1423
|
+
val = :info
|
1424
|
+
end
|
1425
|
+
val
|
1426
|
+
end
|
1427
|
+
end
|
1428
|
+
|
1429
|
+
newmetaparam(:alias) do
|
1430
|
+
desc "Creates an alias for the object. Puppet uses this internally when you
|
1431
|
+
provide a symbolic name::
|
1432
|
+
|
1433
|
+
file { sshdconfig:
|
1434
|
+
path => $operatingsystem ? {
|
1435
|
+
solaris => \"/usr/local/etc/ssh/sshd_config\",
|
1436
|
+
default => \"/etc/ssh/sshd_config\"
|
1437
|
+
},
|
1438
|
+
source => \"...\"
|
1439
|
+
}
|
1440
|
+
|
1441
|
+
service { sshd:
|
1442
|
+
subscribe => file[sshdconfig]
|
1443
|
+
}
|
1444
|
+
|
1445
|
+
When you use this feature, the parser sets ``sshdconfig`` as the name,
|
1446
|
+
and the library sets that as an alias for the file so the dependency
|
1447
|
+
lookup for ``sshd`` works. You can use this parameter yourself,
|
1448
|
+
but note that only the library can use these aliases; for instance,
|
1449
|
+
the following code will not work::
|
1450
|
+
|
1451
|
+
file { \"/etc/ssh/sshd_config\":
|
1452
|
+
owner => root,
|
1453
|
+
group => root,
|
1454
|
+
alias => sshdconfig
|
1455
|
+
}
|
1456
|
+
|
1457
|
+
file { sshdconfig:
|
1458
|
+
mode => 644
|
1459
|
+
}
|
1460
|
+
|
1461
|
+
There's no way here for the Puppet parser to know that these two stanzas
|
1462
|
+
should be affecting the same file.
|
1463
|
+
|
1464
|
+
See the `LanguageTutorial language tutorial`:trac: for more information.
|
1465
|
+
|
1466
|
+
"
|
1467
|
+
|
1468
|
+
munge do |aliases|
|
1469
|
+
unless aliases.is_a?(Array)
|
1470
|
+
aliases = [aliases]
|
1471
|
+
end
|
1472
|
+
|
1473
|
+
raise(ArgumentError, "Cannot add aliases without a catalog") unless @resource.catalog
|
1474
|
+
|
1475
|
+
aliases.each do |other|
|
1476
|
+
if obj = @resource.catalog.resource(@resource.class.name, other)
|
1477
|
+
unless obj.object_id == @resource.object_id
|
1478
|
+
self.fail("%s can not create alias %s: object already exists" % [@resource.title, other])
|
1479
|
+
end
|
1480
|
+
next
|
1481
|
+
end
|
1482
|
+
|
1483
|
+
# LAK:FIXME Old-school, add the alias to the class.
|
1484
|
+
@resource.class.alias(other, @resource)
|
1485
|
+
|
1486
|
+
# Newschool, add it to the catalog.
|
1487
|
+
@resource.catalog.alias(@resource, other)
|
1488
|
+
end
|
1489
|
+
end
|
1490
|
+
end
|
1491
|
+
|
1492
|
+
newmetaparam(:tag) do
|
1493
|
+
desc "Add the specified tags to the associated resource. While all resources
|
1494
|
+
are automatically tagged with as much information as possible
|
1495
|
+
(e.g., each class and definition containing the resource), it can
|
1496
|
+
be useful to add your own tags to a given resource.
|
1497
|
+
|
1498
|
+
Tags are currently useful for things like applying a subset of a
|
1499
|
+
host's configuration::
|
1500
|
+
|
1501
|
+
puppetd --test --tags mytag
|
1502
|
+
|
1503
|
+
This way, when you're testing a configuration you can run just the
|
1504
|
+
portion you're testing."
|
1505
|
+
|
1506
|
+
munge do |tags|
|
1507
|
+
tags = [tags] unless tags.is_a? Array
|
1508
|
+
|
1509
|
+
tags.each do |tag|
|
1510
|
+
@resource.tag(tag)
|
1511
|
+
end
|
1512
|
+
end
|
1513
|
+
end
|
1514
|
+
|
1515
|
+
class RelationshipMetaparam < Puppet::Parameter
|
1516
|
+
class << self
|
1517
|
+
attr_accessor :direction, :events, :callback, :subclasses
|
1518
|
+
end
|
1519
|
+
|
1520
|
+
@subclasses = []
|
1521
|
+
|
1522
|
+
def self.inherited(sub)
|
1523
|
+
@subclasses << sub
|
1524
|
+
end
|
1525
|
+
|
1526
|
+
def munge(rels)
|
1527
|
+
@resource.munge_relationship(self.class.name, rels)
|
1528
|
+
end
|
1529
|
+
|
1530
|
+
def validate_relationship
|
1531
|
+
@value.each do |value|
|
1532
|
+
unless @resource.catalog.resource(*value)
|
1533
|
+
description = self.class.direction == :in ? "dependency" : "dependent"
|
1534
|
+
fail Puppet::Error, "Could not find %s %s[%s] for %s" %
|
1535
|
+
[description, value[0].to_s.capitalize, value[1], resource.ref]
|
1536
|
+
end
|
1537
|
+
end
|
1538
|
+
end
|
1539
|
+
|
1540
|
+
# Create edges from each of our relationships. :in
|
1541
|
+
# relationships are specified by the event-receivers, and :out
|
1542
|
+
# relationships are specified by the event generator. This
|
1543
|
+
# way 'source' and 'target' are consistent terms in both edges
|
1544
|
+
# and events -- that is, an event targets edges whose source matches
|
1545
|
+
# the event's source. The direction of the relationship determines
|
1546
|
+
# which resource is applied first and which resource is considered
|
1547
|
+
# to be the event generator.
|
1548
|
+
def to_edges
|
1549
|
+
@value.collect do |value|
|
1550
|
+
# we just have a name and a type, and we need to convert it
|
1551
|
+
# to an object...
|
1552
|
+
tname, name = value
|
1553
|
+
reference = Puppet::ResourceReference.new(tname, name)
|
1554
|
+
|
1555
|
+
# Either of the two retrieval attempts could have returned
|
1556
|
+
# nil.
|
1557
|
+
unless object = reference.resolve
|
1558
|
+
self.fail "Could not retrieve dependency '%s' of %s" % [reference, @resource.ref]
|
1559
|
+
end
|
1560
|
+
|
1561
|
+
# Are we requiring them, or vice versa? See the method docs
|
1562
|
+
# for futher info on this.
|
1563
|
+
if self.class.direction == :in
|
1564
|
+
source = object
|
1565
|
+
target = @resource
|
1566
|
+
else
|
1567
|
+
source = @resource
|
1568
|
+
target = object
|
1569
|
+
end
|
1570
|
+
|
1571
|
+
if method = self.class.callback
|
1572
|
+
subargs = {
|
1573
|
+
:event => self.class.events,
|
1574
|
+
:callback => method
|
1575
|
+
}
|
1576
|
+
self.debug("subscribes to %s" % [object.ref])
|
1577
|
+
else
|
1578
|
+
# If there's no callback, there's no point in even adding
|
1579
|
+
# a label.
|
1580
|
+
subargs = nil
|
1581
|
+
self.debug("requires %s" % [object.ref])
|
1582
|
+
end
|
1583
|
+
|
1584
|
+
rel = Puppet::Relationship.new(source, target, subargs)
|
1585
|
+
end
|
1586
|
+
end
|
1587
|
+
end
|
1588
|
+
|
1589
|
+
def self.relationship_params
|
1590
|
+
RelationshipMetaparam.subclasses
|
1591
|
+
end
|
1592
|
+
|
1593
|
+
|
1594
|
+
# Note that the order in which the relationships params is defined
|
1595
|
+
# matters. The labelled params (notify and subcribe) must be later,
|
1596
|
+
# so that if both params are used, those ones win. It's a hackish
|
1597
|
+
# solution, but it works.
|
1598
|
+
|
1599
|
+
newmetaparam(:require, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do
|
1600
|
+
desc "One or more objects that this object depends on.
|
1601
|
+
This is used purely for guaranteeing that changes to required objects
|
1602
|
+
happen before the dependent object. For instance::
|
1603
|
+
|
1604
|
+
# Create the destination directory before you copy things down
|
1605
|
+
file { \"/usr/local/scripts\":
|
1606
|
+
ensure => directory
|
1607
|
+
}
|
1608
|
+
|
1609
|
+
file { \"/usr/local/scripts/myscript\":
|
1610
|
+
source => \"puppet://server/module/myscript\",
|
1611
|
+
mode => 755,
|
1612
|
+
require => File[\"/usr/local/scripts\"]
|
1613
|
+
}
|
1614
|
+
|
1615
|
+
Multiple dependencies can be specified by providing a comma-seperated list
|
1616
|
+
of resources, enclosed in square brackets::
|
1617
|
+
|
1618
|
+
require => [ File[\"/usr/local\"], File[\"/usr/local/scripts\"] ]
|
1619
|
+
|
1620
|
+
Note that Puppet will autorequire everything that it can, and
|
1621
|
+
there are hooks in place so that it's easy for resources to add new
|
1622
|
+
ways to autorequire objects, so if you think Puppet could be
|
1623
|
+
smarter here, let us know.
|
1624
|
+
|
1625
|
+
In fact, the above code was redundant -- Puppet will autorequire
|
1626
|
+
any parent directories that are being managed; it will
|
1627
|
+
automatically realize that the parent directory should be created
|
1628
|
+
before the script is pulled down.
|
1629
|
+
|
1630
|
+
Currently, exec resources will autorequire their CWD (if it is
|
1631
|
+
specified) plus any fully qualified paths that appear in the
|
1632
|
+
command. For instance, if you had an ``exec`` command that ran
|
1633
|
+
the ``myscript`` mentioned above, the above code that pulls the
|
1634
|
+
file down would be automatically listed as a requirement to the
|
1635
|
+
``exec`` code, so that you would always be running againts the
|
1636
|
+
most recent version.
|
1637
|
+
"
|
1638
|
+
end
|
1639
|
+
|
1640
|
+
newmetaparam(:subscribe, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :ALL_EVENTS, :callback => :refresh}) do
|
1641
|
+
desc "One or more objects that this object depends on. Changes in the
|
1642
|
+
subscribed to objects result in the dependent objects being
|
1643
|
+
refreshed (e.g., a service will get restarted). For instance::
|
1644
|
+
|
1645
|
+
class nagios {
|
1646
|
+
file { \"/etc/nagios/nagios.conf\":
|
1647
|
+
source => \"puppet://server/module/nagios.conf\",
|
1648
|
+
alias => nagconf # just to make things easier for me
|
1649
|
+
}
|
1650
|
+
service { nagios:
|
1651
|
+
running => true,
|
1652
|
+
subscribe => File[nagconf]
|
1653
|
+
}
|
1654
|
+
}
|
1655
|
+
|
1656
|
+
Currently the ``exec``, ``mount`` and ``service`` type support
|
1657
|
+
refreshing.
|
1658
|
+
"
|
1659
|
+
end
|
1660
|
+
|
1661
|
+
newmetaparam(:before, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do
|
1662
|
+
desc %{This parameter is the opposite of **require** -- it guarantees
|
1663
|
+
that the specified object is applied later than the specifying
|
1664
|
+
object::
|
1665
|
+
|
1666
|
+
file { "/var/nagios/configuration":
|
1667
|
+
source => "...",
|
1668
|
+
recurse => true,
|
1669
|
+
before => Exec["nagios-rebuid"]
|
1670
|
+
}
|
1671
|
+
|
1672
|
+
exec { "nagios-rebuild":
|
1673
|
+
command => "/usr/bin/make",
|
1674
|
+
cwd => "/var/nagios/configuration"
|
1675
|
+
}
|
1676
|
+
|
1677
|
+
This will make sure all of the files are up to date before the
|
1678
|
+
make command is run.}
|
1679
|
+
end
|
1680
|
+
|
1681
|
+
newmetaparam(:notify, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :ALL_EVENTS, :callback => :refresh}) do
|
1682
|
+
desc %{This parameter is the opposite of **subscribe** -- it sends events
|
1683
|
+
to the specified object::
|
1684
|
+
|
1685
|
+
file { "/etc/sshd_config":
|
1686
|
+
source => "....",
|
1687
|
+
notify => Service[sshd]
|
1688
|
+
}
|
1689
|
+
|
1690
|
+
service { sshd:
|
1691
|
+
ensure => running
|
1692
|
+
}
|
1693
|
+
|
1694
|
+
This will restart the sshd service if the sshd config file changes.}
|
1695
|
+
end
|
1696
|
+
|
1697
|
+
###############################
|
1698
|
+
# All of the provider plumbing for the resource types.
|
1699
|
+
require 'puppet/provider'
|
1700
|
+
require 'puppet/util/provider_features'
|
1701
|
+
|
1702
|
+
# Add the feature handling module.
|
1703
|
+
extend Puppet::Util::ProviderFeatures
|
1704
|
+
|
1705
|
+
attr_reader :provider
|
1706
|
+
|
1707
|
+
# the Type class attribute accessors
|
1708
|
+
class << self
|
1709
|
+
attr_accessor :providerloader
|
1710
|
+
attr_writer :defaultprovider
|
1711
|
+
end
|
1712
|
+
|
1713
|
+
# Find the default provider.
|
1714
|
+
def self.defaultprovider
|
1715
|
+
unless defined? @defaultprovider and @defaultprovider
|
1716
|
+
suitable = suitableprovider()
|
1717
|
+
|
1718
|
+
# Find which providers are a default for this system.
|
1719
|
+
defaults = suitable.find_all { |provider| provider.default? }
|
1720
|
+
|
1721
|
+
# If we don't have any default we use suitable providers
|
1722
|
+
defaults = suitable if defaults.empty?
|
1723
|
+
max = defaults.collect { |provider| provider.defaultnum }.max
|
1724
|
+
defaults = defaults.find_all { |provider| provider.defaultnum == max }
|
1725
|
+
|
1726
|
+
retval = nil
|
1727
|
+
if defaults.length > 1
|
1728
|
+
Puppet.warning(
|
1729
|
+
"Found multiple default providers for %s: %s; using %s" %
|
1730
|
+
[self.name, defaults.collect { |i| i.name.to_s }.join(", "),
|
1731
|
+
defaults[0].name]
|
1732
|
+
)
|
1733
|
+
retval = defaults.shift
|
1734
|
+
elsif defaults.length == 1
|
1735
|
+
retval = defaults.shift
|
1736
|
+
else
|
1737
|
+
raise Puppet::DevError, "Could not find a default provider for %s" %
|
1738
|
+
self.name
|
1739
|
+
end
|
1740
|
+
|
1741
|
+
@defaultprovider = retval
|
1742
|
+
end
|
1743
|
+
|
1744
|
+
return @defaultprovider
|
1745
|
+
end
|
1746
|
+
|
1747
|
+
# Convert a hash, as provided by, um, a provider, into an instance of self.
|
1748
|
+
def self.hash2obj(hash)
|
1749
|
+
obj = nil
|
1750
|
+
|
1751
|
+
namevar = self.namevar
|
1752
|
+
unless hash.include?(namevar) and hash[namevar]
|
1753
|
+
raise Puppet::DevError, "Hash was not passed with namevar"
|
1754
|
+
end
|
1755
|
+
|
1756
|
+
# if the obj already exists with that name...
|
1757
|
+
if obj = self[hash[namevar]]
|
1758
|
+
# We're assuming here that objects with the same name
|
1759
|
+
# are the same object, which *should* be the case, assuming
|
1760
|
+
# we've set up our naming stuff correctly everywhere.
|
1761
|
+
|
1762
|
+
# Mark found objects as present
|
1763
|
+
hash.each { |param, value|
|
1764
|
+
if property = obj.property(param)
|
1765
|
+
elsif val = obj[param]
|
1766
|
+
obj[param] = val
|
1767
|
+
else
|
1768
|
+
# There is a value on disk, but it should go away
|
1769
|
+
obj[param] = :absent
|
1770
|
+
end
|
1771
|
+
}
|
1772
|
+
else
|
1773
|
+
# create a new obj, since no existing one seems to
|
1774
|
+
# match
|
1775
|
+
obj = self.create(namevar => hash[namevar])
|
1776
|
+
|
1777
|
+
# We can't just pass the hash in at object creation time,
|
1778
|
+
# because it sets the should value, not the is value.
|
1779
|
+
hash.delete(namevar)
|
1780
|
+
hash.each { |param, value|
|
1781
|
+
obj[param] = value unless obj.add_property_parameter(param)
|
1782
|
+
}
|
1783
|
+
end
|
1784
|
+
|
1785
|
+
return obj
|
1786
|
+
end
|
1787
|
+
|
1788
|
+
# Retrieve a provider by name.
|
1789
|
+
def self.provider(name)
|
1790
|
+
name = Puppet::Util.symbolize(name)
|
1791
|
+
|
1792
|
+
# If we don't have it yet, try loading it.
|
1793
|
+
unless @providers.has_key?(name)
|
1794
|
+
@providerloader.load(name)
|
1795
|
+
end
|
1796
|
+
return @providers[name]
|
1797
|
+
end
|
1798
|
+
|
1799
|
+
# Just list all of the providers.
|
1800
|
+
def self.providers
|
1801
|
+
@providers.keys
|
1802
|
+
end
|
1803
|
+
|
1804
|
+
def self.validprovider?(name)
|
1805
|
+
name = Puppet::Util.symbolize(name)
|
1806
|
+
|
1807
|
+
return (@providers.has_key?(name) && @providers[name].suitable?)
|
1808
|
+
end
|
1809
|
+
|
1810
|
+
# Create a new provider of a type. This method must be called
|
1811
|
+
# directly on the type that it's implementing.
|
1812
|
+
def self.provide(name, options = {}, &block)
|
1813
|
+
name = Puppet::Util.symbolize(name)
|
1814
|
+
|
1815
|
+
if obj = @providers[name]
|
1816
|
+
Puppet.debug "Reloading %s %s provider" % [name, self.name]
|
1817
|
+
unprovide(name)
|
1818
|
+
end
|
1819
|
+
|
1820
|
+
parent = if pname = options[:parent]
|
1821
|
+
options.delete(:parent)
|
1822
|
+
if pname.is_a? Class
|
1823
|
+
pname
|
1824
|
+
else
|
1825
|
+
if provider = self.provider(pname)
|
1826
|
+
provider
|
1827
|
+
else
|
1828
|
+
raise Puppet::DevError,
|
1829
|
+
"Could not find parent provider %s of %s" %
|
1830
|
+
[pname, name]
|
1831
|
+
end
|
1832
|
+
end
|
1833
|
+
else
|
1834
|
+
Puppet::Provider
|
1835
|
+
end
|
1836
|
+
|
1837
|
+
options[:resource_type] ||= self
|
1838
|
+
|
1839
|
+
self.providify
|
1840
|
+
|
1841
|
+
provider = genclass(name,
|
1842
|
+
:parent => parent,
|
1843
|
+
:hash => @providers,
|
1844
|
+
:prefix => "Provider",
|
1845
|
+
:block => block,
|
1846
|
+
:include => feature_module,
|
1847
|
+
:extend => feature_module,
|
1848
|
+
:attributes => options
|
1849
|
+
)
|
1850
|
+
|
1851
|
+
return provider
|
1852
|
+
end
|
1853
|
+
|
1854
|
+
# Make sure we have a :provider parameter defined. Only gets called if there
|
1855
|
+
# are providers.
|
1856
|
+
def self.providify
|
1857
|
+
return if @paramhash.has_key? :provider
|
1858
|
+
|
1859
|
+
newparam(:provider) do
|
1860
|
+
desc "The specific backend for #{self.name.to_s} to use. You will
|
1861
|
+
seldom need to specify this -- Puppet will usually discover the
|
1862
|
+
appropriate provider for your platform."
|
1863
|
+
|
1864
|
+
# This is so we can refer back to the type to get a list of
|
1865
|
+
# providers for documentation.
|
1866
|
+
class << self
|
1867
|
+
attr_accessor :parenttype
|
1868
|
+
end
|
1869
|
+
|
1870
|
+
# We need to add documentation for each provider.
|
1871
|
+
def self.doc
|
1872
|
+
@doc + " Available providers are:\n\n" + parenttype().providers.sort { |a,b|
|
1873
|
+
a.to_s <=> b.to_s
|
1874
|
+
}.collect { |i|
|
1875
|
+
"* **%s**: %s" % [i, parenttype().provider(i).doc]
|
1876
|
+
}.join("\n")
|
1877
|
+
end
|
1878
|
+
|
1879
|
+
defaultto {
|
1880
|
+
@resource.class.defaultprovider.name
|
1881
|
+
}
|
1882
|
+
|
1883
|
+
validate do |provider_class|
|
1884
|
+
provider_class = provider_class[0] if provider_class.is_a? Array
|
1885
|
+
if provider_class.is_a?(Puppet::Provider)
|
1886
|
+
provider_class = provider_class.class.name
|
1887
|
+
end
|
1888
|
+
|
1889
|
+
unless provider = @resource.class.provider(provider_class)
|
1890
|
+
raise ArgumentError, "Invalid %s provider '%s'" % [@resource.class.name, provider_class]
|
1891
|
+
end
|
1892
|
+
end
|
1893
|
+
|
1894
|
+
munge do |provider|
|
1895
|
+
provider = provider[0] if provider.is_a? Array
|
1896
|
+
if provider.is_a? String
|
1897
|
+
provider = provider.intern
|
1898
|
+
end
|
1899
|
+
@resource.provider = provider
|
1900
|
+
|
1901
|
+
if provider.is_a?(Puppet::Provider)
|
1902
|
+
provider.class.name
|
1903
|
+
else
|
1904
|
+
provider
|
1905
|
+
end
|
1906
|
+
end
|
1907
|
+
end.parenttype = self
|
1908
|
+
end
|
1909
|
+
|
1910
|
+
def self.unprovide(name)
|
1911
|
+
if @providers.has_key? name
|
1912
|
+
rmclass(name,
|
1913
|
+
:hash => @providers,
|
1914
|
+
:prefix => "Provider"
|
1915
|
+
)
|
1916
|
+
if @defaultprovider and @defaultprovider.name == name
|
1917
|
+
@defaultprovider = nil
|
1918
|
+
end
|
1919
|
+
end
|
1920
|
+
end
|
1921
|
+
|
1922
|
+
# Return an array of all of the suitable providers.
|
1923
|
+
def self.suitableprovider
|
1924
|
+
if @providers.empty?
|
1925
|
+
providerloader.loadall
|
1926
|
+
end
|
1927
|
+
@providers.find_all { |name, provider|
|
1928
|
+
provider.suitable?
|
1929
|
+
}.collect { |name, provider|
|
1930
|
+
provider
|
1931
|
+
}.reject { |p| p.name == :fake } # For testing
|
1932
|
+
end
|
1933
|
+
|
1934
|
+
def provider=(name)
|
1935
|
+
if name.is_a?(Puppet::Provider)
|
1936
|
+
@provider = name
|
1937
|
+
@provider.resource = self
|
1938
|
+
elsif klass = self.class.provider(name)
|
1939
|
+
@provider = klass.new(self)
|
1940
|
+
else
|
1941
|
+
raise ArgumentError, "Could not find %s provider of %s" %
|
1942
|
+
[name, self.class.name]
|
1943
|
+
end
|
1944
|
+
end
|
1945
|
+
|
1946
|
+
###############################
|
1947
|
+
# All of the relationship code.
|
1948
|
+
|
1949
|
+
# Specify a block for generating a list of objects to autorequire. This
|
1950
|
+
# makes it so that you don't have to manually specify things that you clearly
|
1951
|
+
# require.
|
1952
|
+
def self.autorequire(name, &block)
|
1953
|
+
@autorequires ||= {}
|
1954
|
+
@autorequires[name] = block
|
1955
|
+
end
|
1956
|
+
|
1957
|
+
# Yield each of those autorequires in turn, yo.
|
1958
|
+
def self.eachautorequire
|
1959
|
+
@autorequires ||= {}
|
1960
|
+
@autorequires.each { |type, block|
|
1961
|
+
yield(type, block)
|
1962
|
+
}
|
1963
|
+
end
|
1964
|
+
|
1965
|
+
# Figure out of there are any objects we can automatically add as
|
1966
|
+
# dependencies.
|
1967
|
+
def autorequire
|
1968
|
+
reqs = []
|
1969
|
+
self.class.eachautorequire { |type, block|
|
1970
|
+
# Ignore any types we can't find, although that would be a bit odd.
|
1971
|
+
next unless typeobj = Puppet.type(type)
|
1972
|
+
|
1973
|
+
# Retrieve the list of names from the block.
|
1974
|
+
next unless list = self.instance_eval(&block)
|
1975
|
+
unless list.is_a?(Array)
|
1976
|
+
list = [list]
|
1977
|
+
end
|
1978
|
+
|
1979
|
+
# Collect the current prereqs
|
1980
|
+
list.each { |dep|
|
1981
|
+
obj = nil
|
1982
|
+
# Support them passing objects directly, to save some effort.
|
1983
|
+
unless dep.is_a? Puppet::Type
|
1984
|
+
# Skip autorequires that we aren't managing
|
1985
|
+
unless dep = typeobj[dep]
|
1986
|
+
next
|
1987
|
+
end
|
1988
|
+
end
|
1989
|
+
|
1990
|
+
reqs << Puppet::Relationship.new(dep, self)
|
1991
|
+
}
|
1992
|
+
}
|
1993
|
+
|
1994
|
+
return reqs
|
1995
|
+
end
|
1996
|
+
|
1997
|
+
# Build the dependencies associated with an individual object.
|
1998
|
+
def builddepends
|
1999
|
+
# Handle the requires
|
2000
|
+
self.class.relationship_params.collect do |klass|
|
2001
|
+
if param = @parameters[klass.name]
|
2002
|
+
param.to_edges
|
2003
|
+
end
|
2004
|
+
end.flatten.reject { |r| r.nil? }
|
2005
|
+
end
|
2006
|
+
|
2007
|
+
# Does this resource have a relationship with the other? We have to
|
2008
|
+
# check each object for both directions of relationship.
|
2009
|
+
def requires?(other)
|
2010
|
+
them = [other.class.name, other.title]
|
2011
|
+
me = [self.class.name, self.title]
|
2012
|
+
self.class.relationship_params.each do |param|
|
2013
|
+
case param.direction
|
2014
|
+
when :in: return true if v = self[param.name] and v.include?(them)
|
2015
|
+
when :out: return true if v = other[param.name] and v.include?(me)
|
2016
|
+
end
|
2017
|
+
end
|
2018
|
+
return false
|
2019
|
+
end
|
2020
|
+
|
2021
|
+
# we've received an event
|
2022
|
+
# we only support local events right now, so we can pass actual
|
2023
|
+
# objects around, including the transaction object
|
2024
|
+
# the assumption here is that container objects will pass received
|
2025
|
+
# methods on to contained objects
|
2026
|
+
# i.e., we don't trigger our children, our refresh() method calls
|
2027
|
+
# refresh() on our children
|
2028
|
+
def trigger(event, source)
|
2029
|
+
trans = event.transaction
|
2030
|
+
if @callbacks.include?(source)
|
2031
|
+
[:ALL_EVENTS, event.event].each { |eventname|
|
2032
|
+
if method = @callbacks[source][eventname]
|
2033
|
+
if trans.triggered?(self, method) > 0
|
2034
|
+
next
|
2035
|
+
end
|
2036
|
+
if self.respond_to?(method)
|
2037
|
+
self.send(method)
|
2038
|
+
end
|
2039
|
+
|
2040
|
+
trans.triggered(self, method)
|
2041
|
+
end
|
2042
|
+
}
|
2043
|
+
end
|
2044
|
+
end
|
2045
|
+
|
2046
|
+
# Unsubscribe from a given object, possibly with a specific event.
|
2047
|
+
def unsubscribe(object, event = nil)
|
2048
|
+
# First look through our own relationship params
|
2049
|
+
[:require, :subscribe].each do |param|
|
2050
|
+
if values = self[param]
|
2051
|
+
newvals = values.reject { |d|
|
2052
|
+
d == [object.class.name, object.title]
|
2053
|
+
}
|
2054
|
+
if newvals.length != values.length
|
2055
|
+
self.delete(param)
|
2056
|
+
self[param] = newvals
|
2057
|
+
end
|
2058
|
+
end
|
2059
|
+
end
|
2060
|
+
end
|
2061
|
+
|
2062
|
+
###############################
|
2063
|
+
# All of the scheduling code.
|
2064
|
+
|
2065
|
+
# Look up the schedule and set it appropriately. This is done after
|
2066
|
+
# the instantiation phase, so that the schedule can be anywhere in the
|
2067
|
+
# file.
|
2068
|
+
def schedule
|
2069
|
+
unless defined? @schedule
|
2070
|
+
if name = self[:schedule]
|
2071
|
+
if sched = Puppet.type(:schedule)[name]
|
2072
|
+
@schedule = sched
|
2073
|
+
else
|
2074
|
+
self.fail "Could not find schedule %s" % name
|
2075
|
+
end
|
2076
|
+
else
|
2077
|
+
@schedule = nil
|
2078
|
+
end
|
2079
|
+
end
|
2080
|
+
@schedule
|
2081
|
+
end
|
2082
|
+
|
2083
|
+
# Check whether we are scheduled to run right now or not.
|
2084
|
+
def scheduled?
|
2085
|
+
return true if Puppet[:ignoreschedules]
|
2086
|
+
return true unless schedule = self.schedule
|
2087
|
+
|
2088
|
+
# We use 'checked' here instead of 'synced' because otherwise we'll
|
2089
|
+
# end up checking most resources most times, because they will generally
|
2090
|
+
# have been synced a long time ago (e.g., a file only gets updated
|
2091
|
+
# once a month on the server and its schedule is daily; the last sync time
|
2092
|
+
# will have been a month ago, so we'd end up checking every run).
|
2093
|
+
return schedule.match?(self.cached(:checked).to_i)
|
2094
|
+
end
|
2095
|
+
|
2096
|
+
###############################
|
2097
|
+
# All of the tagging code.
|
2098
|
+
attr_reader :tags
|
2099
|
+
|
2100
|
+
# Add a new tag.
|
2101
|
+
def tag(tag)
|
2102
|
+
tag = tag.intern if tag.is_a? String
|
2103
|
+
unless @tags.include? tag
|
2104
|
+
@tags << tag
|
2105
|
+
end
|
2106
|
+
end
|
2107
|
+
|
2108
|
+
# Define the initial list of tags.
|
2109
|
+
def tags=(list)
|
2110
|
+
list = [list] unless list.is_a? Array
|
2111
|
+
|
2112
|
+
@tags = list.collect do |t|
|
2113
|
+
case t
|
2114
|
+
when String: t.intern
|
2115
|
+
when Symbol: t
|
2116
|
+
else
|
2117
|
+
self.warning "Ignoring tag %s of type %s" % [tag.inspect, tag.class]
|
2118
|
+
end
|
2119
|
+
end
|
2120
|
+
|
2121
|
+
@tags << self.class.name unless @tags.include?(self.class.name)
|
2122
|
+
end
|
2123
|
+
|
2124
|
+
# Figure out of any of the specified tags apply to this object. This is an
|
2125
|
+
# OR operation.
|
2126
|
+
def tagged?(tags)
|
2127
|
+
tags = [tags] unless tags.is_a? Array
|
2128
|
+
|
2129
|
+
tags = tags.collect { |t| t.intern }
|
2130
|
+
|
2131
|
+
return tags.find { |tag| @tags.include? tag }
|
2132
|
+
end
|
37
2133
|
|
38
2134
|
# Types (which map to resources in the languages) are entirely composed of
|
39
2135
|
# attribute value pairs. Generally, Puppet calls any of these things an
|