summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/puppet.rb216
-rw-r--r--lib/puppet/agent.rb170
-rw-r--r--lib/puppet/agent/locker.rb56
-rw-r--r--lib/puppet/application.rb478
-rw-r--r--lib/puppet/application/agent.rb434
-rw-r--r--lib/puppet/application/apply.rb258
-rw-r--r--lib/puppet/application/cert.rb142
-rw-r--r--lib/puppet/application/describe.rb334
-rw-r--r--lib/puppet/application/doc.rb364
-rw-r--r--lib/puppet/application/filebucket.rb142
-rw-r--r--lib/puppet/application/kick.rb358
-rw-r--r--lib/puppet/application/master.rb272
-rw-r--r--lib/puppet/application/queue.rb138
-rw-r--r--lib/puppet/application/resource.rb198
-rw-r--r--lib/puppet/configurer.rb426
-rw-r--r--lib/puppet/configurer/downloader.rb126
-rw-r--r--lib/puppet/configurer/fact_handler.rb102
-rw-r--r--lib/puppet/configurer/plugin_handler.rb38
-rwxr-xr-xlib/puppet/daemon.rb198
-rw-r--r--lib/puppet/defaults.rb1578
-rw-r--r--lib/puppet/dsl.rb2
-rw-r--r--lib/puppet/dsl/resource_api.rb194
-rw-r--r--lib/puppet/dsl/resource_type_api.rb54
-rw-r--r--lib/puppet/error.rb68
-rwxr-xr-xlib/puppet/external/base64.rb14
-rw-r--r--lib/puppet/external/dot.rb514
-rw-r--r--lib/puppet/external/event-loop/better-definers.rb608
-rw-r--r--lib/puppet/external/event-loop/event-loop.rb532
-rw-r--r--lib/puppet/external/event-loop/signal-system.rb324
-rw-r--r--lib/puppet/external/lock.rb82
-rwxr-xr-xlib/puppet/external/nagios.rb64
-rwxr-xr-xlib/puppet/external/nagios/base.rb906
-rw-r--r--lib/puppet/external/nagios/parser.rb1076
-rw-r--r--lib/puppet/external/pson/common.rb678
-rw-r--r--lib/puppet/external/pson/pure.rb124
-rw-r--r--lib/puppet/external/pson/pure/generator.rb836
-rw-r--r--lib/puppet/external/pson/pure/parser.rb486
-rw-r--r--lib/puppet/external/pson/version.rb12
-rw-r--r--lib/puppet/feature/base.rb4
-rw-r--r--lib/puppet/feature/pson.rb8
-rw-r--r--lib/puppet/feature/rack.rb28
-rw-r--r--lib/puppet/feature/rails.rb46
-rw-r--r--lib/puppet/file_bucket.rb2
-rw-r--r--lib/puppet/file_bucket/dipper.rb150
-rw-r--r--lib/puppet/file_bucket/file.rb260
-rw-r--r--lib/puppet/file_bucket/file/indirection_hooks.rb6
-rw-r--r--lib/puppet/file_collection.rb40
-rw-r--r--lib/puppet/file_collection/lookup.rb22
-rw-r--r--lib/puppet/file_serving/base.rb132
-rw-r--r--lib/puppet/file_serving/configuration.rb168
-rw-r--r--lib/puppet/file_serving/configuration/parser.rb198
-rw-r--r--lib/puppet/file_serving/content.rb68
-rw-r--r--lib/puppet/file_serving/fileset.rb262
-rw-r--r--lib/puppet/file_serving/indirection_hooks.rb34
-rw-r--r--lib/puppet/file_serving/metadata.rb194
-rw-r--r--lib/puppet/file_serving/mount.rb44
-rw-r--r--lib/puppet/file_serving/mount/file.rb202
-rw-r--r--lib/puppet/file_serving/mount/modules.rb30
-rw-r--r--lib/puppet/file_serving/mount/plugins.rb30
-rw-r--r--lib/puppet/file_serving/terminus_helper.rb26
-rw-r--r--lib/puppet/indirector.rb94
-rw-r--r--lib/puppet/indirector/active_record.rb38
-rw-r--r--lib/puppet/indirector/catalog/active_record.rb50
-rw-r--r--lib/puppet/indirector/catalog/compiler.rb268
-rw-r--r--lib/puppet/indirector/catalog/rest.rb2
-rw-r--r--lib/puppet/indirector/catalog/yaml.rb26
-rw-r--r--lib/puppet/indirector/certificate/ca.rb6
-rw-r--r--lib/puppet/indirector/certificate/file.rb6
-rw-r--r--lib/puppet/indirector/certificate/rest.rb16
-rw-r--r--lib/puppet/indirector/certificate_request/ca.rb14
-rw-r--r--lib/puppet/indirector/certificate_request/file.rb4
-rw-r--r--lib/puppet/indirector/certificate_request/rest.rb6
-rw-r--r--lib/puppet/indirector/certificate_revocation_list/ca.rb4
-rw-r--r--lib/puppet/indirector/certificate_revocation_list/file.rb4
-rw-r--r--lib/puppet/indirector/certificate_revocation_list/rest.rb6
-rw-r--r--lib/puppet/indirector/couch.rb116
-rw-r--r--lib/puppet/indirector/direct_file_server.rb22
-rw-r--r--lib/puppet/indirector/envelope.rb8
-rw-r--r--lib/puppet/indirector/exec.rb76
-rw-r--r--lib/puppet/indirector/facts/active_record.rb48
-rw-r--r--lib/puppet/indirector/facts/couch.rb40
-rw-r--r--lib/puppet/indirector/facts/facter.rb126
-rw-r--r--lib/puppet/indirector/facts/memory.rb8
-rw-r--r--lib/puppet/indirector/facts/rest.rb2
-rw-r--r--lib/puppet/indirector/facts/yaml.rb4
-rw-r--r--lib/puppet/indirector/file.rb124
-rw-r--r--lib/puppet/indirector/file_bucket_file/file.rb218
-rw-r--r--lib/puppet/indirector/file_bucket_file/rest.rb6
-rw-r--r--lib/puppet/indirector/file_content/file.rb2
-rw-r--r--lib/puppet/indirector/file_content/file_server.rb2
-rw-r--r--lib/puppet/indirector/file_content/rest.rb2
-rw-r--r--lib/puppet/indirector/file_metadata/file.rb22
-rw-r--r--lib/puppet/indirector/file_metadata/file_server.rb2
-rw-r--r--lib/puppet/indirector/file_metadata/rest.rb2
-rw-r--r--lib/puppet/indirector/file_server.rb88
-rw-r--r--lib/puppet/indirector/indirection.rb498
-rw-r--r--lib/puppet/indirector/key/ca.rb10
-rw-r--r--lib/puppet/indirector/key/file.rb58
-rw-r--r--lib/puppet/indirector/ldap.rb124
-rw-r--r--lib/puppet/indirector/memory.rb26
-rw-r--r--lib/puppet/indirector/node/active_record.rb12
-rw-r--r--lib/puppet/indirector/node/exec.rb80
-rw-r--r--lib/puppet/indirector/node/ldap.rb492
-rw-r--r--lib/puppet/indirector/node/memory.rb10
-rw-r--r--lib/puppet/indirector/node/plain.rb24
-rw-r--r--lib/puppet/indirector/node/rest.rb4
-rw-r--r--lib/puppet/indirector/node/yaml.rb4
-rw-r--r--lib/puppet/indirector/plain.rb8
-rw-r--r--lib/puppet/indirector/queue.rb98
-rw-r--r--lib/puppet/indirector/report/processor.rb68
-rw-r--r--lib/puppet/indirector/report/rest.rb6
-rw-r--r--lib/puppet/indirector/request.rb342
-rw-r--r--lib/puppet/indirector/resource/ral.rb76
-rw-r--r--lib/puppet/indirector/resource_type/parser.rb34
-rw-r--r--lib/puppet/indirector/resource_type/rest.rb2
-rw-r--r--lib/puppet/indirector/rest.rb164
-rw-r--r--lib/puppet/indirector/run/local.rb6
-rw-r--r--lib/puppet/indirector/run/rest.rb2
-rw-r--r--lib/puppet/indirector/ssl_file.rb330
-rw-r--r--lib/puppet/indirector/status/local.rb6
-rw-r--r--lib/puppet/indirector/terminus.rb258
-rw-r--r--lib/puppet/indirector/yaml.rb94
-rw-r--r--lib/puppet/metatype/manager.rb218
-rw-r--r--lib/puppet/module.rb394
-rw-r--r--lib/puppet/network/authconfig.rb290
-rw-r--r--lib/puppet/network/authorization.rb126
-rwxr-xr-xlib/puppet/network/authstore.rb452
-rw-r--r--lib/puppet/network/client.rb276
-rw-r--r--lib/puppet/network/client/ca.rb94
-rw-r--r--lib/puppet/network/client/file.rb6
-rw-r--r--lib/puppet/network/client/proxy.rb38
-rw-r--r--lib/puppet/network/client/report.rb34
-rw-r--r--lib/puppet/network/client/runner.rb10
-rw-r--r--lib/puppet/network/client/status.rb2
-rw-r--r--lib/puppet/network/client_request.rb40
-rw-r--r--lib/puppet/network/format.rb158
-rw-r--r--lib/puppet/network/format_handler.rb264
-rw-r--r--lib/puppet/network/formats.rb248
-rw-r--r--lib/puppet/network/handler.rb86
-rw-r--r--lib/puppet/network/handler/ca.rb258
-rwxr-xr-xlib/puppet/network/handler/filebucket.rb86
-rwxr-xr-xlib/puppet/network/handler/fileserver.rb1250
-rw-r--r--lib/puppet/network/handler/master.rb126
-rwxr-xr-xlib/puppet/network/handler/report.rb120
-rwxr-xr-xlib/puppet/network/handler/runner.rb38
-rw-r--r--lib/puppet/network/handler/status.rb18
-rw-r--r--lib/puppet/network/http.rb24
-rw-r--r--lib/puppet/network/http/api/v1.rb96
-rw-r--r--lib/puppet/network/http/compression.rb194
-rw-r--r--lib/puppet/network/http/handler.rb388
-rw-r--r--lib/puppet/network/http/mongrel.rb98
-rw-r--r--lib/puppet/network/http/mongrel/rest.rb146
-rw-r--r--lib/puppet/network/http/rack.rb90
-rw-r--r--lib/puppet/network/http/rack/httphandler.rb14
-rw-r--r--lib/puppet/network/http/rack/rest.rb168
-rw-r--r--lib/puppet/network/http/rack/xmlrpc.rb98
-rw-r--r--lib/puppet/network/http/webrick.rb216
-rw-r--r--lib/puppet/network/http/webrick/rest.rb120
-rw-r--r--lib/puppet/network/http_pool.rb190
-rw-r--r--lib/puppet/network/http_server/mongrel.rb180
-rw-r--r--lib/puppet/network/http_server/webrick.rb278
-rw-r--r--lib/puppet/network/rest_authconfig.rb148
-rw-r--r--lib/puppet/network/rest_authorization.rb22
-rwxr-xr-xlib/puppet/network/rights.rb434
-rw-r--r--lib/puppet/network/server.rb298
-rw-r--r--lib/puppet/network/xmlrpc/client.rb394
-rw-r--r--lib/puppet/network/xmlrpc/processor.rb136
-rw-r--r--lib/puppet/network/xmlrpc/server.rb20
-rw-r--r--lib/puppet/network/xmlrpc/webrick_servlet.rb180
-rw-r--r--lib/puppet/node.rb188
-rw-r--r--lib/puppet/node/environment.rb200
-rwxr-xr-xlib/puppet/node/facts.rb94
-rw-r--r--lib/puppet/parameter.rb494
-rw-r--r--lib/puppet/parameter/value.rb104
-rw-r--r--lib/puppet/parameter/value_collection.rb230
-rw-r--r--lib/puppet/parser/ast.rb128
-rw-r--r--lib/puppet/parser/ast/arithmetic_operator.rb54
-rw-r--r--lib/puppet/parser/ast/astarray.rb100
-rw-r--r--lib/puppet/parser/ast/asthash.rb52
-rw-r--r--lib/puppet/parser/ast/boolean_operator.rb66
-rw-r--r--lib/puppet/parser/ast/branch.rb58
-rw-r--r--lib/puppet/parser/ast/caseopt.rb100
-rw-r--r--lib/puppet/parser/ast/casestatement.rb60
-rw-r--r--lib/puppet/parser/ast/collection.rb78
-rw-r--r--lib/puppet/parser/ast/collexpr.rb132
-rw-r--r--lib/puppet/parser/ast/comparison_operator.rb66
-rw-r--r--lib/puppet/parser/ast/else.rb26
-rw-r--r--lib/puppet/parser/ast/function.rb68
-rw-r--r--lib/puppet/parser/ast/ifstatement.rb46
-rw-r--r--lib/puppet/parser/ast/in_operator.rb28
-rw-r--r--lib/puppet/parser/ast/leaf.rb342
-rw-r--r--lib/puppet/parser/ast/match_operator.rb32
-rw-r--r--lib/puppet/parser/ast/minus.rb26
-rw-r--r--lib/puppet/parser/ast/nop.rb12
-rw-r--r--lib/puppet/parser/ast/not.rb18
-rw-r--r--lib/puppet/parser/ast/relationship.rb84
-rw-r--r--lib/puppet/parser/ast/resource.rb108
-rw-r--r--lib/puppet/parser/ast/resource_defaults.rb32
-rw-r--r--lib/puppet/parser/ast/resource_override.rb98
-rw-r--r--lib/puppet/parser/ast/resource_reference.rb26
-rw-r--r--lib/puppet/parser/ast/resourceparam.rb36
-rw-r--r--lib/puppet/parser/ast/selector.rb60
-rw-r--r--lib/puppet/parser/ast/tag.rb32
-rw-r--r--lib/puppet/parser/ast/vardef.rb40
-rw-r--r--lib/puppet/parser/collector.rb360
-rw-r--r--lib/puppet/parser/compiler.rb822
-rw-r--r--lib/puppet/parser/files.rb130
-rw-r--r--lib/puppet/parser/functions.rb158
-rw-r--r--lib/puppet/parser/functions/defined.rb46
-rw-r--r--lib/puppet/parser/functions/fail.rb4
-rw-r--r--lib/puppet/parser/functions/file.rb38
-rw-r--r--lib/puppet/parser/functions/fqdn_rand.rb14
-rw-r--r--lib/puppet/parser/functions/generate.rb48
-rw-r--r--lib/puppet/parser/functions/include.rb32
-rw-r--r--lib/puppet/parser/functions/inline_template.rb32
-rw-r--r--lib/puppet/parser/functions/realize.rb16
-rw-r--r--lib/puppet/parser/functions/regsubst.rb144
-rw-r--r--lib/puppet/parser/functions/require.rb76
-rw-r--r--lib/puppet/parser/functions/search.rb10
-rw-r--r--lib/puppet/parser/functions/sha1.rb4
-rw-r--r--lib/puppet/parser/functions/shellquote.rb62
-rw-r--r--lib/puppet/parser/functions/split.rb22
-rw-r--r--lib/puppet/parser/functions/sprintf.rb16
-rw-r--r--lib/puppet/parser/functions/tag.rb6
-rw-r--r--lib/puppet/parser/functions/tagged.rb26
-rw-r--r--lib/puppet/parser/functions/template.rb36
-rw-r--r--lib/puppet/parser/functions/versioncmp.rb30
-rw-r--r--lib/puppet/parser/grammar.ra996
-rw-r--r--lib/puppet/parser/lexer.rb1004
-rw-r--r--lib/puppet/parser/parser_support.rb454
-rw-r--r--lib/puppet/parser/relationship.rb68
-rw-r--r--lib/puppet/parser/resource.rb552
-rw-r--r--lib/puppet/parser/resource/param.rb34
-rw-r--r--lib/puppet/parser/scope.rb898
-rw-r--r--lib/puppet/parser/templatewrapper.rb184
-rw-r--r--lib/puppet/parser/type_loader.rb242
-rw-r--r--lib/puppet/parser/yaml_trimmer.rb12
-rw-r--r--lib/puppet/property.rb562
-rw-r--r--lib/puppet/property/ensure.rb146
-rw-r--r--lib/puppet/property/keyvalue.rb148
-rw-r--r--lib/puppet/property/list.rb142
-rw-r--r--lib/puppet/property/ordered_list.rb30
-rw-r--r--lib/puppet/provider.rb452
-rw-r--r--lib/puppet/provider/augeas/augeas.rb636
-rw-r--r--lib/puppet/provider/computer/computer.rb26
-rw-r--r--lib/puppet/provider/confine.rb126
-rw-r--r--lib/puppet/provider/confine/exists.rb28
-rw-r--r--lib/puppet/provider/confine/false.rb24
-rw-r--r--lib/puppet/provider/confine/feature.rb20
-rw-r--r--lib/puppet/provider/confine/true.rb26
-rw-r--r--lib/puppet/provider/confine/variable.rb102
-rw-r--r--lib/puppet/provider/confine_collection.rb76
-rw-r--r--lib/puppet/provider/confiner.rb20
-rwxr-xr-xlib/puppet/provider/cron/crontab.rb336
-rw-r--r--lib/puppet/provider/file/posix.rb146
-rw-r--r--lib/puppet/provider/file/win32.rb112
-rw-r--r--lib/puppet/provider/group/directoryservice.rb12
-rw-r--r--lib/puppet/provider/group/groupadd.rb36
-rw-r--r--lib/puppet/provider/group/ldap.rb80
-rw-r--r--lib/puppet/provider/group/pw.rb46
-rw-r--r--lib/puppet/provider/host/parsed.rb98
-rw-r--r--lib/puppet/provider/ldap.rb242
-rw-r--r--lib/puppet/provider/macauthorization/macauthorization.rb526
-rwxr-xr-xlib/puppet/provider/mailalias/aliases.rb64
-rwxr-xr-xlib/puppet/provider/maillist/mailman.rb174
-rw-r--r--lib/puppet/provider/mcx/mcxcontent.rb308
-rw-r--r--lib/puppet/provider/mount.rb72
-rwxr-xr-xlib/puppet/provider/mount/parsed.rb52
-rw-r--r--lib/puppet/provider/naginator.rb92
-rw-r--r--lib/puppet/provider/nameservice.rb430
-rw-r--r--lib/puppet/provider/nameservice/directoryservice.rb912
-rw-r--r--lib/puppet/provider/nameservice/objectadd.rb42
-rw-r--r--lib/puppet/provider/nameservice/pw.rb26
-rw-r--r--lib/puppet/provider/package.rb36
-rw-r--r--lib/puppet/provider/package/aix.rb180
-rw-r--r--lib/puppet/provider/package/appdmg.rb152
-rwxr-xr-xlib/puppet/provider/package/apple.rb74
-rwxr-xr-xlib/puppet/provider/package/apt.rb176
-rwxr-xr-xlib/puppet/provider/package/aptitude.rb38
-rw-r--r--lib/puppet/provider/package/aptrpm.rb140
-rwxr-xr-xlib/puppet/provider/package/blastwave.rb176
-rwxr-xr-xlib/puppet/provider/package/darwinport.rb134
-rwxr-xr-xlib/puppet/provider/package/dpkg.rb242
-rwxr-xr-xlib/puppet/provider/package/fink.rb132
-rwxr-xr-xlib/puppet/provider/package/freebsd.rb76
-rwxr-xr-xlib/puppet/provider/package/gem.rb196
-rw-r--r--lib/puppet/provider/package/hpux.rb74
-rw-r--r--lib/puppet/provider/package/nim.rb42
-rwxr-xr-xlib/puppet/provider/package/openbsd.rb198
-rw-r--r--lib/puppet/provider/package/pkg.rb164
-rw-r--r--lib/puppet/provider/package/pkgdmg.rb182
-rw-r--r--lib/puppet/provider/package/portage.rb200
-rwxr-xr-xlib/puppet/provider/package/ports.rb142
-rw-r--r--lib/puppet/provider/package/portupgrade.rb406
-rwxr-xr-xlib/puppet/provider/package/rpm.rb226
-rw-r--r--lib/puppet/provider/package/rug.rb92
-rwxr-xr-xlib/puppet/provider/package/sun.rb270
-rwxr-xr-xlib/puppet/provider/package/sunfreeware.rb10
-rw-r--r--lib/puppet/provider/package/up2date.rb62
-rw-r--r--lib/puppet/provider/package/urpmi.rb102
-rwxr-xr-xlib/puppet/provider/package/yum.rb178
-rw-r--r--lib/puppet/provider/package/zypper.rb92
-rwxr-xr-xlib/puppet/provider/parsedfile.rb608
-rw-r--r--lib/puppet/provider/selboolean/getsetsebool.rb70
-rw-r--r--lib/puppet/provider/selmodule/semodule.rb206
-rwxr-xr-xlib/puppet/provider/service/base.rb268
-rw-r--r--lib/puppet/provider/service/bsd.rb82
-rw-r--r--lib/puppet/provider/service/daemontools.rb314
-rwxr-xr-xlib/puppet/provider/service/debian.rb84
-rw-r--r--lib/puppet/provider/service/freebsd.rb254
-rw-r--r--lib/puppet/provider/service/gentoo.rb64
-rwxr-xr-xlib/puppet/provider/service/init.rb250
-rw-r--r--lib/puppet/provider/service/launchd.rb468
-rwxr-xr-xlib/puppet/provider/service/redhat.rb116
-rw-r--r--lib/puppet/provider/service/runit.rb160
-rwxr-xr-xlib/puppet/provider/service/smf.rb164
-rwxr-xr-xlib/puppet/provider/service/src.rb162
-rw-r--r--lib/puppet/provider/ssh_authorized_key/parsed.rb142
-rwxr-xr-xlib/puppet/provider/sshkey/parsed.rb44
-rw-r--r--lib/puppet/provider/user/directoryservice.rb142
-rw-r--r--lib/puppet/provider/user/hpux.rb40
-rw-r--r--lib/puppet/provider/user/ldap.rb212
-rw-r--r--lib/puppet/provider/user/pw.rb64
-rw-r--r--lib/puppet/provider/user/user_role_add.rb336
-rw-r--r--lib/puppet/provider/user/useradd.rb100
-rw-r--r--lib/puppet/provider/zfs/solaris.rb70
-rw-r--r--lib/puppet/provider/zone/solaris.rb414
-rw-r--r--lib/puppet/provider/zpool/solaris.rb190
-rw-r--r--lib/puppet/rails.rb222
-rw-r--r--lib/puppet/rails/benchmark.rb86
-rw-r--r--lib/puppet/rails/database/001_add_created_at_to_all_tables.rb16
-rw-r--r--lib/puppet/rails/database/002_remove_duplicated_index_on_all_tables.rb16
-rw-r--r--lib/puppet/rails/database/003_add_environment_to_host.rb12
-rw-r--r--lib/puppet/rails/database/schema.rb198
-rw-r--r--lib/puppet/rails/fact_name.rb2
-rw-r--r--lib/puppet/rails/fact_value.rb10
-rw-r--r--lib/puppet/rails/host.rb504
-rw-r--r--lib/puppet/rails/param_name.rb30
-rw-r--r--lib/puppet/rails/param_value.rb110
-rw-r--r--lib/puppet/rails/puppet_tag.rb8
-rw-r--r--lib/puppet/rails/resource.rb376
-rw-r--r--lib/puppet/rails/resource_tag.rb38
-rw-r--r--lib/puppet/rails/source_file.rb10
-rw-r--r--lib/puppet/reference/configuration.rb94
-rw-r--r--lib/puppet/reference/function.rb2
-rw-r--r--lib/puppet/reference/indirection.rb24
-rw-r--r--lib/puppet/reference/metaparameter.rb80
-rw-r--r--lib/puppet/reference/network.rb28
-rw-r--r--lib/puppet/reference/providers.rb194
-rw-r--r--lib/puppet/reference/report.rb2
-rw-r--r--lib/puppet/reference/type.rb172
-rw-r--r--lib/puppet/relationship.rb130
-rwxr-xr-xlib/puppet/reports.rb64
-rw-r--r--lib/puppet/reports/http.rb28
-rw-r--r--lib/puppet/reports/log.rb14
-rw-r--r--lib/puppet/reports/rrdgraph.rb212
-rw-r--r--lib/puppet/reports/store.rb92
-rw-r--r--lib/puppet/reports/tagmail.rb298
-rw-r--r--lib/puppet/resource.rb860
-rw-r--r--lib/puppet/resource/catalog.rb982
-rw-r--r--lib/puppet/resource/status.rb108
-rw-r--r--lib/puppet/resource/type.rb454
-rw-r--r--lib/puppet/resource/type_collection.rb332
-rw-r--r--lib/puppet/resource/type_collection_helper.rb6
-rw-r--r--lib/puppet/run.rb98
-rw-r--r--lib/puppet/simple_graph.rb764
-rw-r--r--lib/puppet/ssl.rb4
-rw-r--r--lib/puppet/ssl/base.rb140
-rw-r--r--lib/puppet/ssl/certificate.rb42
-rw-r--r--lib/puppet/ssl/certificate_authority.rb426
-rw-r--r--lib/puppet/ssl/certificate_authority/interface.rb250
-rw-r--r--lib/puppet/ssl/certificate_factory.rb238
-rw-r--r--lib/puppet/ssl/certificate_request.rb104
-rw-r--r--lib/puppet/ssl/certificate_revocation_list.rb156
-rw-r--r--lib/puppet/ssl/host.rb460
-rw-r--r--lib/puppet/ssl/inventory.rb66
-rw-r--r--lib/puppet/ssl/key.rb74
-rwxr-xr-xlib/puppet/sslcertificates.rb248
-rw-r--r--lib/puppet/sslcertificates/ca.rb646
-rw-r--r--lib/puppet/sslcertificates/certificate.rb376
-rw-r--r--lib/puppet/sslcertificates/inventory.rb54
-rw-r--r--lib/puppet/sslcertificates/support.rb226
-rw-r--r--lib/puppet/status.rb36
-rw-r--r--lib/puppet/transaction.rb606
-rw-r--r--lib/puppet/transaction/change.rb160
-rw-r--r--lib/puppet/transaction/event.rb82
-rw-r--r--lib/puppet/transaction/event_manager.rb160
-rw-r--r--lib/puppet/transaction/report.rb230
-rw-r--r--lib/puppet/transaction/resource_harness.rb240
-rw-r--r--lib/puppet/transportable.rb430
-rw-r--r--lib/puppet/type.rb3302
-rw-r--r--lib/puppet/type/augeas.rb306
-rw-r--r--lib/puppet/type/component.rb126
-rw-r--r--lib/puppet/type/computer.rb88
-rwxr-xr-xlib/puppet/type/cron.rb730
-rwxr-xr-xlib/puppet/type/exec.rb1156
-rw-r--r--lib/puppet/type/file.rb1488
-rwxr-xr-xlib/puppet/type/file/checksum.rb40
-rwxr-xr-xlib/puppet/type/file/content.rb348
-rwxr-xr-xlib/puppet/type/file/ensure.rb298
-rwxr-xr-xlib/puppet/type/file/group.rb188
-rwxr-xr-xlib/puppet/type/file/mode.rb216
-rwxr-xr-xlib/puppet/type/file/owner.rb80
-rw-r--r--lib/puppet/type/file/selcontext.rb138
-rwxr-xr-xlib/puppet/type/file/source.rb326
-rw-r--r--lib/puppet/type/file/target.rb112
-rwxr-xr-xlib/puppet/type/file/type.rb36
-rwxr-xr-xlib/puppet/type/filebucket.rb182
-rwxr-xr-xlib/puppet/type/group.rb156
-rwxr-xr-xlib/puppet/type/host.rb170
-rw-r--r--lib/puppet/type/k5login.rb130
-rw-r--r--lib/puppet/type/macauthorization.rb282
-rwxr-xr-xlib/puppet/type/mailalias.rb74
-rwxr-xr-xlib/puppet/type/maillist.rb102
-rw-r--r--lib/puppet/type/mcx.rb124
-rwxr-xr-xlib/puppet/type/mount.rb392
-rw-r--r--lib/puppet/type/notify.rb66
-rw-r--r--lib/puppet/type/package.rb576
-rw-r--r--lib/puppet/type/resources.rb214
-rwxr-xr-xlib/puppet/type/schedule.rb624
-rw-r--r--lib/puppet/type/selboolean.rb38
-rw-r--r--lib/puppet/type/selmodule.rb68
-rw-r--r--lib/puppet/type/service.rb304
-rw-r--r--lib/puppet/type/ssh_authorized_key.rb148
-rwxr-xr-xlib/puppet/type/sshkey.rb104
-rw-r--r--lib/puppet/type/stage.rb22
-rwxr-xr-xlib/puppet/type/tidy.rb580
-rwxr-xr-xlib/puppet/type/user.rb600
-rw-r--r--lib/puppet/type/yumrepo.rb602
-rwxr-xr-xlib/puppet/type/zfs.rb72
-rw-r--r--lib/puppet/type/zone.rb746
-rwxr-xr-xlib/puppet/type/zpool.rb118
-rw-r--r--lib/puppet/util.rb762
-rw-r--r--lib/puppet/util/autoload.rb250
-rw-r--r--lib/puppet/util/autoload/file_cache.rb142
-rw-r--r--lib/puppet/util/backups.rb130
-rw-r--r--lib/puppet/util/cacher.rb224
-rw-r--r--lib/puppet/util/checksums.rb242
-rw-r--r--lib/puppet/util/classgen.rb316
-rw-r--r--lib/puppet/util/command_line.rb178
-rw-r--r--lib/puppet/util/constant_inflector.rb14
-rw-r--r--lib/puppet/util/diff.rb116
-rw-r--r--lib/puppet/util/docs.rb194
-rw-r--r--lib/puppet/util/errors.rb104
-rw-r--r--lib/puppet/util/execution.rb30
-rw-r--r--lib/puppet/util/feature.rb124
-rw-r--r--lib/puppet/util/file_locking.rb66
-rw-r--r--lib/puppet/util/fileparsing.rb588
-rwxr-xr-xlib/puppet/util/filetype.rb478
-rw-r--r--lib/puppet/util/graph.rb32
-rw-r--r--lib/puppet/util/inifile.rb340
-rw-r--r--lib/puppet/util/inline_docs.rb36
-rwxr-xr-xlib/puppet/util/instance_loader.rb116
-rw-r--r--lib/puppet/util/ldap/connection.rb114
-rw-r--r--lib/puppet/util/ldap/generator.rb62
-rw-r--r--lib/puppet/util/ldap/manager.rb468
-rwxr-xr-xlib/puppet/util/loadedfile.rb98
-rw-r--r--lib/puppet/util/log.rb416
-rw-r--r--lib/puppet/util/log/destination.rb78
-rw-r--r--lib/puppet/util/log/destinations.rb360
-rw-r--r--lib/puppet/util/log_paths.rb30
-rw-r--r--lib/puppet/util/logging.rb54
-rw-r--r--lib/puppet/util/metaid.rb30
-rw-r--r--lib/puppet/util/methodhelper.rb48
-rw-r--r--lib/puppet/util/metric.rb246
-rw-r--r--lib/puppet/util/monkey_patches.rb38
-rw-r--r--lib/puppet/util/nagios_maker.rb82
-rw-r--r--lib/puppet/util/package.rb48
-rw-r--r--lib/puppet/util/pidlock.rb98
-rwxr-xr-xlib/puppet/util/posix.rb230
-rw-r--r--lib/puppet/util/provider_features.rb294
-rw-r--r--lib/puppet/util/pson.rb8
-rw-r--r--lib/puppet/util/queue.rb108
-rw-r--r--lib/puppet/util/queue/stomp.rb54
-rw-r--r--lib/puppet/util/rails/cache_accumulator.rb98
-rw-r--r--lib/puppet/util/rails/collection_merger.rb26
-rw-r--r--lib/puppet/util/rails/reference_serializer.rb52
-rw-r--r--lib/puppet/util/rdoc.rb154
-rw-r--r--lib/puppet/util/rdoc/code_objects.rb470
-rw-r--r--lib/puppet/util/rdoc/generators/puppet_generator.rb1432
-rw-r--r--lib/puppet/util/rdoc/parser.rb832
-rw-r--r--lib/puppet/util/reference.rb324
-rw-r--r--lib/puppet/util/resource_template.rb32
-rw-r--r--lib/puppet/util/run_mode.rb128
-rw-r--r--lib/puppet/util/selinux.rb368
-rw-r--r--lib/puppet/util/settings.rb1786
-rw-r--r--lib/puppet/util/settings/boolean_setting.rb40
-rw-r--r--lib/puppet/util/settings/file_setting.rb196
-rw-r--r--lib/puppet/util/settings/setting.rb142
-rw-r--r--lib/puppet/util/storage.rb146
-rw-r--r--lib/puppet/util/subclass_loader.rb114
-rw-r--r--lib/puppet/util/suidmanager.rb190
-rw-r--r--lib/puppet/util/tagging.rb74
-rw-r--r--lib/puppet/util/user_attr.rb28
-rw-r--r--lib/puppet/util/warnings.rb40
-rw-r--r--lib/puppet/util/zaml.rb476
496 files changed, 47547 insertions, 47547 deletions
diff --git a/lib/puppet.rb b/lib/puppet.rb
index dc14c8716..902f5bf5c 100644
--- a/lib/puppet.rb
+++ b/lib/puppet.rb
@@ -1,6 +1,6 @@
# Try to load rubygems. Hey rubygems, I hate you.
begin
- require 'rubygems'
+ require 'rubygems'
rescue LoadError
end
@@ -24,134 +24,134 @@ require 'puppet/util/run_mode'
# it's also a place to find top-level commands like 'debug'
module Puppet
- PUPPETVERSION = '2.6.0'
+ PUPPETVERSION = '2.6.0'
- def Puppet.version
- PUPPETVERSION
- end
-
- class << self
- include Puppet::Util
- attr_reader :features
- attr_writer :name
- end
+ def Puppet.version
+ PUPPETVERSION
+ end
- # the hash that determines how our system behaves
- @@settings = Puppet::Util::Settings.new
+ class << self
+ include Puppet::Util
+ attr_reader :features
+ attr_writer :name
+ end
- # The services running in this process.
- @services ||= []
+ # the hash that determines how our system behaves
+ @@settings = Puppet::Util::Settings.new
- require 'puppet/util/logging'
+ # The services running in this process.
+ @services ||= []
- extend Puppet::Util::Logging
+ require 'puppet/util/logging'
- # The feature collection
- @features = Puppet::Util::Feature.new('puppet/feature')
+ extend Puppet::Util::Logging
- # Load the base features.
- require 'puppet/feature/base'
+ # The feature collection
+ @features = Puppet::Util::Feature.new('puppet/feature')
- # Store a new default value.
- def self.setdefaults(section, hash)
- @@settings.setdefaults(section, hash)
- end
+ # Load the base features.
+ require 'puppet/feature/base'
- # configuration parameter access and stuff
- def self.[](param)
- case param
- when :debug
- return Puppet::Util::Log.level == :debug
- else
- return @@settings[param]
- end
- end
+ # Store a new default value.
+ def self.setdefaults(section, hash)
+ @@settings.setdefaults(section, hash)
+ end
- # configuration parameter access and stuff
- def self.[]=(param,value)
- @@settings[param] = value
- end
-
- def self.clear
- @@settings.clear
- end
-
- def self.debug=(value)
- if value
- Puppet::Util::Log.level=(:debug)
- else
- Puppet::Util::Log.level=(:notice)
- end
+ # configuration parameter access and stuff
+ def self.[](param)
+ case param
+ when :debug
+ return Puppet::Util::Log.level == :debug
+ else
+ return @@settings[param]
end
-
- def self.settings
- @@settings
+ end
+
+ # configuration parameter access and stuff
+ def self.[]=(param,value)
+ @@settings[param] = value
+ end
+
+ def self.clear
+ @@settings.clear
+ end
+
+ def self.debug=(value)
+ if value
+ Puppet::Util::Log.level=(:debug)
+ else
+ Puppet::Util::Log.level=(:notice)
end
+ end
- def self.run_mode
- $puppet_application_mode || Puppet::Util::RunMode[:user]
- end
+ def self.settings
+ @@settings
+ end
- def self.application_name
- $puppet_application_name ||= "apply"
- end
+ def self.run_mode
+ $puppet_application_mode || Puppet::Util::RunMode[:user]
+ end
- # Load all of the configuration parameters.
- require 'puppet/defaults'
+ def self.application_name
+ $puppet_application_name ||= "apply"
+ end
- def self.genmanifest
- if Puppet[:genmanifest]
- puts Puppet.settings.to_manifest
- exit(0)
- end
- end
+ # Load all of the configuration parameters.
+ require 'puppet/defaults'
- # Parse the config file for this process.
- def self.parse_config
- Puppet.settings.parse
+ def self.genmanifest
+ if Puppet[:genmanifest]
+ puts Puppet.settings.to_manifest
+ exit(0)
end
-
- # XXX this should all be done using puppet objects, not using
- # normal mkdir
- def self.recmkdir(dir,mode = 0755)
- if FileTest.exist?(dir)
+ end
+
+ # Parse the config file for this process.
+ def self.parse_config
+ Puppet.settings.parse
+ end
+
+ # XXX this should all be done using puppet objects, not using
+ # normal mkdir
+ def self.recmkdir(dir,mode = 0755)
+ if FileTest.exist?(dir)
+ return false
+ else
+ tmp = dir.sub(/^\//,'')
+ path = [File::SEPARATOR]
+ tmp.split(File::SEPARATOR).each { |dir|
+ path.push dir
+ if ! FileTest.exist?(File.join(path))
+ begin
+ Dir.mkdir(File.join(path), mode)
+ rescue Errno::EACCES => detail
+ Puppet.err detail.to_s
return false
- else
- tmp = dir.sub(/^\//,'')
- path = [File::SEPARATOR]
- tmp.split(File::SEPARATOR).each { |dir|
- path.push dir
- if ! FileTest.exist?(File.join(path))
- begin
- Dir.mkdir(File.join(path), mode)
- rescue Errno::EACCES => detail
- Puppet.err detail.to_s
- return false
- rescue => detail
- Puppet.err "Could not create #{path}: #{detail}"
- return false
- end
- elsif FileTest.directory?(File.join(path))
- next
- else FileTest.exist?(File.join(path))
- raise Puppet::Error, "Cannot create #{dir}: basedir #{File.join(path)} is a file"
- end
- }
- return true
+ rescue => detail
+ Puppet.err "Could not create #{path}: #{detail}"
+ return false
+ end
+ elsif FileTest.directory?(File.join(path))
+ next
+ else FileTest.exist?(File.join(path))
+ raise Puppet::Error, "Cannot create #{dir}: basedir #{File.join(path)} is a file"
end
+ }
+ return true
end
-
- # Create a new type. Just proxy to the Type class.
- def self.newtype(name, options = {}, &block)
- Puppet::Type.newtype(name, options, &block)
- end
-
- # Retrieve a type by name. Just proxy to the Type class.
- def self.type(name)
- # LAK:DEP Deprecation notice added 12/17/2008
- Puppet.warning "Puppet.type is deprecated; use Puppet::Type.type"
- Puppet::Type.type(name)
- end
+ end
+
+ # Create a new type. Just proxy to the Type class.
+ def self.newtype(name, options = {}, &block)
+ Puppet::Type.newtype(name, options, &block)
+ end
+
+ # Retrieve a type by name. Just proxy to the Type class.
+ def self.type(name)
+ # LAK:DEP Deprecation notice added 12/17/2008
+ Puppet.warning "Puppet.type is deprecated; use Puppet::Type.type"
+ Puppet::Type.type(name)
+ end
end
require 'puppet/type'
diff --git a/lib/puppet/agent.rb b/lib/puppet/agent.rb
index a01da483b..52acc64aa 100644
--- a/lib/puppet/agent.rb
+++ b/lib/puppet/agent.rb
@@ -5,101 +5,101 @@ require 'puppet/application'
# A general class for triggering a run of another
# class.
class Puppet::Agent
- require 'puppet/agent/locker'
- include Puppet::Agent::Locker
+ require 'puppet/agent/locker'
+ include Puppet::Agent::Locker
- attr_reader :client_class, :client, :splayed
+ attr_reader :client_class, :client, :splayed
- # Just so we can specify that we are "the" instance.
- def initialize(client_class)
- @splayed = false
+ # Just so we can specify that we are "the" instance.
+ def initialize(client_class)
+ @splayed = false
- @client_class = client_class
- end
-
- def lockfile_path
- client_class.lockfile_path
- end
-
- def needing_restart?
- Puppet::Application.restart_requested?
- end
+ @client_class = client_class
+ end
- # Perform a run with our client.
- def run(*args)
- if running?
- Puppet.notice "Run of #{client_class} already in progress; skipping"
- return
- end
- result = nil
- block_run = Puppet::Application.controlled_run do
- splay
- with_client do |client|
- begin
- sync.synchronize { lock { result = client.run(*args) } }
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not run #{client_class}: #{detail}"
- end
- end
- true
- end
- Puppet.notice "Shutdown/restart in progress; skipping run" unless block_run
- result
- end
+ def lockfile_path
+ client_class.lockfile_path
+ end
- def stopping?
- Puppet::Application.stop_requested?
- end
+ def needing_restart?
+ Puppet::Application.restart_requested?
+ end
- # Have we splayed already?
- def splayed?
- splayed
+ # Perform a run with our client.
+ def run(*args)
+ if running?
+ Puppet.notice "Run of #{client_class} already in progress; skipping"
+ return
end
-
- # Sleep when splay is enabled; else just return.
- def splay
- return unless Puppet[:splay]
- return if splayed?
-
- time = rand(Integer(Puppet[:splaylimit]) + 1)
- Puppet.info "Sleeping for #{time} seconds (splay is enabled)"
- sleep(time)
- @splayed = true
- end
-
- # Start listening for events. We're pretty much just listening for
- # timer events here.
- def start
- # Create our timer. Puppet will handle observing it and such.
- timer = EventLoop::Timer.new(:interval => Puppet[:runinterval], :tolerance => 1, :start? => true) do
- run
+ result = nil
+ block_run = Puppet::Application.controlled_run do
+ splay
+ with_client do |client|
+ begin
+ sync.synchronize { lock { result = client.run(*args) } }
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not run #{client_class}: #{detail}"
end
-
- # Run once before we start following the timer
- timer.sound_alarm
+ end
+ true
end
-
- def sync
- @sync ||= Sync.new
+ Puppet.notice "Shutdown/restart in progress; skipping run" unless block_run
+ result
+ end
+
+ def stopping?
+ Puppet::Application.stop_requested?
+ end
+
+ # Have we splayed already?
+ def splayed?
+ splayed
+ end
+
+ # Sleep when splay is enabled; else just return.
+ def splay
+ return unless Puppet[:splay]
+ return if splayed?
+
+ time = rand(Integer(Puppet[:splaylimit]) + 1)
+ Puppet.info "Sleeping for #{time} seconds (splay is enabled)"
+ sleep(time)
+ @splayed = true
+ end
+
+ # Start listening for events. We're pretty much just listening for
+ # timer events here.
+ def start
+ # Create our timer. Puppet will handle observing it and such.
+ timer = EventLoop::Timer.new(:interval => Puppet[:runinterval], :tolerance => 1, :start? => true) do
+ run
end
- private
-
- # Create and yield a client instance, keeping a reference
- # to it during the yield.
- def with_client
- begin
- @client = client_class.new
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not create instance of #{client_class}: #{detail}"
- return
- end
- yield @client
- ensure
- @client = nil
+ # Run once before we start following the timer
+ timer.sound_alarm
+ end
+
+ def sync
+ @sync ||= Sync.new
+ end
+
+ private
+
+ # Create and yield a client instance, keeping a reference
+ # to it during the yield.
+ def with_client
+ begin
+ @client = client_class.new
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not create instance of #{client_class}: #{detail}"
+ return
end
+ yield @client
+ ensure
+ @client = nil
+ end
end
diff --git a/lib/puppet/agent/locker.rb b/lib/puppet/agent/locker.rb
index 52f3002af..98f5b38d9 100644
--- a/lib/puppet/agent/locker.rb
+++ b/lib/puppet/agent/locker.rb
@@ -3,38 +3,38 @@ require 'puppet/util/pidlock'
# Break out the code related to locking the agent. This module is just
# included into the agent, but having it here makes it easier to test.
module Puppet::Agent::Locker
- # Let the daemon run again, freely in the filesystem.
- def enable
- lockfile.unlock(:anonymous => true)
- end
+ # Let the daemon run again, freely in the filesystem.
+ def enable
+ lockfile.unlock(:anonymous => true)
+ end
- # Stop the daemon from making any catalog runs.
- def disable
- lockfile.lock(:anonymous => true)
- end
+ # Stop the daemon from making any catalog runs.
+ def disable
+ lockfile.lock(:anonymous => true)
+ end
- # Yield if we get a lock, else do nothing. Return
- # true/false depending on whether we get the lock.
- def lock
- if lockfile.lock
- begin
- yield
- ensure
- lockfile.unlock
- end
- return true
- else
- return false
- end
+ # Yield if we get a lock, else do nothing. Return
+ # true/false depending on whether we get the lock.
+ def lock
+ if lockfile.lock
+ begin
+ yield
+ ensure
+ lockfile.unlock
+ end
+ return true
+ else
+ return false
end
+ end
- def lockfile
- @lockfile ||= Puppet::Util::Pidlock.new(lockfile_path)
+ def lockfile
+ @lockfile ||= Puppet::Util::Pidlock.new(lockfile_path)
- @lockfile
- end
+ @lockfile
+ end
- def running?
- lockfile.locked?
- end
+ def running?
+ lockfile.locked?
+ end
end
diff --git a/lib/puppet/application.rb b/lib/puppet/application.rb
index a32650a8f..05b7d466f 100644
--- a/lib/puppet/application.rb
+++ b/lib/puppet/application.rb
@@ -115,291 +115,291 @@ require 'optparse'
# end
module Puppet
class Application
- require 'puppet/util'
- include Puppet::Util
-
- DOCPATTERN = File.expand_path(File.dirname(__FILE__) + "/util/command_line/*" )
-
- class << self
- include Puppet::Util
-
- attr_accessor :run_status
+ require 'puppet/util'
+ include Puppet::Util
- def clear!
- self.run_status = nil
- end
-
- def stop!
- self.run_status = :stop_requested
- end
+ DOCPATTERN = File.expand_path(File.dirname(__FILE__) + "/util/command_line/*" )
- def restart!
- self.run_status = :restart_requested
- end
-
- # Indicates that Puppet::Application.restart! has been invoked and components should
- # do what is necessary to facilitate a restart.
- def restart_requested?
- :restart_requested == run_status
- end
-
- # Indicates that Puppet::Application.stop! has been invoked and components should do what is necessary
- # for a clean stop.
- def stop_requested?
- :stop_requested == run_status
- end
+ class << self
+ include Puppet::Util
- # Indicates that one of stop! or start! was invoked on Puppet::Application, and some kind of process
- # shutdown/short-circuit may be necessary.
- def interrupted?
- [:restart_requested, :stop_requested].include? run_status
- end
+ attr_accessor :run_status
- # Indicates that Puppet::Application believes that it's in usual running run_mode (no stop/restart request
- # currently active).
- def clear?
- run_status.nil?
- end
+ def clear!
+ self.run_status = nil
+ end
- # Only executes the given block if the run status of Puppet::Application is clear (no restarts, stops,
- # etc. requested).
- # Upon block execution, checks the run status again; if a restart has been requested during the block's
- # execution, then controlled_run will send a new HUP signal to the current process.
- # Thus, long-running background processes can potentially finish their work before a restart.
- def controlled_run(&block)
- return unless clear?
- result = block.call
- Process.kill(:HUP, $PID) if restart_requested?
- result
- end
+ def stop!
+ self.run_status = :stop_requested
+ end
- def should_parse_config
- @parse_config = true
- end
+ def restart!
+ self.run_status = :restart_requested
+ end
- def should_not_parse_config
- @parse_config = false
- end
+ # Indicates that Puppet::Application.restart! has been invoked and components should
+ # do what is necessary to facilitate a restart.
+ def restart_requested?
+ :restart_requested == run_status
+ end
- def should_parse_config?
- @parse_config = true if ! defined?(@parse_config)
- @parse_config
- end
+ # Indicates that Puppet::Application.stop! has been invoked and components should do what is necessary
+ # for a clean stop.
+ def stop_requested?
+ :stop_requested == run_status
+ end
- # used to declare code that handle an option
- def option(*options, &block)
- long = options.find { |opt| opt =~ /^--/ }.gsub(/^--(?:\[no-\])?([^ =]+).*$/, '\1' ).gsub('-','_')
- fname = symbolize("handle_#{long}")
- if (block_given?)
- define_method(fname, &block)
- else
- define_method(fname) do |value|
- self.options["#{long}".to_sym] = value
- end
- end
- self.option_parser_commands << [options, fname]
- end
+ # Indicates that one of stop! or start! was invoked on Puppet::Application, and some kind of process
+ # shutdown/short-circuit may be necessary.
+ def interrupted?
+ [:restart_requested, :stop_requested].include? run_status
+ end
- def banner(banner = nil)
- @banner ||= banner
- end
+ # Indicates that Puppet::Application believes that it's in usual running run_mode (no stop/restart request
+ # currently active).
+ def clear?
+ run_status.nil?
+ end
- def option_parser_commands
- @option_parser_commands ||= (
- superclass.respond_to?(:option_parser_commands) ? superclass.option_parser_commands.dup : []
- )
- @option_parser_commands
- end
+ # Only executes the given block if the run status of Puppet::Application is clear (no restarts, stops,
+ # etc. requested).
+ # Upon block execution, checks the run status again; if a restart has been requested during the block's
+ # execution, then controlled_run will send a new HUP signal to the current process.
+ # Thus, long-running background processes can potentially finish their work before a restart.
+ def controlled_run(&block)
+ return unless clear?
+ result = block.call
+ Process.kill(:HUP, $PID) if restart_requested?
+ result
+ end
- def find(name)
- self.const_get(name.to_s.capitalize)
- rescue
- puts "Unable to find application '#{name.to_s}'."
- Kernel::exit(1)
- end
+ def should_parse_config
+ @parse_config = true
+ end
- def [](name)
- find(name).new
- end
+ def should_not_parse_config
+ @parse_config = false
+ end
- # Sets or gets the run_mode name. Sets the run_mode name if a mode_name is
- # passed. Otherwise, gets the run_mode or a default run_mode
- #
- def run_mode( mode_name = nil)
- return @run_mode if @run_mode and not mode_name
+ def should_parse_config?
+ @parse_config = true if ! defined?(@parse_config)
+ @parse_config
+ end
- require 'puppet/util/run_mode'
- @run_mode = Puppet::Util::RunMode[ mode_name || :user ]
+ # used to declare code that handle an option
+ def option(*options, &block)
+ long = options.find { |opt| opt =~ /^--/ }.gsub(/^--(?:\[no-\])?([^ =]+).*$/, '\1' ).gsub('-','_')
+ fname = symbolize("handle_#{long}")
+ if (block_given?)
+ define_method(fname, &block)
+ else
+ define_method(fname) do |value|
+ self.options["#{long}".to_sym] = value
end
+ end
+ self.option_parser_commands << [options, fname]
end
- attr_reader :options, :command_line
-
- # Every app responds to --version
- option("--version", "-V") do |arg|
- puts "#{Puppet.version}"
- exit
+ def banner(banner = nil)
+ @banner ||= banner
end
- # Every app responds to --help
- option("--help", "-h") do |v|
- help
+ def option_parser_commands
+ @option_parser_commands ||= (
+ superclass.respond_to?(:option_parser_commands) ? superclass.option_parser_commands.dup : []
+ )
+ @option_parser_commands
end
- def should_parse_config?
- self.class.should_parse_config?
+ def find(name)
+ self.const_get(name.to_s.capitalize)
+ rescue
+ puts "Unable to find application '#{name.to_s}'."
+ Kernel::exit(1)
end
- # override to execute code before running anything else
- def preinit
+ def [](name)
+ find(name).new
end
- def option_parser
- return @option_parser if defined?(@option_parser)
-
- @option_parser = OptionParser.new(self.class.banner)
+ # Sets or gets the run_mode name. Sets the run_mode name if a mode_name is
+ # passed. Otherwise, gets the run_mode or a default run_mode
+ #
+ def run_mode( mode_name = nil)
+ return @run_mode if @run_mode and not mode_name
- self.class.option_parser_commands.each do |options, fname|
- @option_parser.on(*options) do |value|
- self.send(fname, value)
- end
- end
- @option_parser.default_argv = self.command_line.args
- @option_parser
+ require 'puppet/util/run_mode'
+ @run_mode = Puppet::Util::RunMode[ mode_name || :user ]
end
+ end
- def initialize(command_line = nil)
- require 'puppet/util/command_line'
- @command_line = command_line || Puppet::Util::CommandLine.new
- @run_mode = self.class.run_mode
- @options = {}
-
- $puppet_application_mode = @run_mode
- $puppet_application_name = name
-
- if Puppet.respond_to? :settings
- # This is to reduce the amount of confusion in rspec
- # because it might have loaded defaults.rb before the globals were set
- # and thus have the wrong defaults for the current application
- Puppet.settings.set_value(:confdir, Puppet.run_mode.conf_dir, :mutable_defaults)
- Puppet.settings.set_value(:vardir, Puppet.run_mode.var_dir, :mutable_defaults)
- Puppet.settings.set_value(:name, Puppet.application_name.to_s, :mutable_defaults)
- Puppet.settings.set_value(:logdir, Puppet.run_mode.logopts, :mutable_defaults)
- Puppet.settings.set_value(:rundir, Puppet.run_mode.run_dir, :mutable_defaults)
- Puppet.settings.set_value(:mode, Puppet.run_mode.name.to_s, :mutable_defaults)
- end
+ attr_reader :options, :command_line
- require 'puppet'
- end
+ # Every app responds to --version
+ option("--version", "-V") do |arg|
+ puts "#{Puppet.version}"
+ exit
+ end
- # This is the main application entry point
- def run
- exit_on_fail("initialize") { preinit }
- exit_on_fail("parse options") { parse_options }
- exit_on_fail("parse configuration file") { Puppet.settings.parse } if should_parse_config?
- exit_on_fail("prepare for execution") { setup }
- exit_on_fail("run") { run_command }
- end
+ # Every app responds to --help
+ option("--help", "-h") do |v|
+ help
+ end
- def main
- raise NotImplementedError, "No valid command or main"
- end
+ def should_parse_config?
+ self.class.should_parse_config?
+ end
- def run_command
- main
- end
+ # override to execute code before running anything else
+ def preinit
+ end
- def setup
- # Handle the logging settings
- if options[:debug] or options[:verbose]
- Puppet::Util::Log.newdestination(:console)
- if options[:debug]
- Puppet::Util::Log.level = :debug
- else
- Puppet::Util::Log.level = :info
- end
- end
+ def option_parser
+ return @option_parser if defined?(@option_parser)
- Puppet::Util::Log.newdestination(:syslog) unless options[:setdest]
+ @option_parser = OptionParser.new(self.class.banner)
+
+ self.class.option_parser_commands.each do |options, fname|
+ @option_parser.on(*options) do |value|
+ self.send(fname, value)
+ end
+ end
+ @option_parser.default_argv = self.command_line.args
+ @option_parser
+ end
+
+ def initialize(command_line = nil)
+ require 'puppet/util/command_line'
+ @command_line = command_line || Puppet::Util::CommandLine.new
+ @run_mode = self.class.run_mode
+ @options = {}
+
+ $puppet_application_mode = @run_mode
+ $puppet_application_name = name
+
+ if Puppet.respond_to? :settings
+ # This is to reduce the amount of confusion in rspec
+ # because it might have loaded defaults.rb before the globals were set
+ # and thus have the wrong defaults for the current application
+ Puppet.settings.set_value(:confdir, Puppet.run_mode.conf_dir, :mutable_defaults)
+ Puppet.settings.set_value(:vardir, Puppet.run_mode.var_dir, :mutable_defaults)
+ Puppet.settings.set_value(:name, Puppet.application_name.to_s, :mutable_defaults)
+ Puppet.settings.set_value(:logdir, Puppet.run_mode.logopts, :mutable_defaults)
+ Puppet.settings.set_value(:rundir, Puppet.run_mode.run_dir, :mutable_defaults)
+ Puppet.settings.set_value(:mode, Puppet.run_mode.name.to_s, :mutable_defaults)
end
- def parse_options
- # get all puppet options
- optparse_opt = []
- optparse_opt = Puppet.settings.optparse_addargs(optparse_opt)
+ require 'puppet'
+ end
+
+ # This is the main application entry point
+ def run
+ exit_on_fail("initialize") { preinit }
+ exit_on_fail("parse options") { parse_options }
+ exit_on_fail("parse configuration file") { Puppet.settings.parse } if should_parse_config?
+ exit_on_fail("prepare for execution") { setup }
+ exit_on_fail("run") { run_command }
+ end
+
+ def main
+ raise NotImplementedError, "No valid command or main"
+ end
+
+ def run_command
+ main
+ end
+
+ def setup
+ # Handle the logging settings
+ if options[:debug] or options[:verbose]
+ Puppet::Util::Log.newdestination(:console)
+ if options[:debug]
+ Puppet::Util::Log.level = :debug
+ else
+ Puppet::Util::Log.level = :info
+ end
+ end
- # convert them to OptionParser format
- optparse_opt.each do |option|
- self.option_parser.on(*option) do |arg|
- handlearg(option[0], arg)
- end
- end
+ Puppet::Util::Log.newdestination(:syslog) unless options[:setdest]
+ end
- # scan command line argument
- begin
- self.option_parser.parse!
- rescue OptionParser::ParseError => detail
- $stderr.puts detail
- $stderr.puts "Try 'puppet #{command_line.subcommand_name} --help'"
- exit(1)
- end
- end
+ def parse_options
+ # get all puppet options
+ optparse_opt = []
+ optparse_opt = Puppet.settings.optparse_addargs(optparse_opt)
- def handlearg(opt, arg)
- # rewrite --[no-]option to --no-option if that's what was given
- if opt =~ /\[no-\]/ and !arg
- opt = opt.gsub(/\[no-\]/,'no-')
- end
- # otherwise remove the [no-] prefix to not confuse everybody
- opt = opt.gsub(/\[no-\]/, '')
- unless respond_to?(:handle_unknown) and send(:handle_unknown, opt, arg)
- # Puppet.settings.handlearg doesn't handle direct true/false :-)
- if arg.is_a?(FalseClass)
- arg = "false"
- elsif arg.is_a?(TrueClass)
- arg = "true"
- end
- Puppet.settings.handlearg(opt, arg)
- end
+ # convert them to OptionParser format
+ optparse_opt.each do |option|
+ self.option_parser.on(*option) do |arg|
+ handlearg(option[0], arg)
+ end
end
- # this is used for testing
- def self.exit(code)
- exit(code)
+ # scan command line argument
+ begin
+ self.option_parser.parse!
+ rescue OptionParser::ParseError => detail
+ $stderr.puts detail
+ $stderr.puts "Try 'puppet #{command_line.subcommand_name} --help'"
+ exit(1)
end
+ end
- def name
- self.class.to_s.sub(/.*::/,"").downcase.to_sym
+ def handlearg(opt, arg)
+ # rewrite --[no-]option to --no-option if that's what was given
+ if opt =~ /\[no-\]/ and !arg
+ opt = opt.gsub(/\[no-\]/,'no-')
end
-
- def help
- if Puppet.features.usage?
- # RH:FIXME: My goodness, this is ugly.
- ::RDoc.const_set("PuppetSourceFile", name)
- #:stopdoc: # Issue #4161
- def (::RDoc).caller
- docfile = `grep -l 'Puppet::Application\\[:#{::RDoc::PuppetSourceFile}\\]' #{DOCPATTERN}`.chomp
- super << "#{docfile}:0"
- end
- #:startdoc:
- ::RDoc::usage && exit
- else
- puts "No help available unless you have RDoc::usage installed"
- exit
- end
- rescue Errno::ENOENT
- puts "No help available for puppet #{name}"
- exit
+ # otherwise remove the [no-] prefix to not confuse everybody
+ opt = opt.gsub(/\[no-\]/, '')
+ unless respond_to?(:handle_unknown) and send(:handle_unknown, opt, arg)
+ # Puppet.settings.handlearg doesn't handle direct true/false :-)
+ if arg.is_a?(FalseClass)
+ arg = "false"
+ elsif arg.is_a?(TrueClass)
+ arg = "true"
+ end
+ Puppet.settings.handlearg(opt, arg)
end
-
- private
-
- def exit_on_fail(message, code = 1)
- yield
- rescue RuntimeError, NotImplementedError => detail
- puts detail.backtrace if Puppet[:trace]
- $stderr.puts "Could not #{message}: #{detail}"
- exit(code)
+ end
+
+ # this is used for testing
+ def self.exit(code)
+ exit(code)
+ end
+
+ def name
+ self.class.to_s.sub(/.*::/,"").downcase.to_sym
+ end
+
+ def help
+ if Puppet.features.usage?
+ # RH:FIXME: My goodness, this is ugly.
+ ::RDoc.const_set("PuppetSourceFile", name)
+ #:stopdoc: # Issue #4161
+ def (::RDoc).caller
+ docfile = `grep -l 'Puppet::Application\\[:#{::RDoc::PuppetSourceFile}\\]' #{DOCPATTERN}`.chomp
+ super << "#{docfile}:0"
+ end
+ #:startdoc:
+ ::RDoc::usage && exit
+ else
+ puts "No help available unless you have RDoc::usage installed"
+ exit
end
+ rescue Errno::ENOENT
+ puts "No help available for puppet #{name}"
+ exit
+ end
+
+ private
+
+ def exit_on_fail(message, code = 1)
+ yield
+ rescue RuntimeError, NotImplementedError => detail
+ puts detail.backtrace if Puppet[:trace]
+ $stderr.puts "Could not #{message}: #{detail}"
+ exit(code)
+ end
end
end
diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb
index 2d7ac1b6a..b90bdd484 100644
--- a/lib/puppet/application/agent.rb
+++ b/lib/puppet/application/agent.rb
@@ -2,268 +2,268 @@ require 'puppet/application'
class Puppet::Application::Agent < Puppet::Application
- should_parse_config
- run_mode :agent
-
- attr_accessor :explicit_waitforcert, :args, :agent, :daemon, :host
-
- def preinit
- # Do an initial trap, so that cancels don't get a stack trace.
- trap(:INT) do
- $stderr.puts "Cancelling startup"
- exit(0)
- end
-
- {
- :waitforcert => 120, # Default to checking for certs every 5 minutes
- :detailed_exitcodes => false,
- :verbose => false,
- :debug => false,
- :centrallogs => false,
- :setdest => false,
- :enable => false,
- :disable => false,
- :client => true,
- :fqdn => nil,
- :serve => [],
- :digest => :MD5,
- :fingerprint => false,
- }.each do |opt,val|
- options[opt] = val
- end
-
- @explicit_waitforcert = false
- @args = {}
- require 'puppet/daemon'
- @daemon = Puppet::Daemon.new
- @daemon.argv = ARGV.dup
- end
+ should_parse_config
+ run_mode :agent
- option("--centrallogging")
- option("--disable")
- option("--enable")
- option("--debug","-d")
- option("--fqdn FQDN","-f")
- option("--test","-t")
- option("--verbose","-v")
-
- option("--fingerprint")
- option("--digest DIGEST")
-
- option("--serve HANDLER", "-s") do |arg|
- if Puppet::Network::Handler.handler(arg)
- options[:serve] << arg.to_sym
- else
- raise "Could not find handler for #{arg}"
- end
- end
+ attr_accessor :explicit_waitforcert, :args, :agent, :daemon, :host
- option("--no-client") do |arg|
- options[:client] = false
+ def preinit
+ # Do an initial trap, so that cancels don't get a stack trace.
+ trap(:INT) do
+ $stderr.puts "Cancelling startup"
+ exit(0)
end
- option("--onetime", "-o") do |arg|
- Puppet[:onetime] = true
- options[:waitforcert] = 0 unless @explicit_waitforcert
+ {
+ :waitforcert => 120, # Default to checking for certs every 5 minutes
+ :detailed_exitcodes => false,
+ :verbose => false,
+ :debug => false,
+ :centrallogs => false,
+ :setdest => false,
+ :enable => false,
+ :disable => false,
+ :client => true,
+ :fqdn => nil,
+ :serve => [],
+ :digest => :MD5,
+ :fingerprint => false,
+ }.each do |opt,val|
+ options[opt] = val
end
- option("--detailed-exitcodes") do |arg|
- options[:detailed_exitcodes] = true
+ @explicit_waitforcert = false
+ @args = {}
+ require 'puppet/daemon'
+ @daemon = Puppet::Daemon.new
+ @daemon.argv = ARGV.dup
+ end
+
+ option("--centrallogging")
+ option("--disable")
+ option("--enable")
+ option("--debug","-d")
+ option("--fqdn FQDN","-f")
+ option("--test","-t")
+ option("--verbose","-v")
+
+ option("--fingerprint")
+ option("--digest DIGEST")
+
+ option("--serve HANDLER", "-s") do |arg|
+ if Puppet::Network::Handler.handler(arg)
+ options[:serve] << arg.to_sym
+ else
+ raise "Could not find handler for #{arg}"
end
-
- option("--logdest DEST", "-l DEST") do |arg|
- begin
- Puppet::Util::Log.newdestination(arg)
- options[:setdest] = true
- rescue => detail
- puts detail.backtrace if Puppet[:debug]
- $stderr.puts detail.to_s
- end
+ end
+
+ option("--no-client") do |arg|
+ options[:client] = false
+ end
+
+ option("--onetime", "-o") do |arg|
+ Puppet[:onetime] = true
+ options[:waitforcert] = 0 unless @explicit_waitforcert
+ end
+
+ option("--detailed-exitcodes") do |arg|
+ options[:detailed_exitcodes] = true
+ end
+
+ option("--logdest DEST", "-l DEST") do |arg|
+ begin
+ Puppet::Util::Log.newdestination(arg)
+ options[:setdest] = true
+ rescue => detail
+ puts detail.backtrace if Puppet[:debug]
+ $stderr.puts detail.to_s
end
-
- option("--waitforcert WAITFORCERT", "-w") do |arg|
- options[:waitforcert] = arg.to_i
- @explicit_waitforcert = true
+ end
+
+ option("--waitforcert WAITFORCERT", "-w") do |arg|
+ options[:waitforcert] = arg.to_i
+ @explicit_waitforcert = true
+ end
+
+ option("--port PORT","-p") do |arg|
+ @args[:Port] = arg
+ end
+
+ def run_command
+ return fingerprint if options[:fingerprint]
+ return onetime if Puppet[:onetime]
+ main
+ end
+
+ def fingerprint
+ unless cert = host.certificate || host.certificate_request
+ $stderr.puts "Fingerprint asked but no certificate nor certificate request have yet been issued"
+ exit(1)
+ return
end
-
- option("--port PORT","-p") do |arg|
- @args[:Port] = arg
+ unless fingerprint = cert.fingerprint(options[:digest])
+ raise ArgumentError, "Could not get fingerprint for digest '#{options[:digest]}'"
end
-
- def run_command
- return fingerprint if options[:fingerprint]
- return onetime if Puppet[:onetime]
- main
+ Puppet.notice fingerprint
+ end
+
+ def onetime
+ unless options[:client]
+ $stderr.puts "onetime is specified but there is no client"
+ exit(43)
+ return
end
- def fingerprint
- unless cert = host.certificate || host.certificate_request
- $stderr.puts "Fingerprint asked but no certificate nor certificate request have yet been issued"
- exit(1)
- return
- end
- unless fingerprint = cert.fingerprint(options[:digest])
- raise ArgumentError, "Could not get fingerprint for digest '#{options[:digest]}'"
- end
- Puppet.notice fingerprint
- end
+ @daemon.set_signal_traps
- def onetime
- unless options[:client]
- $stderr.puts "onetime is specified but there is no client"
- exit(43)
- return
- end
-
- @daemon.set_signal_traps
-
- begin
- report = @agent.run
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err detail.to_s
- end
-
- if not report
- exit(1)
- elsif not Puppet[:noop] and options[:detailed_exitcodes] then
- exit(report.exit_status)
- else
- exit(0)
- end
+ begin
+ report = @agent.run
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err detail.to_s
end
- def main
- Puppet.notice "Starting Puppet client version #{Puppet.version}"
-
- @daemon.start
+ if not report
+ exit(1)
+ elsif not Puppet[:noop] and options[:detailed_exitcodes] then
+ exit(report.exit_status)
+ else
+ exit(0)
end
-
- # Enable all of the most common test options.
- def setup_test
- Puppet.settings.handlearg("--ignorecache")
- Puppet.settings.handlearg("--no-usecacheonfailure")
- Puppet.settings.handlearg("--no-splay")
- Puppet.settings.handlearg("--show_diff")
- Puppet.settings.handlearg("--no-daemonize")
- options[:verbose] = true
- Puppet[:onetime] = true
- options[:detailed_exitcodes] = true
- options[:waitforcert] = 0 unless @explicit_waitforcert
+ end
+
+ def main
+ Puppet.notice "Starting Puppet client version #{Puppet.version}"
+
+ @daemon.start
+ end
+
+ # Enable all of the most common test options.
+ def setup_test
+ Puppet.settings.handlearg("--ignorecache")
+ Puppet.settings.handlearg("--no-usecacheonfailure")
+ Puppet.settings.handlearg("--no-splay")
+ Puppet.settings.handlearg("--show_diff")
+ Puppet.settings.handlearg("--no-daemonize")
+ options[:verbose] = true
+ Puppet[:onetime] = true
+ options[:detailed_exitcodes] = true
+ options[:waitforcert] = 0 unless @explicit_waitforcert
+ end
+
+ # Handle the logging settings.
+ def setup_logs
+ if options[:debug] or options[:verbose]
+ Puppet::Util::Log.newdestination(:console)
+ if options[:debug]
+ Puppet::Util::Log.level = :debug
+ else
+ Puppet::Util::Log.level = :info
+ end
end
- # Handle the logging settings.
- def setup_logs
- if options[:debug] or options[:verbose]
- Puppet::Util::Log.newdestination(:console)
- if options[:debug]
- Puppet::Util::Log.level = :debug
- else
- Puppet::Util::Log.level = :info
- end
- end
-
- Puppet::Util::Log.newdestination(:syslog) unless options[:setdest]
+ Puppet::Util::Log.newdestination(:syslog) unless options[:setdest]
+ end
+
+ def enable_disable_client(agent)
+ if options[:enable]
+ agent.enable
+ elsif options[:disable]
+ agent.disable
end
+ exit(0)
+ end
- def enable_disable_client(agent)
- if options[:enable]
- agent.enable
- elsif options[:disable]
- agent.disable
- end
- exit(0)
+ def setup_listen
+ unless FileTest.exists?(Puppet[:authconfig])
+ Puppet.err "Will not start without authorization file #{Puppet[:authconfig]}"
+ exit(14)
end
- def setup_listen
- unless FileTest.exists?(Puppet[:authconfig])
- Puppet.err "Will not start without authorization file #{Puppet[:authconfig]}"
- exit(14)
- end
+ handlers = nil
- handlers = nil
+ if options[:serve].empty?
+ handlers = [:Runner]
+ else
+ handlers = options[:serve]
+ end
- if options[:serve].empty?
- handlers = [:Runner]
- else
- handlers = options[:serve]
- end
+ require 'puppet/network/server'
+ # No REST handlers yet.
+ server = Puppet::Network::Server.new(:xmlrpc_handlers => handlers, :port => Puppet[:puppetport])
- require 'puppet/network/server'
- # No REST handlers yet.
- server = Puppet::Network::Server.new(:xmlrpc_handlers => handlers, :port => Puppet[:puppetport])
+ @daemon.server = server
+ end
- @daemon.server = server
- end
+ def setup
+ setup_test if options[:test]
- def setup
- setup_test if options[:test]
+ setup_logs
- setup_logs
+ exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
- exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+ # If noop is set, then also enable diffs
+ Puppet[:show_diff] = true if Puppet[:noop]
- # If noop is set, then also enable diffs
- Puppet[:show_diff] = true if Puppet[:noop]
-
- args[:Server] = Puppet[:server]
- if options[:fqdn]
- args[:FQDN] = options[:fqdn]
- Puppet[:certname] = options[:fqdn]
- end
+ args[:Server] = Puppet[:server]
+ if options[:fqdn]
+ args[:FQDN] = options[:fqdn]
+ Puppet[:certname] = options[:fqdn]
+ end
- if options[:centrallogs]
- logdest = args[:Server]
+ if options[:centrallogs]
+ logdest = args[:Server]
- logdest += ":" + args[:Port] if args.include?(:Port)
- Puppet::Util::Log.newdestination(logdest)
- end
+ logdest += ":" + args[:Port] if args.include?(:Port)
+ Puppet::Util::Log.newdestination(logdest)
+ end
- Puppet.settings.use :main, :agent, :ssl
+ Puppet.settings.use :main, :agent, :ssl
- # We need to specify a ca location for all of the SSL-related i
- # indirected classes to work; in fingerprint mode we just need
- # access to the local files and we don't need a ca.
- Puppet::SSL::Host.ca_location = options[:fingerprint] ? :none : :remote
+ # We need to specify a ca location for all of the SSL-related i
+ # indirected classes to work; in fingerprint mode we just need
+ # access to the local files and we don't need a ca.
+ Puppet::SSL::Host.ca_location = options[:fingerprint] ? :none : :remote
- Puppet::Transaction::Report.terminus_class = :rest
+ Puppet::Transaction::Report.terminus_class = :rest
- # Override the default; puppetd needs this, usually.
- # You can still override this on the command-line with, e.g., :compiler.
- Puppet[:catalog_terminus] = :rest
+ # Override the default; puppetd needs this, usually.
+ # You can still override this on the command-line with, e.g., :compiler.
+ Puppet[:catalog_terminus] = :rest
- # Override the default.
- Puppet[:facts_terminus] = :facter
+ # Override the default.
+ Puppet[:facts_terminus] = :facter
- Puppet::Resource::Catalog.cache_class = :yaml
+ Puppet::Resource::Catalog.cache_class = :yaml
- # We need tomake the client either way, we just don't start it
- # if --no-client is set.
- require 'puppet/agent'
- require 'puppet/configurer'
- @agent = Puppet::Agent.new(Puppet::Configurer)
+ # We need tomake the client either way, we just don't start it
+ # if --no-client is set.
+ require 'puppet/agent'
+ require 'puppet/configurer'
+ @agent = Puppet::Agent.new(Puppet::Configurer)
- enable_disable_client(@agent) if options[:enable] or options[:disable]
+ enable_disable_client(@agent) if options[:enable] or options[:disable]
- @daemon.agent = agent if options[:client]
+ @daemon.agent = agent if options[:client]
- # It'd be nice to daemonize later, but we have to daemonize before the
- # waitforcert happens.
- @daemon.daemonize if Puppet[:daemonize]
+ # It'd be nice to daemonize later, but we have to daemonize before the
+ # waitforcert happens.
+ @daemon.daemonize if Puppet[:daemonize]
- @host = Puppet::SSL::Host.new
- cert = @host.wait_for_cert(options[:waitforcert]) unless options[:fingerprint]
+ @host = Puppet::SSL::Host.new
+ cert = @host.wait_for_cert(options[:waitforcert]) unless options[:fingerprint]
- @objects = []
+ @objects = []
- # This has to go after the certs are dealt with.
- if Puppet[:listen]
- unless Puppet[:onetime]
- setup_listen
- else
- Puppet.notice "Ignoring --listen on onetime run"
- end
- end
+ # This has to go after the certs are dealt with.
+ if Puppet[:listen]
+ unless Puppet[:onetime]
+ setup_listen
+ else
+ Puppet.notice "Ignoring --listen on onetime run"
+ end
end
+ end
end
diff --git a/lib/puppet/application/apply.rb b/lib/puppet/application/apply.rb
index cd4c75d75..bb4186dbd 100644
--- a/lib/puppet/application/apply.rb
+++ b/lib/puppet/application/apply.rb
@@ -2,164 +2,164 @@ require 'puppet/application'
class Puppet::Application::Apply < Puppet::Application
- should_parse_config
-
- option("--debug","-d")
- option("--execute EXECUTE","-e") do |arg|
- options[:code] = arg
+ should_parse_config
+
+ option("--debug","-d")
+ option("--execute EXECUTE","-e") do |arg|
+ options[:code] = arg
+ end
+ option("--loadclasses","-L")
+ option("--verbose","-v")
+ option("--use-nodes")
+ option("--detailed-exitcodes")
+
+ option("--apply catalog", "-a catalog") do |arg|
+ options[:catalog] = arg
+ end
+
+ option("--logdest LOGDEST", "-l") do |arg|
+ begin
+ Puppet::Util::Log.newdestination(arg)
+ options[:logset] = true
+ rescue => detail
+ $stderr.puts detail.to_s
end
- option("--loadclasses","-L")
- option("--verbose","-v")
- option("--use-nodes")
- option("--detailed-exitcodes")
-
- option("--apply catalog", "-a catalog") do |arg|
- options[:catalog] = arg
+ end
+
+ def run_command
+ if options[:catalog]
+ apply
+ elsif Puppet[:parseonly]
+ parseonly
+ else
+ main
end
+ end
- option("--logdest LOGDEST", "-l") do |arg|
- begin
- Puppet::Util::Log.newdestination(arg)
- options[:logset] = true
- rescue => detail
- $stderr.puts detail.to_s
- end
+ def apply
+ if options[:catalog] == "-"
+ text = $stdin.read
+ else
+ text = File.read(options[:catalog])
end
- def run_command
- if options[:catalog]
- apply
- elsif Puppet[:parseonly]
- parseonly
- else
- main
- end
+ begin
+ catalog = Puppet::Resource::Catalog.convert_from(Puppet::Resource::Catalog.default_format,text)
+ catalog = Puppet::Resource::Catalog.pson_create(catalog) unless catalog.is_a?(Puppet::Resource::Catalog)
+ rescue => detail
+ raise Puppet::Error, "Could not deserialize catalog from pson: #{detail}"
end
- def apply
- if options[:catalog] == "-"
- text = $stdin.read
- else
- text = File.read(options[:catalog])
- end
+ catalog = catalog.to_ral
- begin
- catalog = Puppet::Resource::Catalog.convert_from(Puppet::Resource::Catalog.default_format,text)
- catalog = Puppet::Resource::Catalog.pson_create(catalog) unless catalog.is_a?(Puppet::Resource::Catalog)
- rescue => detail
- raise Puppet::Error, "Could not deserialize catalog from pson: #{detail}"
- end
+ require 'puppet/configurer'
+ configurer = Puppet::Configurer.new
+ configurer.run :catalog => catalog
+ end
- catalog = catalog.to_ral
-
- require 'puppet/configurer'
- configurer = Puppet::Configurer.new
- configurer.run :catalog => catalog
+ def parseonly
+ # Set our code or file to use.
+ if options[:code] or command_line.args.length == 0
+ Puppet[:code] = options[:code] || STDIN.read
+ else
+ Puppet[:manifest] = command_line.args.shift
end
-
- def parseonly
- # Set our code or file to use.
- if options[:code] or command_line.args.length == 0
- Puppet[:code] = options[:code] || STDIN.read
- else
- Puppet[:manifest] = command_line.args.shift
- end
- begin
- Puppet::Node::Environment.new(Puppet[:environment]).known_resource_types
- rescue => detail
- Puppet.err detail
- exit 1
- end
- exit 0
+ begin
+ Puppet::Node::Environment.new(Puppet[:environment]).known_resource_types
+ rescue => detail
+ Puppet.err detail
+ exit 1
+ end
+ exit 0
+ end
+
+ def main
+ # Set our code or file to use.
+ if options[:code] or command_line.args.length == 0
+ Puppet[:code] = options[:code] || STDIN.read
+ else
+ Puppet[:manifest] = command_line.args.shift
end
- def main
- # Set our code or file to use.
- if options[:code] or command_line.args.length == 0
- Puppet[:code] = options[:code] || STDIN.read
- else
- Puppet[:manifest] = command_line.args.shift
- end
+ # Collect our facts.
+ unless facts = Puppet::Node::Facts.find(Puppet[:certname])
+ raise "Could not find facts for #{Puppet[:certname]}"
+ end
- # Collect our facts.
- unless facts = Puppet::Node::Facts.find(Puppet[:certname])
- raise "Could not find facts for #{Puppet[:certname]}"
- end
+ # Find our Node
+ unless node = Puppet::Node.find(Puppet[:certname])
+ raise "Could not find node #{Puppet[:certname]}"
+ end
- # Find our Node
- unless node = Puppet::Node.find(Puppet[:certname])
- raise "Could not find node #{Puppet[:certname]}"
- end
+ # Merge in the facts.
+ node.merge(facts.values)
- # Merge in the facts.
- node.merge(facts.values)
-
- # Allow users to load the classes that puppet agent creates.
- if options[:loadclasses]
- file = Puppet[:classfile]
- if FileTest.exists?(file)
- unless FileTest.readable?(file)
- $stderr.puts "#{file} is not readable"
- exit(63)
- end
- node.classes = File.read(file).split(/[\s\n]+/)
- end
+ # Allow users to load the classes that puppet agent creates.
+ if options[:loadclasses]
+ file = Puppet[:classfile]
+ if FileTest.exists?(file)
+ unless FileTest.readable?(file)
+ $stderr.puts "#{file} is not readable"
+ exit(63)
end
+ node.classes = File.read(file).split(/[\s\n]+/)
+ end
+ end
- begin
- # Compile our catalog
- starttime = Time.now
- catalog = Puppet::Resource::Catalog.find(node.name, :use_node => node)
+ begin
+ # Compile our catalog
+ starttime = Time.now
+ catalog = Puppet::Resource::Catalog.find(node.name, :use_node => node)
- # Translate it to a RAL catalog
- catalog = catalog.to_ral
+ # Translate it to a RAL catalog
+ catalog = catalog.to_ral
- catalog.finalize
+ catalog.finalize
- catalog.retrieval_duration = Time.now - starttime
+ catalog.retrieval_duration = Time.now - starttime
- require 'puppet/configurer'
- configurer = Puppet::Configurer.new
- configurer.execute_prerun_command
+ require 'puppet/configurer'
+ configurer = Puppet::Configurer.new
+ configurer.execute_prerun_command
- # And apply it
- transaction = catalog.apply
+ # And apply it
+ transaction = catalog.apply
- configurer.execute_postrun_command
+ configurer.execute_postrun_command
- status = 0
- if not Puppet[:noop] and options[:detailed_exitcodes]
- transaction.generate_report
- exit(transaction.report.exit_status)
- else
- exit(0)
- end
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- $stderr.puts detail.message
- exit(1)
- end
+ status = 0
+ if not Puppet[:noop] and options[:detailed_exitcodes]
+ transaction.generate_report
+ exit(transaction.report.exit_status)
+ else
+ exit(0)
+ end
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ $stderr.puts detail.message
+ exit(1)
end
+ end
- def setup
- exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+ def setup
+ exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
- # If noop is set, then also enable diffs
- Puppet[:show_diff] = true if Puppet[:noop]
+ # If noop is set, then also enable diffs
+ Puppet[:show_diff] = true if Puppet[:noop]
- Puppet::Util::Log.newdestination(:console) unless options[:logset]
- client = nil
- server = nil
+ Puppet::Util::Log.newdestination(:console) unless options[:logset]
+ client = nil
+ server = nil
- trap(:INT) do
- $stderr.puts "Exiting"
- exit(1)
- end
+ trap(:INT) do
+ $stderr.puts "Exiting"
+ exit(1)
+ end
- if options[:debug]
- Puppet::Util::Log.level = :debug
- elsif options[:verbose]
- Puppet::Util::Log.level = :info
- end
+ if options[:debug]
+ Puppet::Util::Log.level = :debug
+ elsif options[:verbose]
+ Puppet::Util::Log.level = :info
end
+ end
end
diff --git a/lib/puppet/application/cert.rb b/lib/puppet/application/cert.rb
index af9042993..467b0c859 100644
--- a/lib/puppet/application/cert.rb
+++ b/lib/puppet/application/cert.rb
@@ -2,84 +2,84 @@ require 'puppet/application'
class Puppet::Application::Cert < Puppet::Application
- should_parse_config
- run_mode :master
-
- attr_accessor :cert_mode, :all, :ca, :digest, :signed
-
- def find_mode(opt)
- require 'puppet/ssl/certificate_authority'
- modes = Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS
- tmp = opt.sub("--", '').to_sym
- @cert_mode = modes.include?(tmp) ? tmp : nil
- end
-
- option("--clean", "-c") do
- @cert_mode = :destroy
+ should_parse_config
+ run_mode :master
+
+ attr_accessor :cert_mode, :all, :ca, :digest, :signed
+
+ def find_mode(opt)
+ require 'puppet/ssl/certificate_authority'
+ modes = Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS
+ tmp = opt.sub("--", '').to_sym
+ @cert_mode = modes.include?(tmp) ? tmp : nil
+ end
+
+ option("--clean", "-c") do
+ @cert_mode = :destroy
+ end
+
+ option("--all", "-a") do
+ @all = true
+ end
+
+ option("--digest DIGEST") do |arg|
+ @digest = arg
+ end
+
+ option("--signed", "-s") do
+ @signed = true
+ end
+
+ option("--debug", "-d") do |arg|
+ Puppet::Util::Log.level = :debug
+ end
+
+ require 'puppet/ssl/certificate_authority/interface'
+ Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.reject {|m| m == :destroy }.each do |method|
+ option("--#{method}", "-#{method.to_s[0,1]}") do
+ find_mode("--#{method}")
end
-
- option("--all", "-a") do
- @all = true
+ end
+
+ option("--verbose", "-v") do
+ Puppet::Util::Log.level = :info
+ end
+
+ def main
+ if @all
+ hosts = :all
+ elsif @signed
+ hosts = :signed
+ else
+ hosts = command_line.args.collect { |h| h.downcase }
end
-
- option("--digest DIGEST") do |arg|
- @digest = arg
+ begin
+ @ca.apply(:revoke, :to => hosts) if @cert_mode == :destroy
+ @ca.apply(@cert_mode, :to => hosts, :digest => @digest)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ puts detail.to_s
+ exit(24)
end
+ end
- option("--signed", "-s") do
- @signed = true
- end
+ def setup
+ exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
- option("--debug", "-d") do |arg|
- Puppet::Util::Log.level = :debug
- end
+ Puppet::Util::Log.newdestination :console
- require 'puppet/ssl/certificate_authority/interface'
- Puppet::SSL::CertificateAuthority::Interface::INTERFACE_METHODS.reject {|m| m == :destroy }.each do |method|
- option("--#{method}", "-#{method.to_s[0,1]}") do
- find_mode("--#{method}")
- end
+ if [:generate, :destroy].include? @cert_mode
+ Puppet::SSL::Host.ca_location = :local
+ else
+ Puppet::SSL::Host.ca_location = :only
end
- option("--verbose", "-v") do
- Puppet::Util::Log.level = :info
- end
-
- def main
- if @all
- hosts = :all
- elsif @signed
- hosts = :signed
- else
- hosts = command_line.args.collect { |h| h.downcase }
- end
- begin
- @ca.apply(:revoke, :to => hosts) if @cert_mode == :destroy
- @ca.apply(@cert_mode, :to => hosts, :digest => @digest)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- puts detail.to_s
- exit(24)
- end
- end
-
- def setup
- exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
-
- Puppet::Util::Log.newdestination :console
-
- if [:generate, :destroy].include? @cert_mode
- Puppet::SSL::Host.ca_location = :local
- else
- Puppet::SSL::Host.ca_location = :only
- end
-
- begin
- @ca = Puppet::SSL::CertificateAuthority.new
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- puts detail.to_s
- exit(23)
- end
+ begin
+ @ca = Puppet::SSL::CertificateAuthority.new
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ puts detail.to_s
+ exit(23)
end
+ end
end
diff --git a/lib/puppet/application/describe.rb b/lib/puppet/application/describe.rb
index 64246d1ea..5abe3ea14 100644
--- a/lib/puppet/application/describe.rb
+++ b/lib/puppet/application/describe.rb
@@ -2,202 +2,202 @@ require 'puppet/application'
class Formatter
- def initialize(width)
- @width = width
+ def initialize(width)
+ @width = width
+ end
+
+ def wrap(txt, opts)
+ return "" unless txt && !txt.empty?
+ work = (opts[:scrub] ? scrub(txt) : txt)
+ indent = (opts[:indent] ? opts[:indent] : 0)
+ textLen = @width - indent
+ patt = Regexp.new("^(.{0,#{textLen}})[ \n]")
+ prefix = " " * indent
+
+ res = []
+
+ while work.length > textLen
+ if work =~ patt
+ res << $1
+ work.slice!(0, $MATCH.length)
+ else
+ res << work.slice!(0, textLen)
+ end
end
-
- def wrap(txt, opts)
- return "" unless txt && !txt.empty?
- work = (opts[:scrub] ? scrub(txt) : txt)
- indent = (opts[:indent] ? opts[:indent] : 0)
- textLen = @width - indent
- patt = Regexp.new("^(.{0,#{textLen}})[ \n]")
- prefix = " " * indent
-
- res = []
-
- while work.length > textLen
- if work =~ patt
- res << $1
- work.slice!(0, $MATCH.length)
- else
- res << work.slice!(0, textLen)
- end
- end
- res << work if work.length.nonzero?
- prefix + res.join("\n#{prefix}")
- end
-
- def header(txt, sep = "-")
- "\n#{txt}\n" + sep * txt.size
- end
-
- private
-
- def scrub(text)
- # For text with no carriage returns, there's nothing to do.
- return text if text !~ /\n/
- indent = nil
-
- # If we can match an indentation, then just remove that same level of
- # indent from every line.
- if text =~ /^(\s+)/
- indent = $1
- return text.gsub(/^#{indent}/,'')
- else
- return text
- end
+ res << work if work.length.nonzero?
+ prefix + res.join("\n#{prefix}")
+ end
+
+ def header(txt, sep = "-")
+ "\n#{txt}\n" + sep * txt.size
+ end
+
+ private
+
+ def scrub(text)
+ # For text with no carriage returns, there's nothing to do.
+ return text if text !~ /\n/
+ indent = nil
+
+ # If we can match an indentation, then just remove that same level of
+ # indent from every line.
+ if text =~ /^(\s+)/
+ indent = $1
+ return text.gsub(/^#{indent}/,'')
+ else
+ return text
end
+ end
end
class TypeDoc
- def initialize
- @format = Formatter.new(76)
- @types = {}
- Puppet::Type.loadall
- Puppet::Type.eachtype { |type|
- next if type.name == :component
- @types[type.name] = type
- }
+ def initialize
+ @format = Formatter.new(76)
+ @types = {}
+ Puppet::Type.loadall
+ Puppet::Type.eachtype { |type|
+ next if type.name == :component
+ @types[type.name] = type
+ }
+ end
+
+ def list_types
+ puts "These are the types known to puppet:\n"
+ @types.keys.sort { |a, b|
+ a.to_s <=> b.to_s
+ }.each do |name|
+ type = @types[name]
+ s = type.doc.gsub(/\s+/, " ")
+ n = s.index(".")
+ if n.nil?
+ s = ".. no documentation .."
+ elsif n > 45
+ s = s[0, 45] + " ..."
+ else
+ s = s[0, n]
+ end
+ printf "%-15s - %s\n", name, s
end
+ end
- def list_types
- puts "These are the types known to puppet:\n"
- @types.keys.sort { |a, b|
- a.to_s <=> b.to_s
- }.each do |name|
- type = @types[name]
- s = type.doc.gsub(/\s+/, " ")
- n = s.index(".")
- if n.nil?
- s = ".. no documentation .."
- elsif n > 45
- s = s[0, 45] + " ..."
- else
- s = s[0, n]
- end
- printf "%-15s - %s\n", name, s
- end
+ def format_type(name, opts)
+ name = name.to_sym
+ unless @types.has_key?(name)
+ puts "Unknown type #{name}"
+ return
end
-
- def format_type(name, opts)
- name = name.to_sym
- unless @types.has_key?(name)
- puts "Unknown type #{name}"
- return
- end
- type = @types[name]
- puts @format.header(name.to_s, "=")
- puts @format.wrap(type.doc, :indent => 0, :scrub => true) + "\n\n"
-
- puts @format.header("Parameters")
- if opts[:parameters]
- format_attrs(type, [:property, :param])
- else
- list_attrs(type, [:property, :param])
- end
-
- if opts[:meta]
- puts @format.header("Meta Parameters")
- if opts[:parameters]
- format_attrs(type, [:meta])
- else
- list_attrs(type, [:meta])
- end
- end
-
- if type.providers.size > 0
- puts @format.header("Providers")
- if opts[:providers]
- format_providers(type)
- else
- list_providers(type)
- end
- end
+ type = @types[name]
+ puts @format.header(name.to_s, "=")
+ puts @format.wrap(type.doc, :indent => 0, :scrub => true) + "\n\n"
+
+ puts @format.header("Parameters")
+ if opts[:parameters]
+ format_attrs(type, [:property, :param])
+ else
+ list_attrs(type, [:property, :param])
end
- # List details about attributes
- def format_attrs(type, attrs)
- docs = {}
- type.allattrs.each do |name|
- kind = type.attrtype(name)
- docs[name] = type.attrclass(name).doc if attrs.include?(kind) && name != :provider
- end
-
- docs.sort { |a,b|
- a[0].to_s <=> b[0].to_s
- }.each { |name, doc|
- print "\n- **#{name}**"
- if type.namevar == name and name != :name
- puts " (*namevar*)"
- else
- puts ""
- end
- puts @format.wrap(doc, :indent => 4, :scrub => true)
- }
+ if opts[:meta]
+ puts @format.header("Meta Parameters")
+ if opts[:parameters]
+ format_attrs(type, [:meta])
+ else
+ list_attrs(type, [:meta])
+ end
end
- # List the names of attributes
- def list_attrs(type, attrs)
- params = []
- type.allattrs.each do |name|
- kind = type.attrtype(name)
- params << name.to_s if attrs.include?(kind) && name != :provider
- end
- puts @format.wrap(params.sort.join(", "), :indent => 4)
+ if type.providers.size > 0
+ puts @format.header("Providers")
+ if opts[:providers]
+ format_providers(type)
+ else
+ list_providers(type)
+ end
end
-
- def format_providers(type)
- type.providers.sort { |a,b|
- a.to_s <=> b.to_s
- }.each { |prov|
- puts "\n- **#{prov}**"
- puts @format.wrap(type.provider(prov).doc, :indent => 4, :scrub => true)
- }
+ end
+
+ # List details about attributes
+ def format_attrs(type, attrs)
+ docs = {}
+ type.allattrs.each do |name|
+ kind = type.attrtype(name)
+ docs[name] = type.attrclass(name).doc if attrs.include?(kind) && name != :provider
end
- def list_providers(type)
- list = type.providers.sort { |a,b|
- a.to_s <=> b.to_s
- }.join(", ")
- puts @format.wrap(list, :indent => 4)
+ docs.sort { |a,b|
+ a[0].to_s <=> b[0].to_s
+ }.each { |name, doc|
+ print "\n- **#{name}**"
+ if type.namevar == name and name != :name
+ puts " (*namevar*)"
+ else
+ puts ""
+ end
+ puts @format.wrap(doc, :indent => 4, :scrub => true)
+ }
+ end
+
+ # List the names of attributes
+ def list_attrs(type, attrs)
+ params = []
+ type.allattrs.each do |name|
+ kind = type.attrtype(name)
+ params << name.to_s if attrs.include?(kind) && name != :provider
end
+ puts @format.wrap(params.sort.join(", "), :indent => 4)
+ end
+
+ def format_providers(type)
+ type.providers.sort { |a,b|
+ a.to_s <=> b.to_s
+ }.each { |prov|
+ puts "\n- **#{prov}**"
+ puts @format.wrap(type.provider(prov).doc, :indent => 4, :scrub => true)
+ }
+ end
+
+ def list_providers(type)
+ list = type.providers.sort { |a,b|
+ a.to_s <=> b.to_s
+ }.join(", ")
+ puts @format.wrap(list, :indent => 4)
+ end
end
class Puppet::Application::Describe < Puppet::Application
- banner "puppet describe [options] [type]"
+ banner "puppet describe [options] [type]"
- should_not_parse_config
+ should_not_parse_config
- option("--short", "-s", "Only list parameters without detail") do |arg|
- options[:parameters] = false
- end
+ option("--short", "-s", "Only list parameters without detail") do |arg|
+ options[:parameters] = false
+ end
- option("--providers","-p")
- option("--list", "-l")
- option("--meta","-m")
+ option("--providers","-p")
+ option("--list", "-l")
+ option("--meta","-m")
- def preinit
- options[:parameters] = true
- end
+ def preinit
+ options[:parameters] = true
+ end
- def main
- doc = TypeDoc.new
+ def main
+ doc = TypeDoc.new
- if options[:list]
- doc.list_types
- else
- options[:types].each { |name| doc.format_type(name, options) }
- end
+ if options[:list]
+ doc.list_types
+ else
+ options[:types].each { |name| doc.format_type(name, options) }
end
+ end
- def setup
- options[:types] = command_line.args.dup
- handle_help(nil) unless options[:list] || options[:types].size > 0
- $stderr.puts "Warning: ignoring types when listing all types" if options[:list] && options[:types].size > 0
- end
+ def setup
+ options[:types] = command_line.args.dup
+ handle_help(nil) unless options[:list] || options[:types].size > 0
+ $stderr.puts "Warning: ignoring types when listing all types" if options[:list] && options[:types].size > 0
+ end
end
diff --git a/lib/puppet/application/doc.rb b/lib/puppet/application/doc.rb
index ba07f73cb..66aa6c8a1 100644
--- a/lib/puppet/application/doc.rb
+++ b/lib/puppet/application/doc.rb
@@ -2,214 +2,214 @@ require 'puppet/application'
class Puppet::Application::Doc < Puppet::Application
- should_not_parse_config
- run_mode :master
+ should_not_parse_config
+ run_mode :master
- attr_accessor :unknown_args, :manifest
+ attr_accessor :unknown_args, :manifest
- def preinit
- {:references => [], :mode => :text, :format => :to_rest }.each do |name,value|
- options[name] = value
- end
- @unknown_args = []
- @manifest = false
+ def preinit
+ {:references => [], :mode => :text, :format => :to_rest }.each do |name,value|
+ options[name] = value
end
-
- option("--all","-a")
- option("--outputdir OUTPUTDIR","-o")
- option("--verbose","-v")
- option("--debug","-d")
- option("--charset CHARSET")
-
- option("--format FORMAT", "-f") do |arg|
- method = "to_#{arg}"
- require 'puppet/util/reference'
- if Puppet::Util::Reference.method_defined?(method)
- options[:format] = method
- else
- raise "Invalid output format #{arg}"
- end
+ @unknown_args = []
+ @manifest = false
+ end
+
+ option("--all","-a")
+ option("--outputdir OUTPUTDIR","-o")
+ option("--verbose","-v")
+ option("--debug","-d")
+ option("--charset CHARSET")
+
+ option("--format FORMAT", "-f") do |arg|
+ method = "to_#{arg}"
+ require 'puppet/util/reference'
+ if Puppet::Util::Reference.method_defined?(method)
+ options[:format] = method
+ else
+ raise "Invalid output format #{arg}"
end
-
- option("--mode MODE", "-m") do |arg|
- require 'puppet/util/reference'
- if Puppet::Util::Reference.modes.include?(arg) or arg.intern==:rdoc
- options[:mode] = arg.intern
- else
- raise "Invalid output mode #{arg}"
- end
+ end
+
+ option("--mode MODE", "-m") do |arg|
+ require 'puppet/util/reference'
+ if Puppet::Util::Reference.modes.include?(arg) or arg.intern==:rdoc
+ options[:mode] = arg.intern
+ else
+ raise "Invalid output mode #{arg}"
end
-
- option("--list", "-l") do |arg|
- require 'puppet/util/reference'
- puts Puppet::Util::Reference.references.collect { |r| Puppet::Util::Reference.reference(r).doc }.join("\n")
- exit(0)
- end
-
- option("--reference REFERENCE", "-r") do |arg|
- options[:references] << arg.intern
+ end
+
+ option("--list", "-l") do |arg|
+ require 'puppet/util/reference'
+ puts Puppet::Util::Reference.references.collect { |r| Puppet::Util::Reference.reference(r).doc }.join("\n")
+ exit(0)
+ end
+
+ option("--reference REFERENCE", "-r") do |arg|
+ options[:references] << arg.intern
+ end
+
+ def handle_unknown( opt, arg )
+ @unknown_args << {:opt => opt, :arg => arg }
+ true
+ end
+
+ def run_command
+ return[:rdoc, :trac, :markdown].include?(options[:mode]) ? send(options[:mode]) : other
+ end
+
+ def rdoc
+ exit_code = 0
+ files = []
+ unless @manifest
+ env = Puppet::Node::Environment.new
+ files += env.modulepath
+ files << File.dirname(env[:manifest])
end
+ files += command_line.args
+ Puppet.info "scanning: #{files.inspect}"
- def handle_unknown( opt, arg )
- @unknown_args << {:opt => opt, :arg => arg }
- true
- end
-
- def run_command
- return[:rdoc, :trac, :markdown].include?(options[:mode]) ? send(options[:mode]) : other
- end
-
- def rdoc
- exit_code = 0
- files = []
- unless @manifest
- env = Puppet::Node::Environment.new
- files += env.modulepath
- files << File.dirname(env[:manifest])
- end
- files += command_line.args
- Puppet.info "scanning: #{files.inspect}"
-
- Puppet.settings.setdefaults(
- "puppetdoc",
+ Puppet.settings.setdefaults(
+ "puppetdoc",
- "document_all" => [false, "Document all resources"]
- )
- Puppet.settings[:document_all] = options[:all] || false
- begin
- require 'puppet/util/rdoc'
- if @manifest
- Puppet::Util::RDoc.manifestdoc(files)
- else
- options[:outputdir] = "doc" unless options[:outputdir]
- Puppet::Util::RDoc.rdoc(options[:outputdir], files, options[:charset])
- end
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- $stderr.puts "Could not generate documentation: #{detail}"
- exit_code = 1
- end
- exit exit_code
+ "document_all" => [false, "Document all resources"]
+ )
+ Puppet.settings[:document_all] = options[:all] || false
+ begin
+ require 'puppet/util/rdoc'
+ if @manifest
+ Puppet::Util::RDoc.manifestdoc(files)
+ else
+ options[:outputdir] = "doc" unless options[:outputdir]
+ Puppet::Util::RDoc.rdoc(options[:outputdir], files, options[:charset])
+ end
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ $stderr.puts "Could not generate documentation: #{detail}"
+ exit_code = 1
end
-
- def trac
- require 'puppet/util/reference'
- options[:references].each do |name|
- section = Puppet::Util::Reference.reference(name) or raise "Could not find section #{name}"
- section.trac unless options[:mode] == :pdf
- end
+ exit exit_code
+ end
+
+ def trac
+ require 'puppet/util/reference'
+ options[:references].each do |name|
+ section = Puppet::Util::Reference.reference(name) or raise "Could not find section #{name}"
+ section.trac unless options[:mode] == :pdf
end
-
- def markdown
+ end
+
+ def markdown
+ text = ""
+ with_contents = false
+ exit_code = 0
+ require 'puppet/util/reference'
+ options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name|
+ raise "Could not find reference #{name}" unless section = Puppet::Util::Reference.reference(name)
+
+ begin
+ # Add the per-section text, but with no ToC
+ text += section.send(options[:format], with_contents)
+ text += Puppet::Util::Reference.footer
+ text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 }
+ Puppet::Util::Reference.markdown(name, text)
text = ""
- with_contents = false
- exit_code = 0
- require 'puppet/util/reference'
- options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name|
- raise "Could not find reference #{name}" unless section = Puppet::Util::Reference.reference(name)
-
- begin
- # Add the per-section text, but with no ToC
- text += section.send(options[:format], with_contents)
- text += Puppet::Util::Reference.footer
- text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 }
- Puppet::Util::Reference.markdown(name, text)
- text = ""
- rescue => detail
- puts detail.backtrace
- $stderr.puts "Could not generate reference #{name}: #{detail}"
- exit_code = 1
- next
- end
- end
-
- exit exit_code
+ rescue => detail
+ puts detail.backtrace
+ $stderr.puts "Could not generate reference #{name}: #{detail}"
+ exit_code = 1
+ next
+ end
end
- def other
- text = ""
- with_contents = options[:references].length <= 1
- exit_code = 0
- require 'puppet/util/reference'
- options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name|
- raise "Could not find reference #{name}" unless section = Puppet::Util::Reference.reference(name)
-
- begin
- # Add the per-section text, but with no ToC
- text += section.send(options[:format], with_contents)
- rescue => detail
- puts detail.backtrace
- $stderr.puts "Could not generate reference #{name}: #{detail}"
- exit_code = 1
- next
- end
- end
+ exit exit_code
+ end
+
+ def other
+ text = ""
+ with_contents = options[:references].length <= 1
+ exit_code = 0
+ require 'puppet/util/reference'
+ options[:references].sort { |a,b| a.to_s <=> b.to_s }.each do |name|
+ raise "Could not find reference #{name}" unless section = Puppet::Util::Reference.reference(name)
+
+ begin
+ # Add the per-section text, but with no ToC
+ text += section.send(options[:format], with_contents)
+ rescue => detail
+ puts detail.backtrace
+ $stderr.puts "Could not generate reference #{name}: #{detail}"
+ exit_code = 1
+ next
+ end
+ end
- text += Puppet::Util::Reference.footer unless with_contents # We've only got one reference
+ text += Puppet::Util::Reference.footer unless with_contents # We've only got one reference
- # Replace the trac links, since they're invalid everywhere else
- text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 }
+ # Replace the trac links, since they're invalid everywhere else
+ text.gsub!(/`\w+\s+([^`]+)`:trac:/) { |m| $1 }
- if options[:mode] == :pdf
- Puppet::Util::Reference.pdf(text)
- else
- puts text
- end
-
- exit exit_code
+ if options[:mode] == :pdf
+ Puppet::Util::Reference.pdf(text)
+ else
+ puts text
end
- def setup
- # sole manifest documentation
- if command_line.args.size > 0
- options[:mode] = :rdoc
- @manifest = true
- end
+ exit exit_code
+ end
- if options[:mode] == :rdoc
- setup_rdoc
- else
- setup_reference
- end
+ def setup
+ # sole manifest documentation
+ if command_line.args.size > 0
+ options[:mode] = :rdoc
+ @manifest = true
end
- def setup_reference
- if options[:all]
- # Don't add dynamic references to the "all" list.
- require 'puppet/util/reference'
- options[:references] = Puppet::Util::Reference.references.reject do |ref|
- Puppet::Util::Reference.reference(ref).dynamic?
- end
- end
-
- options[:references] << :type if options[:references].empty?
+ if options[:mode] == :rdoc
+ setup_rdoc
+ else
+ setup_reference
+ end
+ end
+
+ def setup_reference
+ if options[:all]
+ # Don't add dynamic references to the "all" list.
+ require 'puppet/util/reference'
+ options[:references] = Puppet::Util::Reference.references.reject do |ref|
+ Puppet::Util::Reference.reference(ref).dynamic?
+ end
end
- def setup_rdoc(dummy_argument=:work_arround_for_ruby_GC_bug)
- # consume the unknown options
- # and feed them as settings
- if @unknown_args.size > 0
- @unknown_args.each do |option|
- # force absolute path for modulepath when passed on commandline
- if option[:opt]=="--modulepath" or option[:opt] == "--manifestdir"
- option[:arg] = option[:arg].split(':').collect { |p| File.expand_path(p) }.join(':')
- end
- Puppet.settings.handlearg(option[:opt], option[:arg])
- end
+ options[:references] << :type if options[:references].empty?
+ end
+
+ def setup_rdoc(dummy_argument=:work_arround_for_ruby_GC_bug)
+ # consume the unknown options
+ # and feed them as settings
+ if @unknown_args.size > 0
+ @unknown_args.each do |option|
+ # force absolute path for modulepath when passed on commandline
+ if option[:opt]=="--modulepath" or option[:opt] == "--manifestdir"
+ option[:arg] = option[:arg].split(':').collect { |p| File.expand_path(p) }.join(':')
end
+ Puppet.settings.handlearg(option[:opt], option[:arg])
+ end
+ end
- # Now parse the config
- Puppet.parse_config
+ # Now parse the config
+ Puppet.parse_config
- # Handle the logging settings.
- if options[:debug] or options[:verbose]
- if options[:debug]
- Puppet::Util::Log.level = :debug
- else
- Puppet::Util::Log.level = :info
- end
+ # Handle the logging settings.
+ if options[:debug] or options[:verbose]
+ if options[:debug]
+ Puppet::Util::Log.level = :debug
+ else
+ Puppet::Util::Log.level = :info
+ end
- Puppet::Util::Log.newdestination(:console)
- end
+ Puppet::Util::Log.newdestination(:console)
end
+ end
end
diff --git a/lib/puppet/application/filebucket.rb b/lib/puppet/application/filebucket.rb
index 8da2d014d..9c3c79bc3 100644
--- a/lib/puppet/application/filebucket.rb
+++ b/lib/puppet/application/filebucket.rb
@@ -2,86 +2,86 @@ require 'puppet/application'
class Puppet::Application::Filebucket < Puppet::Application
- should_not_parse_config
-
- option("--bucket BUCKET","-b")
- option("--debug","-d")
- option("--local","-l")
- option("--remote","-r")
- option("--verbose","-v")
+ should_not_parse_config
+
+ option("--bucket BUCKET","-b")
+ option("--debug","-d")
+ option("--local","-l")
+ option("--remote","-r")
+ option("--verbose","-v")
+
+ attr :args
+
+ def run_command
+ @args = command_line.args
+ command = args.shift
+ return send(command) if %w{get backup restore}.include? command
+ help
+ end
+
+ def get
+ md5 = args.shift
+ out = @client.getfile(md5)
+ print out
+ end
+
+ def backup
+ args.each do |file|
+ unless FileTest.exists?(file)
+ $stderr.puts "#{file}: no such file"
+ next
+ end
+ unless FileTest.readable?(file)
+ $stderr.puts "#{file}: cannot read file"
+ next
+ end
+ md5 = @client.backup(file)
+ puts "#{file}: #{md5}"
+ end
+ end
- attr :args
+ def restore
+ file = args.shift
+ md5 = args.shift
+ @client.restore(file, md5)
+ end
- def run_command
- @args = command_line.args
- command = args.shift
- return send(command) if %w{get backup restore}.include? command
- help
- end
+ def setup
+ Puppet::Log.newdestination(:console)
- def get
- md5 = args.shift
- out = @client.getfile(md5)
- print out
- end
+ @client = nil
+ @server = nil
- def backup
- args.each do |file|
- unless FileTest.exists?(file)
- $stderr.puts "#{file}: no such file"
- next
- end
- unless FileTest.readable?(file)
- $stderr.puts "#{file}: cannot read file"
- next
- end
- md5 = @client.backup(file)
- puts "#{file}: #{md5}"
- end
+ trap(:INT) do
+ $stderr.puts "Cancelling"
+ exit(1)
end
- def restore
- file = args.shift
- md5 = args.shift
- @client.restore(file, md5)
+ if options[:debug]
+ Puppet::Log.level = :debug
+ elsif options[:verbose]
+ Puppet::Log.level = :info
end
- def setup
- Puppet::Log.newdestination(:console)
-
- @client = nil
- @server = nil
-
- trap(:INT) do
- $stderr.puts "Cancelling"
- exit(1)
- end
-
- if options[:debug]
- Puppet::Log.level = :debug
- elsif options[:verbose]
- Puppet::Log.level = :info
- end
-
- # Now parse the config
- Puppet.parse_config
-
- exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
-
- require 'puppet/file_bucket/dipper'
- begin
- if options[:local] or options[:bucket]
- path = options[:bucket] || Puppet[:bucketdir]
- @client = Puppet::FileBucket::Dipper.new(:Path => path)
- else
- @client = Puppet::FileBucket::Dipper.new(:Server => Puppet[:server])
- end
- rescue => detail
- $stderr.puts detail
- puts detail.backtrace if Puppet[:trace]
- exit(1)
- end
+ # Now parse the config
+ Puppet.parse_config
+
+ exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+
+ require 'puppet/file_bucket/dipper'
+ begin
+ if options[:local] or options[:bucket]
+ path = options[:bucket] || Puppet[:bucketdir]
+ @client = Puppet::FileBucket::Dipper.new(:Path => path)
+ else
+ @client = Puppet::FileBucket::Dipper.new(:Server => Puppet[:server])
+ end
+ rescue => detail
+ $stderr.puts detail
+ puts detail.backtrace if Puppet[:trace]
+ exit(1)
end
+ end
end
diff --git a/lib/puppet/application/kick.rb b/lib/puppet/application/kick.rb
index 6c77e74f2..37aeb1ef2 100644
--- a/lib/puppet/application/kick.rb
+++ b/lib/puppet/application/kick.rb
@@ -2,211 +2,211 @@ require 'puppet/application'
class Puppet::Application::Kick < Puppet::Application
- should_not_parse_config
+ should_not_parse_config
+
+ attr_accessor :hosts, :tags, :classes
+
+ option("--all","-a")
+ option("--foreground","-f")
+ option("--debug","-d")
+ option("--ping","-P")
+ option("--test")
+
+ option("--host HOST") do |arg|
+ @hosts << arg
+ end
+
+ option("--tag TAG", "-t") do |arg|
+ @tags << arg
+ end
+
+ option("--class CLASS", "-c") do |arg|
+ @classes << arg
+ end
+
+ option("--no-fqdn", "-n") do |arg|
+ options[:fqdn] = false
+ end
+
+ option("--parallel PARALLEL", "-p") do |arg|
+ begin
+ options[:parallel] = Integer(arg)
+ rescue
+ $stderr.puts "Could not convert #{arg.inspect} to an integer"
+ exit(23)
+ end
+ end
- attr_accessor :hosts, :tags, :classes
+ def run_command
+ @hosts += command_line.args
+ options[:test] ? test : main
+ end
- option("--all","-a")
- option("--foreground","-f")
- option("--debug","-d")
- option("--ping","-P")
- option("--test")
+ def test
+ puts "Skipping execution in test mode"
+ exit(0)
+ end
- option("--host HOST") do |arg|
- @hosts << arg
- end
+ def main
+ require 'puppet/network/client'
- option("--tag TAG", "-t") do |arg|
- @tags << arg
- end
+ Puppet.warning "Failed to load ruby LDAP library. LDAP functionality will not be available" unless Puppet.features.ldap?
+ require 'puppet/util/ldap/connection'
- option("--class CLASS", "-c") do |arg|
- @classes << arg
- end
+ todo = @hosts.dup
- option("--no-fqdn", "-n") do |arg|
- options[:fqdn] = false
- end
+ failures = []
- option("--parallel PARALLEL", "-p") do |arg|
+ # Now do the actual work
+ go = true
+ while go
+ # If we don't have enough children in process and we still have hosts left to
+ # do, then do the next host.
+ if @children.length < options[:parallel] and ! todo.empty?
+ host = todo.shift
+ pid = fork do
+ run_for_host(host)
+ end
+ @children[pid] = host
+ else
+ # Else, see if we can reap a process.
begin
- options[:parallel] = Integer(arg)
- rescue
- $stderr.puts "Could not convert #{arg.inspect} to an integer"
- exit(23)
+ pid = Process.wait
+
+ if host = @children[pid]
+ # Remove our host from the list of children, so the parallelization
+ # continues working.
+ @children.delete(pid)
+ failures << host if $CHILD_STATUS.exitstatus != 0
+ print "#{host} finished with exit code #{$CHILD_STATUS.exitstatus}\n"
+ else
+ $stderr.puts "Could not find host for PID #{pid} with status #{$CHILD_STATUS.exitstatus}"
+ end
+ rescue Errno::ECHILD
+ # There are no children left, so just exit unless there are still
+ # children left to do.
+ next unless todo.empty?
+
+ if failures.empty?
+ puts "Finished"
+ exit(0)
+ else
+ puts "Failed: #{failures.join(", ")}"
+ exit(3)
+ end
end
+ end
end
-
- def run_command
- @hosts += command_line.args
- options[:test] ? test : main
+ end
+
+ def run_for_host(host)
+ if options[:ping]
+ out = %x{ping -c 1 #{host}}
+ unless $CHILD_STATUS == 0
+ $stderr.print "Could not contact #{host}\n"
+ next
+ end
end
- def test
- puts "Skipping execution in test mode"
- exit(0)
+ require 'puppet/run'
+ Puppet::Run.indirection.terminus_class = :rest
+ port = Puppet[:puppetport]
+ url = ["https://#{host}:#{port}", "production", "run", host].join('/')
+
+ print "Triggering #{host}\n"
+ begin
+ run_options = {
+ :tags => @tags,
+ :background => ! options[:foreground],
+ :ignoreschedules => options[:ignoreschedules]
+ }
+ run = Puppet::Run.new( run_options ).save( url )
+ puts "Getting status"
+ result = run.status
+ puts "status is #{result}"
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ $stderr.puts "Host #{host} failed: #{detail}\n"
+ exit(2)
end
- def main
- require 'puppet/network/client'
-
- Puppet.warning "Failed to load ruby LDAP library. LDAP functionality will not be available" unless Puppet.features.ldap?
- require 'puppet/util/ldap/connection'
-
- todo = @hosts.dup
-
- failures = []
-
- # Now do the actual work
- go = true
- while go
- # If we don't have enough children in process and we still have hosts left to
- # do, then do the next host.
- if @children.length < options[:parallel] and ! todo.empty?
- host = todo.shift
- pid = fork do
- run_for_host(host)
- end
- @children[pid] = host
- else
- # Else, see if we can reap a process.
- begin
- pid = Process.wait
-
- if host = @children[pid]
- # Remove our host from the list of children, so the parallelization
- # continues working.
- @children.delete(pid)
- failures << host if $CHILD_STATUS.exitstatus != 0
- print "#{host} finished with exit code #{$CHILD_STATUS.exitstatus}\n"
- else
- $stderr.puts "Could not find host for PID #{pid} with status #{$CHILD_STATUS.exitstatus}"
- end
- rescue Errno::ECHILD
- # There are no children left, so just exit unless there are still
- # children left to do.
- next unless todo.empty?
-
- if failures.empty?
- puts "Finished"
- exit(0)
- else
- puts "Failed: #{failures.join(", ")}"
- exit(3)
- end
- end
- end
- end
+ case result
+ when "success";
+ exit(0)
+ when "running"
+ $stderr.puts "Host #{host} is already running"
+ exit(3)
+ else
+ $stderr.puts "Host #{host} returned unknown answer '#{result}'"
+ exit(12)
end
-
- def run_for_host(host)
- if options[:ping]
- out = %x{ping -c 1 #{host}}
- unless $CHILD_STATUS == 0
- $stderr.print "Could not contact #{host}\n"
- next
- end
- end
-
- require 'puppet/run'
- Puppet::Run.indirection.terminus_class = :rest
- port = Puppet[:puppetport]
- url = ["https://#{host}:#{port}", "production", "run", host].join('/')
-
- print "Triggering #{host}\n"
- begin
- run_options = {
- :tags => @tags,
- :background => ! options[:foreground],
- :ignoreschedules => options[:ignoreschedules]
- }
- run = Puppet::Run.new( run_options ).save( url )
- puts "Getting status"
- result = run.status
- puts "status is #{result}"
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- $stderr.puts "Host #{host} failed: #{detail}\n"
- exit(2)
- end
-
- case result
- when "success";
- exit(0)
- when "running"
- $stderr.puts "Host #{host} is already running"
- exit(3)
- else
- $stderr.puts "Host #{host} returned unknown answer '#{result}'"
- exit(12)
- end
+ end
+
+ def initialize(*args)
+ super
+ @hosts = []
+ @classes = []
+ @tags = []
+ end
+
+ def preinit
+ [:INT, :TERM].each do |signal|
+ trap(signal) do
+ $stderr.puts "Cancelling"
+ exit(1)
+ end
+ end
+ options[:parallel] = 1
+ options[:verbose] = true
+ options[:fqdn] = true
+ options[:ignoreschedules] = false
+ options[:foreground] = false
+ end
+
+ def setup
+ if options[:debug]
+ Puppet::Util::Log.level = :debug
+ else
+ Puppet::Util::Log.level = :info
end
- def initialize(*args)
- super
+ # Now parse the config
+ Puppet.parse_config
+
+ if Puppet[:node_terminus] == "ldap" and (options[:all] or @classes)
+ if options[:all]
+ @hosts = Puppet::Node.search("whatever", :fqdn => options[:fqdn]).collect { |node| node.name }
+ puts "all: #{@hosts.join(", ")}"
+ else
@hosts = []
- @classes = []
- @tags = []
- end
+ @classes.each do |klass|
+ list = Puppet::Node.search("whatever", :fqdn => options[:fqdn], :class => klass).collect { |node| node.name }
+ puts "#{klass}: #{list.join(", ")}"
- def preinit
- [:INT, :TERM].each do |signal|
- trap(signal) do
- $stderr.puts "Cancelling"
- exit(1)
- end
+ @hosts += list
end
- options[:parallel] = 1
- options[:verbose] = true
- options[:fqdn] = true
- options[:ignoreschedules] = false
- options[:foreground] = false
+ end
+ elsif ! @classes.empty?
+ $stderr.puts "You must be using LDAP to specify host classes"
+ exit(24)
end
- def setup
- if options[:debug]
- Puppet::Util::Log.level = :debug
- else
- Puppet::Util::Log.level = :info
- end
+ @children = {}
- # Now parse the config
- Puppet.parse_config
-
- if Puppet[:node_terminus] == "ldap" and (options[:all] or @classes)
- if options[:all]
- @hosts = Puppet::Node.search("whatever", :fqdn => options[:fqdn]).collect { |node| node.name }
- puts "all: #{@hosts.join(", ")}"
- else
- @hosts = []
- @classes.each do |klass|
- list = Puppet::Node.search("whatever", :fqdn => options[:fqdn], :class => klass).collect { |node| node.name }
- puts "#{klass}: #{list.join(", ")}"
-
- @hosts += list
- end
- end
- elsif ! @classes.empty?
- $stderr.puts "You must be using LDAP to specify host classes"
- exit(24)
+ # If we get a signal, then kill all of our children and get out.
+ [:INT, :TERM].each do |signal|
+ trap(signal) do
+ Puppet.notice "Caught #{signal}; shutting down"
+ @children.each do |pid, host|
+ Process.kill("INT", pid)
end
- @children = {}
-
- # If we get a signal, then kill all of our children and get out.
- [:INT, :TERM].each do |signal|
- trap(signal) do
- Puppet.notice "Caught #{signal}; shutting down"
- @children.each do |pid, host|
- Process.kill("INT", pid)
- end
-
- waitall
-
- exit(1)
- end
- end
+ waitall
+ exit(1)
+ end
end
+ end
+
end
diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb
index 7485dcb3f..777a50eaa 100644
--- a/lib/puppet/application/master.rb
+++ b/lib/puppet/application/master.rb
@@ -2,155 +2,155 @@ require 'puppet/application'
class Puppet::Application::Master < Puppet::Application
- should_parse_config
- run_mode :master
-
- option("--debug", "-d")
- option("--verbose", "-v")
-
- # internal option, only to be used by ext/rack/config.ru
- option("--rack")
+ should_parse_config
+ run_mode :master
+
+ option("--debug", "-d")
+ option("--verbose", "-v")
+
+ # internal option, only to be used by ext/rack/config.ru
+ option("--rack")
+
+ option("--compile host", "-c host") do |arg|
+ options[:node] = arg
+ end
+
+ option("--logdest DEST", "-l DEST") do |arg|
+ begin
+ Puppet::Util::Log.newdestination(arg)
+ options[:setdest] = true
+ rescue => detail
+ puts detail.backtrace if Puppet[:debug]
+ $stderr.puts detail.to_s
+ end
+ end
- option("--compile host", "-c host") do |arg|
- options[:node] = arg
+ def preinit
+ trap(:INT) do
+ $stderr.puts "Cancelling startup"
+ exit(0)
end
- option("--logdest DEST", "-l DEST") do |arg|
- begin
- Puppet::Util::Log.newdestination(arg)
- options[:setdest] = true
- rescue => detail
- puts detail.backtrace if Puppet[:debug]
- $stderr.puts detail.to_s
- end
+ # Create this first-off, so we have ARGV
+ require 'puppet/daemon'
+ @daemon = Puppet::Daemon.new
+ @daemon.argv = ARGV.dup
+ end
+
+ def run_command
+ if options[:node]
+ compile
+ elsif Puppet[:parseonly]
+ parseonly
+ else
+ main
+ end
+ end
+
+ def compile
+ Puppet::Util::Log.newdestination :console
+ raise ArgumentError, "Cannot render compiled catalogs without pson support" unless Puppet.features.pson?
+ begin
+ unless catalog = Puppet::Resource::Catalog.find(options[:node])
+ raise "Could not compile catalog for #{options[:node]}"
+ end
+
+ jj catalog.to_resource
+ rescue => detail
+ $stderr.puts detail
+ exit(30)
end
+ exit(0)
+ end
+
+ def parseonly
+ begin
+ Puppet::Node::Environment.new(Puppet[:environment]).known_resource_types
+ rescue => detail
+ Puppet.err detail
+ exit 1
+ end
+ exit(0)
+ end
- def preinit
- trap(:INT) do
- $stderr.puts "Cancelling startup"
- exit(0)
- end
+ def main
+ require 'etc'
+ require 'puppet/file_serving/content'
+ require 'puppet/file_serving/metadata'
- # Create this first-off, so we have ARGV
- require 'puppet/daemon'
- @daemon = Puppet::Daemon.new
- @daemon.argv = ARGV.dup
- end
+ xmlrpc_handlers = [:Status, :FileServer, :Master, :Report, :Filebucket]
- def run_command
- if options[:node]
- compile
- elsif Puppet[:parseonly]
- parseonly
- else
- main
- end
- end
+ xmlrpc_handlers << :CA if Puppet[:ca]
+
+ # Make sure we've got a localhost ssl cert
+ Puppet::SSL::Host.localhost
- def compile
- Puppet::Util::Log.newdestination :console
- raise ArgumentError, "Cannot render compiled catalogs without pson support" unless Puppet.features.pson?
- begin
- unless catalog = Puppet::Resource::Catalog.find(options[:node])
- raise "Could not compile catalog for #{options[:node]}"
- end
-
- jj catalog.to_resource
- rescue => detail
- $stderr.puts detail
- exit(30)
- end
- exit(0)
+ # And now configure our server to *only* hit the CA for data, because that's
+ # all it will have write access to.
+ Puppet::SSL::Host.ca_location = :only if Puppet::SSL::CertificateAuthority.ca?
+
+ if Puppet.features.root?
+ begin
+ Puppet::Util.chuser
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ $stderr.puts "Could not change user to #{Puppet[:user]}: #{detail}"
+ exit(39)
+ end
end
- def parseonly
- begin
- Puppet::Node::Environment.new(Puppet[:environment]).known_resource_types
- rescue => detail
- Puppet.err detail
- exit 1
- end
- exit(0)
+ unless options[:rack]
+ require 'puppet/network/server'
+ @daemon.server = Puppet::Network::Server.new(:xmlrpc_handlers => xmlrpc_handlers)
+ @daemon.daemonize if Puppet[:daemonize]
+ else
+ require 'puppet/network/http/rack'
+ @app = Puppet::Network::HTTP::Rack.new(:xmlrpc_handlers => xmlrpc_handlers, :protocols => [:rest, :xmlrpc])
end
- def main
- require 'etc'
- require 'puppet/file_serving/content'
- require 'puppet/file_serving/metadata'
-
- xmlrpc_handlers = [:Status, :FileServer, :Master, :Report, :Filebucket]
-
- xmlrpc_handlers << :CA if Puppet[:ca]
-
- # Make sure we've got a localhost ssl cert
- Puppet::SSL::Host.localhost
-
- # And now configure our server to *only* hit the CA for data, because that's
- # all it will have write access to.
- Puppet::SSL::Host.ca_location = :only if Puppet::SSL::CertificateAuthority.ca?
-
- if Puppet.features.root?
- begin
- Puppet::Util.chuser
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- $stderr.puts "Could not change user to #{Puppet[:user]}: #{detail}"
- exit(39)
- end
- end
-
- unless options[:rack]
- require 'puppet/network/server'
- @daemon.server = Puppet::Network::Server.new(:xmlrpc_handlers => xmlrpc_handlers)
- @daemon.daemonize if Puppet[:daemonize]
- else
- require 'puppet/network/http/rack'
- @app = Puppet::Network::HTTP::Rack.new(:xmlrpc_handlers => xmlrpc_handlers, :protocols => [:rest, :xmlrpc])
- end
-
- Puppet.notice "Starting Puppet master version #{Puppet.version}"
-
- unless options[:rack]
- @daemon.start
- else
- return @app
- end
+ Puppet.notice "Starting Puppet master version #{Puppet.version}"
+
+ unless options[:rack]
+ @daemon.start
+ else
+ return @app
end
+ end
+
+ def setup
+ # Handle the logging settings.
+ if options[:debug] or options[:verbose]
+ if options[:debug]
+ Puppet::Util::Log.level = :debug
+ else
+ Puppet::Util::Log.level = :info
+ end
+
+ unless Puppet[:daemonize] or options[:rack]
+ Puppet::Util::Log.newdestination(:console)
+ options[:setdest] = true
+ end
+ end
+
+ Puppet::Util::Log.newdestination(:syslog) unless options[:setdest]
+
+ exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+
+ Puppet.settings.use :main, :master, :ssl
+
+ # A temporary solution, to at least make the master work for now.
+ Puppet::Node::Facts.terminus_class = :yaml
+
+ # Cache our nodes in yaml. Currently not configurable.
+ Puppet::Node.cache_class = :yaml
- def setup
- # Handle the logging settings.
- if options[:debug] or options[:verbose]
- if options[:debug]
- Puppet::Util::Log.level = :debug
- else
- Puppet::Util::Log.level = :info
- end
-
- unless Puppet[:daemonize] or options[:rack]
- Puppet::Util::Log.newdestination(:console)
- options[:setdest] = true
- end
- end
-
- Puppet::Util::Log.newdestination(:syslog) unless options[:setdest]
-
- exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
-
- Puppet.settings.use :main, :master, :ssl
-
- # A temporary solution, to at least make the master work for now.
- Puppet::Node::Facts.terminus_class = :yaml
-
- # Cache our nodes in yaml. Currently not configurable.
- Puppet::Node.cache_class = :yaml
-
- # Configure all of the SSL stuff.
- if Puppet::SSL::CertificateAuthority.ca?
- Puppet::SSL::Host.ca_location = :local
- Puppet.settings.use :ca
- Puppet::SSL::CertificateAuthority.instance
- else
- Puppet::SSL::Host.ca_location = :none
- end
+ # Configure all of the SSL stuff.
+ if Puppet::SSL::CertificateAuthority.ca?
+ Puppet::SSL::Host.ca_location = :local
+ Puppet.settings.use :ca
+ Puppet::SSL::CertificateAuthority.instance
+ else
+ Puppet::SSL::Host.ca_location = :none
end
+ end
end
diff --git a/lib/puppet/application/queue.rb b/lib/puppet/application/queue.rb
index 6531f6f92..6df825dd1 100644
--- a/lib/puppet/application/queue.rb
+++ b/lib/puppet/application/queue.rb
@@ -2,90 +2,90 @@ require 'puppet/application'
require 'puppet/util'
class Puppet::Application::Queue < Puppet::Application
- should_parse_config
+ should_parse_config
- attr_accessor :daemon
+ attr_accessor :daemon
- def preinit
- require 'puppet/daemon'
- @daemon = Puppet::Daemon.new
- @daemon.argv = ARGV.dup
- Puppet::Util::Log.newdestination(:console)
+ def preinit
+ require 'puppet/daemon'
+ @daemon = Puppet::Daemon.new
+ @daemon.argv = ARGV.dup
+ Puppet::Util::Log.newdestination(:console)
- # Do an initial trap, so that cancels don't get a stack trace.
+ # Do an initial trap, so that cancels don't get a stack trace.
- # This exits with exit code 1
- trap(:INT) do
- $stderr.puts "Caught SIGINT; shutting down"
- exit(1)
- end
-
- # This is a normal shutdown, so code 0
- trap(:TERM) do
- $stderr.puts "Caught SIGTERM; shutting down"
- exit(0)
- end
+ # This exits with exit code 1
+ trap(:INT) do
+ $stderr.puts "Caught SIGINT; shutting down"
+ exit(1)
+ end
- {
- :verbose => false,
- :debug => false
- }.each do |opt,val|
- options[opt] = val
- end
+ # This is a normal shutdown, so code 0
+ trap(:TERM) do
+ $stderr.puts "Caught SIGTERM; shutting down"
+ exit(0)
end
- option("--debug","-d")
- option("--verbose","-v")
-
- def main
- Puppet.notice "Starting puppetqd #{Puppet.version}"
- Puppet::Resource::Catalog::Queue.subscribe do |catalog|
- # Once you have a Puppet::Resource::Catalog instance, calling save on it should suffice
- # to put it through to the database via its active_record indirector (which is determined
- # by the terminus_class = :active_record setting above)
- Puppet::Util.benchmark(:notice, "Processing queued catalog for #{catalog.name}") do
- begin
- catalog.save
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not save queued catalog for #{catalog.name}: #{detail}"
- end
- end
+ {
+ :verbose => false,
+ :debug => false
+ }.each do |opt,val|
+ options[opt] = val
+ end
+ end
+
+ option("--debug","-d")
+ option("--verbose","-v")
+
+ def main
+ Puppet.notice "Starting puppetqd #{Puppet.version}"
+ Puppet::Resource::Catalog::Queue.subscribe do |catalog|
+ # Once you have a Puppet::Resource::Catalog instance, calling save on it should suffice
+ # to put it through to the database via its active_record indirector (which is determined
+ # by the terminus_class = :active_record setting above)
+ Puppet::Util.benchmark(:notice, "Processing queued catalog for #{catalog.name}") do
+ begin
+ catalog.save
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not save queued catalog for #{catalog.name}: #{detail}"
end
-
- Thread.list.each { |thread| thread.join }
+ end
end
- # Handle the logging settings.
- def setup_logs
- if options[:debug] or options[:verbose]
- Puppet::Util::Log.newdestination(:console)
- if options[:debug]
- Puppet::Util::Log.level = :debug
- else
- Puppet::Util::Log.level = :info
- end
- end
+ Thread.list.each { |thread| thread.join }
+ end
+
+ # Handle the logging settings.
+ def setup_logs
+ if options[:debug] or options[:verbose]
+ Puppet::Util::Log.newdestination(:console)
+ if options[:debug]
+ Puppet::Util::Log.level = :debug
+ else
+ Puppet::Util::Log.level = :info
+ end
end
+ end
- def setup
- unless Puppet.features.stomp?
- raise ArgumentError, "Could not load the 'stomp' library, which must be present for queueing to work. You must install the required library."
- end
+ def setup
+ unless Puppet.features.stomp?
+ raise ArgumentError, "Could not load the 'stomp' library, which must be present for queueing to work. You must install the required library."
+ end
- setup_logs
+ setup_logs
- exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
+ exit(Puppet.settings.print_configs ? 0 : 1) if Puppet.settings.print_configs?
- require 'puppet/resource/catalog'
- Puppet::Resource::Catalog.terminus_class = :active_record
+ require 'puppet/resource/catalog'
+ Puppet::Resource::Catalog.terminus_class = :active_record
- daemon.daemonize if Puppet[:daemonize]
+ daemon.daemonize if Puppet[:daemonize]
- # We want to make sure that we don't have a cache
- # class set up, because if storeconfigs is enabled,
- # we'll get a loop of continually caching the catalog
- # for storage again.
- Puppet::Resource::Catalog.cache_class = nil
- end
+ # We want to make sure that we don't have a cache
+ # class set up, because if storeconfigs is enabled,
+ # we'll get a loop of continually caching the catalog
+ # for storage again.
+ Puppet::Resource::Catalog.cache_class = nil
+ end
end
diff --git a/lib/puppet/application/resource.rb b/lib/puppet/application/resource.rb
index 9e1efe2ef..f55caa58a 100644
--- a/lib/puppet/application/resource.rb
+++ b/lib/puppet/application/resource.rb
@@ -2,117 +2,117 @@ require 'puppet/application'
class Puppet::Application::Resource < Puppet::Application
- should_not_parse_config
-
- attr_accessor :host, :extra_params
-
- def preinit
- @extra_params = []
- @host = nil
- Facter.loadfacts
+ should_not_parse_config
+
+ attr_accessor :host, :extra_params
+
+ def preinit
+ @extra_params = []
+ @host = nil
+ Facter.loadfacts
+ end
+
+ option("--debug","-d")
+ option("--verbose","-v")
+ option("--edit","-e")
+
+ option("--host HOST","-H") do |arg|
+ @host = arg
+ end
+
+ option("--types", "-t") do |arg|
+ types = []
+ Puppet::Type.loadall
+ Puppet::Type.eachtype do |t|
+ next if t.name == :component
+ types << t.name.to_s
end
-
- option("--debug","-d")
- option("--verbose","-v")
- option("--edit","-e")
-
- option("--host HOST","-H") do |arg|
- @host = arg
+ puts types.sort
+ exit
+ end
+
+ option("--param PARAM", "-p") do |arg|
+ @extra_params << arg.to_sym
+ end
+
+ def main
+ args = command_line.args
+ type = args.shift or raise "You must specify the type to display"
+ typeobj = Puppet::Type.type(type) or raise "Could not find type #{type}"
+ name = args.shift
+ params = {}
+ args.each do |setting|
+ if setting =~ /^(\w+)=(.+)$/
+ params[$1] = $2
+ else
+ raise "Invalid parameter setting #{setting}"
+ end
end
- option("--types", "-t") do |arg|
- types = []
- Puppet::Type.loadall
- Puppet::Type.eachtype do |t|
- next if t.name == :component
- types << t.name.to_s
- end
- puts types.sort
- exit
- end
+ raise "You cannot edit a remote host" if options[:edit] and @host
- option("--param PARAM", "-p") do |arg|
- @extra_params << arg.to_sym
- end
+ properties = typeobj.properties.collect { |s| s.name }
- def main
- args = command_line.args
- type = args.shift or raise "You must specify the type to display"
- typeobj = Puppet::Type.type(type) or raise "Could not find type #{type}"
- name = args.shift
- params = {}
- args.each do |setting|
- if setting =~ /^(\w+)=(.+)$/
- params[$1] = $2
- else
- raise "Invalid parameter setting #{setting}"
- end
+ format = proc {|trans|
+ trans.dup.collect do |param, value|
+ if value.nil? or value.to_s.empty?
+ trans.delete(param)
+ elsif value.to_s == "absent" and param.to_s != "ensure"
+ trans.delete(param)
end
- raise "You cannot edit a remote host" if options[:edit] and @host
-
- properties = typeobj.properties.collect { |s| s.name }
-
- format = proc {|trans|
- trans.dup.collect do |param, value|
- if value.nil? or value.to_s.empty?
- trans.delete(param)
- elsif value.to_s == "absent" and param.to_s != "ensure"
- trans.delete(param)
- end
-
- trans.delete(param) unless properties.include?(param) or @extra_params.include?(param)
- end
- trans.to_manifest
- }
-
- if @host
- Puppet::Resource.indirection.terminus_class = :rest
- port = Puppet[:puppetport]
- key = ["https://#{host}:#{port}", "production", "resources", type, name].join('/')
- else
- key = [type, name].join('/')
- end
+ trans.delete(param) unless properties.include?(param) or @extra_params.include?(param)
+ end
+ trans.to_manifest
+ }
+
+ if @host
+ Puppet::Resource.indirection.terminus_class = :rest
+ port = Puppet[:puppetport]
+ key = ["https://#{host}:#{port}", "production", "resources", type, name].join('/')
+ else
+ key = [type, name].join('/')
+ end
- text = if name
- if params.empty?
- [ Puppet::Resource.find( key ) ]
- else
- [ Puppet::Resource.new( type, name, :parameters => params ).save( key ) ]
- end
- else
- Puppet::Resource.search( key, {} )
- end.map(&format).join("\n")
-
- if options[:edit]
- file = "/tmp/x2puppet-#{Process.pid}.pp"
- begin
- File.open(file, "w") do |f|
- f.puts text
- end
- ENV["EDITOR"] ||= "vi"
- system(ENV["EDITOR"], file)
- system("puppet -v #{file}")
- ensure
- #if FileTest.exists? file
- # File.unlink(file)
- #end
- end
- else
- puts text
+ text = if name
+ if params.empty?
+ [ Puppet::Resource.find( key ) ]
+ else
+ [ Puppet::Resource.new( type, name, :parameters => params ).save( key ) ]
+ end
+ else
+ Puppet::Resource.search( key, {} )
+ end.map(&format).join("\n")
+
+ if options[:edit]
+ file = "/tmp/x2puppet-#{Process.pid}.pp"
+ begin
+ File.open(file, "w") do |f|
+ f.puts text
end
+ ENV["EDITOR"] ||= "vi"
+ system(ENV["EDITOR"], file)
+ system("puppet -v #{file}")
+ ensure
+ #if FileTest.exists? file
+ # File.unlink(file)
+ #end
+ end
+ else
+ puts text
end
+ end
- def setup
- Puppet::Util::Log.newdestination(:console)
+ def setup
+ Puppet::Util::Log.newdestination(:console)
- # Now parse the config
- Puppet.parse_config
+ # Now parse the config
+ Puppet.parse_config
- if options[:debug]
- Puppet::Util::Log.level = :debug
- elsif options[:verbose]
- Puppet::Util::Log.level = :info
- end
+ if options[:debug]
+ Puppet::Util::Log.level = :debug
+ elsif options[:verbose]
+ Puppet::Util::Log.level = :info
end
+ end
end
diff --git a/lib/puppet/configurer.rb b/lib/puppet/configurer.rb
index 5b8174588..327955b03 100644
--- a/lib/puppet/configurer.rb
+++ b/lib/puppet/configurer.rb
@@ -5,231 +5,231 @@ require 'puppet/network/http_pool'
require 'puppet/util'
class Puppet::Configurer
- class CommandHookError < RuntimeError; end
+ class CommandHookError < RuntimeError; end
- require 'puppet/configurer/fact_handler'
- require 'puppet/configurer/plugin_handler'
+ require 'puppet/configurer/fact_handler'
+ require 'puppet/configurer/plugin_handler'
- include Puppet::Configurer::FactHandler
- include Puppet::Configurer::PluginHandler
+ include Puppet::Configurer::FactHandler
+ include Puppet::Configurer::PluginHandler
- # For benchmarking
- include Puppet::Util
-
- attr_reader :compile_time
-
- # Provide more helpful strings to the logging that the Agent does
- def self.to_s
- "Puppet configuration client"
- end
-
- class << self
- # Puppetd should only have one instance running, and we need a way
- # to retrieve it.
- attr_accessor :instance
- include Puppet::Util
- end
-
- # How to lock instances of this class.
- def self.lockfile_path
- Puppet[:puppetdlockfile]
- end
-
- def clear
- @catalog.clear(true) if @catalog
- @catalog = nil
- end
-
- def execute_postrun_command
- execute_from_setting(:postrun_command)
- end
-
- def execute_prerun_command
- execute_from_setting(:prerun_command)
- end
-
- # Initialize and load storage
- def dostorage
- Puppet::Util::Storage.load
- @compile_time ||= Puppet::Util::Storage.cache(:configuration)[:compile_time]
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Corrupt state file #{Puppet[:statefile]}: #{detail}"
- begin
- ::File.unlink(Puppet[:statefile])
- retry
- rescue => detail
- raise Puppet::Error.new("Cannot remove #{Puppet[:statefile]}: #{detail}")
- end
- end
-
- # Just so we can specify that we are "the" instance.
- def initialize
- Puppet.settings.use(:main, :ssl, :agent)
-
- self.class.instance = self
- @running = false
- @splayed = false
- end
-
- def initialize_report
- Puppet::Transaction::Report.new
- end
+ # For benchmarking
+ include Puppet::Util
- # Prepare for catalog retrieval. Downloads everything necessary, etc.
- def prepare
- dostorage
+ attr_reader :compile_time
- download_plugins
+ # Provide more helpful strings to the logging that the Agent does
+ def self.to_s
+ "Puppet configuration client"
+ end
- download_fact_plugins
-
- execute_prerun_command
+ class << self
+ # Puppetd should only have one instance running, and we need a way
+ # to retrieve it.
+ attr_accessor :instance
+ include Puppet::Util
+ end
+
+ # How to lock instances of this class.
+ def self.lockfile_path
+ Puppet[:puppetdlockfile]
+ end
+
+ def clear
+ @catalog.clear(true) if @catalog
+ @catalog = nil
+ end
+
+ def execute_postrun_command
+ execute_from_setting(:postrun_command)
+ end
+
+ def execute_prerun_command
+ execute_from_setting(:prerun_command)
+ end
+
+ # Initialize and load storage
+ def dostorage
+ Puppet::Util::Storage.load
+ @compile_time ||= Puppet::Util::Storage.cache(:configuration)[:compile_time]
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Corrupt state file #{Puppet[:statefile]}: #{detail}"
+ begin
+ ::File.unlink(Puppet[:statefile])
+ retry
+ rescue => detail
+ raise Puppet::Error.new("Cannot remove #{Puppet[:statefile]}: #{detail}")
+ end
+ end
+
+ # Just so we can specify that we are "the" instance.
+ def initialize
+ Puppet.settings.use(:main, :ssl, :agent)
+
+ self.class.instance = self
+ @running = false
+ @splayed = false
+ end
+
+ def initialize_report
+ Puppet::Transaction::Report.new
+ end
+
+ # Prepare for catalog retrieval. Downloads everything necessary, etc.
+ def prepare
+ dostorage
+
+ download_plugins
+
+ download_fact_plugins
+
+ execute_prerun_command
+ end
+
+ # Get the remote catalog, yo. Returns nil if no catalog can be found.
+ def retrieve_catalog
+ if Puppet::Resource::Catalog.indirection.terminus_class == :rest
+ # This is a bit complicated. We need the serialized and escaped facts,
+ # and we need to know which format they're encoded in. Thus, we
+ # get a hash with both of these pieces of information.
+ fact_options = facts_for_uploading
+ else
+ fact_options = {}
+ end
+
+ # First try it with no cache, then with the cache.
+ unless (Puppet[:use_cached_catalog] and result = retrieve_catalog_from_cache(fact_options)) or result = retrieve_new_catalog(fact_options)
+ if ! Puppet[:usecacheonfailure]
+ Puppet.warning "Not using cache on failed catalog"
+ return nil
+ end
+ result = retrieve_catalog_from_cache(fact_options)
+ end
+
+ return nil unless result
+
+ convert_catalog(result, @duration)
+ end
+
+ # Convert a plain resource catalog into our full host catalog.
+ def convert_catalog(result, duration)
+ catalog = result.to_ral
+ catalog.finalize
+ catalog.retrieval_duration = duration
+ catalog.write_class_file
+ catalog
+ end
+
+ # The code that actually runs the catalog.
+ # This just passes any options on to the catalog,
+ # which accepts :tags and :ignoreschedules.
+ def run(options = {})
+ begin
+ prepare
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Failed to prepare catalog: #{detail}"
end
- # Get the remote catalog, yo. Returns nil if no catalog can be found.
- def retrieve_catalog
- if Puppet::Resource::Catalog.indirection.terminus_class == :rest
- # This is a bit complicated. We need the serialized and escaped facts,
- # and we need to know which format they're encoded in. Thus, we
- # get a hash with both of these pieces of information.
- fact_options = facts_for_uploading
- else
- fact_options = {}
- end
-
- # First try it with no cache, then with the cache.
- unless (Puppet[:use_cached_catalog] and result = retrieve_catalog_from_cache(fact_options)) or result = retrieve_new_catalog(fact_options)
- if ! Puppet[:usecacheonfailure]
- Puppet.warning "Not using cache on failed catalog"
- return nil
- end
- result = retrieve_catalog_from_cache(fact_options)
- end
-
- return nil unless result
-
- convert_catalog(result, @duration)
- end
+ options[:report] ||= initialize_report
+ report = options[:report]
+ Puppet::Util::Log.newdestination(report)
- # Convert a plain resource catalog into our full host catalog.
- def convert_catalog(result, duration)
- catalog = result.to_ral
- catalog.finalize
- catalog.retrieval_duration = duration
- catalog.write_class_file
- catalog
+ if catalog = options[:catalog]
+ options.delete(:catalog)
+ elsif ! catalog = retrieve_catalog
+ Puppet.err "Could not retrieve catalog; skipping run"
+ return
end
- # The code that actually runs the catalog.
- # This just passes any options on to the catalog,
- # which accepts :tags and :ignoreschedules.
- def run(options = {})
- begin
- prepare
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Failed to prepare catalog: #{detail}"
- end
-
- options[:report] ||= initialize_report
- report = options[:report]
- Puppet::Util::Log.newdestination(report)
-
- if catalog = options[:catalog]
- options.delete(:catalog)
- elsif ! catalog = retrieve_catalog
- Puppet.err "Could not retrieve catalog; skipping run"
- return
- end
-
- transaction = nil
-
- begin
- benchmark(:notice, "Finished catalog run") do
- transaction = catalog.apply(options)
- end
- report
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Failed to apply catalog: #{detail}"
- return
- end
- ensure
- # Now close all of our existing http connections, since there's no
- # reason to leave them lying open.
- Puppet::Network::HttpPool.clear_http_instances
- execute_postrun_command
-
- Puppet::Util::Log.close(report)
-
- send_report(report, transaction)
- end
+ transaction = nil
- def send_report(report, trans = nil)
- trans.generate_report if trans
- puts report.summary if Puppet[:summarize]
- report.save if Puppet[:report]
+ begin
+ benchmark(:notice, "Finished catalog run") do
+ transaction = catalog.apply(options)
+ end
+ report
rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not send report: #{detail}"
- end
-
- private
-
- def self.timeout
- timeout = Puppet[:configtimeout]
- case timeout
- when String
- if timeout =~ /^\d+$/
- timeout = Integer(timeout)
- else
- raise ArgumentError, "Configuration timeout must be an integer"
- end
- when Integer # nothing
- else
- raise ArgumentError, "Configuration timeout must be an integer"
- end
-
- timeout
- end
-
- def execute_from_setting(setting)
- return if (command = Puppet[setting]) == ""
-
- begin
- Puppet::Util.execute([command])
- rescue => detail
- raise CommandHookError, "Could not run command from #{setting}: #{detail}"
- end
- end
-
- def retrieve_catalog_from_cache(fact_options)
- result = nil
- @duration = thinmark do
- result = Puppet::Resource::Catalog.find(Puppet[:certname], fact_options.merge(:ignore_terminus => true))
- end
- Puppet.notice "Using cached catalog"
- result
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Failed to apply catalog: #{detail}"
+ return
+ end
+ ensure
+ # Now close all of our existing http connections, since there's no
+ # reason to leave them lying open.
+ Puppet::Network::HttpPool.clear_http_instances
+ execute_postrun_command
+
+ Puppet::Util::Log.close(report)
+
+ send_report(report, transaction)
+ end
+
+ def send_report(report, trans = nil)
+ trans.generate_report if trans
+ puts report.summary if Puppet[:summarize]
+ report.save if Puppet[:report]
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not send report: #{detail}"
+ end
+
+ private
+
+ def self.timeout
+ timeout = Puppet[:configtimeout]
+ case timeout
+ when String
+ if timeout =~ /^\d+$/
+ timeout = Integer(timeout)
+ else
+ raise ArgumentError, "Configuration timeout must be an integer"
+ end
+ when Integer # nothing
+ else
+ raise ArgumentError, "Configuration timeout must be an integer"
+ end
+
+ timeout
+ end
+
+ def execute_from_setting(setting)
+ return if (command = Puppet[setting]) == ""
+
+ begin
+ Puppet::Util.execute([command])
rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not retrieve catalog from cache: #{detail}"
- return nil
- end
-
- def retrieve_new_catalog(fact_options)
- result = nil
- @duration = thinmark do
- result = Puppet::Resource::Catalog.find(Puppet[:certname], fact_options.merge(:ignore_cache => true))
- end
- result
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not retrieve catalog from remote server: #{detail}"
- return nil
- end
+ raise CommandHookError, "Could not run command from #{setting}: #{detail}"
+ end
+ end
+
+ def retrieve_catalog_from_cache(fact_options)
+ result = nil
+ @duration = thinmark do
+ result = Puppet::Resource::Catalog.find(Puppet[:certname], fact_options.merge(:ignore_terminus => true))
+ end
+ Puppet.notice "Using cached catalog"
+ result
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not retrieve catalog from cache: #{detail}"
+ return nil
+ end
+
+ def retrieve_new_catalog(fact_options)
+ result = nil
+ @duration = thinmark do
+ result = Puppet::Resource::Catalog.find(Puppet[:certname], fact_options.merge(:ignore_cache => true))
+ end
+ result
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not retrieve catalog from remote server: #{detail}"
+ return nil
+ end
end
diff --git a/lib/puppet/configurer/downloader.rb b/lib/puppet/configurer/downloader.rb
index 8f8dda58c..1b587ed4b 100644
--- a/lib/puppet/configurer/downloader.rb
+++ b/lib/puppet/configurer/downloader.rb
@@ -2,78 +2,78 @@ require 'puppet/configurer'
require 'puppet/resource/catalog'
class Puppet::Configurer::Downloader
- attr_reader :name, :path, :source, :ignore
+ attr_reader :name, :path, :source, :ignore
- # Determine the timeout value to use.
- def self.timeout
- timeout = Puppet[:configtimeout]
- case timeout
- when String
- if timeout =~ /^\d+$/
- timeout = Integer(timeout)
- else
- raise ArgumentError, "Configuration timeout must be an integer"
- end
- when Integer # nothing
- else
- raise ArgumentError, "Configuration timeout must be an integer"
- end
-
- timeout
+ # Determine the timeout value to use.
+ def self.timeout
+ timeout = Puppet[:configtimeout]
+ case timeout
+ when String
+ if timeout =~ /^\d+$/
+ timeout = Integer(timeout)
+ else
+ raise ArgumentError, "Configuration timeout must be an integer"
+ end
+ when Integer # nothing
+ else
+ raise ArgumentError, "Configuration timeout must be an integer"
end
- # Evaluate our download, returning the list of changed values.
- def evaluate
- Puppet.info "Retrieving #{name}"
+ timeout
+ end
- files = []
- begin
- Timeout.timeout(self.class.timeout) do
- catalog.apply do |trans|
- trans.changed?.find_all do |resource|
- yield resource if block_given?
- files << resource[:path]
- end
- end
- end
- rescue Puppet::Error, Timeout::Error => detail
- puts detail.backtrace if Puppet[:debug]
- Puppet.err "Could not retrieve #{name}: #{detail}"
- end
+ # Evaluate our download, returning the list of changed values.
+ def evaluate
+ Puppet.info "Retrieving #{name}"
- files
+ files = []
+ begin
+ Timeout.timeout(self.class.timeout) do
+ catalog.apply do |trans|
+ trans.changed?.find_all do |resource|
+ yield resource if block_given?
+ files << resource[:path]
+ end
+ end
+ end
+ rescue Puppet::Error, Timeout::Error => detail
+ puts detail.backtrace if Puppet[:debug]
+ Puppet.err "Could not retrieve #{name}: #{detail}"
end
- def initialize(name, path, source, ignore = nil)
- @name, @path, @source, @ignore = name, path, source, ignore
- end
+ files
+ end
- def catalog
- catalog = Puppet::Resource::Catalog.new
- catalog.add_resource(file)
- catalog
- end
+ def initialize(name, path, source, ignore = nil)
+ @name, @path, @source, @ignore = name, path, source, ignore
+ end
- def file
- args = default_arguments.merge(:path => path, :source => source)
- args[:ignore] = ignore.split if ignore
- Puppet::Type.type(:file).new(args)
- end
+ def catalog
+ catalog = Puppet::Resource::Catalog.new
+ catalog.add_resource(file)
+ catalog
+ end
- private
+ def file
+ args = default_arguments.merge(:path => path, :source => source)
+ args[:ignore] = ignore.split if ignore
+ Puppet::Type.type(:file).new(args)
+ end
- def default_arguments
- {
- :path => path,
- :recurse => true,
- :source => source,
- :tag => name,
- :owner => Process.uid,
- :group => Process.gid,
- :purge => true,
- :force => true,
- :backup => false,
- :noop => false
- }
- end
+ private
+
+ def default_arguments
+ {
+ :path => path,
+ :recurse => true,
+ :source => source,
+ :tag => name,
+ :owner => Process.uid,
+ :group => Process.gid,
+ :purge => true,
+ :force => true,
+ :backup => false,
+ :noop => false
+ }
+ end
end
diff --git a/lib/puppet/configurer/fact_handler.rb b/lib/puppet/configurer/fact_handler.rb
index 2d1565ae7..075a59458 100644
--- a/lib/puppet/configurer/fact_handler.rb
+++ b/lib/puppet/configurer/fact_handler.rb
@@ -6,67 +6,67 @@ require 'puppet/configurer/downloader'
# just included into the agent, but having it here makes it
# easier to test.
module Puppet::Configurer::FactHandler
- def download_fact_plugins?
- Puppet[:factsync]
- end
+ def download_fact_plugins?
+ Puppet[:factsync]
+ end
- def find_facts
- # This works because puppet agent configures Facts to use 'facter' for
- # finding facts and the 'rest' terminus for caching them. Thus, we'll
- # compile them and then "cache" them on the server.
- begin
- reload_facter
- Puppet::Node::Facts.find(Puppet[:certname])
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not retrieve local facts: #{detail}"
- end
+ def find_facts
+ # This works because puppet agent configures Facts to use 'facter' for
+ # finding facts and the 'rest' terminus for caching them. Thus, we'll
+ # compile them and then "cache" them on the server.
+ begin
+ reload_facter
+ Puppet::Node::Facts.find(Puppet[:certname])
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Could not retrieve local facts: #{detail}"
end
+ end
- def facts_for_uploading
- facts = find_facts
- #format = facts.class.default_format
-
- if facts.support_format?(:b64_zlib_yaml)
- format = :b64_zlib_yaml
- else
- format = :yaml
- end
-
- text = facts.render(format)
+ def facts_for_uploading
+ facts = find_facts
+ #format = facts.class.default_format
- {:facts_format => format, :facts => CGI.escape(text)}
+ if facts.support_format?(:b64_zlib_yaml)
+ format = :b64_zlib_yaml
+ else
+ format = :yaml
end
- # Retrieve facts from the central server.
- def download_fact_plugins
- return unless download_fact_plugins?
+ text = facts.render(format)
- # Deprecated prior to 0.25, as of 5/19/2008
- Puppet.warning "Fact syncing is deprecated as of 0.25 -- use 'pluginsync' instead"
+ {:facts_format => format, :facts => CGI.escape(text)}
+ end
- Puppet::Configurer::Downloader.new("fact", Puppet[:factdest], Puppet[:factsource], Puppet[:factsignore]).evaluate
- end
+ # Retrieve facts from the central server.
+ def download_fact_plugins
+ return unless download_fact_plugins?
+
+ # Deprecated prior to 0.25, as of 5/19/2008
+ Puppet.warning "Fact syncing is deprecated as of 0.25 -- use 'pluginsync' instead"
- # Clear out all of the loaded facts and reload them from disk.
- # NOTE: This is clumsy and shouldn't be required for later (1.5.x) versions
- # of Facter.
- def reload_facter
- Facter.clear
+ Puppet::Configurer::Downloader.new("fact", Puppet[:factdest], Puppet[:factsource], Puppet[:factsignore]).evaluate
+ end
- # Reload everything.
- if Facter.respond_to? :loadfacts
- Facter.loadfacts
- elsif Facter.respond_to? :load
- Facter.load
- else
- Puppet.warning "You should upgrade your version of Facter to at least 1.3.8"
- end
+ # Clear out all of the loaded facts and reload them from disk.
+ # NOTE: This is clumsy and shouldn't be required for later (1.5.x) versions
+ # of Facter.
+ def reload_facter
+ Facter.clear
- # This loads all existing facts and any new ones. We have to remove and
- # reload because there's no way to unload specific facts.
- Puppet::Node::Facts::Facter.load_fact_plugins
+ # Reload everything.
+ if Facter.respond_to? :loadfacts
+ Facter.loadfacts
+ elsif Facter.respond_to? :load
+ Facter.load
+ else
+ Puppet.warning "You should upgrade your version of Facter to at least 1.3.8"
end
+
+ # This loads all existing facts and any new ones. We have to remove and
+ # reload because there's no way to unload specific facts.
+ Puppet::Node::Facts::Facter.load_fact_plugins
+ end
end
diff --git a/lib/puppet/configurer/plugin_handler.rb b/lib/puppet/configurer/plugin_handler.rb
index 98c8de367..539441e75 100644
--- a/lib/puppet/configurer/plugin_handler.rb
+++ b/lib/puppet/configurer/plugin_handler.rb
@@ -2,27 +2,27 @@
# just included into the agent, but having it here makes it
# easier to test.
module Puppet::Configurer::PluginHandler
- def download_plugins?
- Puppet[:pluginsync]
- end
+ def download_plugins?
+ Puppet[:pluginsync]
+ end
- # Retrieve facts from the central server.
- def download_plugins
- return nil unless download_plugins?
- Puppet::Configurer::Downloader.new("plugin", Puppet[:plugindest], Puppet[:pluginsource], Puppet[:pluginsignore]).evaluate.each { |file| load_plugin(file) }
- end
+ # Retrieve facts from the central server.
+ def download_plugins
+ return nil unless download_plugins?
+ Puppet::Configurer::Downloader.new("plugin", Puppet[:plugindest], Puppet[:pluginsource], Puppet[:pluginsignore]).evaluate.each { |file| load_plugin(file) }
+ end
- def load_plugin(file)
- return unless FileTest.exist?(file)
- return if FileTest.directory?(file)
+ def load_plugin(file)
+ return unless FileTest.exist?(file)
+ return if FileTest.directory?(file)
- begin
- Puppet.info "Loading downloaded plugin #{file}"
- load file
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- Puppet.err "Could not load downloaded file #{file}: #{detail}"
- end
+ begin
+ Puppet.info "Loading downloaded plugin #{file}"
+ load file
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ Puppet.err "Could not load downloaded file #{file}: #{detail}"
end
+ end
end
diff --git a/lib/puppet/daemon.rb b/lib/puppet/daemon.rb
index b0c2b56ea..aa4a12bfa 100755
--- a/lib/puppet/daemon.rb
+++ b/lib/puppet/daemon.rb
@@ -6,125 +6,125 @@ require 'puppet/application'
# A module that handles operations common to all daemons. This is included
# into the Server and Client base classes.
class Puppet::Daemon
- attr_accessor :agent, :server, :argv
+ attr_accessor :agent, :server, :argv
- def daemonname
- Puppet[:name]
- end
+ def daemonname
+ Puppet[:name]
+ end
- # Put the daemon into the background.
- def daemonize
- if pid = fork
- Process.detach(pid)
- exit(0)
- end
-
- create_pidfile
-
- # Get rid of console logging
- Puppet::Util::Log.close(:console)
-
- Process.setsid
- Dir.chdir("/")
- begin
- $stdin.reopen "/dev/null"
- $stdout.reopen "/dev/null", "a"
- $stderr.reopen $stdout
- Puppet::Util::Log.reopen
- rescue => detail
- Puppet.err "Could not start #{Puppet[:name]}: #{detail}"
- Puppet::Util::secure_open("/tmp/daemonout", "w") { |f|
- f.puts "Could not start #{Puppet[:name]}: #{detail}"
- }
- exit(12)
- end
+ # Put the daemon into the background.
+ def daemonize
+ if pid = fork
+ Process.detach(pid)
+ exit(0)
end
- # Create a pidfile for our daemon, so we can be stopped and others
- # don't try to start.
- def create_pidfile
- Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
- raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock
- end
+ create_pidfile
+
+ # Get rid of console logging
+ Puppet::Util::Log.close(:console)
+
+ Process.setsid
+ Dir.chdir("/")
+ begin
+ $stdin.reopen "/dev/null"
+ $stdout.reopen "/dev/null", "a"
+ $stderr.reopen $stdout
+ Puppet::Util::Log.reopen
+ rescue => detail
+ Puppet.err "Could not start #{Puppet[:name]}: #{detail}"
+ Puppet::Util::secure_open("/tmp/daemonout", "w") { |f|
+ f.puts "Could not start #{Puppet[:name]}: #{detail}"
+ }
+ exit(12)
end
+ end
- # Provide the path to our pidfile.
- def pidfile
- Puppet[:pidfile]
+ # Create a pidfile for our daemon, so we can be stopped and others
+ # don't try to start.
+ def create_pidfile
+ Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
+ raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock
end
-
- def reexec
- raise Puppet::DevError, "Cannot reexec unless ARGV arguments are set" unless argv
- command = $0 + " " + argv.join(" ")
- Puppet.notice "Restarting with '#{command}'"
- stop(:exit => false)
- exec(command)
+ end
+
+ # Provide the path to our pidfile.
+ def pidfile
+ Puppet[:pidfile]
+ end
+
+ def reexec
+ raise Puppet::DevError, "Cannot reexec unless ARGV arguments are set" unless argv
+ command = $0 + " " + argv.join(" ")
+ Puppet.notice "Restarting with '#{command}'"
+ stop(:exit => false)
+ exec(command)
+ end
+
+ def reload
+ return unless agent
+ if agent.running?
+ Puppet.notice "Not triggering already-running agent"
+ return
end
- def reload
- return unless agent
- if agent.running?
- Puppet.notice "Not triggering already-running agent"
- return
- end
+ agent.run
+ end
- agent.run
+ # Remove the pid file for our daemon.
+ def remove_pidfile
+ Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
+ locker = Puppet::Util::Pidlock.new(pidfile)
+ locker.unlock or Puppet.err "Could not remove PID file #{pidfile}" if locker.locked?
end
-
- # Remove the pid file for our daemon.
- def remove_pidfile
- Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
- locker = Puppet::Util::Pidlock.new(pidfile)
- locker.unlock or Puppet.err "Could not remove PID file #{pidfile}" if locker.locked?
- end
+ end
+
+ def restart
+ Puppet::Application.restart!
+ reexec unless agent and agent.running?
+ end
+
+ def reopen_logs
+ Puppet::Util::Log.reopen
+ end
+
+ # Trap a couple of the main signals. This should probably be handled
+ # in a way that anyone else can register callbacks for traps, but, eh.
+ def set_signal_traps
+ signals = {:INT => :stop, :TERM => :stop }
+ # extended signals not supported under windows
+ signals.update({:HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs }) unless Puppet.features.microsoft_windows?
+ signals.each do |signal, method|
+ trap(signal) do
+ Puppet.notice "Caught #{signal}; calling #{method}"
+ send(method)
+ end
end
+ end
- def restart
- Puppet::Application.restart!
- reexec unless agent and agent.running?
- end
+ # Stop everything
+ def stop(args = {:exit => true})
+ Puppet::Application.stop!
- def reopen_logs
- Puppet::Util::Log.reopen
- end
+ server.stop if server
- # Trap a couple of the main signals. This should probably be handled
- # in a way that anyone else can register callbacks for traps, but, eh.
- def set_signal_traps
- signals = {:INT => :stop, :TERM => :stop }
- # extended signals not supported under windows
- signals.update({:HUP => :restart, :USR1 => :reload, :USR2 => :reopen_logs }) unless Puppet.features.microsoft_windows?
- signals.each do |signal, method|
- trap(signal) do
- Puppet.notice "Caught #{signal}; calling #{method}"
- send(method)
- end
- end
- end
+ remove_pidfile
- # Stop everything
- def stop(args = {:exit => true})
- Puppet::Application.stop!
+ Puppet::Util::Log.close_all
- server.stop if server
+ exit if args[:exit]
+ end
- remove_pidfile
+ def start
+ set_signal_traps
- Puppet::Util::Log.close_all
+ create_pidfile
- exit if args[:exit]
- end
-
- def start
- set_signal_traps
-
- create_pidfile
+ raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server
+ agent.start if agent
+ server.start if server
- raise Puppet::DevError, "Daemons must have an agent, server, or both" unless agent or server
- agent.start if agent
- server.start if server
-
- EventLoop.current.run
- end
+ EventLoop.current.run
+ end
end
diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb
index 18d045693..0af40f2cb 100644
--- a/lib/puppet/defaults.rb
+++ b/lib/puppet/defaults.rb
@@ -1,795 +1,795 @@
# The majority of the system configuration parameters are set in this file.
module Puppet
- setdefaults(:main,
- :confdir => [Puppet.run_mode.conf_dir, "The main Puppet configuration directory. The default for this parameter is calculated based on the user. If the process
- is running as root or the user that ``puppet master`` is supposed to run as, it defaults to a system directory, but if it's running as any other user,
- it defaults to being in ``~``."],
- :vardir => [Puppet.run_mode.var_dir, "Where Puppet stores dynamic and growing data. The default for this parameter is calculated specially, like `confdir`_."],
- :name => [Puppet.application_name.to_s, "The name of the application, if we are running as one. The
- default is essentially $0 without the path or ``.rb``."],
- :mode => [Puppet.run_mode.name.to_s, "The effective 'run mode' of the application: master, agent, or user."]
- )
-
- setdefaults(:main, :logdir => Puppet.run_mode.logopts)
-
- setdefaults(:main,
- :trace => [false, "Whether to print stack traces on some errors"],
- :autoflush => [false, "Whether log files should always flush to disk."],
- :syslogfacility => ["daemon", "What syslog facility to use when logging to
- syslog. Syslog has a fixed list of valid facilities, and you must
- choose one of those; you cannot just make one up."],
- :statedir => { :default => "$vardir/state",
- :mode => 01755,
- :desc => "The directory where Puppet state is stored. Generally,
- this directory can be removed without causing harm (although it
- might result in spurious service restarts)."
- },
- :rundir => {
- :default => Puppet.run_mode.run_dir,
- :mode => 01777,
- :desc => "Where Puppet PID files are kept."
- },
- :genconfig => [false,
- "Whether to just print a configuration to stdout and exit. Only makes
- sense when used interactively. Takes into account arguments specified
- on the CLI."],
- :genmanifest => [false,
- "Whether to just print a manifest to stdout and exit. Only makes
- sense when used interactively. Takes into account arguments specified
- on the CLI."],
- :configprint => ["",
- "Print the value of a specific configuration parameter. If a
- parameter is provided for this, then the value is printed and puppet
- exits. Comma-separate multiple values. For a list of all values,
- specify 'all'. This feature is only available in Puppet versions
- higher than 0.18.4."],
- :color => ["ansi", "Whether to use colors when logging to the console.
- Valid values are ``ansi`` (equivalent to ``true``), ``html`` (mostly
- used during testing with TextMate), and ``false``, which produces
- no color."],
- :mkusers => [false,
- "Whether to create the necessary user and group that puppet agent will
- run as."],
- :manage_internal_file_permissions => [true,
- "Whether Puppet should manage the owner, group, and mode of files
- it uses internally"
- ],
- :onetime => [false,
- "Run the configuration once, rather than as a long-running
- daemon. This is useful for interactively running puppetd."
- ],
- :path => {:default => "none",
- :desc => "The shell search path. Defaults to whatever is inherited
- from the parent process.",
- :call_on_define => true, # Call our hook with the default value, so we always get the libdir set.
- :hook => proc do |value|
- ENV["PATH"] = "" if ENV["PATH"].nil?
- ENV["PATH"] = value unless value == "none"
- paths = ENV["PATH"].split(File::PATH_SEPARATOR)
- %w{/usr/sbin /sbin}.each do |path|
- ENV["PATH"] += File::PATH_SEPARATOR + path unless paths.include?(path)
- end
- value
- end
- },
- :libdir => {:default => "$vardir/lib",
- :desc => "An extra search path for Puppet. This is only useful
- for those files that Puppet will load on demand, and is only
- guaranteed to work for those cases. In fact, the autoload
- mechanism is responsible for making sure this directory
- is in Ruby's search path",
- :call_on_define => true, # Call our hook with the default value, so we always get the libdir set.
- :hook => proc do |value|
- $LOAD_PATH.delete(@oldlibdir) if defined?(@oldlibdir) and $LOAD_PATH.include?(@oldlibdir)
- @oldlibdir = value
- $LOAD_PATH << value
- end
- },
- :ignoreimport => [false, "A parameter that can be used in commit
- hooks, since it enables you to parse-check a single file rather
- than requiring that all files exist."],
- :authconfig => [ "$confdir/namespaceauth.conf",
- "The configuration file that defines the rights to the different
- namespaces and methods. This can be used as a coarse-grained
- authorization system for both ``puppet agent`` and ``puppet master``."
- ],
- :environment => {:default => "production", :desc => "The environment Puppet is running in. For clients
- (e.g., ``puppet agent``) this determines the environment itself, which
- is used to find modules and much more. For servers (i.e., ``puppet master``) this provides the default environment for nodes
- we know nothing about."
- },
- :diff_args => ["-u", "Which arguments to pass to the diff command when printing differences between files."],
- :diff => ["diff", "Which diff command to use when printing differences between files."],
- :show_diff => [false, "Whether to print a contextual diff when files are being replaced. The diff
- is printed on stdout, so this option is meaningless unless you are running Puppet interactively.
- This feature currently requires the ``diff/lcs`` Ruby library."],
- :daemonize => { :default => true,
- :desc => "Send the process into the background. This is the default.",
- :short => "D"
- },
- :maximum_uid => [4294967290, "The maximum allowed UID. Some platforms use negative UIDs
- but then ship with tools that do not know how to handle signed ints, so the UIDs show up as
- huge numbers that can then not be fed back into the system. This is a hackish way to fail in a
- slightly more useful way when that happens."],
- :node_terminus => ["plain", "Where to find information about nodes."],
- :catalog_terminus => ["compiler", "Where to get node catalogs. This is useful to change if, for instance,
- you'd like to pre-compile catalogs and store them in memcached or some other easily-accessed store."],
- :facts_terminus => ["facter", "Where to get node facts."],
- :httplog => { :default => "$logdir/http.log",
- :owner => "root",
- :mode => 0640,
- :desc => "Where the puppet agent web server logs."
- },
- :http_proxy_host => ["none",
- "The HTTP proxy host to use for outgoing connections. Note: You
- may need to use a FQDN for the server hostname when using a proxy."],
- :http_proxy_port => [3128, "The HTTP proxy port to use for outgoing connections"],
- :filetimeout => [ 15,
- "The minimum time to wait (in seconds) between checking for updates in
- configuration files. This timeout determines how quickly Puppet checks whether
- a file (such as manifests or templates) has changed on disk."
- ],
- :queue_type => ["stomp", "Which type of queue to use for asynchronous processing."],
- :queue_type => ["stomp", "Which type of queue to use for asynchronous processing."],
- :queue_source => ["stomp://localhost:61613/", "Which type of queue to use for asynchronous processing. If your stomp server requires
- authentication, you can include it in the URI as long as your stomp client library is at least 1.1.1"],
- :async_storeconfigs => {:default => false, :desc => "Whether to use a queueing system to provide asynchronous database integration.
- Requires that ``puppetqd`` be running and that 'PSON' support for ruby be installed.",
- :hook => proc do |value|
- if value
- # This reconfigures the terminii for Node, Facts, and Catalog
- Puppet.settings[:storeconfigs] = true
-
- # But then we modify the configuration
- Puppet::Resource::Catalog.cache_class = :queue
- else
- raise "Cannot disable asynchronous storeconfigs in a running process"
- end
- end
- },
- :thin_storeconfigs => {:default => false, :desc =>
- "Boolean; wether storeconfigs store in the database only the facts and exported resources.
- If true, then storeconfigs performance will be higher and still allow exported/collected
- resources, but other usage external to Puppet might not work",
- :hook => proc do |value|
- Puppet.settings[:storeconfigs] = true if value
- end
- },
- :config_version => ["", "How to determine the configuration version. By default, it will be the
- time that the configuration is parsed, but you can provide a shell script to override how the
- version is determined. The output of this script will be added to every log message in the
- reports, allowing you to correlate changes on your hosts to the source version on the server."],
- :zlib => [true,
- "Boolean; whether to use the zlib library",
- ],
- :prerun_command => ["", "A command to run before every agent run. If this command returns a non-zero
- return code, the entire Puppet run will fail."],
- :postrun_command => ["", "A command to run after every agent run. If this command returns a non-zero
- return code, the entire Puppet run will be considered to have failed, even though it might have
- performed work during the normal run."],
- :freeze_main => [false, "Freezes the 'main' class, disallowing any code to be added to it. This
- essentially means that you can't have any code outside of a node, class, or definition other
- than in the site manifest."]
- )
-
- hostname = Facter["hostname"].value
- domain = Facter["domain"].value
- if domain and domain != ""
- fqdn = [hostname, domain].join(".")
- else
- fqdn = hostname
- end
-
-
- Puppet.setdefaults(
- :main,
-
- # We have to downcase the fqdn, because the current ssl stuff (as oppsed to in master) doesn't have good facilities for
- # manipulating naming.
- :certname => {:default => fqdn.downcase, :desc => "The name to use when handling certificates. Defaults
- to the fully qualified domain name.",
- :call_on_define => true, # Call our hook with the default value, so we're always downcased
- :hook => proc { |value| raise(ArgumentError, "Certificate names must be lower case; see #1168") unless value == value.downcase }},
- :certdnsnames => ['', "The DNS names on the Server certificate as a colon-separated list.
- If it's anything other than an empty string, it will be used as an alias in the created
- certificate. By default, only the server gets an alias set up, and only for 'puppet'."],
- :certdir => {
- :default => "$ssldir/certs",
- :owner => "service",
- :desc => "The certificate directory."
- },
- :ssldir => {
- :default => "$confdir/ssl",
- :mode => 0771,
- :owner => "service",
- :desc => "Where SSL certificates are kept."
- },
- :publickeydir => {
- :default => "$ssldir/public_keys",
- :owner => "service",
- :desc => "The public key directory."
- },
- :requestdir => {
- :default => "$ssldir/certificate_requests",
- :owner => "service",
- :desc => "Where host certificate requests are stored."
- },
- :privatekeydir => { :default => "$ssldir/private_keys",
- :mode => 0750,
- :owner => "service",
- :desc => "The private key directory."
- },
- :privatedir => { :default => "$ssldir/private",
- :mode => 0750,
- :owner => "service",
- :desc => "Where the client stores private certificate information."
- },
- :passfile => { :default => "$privatedir/password",
- :mode => 0640,
- :owner => "service",
- :desc => "Where puppet agent stores the password for its private key.
- Generally unused."
- },
- :hostcsr => { :default => "$ssldir/csr_$certname.pem",
- :mode => 0644,
- :owner => "service",
- :desc => "Where individual hosts store and look for their certificate requests."
- },
- :hostcert => { :default => "$certdir/$certname.pem",
- :mode => 0644,
- :owner => "service",
- :desc => "Where individual hosts store and look for their certificates."
- },
- :hostprivkey => { :default => "$privatekeydir/$certname.pem",
- :mode => 0600,
- :owner => "service",
- :desc => "Where individual hosts store and look for their private key."
- },
- :hostpubkey => { :default => "$publickeydir/$certname.pem",
- :mode => 0644,
- :owner => "service",
- :desc => "Where individual hosts store and look for their public key."
- },
- :localcacert => { :default => "$certdir/ca.pem",
- :mode => 0644,
- :owner => "service",
- :desc => "Where each client stores the CA certificate."
- },
- :hostcrl => { :default => "$ssldir/crl.pem",
- :mode => 0644,
- :owner => "service",
- :desc => "Where the host's certificate revocation list can be found.
- This is distinct from the certificate authority's CRL."
- },
- :certificate_revocation => [true, "Whether certificate revocation should be supported by downloading a Certificate Revocation List (CRL)
- to all clients. If enabled, CA chaining will almost definitely not work."]
- )
+ setdefaults(:main,
+ :confdir => [Puppet.run_mode.conf_dir, "The main Puppet configuration directory. The default for this parameter is calculated based on the user. If the process
+ is running as root or the user that ``puppet master`` is supposed to run as, it defaults to a system directory, but if it's running as any other user,
+ it defaults to being in ``~``."],
+ :vardir => [Puppet.run_mode.var_dir, "Where Puppet stores dynamic and growing data. The default for this parameter is calculated specially, like `confdir`_."],
+ :name => [Puppet.application_name.to_s, "The name of the application, if we are running as one. The
+ default is essentially $0 without the path or ``.rb``."],
+ :mode => [Puppet.run_mode.name.to_s, "The effective 'run mode' of the application: master, agent, or user."]
+ )
+
+ setdefaults(:main, :logdir => Puppet.run_mode.logopts)
+
+ setdefaults(:main,
+ :trace => [false, "Whether to print stack traces on some errors"],
+ :autoflush => [false, "Whether log files should always flush to disk."],
+ :syslogfacility => ["daemon", "What syslog facility to use when logging to
+ syslog. Syslog has a fixed list of valid facilities, and you must
+ choose one of those; you cannot just make one up."],
+ :statedir => { :default => "$vardir/state",
+ :mode => 01755,
+ :desc => "The directory where Puppet state is stored. Generally,
+ this directory can be removed without causing harm (although it
+ might result in spurious service restarts)."
+ },
+ :rundir => {
+ :default => Puppet.run_mode.run_dir,
+ :mode => 01777,
+ :desc => "Where Puppet PID files are kept."
+ },
+ :genconfig => [false,
+ "Whether to just print a configuration to stdout and exit. Only makes
+ sense when used interactively. Takes into account arguments specified
+ on the CLI."],
+ :genmanifest => [false,
+ "Whether to just print a manifest to stdout and exit. Only makes
+ sense when used interactively. Takes into account arguments specified
+ on the CLI."],
+ :configprint => ["",
+ "Print the value of a specific configuration parameter. If a
+ parameter is provided for this, then the value is printed and puppet
+ exits. Comma-separate multiple values. For a list of all values,
+ specify 'all'. This feature is only available in Puppet versions
+ higher than 0.18.4."],
+ :color => ["ansi", "Whether to use colors when logging to the console.
+ Valid values are ``ansi`` (equivalent to ``true``), ``html`` (mostly
+ used during testing with TextMate), and ``false``, which produces
+ no color."],
+ :mkusers => [false,
+ "Whether to create the necessary user and group that puppet agent will
+ run as."],
+ :manage_internal_file_permissions => [true,
+ "Whether Puppet should manage the owner, group, and mode of files
+ it uses internally"
+ ],
+ :onetime => [false,
+ "Run the configuration once, rather than as a long-running
+ daemon. This is useful for interactively running puppetd."
+ ],
+ :path => {:default => "none",
+ :desc => "The shell search path. Defaults to whatever is inherited
+ from the parent process.",
+ :call_on_define => true, # Call our hook with the default value, so we always get the libdir set.
+ :hook => proc do |value|
+ ENV["PATH"] = "" if ENV["PATH"].nil?
+ ENV["PATH"] = value unless value == "none"
+ paths = ENV["PATH"].split(File::PATH_SEPARATOR)
+ %w{/usr/sbin /sbin}.each do |path|
+ ENV["PATH"] += File::PATH_SEPARATOR + path unless paths.include?(path)
+ end
+ value
+ end
+ },
+ :libdir => {:default => "$vardir/lib",
+ :desc => "An extra search path for Puppet. This is only useful
+ for those files that Puppet will load on demand, and is only
+ guaranteed to work for those cases. In fact, the autoload
+ mechanism is responsible for making sure this directory
+ is in Ruby's search path",
+ :call_on_define => true, # Call our hook with the default value, so we always get the libdir set.
+ :hook => proc do |value|
+ $LOAD_PATH.delete(@oldlibdir) if defined?(@oldlibdir) and $LOAD_PATH.include?(@oldlibdir)
+ @oldlibdir = value
+ $LOAD_PATH << value
+ end
+ },
+ :ignoreimport => [false, "A parameter that can be used in commit
+ hooks, since it enables you to parse-check a single file rather
+ than requiring that all files exist."],
+ :authconfig => [ "$confdir/namespaceauth.conf",
+ "The configuration file that defines the rights to the different
+ namespaces and methods. This can be used as a coarse-grained
+ authorization system for both ``puppet agent`` and ``puppet master``."
+ ],
+ :environment => {:default => "production", :desc => "The environment Puppet is running in. For clients
+ (e.g., ``puppet agent``) this determines the environment itself, which
+ is used to find modules and much more. For servers (i.e., ``puppet master``) this provides the default environment for nodes
+ we know nothing about."
+ },
+ :diff_args => ["-u", "Which arguments to pass to the diff command when printing differences between files."],
+ :diff => ["diff", "Which diff command to use when printing differences between files."],
+ :show_diff => [false, "Whether to print a contextual diff when files are being replaced. The diff
+ is printed on stdout, so this option is meaningless unless you are running Puppet interactively.
+ This feature currently requires the ``diff/lcs`` Ruby library."],
+ :daemonize => { :default => true,
+ :desc => "Send the process into the background. This is the default.",
+ :short => "D"
+ },
+ :maximum_uid => [4294967290, "The maximum allowed UID. Some platforms use negative UIDs
+ but then ship with tools that do not know how to handle signed ints, so the UIDs show up as
+ huge numbers that can then not be fed back into the system. This is a hackish way to fail in a
+ slightly more useful way when that happens."],
+ :node_terminus => ["plain", "Where to find information about nodes."],
+ :catalog_terminus => ["compiler", "Where to get node catalogs. This is useful to change if, for instance,
+ you'd like to pre-compile catalogs and store them in memcached or some other easily-accessed store."],
+ :facts_terminus => ["facter", "Where to get node facts."],
+ :httplog => { :default => "$logdir/http.log",
+ :owner => "root",
+ :mode => 0640,
+ :desc => "Where the puppet agent web server logs."
+ },
+ :http_proxy_host => ["none",
+ "The HTTP proxy host to use for outgoing connections. Note: You
+ may need to use a FQDN for the server hostname when using a proxy."],
+ :http_proxy_port => [3128, "The HTTP proxy port to use for outgoing connections"],
+ :filetimeout => [ 15,
+ "The minimum time to wait (in seconds) between checking for updates in
+ configuration files. This timeout determines how quickly Puppet checks whether
+ a file (such as manifests or templates) has changed on disk."
+ ],
+ :queue_type => ["stomp", "Which type of queue to use for asynchronous processing."],
+ :queue_type => ["stomp", "Which type of queue to use for asynchronous processing."],
+ :queue_source => ["stomp://localhost:61613/", "Which type of queue to use for asynchronous processing. If your stomp server requires
+ authentication, you can include it in the URI as long as your stomp client library is at least 1.1.1"],
+ :async_storeconfigs => {:default => false, :desc => "Whether to use a queueing system to provide asynchronous database integration.
+ Requires that ``puppetqd`` be running and that 'PSON' support for ruby be installed.",
+ :hook => proc do |value|
+ if value
+ # This reconfigures the terminii for Node, Facts, and Catalog
+ Puppet.settings[:storeconfigs] = true
+
+ # But then we modify the configuration
+ Puppet::Resource::Catalog.cache_class = :queue
+ else
+ raise "Cannot disable asynchronous storeconfigs in a running process"
+ end
+ end
+ },
+ :thin_storeconfigs => {:default => false, :desc =>
+ "Boolean; wether storeconfigs store in the database only the facts and exported resources.
+ If true, then storeconfigs performance will be higher and still allow exported/collected
+ resources, but other usage external to Puppet might not work",
+ :hook => proc do |value|
+ Puppet.settings[:storeconfigs] = true if value
+ end
+ },
+ :config_version => ["", "How to determine the configuration version. By default, it will be the
+ time that the configuration is parsed, but you can provide a shell script to override how the
+ version is determined. The output of this script will be added to every log message in the
+ reports, allowing you to correlate changes on your hosts to the source version on the server."],
+ :zlib => [true,
+ "Boolean; whether to use the zlib library",
+ ],
+ :prerun_command => ["", "A command to run before every agent run. If this command returns a non-zero
+ return code, the entire Puppet run will fail."],
+ :postrun_command => ["", "A command to run after every agent run. If this command returns a non-zero
+ return code, the entire Puppet run will be considered to have failed, even though it might have
+ performed work during the normal run."],
+ :freeze_main => [false, "Freezes the 'main' class, disallowing any code to be added to it. This
+ essentially means that you can't have any code outside of a node, class, or definition other
+ than in the site manifest."]
+ )
+
+ hostname = Facter["hostname"].value
+ domain = Facter["domain"].value
+ if domain and domain != ""
+ fqdn = [hostname, domain].join(".")
+ else
+ fqdn = hostname
+ end
+
+
+ Puppet.setdefaults(
+ :main,
+
+ # We have to downcase the fqdn, because the current ssl stuff (as oppsed to in master) doesn't have good facilities for
+ # manipulating naming.
+ :certname => {:default => fqdn.downcase, :desc => "The name to use when handling certificates. Defaults
+ to the fully qualified domain name.",
+ :call_on_define => true, # Call our hook with the default value, so we're always downcased
+ :hook => proc { |value| raise(ArgumentError, "Certificate names must be lower case; see #1168") unless value == value.downcase }},
+ :certdnsnames => ['', "The DNS names on the Server certificate as a colon-separated list.
+ If it's anything other than an empty string, it will be used as an alias in the created
+ certificate. By default, only the server gets an alias set up, and only for 'puppet'."],
+ :certdir => {
+ :default => "$ssldir/certs",
+ :owner => "service",
+ :desc => "The certificate directory."
+ },
+ :ssldir => {
+ :default => "$confdir/ssl",
+ :mode => 0771,
+ :owner => "service",
+ :desc => "Where SSL certificates are kept."
+ },
+ :publickeydir => {
+ :default => "$ssldir/public_keys",
+ :owner => "service",
+ :desc => "The public key directory."
+ },
+ :requestdir => {
+ :default => "$ssldir/certificate_requests",
+ :owner => "service",
+ :desc => "Where host certificate requests are stored."
+ },
+ :privatekeydir => { :default => "$ssldir/private_keys",
+ :mode => 0750,
+ :owner => "service",
+ :desc => "The private key directory."
+ },
+ :privatedir => { :default => "$ssldir/private",
+ :mode => 0750,
+ :owner => "service",
+ :desc => "Where the client stores private certificate information."
+ },
+ :passfile => { :default => "$privatedir/password",
+ :mode => 0640,
+ :owner => "service",
+ :desc => "Where puppet agent stores the password for its private key.
+ Generally unused."
+ },
+ :hostcsr => { :default => "$ssldir/csr_$certname.pem",
+ :mode => 0644,
+ :owner => "service",
+ :desc => "Where individual hosts store and look for their certificate requests."
+ },
+ :hostcert => { :default => "$certdir/$certname.pem",
+ :mode => 0644,
+ :owner => "service",
+ :desc => "Where individual hosts store and look for their certificates."
+ },
+ :hostprivkey => { :default => "$privatekeydir/$certname.pem",
+ :mode => 0600,
+ :owner => "service",
+ :desc => "Where individual hosts store and look for their private key."
+ },
+ :hostpubkey => { :default => "$publickeydir/$certname.pem",
+ :mode => 0644,
+ :owner => "service",
+ :desc => "Where individual hosts store and look for their public key."
+ },
+ :localcacert => { :default => "$certdir/ca.pem",
+ :mode => 0644,
+ :owner => "service",
+ :desc => "Where each client stores the CA certificate."
+ },
+ :hostcrl => { :default => "$ssldir/crl.pem",
+ :mode => 0644,
+ :owner => "service",
+ :desc => "Where the host's certificate revocation list can be found.
+ This is distinct from the certificate authority's CRL."
+ },
+ :certificate_revocation => [true, "Whether certificate revocation should be supported by downloading a Certificate Revocation List (CRL)
+ to all clients. If enabled, CA chaining will almost definitely not work."]
+ )
+
+
+ setdefaults(
+ :ca,
+ :ca_name => ["$certname", "The name to use the Certificate Authority certificate."],
+ :cadir => { :default => "$ssldir/ca",
+ :owner => "service",
+ :group => "service",
+ :mode => 0770,
+ :desc => "The root directory for the certificate authority."
+ },
+ :cacert => { :default => "$cadir/ca_crt.pem",
+ :owner => "service",
+ :group => "service",
+ :mode => 0660,
+ :desc => "The CA certificate."
+ },
+ :cakey => { :default => "$cadir/ca_key.pem",
+ :owner => "service",
+ :group => "service",
+ :mode => 0660,
+ :desc => "The CA private key."
+ },
+ :capub => { :default => "$cadir/ca_pub.pem",
+ :owner => "service",
+ :group => "service",
+ :desc => "The CA public key."
+ },
+ :cacrl => { :default => "$cadir/ca_crl.pem",
+ :owner => "service",
+ :group => "service",
+ :mode => 0664,
+
+ :desc => "The certificate revocation list (CRL) for the CA. Will be used if present but otherwise ignored.",
+ :hook => proc do |value|
+ if value == 'false'
+ Puppet.warning "Setting the :cacrl to 'false' is deprecated; Puppet will just ignore the crl if yours is missing"
+ end
+ end
+ },
+ :caprivatedir => { :default => "$cadir/private",
+ :owner => "service",
+ :group => "service",
+ :mode => 0770,
+ :desc => "Where the CA stores private certificate information."
+ },
+ :csrdir => { :default => "$cadir/requests",
+ :owner => "service",
+ :group => "service",
+ :desc => "Where the CA stores certificate requests"
+ },
+ :signeddir => { :default => "$cadir/signed",
+ :owner => "service",
+ :group => "service",
+ :mode => 0770,
+ :desc => "Where the CA stores signed certificates."
+ },
+ :capass => { :default => "$caprivatedir/ca.pass",
+ :owner => "service",
+ :group => "service",
+ :mode => 0660,
+ :desc => "Where the CA stores the password for the private key"
+ },
+ :serial => { :default => "$cadir/serial",
+ :owner => "service",
+ :group => "service",
+ :mode => 0644,
+ :desc => "Where the serial number for certificates is stored."
+ },
+ :autosign => { :default => "$confdir/autosign.conf",
+ :mode => 0644,
+ :desc => "Whether to enable autosign. Valid values are true (which
+ autosigns any key request, and is a very bad idea), false (which
+ never autosigns any key request), and the path to a file, which
+ uses that configuration file to determine which keys to sign."},
+ :ca_days => ["", "How long a certificate should be valid.
+ This parameter is deprecated, use ca_ttl instead"],
+ :ca_ttl => ["5y", "The default TTL for new certificates; valid values
+ must be an integer, optionally followed by one of the units
+ 'y' (years of 365 days), 'd' (days), 'h' (hours), or
+ 's' (seconds). The unit defaults to seconds. If this parameter
+ is set, ca_days is ignored. Examples are '3600' (one hour)
+ and '1825d', which is the same as '5y' (5 years) "],
+ :ca_md => ["md5", "The type of hash used in certificates."],
+ :req_bits => [2048, "The bit length of the certificates."],
+ :keylength => [1024, "The bit length of keys."],
+ :cert_inventory => {
+ :default => "$cadir/inventory.txt",
+ :mode => 0644,
+ :owner => "service",
+ :group => "service",
+ :desc => "A Complete listing of all certificates"
+ }
+ )
+
+ # Define the config default.
+
+ setdefaults(
+ Puppet.settings[:name],
+ :config => ["$confdir/puppet.conf",
+ "The configuration file for #{Puppet[:name]}."],
+ :pidfile => ["$rundir/$name.pid", "The pid file"],
+ :bindaddress => ["", "The address a listening server should bind to. Mongrel servers
+ default to 127.0.0.1 and WEBrick defaults to 0.0.0.0."],
+ :servertype => {:default => "webrick", :desc => "The type of server to use. Currently supported
+ options are webrick and mongrel. If you use mongrel, you will need
+ a proxy in front of the process or processes, since Mongrel cannot
+ speak SSL.",
+
+ :call_on_define => true, # Call our hook with the default value, so we always get the correct bind address set.
+ :hook => proc { |value| value == "webrick" ? Puppet.settings[:bindaddress] = "0.0.0.0" : Puppet.settings[:bindaddress] = "127.0.0.1" if Puppet.settings[:bindaddress] == "" }
+ }
+ )
+
+ setdefaults(:master,
+ :user => ["puppet", "The user puppet master should run as."],
+ :group => ["puppet", "The group puppet master should run as."],
+ :manifestdir => ["$confdir/manifests", "Where puppet master looks for its manifests."],
+ :manifest => ["$manifestdir/site.pp", "The entry-point manifest for puppet master."],
+ :code => ["", "Code to parse directly. This is essentially only used
+ by ``puppet``, and should only be set if you're writing your own Puppet
+ executable"],
+ :masterlog => { :default => "$logdir/puppetmaster.log",
+ :owner => "service",
+ :group => "service",
+ :mode => 0660,
+ :desc => "Where puppet master logs. This is generally not used,
+ since syslog is the default log destination."
+ },
+ :masterhttplog => { :default => "$logdir/masterhttp.log",
+ :owner => "service",
+ :group => "service",
+ :mode => 0660,
+ :create => true,
+ :desc => "Where the puppet master web server logs."
+ },
+ :masterport => [8140, "Which port puppet master listens on."],
+ :parseonly => [false, "Just check the syntax of the manifests."],
+ :node_name => ["cert", "How the puppetmaster determines the client's identity
+ and sets the 'hostname', 'fqdn' and 'domain' facts for use in the manifest,
+ in particular for determining which 'node' statement applies to the client.
+ Possible values are 'cert' (use the subject's CN in the client's
+ certificate) and 'facter' (use the hostname that the client
+ reported in its facts)"],
+ :bucketdir => {
+ :default => "$vardir/bucket",
+ :mode => 0750,
+ :owner => "service",
+ :group => "service",
+ :desc => "Where FileBucket files are stored."
+ },
+ :rest_authconfig => [ "$confdir/auth.conf",
+ "The configuration file that defines the rights to the different
+ rest indirections. This can be used as a fine-grained
+ authorization system for ``puppet master``."
+ ],
+ :ca => [true, "Wether the master should function as a certificate authority."],
+ :modulepath => {:default => "$confdir/modules:/usr/share/puppet/modules",
+ :desc => "The search path for modules as a colon-separated list of
+ directories.", :type => :setting }, # We don't want this to be considered a file, since it's multiple files.
+ :ssl_client_header => ["HTTP_X_CLIENT_DN", "The header containing an authenticated
+ client's SSL DN. Only used with Mongrel. This header must be set by the proxy
+ to the authenticated client's SSL DN (e.g., ``/CN=puppet.puppetlabs.com``).
+ See http://projects.puppetlabs.com/projects/puppet/wiki/Using_Mongrel for more information."],
+ :ssl_client_verify_header => ["HTTP_X_CLIENT_VERIFY", "The header containing the status
+ message of the client verification. Only used with Mongrel. This header must be set by the proxy
+ to 'SUCCESS' if the client successfully authenticated, and anything else otherwise.
+ See http://projects.puppetlabs.com/projects/puppet/wiki/Using_Mongrel for more information."],
+ # To make sure this directory is created before we try to use it on the server, we need
+ # it to be in the server section (#1138).
+ :yamldir => {:default => "$vardir/yaml", :owner => "service", :group => "service", :mode => "750",
+ :desc => "The directory in which YAML data is stored, usually in a subdirectory."},
+ :server_datadir => {:default => "$vardir/server_data", :owner => "service", :group => "service", :mode => "750",
+ :desc => "The directory in which serialized data is stored, usually in a subdirectory."},
+ :reports => ["store",
+ "The list of reports to generate. All reports are looked for
+ in puppet/reports/name.rb, and multiple report names should be
+ comma-separated (whitespace is okay)."
+ ],
+ :fileserverconfig => ["$confdir/fileserver.conf", "Where the fileserver configuration is stored."],
+ :rrddir => {:default => "$vardir/rrd",
+ :owner => "service",
+ :group => "service",
+ :desc => "The directory where RRD database files are stored.
+ Directories for each reporting host will be created under
+ this directory."
+ },
+ :rrdinterval => ["$runinterval", "How often RRD should expect data.
+ This should match how often the hosts report back to the server."],
+ :strict_hostname_checking => [false, "Whether to only search for the complete
+ hostname as it is in the certificate when searching for node information
+ in the catalogs."]
+ )
+
+ setdefaults(:agent,
+ :localconfig => { :default => "$statedir/localconfig",
+ :owner => "root",
+ :mode => 0660,
+ :desc => "Where puppet agent caches the local configuration. An
+ extension indicating the cache format is added automatically."},
+ :statefile => { :default => "$statedir/state.yaml",
+ :mode => 0660,
+ :desc => "Where puppet agent and puppet master store state associated
+ with the running configuration. In the case of puppet master,
+ this file reflects the state discovered through interacting
+ with clients."
+ },
+ :clientyamldir => {:default => "$vardir/client_yaml", :mode => "750", :desc => "The directory in which client-side YAML data is stored."},
+ :client_datadir => {:default => "$vardir/client_data", :mode => "750", :desc => "The directory in which serialized data is stored on the client."},
+ :classfile => { :default => "$statedir/classes.txt",
+ :owner => "root",
+ :mode => 0644,
+ :desc => "The file in which puppet agent stores a list of the classes
+ associated with the retrieved configuration. Can be loaded in
+ the separate ``puppet`` executable using the ``--loadclasses``
+ option."},
+ :puppetdlog => { :default => "$logdir/puppetd.log",
+ :owner => "root",
+ :mode => 0640,
+ :desc => "The log file for puppet agent. This is generally not used."
+ },
+ :server => ["puppet", "The server to which server puppet agent should connect"],
+ :ignoreschedules => [false,
+ "Boolean; whether puppet agent should ignore schedules. This is useful
+ for initial puppet agent runs."],
+ :puppetport => [8139, "Which port puppet agent listens on."],
+ :noop => [false, "Whether puppet agent should be run in noop mode."],
+ :runinterval => [1800, # 30 minutes
+ "How often puppet agent applies the client configuration; in seconds."],
+ :listen => [false, "Whether puppet agent should listen for
+ connections. If this is true, then by default only the
+ ``runner`` server is started, which allows remote authorized
+ and authenticated nodes to connect and trigger ``puppet agent``
+ runs."],
+ :ca_server => ["$server", "The server to use for certificate
+ authority requests. It's a separate server because it cannot
+ and does not need to horizontally scale."],
+ :ca_port => ["$masterport", "The port to use for the certificate authority."],
+ :catalog_format => {
+ :default => "",
+ :desc => "(Deprecated for 'preferred_serialization_format') What format to
+ use to dump the catalog. Only supports 'marshal' and 'yaml'. Only
+ matters on the client, since it asks the server for a specific format.",
+ :hook => proc { |value|
+ if value
+ Puppet.warning "Setting 'catalog_format' is deprecated; use 'preferred_serialization_format' instead."
+ Puppet.settings[:preferred_serialization_format] = value
+ end
+ }
+ },
+ :preferred_serialization_format => ["pson", "The preferred means of serializing
+ ruby instances for passing over the wire. This won't guarantee that all
+ instances will be serialized using this method, since not all classes
+ can be guaranteed to support this format, but it will be used for all
+ classes that support it."],
+ :puppetdlockfile => [ "$statedir/puppetdlock", "A lock file to temporarily stop puppet agent from doing anything."],
+ :usecacheonfailure => [true,
+ "Whether to use the cached configuration when the remote
+ configuration will not compile. This option is useful for testing
+ new configurations, where you want to fix the broken configuration
+ rather than reverting to a known-good one."
+ ],
+ :use_cached_catalog => [false,
+ "Whether to only use the cached catalog rather than compiling a new catalog
+ on every run. Puppet can be run with this enabled by default and then selectively
+ disabled when a recompile is desired."],
+ :ignorecache => [false,
+ "Ignore cache and always recompile the configuration. This is
+ useful for testing new configurations, where the local cache may in
+ fact be stale even if the timestamps are up to date - if the facts
+ change or if the server changes."
+ ],
+ :downcasefacts => [false, "Whether facts should be made all lowercase when sent to the server."],
+ :dynamicfacts => ["memorysize,memoryfree,swapsize,swapfree",
+ "Facts that are dynamic; these facts will be ignored when deciding whether
+ changed facts should result in a recompile. Multiple facts should be
+ comma-separated."],
+ :splaylimit => ["$runinterval",
+ "The maximum time to delay before runs. Defaults to being the same as the
+ run interval."],
+ :splay => [false,
+ "Whether to sleep for a pseudo-random (but consistent) amount of time before
+ a run."],
+ :clientbucketdir => {
+ :default => "$vardir/clientbucket",
+ :mode => 0750,
+ :desc => "Where FileBucket files are stored locally."
+ },
+ :configtimeout => [120,
+ "How long the client should wait for the configuration to be retrieved
+ before considering it a failure. This can help reduce flapping if too
+ many clients contact the server at one time."
+ ],
+ :reportserver => {
+ :default => "$server",
+ :call_on_define => false,
+ :desc => "(Deprecated for 'report_server') The server to which to send transaction reports.",
+ :hook => proc do |value|
+ Puppet.settings[:report_server] = value if value
+ end
+ },
+ :report_server => ["$server",
+ "The server to which to send transaction reports."
+ ],
+ :report_port => ["$masterport",
+ "The port to communicate with the report_server."
+ ],
+ :report => [false,
+ "Whether to send reports after every transaction."
+ ],
+ :graph => [false, "Whether to create dot graph files for the different
+ configuration graphs. These dot files can be interpreted by tools
+ like OmniGraffle or dot (which is part of ImageMagick)."],
+ :graphdir => ["$statedir/graphs", "Where to store dot-outputted graphs."],
+ :http_compression => [false, "Allow http compression in REST communication with the master.
+ This setting might improve performance for agent -> master communications over slow WANs.
+ Your puppetmaster needs to support compression (usually by activating some settings in a reverse-proxy
+ in front of the puppetmaster, which rules out webrick).
+ It is harmless to activate this settings if your master doesn't support
+ compression, but if it supports it, this setting might reduce performance on high-speed LANs."]
+ )
+
+ # Plugin information.
+
+ setdefaults(
+ :main,
+ :plugindest => ["$libdir",
+ "Where Puppet should store plugins that it pulls down from the central
+ server."],
+ :pluginsource => ["puppet://$server/plugins",
+ "From where to retrieve plugins. The standard Puppet ``file`` type
+ is used for retrieval, so anything that is a valid file source can
+ be used here."],
+ :pluginsync => [false, "Whether plugins should be synced with the central server."],
+
+ :pluginsignore => [".svn CVS .git", "What files to ignore when pulling down plugins."]
+ )
+
+ # Central fact information.
+
+ setdefaults(
+ :main,
+ :factpath => {:default => "$vardir/lib/facter/${File::PATH_SEPARATOR}$vardir/facts",
+ :desc => "Where Puppet should look for facts. Multiple directories should
+ be colon-separated, like normal PATH variables.",
+
+ :call_on_define => true, # Call our hook with the default value, so we always get the value added to facter.
+ :type => :setting, # Don't consider it a file, because it could be multiple colon-separated files
+ :hook => proc { |value| Facter.search(value) if Facter.respond_to?(:search) }},
+ :factdest => ["$vardir/facts/",
+ "Where Puppet should store facts that it pulls down from the central
+ server."],
+ :factsource => ["puppet://$server/facts/",
+ "From where to retrieve facts. The standard Puppet ``file`` type
+ is used for retrieval, so anything that is a valid file source can
+ be used here."],
+ :factsync => [false, "Whether facts should be synced with the central server."],
+ :factsignore => [".svn CVS", "What files to ignore when pulling down facts."],
+ :reportdir => {:default => "$vardir/reports",
+ :mode => 0750,
+ :owner => "service",
+ :group => "service",
+ :desc => "The directory in which to store reports
+ received from the client. Each client gets a separate
+ subdirectory."},
+ :reporturl => ["http://localhost:3000/reports",
+ "The URL used by the http reports processor to send reports"]
+ )
+
+
+ setdefaults(
+ :tagmail,
+ :tagmap => ["$confdir/tagmail.conf", "The mapping between reporting tags and email addresses."],
+ :sendmail => [%x{which sendmail 2>/dev/null}.chomp, "Where to find the sendmail binary with which to send email."],
+
+ :reportfrom => ["report@" + [Facter["hostname"].value, Facter["domain"].value].join("."), "The 'from' email address for the reports."],
+ :smtpserver => ["none", "The server through which to send email reports."]
+ )
+
+
+ setdefaults(
+ :rails,
+ :dblocation => { :default => "$statedir/clientconfigs.sqlite3",
+ :mode => 0660,
+ :owner => "service",
+ :group => "service",
+ :desc => "The database cache for client configurations. Used for
+ querying within the language."
+ },
+ :dbadapter => [ "sqlite3", "The type of database to use." ],
+ :dbmigrate => [ false, "Whether to automatically migrate the database." ],
+ :dbname => [ "puppet", "The name of the database to use." ],
+ :dbserver => [ "localhost", "The database server for caching. Only
+ used when networked databases are used."],
+ :dbport => [ "", "The database password for caching. Only
+ used when networked databases are used."],
+ :dbuser => [ "puppet", "The database user for caching. Only
+ used when networked databases are used."],
+ :dbpassword => [ "puppet", "The database password for caching. Only
+ used when networked databases are used."],
+ :dbsocket => [ "", "The database socket location. Only used when networked
+ databases are used. Will be ignored if the value is an empty string."],
+ :dbconnections => [ 0, "The number of database connections. Only used when
+ networked databases are used. Will be ignored if the value is an empty
+ string or is less than 1."],
+ :railslog => {:default => "$logdir/rails.log",
+ :mode => 0600,
+ :owner => "service",
+ :group => "service",
+ :desc => "Where Rails-specific logs are sent"
+ },
+
+ :rails_loglevel => ["info", "The log level for Rails connections. The value must be
+ a valid log level within Rails. Production environments normally use ``info``
+ and other environments normally use ``debug``."]
+ )
+
+
+ setdefaults(
+ :couchdb,
+
+ :couchdb_url => ["http://127.0.0.1:5984/puppet", "The url where the puppet couchdb database will be created"]
+ )
+
+
+ setdefaults(
+ :transaction,
+ :tags => ["", "Tags to use to find resources. If this is set, then
+ only resources tagged with the specified tags will be applied.
+ Values must be comma-separated."],
+ :evaltrace => [false, "Whether each resource should log when it is
+ being evaluated. This allows you to interactively see exactly
+ what is being done."],
+ :summarize => [false,
+
+ "Whether to print a transaction summary."
+ ]
+ )
+
+
+ setdefaults(
+ :main,
+ :external_nodes => ["none",
+
+ "An external command that can produce node information. The output
+ must be a YAML dump of a hash, and that hash must have one or both of
+ ``classes`` and ``parameters``, where ``classes`` is an array and
+ ``parameters`` is a hash. For unknown nodes, the commands should
+ exit with a non-zero exit code.
+
+ This command makes it straightforward to store your node mapping
+ information in other data sources like databases."])
setdefaults(
- :ca,
- :ca_name => ["$certname", "The name to use the Certificate Authority certificate."],
- :cadir => { :default => "$ssldir/ca",
- :owner => "service",
- :group => "service",
- :mode => 0770,
- :desc => "The root directory for the certificate authority."
- },
- :cacert => { :default => "$cadir/ca_crt.pem",
- :owner => "service",
- :group => "service",
- :mode => 0660,
- :desc => "The CA certificate."
- },
- :cakey => { :default => "$cadir/ca_key.pem",
- :owner => "service",
- :group => "service",
- :mode => 0660,
- :desc => "The CA private key."
- },
- :capub => { :default => "$cadir/ca_pub.pem",
- :owner => "service",
- :group => "service",
- :desc => "The CA public key."
- },
- :cacrl => { :default => "$cadir/ca_crl.pem",
- :owner => "service",
- :group => "service",
- :mode => 0664,
-
- :desc => "The certificate revocation list (CRL) for the CA. Will be used if present but otherwise ignored.",
- :hook => proc do |value|
- if value == 'false'
- Puppet.warning "Setting the :cacrl to 'false' is deprecated; Puppet will just ignore the crl if yours is missing"
- end
- end
- },
- :caprivatedir => { :default => "$cadir/private",
- :owner => "service",
- :group => "service",
- :mode => 0770,
- :desc => "Where the CA stores private certificate information."
- },
- :csrdir => { :default => "$cadir/requests",
- :owner => "service",
- :group => "service",
- :desc => "Where the CA stores certificate requests"
- },
- :signeddir => { :default => "$cadir/signed",
- :owner => "service",
- :group => "service",
- :mode => 0770,
- :desc => "Where the CA stores signed certificates."
- },
- :capass => { :default => "$caprivatedir/ca.pass",
- :owner => "service",
- :group => "service",
- :mode => 0660,
- :desc => "Where the CA stores the password for the private key"
- },
- :serial => { :default => "$cadir/serial",
- :owner => "service",
- :group => "service",
- :mode => 0644,
- :desc => "Where the serial number for certificates is stored."
- },
- :autosign => { :default => "$confdir/autosign.conf",
- :mode => 0644,
- :desc => "Whether to enable autosign. Valid values are true (which
- autosigns any key request, and is a very bad idea), false (which
- never autosigns any key request), and the path to a file, which
- uses that configuration file to determine which keys to sign."},
- :ca_days => ["", "How long a certificate should be valid.
- This parameter is deprecated, use ca_ttl instead"],
- :ca_ttl => ["5y", "The default TTL for new certificates; valid values
- must be an integer, optionally followed by one of the units
- 'y' (years of 365 days), 'd' (days), 'h' (hours), or
- 's' (seconds). The unit defaults to seconds. If this parameter
- is set, ca_days is ignored. Examples are '3600' (one hour)
- and '1825d', which is the same as '5y' (5 years) "],
- :ca_md => ["md5", "The type of hash used in certificates."],
- :req_bits => [2048, "The bit length of the certificates."],
- :keylength => [1024, "The bit length of keys."],
- :cert_inventory => {
- :default => "$cadir/inventory.txt",
- :mode => 0644,
- :owner => "service",
- :group => "service",
- :desc => "A Complete listing of all certificates"
- }
- )
-
- # Define the config default.
-
- setdefaults(
- Puppet.settings[:name],
- :config => ["$confdir/puppet.conf",
- "The configuration file for #{Puppet[:name]}."],
- :pidfile => ["$rundir/$name.pid", "The pid file"],
- :bindaddress => ["", "The address a listening server should bind to. Mongrel servers
- default to 127.0.0.1 and WEBrick defaults to 0.0.0.0."],
- :servertype => {:default => "webrick", :desc => "The type of server to use. Currently supported
- options are webrick and mongrel. If you use mongrel, you will need
- a proxy in front of the process or processes, since Mongrel cannot
- speak SSL.",
-
- :call_on_define => true, # Call our hook with the default value, so we always get the correct bind address set.
- :hook => proc { |value| value == "webrick" ? Puppet.settings[:bindaddress] = "0.0.0.0" : Puppet.settings[:bindaddress] = "127.0.0.1" if Puppet.settings[:bindaddress] == "" }
- }
- )
-
- setdefaults(:master,
- :user => ["puppet", "The user puppet master should run as."],
- :group => ["puppet", "The group puppet master should run as."],
- :manifestdir => ["$confdir/manifests", "Where puppet master looks for its manifests."],
- :manifest => ["$manifestdir/site.pp", "The entry-point manifest for puppet master."],
- :code => ["", "Code to parse directly. This is essentially only used
- by ``puppet``, and should only be set if you're writing your own Puppet
- executable"],
- :masterlog => { :default => "$logdir/puppetmaster.log",
- :owner => "service",
- :group => "service",
- :mode => 0660,
- :desc => "Where puppet master logs. This is generally not used,
- since syslog is the default log destination."
- },
- :masterhttplog => { :default => "$logdir/masterhttp.log",
- :owner => "service",
- :group => "service",
- :mode => 0660,
- :create => true,
- :desc => "Where the puppet master web server logs."
- },
- :masterport => [8140, "Which port puppet master listens on."],
- :parseonly => [false, "Just check the syntax of the manifests."],
- :node_name => ["cert", "How the puppetmaster determines the client's identity
- and sets the 'hostname', 'fqdn' and 'domain' facts for use in the manifest,
- in particular for determining which 'node' statement applies to the client.
- Possible values are 'cert' (use the subject's CN in the client's
- certificate) and 'facter' (use the hostname that the client
- reported in its facts)"],
- :bucketdir => {
- :default => "$vardir/bucket",
- :mode => 0750,
- :owner => "service",
- :group => "service",
- :desc => "Where FileBucket files are stored."
- },
- :rest_authconfig => [ "$confdir/auth.conf",
- "The configuration file that defines the rights to the different
- rest indirections. This can be used as a fine-grained
- authorization system for ``puppet master``."
- ],
- :ca => [true, "Wether the master should function as a certificate authority."],
- :modulepath => {:default => "$confdir/modules:/usr/share/puppet/modules",
- :desc => "The search path for modules as a colon-separated list of
- directories.", :type => :setting }, # We don't want this to be considered a file, since it's multiple files.
- :ssl_client_header => ["HTTP_X_CLIENT_DN", "The header containing an authenticated
- client's SSL DN. Only used with Mongrel. This header must be set by the proxy
- to the authenticated client's SSL DN (e.g., ``/CN=puppet.puppetlabs.com``).
- See http://projects.puppetlabs.com/projects/puppet/wiki/Using_Mongrel for more information."],
- :ssl_client_verify_header => ["HTTP_X_CLIENT_VERIFY", "The header containing the status
- message of the client verification. Only used with Mongrel. This header must be set by the proxy
- to 'SUCCESS' if the client successfully authenticated, and anything else otherwise.
- See http://projects.puppetlabs.com/projects/puppet/wiki/Using_Mongrel for more information."],
- # To make sure this directory is created before we try to use it on the server, we need
- # it to be in the server section (#1138).
- :yamldir => {:default => "$vardir/yaml", :owner => "service", :group => "service", :mode => "750",
- :desc => "The directory in which YAML data is stored, usually in a subdirectory."},
- :server_datadir => {:default => "$vardir/server_data", :owner => "service", :group => "service", :mode => "750",
- :desc => "The directory in which serialized data is stored, usually in a subdirectory."},
- :reports => ["store",
- "The list of reports to generate. All reports are looked for
- in puppet/reports/name.rb, and multiple report names should be
- comma-separated (whitespace is okay)."
- ],
- :fileserverconfig => ["$confdir/fileserver.conf", "Where the fileserver configuration is stored."],
- :rrddir => {:default => "$vardir/rrd",
- :owner => "service",
- :group => "service",
- :desc => "The directory where RRD database files are stored.
- Directories for each reporting host will be created under
- this directory."
- },
- :rrdinterval => ["$runinterval", "How often RRD should expect data.
- This should match how often the hosts report back to the server."],
- :strict_hostname_checking => [false, "Whether to only search for the complete
- hostname as it is in the certificate when searching for node information
- in the catalogs."]
- )
-
- setdefaults(:agent,
- :localconfig => { :default => "$statedir/localconfig",
- :owner => "root",
- :mode => 0660,
- :desc => "Where puppet agent caches the local configuration. An
- extension indicating the cache format is added automatically."},
- :statefile => { :default => "$statedir/state.yaml",
- :mode => 0660,
- :desc => "Where puppet agent and puppet master store state associated
- with the running configuration. In the case of puppet master,
- this file reflects the state discovered through interacting
- with clients."
- },
- :clientyamldir => {:default => "$vardir/client_yaml", :mode => "750", :desc => "The directory in which client-side YAML data is stored."},
- :client_datadir => {:default => "$vardir/client_data", :mode => "750", :desc => "The directory in which serialized data is stored on the client."},
- :classfile => { :default => "$statedir/classes.txt",
- :owner => "root",
- :mode => 0644,
- :desc => "The file in which puppet agent stores a list of the classes
- associated with the retrieved configuration. Can be loaded in
- the separate ``puppet`` executable using the ``--loadclasses``
- option."},
- :puppetdlog => { :default => "$logdir/puppetd.log",
- :owner => "root",
- :mode => 0640,
- :desc => "The log file for puppet agent. This is generally not used."
- },
- :server => ["puppet", "The server to which server puppet agent should connect"],
- :ignoreschedules => [false,
- "Boolean; whether puppet agent should ignore schedules. This is useful
- for initial puppet agent runs."],
- :puppetport => [8139, "Which port puppet agent listens on."],
- :noop => [false, "Whether puppet agent should be run in noop mode."],
- :runinterval => [1800, # 30 minutes
- "How often puppet agent applies the client configuration; in seconds."],
- :listen => [false, "Whether puppet agent should listen for
- connections. If this is true, then by default only the
- ``runner`` server is started, which allows remote authorized
- and authenticated nodes to connect and trigger ``puppet agent``
- runs."],
- :ca_server => ["$server", "The server to use for certificate
- authority requests. It's a separate server because it cannot
- and does not need to horizontally scale."],
- :ca_port => ["$masterport", "The port to use for the certificate authority."],
- :catalog_format => {
- :default => "",
- :desc => "(Deprecated for 'preferred_serialization_format') What format to
- use to dump the catalog. Only supports 'marshal' and 'yaml'. Only
- matters on the client, since it asks the server for a specific format.",
- :hook => proc { |value|
- if value
- Puppet.warning "Setting 'catalog_format' is deprecated; use 'preferred_serialization_format' instead."
- Puppet.settings[:preferred_serialization_format] = value
- end
- }
- },
- :preferred_serialization_format => ["pson", "The preferred means of serializing
- ruby instances for passing over the wire. This won't guarantee that all
- instances will be serialized using this method, since not all classes
- can be guaranteed to support this format, but it will be used for all
- classes that support it."],
- :puppetdlockfile => [ "$statedir/puppetdlock", "A lock file to temporarily stop puppet agent from doing anything."],
- :usecacheonfailure => [true,
- "Whether to use the cached configuration when the remote
- configuration will not compile. This option is useful for testing
- new configurations, where you want to fix the broken configuration
- rather than reverting to a known-good one."
- ],
- :use_cached_catalog => [false,
- "Whether to only use the cached catalog rather than compiling a new catalog
- on every run. Puppet can be run with this enabled by default and then selectively
- disabled when a recompile is desired."],
- :ignorecache => [false,
- "Ignore cache and always recompile the configuration. This is
- useful for testing new configurations, where the local cache may in
- fact be stale even if the timestamps are up to date - if the facts
- change or if the server changes."
- ],
- :downcasefacts => [false, "Whether facts should be made all lowercase when sent to the server."],
- :dynamicfacts => ["memorysize,memoryfree,swapsize,swapfree",
- "Facts that are dynamic; these facts will be ignored when deciding whether
- changed facts should result in a recompile. Multiple facts should be
- comma-separated."],
- :splaylimit => ["$runinterval",
- "The maximum time to delay before runs. Defaults to being the same as the
- run interval."],
- :splay => [false,
- "Whether to sleep for a pseudo-random (but consistent) amount of time before
- a run."],
- :clientbucketdir => {
- :default => "$vardir/clientbucket",
- :mode => 0750,
- :desc => "Where FileBucket files are stored locally."
- },
- :configtimeout => [120,
- "How long the client should wait for the configuration to be retrieved
- before considering it a failure. This can help reduce flapping if too
- many clients contact the server at one time."
- ],
- :reportserver => {
- :default => "$server",
- :call_on_define => false,
- :desc => "(Deprecated for 'report_server') The server to which to send transaction reports.",
- :hook => proc do |value|
- Puppet.settings[:report_server] = value if value
- end
- },
- :report_server => ["$server",
- "The server to which to send transaction reports."
- ],
- :report_port => ["$masterport",
- "The port to communicate with the report_server."
- ],
- :report => [false,
- "Whether to send reports after every transaction."
- ],
- :graph => [false, "Whether to create dot graph files for the different
- configuration graphs. These dot files can be interpreted by tools
- like OmniGraffle or dot (which is part of ImageMagick)."],
- :graphdir => ["$statedir/graphs", "Where to store dot-outputted graphs."],
- :http_compression => [false, "Allow http compression in REST communication with the master.
- This setting might improve performance for agent -> master communications over slow WANs.
- Your puppetmaster needs to support compression (usually by activating some settings in a reverse-proxy
- in front of the puppetmaster, which rules out webrick).
- It is harmless to activate this settings if your master doesn't support
- compression, but if it supports it, this setting might reduce performance on high-speed LANs."]
- )
-
- # Plugin information.
-
- setdefaults(
- :main,
- :plugindest => ["$libdir",
- "Where Puppet should store plugins that it pulls down from the central
- server."],
- :pluginsource => ["puppet://$server/plugins",
- "From where to retrieve plugins. The standard Puppet ``file`` type
- is used for retrieval, so anything that is a valid file source can
- be used here."],
- :pluginsync => [false, "Whether plugins should be synced with the central server."],
-
- :pluginsignore => [".svn CVS .git", "What files to ignore when pulling down plugins."]
- )
-
- # Central fact information.
-
- setdefaults(
- :main,
- :factpath => {:default => "$vardir/lib/facter/${File::PATH_SEPARATOR}$vardir/facts",
- :desc => "Where Puppet should look for facts. Multiple directories should
- be colon-separated, like normal PATH variables.",
-
- :call_on_define => true, # Call our hook with the default value, so we always get the value added to facter.
- :type => :setting, # Don't consider it a file, because it could be multiple colon-separated files
- :hook => proc { |value| Facter.search(value) if Facter.respond_to?(:search) }},
- :factdest => ["$vardir/facts/",
- "Where Puppet should store facts that it pulls down from the central
- server."],
- :factsource => ["puppet://$server/facts/",
- "From where to retrieve facts. The standard Puppet ``file`` type
- is used for retrieval, so anything that is a valid file source can
- be used here."],
- :factsync => [false, "Whether facts should be synced with the central server."],
- :factsignore => [".svn CVS", "What files to ignore when pulling down facts."],
- :reportdir => {:default => "$vardir/reports",
- :mode => 0750,
- :owner => "service",
- :group => "service",
- :desc => "The directory in which to store reports
- received from the client. Each client gets a separate
- subdirectory."},
- :reporturl => ["http://localhost:3000/reports",
- "The URL used by the http reports processor to send reports"]
- )
-
-
- setdefaults(
- :tagmail,
- :tagmap => ["$confdir/tagmail.conf", "The mapping between reporting tags and email addresses."],
- :sendmail => [%x{which sendmail 2>/dev/null}.chomp, "Where to find the sendmail binary with which to send email."],
-
- :reportfrom => ["report@" + [Facter["hostname"].value, Facter["domain"].value].join("."), "The 'from' email address for the reports."],
- :smtpserver => ["none", "The server through which to send email reports."]
- )
-
-
- setdefaults(
- :rails,
- :dblocation => { :default => "$statedir/clientconfigs.sqlite3",
- :mode => 0660,
- :owner => "service",
- :group => "service",
- :desc => "The database cache for client configurations. Used for
- querying within the language."
- },
- :dbadapter => [ "sqlite3", "The type of database to use." ],
- :dbmigrate => [ false, "Whether to automatically migrate the database." ],
- :dbname => [ "puppet", "The name of the database to use." ],
- :dbserver => [ "localhost", "The database server for caching. Only
- used when networked databases are used."],
- :dbport => [ "", "The database password for caching. Only
- used when networked databases are used."],
- :dbuser => [ "puppet", "The database user for caching. Only
- used when networked databases are used."],
- :dbpassword => [ "puppet", "The database password for caching. Only
- used when networked databases are used."],
- :dbsocket => [ "", "The database socket location. Only used when networked
- databases are used. Will be ignored if the value is an empty string."],
- :dbconnections => [ 0, "The number of database connections. Only used when
- networked databases are used. Will be ignored if the value is an empty
- string or is less than 1."],
- :railslog => {:default => "$logdir/rails.log",
- :mode => 0600,
- :owner => "service",
- :group => "service",
- :desc => "Where Rails-specific logs are sent"
- },
-
- :rails_loglevel => ["info", "The log level for Rails connections. The value must be
- a valid log level within Rails. Production environments normally use ``info``
- and other environments normally use ``debug``."]
- )
-
-
- setdefaults(
- :couchdb,
-
- :couchdb_url => ["http://127.0.0.1:5984/puppet", "The url where the puppet couchdb database will be created"]
- )
-
-
- setdefaults(
- :transaction,
- :tags => ["", "Tags to use to find resources. If this is set, then
- only resources tagged with the specified tags will be applied.
- Values must be comma-separated."],
- :evaltrace => [false, "Whether each resource should log when it is
- being evaluated. This allows you to interactively see exactly
- what is being done."],
- :summarize => [false,
-
- "Whether to print a transaction summary."
- ]
- )
-
-
- setdefaults(
- :main,
- :external_nodes => ["none",
-
- "An external command that can produce node information. The output
- must be a YAML dump of a hash, and that hash must have one or both of
- ``classes`` and ``parameters``, where ``classes`` is an array and
- ``parameters`` is a hash. For unknown nodes, the commands should
- exit with a non-zero exit code.
-
- This command makes it straightforward to store your node mapping
- information in other data sources like databases."])
-
-
- setdefaults(
- :ldap,
- :ldapnodes => [false,
- "Whether to search for node configurations in LDAP. See
- http://projects.puppetlabs.com/projects/puppet/wiki/LDAP_Nodes for more information."],
- :ldapssl => [false,
- "Whether SSL should be used when searching for nodes.
- Defaults to false because SSL usually requires certificates
- to be set up on the client side."],
- :ldaptls => [false,
- "Whether TLS should be used when searching for nodes.
- Defaults to false because TLS usually requires certificates
- to be set up on the client side."],
- :ldapserver => ["ldap",
- "The LDAP server. Only used if ``ldapnodes`` is enabled."],
- :ldapport => [389,
- "The LDAP port. Only used if ``ldapnodes`` is enabled."],
-
- :ldapstring => ["(&(objectclass=puppetClient)(cn=%s))",
- "The search string used to find an LDAP node."],
- :ldapclassattrs => ["puppetclass",
- "The LDAP attributes to use to define Puppet classes. Values
- should be comma-separated."],
- :ldapstackedattrs => ["puppetvar",
- "The LDAP attributes that should be stacked to arrays by adding
- the values in all hierarchy elements of the tree. Values
- should be comma-separated."],
- :ldapattrs => ["all",
- "The LDAP attributes to include when querying LDAP for nodes. All
- returned attributes are set as variables in the top-level scope.
- Multiple values should be comma-separated. The value 'all' returns
- all attributes."],
- :ldapparentattr => ["parentnode",
- "The attribute to use to define the parent node."],
- :ldapuser => ["",
- "The user to use to connect to LDAP. Must be specified as a
- full DN."],
- :ldappassword => ["", "The password to use to connect to LDAP."],
- :ldapbase => ["",
- "The search base for LDAP searches. It's impossible to provide
- a meaningful default here, although the LDAP libraries might
- have one already set. Generally, it should be the 'ou=Hosts'
- branch under your main directory."]
- )
-
- setdefaults(:master,
- :storeconfigs => {:default => false, :desc => "Whether to store each client's configuration. This
- requires ActiveRecord from Ruby on Rails.",
- :call_on_define => true, # Call our hook with the default value, so we always get the libdir set.
- :hook => proc do |value|
- require 'puppet/node'
- require 'puppet/node/facts'
- if value
- require 'puppet/rails'
- raise "StoreConfigs not supported without ActiveRecord 2.1 or higher" unless Puppet.features.rails?
- Puppet::Resource::Catalog.cache_class = :active_record unless Puppet.settings[:async_storeconfigs]
- Puppet::Node::Facts.cache_class = :active_record
- Puppet::Node.cache_class = :active_record
- end
- end
- }
- )
-
- # This doesn't actually work right now.
-
- setdefaults(
- :parser,
-
- :lexical => [false, "Whether to use lexical scoping (vs. dynamic)."],
- :templatedir => ["$vardir/templates",
- "Where Puppet looks for template files. Can be a list of colon-seperated
- directories."
- ]
- )
+ :ldap,
+ :ldapnodes => [false,
+ "Whether to search for node configurations in LDAP. See
+ http://projects.puppetlabs.com/projects/puppet/wiki/LDAP_Nodes for more information."],
+ :ldapssl => [false,
+ "Whether SSL should be used when searching for nodes.
+ Defaults to false because SSL usually requires certificates
+ to be set up on the client side."],
+ :ldaptls => [false,
+ "Whether TLS should be used when searching for nodes.
+ Defaults to false because TLS usually requires certificates
+ to be set up on the client side."],
+ :ldapserver => ["ldap",
+ "The LDAP server. Only used if ``ldapnodes`` is enabled."],
+ :ldapport => [389,
+ "The LDAP port. Only used if ``ldapnodes`` is enabled."],
+
+ :ldapstring => ["(&(objectclass=puppetClient)(cn=%s))",
+ "The search string used to find an LDAP node."],
+ :ldapclassattrs => ["puppetclass",
+ "The LDAP attributes to use to define Puppet classes. Values
+ should be comma-separated."],
+ :ldapstackedattrs => ["puppetvar",
+ "The LDAP attributes that should be stacked to arrays by adding
+ the values in all hierarchy elements of the tree. Values
+ should be comma-separated."],
+ :ldapattrs => ["all",
+ "The LDAP attributes to include when querying LDAP for nodes. All
+ returned attributes are set as variables in the top-level scope.
+ Multiple values should be comma-separated. The value 'all' returns
+ all attributes."],
+ :ldapparentattr => ["parentnode",
+ "The attribute to use to define the parent node."],
+ :ldapuser => ["",
+ "The user to use to connect to LDAP. Must be specified as a
+ full DN."],
+ :ldappassword => ["", "The password to use to connect to LDAP."],
+ :ldapbase => ["",
+ "The search base for LDAP searches. It's impossible to provide
+ a meaningful default here, although the LDAP libraries might
+ have one already set. Generally, it should be the 'ou=Hosts'
+ branch under your main directory."]
+ )
+
+ setdefaults(:master,
+ :storeconfigs => {:default => false, :desc => "Whether to store each client's configuration. This
+ requires ActiveRecord from Ruby on Rails.",
+ :call_on_define => true, # Call our hook with the default value, so we always get the libdir set.
+ :hook => proc do |value|
+ require 'puppet/node'
+ require 'puppet/node/facts'
+ if value
+ require 'puppet/rails'
+ raise "StoreConfigs not supported without ActiveRecord 2.1 or higher" unless Puppet.features.rails?
+ Puppet::Resource::Catalog.cache_class = :active_record unless Puppet.settings[:async_storeconfigs]
+ Puppet::Node::Facts.cache_class = :active_record
+ Puppet::Node.cache_class = :active_record
+ end
+ end
+ }
+ )
+
+ # This doesn't actually work right now.
+
+ setdefaults(
+ :parser,
+
+ :lexical => [false, "Whether to use lexical scoping (vs. dynamic)."],
+ :templatedir => ["$vardir/templates",
+ "Where Puppet looks for template files. Can be a list of colon-seperated
+ directories."
+ ]
+ )
end
diff --git a/lib/puppet/dsl.rb b/lib/puppet/dsl.rb
index 28f4a7e0c..abdb78f67 100644
--- a/lib/puppet/dsl.rb
+++ b/lib/puppet/dsl.rb
@@ -7,5 +7,5 @@ require 'puppet/dsl/resource_type_api'
require 'puppet/dsl/resource_api'
class Object
- include Puppet::DSL::ResourceTypeAPI
+ include Puppet::DSL::ResourceTypeAPI
end
diff --git a/lib/puppet/dsl/resource_api.rb b/lib/puppet/dsl/resource_api.rb
index 3e56a5543..9aa1ea07a 100644
--- a/lib/puppet/dsl/resource_api.rb
+++ b/lib/puppet/dsl/resource_api.rb
@@ -4,117 +4,117 @@
require 'puppet/resource/type_collection_helper'
class Puppet::DSL::ResourceAPI
- include Puppet::Resource::TypeCollectionHelper
+ include Puppet::Resource::TypeCollectionHelper
- FUNCTION_MAP = {:acquire => :include}
+ FUNCTION_MAP = {:acquire => :include}
- attr_reader :scope, :resource, :block
+ attr_reader :scope, :resource, :block
- def environment
- scope.environment
- end
+ def environment
+ scope.environment
+ end
- def evaluate
- set_instance_variables
- instance_eval(&block)
- end
+ def evaluate
+ set_instance_variables
+ instance_eval(&block)
+ end
- def initialize(resource, scope, block)
- @scope = scope
- @resource = resource
- @block = block
- end
+ def initialize(resource, scope, block)
+ @scope = scope
+ @resource = resource
+ @block = block
+ end
- # Try to convert a missing method into a resource type or a function.
- def method_missing(name, *args)
- raise "MethodMissing loop when searching for #{name} with #{args.inspect}" if searching_for_method?
- @searching_for_method = true
- return create_resource(name, args[0], args[1]) if valid_type?(name)
+ # Try to convert a missing method into a resource type or a function.
+ def method_missing(name, *args)
+ raise "MethodMissing loop when searching for #{name} with #{args.inspect}" if searching_for_method?
+ @searching_for_method = true
+ return create_resource(name, args[0], args[1]) if valid_type?(name)
- name = map_function(name)
+ name = map_function(name)
- return call_function(name, args) if Puppet::Parser::Functions.function(name)
+ return call_function(name, args) if Puppet::Parser::Functions.function(name)
- super
- ensure
- @searching_for_method = true
- end
+ super
+ ensure
+ @searching_for_method = true
+ end
- def set_instance_variables
- resource.eachparam do |param|
- instance_variable_set("@#{param.name}", param.value)
- end
- @title = resource.title
- @name ||= resource.title
+ def set_instance_variables
+ resource.eachparam do |param|
+ instance_variable_set("@#{param.name}", param.value)
end
-
- def create_resource(type, names, arguments = nil)
- names = [names] unless names.is_a?(Array)
-
- arguments ||= {}
- raise ArgumentError, "Resource arguments must be provided as a hash" unless arguments.is_a?(Hash)
-
- names.collect do |name|
- resource = Puppet::Parser::Resource.new(type, name, :scope => scope)
- arguments.each do |param, value|
- resource[param] = value
- end
-
- resource.exported = true if exporting?
- resource.virtual = true if virtualizing?
- scope.compiler.add_resource(scope, resource)
- resource
- end
+ @title = resource.title
+ @name ||= resource.title
+ end
+
+ def create_resource(type, names, arguments = nil)
+ names = [names] unless names.is_a?(Array)
+
+ arguments ||= {}
+ raise ArgumentError, "Resource arguments must be provided as a hash" unless arguments.is_a?(Hash)
+
+ names.collect do |name|
+ resource = Puppet::Parser::Resource.new(type, name, :scope => scope)
+ arguments.each do |param, value|
+ resource[param] = value
+ end
+
+ resource.exported = true if exporting?
+ resource.virtual = true if virtualizing?
+ scope.compiler.add_resource(scope, resource)
+ resource
end
+ end
- def call_function(name, args)
- return false unless method = Puppet::Parser::Functions.function(name)
- scope.send(method, *args)
- end
-
- def export(resources = nil, &block)
- if resources
- resources.each { |resource| resource.exported = true }
- return resources
- end
- @exporting = true
- instance_eval(&block)
- ensure
- @exporting = false
- end
+ def call_function(name, args)
+ return false unless method = Puppet::Parser::Functions.function(name)
+ scope.send(method, *args)
+ end
- def virtual(resources = nil, &block)
- if resources
- resources.each { |resource| resource.virtual = true }
- return resources
- end
- @virtualizing = true
- instance_eval(&block)
- ensure
- @virtualizing = false
+ def export(resources = nil, &block)
+ if resources
+ resources.each { |resource| resource.exported = true }
+ return resources
end
-
- def valid_type?(name)
- return true if [:class, :node].include?(name)
- return true if Puppet::Type.type(name)
- return(known_resource_types.definition(name) ? true : false)
- end
-
- private
-
- def exporting?
- @exporting
- end
-
- def map_function(name)
- FUNCTION_MAP[name] || name
- end
-
- def searching_for_method?
- @searching_for_method
- end
-
- def virtualizing?
- @virtualizing
+ @exporting = true
+ instance_eval(&block)
+ ensure
+ @exporting = false
+ end
+
+ def virtual(resources = nil, &block)
+ if resources
+ resources.each { |resource| resource.virtual = true }
+ return resources
end
+ @virtualizing = true
+ instance_eval(&block)
+ ensure
+ @virtualizing = false
+ end
+
+ def valid_type?(name)
+ return true if [:class, :node].include?(name)
+ return true if Puppet::Type.type(name)
+ return(known_resource_types.definition(name) ? true : false)
+ end
+
+ private
+
+ def exporting?
+ @exporting
+ end
+
+ def map_function(name)
+ FUNCTION_MAP[name] || name
+ end
+
+ def searching_for_method?
+ @searching_for_method
+ end
+
+ def virtualizing?
+ @virtualizing
+ end
end
diff --git a/lib/puppet/dsl/resource_type_api.rb b/lib/puppet/dsl/resource_type_api.rb
index ba489680d..487aab99d 100644
--- a/lib/puppet/dsl/resource_type_api.rb
+++ b/lib/puppet/dsl/resource_type_api.rb
@@ -1,40 +1,40 @@
require 'puppet/resource/type'
module Puppet::DSL::ResourceTypeAPI
- def define(name, *args, &block)
- result = mk_resource_type(:definition, name, Hash.new, block)
- result.set_arguments(munge_type_arguments(args))
- result
- end
+ def define(name, *args, &block)
+ result = mk_resource_type(:definition, name, Hash.new, block)
+ result.set_arguments(munge_type_arguments(args))
+ result
+ end
- def hostclass(name, options = {}, &block)
- mk_resource_type(:hostclass, name, options, block)
- end
+ def hostclass(name, options = {}, &block)
+ mk_resource_type(:hostclass, name, options, block)
+ end
- def node(name, options = {}, &block)
- mk_resource_type(:node, name, options, block)
- end
+ def node(name, options = {}, &block)
+ mk_resource_type(:node, name, options, block)
+ end
- private
+ private
- def mk_resource_type(type, name, options, code)
- klass = Puppet::Resource::Type.new(type, name, options)
+ def mk_resource_type(type, name, options, code)
+ klass = Puppet::Resource::Type.new(type, name, options)
- klass.ruby_code = code if code
+ klass.ruby_code = code if code
- Puppet::Node::Environment.new.known_resource_types.add klass
+ Puppet::Node::Environment.new.known_resource_types.add klass
- klass
- end
+ klass
+ end
- def munge_type_arguments(args)
- args.inject([]) do |result, item|
- if item.is_a?(Hash)
- item.each { |p, v| result << [p, v] }
- else
- result << item
- end
- result
- end
+ def munge_type_arguments(args)
+ args.inject([]) do |result, item|
+ if item.is_a?(Hash)
+ item.each { |p, v| result << [p, v] }
+ else
+ result << item
+ end
+ result
end
+ end
end
diff --git a/lib/puppet/error.rb b/lib/puppet/error.rb
index 7be84d573..d0a0c9cc5 100644
--- a/lib/puppet/error.rb
+++ b/lib/puppet/error.rb
@@ -1,43 +1,43 @@
module Puppet # :nodoc:
- # The base class for all Puppet errors. We want to make it easy to add
- # line and file information. This probably isn't necessary for all
- # errors, but...
- class Error < RuntimeError
- attr_accessor :line, :file
+ # The base class for all Puppet errors. We want to make it easy to add
+ # line and file information. This probably isn't necessary for all
+ # errors, but...
+ class Error < RuntimeError
+ attr_accessor :line, :file
- def backtrace
- if defined?(@backtrace)
- return @backtrace
- else
- return super
- end
- end
+ def backtrace
+ if defined?(@backtrace)
+ return @backtrace
+ else
+ return super
+ end
+ end
- def initialize(message, line = nil, file = nil)
- @message = message
+ def initialize(message, line = nil, file = nil)
+ @message = message
- @line = line if line
- @file = file if file
- end
+ @line = line if line
+ @file = file if file
+ end
- def to_s
- str = nil
- if self.file and self.line
- str = "#{@message} at #{@file}:#{@line}"
- elsif self.line
- str = "#{@message} at line #{@line}"
- elsif self.file
- str = "#{@message} in #{self.file}"
- else
- str = @message.to_s
- end
+ def to_s
+ str = nil
+ if self.file and self.line
+ str = "#{@message} at #{@file}:#{@line}"
+ elsif self.line
+ str = "#{@message} at line #{@line}"
+ elsif self.file
+ str = "#{@message} in #{self.file}"
+ else
+ str = @message.to_s
+ end
- str
- end
+ str
end
+ end
- # An error class for when I don't know what happened. Automatically
- # prints a stack trace when in debug mode.
- class DevError < Puppet::Error
- end
+ # An error class for when I don't know what happened. Automatically
+ # prints a stack trace when in debug mode.
+ class DevError < Puppet::Error
+ end
end
diff --git a/lib/puppet/external/base64.rb b/lib/puppet/external/base64.rb
index 1005c8f2f..57359dc18 100755
--- a/lib/puppet/external/base64.rb
+++ b/lib/puppet/external/base64.rb
@@ -7,13 +7,13 @@
require 'base64'
unless defined?(Base64)
- class Base64
- def Base64.encode64(*args)
- Object.method(:encode64).call(*args)
- end
+ class Base64
+ def Base64.encode64(*args)
+ Object.method(:encode64).call(*args)
+ end
- def Base64.decode64(*args)
- Object.method(:decode64).call(*args)
- end
+ def Base64.decode64(*args)
+ Object.method(:decode64).call(*args)
end
+ end
end
diff --git a/lib/puppet/external/dot.rb b/lib/puppet/external/dot.rb
index 5d89ddbc9..c0e770ec5 100644
--- a/lib/puppet/external/dot.rb
+++ b/lib/puppet/external/dot.rb
@@ -8,319 +8,319 @@
module DOT
- # These glogal vars are used to make nice graph source.
+ # These glogal vars are used to make nice graph source.
+
+ $tab = ' '
+ $tab2 = $tab * 2
+
+ # if we don't like 4 spaces, we can change it any time
+
+ def change_tab (t)
+ $tab = t
+ $tab2 = t * 2
+ end
+
+ # options for node declaration
+
+ NODE_OPTS = [
+ # attributes due to
+ # http://www.graphviz.org/Documentation/dotguide.pdf
+ # March, 26, 2005
+ 'bottomlabel', # auxiliary label for nodes of shape M*
+ 'color', # default: black; node shape color
+ 'comment', # any string (format-dependent)
+ 'distortion', # default: 0.0; node distortion for shape=polygon
+ 'fillcolor', # default: lightgrey/black; node fill color
+ 'fixedsize', # default: false; label text has no affect on node size
+ 'fontcolor', # default: black; type face color
+ 'fontname', # default: Times-Roman; font family
+ 'fontsize', # default: 14; point size of label
+ 'group', # name of nodes group
+ 'height', # default: .5; height in inches
+ 'label', # default: node name; any string
+ 'layer', # default: overlay range; all, id or id:id
+ 'orientation', # dafault: 0.0; node rotation angle
+ 'peripheries', # shape-dependent number of node boundaries
+ 'regular', # default: false; force polygon to be regular
+ 'shape', # default: ellipse; node shape; see Section 2.1 and Appendix E
+ 'shapefile', # external EPSF or SVG custom shape file
+ 'sides', # default: 4; number of sides for shape=polygon
+ 'skew' , # default: 0.0; skewing of node for shape=polygon
+ 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
+ 'toplabel', # auxiliary label for nodes of shape M*
+ 'URL', # URL associated with node (format-dependent)
+ 'width', # default: .75; width in inches
+ 'z', # default: 0.0; z coordinate for VRML output
+
+ # maintained for backward compatibility or rdot internal
+ 'bgcolor',
+ 'rank'
+ ]
+
+ # options for edge declaration
+
+ EDGE_OPTS = [
+ 'arrowhead', # default: normal; style of arrowhead at head end
+ 'arrowsize', # default: 1.0; scaling factor for arrowheads
+ 'arrowtail', # default: normal; style of arrowhead at tail end
+ 'color', # default: black; edge stroke color
+ 'comment', # any string (format-dependent)
+ 'constraint', # default: true use edge to affect node ranking
+ 'decorate', # if set, draws a line connecting labels with their edges
+ 'dir', # default: forward; forward, back, both, or none
+ 'fontcolor', # default: black type face color
+ 'fontname', # default: Times-Roman; font family
+ 'fontsize', # default: 14; point size of label
+ 'headlabel', # label placed near head of edge
+ 'headport', # n,ne,e,se,s,sw,w,nw
+ 'headURL', # URL attached to head label if output format is ismap
+ 'label', # edge label
+ 'labelangle', # default: -25.0; angle in degrees which head or tail label is rotated off edge
+ 'labeldistance', # default: 1.0; scaling factor for distance of head or tail label from node
+ 'labelfloat', # default: false; lessen constraints on edge label placement
+ 'labelfontcolor', # default: black; type face color for head and tail labels
+ 'labelfontname', # default: Times-Roman; font family for head and tail labels
+ 'labelfontsize', # default: 14 point size for head and tail labels
+ 'layer', # default: overlay range; all, id or id:id
+ 'lhead', # name of cluster to use as head of edge
+ 'ltail', # name of cluster to use as tail of edge
+ 'minlen', # default: 1 minimum rank distance between head and tail
+ 'samehead', # tag for head node; edge heads with the same tag are merged onto the same port
+ 'sametail', # tag for tail node; edge tails with the same tag are merged onto the same port
+ 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
+ 'taillabel', # label placed near tail of edge
+ 'tailport', # n,ne,e,se,s,sw,w,nw
+ 'tailURL', # URL attached to tail label if output format is ismap
+ 'weight', # default: 1; integer cost of stretching an edge
+
+ # maintained for backward compatibility or rdot internal
+ 'id'
+ ]
+
+ # options for graph declaration
+
+ GRAPH_OPTS = [
+ 'bgcolor',
+ 'center', 'clusterrank', 'color', 'concentrate',
+ 'fontcolor', 'fontname', 'fontsize',
+ 'label', 'layerseq',
+ 'margin', 'mclimit',
+ 'nodesep', 'nslimit',
+ 'ordering', 'orientation',
+ 'page',
+ 'rank', 'rankdir', 'ranksep', 'ratio',
+ 'size'
+ ]
+
+ # a root class for any element in dot notation
+
+ class DOTSimpleElement
+
+ attr_accessor :name
+
+ def initialize (params = {})
+ @label = params['name'] ? params['name'] : ''
+ end
+
+ def to_s
+ @name
+ end
+ end
+
+ # an element that has options ( node, edge, or graph )
- $tab = ' '
- $tab2 = $tab * 2
+ class DOTElement < DOTSimpleElement
- # if we don't like 4 spaces, we can change it any time
+ # attr_reader :parent
+ attr_accessor :name, :options
- def change_tab (t)
- $tab = t
- $tab2 = t * 2
+ def initialize (params = {}, option_list = [])
+ super(params)
+ @name = params['name'] ? params['name'] : nil
+ @parent = params['parent'] ? params['parent'] : nil
+ @options = {}
+ option_list.each{ |i|
+ @options[i] = params[i] if params[i]
+ }
+ @options['label'] ||= @name if @name != 'node'
end
- # options for node declaration
-
- NODE_OPTS = [
- # attributes due to
- # http://www.graphviz.org/Documentation/dotguide.pdf
- # March, 26, 2005
- 'bottomlabel', # auxiliary label for nodes of shape M*
- 'color', # default: black; node shape color
- 'comment', # any string (format-dependent)
- 'distortion', # default: 0.0; node distortion for shape=polygon
- 'fillcolor', # default: lightgrey/black; node fill color
- 'fixedsize', # default: false; label text has no affect on node size
- 'fontcolor', # default: black; type face color
- 'fontname', # default: Times-Roman; font family
- 'fontsize', # default: 14; point size of label
- 'group', # name of nodes group
- 'height', # default: .5; height in inches
- 'label', # default: node name; any string
- 'layer', # default: overlay range; all, id or id:id
- 'orientation', # dafault: 0.0; node rotation angle
- 'peripheries', # shape-dependent number of node boundaries
- 'regular', # default: false; force polygon to be regular
- 'shape', # default: ellipse; node shape; see Section 2.1 and Appendix E
- 'shapefile', # external EPSF or SVG custom shape file
- 'sides', # default: 4; number of sides for shape=polygon
- 'skew' , # default: 0.0; skewing of node for shape=polygon
- 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
- 'toplabel', # auxiliary label for nodes of shape M*
- 'URL', # URL associated with node (format-dependent)
- 'width', # default: .75; width in inches
- 'z', # default: 0.0; z coordinate for VRML output
-
- # maintained for backward compatibility or rdot internal
- 'bgcolor',
- 'rank'
- ]
-
- # options for edge declaration
-
- EDGE_OPTS = [
- 'arrowhead', # default: normal; style of arrowhead at head end
- 'arrowsize', # default: 1.0; scaling factor for arrowheads
- 'arrowtail', # default: normal; style of arrowhead at tail end
- 'color', # default: black; edge stroke color
- 'comment', # any string (format-dependent)
- 'constraint', # default: true use edge to affect node ranking
- 'decorate', # if set, draws a line connecting labels with their edges
- 'dir', # default: forward; forward, back, both, or none
- 'fontcolor', # default: black type face color
- 'fontname', # default: Times-Roman; font family
- 'fontsize', # default: 14; point size of label
- 'headlabel', # label placed near head of edge
- 'headport', # n,ne,e,se,s,sw,w,nw
- 'headURL', # URL attached to head label if output format is ismap
- 'label', # edge label
- 'labelangle', # default: -25.0; angle in degrees which head or tail label is rotated off edge
- 'labeldistance', # default: 1.0; scaling factor for distance of head or tail label from node
- 'labelfloat', # default: false; lessen constraints on edge label placement
- 'labelfontcolor', # default: black; type face color for head and tail labels
- 'labelfontname', # default: Times-Roman; font family for head and tail labels
- 'labelfontsize', # default: 14 point size for head and tail labels
- 'layer', # default: overlay range; all, id or id:id
- 'lhead', # name of cluster to use as head of edge
- 'ltail', # name of cluster to use as tail of edge
- 'minlen', # default: 1 minimum rank distance between head and tail
- 'samehead', # tag for head node; edge heads with the same tag are merged onto the same port
- 'sametail', # tag for tail node; edge tails with the same tag are merged onto the same port
- 'style', # graphics options, e.g. bold, dotted, filled; cf. Section 2.3
- 'taillabel', # label placed near tail of edge
- 'tailport', # n,ne,e,se,s,sw,w,nw
- 'tailURL', # URL attached to tail label if output format is ismap
- 'weight', # default: 1; integer cost of stretching an edge
-
- # maintained for backward compatibility or rdot internal
- 'id'
- ]
-
- # options for graph declaration
-
- GRAPH_OPTS = [
- 'bgcolor',
- 'center', 'clusterrank', 'color', 'concentrate',
- 'fontcolor', 'fontname', 'fontsize',
- 'label', 'layerseq',
- 'margin', 'mclimit',
- 'nodesep', 'nslimit',
- 'ordering', 'orientation',
- 'page',
- 'rank', 'rankdir', 'ranksep', 'ratio',
- 'size'
- ]
-
- # a root class for any element in dot notation
-
- class DOTSimpleElement
-
- attr_accessor :name
-
- def initialize (params = {})
- @label = params['name'] ? params['name'] : ''
- end
-
- def to_s
- @name
- end
+ def each_option
+ @options.each{ |i| yield i }
end
- # an element that has options ( node, edge, or graph )
+ def each_option_pair
+ @options.each_pair{ |key, val| yield key, val }
+ end
- class DOTElement < DOTSimpleElement
+ #def parent=( thing )
+ # @parent.delete( self ) if defined?( @parent ) and @parent
+ # @parent = thing
+ #end
- # attr_reader :parent
- attr_accessor :name, :options
+ end
- def initialize (params = {}, option_list = [])
- super(params)
- @name = params['name'] ? params['name'] : nil
- @parent = params['parent'] ? params['parent'] : nil
- @options = {}
- option_list.each{ |i|
- @options[i] = params[i] if params[i]
- }
- @options['label'] ||= @name if @name != 'node'
- end
- def each_option
- @options.each{ |i| yield i }
- end
+ # This is used when we build nodes that have shape=record
+ # ports don't have options :)
- def each_option_pair
- @options.each_pair{ |key, val| yield key, val }
- end
+ class DOTPort < DOTSimpleElement
- #def parent=( thing )
- # @parent.delete( self ) if defined?( @parent ) and @parent
- # @parent = thing
- #end
+ attr_accessor :label
+ def initialize (params = {})
+ super(params)
+ @name = params['label'] ? params['label'] : ''
end
+ def to_s
+ ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}"
+ end
+ end
- # This is used when we build nodes that have shape=record
- # ports don't have options :)
+ # node element
- class DOTPort < DOTSimpleElement
+ class DOTNode < DOTElement
- attr_accessor :label
+ @ports
- def initialize (params = {})
- super(params)
- @name = params['label'] ? params['label'] : ''
- end
+ def initialize (params = {}, option_list = NODE_OPTS)
+ super(params, option_list)
+ @ports = params['ports'] ? params['ports'] : []
+ end
- def to_s
- ( @name && @name != "" ? "<#{@name}>" : "" ) + "#{@label}"
- end
+ def each_port
+ @ports.each { |i| yield i }
end
- # node element
+ def << (thing)
+ @ports << thing
+ end
- class DOTNode < DOTElement
+ def push (thing)
+ @ports.push(thing)
+ end
- @ports
+ def pop
+ @ports.pop
+ end
- def initialize (params = {}, option_list = NODE_OPTS)
- super(params, option_list)
- @ports = params['ports'] ? params['ports'] : []
- end
+ def to_s (t = '')
+
+ # This code is totally incomprehensible; it needs to be replaced!
+
+ label = @options['shape'] != 'record' && @ports.length == 0 ?
+ @options['label'] ?
+ t + $tab + "label = \"#{@options['label']}\"\n" :
+ '' :
+ t + $tab + 'label = "' + " \\\n" +
+ t + $tab2 + "#{@options['label']}| \\\n" +
+ @ports.collect{ |i|
+ t + $tab2 + i.to_s
+ }.join( "| \\\n" ) + " \\\n" +
+ t + $tab + '"' + "\n"
+
+ t + "#{@name} [\n" +
+ @options.to_a.collect{ |i|
+ i[1] && i[0] != 'label' ?
+ t + $tab + "#{i[0]} = #{i[1]}" : nil
+ }.compact.join( ",\n" ) + ( label != '' ? ",\n" : "\n" ) +
+ label +
+ t + "]\n"
+ end
- def each_port
- @ports.each { |i| yield i }
- end
+ end
- def << (thing)
- @ports << thing
- end
+ # A subgraph element is the same to graph, but has another header in dot
+ # notation.
- def push (thing)
- @ports.push(thing)
- end
+ class DOTSubgraph < DOTElement
- def pop
- @ports.pop
- end
+ @nodes
+ @dot_string
- def to_s (t = '')
+ def initialize (params = {}, option_list = GRAPH_OPTS)
+ super(params, option_list)
+ @nodes = params['nodes'] ? params['nodes'] : []
+ @dot_string = 'graph'
+ end
- # This code is totally incomprehensible; it needs to be replaced!
+ def each_node
+ @nodes.each{ |i| yield i }
+ end
- label = @options['shape'] != 'record' && @ports.length == 0 ?
- @options['label'] ?
- t + $tab + "label = \"#{@options['label']}\"\n" :
- '' :
- t + $tab + 'label = "' + " \\\n" +
- t + $tab2 + "#{@options['label']}| \\\n" +
- @ports.collect{ |i|
- t + $tab2 + i.to_s
- }.join( "| \\\n" ) + " \\\n" +
- t + $tab + '"' + "\n"
+ def << (thing)
+ @nodes << thing
+ end
- t + "#{@name} [\n" +
- @options.to_a.collect{ |i|
- i[1] && i[0] != 'label' ?
- t + $tab + "#{i[0]} = #{i[1]}" : nil
- }.compact.join( ",\n" ) + ( label != '' ? ",\n" : "\n" ) +
- label +
- t + "]\n"
- end
+ def push (thing)
+ @nodes.push( thing )
+ end
+ def pop
+ @nodes.pop
end
- # A subgraph element is the same to graph, but has another header in dot
- # notation.
+ def to_s (t = '')
+ hdr = t + "#{@dot_string} #{@name} {\n"
- class DOTSubgraph < DOTElement
+ options = @options.to_a.collect{ |name, val|
+ val && name != 'label' ?
+ t + $tab + "#{name} = #{val}" :
+ name ? t + $tab + "#{name} = \"#{val}\"" : nil
+ }.compact.join( "\n" ) + "\n"
- @nodes
- @dot_string
+ nodes = @nodes.collect{ |i|
+ i.to_s( t + $tab )
+ }.join( "\n" ) + "\n"
+ hdr + options + nodes + t + "}\n"
+ end
- def initialize (params = {}, option_list = GRAPH_OPTS)
- super(params, option_list)
- @nodes = params['nodes'] ? params['nodes'] : []
- @dot_string = 'graph'
- end
+ end
- def each_node
- @nodes.each{ |i| yield i }
- end
+ # This is a graph.
- def << (thing)
- @nodes << thing
- end
+ class DOTDigraph < DOTSubgraph
- def push (thing)
- @nodes.push( thing )
- end
+ def initialize (params = {}, option_list = GRAPH_OPTS)
+ super(params, option_list)
+ @dot_string = 'digraph'
+ end
- def pop
- @nodes.pop
- end
+ end
- def to_s (t = '')
- hdr = t + "#{@dot_string} #{@name} {\n"
+ # This is an edge.
- options = @options.to_a.collect{ |name, val|
- val && name != 'label' ?
- t + $tab + "#{name} = #{val}" :
- name ? t + $tab + "#{name} = \"#{val}\"" : nil
- }.compact.join( "\n" ) + "\n"
+ class DOTEdge < DOTElement
- nodes = @nodes.collect{ |i|
- i.to_s( t + $tab )
- }.join( "\n" ) + "\n"
- hdr + options + nodes + t + "}\n"
- end
+ attr_accessor :from, :to
+ def initialize (params = {}, option_list = EDGE_OPTS)
+ super(params, option_list)
+ @from = params['from'] ? params['from'] : nil
+ @to = params['to'] ? params['to'] : nil
end
- # This is a graph.
-
- class DOTDigraph < DOTSubgraph
-
- def initialize (params = {}, option_list = GRAPH_OPTS)
- super(params, option_list)
- @dot_string = 'digraph'
+ def edge_link
+ '--'
end
+ def to_s (t = '')
+ t + "#{@from} #{edge_link} #{to} [\n" +
+ @options.to_a.collect{ |i|
+ i[1] && i[0] != 'label' ?
+ t + $tab + "#{i[0]} = #{i[1]}" :
+ i[1] ? t + $tab + "#{i[0]} = \"#{i[1]}\"" : nil
+ }.compact.join( "\n" ) + "\n#{t}]\n"
end
- # This is an edge.
-
- class DOTEdge < DOTElement
+ end
- attr_accessor :from, :to
-
- def initialize (params = {}, option_list = EDGE_OPTS)
- super(params, option_list)
- @from = params['from'] ? params['from'] : nil
- @to = params['to'] ? params['to'] : nil
- end
-
- def edge_link
- '--'
- end
-
- def to_s (t = '')
- t + "#{@from} #{edge_link} #{to} [\n" +
- @options.to_a.collect{ |i|
- i[1] && i[0] != 'label' ?
- t + $tab + "#{i[0]} = #{i[1]}" :
- i[1] ? t + $tab + "#{i[0]} = \"#{i[1]}\"" : nil
- }.compact.join( "\n" ) + "\n#{t}]\n"
- end
+ class DOTDirectedEdge < DOTEdge
+ def edge_link
+ '->'
end
- class DOTDirectedEdge < DOTEdge
-
- def edge_link
- '->'
- end
-
- end
+ end
end
diff --git a/lib/puppet/external/event-loop/better-definers.rb b/lib/puppet/external/event-loop/better-definers.rb
index c600fc208..ef1d44c53 100644
--- a/lib/puppet/external/event-loop/better-definers.rb
+++ b/lib/puppet/external/event-loop/better-definers.rb
@@ -18,350 +18,350 @@
# Boston, MA 02110-1301, USA.
class Symbol
- def predicate?
- to_s.include? "?" end
- def imperative?
- to_s.include? "!" end
- def writer?
- to_s.include? "=" end
-
- def punctuated?
- predicate? or imperative? or writer? end
- def without_punctuation
- to_s.delete("?!=").to_sym end
-
- def predicate
- without_punctuation.to_s + "?" end
- def imperative
- without_punctuation.to_s + "!" end
- def writer
- without_punctuation.to_s + "=" end
+ def predicate?
+ to_s.include? "?" end
+ def imperative?
+ to_s.include? "!" end
+ def writer?
+ to_s.include? "=" end
+
+ def punctuated?
+ predicate? or imperative? or writer? end
+ def without_punctuation
+ to_s.delete("?!=").to_sym end
+
+ def predicate
+ without_punctuation.to_s + "?" end
+ def imperative
+ without_punctuation.to_s + "!" end
+ def writer
+ without_punctuation.to_s + "=" end
end
class Hash
- def collect! (&block)
- replace Hash[*collect(&block).flatten]
- end
+ def collect! (&block)
+ replace Hash[*collect(&block).flatten]
+ end
- def flatten
- to_a.flatten
- end
+ def flatten
+ to_a.flatten
+ end
end
module Kernel
- def returning (value)
- yield value ; value
- end
+ def returning (value)
+ yield value ; value
+ end
end
class Module
- def define_hard_aliases (name_pairs)
- for new_aliases, existing_name in name_pairs do
- new_aliases.kind_of? Array or new_aliases = [new_aliases]
- for new_alias in new_aliases do
- alias_method(new_alias, existing_name)
- end
- end
- end
-
- def define_soft_aliases (name_pairs)
- for new_aliases, existing_name in name_pairs do
- new_aliases.kind_of? Array or new_aliases = [new_aliases]
- for new_alias in new_aliases do
- class_eval %{def #{new_alias}(*args, &block)
- #{existing_name}(*args, &block) end}
- end
- end
- end
-
- define_soft_aliases \
- :define_hard_alias => :define_hard_aliases,
- :define_soft_alias => :define_soft_aliases
-
- # This method lets you define predicates like :foo?,
- # which will be defined to return the value of @foo.
- def define_readers (*names)
- for name in names.map { |x| x.to_sym } do
- if name.punctuated?
- # There's no way to define an efficient reader whose
- # name is different from the instance variable.
- class_eval %{def #{name} ; @#{name.without_punctuation} end}
- else
- # Use `attr_reader' to define an efficient method.
- attr_reader(name)
- end
- end
- end
-
- def writer_defined? (name)
- method_defined?(name.to_sym.writer)
- end
-
- # If you pass a predicate symbol :foo? to this method, it'll first
- # define a regular writer method :foo, without a question mark.
- # Then it'll define an imperative writer method :foo! as a shorthand
- # for setting the property to true.
- def define_writers (*names, &body)
- for name in names.map { |x| x.to_sym } do
- if block_given?
- define_method(name.writer, &body)
- else
- attr_writer(name.without_punctuation)
- end
- if name.predicate?
- class_eval %{def #{name.imperative}
- self.#{name.writer} true end}
- end
- end
- end
-
- define_soft_aliases \
- :define_reader => :define_readers,
- :define_writer => :define_writers
-
- # We don't need a singular alias for `define_accessors',
- # because it always defines at least two methods.
-
- def define_accessors (*names)
- define_readers(*names)
- define_writers(*names)
- end
-
- def define_opposite_readers (name_pairs)
- name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
- for opposite_name, name in name_pairs do
- define_reader(name) unless method_defined?(name)
- class_eval %{def #{opposite_name} ; not #{name} end}
- end
+ def define_hard_aliases (name_pairs)
+ for new_aliases, existing_name in name_pairs do
+ new_aliases.kind_of? Array or new_aliases = [new_aliases]
+ for new_alias in new_aliases do
+ alias_method(new_alias, existing_name)
+ end
end
-
- def define_opposite_writers (name_pairs)
- name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
- for opposite_name, name in name_pairs do
- define_writer(name) unless writer_defined?(name)
- class_eval %{def #{opposite_name.writer} x
- self.#{name.writer} !x end}
- class_eval %{def #{opposite_name.imperative}
- self.#{name.writer} false end}
- end
+ end
+
+ def define_soft_aliases (name_pairs)
+ for new_aliases, existing_name in name_pairs do
+ new_aliases.kind_of? Array or new_aliases = [new_aliases]
+ for new_alias in new_aliases do
+ class_eval %{def #{new_alias}(*args, &block)
+ #{existing_name}(*args, &block) end}
+ end
end
-
- define_soft_aliases \
- :define_opposite_reader => :define_opposite_readers,
- :define_opposite_writer => :define_opposite_writers
-
- def define_opposite_accessors (name_pairs)
- define_opposite_readers name_pairs
- define_opposite_writers name_pairs
- end
-
- def define_reader_with_opposite (name_pair, &body)
- name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
- define_method(name, &body)
- define_opposite_reader(opposite_name => name)
+ end
+
+ define_soft_aliases \
+ :define_hard_alias => :define_hard_aliases,
+ :define_soft_alias => :define_soft_aliases
+
+ # This method lets you define predicates like :foo?,
+ # which will be defined to return the value of @foo.
+ def define_readers (*names)
+ for name in names.map { |x| x.to_sym } do
+ if name.punctuated?
+ # There's no way to define an efficient reader whose
+ # name is different from the instance variable.
+ class_eval %{def #{name} ; @#{name.without_punctuation} end}
+ else
+ # Use `attr_reader' to define an efficient method.
+ attr_reader(name)
+ end
end
-
- def define_writer_with_opposite (name_pair, &body)
- name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
- define_writer(name, &body)
- define_opposite_writer(opposite_name => name)
+ end
+
+ def writer_defined? (name)
+ method_defined?(name.to_sym.writer)
+ end
+
+ # If you pass a predicate symbol :foo? to this method, it'll first
+ # define a regular writer method :foo, without a question mark.
+ # Then it'll define an imperative writer method :foo! as a shorthand
+ # for setting the property to true.
+ def define_writers (*names, &body)
+ for name in names.map { |x| x.to_sym } do
+ if block_given?
+ define_method(name.writer, &body)
+ else
+ attr_writer(name.without_punctuation)
+ end
+ if name.predicate?
+ class_eval %{def #{name.imperative}
+ self.#{name.writer} true end}
+ end
end
+ end
- public :define_method
+ define_soft_aliases \
+ :define_reader => :define_readers,
+ :define_writer => :define_writers
- def define_methods (*names, &body)
- names.each { |name| define_method(name, &body) }
- end
+ # We don't need a singular alias for `define_accessors',
+ # because it always defines at least two methods.
- def define_private_methods (*names, &body)
- define_methods(*names, &body)
- names.each { |name| private name }
- end
+ def define_accessors (*names)
+ define_readers(*names)
+ define_writers(*names)
+ end
- def define_protected_methods (*names, &body)
- define_methods(*names, &body)
- names.each { |name| protected name }
+ def define_opposite_readers (name_pairs)
+ name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
+ for opposite_name, name in name_pairs do
+ define_reader(name) unless method_defined?(name)
+ class_eval %{def #{opposite_name} ; not #{name} end}
end
-
- def define_private_method (name, &body)
- define_method(name, &body)
- private name
- end
-
- def define_protected_method (name, &body)
- define_method(name, &body)
- protected name
+ end
+
+ def define_opposite_writers (name_pairs)
+ name_pairs.collect! { |k, v| [k.to_sym, v.to_sym] }
+ for opposite_name, name in name_pairs do
+ define_writer(name) unless writer_defined?(name)
+ class_eval %{def #{opposite_name.writer} x
+ self.#{name.writer} !x end}
+ class_eval %{def #{opposite_name.imperative}
+ self.#{name.writer} false end}
end
+ end
+
+ define_soft_aliases \
+ :define_opposite_reader => :define_opposite_readers,
+ :define_opposite_writer => :define_opposite_writers
+
+ def define_opposite_accessors (name_pairs)
+ define_opposite_readers name_pairs
+ define_opposite_writers name_pairs
+ end
+
+ def define_reader_with_opposite (name_pair, &body)
+ name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
+ define_method(name, &body)
+ define_opposite_reader(opposite_name => name)
+ end
+
+ def define_writer_with_opposite (name_pair, &body)
+ name, opposite_name = name_pair.flatten.collect { |x| x.to_sym }
+ define_writer(name, &body)
+ define_opposite_writer(opposite_name => name)
+ end
+
+ public :define_method
+
+ def define_methods (*names, &body)
+ names.each { |name| define_method(name, &body) }
+ end
+
+ def define_private_methods (*names, &body)
+ define_methods(*names, &body)
+ names.each { |name| private name }
+ end
+
+ def define_protected_methods (*names, &body)
+ define_methods(*names, &body)
+ names.each { |name| protected name }
+ end
+
+ def define_private_method (name, &body)
+ define_method(name, &body)
+ private name
+ end
+
+ def define_protected_method (name, &body)
+ define_method(name, &body)
+ protected name
+ end
end
class ImmutableAttributeError < StandardError
- def initialize (attribute=nil, message=nil)
- super message
- @attribute = attribute
- end
-
- define_accessors :attribute
-
- def to_s
- if @attribute and @message
- "cannot change the value of `#@attribute': #@message"
- elsif @attribute
- "cannot change the value of `#@attribute'"
- elsif @message
- "cannot change the value of attribute: #@message"
- else
- "cannot change the value of attribute"
- end
+ def initialize (attribute=nil, message=nil)
+ super message
+ @attribute = attribute
+ end
+
+ define_accessors :attribute
+
+ def to_s
+ if @attribute and @message
+ "cannot change the value of `#@attribute': #@message"
+ elsif @attribute
+ "cannot change the value of `#@attribute'"
+ elsif @message
+ "cannot change the value of attribute: #@message"
+ else
+ "cannot change the value of attribute"
end
+ end
end
class Module
- # Guard each of the specified attributes by replacing the writer
- # method with a proxy that asks the supplied block before proceeding
- # with the change.
- #
- # If it's okay to change the attribute, the block should return
- # either nil or the symbol :mutable. If it isn't okay, the block
- # should return a string saying why the attribute can't be changed.
- # If you don't want to provide a reason, you can have the block
- # return just the symbol :immutable.
- def guard_writers(*names, &predicate)
- for name in names.map { |x| x.to_sym } do
- define_hard_alias("__unguarded_#{name.writer}" => name.writer)
- define_method(name.writer) do |new_value|
- case result = predicate.call
- when :mutable, nil
- __send__("__unguarded_#{name.writer}", new_value)
- when :immutable
- raise ImmutableAttributeError.new(name)
- else
- raise ImmutableAttributeError.new(name, result)
- end
- end
+ # Guard each of the specified attributes by replacing the writer
+ # method with a proxy that asks the supplied block before proceeding
+ # with the change.
+ #
+ # If it's okay to change the attribute, the block should return
+ # either nil or the symbol :mutable. If it isn't okay, the block
+ # should return a string saying why the attribute can't be changed.
+ # If you don't want to provide a reason, you can have the block
+ # return just the symbol :immutable.
+ def guard_writers(*names, &predicate)
+ for name in names.map { |x| x.to_sym } do
+ define_hard_alias("__unguarded_#{name.writer}" => name.writer)
+ define_method(name.writer) do |new_value|
+ case result = predicate.call
+ when :mutable, nil
+ __send__("__unguarded_#{name.writer}", new_value)
+ when :immutable
+ raise ImmutableAttributeError.new(name)
+ else
+ raise ImmutableAttributeError.new(name, result)
end
+ end
end
+ end
- def define_guarded_writers (*names, &block)
- define_writers(*names)
- guard_writers(*names, &block)
- end
+ def define_guarded_writers (*names, &block)
+ define_writers(*names)
+ guard_writers(*names, &block)
+ end
- define_soft_alias :guard_writer => :guard_writers
- define_soft_alias :define_guarded_writer => :define_guarded_writers
+ define_soft_alias :guard_writer => :guard_writers
+ define_soft_alias :define_guarded_writer => :define_guarded_writers
end
if __FILE__ == $0
- require "test/unit"
-
- class DefineAccessorsTest < Test::Unit::TestCase
- def setup
- @X = Class.new
- @Y = Class.new @X
- @x = @X.new
- @y = @Y.new
- end
+ require "test/unit"
+
+ class DefineAccessorsTest < Test::Unit::TestCase
+ def setup
+ @X = Class.new
+ @Y = Class.new @X
+ @x = @X.new
+ @y = @Y.new
+ end
- def test_define_hard_aliases
- @X.define_method(:foo) { 123 }
- @X.define_method(:baz) { 321 }
- @X.define_hard_aliases :bar => :foo, :quux => :baz
- assert_equal @x.foo, 123
- assert_equal @x.bar, 123
- assert_equal @y.foo, 123
- assert_equal @y.bar, 123
- assert_equal @x.baz, 321
- assert_equal @x.quux, 321
- assert_equal @y.baz, 321
- assert_equal @y.quux, 321
- @Y.define_method(:foo) { 456 }
- assert_equal @y.foo, 456
- assert_equal @y.bar, 123
- @Y.define_method(:quux) { 654 }
- assert_equal @y.baz, 321
- assert_equal @y.quux, 654
- end
+ def test_define_hard_aliases
+ @X.define_method(:foo) { 123 }
+ @X.define_method(:baz) { 321 }
+ @X.define_hard_aliases :bar => :foo, :quux => :baz
+ assert_equal @x.foo, 123
+ assert_equal @x.bar, 123
+ assert_equal @y.foo, 123
+ assert_equal @y.bar, 123
+ assert_equal @x.baz, 321
+ assert_equal @x.quux, 321
+ assert_equal @y.baz, 321
+ assert_equal @y.quux, 321
+ @Y.define_method(:foo) { 456 }
+ assert_equal @y.foo, 456
+ assert_equal @y.bar, 123
+ @Y.define_method(:quux) { 654 }
+ assert_equal @y.baz, 321
+ assert_equal @y.quux, 654
+ end
- def test_define_soft_aliases
- @X.define_method(:foo) { 123 }
- @X.define_method(:baz) { 321 }
- @X.define_soft_aliases :bar => :foo, :quux => :baz
- assert_equal @x.foo, 123
- assert_equal @x.bar, 123
- assert_equal @y.foo, 123
- assert_equal @y.bar, 123
- assert_equal @x.baz, 321
- assert_equal @x.quux, 321
- assert_equal @y.baz, 321
- assert_equal @y.quux, 321
- @Y.define_method(:foo) { 456 }
- assert_equal @y.foo, @y.bar, 456
- @Y.define_method(:quux) { 654 }
- assert_equal @y.baz, 321
- assert_equal @y.quux, 654
- end
+ def test_define_soft_aliases
+ @X.define_method(:foo) { 123 }
+ @X.define_method(:baz) { 321 }
+ @X.define_soft_aliases :bar => :foo, :quux => :baz
+ assert_equal @x.foo, 123
+ assert_equal @x.bar, 123
+ assert_equal @y.foo, 123
+ assert_equal @y.bar, 123
+ assert_equal @x.baz, 321
+ assert_equal @x.quux, 321
+ assert_equal @y.baz, 321
+ assert_equal @y.quux, 321
+ @Y.define_method(:foo) { 456 }
+ assert_equal @y.foo, @y.bar, 456
+ @Y.define_method(:quux) { 654 }
+ assert_equal @y.baz, 321
+ assert_equal @y.quux, 654
+ end
- def test_define_readers
- @X.define_readers :foo, :bar
- assert !@x.respond_to?(:foo=)
- assert !@x.respond_to?(:bar=)
- @x.instance_eval { @foo = 123 ; @bar = 456 }
- assert_equal @x.foo, 123
- assert_equal @x.bar, 456
- @X.define_readers :baz?, :quux?
- assert !@x.respond_to?(:baz=)
- assert !@x.respond_to?(:quux=)
- @x.instance_eval { @baz = false ; @quux = true }
- assert !@x.baz?
- assert @x.quux?
- end
+ def test_define_readers
+ @X.define_readers :foo, :bar
+ assert !@x.respond_to?(:foo=)
+ assert !@x.respond_to?(:bar=)
+ @x.instance_eval { @foo = 123 ; @bar = 456 }
+ assert_equal @x.foo, 123
+ assert_equal @x.bar, 456
+ @X.define_readers :baz?, :quux?
+ assert !@x.respond_to?(:baz=)
+ assert !@x.respond_to?(:quux=)
+ @x.instance_eval { @baz = false ; @quux = true }
+ assert !@x.baz?
+ assert @x.quux?
+ end
- def test_define_writers
- assert !@X.writer_defined?(:foo)
- assert !@X.writer_defined?(:bar)
- @X.define_writers :foo, :bar
- assert @X.writer_defined?(:foo)
- assert @X.writer_defined?(:bar)
- assert @X.writer_defined?(:foo=)
- assert @X.writer_defined?(:bar=)
- assert @X.writer_defined?(:foo?)
- assert @X.writer_defined?(:bar?)
- assert !@x.respond_to?(:foo)
- assert !@x.respond_to?(:bar)
- @x.foo = 123
- @x.bar = 456
- assert_equal @x.instance_eval { @foo }, 123
- assert_equal @x.instance_eval { @bar }, 456
- @X.define_writers :baz?, :quux?
- assert !@x.respond_to?(:baz?)
- assert !@x.respond_to?(:quux?)
- @x.baz = true
- @x.quux = false
- assert_equal @x.instance_eval { @baz }, true
- assert_equal @x.instance_eval { @quux }, false
- end
+ def test_define_writers
+ assert !@X.writer_defined?(:foo)
+ assert !@X.writer_defined?(:bar)
+ @X.define_writers :foo, :bar
+ assert @X.writer_defined?(:foo)
+ assert @X.writer_defined?(:bar)
+ assert @X.writer_defined?(:foo=)
+ assert @X.writer_defined?(:bar=)
+ assert @X.writer_defined?(:foo?)
+ assert @X.writer_defined?(:bar?)
+ assert !@x.respond_to?(:foo)
+ assert !@x.respond_to?(:bar)
+ @x.foo = 123
+ @x.bar = 456
+ assert_equal @x.instance_eval { @foo }, 123
+ assert_equal @x.instance_eval { @bar }, 456
+ @X.define_writers :baz?, :quux?
+ assert !@x.respond_to?(:baz?)
+ assert !@x.respond_to?(:quux?)
+ @x.baz = true
+ @x.quux = false
+ assert_equal @x.instance_eval { @baz }, true
+ assert_equal @x.instance_eval { @quux }, false
+ end
- def test_define_accessors
- @X.define_accessors :foo, :bar
- @x.foo = 123 ; @x.bar = 456
- assert_equal @x.foo, 123
- assert_equal @x.bar, 456
- end
+ def test_define_accessors
+ @X.define_accessors :foo, :bar
+ @x.foo = 123 ; @x.bar = 456
+ assert_equal @x.foo, 123
+ assert_equal @x.bar, 456
+ end
- def test_define_opposite_readers
- @X.define_opposite_readers :foo? => :bar?, :baz? => :quux?
- assert !@x.respond_to?(:foo=)
- assert !@x.respond_to?(:bar=)
- assert !@x.respond_to?(:baz=)
- assert !@x.respond_to?(:quux=)
- @x.instance_eval { @bar = true ; @quux = false }
- assert !@x.foo?
- assert @x.bar?
- assert @x.baz?
- assert !@x.quux?
- end
+ def test_define_opposite_readers
+ @X.define_opposite_readers :foo? => :bar?, :baz? => :quux?
+ assert !@x.respond_to?(:foo=)
+ assert !@x.respond_to?(:bar=)
+ assert !@x.respond_to?(:baz=)
+ assert !@x.respond_to?(:quux=)
+ @x.instance_eval { @bar = true ; @quux = false }
+ assert !@x.foo?
+ assert @x.bar?
+ assert @x.baz?
+ assert !@x.quux?
+ end
- def test_define_opposite_writers
- @X.define_opposite_writers :foo? => :bar?, :baz => :quux
- end
+ def test_define_opposite_writers
+ @X.define_opposite_writers :foo? => :bar?, :baz => :quux
end
+ end
end
diff --git a/lib/puppet/external/event-loop/event-loop.rb b/lib/puppet/external/event-loop/event-loop.rb
index bd278556c..dc51a55ae 100644
--- a/lib/puppet/external/event-loop/event-loop.rb
+++ b/lib/puppet/external/event-loop/event-loop.rb
@@ -23,329 +23,329 @@ require "puppet/external/event-loop/signal-system"
require "fcntl"
class EventLoop
- include SignalEmitter
-
- IO_STATES = [:readable, :writable, :exceptional]
-
- class << self
- def default ; @default ||= new end
- def default= x ; @default = x end
-
- def current
- Thread.current["event-loop::current"] || default end
- def current= x
- Thread.current["event-loop::current"] = x end
-
- def with_current (new)
- if current == new
- yield
- else
- begin
- old = self.current
- self.current = new
- yield
- ensure
- self.current = old
- end
- end
- end
-
- def method_missing (name, *args, &block)
- if current.respond_to? name
- current.__send__(name, *args, &block)
- else
- super
- end
+ include SignalEmitter
+
+ IO_STATES = [:readable, :writable, :exceptional]
+
+ class << self
+ def default ; @default ||= new end
+ def default= x ; @default = x end
+
+ def current
+ Thread.current["event-loop::current"] || default end
+ def current= x
+ Thread.current["event-loop::current"] = x end
+
+ def with_current (new)
+ if current == new
+ yield
+ else
+ begin
+ old = self.current
+ self.current = new
+ yield
+ ensure
+ self.current = old
end
+ end
end
- define_signals :before_sleep, :after_sleep
-
- def initialize
- @running = false
- @awake = false
- @wakeup_time = nil
- @timers = []
-
- @io_arrays = [[], [], []]
- @ios = Hash.new do |h, k| raise ArgumentError,
- "invalid IO event: #{k}", caller(2) end
- IO_STATES.each_with_index { |x, i| @ios[x] = @io_arrays[i] }
-
- @notify_src, @notify_snk = IO.pipe
-
- # prevent file descriptor leaks
- @notify_src.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
- @notify_snk.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
-
- @notify_src.will_block = false
- @notify_snk.will_block = false
-
- # Each time a byte is sent through the notification pipe
- # we need to read it, or IO.select will keep returning.
- monitor_io(@notify_src, :readable)
- @notify_src.extend(Watchable)
- @notify_src.on_readable do
- begin
- @notify_src.sysread(256)
- rescue Errno::EAGAIN
- # The pipe wasn't readable after all.
- end
- end
+ def method_missing (name, *args, &block)
+ if current.respond_to? name
+ current.__send__(name, *args, &block)
+ else
+ super
+ end
end
-
- define_opposite_accessors \
- :stopped? => :running?,
- :sleeping? => :awake?
-
- def run
- if block_given?
- thread = Thread.new { run }
- yield ; quit ; thread.join
- else
- running!
- iterate while running?
- end
- ensure
- quit
+ end
+
+ define_signals :before_sleep, :after_sleep
+
+ def initialize
+ @running = false
+ @awake = false
+ @wakeup_time = nil
+ @timers = []
+
+ @io_arrays = [[], [], []]
+ @ios = Hash.new do |h, k| raise ArgumentError,
+ "invalid IO event: #{k}", caller(2) end
+ IO_STATES.each_with_index { |x, i| @ios[x] = @io_arrays[i] }
+
+ @notify_src, @notify_snk = IO.pipe
+
+ # prevent file descriptor leaks
+ @notify_src.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+ @notify_snk.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+
+ @notify_src.will_block = false
+ @notify_snk.will_block = false
+
+ # Each time a byte is sent through the notification pipe
+ # we need to read it, or IO.select will keep returning.
+ monitor_io(@notify_src, :readable)
+ @notify_src.extend(Watchable)
+ @notify_src.on_readable do
+ begin
+ @notify_src.sysread(256)
+ rescue Errno::EAGAIN
+ # The pipe wasn't readable after all.
+ end
end
-
- def iterate (user_timeout=nil)
- t1, t2 = user_timeout, max_timeout
- timeout = t1 && t2 ? [t1, t2].min : t1 || t2
- select(timeout).zip(IO_STATES) do |ios, state|
- ios.each { |x| x.signal(state) } if ios
- end
+ end
+
+ define_opposite_accessors \
+ :stopped? => :running?,
+ :sleeping? => :awake?
+
+ def run
+ if block_given?
+ thread = Thread.new { run }
+ yield ; quit ; thread.join
+ else
+ running!
+ iterate while running?
+ end
+ ensure
+ quit
+ end
+
+ def iterate (user_timeout=nil)
+ t1, t2 = user_timeout, max_timeout
+ timeout = t1 && t2 ? [t1, t2].min : t1 || t2
+ select(timeout).zip(IO_STATES) do |ios, state|
+ ios.each { |x| x.signal(state) } if ios
end
+ end
- private
+ private
- def select (timeout)
- @wakeup_time = timeout ? Time.now + timeout : nil
- # puts "waiting: #{timeout} seconds"
- signal :before_sleep ; sleeping!
- IO.select(*@io_arrays + [timeout]) || []
- ensure
- awake! ; signal :after_sleep
- @timers.each { |x| x.sound_alarm if x.ready? }
- end
+ def select (timeout)
+ @wakeup_time = timeout ? Time.now + timeout : nil
+ # puts "waiting: #{timeout} seconds"
+ signal :before_sleep ; sleeping!
+ IO.select(*@io_arrays + [timeout]) || []
+ ensure
+ awake! ; signal :after_sleep
+ @timers.each { |x| x.sound_alarm if x.ready? }
+ end
- public
+ public
- def quit ; stopped! ; wake_up ; self end
+ def quit ; stopped! ; wake_up ; self end
- def monitoring_io? (io, event)
- @ios[event].include? io end
- def monitoring_timer? (timer)
- @timers.include? timer end
+ def monitoring_io? (io, event)
+ @ios[event].include? io end
+ def monitoring_timer? (timer)
+ @timers.include? timer end
- def monitor_io (io, *events)
- for event in events do
- @ios[event] << io ; wake_up unless monitoring_io?(io, event)
- end
+ def monitor_io (io, *events)
+ for event in events do
+ @ios[event] << io ; wake_up unless monitoring_io?(io, event)
end
+ end
- def monitor_timer (timer)
- @timers << timer unless monitoring_timer? timer
- end
+ def monitor_timer (timer)
+ @timers << timer unless monitoring_timer? timer
+ end
- def check_timer (timer)
- wake_up if timer.end_time < @wakeup_time
- end
+ def check_timer (timer)
+ wake_up if timer.end_time < @wakeup_time
+ end
- def ignore_io (io, *events)
- events = IO_STATES if events.empty?
- for event in events do
- wake_up if @ios[event].delete(io)
- end
+ def ignore_io (io, *events)
+ events = IO_STATES if events.empty?
+ for event in events do
+ wake_up if @ios[event].delete(io)
end
+ end
- def ignore_timer (timer)
- # Don't need to wake up for this.
- @timers.delete(timer)
- end
+ def ignore_timer (timer)
+ # Don't need to wake up for this.
+ @timers.delete(timer)
+ end
- def max_timeout
- return nil if @timers.empty?
- [@timers.collect { |x| x.time_left }.min, 0].max
- end
+ def max_timeout
+ return nil if @timers.empty?
+ [@timers.collect { |x| x.time_left }.min, 0].max
+ end
- def wake_up
- @notify_snk.write('.') if sleeping?
- end
+ def wake_up
+ @notify_snk.write('.') if sleeping?
+ end
end
class Symbol
- def io_state?
- EventLoop::IO_STATES.include? self
- end
+ def io_state?
+ EventLoop::IO_STATES.include? self
+ end
end
module EventLoop::Watchable
- include SignalEmitter
+ include SignalEmitter
- define_signals :readable, :writable, :exceptional
+ define_signals :readable, :writable, :exceptional
- def monitor_events (*events)
- EventLoop.monitor_io(self, *events) end
- def ignore_events (*events)
- EventLoop.ignore_io(self, *events) end
+ def monitor_events (*events)
+ EventLoop.monitor_io(self, *events) end
+ def ignore_events (*events)
+ EventLoop.ignore_io(self, *events) end
- define_soft_aliases \
- :monitor_event => :monitor_events,
- :ignore_event => :ignore_events
+ define_soft_aliases \
+ :monitor_event => :monitor_events,
+ :ignore_event => :ignore_events
- def close ; super
- ignore_events end
- def close_read ; super
- ignore_event :readable end
- def close_write ; super
- ignore_event :writable end
+ def close ; super
+ ignore_events end
+ def close_read ; super
+ ignore_event :readable end
+ def close_write ; super
+ ignore_event :writable end
- module Automatic
- include EventLoop::Watchable
+ module Automatic
+ include EventLoop::Watchable
- def add_signal_handler (name, &handler) super
- monitor_event(name) if name.io_state?
- end
+ def add_signal_handler (name, &handler) super
+ monitor_event(name) if name.io_state?
+ end
- def remove_signal_handler (name, handler) super
- if @signal_handlers[name].empty?
- ignore_event(name) if name.io_state?
- end
- end
+ def remove_signal_handler (name, handler) super
+ if @signal_handlers[name].empty?
+ ignore_event(name) if name.io_state?
+ end
end
+ end
end
class IO
- def on_readable &block
- extend EventLoop::Watchable::Automatic
- on_readable(&block)
- end
-
- def on_writable &block
- extend EventLoop::Watchable::Automatic
- on_writable(&block)
- end
-
- def on_exceptional &block
- extend EventLoop::Watchable::Automatic
- on_exceptional(&block)
- end
-
- def will_block?
- require "fcntl"
- fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK == 0
- end
-
- def will_block= (wants_blocking)
- require "fcntl"
- flags = fcntl(Fcntl::F_GETFL, 0)
- if wants_blocking
- flags &= ~Fcntl::O_NONBLOCK
- else
- flags |= Fcntl::O_NONBLOCK
- end
- fcntl(Fcntl::F_SETFL, flags)
+ def on_readable &block
+ extend EventLoop::Watchable::Automatic
+ on_readable(&block)
+ end
+
+ def on_writable &block
+ extend EventLoop::Watchable::Automatic
+ on_writable(&block)
+ end
+
+ def on_exceptional &block
+ extend EventLoop::Watchable::Automatic
+ on_exceptional(&block)
+ end
+
+ def will_block?
+ require "fcntl"
+ fcntl(Fcntl::F_GETFL, 0) & Fcntl::O_NONBLOCK == 0
+ end
+
+ def will_block= (wants_blocking)
+ require "fcntl"
+ flags = fcntl(Fcntl::F_GETFL, 0)
+ if wants_blocking
+ flags &= ~Fcntl::O_NONBLOCK
+ else
+ flags |= Fcntl::O_NONBLOCK
end
+ fcntl(Fcntl::F_SETFL, flags)
+ end
end
class EventLoop::Timer
- include SignalEmitter
+ include SignalEmitter
- DEFAULT_INTERVAL = 0.0
- DEFAULT_TOLERANCE = 0.001
+ DEFAULT_INTERVAL = 0.0
+ DEFAULT_TOLERANCE = 0.001
- def initialize (options={}, &handler)
- @running = false
- @start_time = nil
+ def initialize (options={}, &handler)
+ @running = false
+ @start_time = nil
- options = { :interval => options } if options.kind_of? Numeric
+ options = { :interval => options } if options.kind_of? Numeric
- if options[:interval]
- @interval = options[:interval].to_f
- else
- @interval = DEFAULT_INTERVAL
- end
-
- if options[:tolerance]
- @tolerance = options[:tolerance].to_f
- elsif DEFAULT_TOLERANCE < @interval
- @tolerance = DEFAULT_TOLERANCE
- else
- @tolerance = 0.0
- end
-
- @event_loop = options[:event_loop] || EventLoop.current
-
- if block_given?
- add_signal_handler(:alarm, &handler)
- start unless options[:start?] == false
- else
- start if options[:start?]
- end
+ if options[:interval]
+ @interval = options[:interval].to_f
+ else
+ @interval = DEFAULT_INTERVAL
end
- define_readers :interval, :tolerance
- define_signal :alarm
-
- def stopped? ; @start_time == nil end
- def running? ; @start_time != nil end
-
- def interval= (new_interval)
- old_interval = @interval
- @interval = new_interval
- @event_loop.check_timer(self) if new_interval < old_interval
- end
-
- def end_time
- @start_time + @interval end
- def time_left
- end_time - Time.now end
- def ready?
- time_left <= @tolerance end
-
- def restart
- @start_time = Time.now
+ if options[:tolerance]
+ @tolerance = options[:tolerance].to_f
+ elsif DEFAULT_TOLERANCE < @interval
+ @tolerance = DEFAULT_TOLERANCE
+ else
+ @tolerance = 0.0
end
- def sound_alarm
- signal :alarm
- restart if running?
- end
+ @event_loop = options[:event_loop] || EventLoop.current
- def start
- @start_time = Time.now
- @event_loop.monitor_timer(self)
- end
-
- def stop
- @start_time = nil
- @event_loop.ignore_timer(self)
+ if block_given?
+ add_signal_handler(:alarm, &handler)
+ start unless options[:start?] == false
+ else
+ start if options[:start?]
end
+ end
+
+ define_readers :interval, :tolerance
+ define_signal :alarm
+
+ def stopped? ; @start_time == nil end
+ def running? ; @start_time != nil end
+
+ def interval= (new_interval)
+ old_interval = @interval
+ @interval = new_interval
+ @event_loop.check_timer(self) if new_interval < old_interval
+ end
+
+ def end_time
+ @start_time + @interval end
+ def time_left
+ end_time - Time.now end
+ def ready?
+ time_left <= @tolerance end
+
+ def restart
+ @start_time = Time.now
+ end
+
+ def sound_alarm
+ signal :alarm
+ restart if running?
+ end
+
+ def start
+ @start_time = Time.now
+ @event_loop.monitor_timer(self)
+ end
+
+ def stop
+ @start_time = nil
+ @event_loop.ignore_timer(self)
+ end
end
if __FILE__ == $0
- require "test/unit"
+ require "test/unit"
- class TimerTest < Test::Unit::TestCase
- def setup
- @timer = EventLoop::Timer.new(:interval => 0.001)
- end
+ class TimerTest < Test::Unit::TestCase
+ def setup
+ @timer = EventLoop::Timer.new(:interval => 0.001)
+ end
- def test_timer
- @timer.on_alarm do
- puts "[#{@timer.time_left} seconds left after alarm]"
- EventLoop.quit
- end
- 8.times do
- t0 = Time.now
- @timer.start ; EventLoop.run
- t1 = Time.now
- assert(t1 - t0 > @timer.interval - @timer.tolerance)
- end
- end
+ def test_timer
+ @timer.on_alarm do
+ puts "[#{@timer.time_left} seconds left after alarm]"
+ EventLoop.quit
+ end
+ 8.times do
+ t0 = Time.now
+ @timer.start ; EventLoop.run
+ t1 = Time.now
+ assert(t1 - t0 > @timer.interval - @timer.tolerance)
+ end
end
+ end
end
## event-loop.rb ends here.
diff --git a/lib/puppet/external/event-loop/signal-system.rb b/lib/puppet/external/event-loop/signal-system.rb
index 09498c9f4..d3c924bf8 100644
--- a/lib/puppet/external/event-loop/signal-system.rb
+++ b/lib/puppet/external/event-loop/signal-system.rb
@@ -20,84 +20,84 @@
require "puppet/external/event-loop/better-definers"
module SignalEmitterModule
- def self.extended (object)
- if object.kind_of? Module and not object < SignalEmitter
- if object.respond_to? :fcall
- # This is the way to call private methods
- # in Ruby 1.9 as of November 16.
- object.fcall :include, SignalEmitter
- else
- object.__send__ :include, SignalEmitter
- end
- end
- end
-
- def define_signal (name, slot=:before, &body)
- # Can't use `define_method' and take a block pre-1.9.
- class_eval %{ def on_#{name} &block
- add_signal_handler(:#{name}, &block) end }
- define_signal_handler(name, :before, &lambda {|*a|})
- define_signal_handler(name, :after, &lambda {|*a|})
- define_signal_handler(name, slot, &body) if block_given?
- end
-
- def define_signals (*names, &body)
- names.each { |x| define_signal(x, &body) }
- end
-
- def define_signal_handler (name, slot=:before, &body)
- case slot
- when :before
- define_protected_method "handle_#{name}", &body
- when :after
- define_protected_method "after_handle_#{name}", &body
- else
- raise ArgumentError, "invalid slot `#{slot.inspect}'; " +
- "should be `:before' or `:after'", caller(1)
- end
- end
+ def self.extended (object)
+ if object.kind_of? Module and not object < SignalEmitter
+ if object.respond_to? :fcall
+ # This is the way to call private methods
+ # in Ruby 1.9 as of November 16.
+ object.fcall :include, SignalEmitter
+ else
+ object.__send__ :include, SignalEmitter
+ end
+ end
+ end
+
+ def define_signal (name, slot=:before, &body)
+ # Can't use `define_method' and take a block pre-1.9.
+ class_eval %{ def on_#{name} &block
+ add_signal_handler(:#{name}, &block) end }
+ define_signal_handler(name, :before, &lambda {|*a|})
+ define_signal_handler(name, :after, &lambda {|*a|})
+ define_signal_handler(name, slot, &body) if block_given?
+ end
+
+ def define_signals (*names, &body)
+ names.each { |x| define_signal(x, &body) }
+ end
+
+ def define_signal_handler (name, slot=:before, &body)
+ case slot
+ when :before
+ define_protected_method "handle_#{name}", &body
+ when :after
+ define_protected_method "after_handle_#{name}", &body
+ else
+ raise ArgumentError, "invalid slot `#{slot.inspect}'; " +
+ "should be `:before' or `:after'", caller(1)
+ end
+ end
end
# This is an old name for the same thing.
SignalEmitterClass = SignalEmitterModule
module SignalEmitter
- def self.included (includer)
- includer.extend SignalEmitterClass if not includer.kind_of? SignalEmitterClass
- end
-
- def __maybe_initialize_signal_emitter
- @signal_handlers ||= Hash.new { |h, k| h[k] = Array.new }
- @allow_dynamic_signals ||= false
- end
-
- define_accessors :allow_dynamic_signals?
-
- def add_signal_handler (name, &handler)
- __maybe_initialize_signal_emitter
- @signal_handlers[name] << handler
- handler
- end
-
- define_soft_aliases [:on, :on_signal] => :add_signal_handler
-
- def remove_signal_handler (name, handler)
- __maybe_initialize_signal_emitter
- @signal_handlers[name].delete(handler)
- end
-
- def __signal__ (name, *args, &block)
- __maybe_initialize_signal_emitter
- respond_to? "on_#{name}" or allow_dynamic_signals? or
- fail "undefined signal `#{name}' for #{self}:#{self.class}"
- __send__("handle_#{name}", *args, &block) if
- respond_to? "handle_#{name}"
- @signal_handlers[name].each { |x| x.call(*args, &block) }
- __send__("after_handle_#{name}", *args, &block) if
- respond_to? "after_handle_#{name}"
- end
-
- define_soft_alias :signal => :__signal__
+ def self.included (includer)
+ includer.extend SignalEmitterClass if not includer.kind_of? SignalEmitterClass
+ end
+
+ def __maybe_initialize_signal_emitter
+ @signal_handlers ||= Hash.new { |h, k| h[k] = Array.new }
+ @allow_dynamic_signals ||= false
+ end
+
+ define_accessors :allow_dynamic_signals?
+
+ def add_signal_handler (name, &handler)
+ __maybe_initialize_signal_emitter
+ @signal_handlers[name] << handler
+ handler
+ end
+
+ define_soft_aliases [:on, :on_signal] => :add_signal_handler
+
+ def remove_signal_handler (name, handler)
+ __maybe_initialize_signal_emitter
+ @signal_handlers[name].delete(handler)
+ end
+
+ def __signal__ (name, *args, &block)
+ __maybe_initialize_signal_emitter
+ respond_to? "on_#{name}" or allow_dynamic_signals? or
+ fail "undefined signal `#{name}' for #{self}:#{self.class}"
+ __send__("handle_#{name}", *args, &block) if
+ respond_to? "handle_#{name}"
+ @signal_handlers[name].each { |x| x.call(*args, &block) }
+ __send__("after_handle_#{name}", *args, &block) if
+ respond_to? "after_handle_#{name}"
+ end
+
+ define_soft_alias :signal => :__signal__
end
# This module is indended to be a convenience mixin to be used by
@@ -111,108 +111,108 @@ end
# XXX: This has not seen much use, and I'd like to provide a
# better solution for the problem in the future.
module SignalObserver
- def __maybe_initialize_signal_observer
- @observed_signals ||= Hash.new do |signals, object|
- signals[object] = Hash.new do |handlers, name|
- handlers[name] = Array.new
- end
- end
- end
-
- def observe_signal (subject, name, &handler)
- __maybe_initialize_signal_observer
- @observed_signals[subject][name] << handler
- subject.add_signal_handler(name, &handler)
- end
+ def __maybe_initialize_signal_observer
+ @observed_signals ||= Hash.new do |signals, object|
+ signals[object] = Hash.new do |handlers, name|
+ handlers[name] = Array.new
+ end
+ end
+ end
+
+ def observe_signal (subject, name, &handler)
+ __maybe_initialize_signal_observer
+ @observed_signals[subject][name] << handler
+ subject.add_signal_handler(name, &handler)
+ end
+
+ def map_signals (source, pairs={})
+ pairs.each do |src_name, dst_name|
+ observe_signal(source, src_name) do |*args|
+ __signal__(dst_name, *args)
+ end
+ end
+ end
+
+ def absorb_signals (subject, *names)
+ names.each do |name|
+ observe_signal(subject, name) do |*args|
+ __signal__(name, *args)
+ end
+ end
+ end
+
+ define_soft_aliases \
+ :map_signal => :map_signals,
+ :absorb_signal => :absorb_signals
+
+ def ignore_signal (subject, name)
+ __maybe_initialize_signal_observer
+ __ignore_signal_1(subject, name)
+ @observed_signals.delete(subject) if
+ @observed_signals[subject].empty?
+ end
+
+ def ignore_signals (subject, *names)
+ __maybe_initialize_signal_observer
+ names = @observed_signals[subject] if names.empty?
+ names.each { |x| __ignore_signal_1(subject, x) }
+ end
+
+ private
+
+ def __ignore_signal_1(subject, name)
+ @observed_signals[subject][name].each do |handler|
+ subject.remove_signal_handler(name, handler) end
+ @observed_signals[subject].delete(name)
+ end
+end
- def map_signals (source, pairs={})
- pairs.each do |src_name, dst_name|
- observe_signal(source, src_name) do |*args|
- __signal__(dst_name, *args)
- end
- end
+if __FILE__ == $0
+ require "test/unit"
+ class SignalEmitterTest < Test::Unit::TestCase
+ class X
+ include SignalEmitter
+ define_signal :foo
end
- def absorb_signals (subject, *names)
- names.each do |name|
- observe_signal(subject, name) do |*args|
- __signal__(name, *args)
- end
- end
+ def setup
+ @x = X.new
end
- define_soft_aliases \
- :map_signal => :map_signals,
- :absorb_signal => :absorb_signals
-
- def ignore_signal (subject, name)
- __maybe_initialize_signal_observer
- __ignore_signal_1(subject, name)
- @observed_signals.delete(subject) if
- @observed_signals[subject].empty?
+ def test_on_signal
+ moomin = 0
+ @x.on_signal(:foo) { moomin = 1 }
+ @x.signal :foo
+ assert moomin == 1
end
- def ignore_signals (subject, *names)
- __maybe_initialize_signal_observer
- names = @observed_signals[subject] if names.empty?
- names.each { |x| __ignore_signal_1(subject, x) }
+ def test_on_foo
+ moomin = 0
+ @x.on_foo { moomin = 1 }
+ @x.signal :foo
+ assert moomin == 1
end
- private
-
- def __ignore_signal_1(subject, name)
- @observed_signals[subject][name].each do |handler|
- subject.remove_signal_handler(name, handler) end
- @observed_signals[subject].delete(name)
+ def test_multiple_on_signal
+ moomin = 0
+ @x.on_signal(:foo) { moomin += 1 }
+ @x.on_signal(:foo) { moomin += 2 }
+ @x.on_signal(:foo) { moomin += 4 }
+ @x.on_signal(:foo) { moomin += 8 }
+ @x.signal :foo
+ assert moomin == 15
end
-end
-if __FILE__ == $0
- require "test/unit"
- class SignalEmitterTest < Test::Unit::TestCase
- class X
- include SignalEmitter
- define_signal :foo
- end
-
- def setup
- @x = X.new
- end
-
- def test_on_signal
- moomin = 0
- @x.on_signal(:foo) { moomin = 1 }
- @x.signal :foo
- assert moomin == 1
- end
-
- def test_on_foo
- moomin = 0
- @x.on_foo { moomin = 1 }
- @x.signal :foo
- assert moomin == 1
- end
-
- def test_multiple_on_signal
- moomin = 0
- @x.on_signal(:foo) { moomin += 1 }
- @x.on_signal(:foo) { moomin += 2 }
- @x.on_signal(:foo) { moomin += 4 }
- @x.on_signal(:foo) { moomin += 8 }
- @x.signal :foo
- assert moomin == 15
- end
-
- def test_multiple_on_foo
- moomin = 0
- @x.on_foo { moomin += 1 }
- @x.on_foo { moomin += 2 }
- @x.on_foo { moomin += 4 }
- @x.on_foo { moomin += 8 }
- @x.signal :foo
- assert moomin == 15
- end
+ def test_multiple_on_foo
+ moomin = 0
+ @x.on_foo { moomin += 1 }
+ @x.on_foo { moomin += 2 }
+ @x.on_foo { moomin += 4 }
+ @x.on_foo { moomin += 8 }
+ @x.signal :foo
+ assert moomin == 15
end
+ end
end
## application-signals.rb ends here.
diff --git a/lib/puppet/external/lock.rb b/lib/puppet/external/lock.rb
index 785ecd637..024fedf3d 100644
--- a/lib/puppet/external/lock.rb
+++ b/lib/puppet/external/lock.rb
@@ -15,49 +15,49 @@ require 'sync'
$reader_count = Hash.new(0)
class File
- # Get an exclusive (i.e., write) lock on the file, and yield to the block.
- # If the lock is not available, wait for it without blocking other ruby
- # threads.
- def lock_exclusive
- if Thread.list.size == 1
- flock(LOCK_EX)
- else
- # ugly hack because waiting for a lock in a Ruby thread blocks the
- # process
- period = 0.001
- until flock(LOCK_EX|LOCK_NB)
- sleep period
- period *= 2 if period < 1
- end
- end
-
- yield self
- ensure
- flush
- flock(LOCK_UN)
+ # Get an exclusive (i.e., write) lock on the file, and yield to the block.
+ # If the lock is not available, wait for it without blocking other ruby
+ # threads.
+ def lock_exclusive
+ if Thread.list.size == 1
+ flock(LOCK_EX)
+ else
+ # ugly hack because waiting for a lock in a Ruby thread blocks the
+ # process
+ period = 0.001
+ until flock(LOCK_EX|LOCK_NB)
+ sleep period
+ period *= 2 if period < 1
+ end
end
- # Get a shared (i.e., read) lock on the file, and yield to the block.
- # If the lock is not available, wait for it without blocking other ruby
- # threads.
- def lock_shared
- if Thread.list.size == 1
- flock(LOCK_SH)
- else
- # ugly hack because waiting for a lock in a Ruby thread blocks the
- # process
- period = 0.001
- until flock(LOCK_SH|LOCK_NB)
- sleep period
- period *= 2 if period < 1
- end
- end
-
- yield self
- ensure
- Thread.exclusive {flock(LOCK_UN) if $reader_count[self.stat.ino] == 1}
- ## for solaris, no need to unlock here--closing does it
- ## but this has no effect on the bug
+ yield self
+ ensure
+ flush
+ flock(LOCK_UN)
+ end
+
+ # Get a shared (i.e., read) lock on the file, and yield to the block.
+ # If the lock is not available, wait for it without blocking other ruby
+ # threads.
+ def lock_shared
+ if Thread.list.size == 1
+ flock(LOCK_SH)
+ else
+ # ugly hack because waiting for a lock in a Ruby thread blocks the
+ # process
+ period = 0.001
+ until flock(LOCK_SH|LOCK_NB)
+ sleep period
+ period *= 2 if period < 1
+ end
end
+
+ yield self
+ ensure
+ Thread.exclusive {flock(LOCK_UN) if $reader_count[self.stat.ino] == 1}
+ ## for solaris, no need to unlock here--closing does it
+ ## but this has no effect on the bug
+ end
end
diff --git a/lib/puppet/external/nagios.rb b/lib/puppet/external/nagios.rb
index 2dd040dba..6b8852ee5 100755
--- a/lib/puppet/external/nagios.rb
+++ b/lib/puppet/external/nagios.rb
@@ -12,39 +12,39 @@ require 'puppet/external/nagios/parser.rb'
require 'puppet/external/nagios/base.rb'
module Nagios
- NAGIOSVERSION = '1.1'
- # yay colors
- PINK = ""
- GREEN = ""
- YELLOW = ""
- SLATE = ""
- ORANGE = ""
- BLUE = ""
- NOCOLOR = ""
- RESET = ""
-
- def self.version
- NAGIOSVERSION
+ NAGIOSVERSION = '1.1'
+ # yay colors
+ PINK = ""
+ GREEN = ""
+ YELLOW = ""
+ SLATE = ""
+ ORANGE = ""
+ BLUE = ""
+ NOCOLOR = ""
+ RESET = ""
+
+ def self.version
+ NAGIOSVERSION
+ end
+
+ class Config
+ def Config.import(config)
+
+ text = String.new
+
+ File.open(config) { |file|
+ file.each { |line|
+ text += line
+ }
+ }
+ parser = Nagios::Parser.new
+ parser.parse(text)
end
- class Config
- def Config.import(config)
-
- text = String.new
-
- File.open(config) { |file|
- file.each { |line|
- text += line
- }
- }
- parser = Nagios::Parser.new
- parser.parse(text)
- end
-
- def Config.each
- Nagios::Object.objects.each { |object|
- yield object
- }
- end
+ def Config.each
+ Nagios::Object.objects.each { |object|
+ yield object
+ }
end
+ end
end
diff --git a/lib/puppet/external/nagios/base.rb b/lib/puppet/external/nagios/base.rb
index 6e3b0038d..ac1d25e2e 100755
--- a/lib/puppet/external/nagios/base.rb
+++ b/lib/puppet/external/nagios/base.rb
@@ -2,472 +2,472 @@
# is mostly just data.
class Nagios::Base
- class UnknownNagiosType < RuntimeError # When an unknown type is asked for by name.
- end
-
- include Enumerable
-
- class << self
- attr_accessor :parameters, :derivatives, :ocs, :name, :att
- attr_accessor :ldapbase
-
- attr_writer :namevar
-
- attr_reader :superior
- end
-
- # Attach one class to another.
- def self.attach(hash)
- @attach ||= {}
- hash.each do |n, v| @attach[n] = v end
- end
-
- # Convert a parameter to camelcase
- def self.camelcase(param)
- param.gsub(/_./) do |match|
- match.sub(/_/,'').capitalize
- end
- end
-
- # Uncamelcase a parameter.
- def self.decamelcase(param)
- param.gsub(/[A-Z]/) do |match|
- "_#{match.downcase}"
- end
- end
-
- # Create a new instance of a given class.
- def self.create(name, args = {})
- name = name.intern if name.is_a? String
-
- if @types.include?(name)
- @types[name].new(args)
- else
- raise UnknownNagiosType, "Unknown type #{name}"
- end
- end
-
- # Yield each type in turn.
- def self.eachtype
- @types.each do |name, type|
- yield [name, type]
- end
- end
-
- # Create a mapping.
- def self.map(hash)
- @map ||= {}
- hash.each do |n, v| @map[n] = v end
- end
-
- # Return a mapping (or nil) for a param
- def self.mapping(name)
- name = name.intern if name.is_a? String
- if defined?(@map)
- @map[name]
- else
- nil
- end
- end
-
- # Return the namevar for the canonical name.
- def self.namevar
- if defined?(@namevar)
- return @namevar
- else
- if parameter?(:name)
- return :name
- elsif tmp = (self.name.to_s + "_name").intern and parameter?(tmp)
- @namevar = tmp
- return @namevar
- else
- raise "Type #{self.name} has no name var"
- end
- end
- end
-
- # Create a new type.
- def self.newtype(name, &block)
- name = name.intern if name.is_a? String
-
- @types ||= {}
-
- # Create the class, with the correct name.
- t = Class.new(self)
- t.name = name
-
- # Everyone gets this. There should probably be a better way, and I
- # should probably hack the attribute system to look things up based on
- # this "use" setting, but, eh.
- t.parameters = [:use]
-
- const_set(name.to_s.capitalize,t)
-
- # Evaluate the passed block. This should usually define all of the work.
- t.class_eval(&block)
-
- @types[name] = t
- end
-
- # Define both the normal case and camelcase method for a parameter
- def self.paramattr(name)
- camel = camelcase(name)
- param = name
-
- [name, camel].each do |method|
- define_method(method) do
- @parameters[param]
- end
-
- define_method(method.to_s + "=") do |value|
- @parameters[param] = value
- end
- end
-
- end
-
- # Is the specified name a valid parameter?
- def self.parameter?(name)
- name = name.intern if name.is_a? String
- @parameters.include?(name)
- end
-
- # Manually set the namevar
- def self.setnamevar(name)
- name = name.intern if name.is_a? String
- @namevar = name
- end
-
- # Set the valid parameters for this class
- def self.setparameters(*array)
- @parameters += array
- end
-
- # Set the superior ldap object class. Seems silly to include this
- # in this class, but, eh.
- def self.setsuperior(name)
- @superior = name
- end
-
- # Parameters to suppress in output.
- def self.suppress(name)
- @suppress ||= []
- @suppress << name
- end
-
- # Whether a given parameter is suppressed.
- def self.suppress?(name)
- defined?(@suppress) and @suppress.include?(name)
- end
-
- # Return our name as the string.
- def self.to_s
- self.name.to_s
- end
-
- # Return a type by name.
- def self.type(name)
- name = name.intern if name.is_a? String
-
- @types[name]
- end
+ class UnknownNagiosType < RuntimeError # When an unknown type is asked for by name.
+ end
- # Convenience methods.
- def [](param)
- send(param)
- end
-
- # Convenience methods.
- def []=(param,value)
- send(param.to_s + "=", value)
- end
+ include Enumerable
- # Iterate across all ofour set parameters.
- def each
- @parameters.each { |param,value|
- yield(param,value)
- }
- end
+ class << self
+ attr_accessor :parameters, :derivatives, :ocs, :name, :att
+ attr_accessor :ldapbase
- # Initialize our object, optionally with a list of parameters.
- def initialize(args = {})
- @parameters = {}
+ attr_writer :namevar
- args.each { |param,value|
- self[param] = value
- }
- if @namevar == :_naginator_name
- self['_naginator_name'] = self['name']
- end
- end
+ attr_reader :superior
+ end
- # Handle parameters like attributes.
- def method_missing(mname, *args)
- pname = mname.to_s
- pname.sub!(/=/, '')
-
- if self.class.parameter?(pname)
- if pname =~ /A-Z/
- pname = self.class.decamelcase(pname)
- end
- self.class.paramattr(pname)
-
- # Now access the parameters directly, to make it at least less
- # likely we'll end up in an infinite recursion.
- if mname.to_s =~ /=$/
- @parameters[pname] = *args
- else
- return @parameters[mname]
- end
- else
- super
- end
+ # Attach one class to another.
+ def self.attach(hash)
+ @attach ||= {}
+ hash.each do |n, v| @attach[n] = v end
+ end
+
+ # Convert a parameter to camelcase
+ def self.camelcase(param)
+ param.gsub(/_./) do |match|
+ match.sub(/_/,'').capitalize
end
+ end
- # Retrieve our name, through a bit of redirection.
- def name
- send(self.class.namevar)
+ # Uncamelcase a parameter.
+ def self.decamelcase(param)
+ param.gsub(/[A-Z]/) do |match|
+ "_#{match.downcase}"
end
+ end
- # This is probably a bad idea.
- def name=(value)
- unless self.class.namevar.to_s == "name"
- send(self.class.namevar.to_s + "=", value)
- end
- end
+ # Create a new instance of a given class.
+ def self.create(name, args = {})
+ name = name.intern if name.is_a? String
- def namevar
- (self.type + "_name").intern
+ if @types.include?(name)
+ @types[name].new(args)
+ else
+ raise UnknownNagiosType, "Unknown type #{name}"
end
-
- def parammap(param)
- unless defined?(@map)
- map = {
- self.namevar => "cn"
- }
- map.update(self.class.map) if self.class.map
- end
- if map.include?(param)
- return map[param]
+ end
+
+ # Yield each type in turn.
+ def self.eachtype
+ @types.each do |name, type|
+ yield [name, type]
+ end
+ end
+
+ # Create a mapping.
+ def self.map(hash)
+ @map ||= {}
+ hash.each do |n, v| @map[n] = v end
+ end
+
+ # Return a mapping (or nil) for a param
+ def self.mapping(name)
+ name = name.intern if name.is_a? String
+ if defined?(@map)
+ @map[name]
+ else
+ nil
+ end
+ end
+
+ # Return the namevar for the canonical name.
+ def self.namevar
+ if defined?(@namevar)
+ return @namevar
+ else
+ if parameter?(:name)
+ return :name
+ elsif tmp = (self.name.to_s + "_name").intern and parameter?(tmp)
+ @namevar = tmp
+ return @namevar
+ else
+ raise "Type #{self.name} has no name var"
+ end
+ end
+ end
+
+ # Create a new type.
+ def self.newtype(name, &block)
+ name = name.intern if name.is_a? String
+
+ @types ||= {}
+
+ # Create the class, with the correct name.
+ t = Class.new(self)
+ t.name = name
+
+ # Everyone gets this. There should probably be a better way, and I
+ # should probably hack the attribute system to look things up based on
+ # this "use" setting, but, eh.
+ t.parameters = [:use]
+
+ const_set(name.to_s.capitalize,t)
+
+ # Evaluate the passed block. This should usually define all of the work.
+ t.class_eval(&block)
+
+ @types[name] = t
+ end
+
+ # Define both the normal case and camelcase method for a parameter
+ def self.paramattr(name)
+ camel = camelcase(name)
+ param = name
+
+ [name, camel].each do |method|
+ define_method(method) do
+ @parameters[param]
+ end
+
+ define_method(method.to_s + "=") do |value|
+ @parameters[param] = value
+ end
+ end
+
+ end
+
+ # Is the specified name a valid parameter?
+ def self.parameter?(name)
+ name = name.intern if name.is_a? String
+ @parameters.include?(name)
+ end
+
+ # Manually set the namevar
+ def self.setnamevar(name)
+ name = name.intern if name.is_a? String
+ @namevar = name
+ end
+
+ # Set the valid parameters for this class
+ def self.setparameters(*array)
+ @parameters += array
+ end
+
+ # Set the superior ldap object class. Seems silly to include this
+ # in this class, but, eh.
+ def self.setsuperior(name)
+ @superior = name
+ end
+
+ # Parameters to suppress in output.
+ def self.suppress(name)
+ @suppress ||= []
+ @suppress << name
+ end
+
+ # Whether a given parameter is suppressed.
+ def self.suppress?(name)
+ defined?(@suppress) and @suppress.include?(name)
+ end
+
+ # Return our name as the string.
+ def self.to_s
+ self.name.to_s
+ end
+
+ # Return a type by name.
+ def self.type(name)
+ name = name.intern if name.is_a? String
+
+ @types[name]
+ end
+
+ # Convenience methods.
+ def [](param)
+ send(param)
+ end
+
+ # Convenience methods.
+ def []=(param,value)
+ send(param.to_s + "=", value)
+ end
+
+ # Iterate across all ofour set parameters.
+ def each
+ @parameters.each { |param,value|
+ yield(param,value)
+ }
+ end
+
+ # Initialize our object, optionally with a list of parameters.
+ def initialize(args = {})
+ @parameters = {}
+
+ args.each { |param,value|
+ self[param] = value
+ }
+ if @namevar == :_naginator_name
+ self['_naginator_name'] = self['name']
+ end
+ end
+
+ # Handle parameters like attributes.
+ def method_missing(mname, *args)
+ pname = mname.to_s
+ pname.sub!(/=/, '')
+
+ if self.class.parameter?(pname)
+ if pname =~ /A-Z/
+ pname = self.class.decamelcase(pname)
+ end
+ self.class.paramattr(pname)
+
+ # Now access the parameters directly, to make it at least less
+ # likely we'll end up in an infinite recursion.
+ if mname.to_s =~ /=$/
+ @parameters[pname] = *args
+ else
+ return @parameters[mname]
+ end
+ else
+ super
+ end
+ end
+
+ # Retrieve our name, through a bit of redirection.
+ def name
+ send(self.class.namevar)
+ end
+
+ # This is probably a bad idea.
+ def name=(value)
+ unless self.class.namevar.to_s == "name"
+ send(self.class.namevar.to_s + "=", value)
+ end
+ end
+
+ def namevar
+ (self.type + "_name").intern
+ end
+
+ def parammap(param)
+ unless defined?(@map)
+ map = {
+ self.namevar => "cn"
+ }
+ map.update(self.class.map) if self.class.map
+ end
+ if map.include?(param)
+ return map[param]
+ else
+ return "nagios-" + param.id2name.gsub(/_/,'-')
+ end
+ end
+
+ def parent
+ unless defined?(self.class.attached)
+ puts "Duh, you called parent on an unattached class"
+ return
+ end
+
+ klass,param = self.class.attached
+ unless @parameters.include?(param)
+ puts "Huh, no attachment param"
+ return
+ end
+ klass[@parameters[param]]
+ end
+
+ # okay, this sucks
+ # how do i get my list of ocs?
+ def to_ldif
+ base = self.class.ldapbase
+ str = self.dn + "\n"
+ ocs = Array.new
+ if self.class.ocs
+ # i'm storing an array, so i have to flatten it and stuff
+ kocs = self.class.ocs
+ ocs.push(*kocs)
+ end
+ ocs.push "top"
+ oc = self.class.to_s
+ oc.sub!(/Nagios/,'nagios')
+ oc.sub!(/::/,'')
+ ocs.push oc
+ ocs.each { |oc|
+ str += "objectclass: #{oc}\n"
+ }
+ @parameters.each { |name,value|
+ next if self.class.suppress.include?(name)
+ ldapname = self.parammap(name)
+ str += ldapname + ": #{value}\n"
+ }
+ str += "\n"
+ end
+
+ def to_s
+ str = "define #{self.type} {\n"
+
+ self.each { |param,value|
+ str += %{\t%-30s %s\n} % [ param,
+ if value.is_a? Array
+ value.join(",")
else
- return "nagios-" + param.id2name.gsub(/_/,'-')
- end
- end
-
- def parent
- unless defined?(self.class.attached)
- puts "Duh, you called parent on an unattached class"
- return
- end
-
- klass,param = self.class.attached
- unless @parameters.include?(param)
- puts "Huh, no attachment param"
- return
- end
- klass[@parameters[param]]
- end
-
- # okay, this sucks
- # how do i get my list of ocs?
- def to_ldif
- base = self.class.ldapbase
- str = self.dn + "\n"
- ocs = Array.new
- if self.class.ocs
- # i'm storing an array, so i have to flatten it and stuff
- kocs = self.class.ocs
- ocs.push(*kocs)
+ value
end
- ocs.push "top"
- oc = self.class.to_s
- oc.sub!(/Nagios/,'nagios')
- oc.sub!(/::/,'')
- ocs.push oc
- ocs.each { |oc|
- str += "objectclass: #{oc}\n"
- }
- @parameters.each { |name,value|
- next if self.class.suppress.include?(name)
- ldapname = self.parammap(name)
- str += ldapname + ": #{value}\n"
- }
- str += "\n"
- end
-
- def to_s
- str = "define #{self.type} {\n"
-
- self.each { |param,value|
- str += %{\t%-30s %s\n} % [ param,
- if value.is_a? Array
- value.join(",")
- else
- value
- end
- ]
- }
-
- str += "}\n"
-
- str
- end
-
- # The type of object we are.
- def type
- self.class.name
- end
-
- # object types
- newtype :host do
- setparameters :host_name, :alias, :display_name, :address, :parents,
- :hostgroups, :check_command, :initial_state, :max_check_attempts,
- :check_interval, :retry_interval, :active_checks_enabled,
- :passive_checks_enabled, :check_period, :obsess_over_host,
- :check_freshness, :freshness_threshold, :event_handler,
- :event_handler_enabled, :low_flap_threshold, :high_flap_threshold,
- :flap_detection_enabled, :flap_detection_options,
- :failure_prediction_enabled, :process_perf_data,
- :retain_status_information, :retain_nonstatus_information, :contacts,
- :contact_groups, :notification_interval, :first_notification_delay,
- :notification_period, :notification_options, :notifications_enabled,
- :stalking_options, :notes, :notes_url, :action_url, :icon_image,
- :icon_image_alt, :vrml_image, :statusmap_image, "2d_coords".intern,
- "3d_coords".intern,
- :register, :use
-
- setsuperior "person"
- map :address => "ipHostNumber"
- end
-
- newtype :hostgroup do
- setparameters :hostgroup_name, :alias, :members, :hostgroup_members, :notes,
- :notes_url, :action_url,
- :register, :use
- end
-
- newtype :service do
- attach :host => :host_name
- setparameters :host_name, :hostgroup_name, :service_description,
- :display_name, :servicegroups, :is_volatile, :check_command,
- :initial_state, :max_check_attempts, :check_interval, :retry_interval,
- :normal_check_interval, :retry_check_interval, :active_checks_enabled,
- :passive_checks_enabled, :parallelize_check, :check_period,
- :obsess_over_service, :check_freshness, :freshness_threshold,
- :event_handler, :event_handler_enabled, :low_flap_threshold,
- :high_flap_threshold, :flap_detection_enabled,:flap_detection_options,
- :process_perf_data, :failure_prediction_enabled, :retain_status_information,
- :retain_nonstatus_information, :notification_interval,
- :first_notification_delay, :notification_period, :notification_options,
- :notifications_enabled, :contacts, :contact_groups, :stalking_options,
- :notes, :notes_url, :action_url, :icon_image, :icon_image_alt,
- :register, :use,
- :_naginator_name
-
- suppress :host_name
-
- setnamevar :_naginator_name
- end
-
- newtype :servicegroup do
- setparameters :servicegroup_name, :alias, :members, :servicegroup_members,
- :notes, :notes_url, :action_url,
- :register, :use
- end
-
- newtype :contact do
- setparameters :contact_name, :alias, :contactgroups,
- :host_notifications_enabled, :service_notifications_enabled,
- :host_notification_period, :service_notification_period,
- :host_notification_options, :service_notification_options,
- :host_notification_commands, :service_notification_commands,
- :email, :pager, :address1, :address2, :address3, :address4,
- :address5, :address6, :can_submit_commands, :retain_status_information,
- :retain_nonstatus_information,
- :register, :use
-
- setsuperior "person"
- end
-
- newtype :contactgroup do
- setparameters :contactgroup_name, :alias, :members, :contactgroup_members,
- :register, :use
- end
-
- # TODO - We should support generic time periods here eg "day 1 - 15"
- newtype :timeperiod do
- setparameters :timeperiod_name, :alias, :sunday, :monday, :tuesday,
- :wednesday, :thursday, :friday, :saturday, :exclude,
- :register, :use
- end
-
- newtype :command do
- setparameters :command_name, :command_line
- end
-
- newtype :servicedependency do
- auxiliary = true
- setparameters :dependent_host_name, :dependent_hostgroup_name,
- :dependent_service_description, :host_name, :hostgroup_name,
- :service_description, :inherits_parent, :execution_failure_criteria,
- :notification_failure_criteria, :dependency_period,
- :register, :use,
- :_naginator_name
-
- setnamevar :_naginator_name
- end
-
- newtype :serviceescalation do
- setparameters :host_name, :hostgroup_name, :servicegroup_name,
- :service_description, :contacts, :contact_groups,
- :first_notification, :last_notification, :notification_interval,
- :escalation_period, :escalation_options,
- :register, :use,
- :_naginator_name
-
- setnamevar :_naginator_name
- end
-
- newtype :hostdependency do
- auxiliary = true
- setparameters :dependent_host_name, :dependent_hostgroup_name, :host_name,
- :hostgroup_name, :inherits_parent, :execution_failure_criteria,
- :notification_failure_criteria, :dependency_period,
- :register, :use,
- :_naginator_name
-
- setnamevar :_naginator_name
- end
-
- newtype :hostescalation do
- setparameters :host_name, :hostgroup_name, :contacts, :contact_groups,
- :first_notification, :last_notification, :notification_interval,
- :escalation_period, :escalation_options,
- :register, :use,
- :_naginator_name
-
- setnamevar :_naginator_name
- end
-
- newtype :hostextinfo do
- auxiliary = true
- setparameters :host_name, :notes, :notes_url, :icon_image, :icon_image_alt,
- :vrml_image, :statusmap_image, "2d_coords".intern, "3d_coords".intern,
- :register, :use
-
- setnamevar :host_name
- end
-
- newtype :serviceextinfo do
- auxiliary = true
-
- setparameters :host_name, :service_description, :notes, :notes_url,
- :action_url, :icon_image, :icon_image_alt,
- :register, :use,
- :_naginator_name
-
- setnamevar :_naginator_name
- end
+ ]
+ }
+
+ str += "}\n"
+
+ str
+ end
+
+ # The type of object we are.
+ def type
+ self.class.name
+ end
+
+ # object types
+ newtype :host do
+ setparameters :host_name, :alias, :display_name, :address, :parents,
+ :hostgroups, :check_command, :initial_state, :max_check_attempts,
+ :check_interval, :retry_interval, :active_checks_enabled,
+ :passive_checks_enabled, :check_period, :obsess_over_host,
+ :check_freshness, :freshness_threshold, :event_handler,
+ :event_handler_enabled, :low_flap_threshold, :high_flap_threshold,
+ :flap_detection_enabled, :flap_detection_options,
+ :failure_prediction_enabled, :process_perf_data,
+ :retain_status_information, :retain_nonstatus_information, :contacts,
+ :contact_groups, :notification_interval, :first_notification_delay,
+ :notification_period, :notification_options, :notifications_enabled,
+ :stalking_options, :notes, :notes_url, :action_url, :icon_image,
+ :icon_image_alt, :vrml_image, :statusmap_image, "2d_coords".intern,
+ "3d_coords".intern,
+ :register, :use
+
+ setsuperior "person"
+ map :address => "ipHostNumber"
+ end
+
+ newtype :hostgroup do
+ setparameters :hostgroup_name, :alias, :members, :hostgroup_members, :notes,
+ :notes_url, :action_url,
+ :register, :use
+ end
+
+ newtype :service do
+ attach :host => :host_name
+ setparameters :host_name, :hostgroup_name, :service_description,
+ :display_name, :servicegroups, :is_volatile, :check_command,
+ :initial_state, :max_check_attempts, :check_interval, :retry_interval,
+ :normal_check_interval, :retry_check_interval, :active_checks_enabled,
+ :passive_checks_enabled, :parallelize_check, :check_period,
+ :obsess_over_service, :check_freshness, :freshness_threshold,
+ :event_handler, :event_handler_enabled, :low_flap_threshold,
+ :high_flap_threshold, :flap_detection_enabled,:flap_detection_options,
+ :process_perf_data, :failure_prediction_enabled, :retain_status_information,
+ :retain_nonstatus_information, :notification_interval,
+ :first_notification_delay, :notification_period, :notification_options,
+ :notifications_enabled, :contacts, :contact_groups, :stalking_options,
+ :notes, :notes_url, :action_url, :icon_image, :icon_image_alt,
+ :register, :use,
+ :_naginator_name
+
+ suppress :host_name
+
+ setnamevar :_naginator_name
+ end
+
+ newtype :servicegroup do
+ setparameters :servicegroup_name, :alias, :members, :servicegroup_members,
+ :notes, :notes_url, :action_url,
+ :register, :use
+ end
+
+ newtype :contact do
+ setparameters :contact_name, :alias, :contactgroups,
+ :host_notifications_enabled, :service_notifications_enabled,
+ :host_notification_period, :service_notification_period,
+ :host_notification_options, :service_notification_options,
+ :host_notification_commands, :service_notification_commands,
+ :email, :pager, :address1, :address2, :address3, :address4,
+ :address5, :address6, :can_submit_commands, :retain_status_information,
+ :retain_nonstatus_information,
+ :register, :use
+
+ setsuperior "person"
+ end
+
+ newtype :contactgroup do
+ setparameters :contactgroup_name, :alias, :members, :contactgroup_members,
+ :register, :use
+ end
+
+ # TODO - We should support generic time periods here eg "day 1 - 15"
+ newtype :timeperiod do
+ setparameters :timeperiod_name, :alias, :sunday, :monday, :tuesday,
+ :wednesday, :thursday, :friday, :saturday, :exclude,
+ :register, :use
+ end
+
+ newtype :command do
+ setparameters :command_name, :command_line
+ end
+
+ newtype :servicedependency do
+ auxiliary = true
+ setparameters :dependent_host_name, :dependent_hostgroup_name,
+ :dependent_service_description, :host_name, :hostgroup_name,
+ :service_description, :inherits_parent, :execution_failure_criteria,
+ :notification_failure_criteria, :dependency_period,
+ :register, :use,
+ :_naginator_name
+
+ setnamevar :_naginator_name
+ end
+
+ newtype :serviceescalation do
+ setparameters :host_name, :hostgroup_name, :servicegroup_name,
+ :service_description, :contacts, :contact_groups,
+ :first_notification, :last_notification, :notification_interval,
+ :escalation_period, :escalation_options,
+ :register, :use,
+ :_naginator_name
+
+ setnamevar :_naginator_name
+ end
+
+ newtype :hostdependency do
+ auxiliary = true
+ setparameters :dependent_host_name, :dependent_hostgroup_name, :host_name,
+ :hostgroup_name, :inherits_parent, :execution_failure_criteria,
+ :notification_failure_criteria, :dependency_period,
+ :register, :use,
+ :_naginator_name
+
+ setnamevar :_naginator_name
+ end
+
+ newtype :hostescalation do
+ setparameters :host_name, :hostgroup_name, :contacts, :contact_groups,
+ :first_notification, :last_notification, :notification_interval,
+ :escalation_period, :escalation_options,
+ :register, :use,
+ :_naginator_name
+
+ setnamevar :_naginator_name
+ end
+
+ newtype :hostextinfo do
+ auxiliary = true
+ setparameters :host_name, :notes, :notes_url, :icon_image, :icon_image_alt,
+ :vrml_image, :statusmap_image, "2d_coords".intern, "3d_coords".intern,
+ :register, :use
+
+ setnamevar :host_name
+ end
+
+ newtype :serviceextinfo do
+ auxiliary = true
+
+ setparameters :host_name, :service_description, :notes, :notes_url,
+ :action_url, :icon_image, :icon_image_alt,
+ :register, :use,
+ :_naginator_name
+
+ setnamevar :_naginator_name
+ end
end
diff --git a/lib/puppet/external/nagios/parser.rb b/lib/puppet/external/nagios/parser.rb
index 43444cccb..5504f5818 100644
--- a/lib/puppet/external/nagios/parser.rb
+++ b/lib/puppet/external/nagios/parser.rb
@@ -27,420 +27,420 @@ self.class.module_eval <<'..end racc/parser.rb modeval..id5256434e8a', 'racc/par
NotImplementedError = NotImplementError unless defined?(NotImplementedError)
module Racc
- class ParseError < StandardError; end
+ class ParseError < StandardError; end
end
ParseError = Racc::ParseError unless defined?(::ParseError)
module Racc
- Racc_No_Extentions = false unless defined?(Racc_No_Extentions)
-
- class Parser
-
- Racc_Runtime_Version = '1.4.5'
- Racc_Runtime_Revision = '$Revision: 1.7 $'.split[1]
-
- Racc_Runtime_Core_Version_R = '1.4.5'
- Racc_Runtime_Core_Revision_R = '$Revision: 1.7 $'.split[1]
- begin
- require 'racc/cparse'
- # Racc_Runtime_Core_Version_C = (defined in extention)
- Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split[2]
- raise LoadError, 'old cparse.so' unless new.respond_to?(:_racc_do_parse_c, true)
- raise LoadError, 'selecting ruby version of racc runtime core' if Racc_No_Extentions
-
- Racc_Main_Parsing_Routine = :_racc_do_parse_c
- Racc_YY_Parse_Method = :_racc_yyparse_c
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C
- Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C
- Racc_Runtime_Type = 'c'
- rescue LoadError
- Racc_Main_Parsing_Routine = :_racc_do_parse_rb
- Racc_YY_Parse_Method = :_racc_yyparse_rb
- Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
- Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R
- Racc_Runtime_Type = 'ruby'
- end
-
- def Parser.racc_runtime_type
- Racc_Runtime_Type
- end
+ Racc_No_Extentions = false unless defined?(Racc_No_Extentions)
+
+ class Parser
+
+ Racc_Runtime_Version = '1.4.5'
+ Racc_Runtime_Revision = '$Revision: 1.7 $'.split[1]
+
+ Racc_Runtime_Core_Version_R = '1.4.5'
+ Racc_Runtime_Core_Revision_R = '$Revision: 1.7 $'.split[1]
+ begin
+ require 'racc/cparse'
+ # Racc_Runtime_Core_Version_C = (defined in extention)
+ Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split[2]
+ raise LoadError, 'old cparse.so' unless new.respond_to?(:_racc_do_parse_c, true)
+ raise LoadError, 'selecting ruby version of racc runtime core' if Racc_No_Extentions
+
+ Racc_Main_Parsing_Routine = :_racc_do_parse_c
+ Racc_YY_Parse_Method = :_racc_yyparse_c
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C
+ Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C
+ Racc_Runtime_Type = 'c'
+ rescue LoadError
+ Racc_Main_Parsing_Routine = :_racc_do_parse_rb
+ Racc_YY_Parse_Method = :_racc_yyparse_rb
+ Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R
+ Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R
+ Racc_Runtime_Type = 'ruby'
+ end
- private
+ def Parser.racc_runtime_type
+ Racc_Runtime_Type
+ end
- def _racc_setup
- @yydebug = false unless self.class::Racc_debug_parser
- @yydebug ||= false
- if @yydebug
- @racc_debug_out ||= $stderr
- @racc_debug_out ||= $stderr
- end
- arg = self.class::Racc_arg
- arg[13] = true if arg.size < 14
- arg
- end
+ private
+
+ def _racc_setup
+ @yydebug = false unless self.class::Racc_debug_parser
+ @yydebug ||= false
+ if @yydebug
+ @racc_debug_out ||= $stderr
+ @racc_debug_out ||= $stderr
+ end
+ arg = self.class::Racc_arg
+ arg[13] = true if arg.size < 14
+ arg
+ end
- def _racc_init_sysvars
- @racc_state = [0]
- @racc_tstack = []
- @racc_vstack = []
+ def _racc_init_sysvars
+ @racc_state = [0]
+ @racc_tstack = []
+ @racc_vstack = []
- @racc_t = nil
- @racc_val = nil
+ @racc_t = nil
+ @racc_val = nil
- @racc_read_next = true
+ @racc_read_next = true
- @racc_user_yyerror = false
- @racc_error_status = 0
- end
+ @racc_user_yyerror = false
+ @racc_error_status = 0
+ end
- ###
- ### do_parse
- ###
+ ###
+ ### do_parse
+ ###
- def do_parse
- __send__(Racc_Main_Parsing_Routine, _racc_setup, false)
- end
+ def do_parse
+ __send__(Racc_Main_Parsing_Routine, _racc_setup, false)
+ end
- def next_token
- raise NotImplementedError, "#{self.class}\#next_token is not defined"
- end
+ def next_token
+ raise NotImplementedError, "#{self.class}\#next_token is not defined"
+ end
- def _racc_do_parse_rb(arg, in_debug)
- action_table, action_check, action_default, action_pointer,
- goto_table, goto_check, goto_default, goto_pointer,
- nt_base, reduce_table, token_table, shift_n,
- reduce_n, use_result, * = arg
-
- _racc_init_sysvars
- tok = act = i = nil
- nerr = 0
-
- catch(:racc_end_parse) {
- while true
- if i = action_pointer[@racc_state[-1]]
- if @racc_read_next
- if @racc_t != 0 # not EOF
- tok, @racc_val = next_token
- unless tok # EOF
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- racc_read_token(@racc_t, tok, @racc_val) if @yydebug
- @racc_read_next = false
- end
- end
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- else
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
+ def _racc_do_parse_rb(arg, in_debug)
+ action_table, action_check, action_default, action_pointer,
+ goto_table, goto_check, goto_default, goto_pointer,
+ nt_base, reduce_table, token_table, shift_n,
+ reduce_n, use_result, * = arg
+
+ _racc_init_sysvars
+ tok = act = i = nil
+ nerr = 0
+
+ catch(:racc_end_parse) {
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ if @racc_read_next
+ if @racc_t != 0 # not EOF
+ tok, @racc_val = next_token
+ unless tok # EOF
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ racc_read_token(@racc_t, tok, @racc_val) if @yydebug
+ @racc_read_next = false
end
- }
+ end
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ else
+ act = action_default[@racc_state[-1]]
end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
+ end
+ }
+ end
+
+ ###
+ ### yyparse
+ ###
- ###
- ### yyparse
- ###
+ def yyparse(recv, mid)
+ __send__(Racc_YY_Parse_Method, recv, mid, _racc_setup, true)
+ end
- def yyparse(recv, mid)
- __send__(Racc_YY_Parse_Method, recv, mid, _racc_setup, true)
+ def _racc_yyparse_rb(recv, mid, arg, c_debug)
+ action_table, action_check, action_default, action_pointer,
+ goto_table, goto_check, goto_default, goto_pointer,
+ nt_base, reduce_table, token_table, shift_n,
+ reduce_n, use_result, * = arg
+
+ _racc_init_sysvars
+ tok = nil
+ act = nil
+ i = nil
+ nerr = 0
+
+ catch(:racc_end_parse) {
+ until i = action_pointer[@racc_state[-1]]
+ while act = _racc_evalact(action_default[@racc_state[-1]], arg)
+ ;
+ end
+ end
+ recv.__send__(mid) do |tok, val|
+ unless tok
+ @racc_t = 0
+ else
+ @racc_t = (token_table[tok] or 1) # error token
+ end
+ @racc_val = val
+ @racc_read_next = false
+
+ i += @racc_t
+ unless i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
end
- def _racc_yyparse_rb(recv, mid, arg, c_debug)
- action_table, action_check, action_default, action_pointer,
- goto_table, goto_check, goto_default, goto_pointer,
- nt_base, reduce_table, token_table, shift_n,
- reduce_n, use_result, * = arg
-
- _racc_init_sysvars
- tok = nil
- act = nil
- i = nil
- nerr = 0
-
- catch(:racc_end_parse) {
- until i = action_pointer[@racc_state[-1]]
- while act = _racc_evalact(action_default[@racc_state[-1]], arg)
- ;
- end
- end
- recv.__send__(mid) do |tok, val|
- unless tok
- @racc_t = 0
- else
- @racc_t = (token_table[tok] or 1) # error token
- end
- @racc_val = val
- @racc_read_next = false
-
- i += @racc_t
- unless i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
-
- while not (i = action_pointer[@racc_state[-1]]) or
- not @racc_read_next or
- @racc_t == 0 # $
- unless i and i += @racc_t and
- i >= 0 and
- act = action_table[i] and
- action_check[i] == @racc_state[-1]
- act = action_default[@racc_state[-1]]
- end
- while act = _racc_evalact(act, arg)
- ;
- end
- end
- end
- }
+ while not (i = action_pointer[@racc_state[-1]]) or
+ not @racc_read_next or
+ @racc_t == 0 # $
+ unless i and i += @racc_t and
+ i >= 0 and
+ act = action_table[i] and
+ action_check[i] == @racc_state[-1]
+ act = action_default[@racc_state[-1]]
+ end
+ while act = _racc_evalact(act, arg)
+ ;
+ end
end
+ end
+ }
+ end
- ###
- ### common
- ###
-
- def _racc_evalact(act, arg)
- action_table, action_check, action_default, action_pointer,
- goto_table, goto_check, goto_default, goto_pointer,
- nt_base, reduce_table, token_table, shift_n,
- reduce_n, use_result, * = arg
- nerr = 0 # tmp
-
- if act > 0 and act < shift_n
- #
- # shift
- #
- if @racc_error_status > 0
- @racc_error_status -= 1 unless @racc_t == 1 # error token
- end
- @racc_vstack.push @racc_val
- @racc_state.push act
- @racc_read_next = true
- if @yydebug
- @racc_tstack.push @racc_t
- racc_shift @racc_t, @racc_tstack, @racc_vstack
- end
-
- elsif act < 0 and act > -reduce_n
- #
- # reduce
- #
- code = catch(:racc_jump) {
- @racc_state.push _racc_do_reduce(arg, act)
- false
- }
- if code
- case code
- when 1 # yyerror
- @racc_user_yyerror = true # user_yyerror
- return -reduce_n
- when 2 # yyaccept
- return shift_n
- else
- raise '[Racc Bug] unknown jump code'
- end
- end
-
- elsif act == shift_n
- #
- # accept
- #
- racc_accept if @yydebug
- throw :racc_end_parse, @racc_vstack[0]
-
- elsif act == -reduce_n
- #
- # error
- #
- case @racc_error_status
- when 0
- unless arg[21] # user_yyerror
- nerr += 1
- on_error @racc_t, @racc_val, @racc_vstack
- end
- when 3
- if @racc_t == 0 # is $
- throw :racc_end_parse, nil
- end
- @racc_read_next = true
- end
- @racc_user_yyerror = false
- @racc_error_status = 3
- while true
- if i = action_pointer[@racc_state[-1]]
- i += 1 # error token
- if i >= 0 and
- (act = action_table[i]) and
- action_check[i] == @racc_state[-1]
- break
- end
- end
- throw :racc_end_parse, nil if @racc_state.size <= 1
- @racc_state.pop
- @racc_vstack.pop
- if @yydebug
- @racc_tstack.pop
- racc_e_pop @racc_state, @racc_tstack, @racc_vstack
- end
- end
- return act
-
- else
- raise "[Racc Bug] unknown action #{act.inspect}"
- end
+ ###
+ ### common
+ ###
- racc_next_state(@racc_state[-1], @racc_state) if @yydebug
+ def _racc_evalact(act, arg)
+ action_table, action_check, action_default, action_pointer,
+ goto_table, goto_check, goto_default, goto_pointer,
+ nt_base, reduce_table, token_table, shift_n,
+ reduce_n, use_result, * = arg
+ nerr = 0 # tmp
- nil
+ if act > 0 and act < shift_n
+ #
+ # shift
+ #
+ if @racc_error_status > 0
+ @racc_error_status -= 1 unless @racc_t == 1 # error token
+ end
+ @racc_vstack.push @racc_val
+ @racc_state.push act
+ @racc_read_next = true
+ if @yydebug
+ @racc_tstack.push @racc_t
+ racc_shift @racc_t, @racc_tstack, @racc_vstack
end
- def _racc_do_reduce(arg, act)
- action_table, action_check, action_default, action_pointer,
- goto_table, goto_check, goto_default, goto_pointer,
- nt_base, reduce_table, token_table, shift_n,
- reduce_n, use_result, * = arg
- state = @racc_state
- vstack = @racc_vstack
- tstack = @racc_tstack
-
- i = act * -3
- len = reduce_table[i]
- reduce_to = reduce_table[i+1]
- method_id = reduce_table[i+2]
- void_array = []
-
- tmp_t = tstack[-len, len] if @yydebug
- tmp_v = vstack[-len, len]
- tstack[-len, len] = void_array if @yydebug
- vstack[-len, len] = void_array
- state[-len, len] = void_array
-
- # tstack must be updated AFTER method call
- if use_result
- vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
- else
- vstack.push __send__(method_id, tmp_v, vstack)
- end
- tstack.push reduce_to
+ elsif act < 0 and act > -reduce_n
+ #
+ # reduce
+ #
+ code = catch(:racc_jump) {
+ @racc_state.push _racc_do_reduce(arg, act)
+ false
+ }
+ if code
+ case code
+ when 1 # yyerror
+ @racc_user_yyerror = true # user_yyerror
+ return -reduce_n
+ when 2 # yyaccept
+ return shift_n
+ else
+ raise '[Racc Bug] unknown jump code'
+ end
+ end
- racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
+ elsif act == shift_n
+ #
+ # accept
+ #
+ racc_accept if @yydebug
+ throw :racc_end_parse, @racc_vstack[0]
- k1 = reduce_to - nt_base
- if i = goto_pointer[k1]
- i += state[-1]
- if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
- return curstate
- end
+ elsif act == -reduce_n
+ #
+ # error
+ #
+ case @racc_error_status
+ when 0
+ unless arg[21] # user_yyerror
+ nerr += 1
+ on_error @racc_t, @racc_val, @racc_vstack
+ end
+ when 3
+ if @racc_t == 0 # is $
+ throw :racc_end_parse, nil
+ end
+ @racc_read_next = true
+ end
+ @racc_user_yyerror = false
+ @racc_error_status = 3
+ while true
+ if i = action_pointer[@racc_state[-1]]
+ i += 1 # error token
+ if i >= 0 and
+ (act = action_table[i]) and
+ action_check[i] == @racc_state[-1]
+ break
end
- goto_default[k1]
+ end
+ throw :racc_end_parse, nil if @racc_state.size <= 1
+ @racc_state.pop
+ @racc_vstack.pop
+ if @yydebug
+ @racc_tstack.pop
+ racc_e_pop @racc_state, @racc_tstack, @racc_vstack
+ end
end
+ return act
- def on_error(t, val, vstack)
- raise ParseError, sprintf("\nparse error on value %s (%s)", val.inspect, token_to_str(t) || '?')
- end
+ else
+ raise "[Racc Bug] unknown action #{act.inspect}"
+ end
- def yyerror
- throw :racc_jump, 1
- end
+ racc_next_state(@racc_state[-1], @racc_state) if @yydebug
- def yyaccept
- throw :racc_jump, 2
- end
+ nil
+ end
- def yyerrok
- @racc_error_status = 0
+ def _racc_do_reduce(arg, act)
+ action_table, action_check, action_default, action_pointer,
+ goto_table, goto_check, goto_default, goto_pointer,
+ nt_base, reduce_table, token_table, shift_n,
+ reduce_n, use_result, * = arg
+ state = @racc_state
+ vstack = @racc_vstack
+ tstack = @racc_tstack
+
+ i = act * -3
+ len = reduce_table[i]
+ reduce_to = reduce_table[i+1]
+ method_id = reduce_table[i+2]
+ void_array = []
+
+ tmp_t = tstack[-len, len] if @yydebug
+ tmp_v = vstack[-len, len]
+ tstack[-len, len] = void_array if @yydebug
+ vstack[-len, len] = void_array
+ state[-len, len] = void_array
+
+ # tstack must be updated AFTER method call
+ if use_result
+ vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0])
+ else
+ vstack.push __send__(method_id, tmp_v, vstack)
+ end
+ tstack.push reduce_to
+
+ racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug
+
+ k1 = reduce_to - nt_base
+ if i = goto_pointer[k1]
+ i += state[-1]
+ if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1
+ return curstate
end
+ end
+ goto_default[k1]
+ end
- #
- # for debugging output
- #
+ def on_error(t, val, vstack)
+ raise ParseError, sprintf("\nparse error on value %s (%s)", val.inspect, token_to_str(t) || '?')
+ end
- def racc_read_token(t, tok, val)
- @racc_debug_out.print 'read '
- @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
- @racc_debug_out.puts val.inspect
- @racc_debug_out.puts
- end
+ def yyerror
+ throw :racc_jump, 1
+ end
- def racc_shift(tok, tstack, vstack)
- @racc_debug_out.puts "shift #{racc_token2str tok}"
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
+ def yyaccept
+ throw :racc_jump, 2
+ end
- def racc_reduce(toks, sim, tstack, vstack)
- out = @racc_debug_out
- out.print 'reduce '
- if toks.empty?
- out.print ' <none>'
- else
- toks.each {|t| out.print ' ', racc_token2str(t) }
- end
- out.puts " --> #{racc_token2str(sim)}"
+ def yyerrok
+ @racc_error_status = 0
+ end
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
+ #
+ # for debugging output
+ #
- def racc_accept
- @racc_debug_out.puts 'accept'
- @racc_debug_out.puts
- end
+ def racc_read_token(t, tok, val)
+ @racc_debug_out.print 'read '
+ @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') '
+ @racc_debug_out.puts val.inspect
+ @racc_debug_out.puts
+ end
- def racc_e_pop(state, tstack, vstack)
- @racc_debug_out.puts 'error recovering mode: pop token'
- racc_print_states state
- racc_print_stacks tstack, vstack
- @racc_debug_out.puts
- end
+ def racc_shift(tok, tstack, vstack)
+ @racc_debug_out.puts "shift #{racc_token2str tok}"
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
- def racc_next_state(curstate, state)
- @racc_debug_out.puts "goto #{curstate}"
- racc_print_states state
- @racc_debug_out.puts
- end
+ def racc_reduce(toks, sim, tstack, vstack)
+ out = @racc_debug_out
+ out.print 'reduce '
+ if toks.empty?
+ out.print ' <none>'
+ else
+ toks.each {|t| out.print ' ', racc_token2str(t) }
+ end
+ out.puts " --> #{racc_token2str(sim)}"
+
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
- def racc_print_stacks(t, v)
- out = @racc_debug_out
- out.print ' ['
- t.each_index do |i|
- out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
- end
- out.puts ' ]'
- end
+ def racc_accept
+ @racc_debug_out.puts 'accept'
+ @racc_debug_out.puts
+ end
- def racc_print_states(s)
- out = @racc_debug_out
- out.print ' ['
- s.each {|st| out.print ' ', st }
- out.puts ' ]'
- end
+ def racc_e_pop(state, tstack, vstack)
+ @racc_debug_out.puts 'error recovering mode: pop token'
+ racc_print_states state
+ racc_print_stacks tstack, vstack
+ @racc_debug_out.puts
+ end
- def racc_token2str(tok)
- self.class::Racc_token_to_s_table[tok] or
- raise "[Racc Bug] can't convert token #{tok} to string"
- end
+ def racc_next_state(curstate, state)
+ @racc_debug_out.puts "goto #{curstate}"
+ racc_print_states state
+ @racc_debug_out.puts
+ end
- def token_to_str(t)
- self.class::Racc_token_to_s_table[t]
- end
+ def racc_print_stacks(t, v)
+ out = @racc_debug_out
+ out.print ' ['
+ t.each_index do |i|
+ out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')'
+ end
+ out.puts ' ]'
+ end
+
+ def racc_print_states(s)
+ out = @racc_debug_out
+ out.print ' ['
+ s.each {|st| out.print ' ', st }
+ out.puts ' ]'
+ end
+
+ def racc_token2str(tok)
+ self.class::Racc_token_to_s_table[tok] or
+ raise "[Racc Bug] can't convert token #{tok} to string"
+ end
+ def token_to_str(t)
+ self.class::Racc_token_to_s_table[t]
end
+ end
+
end
..end racc/parser.rb modeval..id5256434e8a
end
@@ -449,172 +449,172 @@ end
module Nagios
- class Parser < Racc::Parser
+ class Parser < Racc::Parser
module_eval <<'..end grammar.ry modeval..idcb2ea30b34', 'grammar.ry', 57
class ::Nagios::Parser::SyntaxError < RuntimeError; end
def parse(src)
- @src = src
+ @src = src
- # state variables
- @invar = false
- @inobject = false
- @done = false
+ # state variables
+ @invar = false
+ @inobject = false
+ @done = false
- @line = 0
- @yydebug = true
+ @line = 0
+ @yydebug = true
- do_parse
+ do_parse
end
# The lexer. Very simple.
def token
- @src.sub!(/\A\n/,'')
- if $MATCH
- @line += 1
- return [ :RETURN, "\n" ]
- end
+ @src.sub!(/\A\n/,'')
+ if $MATCH
+ @line += 1
+ return [ :RETURN, "\n" ]
+ end
- return nil if @done
- yytext = String.new
+ return nil if @done
+ yytext = String.new
- # remove comments from this line
- @src.sub!(/\A[ \t]*;.*\n/,"\n")
- return [:INLINECOMMENT, ""] if $MATCH
+ # remove comments from this line
+ @src.sub!(/\A[ \t]*;.*\n/,"\n")
+ return [:INLINECOMMENT, ""] if $MATCH
- @src.sub!(/\A#.*\n/,"\n")
- return [:COMMENT, ""] if $MATCH
+ @src.sub!(/\A#.*\n/,"\n")
+ return [:COMMENT, ""] if $MATCH
- @src.sub!(/#.*/,'')
+ @src.sub!(/#.*/,'')
- if @src.length == 0
- @done = true
- return [false, '$']
- end
+ if @src.length == 0
+ @done = true
+ return [false, '$']
+ end
- if @invar
- @src.sub!(/\A[ \t]+/,'')
- @src.sub!(/\A([^;\n]+)(\n|;)/,'\2')
- if $1
- yytext += $1
- end
- @invar = false
- return [:VALUE, yytext]
- else
- @src.sub!(/\A[\t ]*(\S+)([\t ]*|$)/,'')
- if $1
- yytext = $1
- case yytext
- when 'define'
- #puts "got define"
- return [:DEFINE, yytext]
- when '{'
- #puts "got {"
- @inobject = true
- return [:LCURLY, yytext]
- else
- unless @inobject
- #puts "got type: #{yytext}"
- if yytext =~ /\W/
- giveback = yytext.dup
- giveback.sub!(/^\w+/,'')
- #puts "giveback #{giveback}"
- #puts "yytext #{yytext}"
- yytext.sub!(/\W.*$/,'')
- #puts "yytext #{yytext}"
- #puts "all [#{giveback} #{yytext} #{orig}]"
- @src = giveback + @src
- end
- return [:NAME, yytext]
- else
- if yytext == '}'
- #puts "got closure: #{yytext}"
- @inobject = false
- return [:RCURLY, '}']
- end
-
- unless @invar
- @invar = true
- return [:PARAM, $1]
- else
- end
- end
- end
+ if @invar
+ @src.sub!(/\A[ \t]+/,'')
+ @src.sub!(/\A([^;\n]+)(\n|;)/,'\2')
+ if $1
+ yytext += $1
end
+ @invar = false
+ return [:VALUE, yytext]
+ else
+ @src.sub!(/\A[\t ]*(\S+)([\t ]*|$)/,'')
+ if $1
+ yytext = $1
+ case yytext
+ when 'define'
+ #puts "got define"
+ return [:DEFINE, yytext]
+ when '{'
+ #puts "got {"
+ @inobject = true
+ return [:LCURLY, yytext]
+ else
+ unless @inobject
+ #puts "got type: #{yytext}"
+ if yytext =~ /\W/
+ giveback = yytext.dup
+ giveback.sub!(/^\w+/,'')
+ #puts "giveback #{giveback}"
+ #puts "yytext #{yytext}"
+ yytext.sub!(/\W.*$/,'')
+ #puts "yytext #{yytext}"
+ #puts "all [#{giveback} #{yytext} #{orig}]"
+ @src = giveback + @src
+ end
+ return [:NAME, yytext]
+ else
+ if yytext == '}'
+ #puts "got closure: #{yytext}"
+ @inobject = false
+ return [:RCURLY, '}']
+ end
+
+ unless @invar
+ @invar = true
+ return [:PARAM, $1]
+ else
+ end
end
+ end
+ end
+ end
end
def next_token
- token
+ token
end
def yydebug
- 1
+ 1
end
def yywrap
- 0
+ 0
end
def on_error(token, value, vstack )
- msg = ""
- unless value.nil?
- msg = "line #{@line}: syntax error at '#{value}'"
- else
- msg = "line #{@line}: syntax error at '#{token}'"
- end
- msg = "line #{@line}: Unexpected end of file" unless @src.size > 0
- if token == '$end'.intern
- puts "okay, this is silly"
- else
- raise ::Nagios::Parser::SyntaxError, msg
- end
+ msg = ""
+ unless value.nil?
+ msg = "line #{@line}: syntax error at '#{value}'"
+ else
+ msg = "line #{@line}: syntax error at '#{token}'"
+ end
+ msg = "line #{@line}: Unexpected end of file" unless @src.size > 0
+ if token == '$end'.intern
+ puts "okay, this is silly"
+ else
+ raise ::Nagios::Parser::SyntaxError, msg
+ end
end
..end grammar.ry modeval..idcb2ea30b34
##### racc 1.4.5 generates ###
racc_reduce_table = [
- 0, 0, :racc_error,
- 1, 13, :_reduce_1,
- 2, 13, :_reduce_2,
- 1, 14, :_reduce_3,
- 1, 14, :_reduce_4,
- 1, 14, :_reduce_none,
- 2, 16, :_reduce_6,
- 6, 15, :_reduce_7,
- 1, 17, :_reduce_none,
- 2, 17, :_reduce_9,
- 4, 18, :_reduce_10,
- 1, 20, :_reduce_none,
- 2, 20, :_reduce_none,
- 0, 19, :_reduce_none,
- 1, 19, :_reduce_none ]
+ 0, 0, :racc_error,
+ 1, 13, :_reduce_1,
+ 2, 13, :_reduce_2,
+ 1, 14, :_reduce_3,
+ 1, 14, :_reduce_4,
+ 1, 14, :_reduce_none,
+ 2, 16, :_reduce_6,
+ 6, 15, :_reduce_7,
+ 1, 17, :_reduce_none,
+ 2, 17, :_reduce_9,
+ 4, 18, :_reduce_10,
+ 1, 20, :_reduce_none,
+ 2, 20, :_reduce_none,
+ 0, 19, :_reduce_none,
+ 1, 19, :_reduce_none ]
racc_reduce_n = 15
racc_shift_n = 26
racc_action_table = [
- 9, 15, 1, 20, 1, 14, 12, 13, 11, 6,
- 7, 6, 7, 15, 18, 8, 21, 23, 25 ]
+ 9, 15, 1, 20, 1, 14, 12, 13, 11, 6,
+ 7, 6, 7, 15, 18, 8, 21, 23, 25 ]
racc_action_check = [
- 2, 16, 2, 16, 0, 12, 8, 9, 7, 2,
- 2, 0, 0, 14, 15, 1, 18, 22, 24 ]
+ 2, 16, 2, 16, 0, 12, 8, 9, 7, 2,
+ 2, 0, 0, 14, 15, 1, 18, 22, 24 ]
racc_action_pointer = [
- 2, 12, 0, nil, nil, nil, nil, -1, 0, 7,
- nil, nil, -4, nil, 8, 6, -4, nil, 5, nil,
- nil, nil, 8, nil, 9, nil ]
+ 2, 12, 0, nil, nil, nil, nil, -1, 0, 7,
+ nil, nil, -4, nil, 8, 6, -4, nil, 5, nil,
+ nil, nil, 8, nil, 9, nil ]
racc_action_default = [
- -15, -15, -15, -1, -3, -5, -4, -15, -15, -15,
- -2, -6, -15, 26, -15, -15, -15, -8, -13, -9,
- -7, -14, -15, -11, -10, -12 ]
+ -15, -15, -15, -1, -3, -5, -4, -15, -15, -15,
+ -2, -6, -15, 26, -15, -15, -15, -8, -13, -9,
+ -7, -14, -15, -11, -10, -12 ]
racc_goto_table = [ 17, 3, 19, 10, 2, 16, 22, 24 ]
@@ -625,38 +625,38 @@ racc_goto_pointer = [ nil, 4, 1, nil, nil, -9, -14, -12, -1
racc_goto_default = [ nil, nil, nil, 4, 5, nil, nil, nil, nil ]
racc_token_table = {
- false => 0,
- Object.new => 1,
- :DEFINE => 2,
- :NAME => 3,
- :STRING => 4,
- :PARAM => 5,
- :LCURLY => 6,
- :RCURLY => 7,
- :VALUE => 8,
- :RETURN => 9,
- :COMMENT => 10,
- :INLINECOMMENT => 11 }
+ false => 0,
+ Object.new => 1,
+ :DEFINE => 2,
+ :NAME => 3,
+ :STRING => 4,
+ :PARAM => 5,
+ :LCURLY => 6,
+ :RCURLY => 7,
+ :VALUE => 8,
+ :RETURN => 9,
+ :COMMENT => 10,
+ :INLINECOMMENT => 11 }
racc_use_result_var = true
racc_nt_base = 12
Racc_arg = [
- racc_action_table,
- racc_action_check,
- racc_action_default,
- racc_action_pointer,
- racc_goto_table,
- racc_goto_check,
- racc_goto_default,
- racc_goto_pointer,
- racc_nt_base,
- racc_reduce_table,
- racc_token_table,
- racc_shift_n,
- racc_reduce_n,
- racc_use_result_var ]
+ racc_action_table,
+ racc_action_check,
+ racc_action_default,
+ racc_action_pointer,
+ racc_goto_table,
+ racc_goto_check,
+ racc_goto_default,
+ racc_goto_pointer,
+ racc_nt_base,
+ racc_reduce_table,
+ racc_token_table,
+ racc_shift_n,
+ racc_reduce_n,
+ racc_use_result_var ]
Racc_token_to_s_table = [
'$end',
@@ -688,73 +688,73 @@ Racc_debug_parser = false
# reduce 0 omitted
module_eval <<'.,.,', 'grammar.ry', 6
- def _reduce_1( val, _values, result )
+ def _reduce_1( val, _values, result )
return val[0] if val[0]
- result
+ result
end
.,.,
module_eval <<'.,.,', 'grammar.ry', 18
- def _reduce_2( val, _values, result )
- if val[1].nil?
- result = val[0]
- else
- if val[0].nil?
- result = val[1]
- else
- result = [ val[0], val[1] ].flatten
- end
- end
- result
- end
+ def _reduce_2( val, _values, result )
+ if val[1].nil?
+ result = val[0]
+ else
+ if val[0].nil?
+ result = val[1]
+ else
+ result = [ val[0], val[1] ].flatten
+ end
+ end
+ result
+ end
.,.,
module_eval <<'.,.,', 'grammar.ry', 20
- def _reduce_3( val, _values, result )
+ def _reduce_3( val, _values, result )
result = [val[0]]
- result
+ result
end
.,.,
module_eval <<'.,.,', 'grammar.ry', 21
- def _reduce_4( val, _values, result )
+ def _reduce_4( val, _values, result )
result = nil
- result
+ result
end
.,.,
# reduce 5 omitted
module_eval <<'.,.,', 'grammar.ry', 25
- def _reduce_6( val, _values, result )
+ def _reduce_6( val, _values, result )
result = nil
- result
+ result
end
.,.,
module_eval <<'.,.,', 'grammar.ry', 31
- def _reduce_7( val, _values, result )
- result = Nagios::Base.create(val[1],val[4])
- result
- end
+ def _reduce_7( val, _values, result )
+ result = Nagios::Base.create(val[1],val[4])
+ result
+ end
.,.,
# reduce 8 omitted
module_eval <<'.,.,', 'grammar.ry', 40
- def _reduce_9( val, _values, result )
- val[1].each {|p,v|
- val[0][p] = v
- }
- result = val[0]
- result
- end
+ def _reduce_9( val, _values, result )
+ val[1].each {|p,v|
+ val[0][p] = v
+ }
+ result = val[0]
+ result
+ end
.,.,
module_eval <<'.,.,', 'grammar.ry', 42
- def _reduce_10( val, _values, result )
+ def _reduce_10( val, _values, result )
result = {val[0],val[1]}
- result
+ result
end
.,.,
@@ -767,9 +767,9 @@ end
# reduce 14 omitted
def _reduce_none( val, _values, result )
- result
+ result
end
- end
+ end
end
diff --git a/lib/puppet/external/pson/common.rb b/lib/puppet/external/pson/common.rb
index 17da5ad11..160a502d1 100644
--- a/lib/puppet/external/pson/common.rb
+++ b/lib/puppet/external/pson/common.rb
@@ -1,370 +1,370 @@
require 'puppet/external/pson/version'
module PSON
- class << self
- # If _object_ is string-like parse the string and return the parsed result
- # as a Ruby data structure. Otherwise generate a PSON text from the Ruby
- # data structure object and return it.
- #
- # The _opts_ argument is passed through to generate/parse respectively, see
- # generate and parse for their documentation.
- def [](object, opts = {})
- if object.respond_to? :to_str
- PSON.parse(object.to_str, opts => {})
- else
- PSON.generate(object, opts => {})
- end
- end
-
- # Returns the PSON parser class, that is used by PSON. This might be either
- # PSON::Ext::Parser or PSON::Pure::Parser.
- attr_reader :parser
-
- # Set the PSON parser class _parser_ to be used by PSON.
- def parser=(parser) # :nodoc:
- @parser = parser
- remove_const :Parser if const_defined? :Parser
- const_set :Parser, parser
- end
-
- def registered_document_types
- @registered_document_types ||= {}
- end
-
- # Register a class-constant for deserializaion.
- def register_document_type(name,klass)
- registered_document_types[name.to_s] = klass
- end
-
- # Return the constant located at _path_.
- # Anything may be registered as a path by calling register_path, above.
- # Otherwise, the format of _path_ has to be either ::A::B::C or A::B::C.
- # In either of these cases A has to be defined in Object (e.g. the path
- # must be an absolute namespace path. If the constant doesn't exist at
- # the given path, an ArgumentError is raised.
- def deep_const_get(path) # :nodoc:
- path = path.to_s
- registered_document_types[path] || path.split(/::/).inject(Object) do |p, c|
- case
- when c.empty? then p
- when p.const_defined?(c) then p.const_get(c)
- else raise ArgumentError, "can't find const for unregistered document type #{path}"
- end
- end
- end
-
- # Set the module _generator_ to be used by PSON.
- def generator=(generator) # :nodoc:
- @generator = generator
- generator_methods = generator::GeneratorMethods
- for const in generator_methods.constants
- klass = deep_const_get(const)
- modul = generator_methods.const_get(const)
- klass.class_eval do
- instance_methods(false).each do |m|
- m.to_s == 'to_pson' and remove_method m
- end
- include modul
- end
- end
- self.state = generator::State
- const_set :State, self.state
- end
-
- # Returns the PSON generator modul, that is used by PSON. This might be
- # either PSON::Ext::Generator or PSON::Pure::Generator.
- attr_reader :generator
-
- # Returns the PSON generator state class, that is used by PSON. This might
- # be either PSON::Ext::Generator::State or PSON::Pure::Generator::State.
- attr_accessor :state
-
- # This is create identifier, that is used to decide, if the _pson_create_
- # hook of a class should be called. It defaults to 'document_type'.
- attr_accessor :create_id
- end
- self.create_id = 'document_type'
-
- NaN = (-1.0) ** 0.5
-
- Infinity = 1.0/0
-
- MinusInfinity = -Infinity
-
- # The base exception for PSON errors.
- class PSONError < StandardError; end
-
- # This exception is raised, if a parser error occurs.
- class ParserError < PSONError; end
-
- # This exception is raised, if the nesting of parsed datastructures is too
- # deep.
- class NestingError < ParserError; end
-
- # This exception is raised, if a generator or unparser error occurs.
- class GeneratorError < PSONError; end
- # For backwards compatibility
- UnparserError = GeneratorError
-
- # If a circular data structure is encountered while unparsing
- # this exception is raised.
- class CircularDatastructure < GeneratorError; end
-
- # This exception is raised, if the required unicode support is missing on the
- # system. Usually this means, that the iconv library is not installed.
- class MissingUnicodeSupport < PSONError; end
-
- module_function
-
- # Parse the PSON string _source_ into a Ruby data structure and return it.
+ class << self
+ # If _object_ is string-like parse the string and return the parsed result
+ # as a Ruby data structure. Otherwise generate a PSON text from the Ruby
+ # data structure object and return it.
#
- # _opts_ can have the following
- # keys:
- # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
- # structures. Disable depth checking with :max_nesting => false, it defaults
- # to 19.
- # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
- # defiance of RFC 4627 to be parsed by the Parser. This option defaults
- # to false.
- # * *create_additions*: If set to false, the Parser doesn't create
- # additions even if a matchin class and create_id was found. This option
- # defaults to true.
- def parse(source, opts = {})
- PSON.parser.new(source, opts).parse
+ # The _opts_ argument is passed through to generate/parse respectively, see
+ # generate and parse for their documentation.
+ def [](object, opts = {})
+ if object.respond_to? :to_str
+ PSON.parse(object.to_str, opts => {})
+ else
+ PSON.generate(object, opts => {})
+ end
end
- # Parse the PSON string _source_ into a Ruby data structure and return it.
- # The bang version of the parse method, defaults to the more dangerous values
- # for the _opts_ hash, so be sure only to parse trusted _source_ strings.
- #
- # _opts_ can have the following keys:
- # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
- # structures. Enable depth checking with :max_nesting => anInteger. The parse!
- # methods defaults to not doing max depth checking: This can be dangerous,
- # if someone wants to fill up your stack.
- # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
- # defiance of RFC 4627 to be parsed by the Parser. This option defaults
- # to true.
- # * *create_additions*: If set to false, the Parser doesn't create
- # additions even if a matchin class and create_id was found. This option
- # defaults to true.
- def parse!(source, opts = {})
- opts = {
- :max_nesting => false,
- :allow_nan => true
- }.update(opts)
- PSON.parser.new(source, opts).parse
- end
+ # Returns the PSON parser class, that is used by PSON. This might be either
+ # PSON::Ext::Parser or PSON::Pure::Parser.
+ attr_reader :parser
- # Unparse the Ruby data structure _obj_ into a single line PSON string and
- # return it. _state_ is
- # * a PSON::State object,
- # * or a Hash like object (responding to to_hash),
- # * an object convertible into a hash by a to_h method,
- # that is used as or to configure a State object.
- #
- # It defaults to a state object, that creates the shortest possible PSON text
- # in one line, checks for circular data structures and doesn't allow NaN,
- # Infinity, and -Infinity.
- #
- # A _state_ hash can have the following keys:
- # * *indent*: a string used to indent levels (default: ''),
- # * *space*: a string that is put after, a : or , delimiter (default: ''),
- # * *space_before*: a string that is put before a : pair delimiter (default: ''),
- # * *object_nl*: a string that is put at the end of a PSON object (default: ''),
- # * *array_nl*: a string that is put at the end of a PSON array (default: ''),
- # * *check_circular*: true if checking for circular data structures
- # should be done (the default), false otherwise.
- # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
- # generated, otherwise an exception is thrown, if these values are
- # encountered. This options defaults to false.
- # * *max_nesting*: The maximum depth of nesting allowed in the data
- # structures from which PSON is to be generated. Disable depth checking
- # with :max_nesting => false, it defaults to 19.
- #
- # See also the fast_generate for the fastest creation method with the least
- # amount of sanity checks, and the pretty_generate method for some
- # defaults for a pretty output.
- def generate(obj, state = nil)
- if state
- state = State.from_state(state)
- else
- state = State.new
- end
- obj.to_pson(state)
+ # Set the PSON parser class _parser_ to be used by PSON.
+ def parser=(parser) # :nodoc:
+ @parser = parser
+ remove_const :Parser if const_defined? :Parser
+ const_set :Parser, parser
end
- # :stopdoc:
- # I want to deprecate these later, so I'll first be silent about them, and
- # later delete them.
- alias unparse generate
- module_function :unparse
- # :startdoc:
-
- # Unparse the Ruby data structure _obj_ into a single line PSON string and
- # return it. This method disables the checks for circles in Ruby objects, and
- # also generates NaN, Infinity, and, -Infinity float values.
- #
- # *WARNING*: Be careful not to pass any Ruby data structures with circles as
- # _obj_ argument, because this will cause PSON to go into an infinite loop.
- def fast_generate(obj)
- obj.to_pson(nil)
+ def registered_document_types
+ @registered_document_types ||= {}
end
- # :stopdoc:
- # I want to deprecate these later, so I'll first be silent about them, and later delete them.
- alias fast_unparse fast_generate
- module_function :fast_unparse
- # :startdoc:
-
- # Unparse the Ruby data structure _obj_ into a PSON string and return it. The
- # returned string is a prettier form of the string returned by #unparse.
- #
- # The _opts_ argument can be used to configure the generator, see the
- # generate method for a more detailed explanation.
- def pretty_generate(obj, opts = nil)
-
- state = PSON.state.new(
-
- :indent => ' ',
- :space => ' ',
- :object_nl => "\n",
- :array_nl => "\n",
-
- :check_circular => true
- )
- if opts
- if opts.respond_to? :to_hash
- opts = opts.to_hash
- elsif opts.respond_to? :to_h
- opts = opts.to_h
- else
- raise TypeError, "can't convert #{opts.class} into Hash"
- end
- state.configure(opts)
- end
- obj.to_pson(state)
+ # Register a class-constant for deserializaion.
+ def register_document_type(name,klass)
+ registered_document_types[name.to_s] = klass
end
- # :stopdoc:
- # I want to deprecate these later, so I'll first be silent about them, and later delete them.
- alias pretty_unparse pretty_generate
- module_function :pretty_unparse
- # :startdoc:
-
- # Load a ruby data structure from a PSON _source_ and return it. A source can
- # either be a string-like object, an IO like object, or an object responding
- # to the read method. If _proc_ was given, it will be called with any nested
- # Ruby object as an argument recursively in depth first order.
- #
- # This method is part of the implementation of the load/dump interface of
- # Marshal and YAML.
- def load(source, proc = nil)
- if source.respond_to? :to_str
- source = source.to_str
- elsif source.respond_to? :to_io
- source = source.to_io.read
- else
- source = source.read
+ # Return the constant located at _path_.
+ # Anything may be registered as a path by calling register_path, above.
+ # Otherwise, the format of _path_ has to be either ::A::B::C or A::B::C.
+ # In either of these cases A has to be defined in Object (e.g. the path
+ # must be an absolute namespace path. If the constant doesn't exist at
+ # the given path, an ArgumentError is raised.
+ def deep_const_get(path) # :nodoc:
+ path = path.to_s
+ registered_document_types[path] || path.split(/::/).inject(Object) do |p, c|
+ case
+ when c.empty? then p
+ when p.const_defined?(c) then p.const_get(c)
+ else raise ArgumentError, "can't find const for unregistered document type #{path}"
end
- result = parse(source, :max_nesting => false, :allow_nan => true)
- recurse_proc(result, &proc) if proc
- result
+ end
end
- def recurse_proc(result, &proc)
- case result
- when Array
- result.each { |x| recurse_proc x, &proc }
- proc.call result
- when Hash
- result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
- proc.call result
- else
- proc.call result
+ # Set the module _generator_ to be used by PSON.
+ def generator=(generator) # :nodoc:
+ @generator = generator
+ generator_methods = generator::GeneratorMethods
+ for const in generator_methods.constants
+ klass = deep_const_get(const)
+ modul = generator_methods.const_get(const)
+ klass.class_eval do
+ instance_methods(false).each do |m|
+ m.to_s == 'to_pson' and remove_method m
+ end
+ include modul
end
+ end
+ self.state = generator::State
+ const_set :State, self.state
end
- private :recurse_proc
- module_function :recurse_proc
-
- alias restore load
- module_function :restore
- # Dumps _obj_ as a PSON string, i.e. calls generate on the object and returns
- # the result.
- #
- # If anIO (an IO like object or an object that responds to the write method)
- # was given, the resulting PSON is written to it.
- #
- # If the number of nested arrays or objects exceeds _limit_ an ArgumentError
- # exception is raised. This argument is similar (but not exactly the
- # same!) to the _limit_ argument in Marshal.dump.
- #
- # This method is part of the implementation of the load/dump interface of
- # Marshal and YAML.
- def dump(obj, anIO = nil, limit = nil)
- if anIO and limit.nil?
- anIO = anIO.to_io if anIO.respond_to?(:to_io)
- unless anIO.respond_to?(:write)
- limit = anIO
- anIO = nil
- end
- end
- limit ||= 0
- result = generate(obj, :allow_nan => true, :max_nesting => limit)
- if anIO
- anIO.write result
- anIO
- else
- result
- end
- rescue PSON::NestingError
- raise ArgumentError, "exceed depth limit"
+ # Returns the PSON generator modul, that is used by PSON. This might be
+ # either PSON::Ext::Generator or PSON::Pure::Generator.
+ attr_reader :generator
+
+ # Returns the PSON generator state class, that is used by PSON. This might
+ # be either PSON::Ext::Generator::State or PSON::Pure::Generator::State.
+ attr_accessor :state
+
+ # This is create identifier, that is used to decide, if the _pson_create_
+ # hook of a class should be called. It defaults to 'document_type'.
+ attr_accessor :create_id
+ end
+ self.create_id = 'document_type'
+
+ NaN = (-1.0) ** 0.5
+
+ Infinity = 1.0/0
+
+ MinusInfinity = -Infinity
+
+ # The base exception for PSON errors.
+ class PSONError < StandardError; end
+
+ # This exception is raised, if a parser error occurs.
+ class ParserError < PSONError; end
+
+ # This exception is raised, if the nesting of parsed datastructures is too
+ # deep.
+ class NestingError < ParserError; end
+
+ # This exception is raised, if a generator or unparser error occurs.
+ class GeneratorError < PSONError; end
+ # For backwards compatibility
+ UnparserError = GeneratorError
+
+ # If a circular data structure is encountered while unparsing
+ # this exception is raised.
+ class CircularDatastructure < GeneratorError; end
+
+ # This exception is raised, if the required unicode support is missing on the
+ # system. Usually this means, that the iconv library is not installed.
+ class MissingUnicodeSupport < PSONError; end
+
+ module_function
+
+ # Parse the PSON string _source_ into a Ruby data structure and return it.
+ #
+ # _opts_ can have the following
+ # keys:
+ # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+ # structures. Disable depth checking with :max_nesting => false, it defaults
+ # to 19.
+ # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+ # defiance of RFC 4627 to be parsed by the Parser. This option defaults
+ # to false.
+ # * *create_additions*: If set to false, the Parser doesn't create
+ # additions even if a matchin class and create_id was found. This option
+ # defaults to true.
+ def parse(source, opts = {})
+ PSON.parser.new(source, opts).parse
+ end
+
+ # Parse the PSON string _source_ into a Ruby data structure and return it.
+ # The bang version of the parse method, defaults to the more dangerous values
+ # for the _opts_ hash, so be sure only to parse trusted _source_ strings.
+ #
+ # _opts_ can have the following keys:
+ # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+ # structures. Enable depth checking with :max_nesting => anInteger. The parse!
+ # methods defaults to not doing max depth checking: This can be dangerous,
+ # if someone wants to fill up your stack.
+ # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
+ # defiance of RFC 4627 to be parsed by the Parser. This option defaults
+ # to true.
+ # * *create_additions*: If set to false, the Parser doesn't create
+ # additions even if a matchin class and create_id was found. This option
+ # defaults to true.
+ def parse!(source, opts = {})
+ opts = {
+ :max_nesting => false,
+ :allow_nan => true
+ }.update(opts)
+ PSON.parser.new(source, opts).parse
+ end
+
+ # Unparse the Ruby data structure _obj_ into a single line PSON string and
+ # return it. _state_ is
+ # * a PSON::State object,
+ # * or a Hash like object (responding to to_hash),
+ # * an object convertible into a hash by a to_h method,
+ # that is used as or to configure a State object.
+ #
+ # It defaults to a state object, that creates the shortest possible PSON text
+ # in one line, checks for circular data structures and doesn't allow NaN,
+ # Infinity, and -Infinity.
+ #
+ # A _state_ hash can have the following keys:
+ # * *indent*: a string used to indent levels (default: ''),
+ # * *space*: a string that is put after, a : or , delimiter (default: ''),
+ # * *space_before*: a string that is put before a : pair delimiter (default: ''),
+ # * *object_nl*: a string that is put at the end of a PSON object (default: ''),
+ # * *array_nl*: a string that is put at the end of a PSON array (default: ''),
+ # * *check_circular*: true if checking for circular data structures
+ # should be done (the default), false otherwise.
+ # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
+ # generated, otherwise an exception is thrown, if these values are
+ # encountered. This options defaults to false.
+ # * *max_nesting*: The maximum depth of nesting allowed in the data
+ # structures from which PSON is to be generated. Disable depth checking
+ # with :max_nesting => false, it defaults to 19.
+ #
+ # See also the fast_generate for the fastest creation method with the least
+ # amount of sanity checks, and the pretty_generate method for some
+ # defaults for a pretty output.
+ def generate(obj, state = nil)
+ if state
+ state = State.from_state(state)
+ else
+ state = State.new
+ end
+ obj.to_pson(state)
+ end
+
+ # :stopdoc:
+ # I want to deprecate these later, so I'll first be silent about them, and
+ # later delete them.
+ alias unparse generate
+ module_function :unparse
+ # :startdoc:
+
+ # Unparse the Ruby data structure _obj_ into a single line PSON string and
+ # return it. This method disables the checks for circles in Ruby objects, and
+ # also generates NaN, Infinity, and, -Infinity float values.
+ #
+ # *WARNING*: Be careful not to pass any Ruby data structures with circles as
+ # _obj_ argument, because this will cause PSON to go into an infinite loop.
+ def fast_generate(obj)
+ obj.to_pson(nil)
+ end
+
+ # :stopdoc:
+ # I want to deprecate these later, so I'll first be silent about them, and later delete them.
+ alias fast_unparse fast_generate
+ module_function :fast_unparse
+ # :startdoc:
+
+ # Unparse the Ruby data structure _obj_ into a PSON string and return it. The
+ # returned string is a prettier form of the string returned by #unparse.
+ #
+ # The _opts_ argument can be used to configure the generator, see the
+ # generate method for a more detailed explanation.
+ def pretty_generate(obj, opts = nil)
+
+ state = PSON.state.new(
+
+ :indent => ' ',
+ :space => ' ',
+ :object_nl => "\n",
+ :array_nl => "\n",
+
+ :check_circular => true
+ )
+ if opts
+ if opts.respond_to? :to_hash
+ opts = opts.to_hash
+ elsif opts.respond_to? :to_h
+ opts = opts.to_h
+ else
+ raise TypeError, "can't convert #{opts.class} into Hash"
+ end
+ state.configure(opts)
+ end
+ obj.to_pson(state)
+ end
+
+ # :stopdoc:
+ # I want to deprecate these later, so I'll first be silent about them, and later delete them.
+ alias pretty_unparse pretty_generate
+ module_function :pretty_unparse
+ # :startdoc:
+
+ # Load a ruby data structure from a PSON _source_ and return it. A source can
+ # either be a string-like object, an IO like object, or an object responding
+ # to the read method. If _proc_ was given, it will be called with any nested
+ # Ruby object as an argument recursively in depth first order.
+ #
+ # This method is part of the implementation of the load/dump interface of
+ # Marshal and YAML.
+ def load(source, proc = nil)
+ if source.respond_to? :to_str
+ source = source.to_str
+ elsif source.respond_to? :to_io
+ source = source.to_io.read
+ else
+ source = source.read
+ end
+ result = parse(source, :max_nesting => false, :allow_nan => true)
+ recurse_proc(result, &proc) if proc
+ result
+ end
+
+ def recurse_proc(result, &proc)
+ case result
+ when Array
+ result.each { |x| recurse_proc x, &proc }
+ proc.call result
+ when Hash
+ result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
+ proc.call result
+ else
+ proc.call result
end
+ end
+ private :recurse_proc
+ module_function :recurse_proc
+
+ alias restore load
+ module_function :restore
+
+ # Dumps _obj_ as a PSON string, i.e. calls generate on the object and returns
+ # the result.
+ #
+ # If anIO (an IO like object or an object that responds to the write method)
+ # was given, the resulting PSON is written to it.
+ #
+ # If the number of nested arrays or objects exceeds _limit_ an ArgumentError
+ # exception is raised. This argument is similar (but not exactly the
+ # same!) to the _limit_ argument in Marshal.dump.
+ #
+ # This method is part of the implementation of the load/dump interface of
+ # Marshal and YAML.
+ def dump(obj, anIO = nil, limit = nil)
+ if anIO and limit.nil?
+ anIO = anIO.to_io if anIO.respond_to?(:to_io)
+ unless anIO.respond_to?(:write)
+ limit = anIO
+ anIO = nil
+ end
+ end
+ limit ||= 0
+ result = generate(obj, :allow_nan => true, :max_nesting => limit)
+ if anIO
+ anIO.write result
+ anIO
+ else
+ result
+ end
+ rescue PSON::NestingError
+ raise ArgumentError, "exceed depth limit"
+ end
end
module ::Kernel
- private
+ private
- # Outputs _objs_ to STDOUT as PSON strings in the shortest form, that is in
- # one line.
- def j(*objs)
- objs.each do |obj|
- puts PSON::generate(obj, :allow_nan => true, :max_nesting => false)
- end
- nil
+ # Outputs _objs_ to STDOUT as PSON strings in the shortest form, that is in
+ # one line.
+ def j(*objs)
+ objs.each do |obj|
+ puts PSON::generate(obj, :allow_nan => true, :max_nesting => false)
end
-
- # Ouputs _objs_ to STDOUT as PSON strings in a pretty format, with
- # indentation and over many lines.
- def jj(*objs)
- objs.each do |obj|
- puts PSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
- end
- nil
+ nil
+ end
+
+ # Ouputs _objs_ to STDOUT as PSON strings in a pretty format, with
+ # indentation and over many lines.
+ def jj(*objs)
+ objs.each do |obj|
+ puts PSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
end
-
- # If _object_ is string-like parse the string and return the parsed result as
- # a Ruby data structure. Otherwise generate a PSON text from the Ruby data
- # structure object and return it.
- #
- # The _opts_ argument is passed through to generate/parse respectively, see
- # generate and parse for their documentation.
- def PSON(object, opts = {})
- if object.respond_to? :to_str
- PSON.parse(object.to_str, opts)
- else
- PSON.generate(object, opts)
- end
+ nil
+ end
+
+ # If _object_ is string-like parse the string and return the parsed result as
+ # a Ruby data structure. Otherwise generate a PSON text from the Ruby data
+ # structure object and return it.
+ #
+ # The _opts_ argument is passed through to generate/parse respectively, see
+ # generate and parse for their documentation.
+ def PSON(object, opts = {})
+ if object.respond_to? :to_str
+ PSON.parse(object.to_str, opts)
+ else
+ PSON.generate(object, opts)
end
+ end
end
class ::Class
- # Returns true, if this class can be used to create an instance
- # from a serialised PSON string. The class has to implement a class
- # method _pson_create_ that expects a hash as first parameter, which includes
- # the required data.
- def pson_creatable?
- respond_to?(:pson_create)
- end
+ # Returns true, if this class can be used to create an instance
+ # from a serialised PSON string. The class has to implement a class
+ # method _pson_create_ that expects a hash as first parameter, which includes
+ # the required data.
+ def pson_creatable?
+ respond_to?(:pson_create)
+ end
end
diff --git a/lib/puppet/external/pson/pure.rb b/lib/puppet/external/pson/pure.rb
index dffd06d92..53d1ea2a7 100644
--- a/lib/puppet/external/pson/pure.rb
+++ b/lib/puppet/external/pson/pure.rb
@@ -3,75 +3,75 @@ require 'puppet/external/pson/pure/parser'
require 'puppet/external/pson/pure/generator'
module PSON
+ begin
+ require 'iconv'
+ # An iconv instance to convert from UTF8 to UTF16 Big Endian.
+ UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be') # :nodoc:
+ # An iconv instance to convert from UTF16 Big Endian to UTF8.
+ UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8') # :nodoc:
+ UTF8toUTF16.iconv('no bom')
+ rescue LoadError
+ # We actually don't care
+ Puppet.warning "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions"
+ rescue Errno::EINVAL, Iconv::InvalidEncoding
+ # Iconv doesn't support big endian utf-16. Let's try to hack this manually
+ # into the converters.
begin
- require 'iconv'
- # An iconv instance to convert from UTF8 to UTF16 Big Endian.
- UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be') # :nodoc:
- # An iconv instance to convert from UTF16 Big Endian to UTF8.
- UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8') # :nodoc:
- UTF8toUTF16.iconv('no bom')
- rescue LoadError
- # We actually don't care
- Puppet.warning "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions"
- rescue Errno::EINVAL, Iconv::InvalidEncoding
- # Iconv doesn't support big endian utf-16. Let's try to hack this manually
- # into the converters.
- begin
- old_verbose, $VERBSOSE = $VERBOSE, nil
- # An iconv instance to convert from UTF8 to UTF16 Big Endian.
- UTF16toUTF8 = Iconv.new('utf-8', 'utf-16') # :nodoc:
- # An iconv instance to convert from UTF16 Big Endian to UTF8.
- UTF8toUTF16 = Iconv.new('utf-16', 'utf-8') # :nodoc:
- UTF8toUTF16.iconv('no bom')
- if UTF8toUTF16.iconv("\xe2\x82\xac") == "\xac\x20"
- swapper = Class.new do
- def initialize(iconv) # :nodoc:
- @iconv = iconv
- end
-
- def iconv(string) # :nodoc:
- result = @iconv.iconv(string)
- PSON.swap!(result)
- end
- end
- UTF8toUTF16 = swapper.new(UTF8toUTF16) # :nodoc:
- end
- if UTF16toUTF8.iconv("\xac\x20") == "\xe2\x82\xac"
- swapper = Class.new do
- def initialize(iconv) # :nodoc:
- @iconv = iconv
- end
+ old_verbose, $VERBSOSE = $VERBOSE, nil
+ # An iconv instance to convert from UTF8 to UTF16 Big Endian.
+ UTF16toUTF8 = Iconv.new('utf-8', 'utf-16') # :nodoc:
+ # An iconv instance to convert from UTF16 Big Endian to UTF8.
+ UTF8toUTF16 = Iconv.new('utf-16', 'utf-8') # :nodoc:
+ UTF8toUTF16.iconv('no bom')
+ if UTF8toUTF16.iconv("\xe2\x82\xac") == "\xac\x20"
+ swapper = Class.new do
+ def initialize(iconv) # :nodoc:
+ @iconv = iconv
+ end
- def iconv(string) # :nodoc:
- string = PSON.swap!(string.dup)
- @iconv.iconv(string)
- end
- end
- UTF16toUTF8 = swapper.new(UTF16toUTF8) # :nodoc:
- end
- rescue Errno::EINVAL, Iconv::InvalidEncoding
- Puppet.warning "iconv doesn't seem to support UTF-8/UTF-16 conversions"
- ensure
- $VERBOSE = old_verbose
+ def iconv(string) # :nodoc:
+ result = @iconv.iconv(string)
+ PSON.swap!(result)
+ end
end
- end
+ UTF8toUTF16 = swapper.new(UTF8toUTF16) # :nodoc:
+ end
+ if UTF16toUTF8.iconv("\xac\x20") == "\xe2\x82\xac"
+ swapper = Class.new do
+ def initialize(iconv) # :nodoc:
+ @iconv = iconv
+ end
- # Swap consecutive bytes of _string_ in place.
- def self.swap!(string) # :nodoc:
- 0.upto(string.size / 2) do |i|
- break unless string[2 * i + 1]
- string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i]
+ def iconv(string) # :nodoc:
+ string = PSON.swap!(string.dup)
+ @iconv.iconv(string)
+ end
end
- string
+ UTF16toUTF8 = swapper.new(UTF16toUTF8) # :nodoc:
+ end
+ rescue Errno::EINVAL, Iconv::InvalidEncoding
+ Puppet.warning "iconv doesn't seem to support UTF-8/UTF-16 conversions"
+ ensure
+ $VERBOSE = old_verbose
end
+ end
- # This module holds all the modules/classes that implement PSON's
- # functionality in pure ruby.
- module Pure
- $DEBUG and warn "Using pure library for PSON."
- PSON.parser = Parser
- PSON.generator = Generator
+ # Swap consecutive bytes of _string_ in place.
+ def self.swap!(string) # :nodoc:
+ 0.upto(string.size / 2) do |i|
+ break unless string[2 * i + 1]
+ string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i]
end
+ string
+ end
+
+ # This module holds all the modules/classes that implement PSON's
+ # functionality in pure ruby.
+ module Pure
+ $DEBUG and warn "Using pure library for PSON."
+ PSON.parser = Parser
+ PSON.generator = Generator
+ end
- PSON_LOADED = true
+ PSON_LOADED = true
end
diff --git a/lib/puppet/external/pson/pure/generator.rb b/lib/puppet/external/pson/pure/generator.rb
index 42981b9dc..ef8b36d31 100644
--- a/lib/puppet/external/pson/pure/generator.rb
+++ b/lib/puppet/external/pson/pure/generator.rb
@@ -1,429 +1,429 @@
module PSON
- MAP = {
- "\x0" => '\u0000',
- "\x1" => '\u0001',
- "\x2" => '\u0002',
- "\x3" => '\u0003',
- "\x4" => '\u0004',
- "\x5" => '\u0005',
- "\x6" => '\u0006',
- "\x7" => '\u0007',
- "\b" => '\b',
- "\t" => '\t',
- "\n" => '\n',
- "\xb" => '\u000b',
- "\f" => '\f',
- "\r" => '\r',
- "\xe" => '\u000e',
- "\xf" => '\u000f',
- "\x10" => '\u0010',
- "\x11" => '\u0011',
- "\x12" => '\u0012',
- "\x13" => '\u0013',
- "\x14" => '\u0014',
- "\x15" => '\u0015',
- "\x16" => '\u0016',
- "\x17" => '\u0017',
- "\x18" => '\u0018',
- "\x19" => '\u0019',
- "\x1a" => '\u001a',
- "\x1b" => '\u001b',
- "\x1c" => '\u001c',
- "\x1d" => '\u001d',
- "\x1e" => '\u001e',
- "\x1f" => '\u001f',
- '"' => '\"',
- '\\' => '\\\\',
- } # :nodoc:
-
- # Convert a UTF8 encoded Ruby string _string_ to a PSON string, encoded with
- # UTF16 big endian characters as \u????, and return it.
- if String.method_defined?(:force_encoding)
- def utf8_to_pson(string) # :nodoc:
- string = string.dup
- string << '' # XXX workaround: avoid buffer sharing
- string.force_encoding(Encoding::ASCII_8BIT)
- string.gsub!(/["\\\x0-\x1f]/) { MAP[$MATCH] }
- string.gsub!(/(
- (?:
- [\xc2-\xdf][\x80-\xbf] |
- [\xe0-\xef][\x80-\xbf]{2} |
- [\xf0-\xf4][\x80-\xbf]{3}
- )+ |
- [\x80-\xc1\xf5-\xff] # invalid
- )/nx) { |c|
- c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
- s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
- s.gsub!(/.{4}/n, '\\\\u\&')
- }
- string.force_encoding(Encoding::UTF_8)
- string
- rescue Iconv::Failure => e
- raise GeneratorError, "Caught #{e.class}: #{e}"
- end
- else
- def utf8_to_pson(string) # :nodoc:
- string = string.gsub(/["\\\x0-\x1f]/) { MAP[$MATCH] }
- string.gsub!(/(
- (?:
- [\xc2-\xdf][\x80-\xbf] |
- [\xe0-\xef][\x80-\xbf]{2} |
- [\xf0-\xf4][\x80-\xbf]{3}
- )+ |
- [\x80-\xc1\xf5-\xff] # invalid
- )/nx) { |c|
+ MAP = {
+ "\x0" => '\u0000',
+ "\x1" => '\u0001',
+ "\x2" => '\u0002',
+ "\x3" => '\u0003',
+ "\x4" => '\u0004',
+ "\x5" => '\u0005',
+ "\x6" => '\u0006',
+ "\x7" => '\u0007',
+ "\b" => '\b',
+ "\t" => '\t',
+ "\n" => '\n',
+ "\xb" => '\u000b',
+ "\f" => '\f',
+ "\r" => '\r',
+ "\xe" => '\u000e',
+ "\xf" => '\u000f',
+ "\x10" => '\u0010',
+ "\x11" => '\u0011',
+ "\x12" => '\u0012',
+ "\x13" => '\u0013',
+ "\x14" => '\u0014',
+ "\x15" => '\u0015',
+ "\x16" => '\u0016',
+ "\x17" => '\u0017',
+ "\x18" => '\u0018',
+ "\x19" => '\u0019',
+ "\x1a" => '\u001a',
+ "\x1b" => '\u001b',
+ "\x1c" => '\u001c',
+ "\x1d" => '\u001d',
+ "\x1e" => '\u001e',
+ "\x1f" => '\u001f',
+ '"' => '\"',
+ '\\' => '\\\\',
+ } # :nodoc:
+
+ # Convert a UTF8 encoded Ruby string _string_ to a PSON string, encoded with
+ # UTF16 big endian characters as \u????, and return it.
+ if String.method_defined?(:force_encoding)
+ def utf8_to_pson(string) # :nodoc:
+ string = string.dup
+ string << '' # XXX workaround: avoid buffer sharing
+ string.force_encoding(Encoding::ASCII_8BIT)
+ string.gsub!(/["\\\x0-\x1f]/) { MAP[$MATCH] }
+ string.gsub!(/(
+ (?:
+ [\xc2-\xdf][\x80-\xbf] |
+ [\xe0-\xef][\x80-\xbf]{2} |
+ [\xf0-\xf4][\x80-\xbf]{3}
+ )+ |
+ [\x80-\xc1\xf5-\xff] # invalid
+ )/nx) { |c|
c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
s.gsub!(/.{4}/n, '\\\\u\&')
- }
- string
- rescue Iconv::Failure => e
- raise GeneratorError, "Caught #{e.class}: #{e}"
- end
+ }
+ string.force_encoding(Encoding::UTF_8)
+ string
+ rescue Iconv::Failure => e
+ raise GeneratorError, "Caught #{e.class}: #{e}"
+ end
+ else
+ def utf8_to_pson(string) # :nodoc:
+ string = string.gsub(/["\\\x0-\x1f]/) { MAP[$MATCH] }
+ string.gsub!(/(
+ (?:
+ [\xc2-\xdf][\x80-\xbf] |
+ [\xe0-\xef][\x80-\xbf]{2} |
+ [\xf0-\xf4][\x80-\xbf]{3}
+ )+ |
+ [\x80-\xc1\xf5-\xff] # invalid
+ )/nx) { |c|
+ c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
+ s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
+ s.gsub!(/.{4}/n, '\\\\u\&')
+ }
+ string
+ rescue Iconv::Failure => e
+ raise GeneratorError, "Caught #{e.class}: #{e}"
end
- module_function :utf8_to_pson
-
- module Pure
- module Generator
- # This class is used to create State instances, that are use to hold data
- # while generating a PSON text from a a Ruby data structure.
- class State
- # Creates a State object from _opts_, which ought to be Hash to create
- # a new State instance configured by _opts_, something else to create
- # an unconfigured instance. If _opts_ is a State object, it is just
- # returned.
- def self.from_state(opts)
- case opts
- when self
- opts
- when Hash
- new(opts)
- else
- new
- end
- end
-
- # Instantiates a new State object, configured by _opts_.
- #
- # _opts_ can have the following keys:
- #
- # * *indent*: a string used to indent levels (default: ''),
- # * *space*: a string that is put after, a : or , delimiter (default: ''),
- # * *space_before*: a string that is put before a : pair delimiter (default: ''),
- # * *object_nl*: a string that is put at the end of a PSON object (default: ''),
- # * *array_nl*: a string that is put at the end of a PSON array (default: ''),
- # * *check_circular*: true if checking for circular data structures
- # should be done (the default), false otherwise.
- # * *check_circular*: true if checking for circular data structures
- # should be done, false (the default) otherwise.
- # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
- # generated, otherwise an exception is thrown, if these values are
- # encountered. This options defaults to false.
- def initialize(opts = {})
- @seen = {}
- @indent = ''
- @space = ''
- @space_before = ''
- @object_nl = ''
- @array_nl = ''
- @check_circular = true
- @allow_nan = false
- configure opts
- end
-
- # This string is used to indent levels in the PSON text.
- attr_accessor :indent
-
- # This string is used to insert a space between the tokens in a PSON
- # string.
- attr_accessor :space
-
- # This string is used to insert a space before the ':' in PSON objects.
- attr_accessor :space_before
-
- # This string is put at the end of a line that holds a PSON object (or
- # Hash).
- attr_accessor :object_nl
-
- # This string is put at the end of a line that holds a PSON array.
- attr_accessor :array_nl
-
- # This integer returns the maximum level of data structure nesting in
- # the generated PSON, max_nesting = 0 if no maximum is checked.
- attr_accessor :max_nesting
-
- def check_max_nesting(depth) # :nodoc:
- return if @max_nesting.zero?
- current_nesting = depth + 1
- current_nesting > @max_nesting and
- raise NestingError, "nesting of #{current_nesting} is too deep"
- end
-
- # Returns true, if circular data structures should be checked,
- # otherwise returns false.
- def check_circular?
- @check_circular
- end
-
- # Returns true if NaN, Infinity, and -Infinity should be considered as
- # valid PSON and output.
- def allow_nan?
- @allow_nan
- end
-
- # Returns _true_, if _object_ was already seen during this generating
- # run.
- def seen?(object)
- @seen.key?(object.__id__)
- end
-
- # Remember _object_, to find out if it was already encountered (if a
- # cyclic data structure is if a cyclic data structure is rendered).
- def remember(object)
- @seen[object.__id__] = true
- end
-
- # Forget _object_ for this generating run.
- def forget(object)
- @seen.delete object.__id__
- end
-
- # Configure this State instance with the Hash _opts_, and return
- # itself.
- def configure(opts)
- @indent = opts[:indent] if opts.key?(:indent)
- @space = opts[:space] if opts.key?(:space)
- @space_before = opts[:space_before] if opts.key?(:space_before)
- @object_nl = opts[:object_nl] if opts.key?(:object_nl)
- @array_nl = opts[:array_nl] if opts.key?(:array_nl)
- @check_circular = !!opts[:check_circular] if opts.key?(:check_circular)
- @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
- if !opts.key?(:max_nesting) # defaults to 19
- @max_nesting = 19
- elsif opts[:max_nesting]
- @max_nesting = opts[:max_nesting]
- else
- @max_nesting = 0
- end
- self
- end
-
- # Returns the configuration instance variables as a hash, that can be
- # passed to the configure method.
- def to_h
- result = {}
- for iv in %w{indent space space_before object_nl array_nl check_circular allow_nan max_nesting}
- result[iv.intern] = instance_variable_get("@#{iv}")
- end
- result
- end
+ end
+ module_function :utf8_to_pson
+
+ module Pure
+ module Generator
+ # This class is used to create State instances, that are use to hold data
+ # while generating a PSON text from a a Ruby data structure.
+ class State
+ # Creates a State object from _opts_, which ought to be Hash to create
+ # a new State instance configured by _opts_, something else to create
+ # an unconfigured instance. If _opts_ is a State object, it is just
+ # returned.
+ def self.from_state(opts)
+ case opts
+ when self
+ opts
+ when Hash
+ new(opts)
+ else
+ new
+ end
+ end
+
+ # Instantiates a new State object, configured by _opts_.
+ #
+ # _opts_ can have the following keys:
+ #
+ # * *indent*: a string used to indent levels (default: ''),
+ # * *space*: a string that is put after, a : or , delimiter (default: ''),
+ # * *space_before*: a string that is put before a : pair delimiter (default: ''),
+ # * *object_nl*: a string that is put at the end of a PSON object (default: ''),
+ # * *array_nl*: a string that is put at the end of a PSON array (default: ''),
+ # * *check_circular*: true if checking for circular data structures
+ # should be done (the default), false otherwise.
+ # * *check_circular*: true if checking for circular data structures
+ # should be done, false (the default) otherwise.
+ # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
+ # generated, otherwise an exception is thrown, if these values are
+ # encountered. This options defaults to false.
+ def initialize(opts = {})
+ @seen = {}
+ @indent = ''
+ @space = ''
+ @space_before = ''
+ @object_nl = ''
+ @array_nl = ''
+ @check_circular = true
+ @allow_nan = false
+ configure opts
+ end
+
+ # This string is used to indent levels in the PSON text.
+ attr_accessor :indent
+
+ # This string is used to insert a space between the tokens in a PSON
+ # string.
+ attr_accessor :space
+
+ # This string is used to insert a space before the ':' in PSON objects.
+ attr_accessor :space_before
+
+ # This string is put at the end of a line that holds a PSON object (or
+ # Hash).
+ attr_accessor :object_nl
+
+ # This string is put at the end of a line that holds a PSON array.
+ attr_accessor :array_nl
+
+ # This integer returns the maximum level of data structure nesting in
+ # the generated PSON, max_nesting = 0 if no maximum is checked.
+ attr_accessor :max_nesting
+
+ def check_max_nesting(depth) # :nodoc:
+ return if @max_nesting.zero?
+ current_nesting = depth + 1
+ current_nesting > @max_nesting and
+ raise NestingError, "nesting of #{current_nesting} is too deep"
+ end
+
+ # Returns true, if circular data structures should be checked,
+ # otherwise returns false.
+ def check_circular?
+ @check_circular
+ end
+
+ # Returns true if NaN, Infinity, and -Infinity should be considered as
+ # valid PSON and output.
+ def allow_nan?
+ @allow_nan
+ end
+
+ # Returns _true_, if _object_ was already seen during this generating
+ # run.
+ def seen?(object)
+ @seen.key?(object.__id__)
+ end
+
+ # Remember _object_, to find out if it was already encountered (if a
+ # cyclic data structure is if a cyclic data structure is rendered).
+ def remember(object)
+ @seen[object.__id__] = true
+ end
+
+ # Forget _object_ for this generating run.
+ def forget(object)
+ @seen.delete object.__id__
+ end
+
+ # Configure this State instance with the Hash _opts_, and return
+ # itself.
+ def configure(opts)
+ @indent = opts[:indent] if opts.key?(:indent)
+ @space = opts[:space] if opts.key?(:space)
+ @space_before = opts[:space_before] if opts.key?(:space_before)
+ @object_nl = opts[:object_nl] if opts.key?(:object_nl)
+ @array_nl = opts[:array_nl] if opts.key?(:array_nl)
+ @check_circular = !!opts[:check_circular] if opts.key?(:check_circular)
+ @allow_nan = !!opts[:allow_nan] if opts.key?(:allow_nan)
+ if !opts.key?(:max_nesting) # defaults to 19
+ @max_nesting = 19
+ elsif opts[:max_nesting]
+ @max_nesting = opts[:max_nesting]
+ else
+ @max_nesting = 0
+ end
+ self
+ end
+
+ # Returns the configuration instance variables as a hash, that can be
+ # passed to the configure method.
+ def to_h
+ result = {}
+ for iv in %w{indent space space_before object_nl array_nl check_circular allow_nan max_nesting}
+ result[iv.intern] = instance_variable_get("@#{iv}")
+ end
+ result
+ end
+ end
+
+ module GeneratorMethods
+ module Object
+ # Converts this object to a string (calling #to_s), converts
+ # it to a PSON string, and returns the result. This is a fallback, if no
+ # special method #to_pson was defined for some object.
+ def to_pson(*) to_s.to_pson end
+ end
+
+ module Hash
+ # Returns a PSON string containing a PSON object, that is unparsed from
+ # this Hash instance.
+ # _state_ is a PSON::State object, that can also be used to configure the
+ # produced PSON string output further.
+ # _depth_ is used to find out nesting depth, to indent accordingly.
+ def to_pson(state = nil, depth = 0, *)
+ if state
+ state = PSON.state.from_state(state)
+ state.check_max_nesting(depth)
+ pson_check_circular(state) { pson_transform(state, depth) }
+ else
+ pson_transform(state, depth)
+ end
+ end
+
+ private
+
+ def pson_check_circular(state)
+ if state and state.check_circular?
+ state.seen?(self) and raise PSON::CircularDatastructure,
+ "circular data structures not supported!"
+ state.remember self
+ end
+ yield
+ ensure
+ state and state.forget self
+ end
+
+ def pson_shift(state, depth)
+ state and not state.object_nl.empty? or return ''
+ state.indent * depth
+ end
+
+ def pson_transform(state, depth)
+ delim = ','
+ if state
+ delim << state.object_nl
+ result = '{'
+ result << state.object_nl
+ result << map { |key,value|
+ s = pson_shift(state, depth + 1)
+ s << key.to_s.to_pson(state, depth + 1)
+ s << state.space_before
+ s << ':'
+ s << state.space
+ s << value.to_pson(state, depth + 1)
+ }.join(delim)
+ result << state.object_nl
+ result << pson_shift(state, depth)
+ result << '}'
+ else
+ result = '{'
+ result << map { |key,value|
+ key.to_s.to_pson << ':' << value.to_pson
+ }.join(delim)
+ result << '}'
+ end
+ result
+ end
+ end
+
+ module Array
+ # Returns a PSON string containing a PSON array, that is unparsed from
+ # this Array instance.
+ # _state_ is a PSON::State object, that can also be used to configure the
+ # produced PSON string output further.
+ # _depth_ is used to find out nesting depth, to indent accordingly.
+ def to_pson(state = nil, depth = 0, *)
+ if state
+ state = PSON.state.from_state(state)
+ state.check_max_nesting(depth)
+ pson_check_circular(state) { pson_transform(state, depth) }
+ else
+ pson_transform(state, depth)
+ end
+ end
+
+ private
+
+ def pson_check_circular(state)
+ if state and state.check_circular?
+ state.seen?(self) and raise PSON::CircularDatastructure,
+ "circular data structures not supported!"
+ state.remember self
+ end
+ yield
+ ensure
+ state and state.forget self
+ end
+
+ def pson_shift(state, depth)
+ state and not state.array_nl.empty? or return ''
+ state.indent * depth
+ end
+
+ def pson_transform(state, depth)
+ delim = ','
+ if state
+ delim << state.array_nl
+ result = '['
+ result << state.array_nl
+ result << map { |value|
+ pson_shift(state, depth + 1) << value.to_pson(state, depth + 1)
+ }.join(delim)
+ result << state.array_nl
+ result << pson_shift(state, depth)
+ result << ']'
+ else
+ '[' << map { |value| value.to_pson }.join(delim) << ']'
end
+ end
+ end
+
+ module Integer
+ # Returns a PSON string representation for this Integer number.
+ def to_pson(*) to_s end
+ end
- module GeneratorMethods
- module Object
- # Converts this object to a string (calling #to_s), converts
- # it to a PSON string, and returns the result. This is a fallback, if no
- # special method #to_pson was defined for some object.
- def to_pson(*) to_s.to_pson end
- end
-
- module Hash
- # Returns a PSON string containing a PSON object, that is unparsed from
- # this Hash instance.
- # _state_ is a PSON::State object, that can also be used to configure the
- # produced PSON string output further.
- # _depth_ is used to find out nesting depth, to indent accordingly.
- def to_pson(state = nil, depth = 0, *)
- if state
- state = PSON.state.from_state(state)
- state.check_max_nesting(depth)
- pson_check_circular(state) { pson_transform(state, depth) }
- else
- pson_transform(state, depth)
- end
- end
-
- private
-
- def pson_check_circular(state)
- if state and state.check_circular?
- state.seen?(self) and raise PSON::CircularDatastructure,
- "circular data structures not supported!"
- state.remember self
- end
- yield
- ensure
- state and state.forget self
- end
-
- def pson_shift(state, depth)
- state and not state.object_nl.empty? or return ''
- state.indent * depth
- end
-
- def pson_transform(state, depth)
- delim = ','
- if state
- delim << state.object_nl
- result = '{'
- result << state.object_nl
- result << map { |key,value|
- s = pson_shift(state, depth + 1)
- s << key.to_s.to_pson(state, depth + 1)
- s << state.space_before
- s << ':'
- s << state.space
- s << value.to_pson(state, depth + 1)
- }.join(delim)
- result << state.object_nl
- result << pson_shift(state, depth)
- result << '}'
- else
- result = '{'
- result << map { |key,value|
- key.to_s.to_pson << ':' << value.to_pson
- }.join(delim)
- result << '}'
- end
- result
- end
- end
-
- module Array
- # Returns a PSON string containing a PSON array, that is unparsed from
- # this Array instance.
- # _state_ is a PSON::State object, that can also be used to configure the
- # produced PSON string output further.
- # _depth_ is used to find out nesting depth, to indent accordingly.
- def to_pson(state = nil, depth = 0, *)
- if state
- state = PSON.state.from_state(state)
- state.check_max_nesting(depth)
- pson_check_circular(state) { pson_transform(state, depth) }
- else
- pson_transform(state, depth)
- end
- end
-
- private
-
- def pson_check_circular(state)
- if state and state.check_circular?
- state.seen?(self) and raise PSON::CircularDatastructure,
- "circular data structures not supported!"
- state.remember self
- end
- yield
- ensure
- state and state.forget self
- end
-
- def pson_shift(state, depth)
- state and not state.array_nl.empty? or return ''
- state.indent * depth
- end
-
- def pson_transform(state, depth)
- delim = ','
- if state
- delim << state.array_nl
- result = '['
- result << state.array_nl
- result << map { |value|
- pson_shift(state, depth + 1) << value.to_pson(state, depth + 1)
- }.join(delim)
- result << state.array_nl
- result << pson_shift(state, depth)
- result << ']'
- else
- '[' << map { |value| value.to_pson }.join(delim) << ']'
- end
- end
- end
-
- module Integer
- # Returns a PSON string representation for this Integer number.
- def to_pson(*) to_s end
- end
-
- module Float
- # Returns a PSON string representation for this Float number.
- def to_pson(state = nil, *)
- case
- when infinite?
- if !state || state.allow_nan?
- to_s
- else
- raise GeneratorError, "#{self} not allowed in PSON"
- end
- when nan?
- if !state || state.allow_nan?
- to_s
- else
- raise GeneratorError, "#{self} not allowed in PSON"
- end
- else
- to_s
- end
- end
- end
-
- module String
- # This string should be encoded with UTF-8 A call to this method
- # returns a PSON string encoded with UTF16 big endian characters as
- # \u????.
- def to_pson(*)
- '"' << PSON.utf8_to_pson(self) << '"'
- end
-
- # Module that holds the extinding methods if, the String module is
- # included.
- module Extend
- # Raw Strings are PSON Objects (the raw bytes are stored in an array for the
- # key "raw"). The Ruby String can be created by this module method.
- def pson_create(o)
- o['raw'].pack('C*')
- end
- end
-
- # Extends _modul_ with the String::Extend module.
- def self.included(modul)
- modul.extend Extend
- end
-
- # This method creates a raw object hash, that can be nested into
- # other data structures and will be unparsed as a raw string. This
- # method should be used, if you want to convert raw strings to PSON
- # instead of UTF-8 strings, e. g. binary data.
- def to_pson_raw_object
- {
- PSON.create_id => self.class.name,
- 'raw' => self.unpack('C*'),
- }
- end
-
- # This method creates a PSON text from the result of
- # a call to to_pson_raw_object of this String.
- def to_pson_raw(*args)
- to_pson_raw_object.to_pson(*args)
- end
- end
-
- module TrueClass
- # Returns a PSON string for true: 'true'.
- def to_pson(*) 'true' end
- end
-
- module FalseClass
- # Returns a PSON string for false: 'false'.
- def to_pson(*) 'false' end
- end
-
- module NilClass
- # Returns a PSON string for nil: 'null'.
- def to_pson(*) 'null' end
- end
+ module Float
+ # Returns a PSON string representation for this Float number.
+ def to_pson(state = nil, *)
+ case
+ when infinite?
+ if !state || state.allow_nan?
+ to_s
+ else
+ raise GeneratorError, "#{self} not allowed in PSON"
+ end
+ when nan?
+ if !state || state.allow_nan?
+ to_s
+ else
+ raise GeneratorError, "#{self} not allowed in PSON"
+ end
+ else
+ to_s
end
+ end
+ end
+
+ module String
+ # This string should be encoded with UTF-8 A call to this method
+ # returns a PSON string encoded with UTF16 big endian characters as
+ # \u????.
+ def to_pson(*)
+ '"' << PSON.utf8_to_pson(self) << '"'
+ end
+
+ # Module that holds the extinding methods if, the String module is
+ # included.
+ module Extend
+ # Raw Strings are PSON Objects (the raw bytes are stored in an array for the
+ # key "raw"). The Ruby String can be created by this module method.
+ def pson_create(o)
+ o['raw'].pack('C*')
+ end
+ end
+
+ # Extends _modul_ with the String::Extend module.
+ def self.included(modul)
+ modul.extend Extend
+ end
+
+ # This method creates a raw object hash, that can be nested into
+ # other data structures and will be unparsed as a raw string. This
+ # method should be used, if you want to convert raw strings to PSON
+ # instead of UTF-8 strings, e. g. binary data.
+ def to_pson_raw_object
+ {
+ PSON.create_id => self.class.name,
+ 'raw' => self.unpack('C*'),
+ }
+ end
+
+ # This method creates a PSON text from the result of
+ # a call to to_pson_raw_object of this String.
+ def to_pson_raw(*args)
+ to_pson_raw_object.to_pson(*args)
+ end
+ end
+
+ module TrueClass
+ # Returns a PSON string for true: 'true'.
+ def to_pson(*) 'true' end
+ end
+
+ module FalseClass
+ # Returns a PSON string for false: 'false'.
+ def to_pson(*) 'false' end
+ end
+
+ module NilClass
+ # Returns a PSON string for nil: 'null'.
+ def to_pson(*) 'null' end
end
+ end
end
+ end
end
diff --git a/lib/puppet/external/pson/pure/parser.rb b/lib/puppet/external/pson/pure/parser.rb
index 2d0a03066..6048f67e0 100644
--- a/lib/puppet/external/pson/pure/parser.rb
+++ b/lib/puppet/external/pson/pure/parser.rb
@@ -1,264 +1,264 @@
require 'strscan'
module PSON
- module Pure
- # This class implements the PSON parser that is used to parse a PSON string
- # into a Ruby data structure.
- class Parser < StringScanner
- STRING = /" ((?:[^\x0-\x1f"\\] |
- # escaped special characters:
- \\["\\\/bfnrt] |
- \\u[0-9a-fA-F]{4} |
- # match all but escaped special characters:
- \\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*)
- "/nx
- INTEGER = /(-?0|-?[1-9]\d*)/
- FLOAT = /(-?
- (?:0|[1-9]\d*)
- (?:
- \.\d+(?i:e[+-]?\d+) |
- \.\d+ |
- (?i:e[+-]?\d+)
- )
- )/x
- NAN = /NaN/
- INFINITY = /Infinity/
- MINUS_INFINITY = /-Infinity/
- OBJECT_OPEN = /\{/
- OBJECT_CLOSE = /\}/
- ARRAY_OPEN = /\[/
- ARRAY_CLOSE = /\]/
- PAIR_DELIMITER = /:/
- COLLECTION_DELIMITER = /,/
- TRUE = /true/
- FALSE = /false/
- NULL = /null/
- IGNORE = %r(
- (?:
- //[^\n\r]*[\n\r]| # line comments
- /\* # c-style comments
- (?:
- [^*/]| # normal chars
- /[^*]| # slashes that do not start a nested comment
- \*[^/]| # asterisks that do not end this comment
- /(?=\*/) # single slash before this comment's end
- )*
- \*/ # the End of this comment
- |[ \t\r\n]+ # whitespaces: space, horicontal tab, lf, cr
- )+
- )mx
+ module Pure
+ # This class implements the PSON parser that is used to parse a PSON string
+ # into a Ruby data structure.
+ class Parser < StringScanner
+ STRING = /" ((?:[^\x0-\x1f"\\] |
+ # escaped special characters:
+ \\["\\\/bfnrt] |
+ \\u[0-9a-fA-F]{4} |
+ # match all but escaped special characters:
+ \\[\x20-\x21\x23-\x2e\x30-\x5b\x5d-\x61\x63-\x65\x67-\x6d\x6f-\x71\x73\x75-\xff])*)
+ "/nx
+ INTEGER = /(-?0|-?[1-9]\d*)/
+ FLOAT = /(-?
+ (?:0|[1-9]\d*)
+ (?:
+ \.\d+(?i:e[+-]?\d+) |
+ \.\d+ |
+ (?i:e[+-]?\d+)
+ )
+ )/x
+ NAN = /NaN/
+ INFINITY = /Infinity/
+ MINUS_INFINITY = /-Infinity/
+ OBJECT_OPEN = /\{/
+ OBJECT_CLOSE = /\}/
+ ARRAY_OPEN = /\[/
+ ARRAY_CLOSE = /\]/
+ PAIR_DELIMITER = /:/
+ COLLECTION_DELIMITER = /,/
+ TRUE = /true/
+ FALSE = /false/
+ NULL = /null/
+ IGNORE = %r(
+ (?:
+ //[^\n\r]*[\n\r]| # line comments
+ /\* # c-style comments
+ (?:
+ [^*/]| # normal chars
+ /[^*]| # slashes that do not start a nested comment
+ \*[^/]| # asterisks that do not end this comment
+ /(?=\*/) # single slash before this comment's end
+ )*
+ \*/ # the End of this comment
+ |[ \t\r\n]+ # whitespaces: space, horicontal tab, lf, cr
+ )+
+ )mx
- UNPARSED = Object.new
+ UNPARSED = Object.new
- # Creates a new PSON::Pure::Parser instance for the string _source_.
- #
- # It will be configured by the _opts_ hash. _opts_ can have the following
- # keys:
- # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
- # structures. Disable depth checking with :max_nesting => false|nil|0,
- # it defaults to 19.
- # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
- # defiance of RFC 4627 to be parsed by the Parser. This option defaults
- # to false.
- # * *create_additions*: If set to false, the Parser doesn't create
- # additions even if a matchin class and create_id was found. This option
- # defaults to true.
- # * *object_class*: Defaults to Hash
- # * *array_class*: Defaults to Array
- def initialize(source, opts = {})
- super
- if !opts.key?(:max_nesting) # defaults to 19
- @max_nesting = 19
- elsif opts[:max_nesting]
- @max_nesting = opts[:max_nesting]
- else
- @max_nesting = 0
- end
- @allow_nan = !!opts[:allow_nan]
- ca = true
- ca = opts[:create_additions] if opts.key?(:create_additions)
- @create_id = ca ? PSON.create_id : nil
- @object_class = opts[:object_class] || Hash
- @array_class = opts[:array_class] || Array
- end
+ # Creates a new PSON::Pure::Parser instance for the string _source_.
+ #
+ # It will be configured by the _opts_ hash. _opts_ can have the following
+ # keys:
+ # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+ # structures. Disable depth checking with :max_nesting => false|nil|0,
+ # it defaults to 19.
+ # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+ # defiance of RFC 4627 to be parsed by the Parser. This option defaults
+ # to false.
+ # * *create_additions*: If set to false, the Parser doesn't create
+ # additions even if a matchin class and create_id was found. This option
+ # defaults to true.
+ # * *object_class*: Defaults to Hash
+ # * *array_class*: Defaults to Array
+ def initialize(source, opts = {})
+ super
+ if !opts.key?(:max_nesting) # defaults to 19
+ @max_nesting = 19
+ elsif opts[:max_nesting]
+ @max_nesting = opts[:max_nesting]
+ else
+ @max_nesting = 0
+ end
+ @allow_nan = !!opts[:allow_nan]
+ ca = true
+ ca = opts[:create_additions] if opts.key?(:create_additions)
+ @create_id = ca ? PSON.create_id : nil
+ @object_class = opts[:object_class] || Hash
+ @array_class = opts[:array_class] || Array
+ end
- alias source string
+ alias source string
- # Parses the current PSON string _source_ and returns the complete data
- # structure as a result.
- def parse
- reset
- obj = nil
- until eos?
- case
- when scan(OBJECT_OPEN)
- obj and raise ParserError, "source '#{peek(20)}' not in PSON!"
- @current_nesting = 1
- obj = parse_object
- when scan(ARRAY_OPEN)
- obj and raise ParserError, "source '#{peek(20)}' not in PSON!"
- @current_nesting = 1
- obj = parse_array
- when skip(IGNORE)
- ;
- else
- raise ParserError, "source '#{peek(20)}' not in PSON!"
- end
- end
- obj or raise ParserError, "source did not contain any PSON!"
- obj
- end
+ # Parses the current PSON string _source_ and returns the complete data
+ # structure as a result.
+ def parse
+ reset
+ obj = nil
+ until eos?
+ case
+ when scan(OBJECT_OPEN)
+ obj and raise ParserError, "source '#{peek(20)}' not in PSON!"
+ @current_nesting = 1
+ obj = parse_object
+ when scan(ARRAY_OPEN)
+ obj and raise ParserError, "source '#{peek(20)}' not in PSON!"
+ @current_nesting = 1
+ obj = parse_array
+ when skip(IGNORE)
+ ;
+ else
+ raise ParserError, "source '#{peek(20)}' not in PSON!"
+ end
+ end
+ obj or raise ParserError, "source did not contain any PSON!"
+ obj
+ end
- private
+ private
- # Unescape characters in strings.
- UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
+ # Unescape characters in strings.
+ UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
- UNESCAPE_MAP.update(
- {
- ?" => '"',
- ?\\ => '\\',
- ?/ => '/',
- ?b => "\b",
- ?f => "\f",
- ?n => "\n",
- ?r => "\r",
- ?t => "\t",
- ?u => nil,
+ UNESCAPE_MAP.update(
+ {
+ ?" => '"',
+ ?\\ => '\\',
+ ?/ => '/',
+ ?b => "\b",
+ ?f => "\f",
+ ?n => "\n",
+ ?r => "\r",
+ ?t => "\t",
+ ?u => nil,
- })
+ })
- def parse_string
- if scan(STRING)
- return '' if self[1].empty?
- string = self[1].gsub(%r{(?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff])}n) do |c|
- if u = UNESCAPE_MAP[$MATCH[1]]
- u
- else # \uXXXX
- bytes = ''
- i = 0
- while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
- bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
- i += 1
- end
- PSON::UTF16toUTF8.iconv(bytes)
- end
- end
- string.force_encoding(Encoding::UTF_8) if string.respond_to?(:force_encoding)
- string
- else
- UNPARSED
- end
- rescue Iconv::Failure => e
- raise GeneratorError, "Caught #{e.class}: #{e}"
+ def parse_string
+ if scan(STRING)
+ return '' if self[1].empty?
+ string = self[1].gsub(%r{(?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff])}n) do |c|
+ if u = UNESCAPE_MAP[$MATCH[1]]
+ u
+ else # \uXXXX
+ bytes = ''
+ i = 0
+ while c[6 * i] == ?\\ && c[6 * i + 1] == ?u
+ bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
+ i += 1
+ end
+ PSON::UTF16toUTF8.iconv(bytes)
end
+ end
+ string.force_encoding(Encoding::UTF_8) if string.respond_to?(:force_encoding)
+ string
+ else
+ UNPARSED
+ end
+ rescue Iconv::Failure => e
+ raise GeneratorError, "Caught #{e.class}: #{e}"
+ end
- def parse_value
- case
- when scan(FLOAT)
- Float(self[1])
- when scan(INTEGER)
- Integer(self[1])
- when scan(TRUE)
- true
- when scan(FALSE)
- false
- when scan(NULL)
- nil
- when (string = parse_string) != UNPARSED
- string
- when scan(ARRAY_OPEN)
- @current_nesting += 1
- ary = parse_array
- @current_nesting -= 1
- ary
- when scan(OBJECT_OPEN)
- @current_nesting += 1
- obj = parse_object
- @current_nesting -= 1
- obj
- when @allow_nan && scan(NAN)
- NaN
- when @allow_nan && scan(INFINITY)
- Infinity
- when @allow_nan && scan(MINUS_INFINITY)
- MinusInfinity
- else
- UNPARSED
- end
- end
+ def parse_value
+ case
+ when scan(FLOAT)
+ Float(self[1])
+ when scan(INTEGER)
+ Integer(self[1])
+ when scan(TRUE)
+ true
+ when scan(FALSE)
+ false
+ when scan(NULL)
+ nil
+ when (string = parse_string) != UNPARSED
+ string
+ when scan(ARRAY_OPEN)
+ @current_nesting += 1
+ ary = parse_array
+ @current_nesting -= 1
+ ary
+ when scan(OBJECT_OPEN)
+ @current_nesting += 1
+ obj = parse_object
+ @current_nesting -= 1
+ obj
+ when @allow_nan && scan(NAN)
+ NaN
+ when @allow_nan && scan(INFINITY)
+ Infinity
+ when @allow_nan && scan(MINUS_INFINITY)
+ MinusInfinity
+ else
+ UNPARSED
+ end
+ end
- def parse_array
- raise NestingError, "nesting of #@current_nesting is too deep" if
- @max_nesting.nonzero? && @current_nesting > @max_nesting
- result = @array_class.new
- delim = false
- until eos?
- case
- when (value = parse_value) != UNPARSED
- delim = false
- result << value
- skip(IGNORE)
- if scan(COLLECTION_DELIMITER)
- delim = true
- elsif match?(ARRAY_CLOSE)
- ;
- else
- raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
- end
- when scan(ARRAY_CLOSE)
- raise ParserError, "expected next element in array at '#{peek(20)}'!" if delim
- break
- when skip(IGNORE)
- ;
- else
- raise ParserError, "unexpected token in array at '#{peek(20)}'!"
- end
- end
- result
+ def parse_array
+ raise NestingError, "nesting of #@current_nesting is too deep" if
+ @max_nesting.nonzero? && @current_nesting > @max_nesting
+ result = @array_class.new
+ delim = false
+ until eos?
+ case
+ when (value = parse_value) != UNPARSED
+ delim = false
+ result << value
+ skip(IGNORE)
+ if scan(COLLECTION_DELIMITER)
+ delim = true
+ elsif match?(ARRAY_CLOSE)
+ ;
+ else
+ raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
end
+ when scan(ARRAY_CLOSE)
+ raise ParserError, "expected next element in array at '#{peek(20)}'!" if delim
+ break
+ when skip(IGNORE)
+ ;
+ else
+ raise ParserError, "unexpected token in array at '#{peek(20)}'!"
+ end
+ end
+ result
+ end
- def parse_object
- raise NestingError, "nesting of #@current_nesting is too deep" if
- @max_nesting.nonzero? && @current_nesting > @max_nesting
- result = @object_class.new
- delim = false
- until eos?
- case
- when (string = parse_string) != UNPARSED
- skip(IGNORE)
- raise ParserError, "expected ':' in object at '#{peek(20)}'!" unless scan(PAIR_DELIMITER)
- skip(IGNORE)
- unless (value = parse_value).equal? UNPARSED
- result[string] = value
- delim = false
- skip(IGNORE)
- if scan(COLLECTION_DELIMITER)
- delim = true
- elsif match?(OBJECT_CLOSE)
- ;
- else
- raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
- end
- else
- raise ParserError, "expected value in object at '#{peek(20)}'!"
- end
- when scan(OBJECT_CLOSE)
- raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!" if delim
- if @create_id and klassname = result[@create_id]
- klass = PSON.deep_const_get klassname
- break unless klass and klass.pson_creatable?
- result = klass.pson_create(result)
- end
- break
- when skip(IGNORE)
- ;
- else
- raise ParserError, "unexpected token in object at '#{peek(20)}'!"
- end
- end
- result
+ def parse_object
+ raise NestingError, "nesting of #@current_nesting is too deep" if
+ @max_nesting.nonzero? && @current_nesting > @max_nesting
+ result = @object_class.new
+ delim = false
+ until eos?
+ case
+ when (string = parse_string) != UNPARSED
+ skip(IGNORE)
+ raise ParserError, "expected ':' in object at '#{peek(20)}'!" unless scan(PAIR_DELIMITER)
+ skip(IGNORE)
+ unless (value = parse_value).equal? UNPARSED
+ result[string] = value
+ delim = false
+ skip(IGNORE)
+ if scan(COLLECTION_DELIMITER)
+ delim = true
+ elsif match?(OBJECT_CLOSE)
+ ;
+ else
+ raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
+ end
+ else
+ raise ParserError, "expected value in object at '#{peek(20)}'!"
+ end
+ when scan(OBJECT_CLOSE)
+ raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!" if delim
+ if @create_id and klassname = result[@create_id]
+ klass = PSON.deep_const_get klassname
+ break unless klass and klass.pson_creatable?
+ result = klass.pson_create(result)
end
+ break
+ when skip(IGNORE)
+ ;
+ else
+ raise ParserError, "unexpected token in object at '#{peek(20)}'!"
+ end
end
+ result
+ end
end
+ end
end
diff --git a/lib/puppet/external/pson/version.rb b/lib/puppet/external/pson/version.rb
index 0bcfa4ad8..a5a8e4702 100644
--- a/lib/puppet/external/pson/version.rb
+++ b/lib/puppet/external/pson/version.rb
@@ -1,8 +1,8 @@
module PSON
- # PSON version
- VERSION = '1.1.9'
- VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
- VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
- VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
- VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
+ # PSON version
+ VERSION = '1.1.9'
+ VERSION_ARRAY = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
+ VERSION_MAJOR = VERSION_ARRAY[0] # :nodoc:
+ VERSION_MINOR = VERSION_ARRAY[1] # :nodoc:
+ VERSION_BUILD = VERSION_ARRAY[2] # :nodoc:
end
diff --git a/lib/puppet/feature/base.rb b/lib/puppet/feature/base.rb
index f11fb00d0..c153fba98 100644
--- a/lib/puppet/feature/base.rb
+++ b/lib/puppet/feature/base.rb
@@ -37,8 +37,8 @@ Puppet.features.add(:syslog, :libs => ["syslog"])
# We can use POSIX user functions
Puppet.features.add(:posix) do
- require 'etc'
- Etc.getpwuid(0) != nil && Puppet.features.syslog?
+ require 'etc'
+ Etc.getpwuid(0) != nil && Puppet.features.syslog?
end
# We can use Microsoft Windows functions
diff --git a/lib/puppet/feature/pson.rb b/lib/puppet/feature/pson.rb
index 21576c648..0ebb2806f 100644
--- a/lib/puppet/feature/pson.rb
+++ b/lib/puppet/feature/pson.rb
@@ -1,6 +1,6 @@
Puppet.features.add(:pson) do
- require 'puppet/external/pson/common'
- require 'puppet/external/pson/version'
- require 'puppet/external/pson/pure'
- true
+ require 'puppet/external/pson/common'
+ require 'puppet/external/pson/version'
+ require 'puppet/external/pson/pure'
+ true
end
diff --git a/lib/puppet/feature/rack.rb b/lib/puppet/feature/rack.rb
index b91aa13b7..8d101ffc5 100644
--- a/lib/puppet/feature/rack.rb
+++ b/lib/puppet/feature/rack.rb
@@ -3,22 +3,22 @@ require 'puppet/util/feature'
# See if we have rack available, an HTTP Application Stack
# Explicitly depend on rack library version >= 1.0.0
Puppet.features.add(:rack) do
- begin
- require 'rack'
- rescue LoadError => detail
- require 'rubygems'
- require 'rack'
- end
+ begin
+ require 'rack'
+ rescue LoadError => detail
+ require 'rubygems'
+ require 'rack'
+ end
- if ! (defined?(::Rack) and defined?(::Rack.release))
- false
+ if ! (defined?(::Rack) and defined?(::Rack.release))
+ false
+ else
+ major_version = ::Rack.release.split('.')[0].to_i
+ if major_version >= 1
+ true
else
- major_version = ::Rack.release.split('.')[0].to_i
- if major_version >= 1
- true
- else
- false
- end
+ false
end
+ end
end
diff --git a/lib/puppet/feature/rails.rb b/lib/puppet/feature/rails.rb
index 05d416edc..e0e14ebeb 100644
--- a/lib/puppet/feature/rails.rb
+++ b/lib/puppet/feature/rails.rb
@@ -6,30 +6,30 @@ require 'puppet/util/feature'
Puppet.features.rubygems?
Puppet.features.add(:rails) do
- begin
- require 'active_record'
- require 'active_record/version'
- rescue LoadError => detail
- if FileTest.exists?("/usr/share/rails")
- count = 0
- Dir.entries("/usr/share/rails").each do |dir|
- libdir = File.join("/usr/share/rails", dir, "lib")
- if FileTest.exists?(libdir) and ! $LOAD_PATH.include?(libdir)
- count += 1
- $LOAD_PATH << libdir
- end
- end
-
- retry if count > 0
+ begin
+ require 'active_record'
+ require 'active_record/version'
+ rescue LoadError => detail
+ if FileTest.exists?("/usr/share/rails")
+ count = 0
+ Dir.entries("/usr/share/rails").each do |dir|
+ libdir = File.join("/usr/share/rails", dir, "lib")
+ if FileTest.exists?(libdir) and ! $LOAD_PATH.include?(libdir)
+ count += 1
+ $LOAD_PATH << libdir
end
- end
+ end
- if ! (defined?(::ActiveRecord) and defined?(::ActiveRecord::VERSION) and defined?(::ActiveRecord::VERSION::MAJOR) and defined?(::ActiveRecord::VERSION::MINOR))
- false
- elsif ! (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR >= 1)
- Puppet.info "ActiveRecord 2.1 or later required for StoreConfigs"
- false
- else
- true
+ retry if count > 0
end
+ end
+
+ if ! (defined?(::ActiveRecord) and defined?(::ActiveRecord::VERSION) and defined?(::ActiveRecord::VERSION::MAJOR) and defined?(::ActiveRecord::VERSION::MINOR))
+ false
+ elsif ! (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR >= 1)
+ Puppet.info "ActiveRecord 2.1 or later required for StoreConfigs"
+ false
+ else
+ true
+ end
end
diff --git a/lib/puppet/file_bucket.rb b/lib/puppet/file_bucket.rb
index 881c81e58..5eafcd269 100644
--- a/lib/puppet/file_bucket.rb
+++ b/lib/puppet/file_bucket.rb
@@ -1,4 +1,4 @@
# stub
module Puppet::FileBucket
- class BucketError < RuntimeError; end
+ class BucketError < RuntimeError; end
end
diff --git a/lib/puppet/file_bucket/dipper.rb b/lib/puppet/file_bucket/dipper.rb
index 08192aa89..dbfcdcd43 100644
--- a/lib/puppet/file_bucket/dipper.rb
+++ b/lib/puppet/file_bucket/dipper.rb
@@ -3,97 +3,97 @@ require 'puppet/file_bucket/file'
require 'puppet/indirector/request'
class Puppet::FileBucket::Dipper
- # This is a transitional implementation that uses REST
- # to access remote filebucket files.
+ # This is a transitional implementation that uses REST
+ # to access remote filebucket files.
- attr_accessor :name
+ attr_accessor :name
- # Create our bucket client
- def initialize(hash = {})
- # Emulate the XMLRPC client
- server = hash[:Server]
- port = hash[:Port] || Puppet[:masterport]
- environment = Puppet[:environment]
+ # Create our bucket client
+ def initialize(hash = {})
+ # Emulate the XMLRPC client
+ server = hash[:Server]
+ port = hash[:Port] || Puppet[:masterport]
+ environment = Puppet[:environment]
- if hash.include?(:Path)
- @local_path = hash[:Path]
- @rest_path = nil
- else
- @local_path = nil
- @rest_path = "https://#{server}:#{port}/#{environment}/file_bucket_file/"
- end
+ if hash.include?(:Path)
+ @local_path = hash[:Path]
+ @rest_path = nil
+ else
+ @local_path = nil
+ @rest_path = "https://#{server}:#{port}/#{environment}/file_bucket_file/"
end
+ end
- def local?
- !! @local_path
- end
+ def local?
+ !! @local_path
+ end
- # Back up a file to our bucket
- def backup(file)
- raise(ArgumentError, "File #{file} does not exist") unless ::File.exist?(file)
- contents = ::File.read(file)
- begin
- file_bucket_file = Puppet::FileBucket::File.new(contents, :bucket_path => @local_path, :path => absolutize_path(file) )
- dest_path = "#{@rest_path}#{file_bucket_file.name}"
+ # Back up a file to our bucket
+ def backup(file)
+ raise(ArgumentError, "File #{file} does not exist") unless ::File.exist?(file)
+ contents = ::File.read(file)
+ begin
+ file_bucket_file = Puppet::FileBucket::File.new(contents, :bucket_path => @local_path, :path => absolutize_path(file) )
+ dest_path = "#{@rest_path}#{file_bucket_file.name}"
- file_bucket_file.save(dest_path)
- return file_bucket_file.checksum_data
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not back up #{file}: #{detail}"
- end
+ file_bucket_file.save(dest_path)
+ return file_bucket_file.checksum_data
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Could not back up #{file}: #{detail}"
end
+ end
- # Retrieve a file by sum.
- def getfile(sum)
- source_path = "#{@rest_path}md5/#{sum}"
- file_bucket_file = Puppet::FileBucket::File.find(source_path, :bucket_path => @local_path)
+ # Retrieve a file by sum.
+ def getfile(sum)
+ source_path = "#{@rest_path}md5/#{sum}"
+ file_bucket_file = Puppet::FileBucket::File.find(source_path, :bucket_path => @local_path)
- raise Puppet::Error, "File not found" unless file_bucket_file
- file_bucket_file.to_s
- end
+ raise Puppet::Error, "File not found" unless file_bucket_file
+ file_bucket_file.to_s
+ end
- # Restore the file
- def restore(file,sum)
- restore = true
- if FileTest.exists?(file)
- cursum = Digest::MD5.hexdigest(::File.read(file))
+ # Restore the file
+ def restore(file,sum)
+ restore = true
+ if FileTest.exists?(file)
+ cursum = Digest::MD5.hexdigest(::File.read(file))
- # if the checksum has changed...
- # this might be extra effort
- if cursum == sum
- restore = false
- end
- end
+ # if the checksum has changed...
+ # this might be extra effort
+ if cursum == sum
+ restore = false
+ end
+ end
- if restore
- if newcontents = getfile(sum)
- tmp = ""
- newsum = Digest::MD5.hexdigest(newcontents)
- changed = nil
- if FileTest.exists?(file) and ! FileTest.writable?(file)
- changed = ::File.stat(file).mode
- ::File.chmod(changed | 0200, file)
- end
- ::File.open(file, ::File::WRONLY|::File::TRUNC|::File::CREAT) { |of|
- of.print(newcontents)
- }
- ::File.chmod(changed, file) if changed
- else
- Puppet.err "Could not find file with checksum #{sum}"
- return nil
- end
- return newsum
- else
- return nil
+ if restore
+ if newcontents = getfile(sum)
+ tmp = ""
+ newsum = Digest::MD5.hexdigest(newcontents)
+ changed = nil
+ if FileTest.exists?(file) and ! FileTest.writable?(file)
+ changed = ::File.stat(file).mode
+ ::File.chmod(changed | 0200, file)
end
+ ::File.open(file, ::File::WRONLY|::File::TRUNC|::File::CREAT) { |of|
+ of.print(newcontents)
+ }
+ ::File.chmod(changed, file) if changed
+ else
+ Puppet.err "Could not find file with checksum #{sum}"
+ return nil
+ end
+ return newsum
+ else
+ return nil
end
+ end
- private
- def absolutize_path( path )
- require 'pathname'
- Pathname.new(path).realpath
- end
+ private
+ def absolutize_path( path )
+ require 'pathname'
+ Pathname.new(path).realpath
+ end
end
diff --git a/lib/puppet/file_bucket/file.rb b/lib/puppet/file_bucket/file.rb
index 52ee4f711..96fd8e225 100644
--- a/lib/puppet/file_bucket/file.rb
+++ b/lib/puppet/file_bucket/file.rb
@@ -3,134 +3,134 @@ require 'puppet/indirector'
require 'puppet/util/checksums'
class Puppet::FileBucket::File
- include Puppet::Util::Checksums
-
- # This class handles the abstract notion of a file in a filebucket.
- # There are mechanisms to save and load this file locally and remotely in puppet/indirector/filebucketfile/*
- # There is a compatibility class that emulates pre-indirector filebuckets in Puppet::FileBucket::Dipper
- extend Puppet::Indirector
- require 'puppet/file_bucket/file/indirection_hooks'
- indirects :file_bucket_file, :terminus_class => :file, :extend => Puppet::FileBucket::File::IndirectionHooks
-
- attr :path, true
- attr :paths, true
- attr :contents, true
- attr :checksum_type
- attr :bucket_path, true
-
- def self.default_checksum_type
- "md5"
- end
-
- def initialize( contents, options = {} )
- @bucket_path = options[:bucket_path]
- @path = options[:path]
- @paths = options[:paths] || []
-
- @checksum = options[:checksum]
- @checksum_type = options[:checksum_type]
-
- self.contents = contents
-
- yield(self) if block_given?
-
- validate!
- end
-
- def validate!
- validate_checksum_type!(checksum_type)
- validate_checksum!(checksum) if checksum
- end
-
- def contents=(str)
- raise "You may not change the contents of a FileBucket File" if @contents
- validate_content!(str)
- @contents = str
- end
-
- def checksum
- return @checksum if @checksum
- @checksum = calculate_checksum if contents
- @checksum
- end
-
- def checksum=(checksum)
- validate_checksum!(checksum)
- @checksum = checksum
- end
-
- def checksum_type=( new_checksum_type )
- @checksum = nil
- @checksum_type = new_checksum_type
- end
-
- def checksum_type
- unless @checksum_type
- if @checksum
- @checksum_type = sumtype(checksum)
- else
- @checksum_type = self.class.default_checksum_type
- end
- end
- @checksum_type
- end
-
- def checksum_data
- sumdata(checksum)
- end
-
- def to_s
- contents
- end
-
- def name
- [checksum_type, checksum_data, path].compact.join('/')
- end
-
- def name=(name)
- data = name.split('/',3)
- self.path = data.pop
- @checksum_type = nil
- self.checksum = "{#{data[0]}}#{data[1]}"
- end
-
- def conflict_check?
- true
- end
-
- def self.from_s( contents )
- self.new( contents )
- end
-
- def to_pson
- hash = { "contents" => contents }
- hash["path"] = @path if @path
- hash.to_pson
- end
-
- def self.from_pson( pson )
- self.new( pson["contents"], :path => pson["path"] )
- end
-
- private
-
- def calculate_checksum
- "{#{checksum_type}}" + send(checksum_type, contents)
- end
-
- def validate_content!(content)
- raise ArgumentError, "Contents must be a string" if content and ! content.is_a?(String)
- end
-
- def validate_checksum!(new_checksum)
- newtype = sumtype(new_checksum)
-
- unless sumdata(new_checksum) == (calc_sum = send(newtype, contents))
- raise Puppet::Error, "Checksum #{new_checksum} does not match contents #{calc_sum}"
- end
- end
-
- def validate_checksum_type!(type)
- raise ArgumentError, "Invalid checksum type #{type}" unless respond_to?(type)
- end
+ include Puppet::Util::Checksums
+
+ # This class handles the abstract notion of a file in a filebucket.
+ # There are mechanisms to save and load this file locally and remotely in puppet/indirector/filebucketfile/*
+ # There is a compatibility class that emulates pre-indirector filebuckets in Puppet::FileBucket::Dipper
+ extend Puppet::Indirector
+ require 'puppet/file_bucket/file/indirection_hooks'
+ indirects :file_bucket_file, :terminus_class => :file, :extend => Puppet::FileBucket::File::IndirectionHooks
+
+ attr :path, true
+ attr :paths, true
+ attr :contents, true
+ attr :checksum_type
+ attr :bucket_path, true
+
+ def self.default_checksum_type
+ "md5"
+ end
+
+ def initialize( contents, options = {} )
+ @bucket_path = options[:bucket_path]
+ @path = options[:path]
+ @paths = options[:paths] || []
+
+ @checksum = options[:checksum]
+ @checksum_type = options[:checksum_type]
+
+ self.contents = contents
+
+ yield(self) if block_given?
+
+ validate!
+ end
+
+ def validate!
+ validate_checksum_type!(checksum_type)
+ validate_checksum!(checksum) if checksum
+ end
+
+ def contents=(str)
+ raise "You may not change the contents of a FileBucket File" if @contents
+ validate_content!(str)
+ @contents = str
+ end
+
+ def checksum
+ return @checksum if @checksum
+ @checksum = calculate_checksum if contents
+ @checksum
+ end
+
+ def checksum=(checksum)
+ validate_checksum!(checksum)
+ @checksum = checksum
+ end
+
+ def checksum_type=( new_checksum_type )
+ @checksum = nil
+ @checksum_type = new_checksum_type
+ end
+
+ def checksum_type
+ unless @checksum_type
+ if @checksum
+ @checksum_type = sumtype(checksum)
+ else
+ @checksum_type = self.class.default_checksum_type
+ end
+ end
+ @checksum_type
+ end
+
+ def checksum_data
+ sumdata(checksum)
+ end
+
+ def to_s
+ contents
+ end
+
+ def name
+ [checksum_type, checksum_data, path].compact.join('/')
+ end
+
+ def name=(name)
+ data = name.split('/',3)
+ self.path = data.pop
+ @checksum_type = nil
+ self.checksum = "{#{data[0]}}#{data[1]}"
+ end
+
+ def conflict_check?
+ true
+ end
+
+ def self.from_s( contents )
+ self.new( contents )
+ end
+
+ def to_pson
+ hash = { "contents" => contents }
+ hash["path"] = @path if @path
+ hash.to_pson
+ end
+
+ def self.from_pson( pson )
+ self.new( pson["contents"], :path => pson["path"] )
+ end
+
+ private
+
+ def calculate_checksum
+ "{#{checksum_type}}" + send(checksum_type, contents)
+ end
+
+ def validate_content!(content)
+ raise ArgumentError, "Contents must be a string" if content and ! content.is_a?(String)
+ end
+
+ def validate_checksum!(new_checksum)
+ newtype = sumtype(new_checksum)
+
+ unless sumdata(new_checksum) == (calc_sum = send(newtype, contents))
+ raise Puppet::Error, "Checksum #{new_checksum} does not match contents #{calc_sum}"
+ end
+ end
+
+ def validate_checksum_type!(type)
+ raise ArgumentError, "Invalid checksum type #{type}" unless respond_to?(type)
+ end
end
diff --git a/lib/puppet/file_bucket/file/indirection_hooks.rb b/lib/puppet/file_bucket/file/indirection_hooks.rb
index ab0912b39..58c292745 100644
--- a/lib/puppet/file_bucket/file/indirection_hooks.rb
+++ b/lib/puppet/file_bucket/file/indirection_hooks.rb
@@ -3,7 +3,7 @@ require 'puppet/file_bucket/file'
# This module is used to pick the appropriate terminus
# in filebucket indirections.
module Puppet::FileBucket::File::IndirectionHooks
- def select_terminus(request)
- return(request.protocol == 'https' ? :rest : Puppet::FileBucket::File.indirection.terminus_class)
- end
+ def select_terminus(request)
+ return(request.protocol == 'https' ? :rest : Puppet::FileBucket::File.indirection.terminus_class)
+ end
end
diff --git a/lib/puppet/file_collection.rb b/lib/puppet/file_collection.rb
index 7db2600c0..a7bdd04a8 100644
--- a/lib/puppet/file_collection.rb
+++ b/lib/puppet/file_collection.rb
@@ -1,30 +1,30 @@
# A simple way to turn file names into singletons,
# so we don't have tons of copies of each file path around.
class Puppet::FileCollection
- require 'puppet/file_collection/lookup'
+ require 'puppet/file_collection/lookup'
- def self.collection
- @collection
- end
+ def self.collection
+ @collection
+ end
- def initialize
- @paths = []
- @inverse = {}
- end
+ def initialize
+ @paths = []
+ @inverse = {}
+ end
- def index(path)
- if i = @inverse[path]
- return i
- else
- @paths << path
- i = @inverse[path] = @paths.length - 1
- return i
- end
+ def index(path)
+ if i = @inverse[path]
+ return i
+ else
+ @paths << path
+ i = @inverse[path] = @paths.length - 1
+ return i
end
+ end
- def path(index)
- @paths[index]
- end
+ def path(index)
+ @paths[index]
+ end
- @collection = self.new
+ @collection = self.new
end
diff --git a/lib/puppet/file_collection/lookup.rb b/lib/puppet/file_collection/lookup.rb
index ddb0c8431..30679480d 100644
--- a/lib/puppet/file_collection/lookup.rb
+++ b/lib/puppet/file_collection/lookup.rb
@@ -3,18 +3,18 @@ require 'puppet/file_collection'
# A simple module for looking up file paths and indexes
# in a file collection.
module Puppet::FileCollection::Lookup
- attr_accessor :line, :file_index
+ attr_accessor :line, :file_index
- def file_collection
- Puppet::FileCollection.collection
- end
+ def file_collection
+ Puppet::FileCollection.collection
+ end
- def file=(path)
- @file_index = file_collection.index(path)
- end
+ def file=(path)
+ @file_index = file_collection.index(path)
+ end
- def file
- return nil unless file_index
- file_collection.path(file_index)
- end
+ def file
+ return nil unless file_index
+ file_collection.path(file_index)
+ end
end
diff --git a/lib/puppet/file_serving/base.rb b/lib/puppet/file_serving/base.rb
index 379012f76..09cab97d9 100644
--- a/lib/puppet/file_serving/base.rb
+++ b/lib/puppet/file_serving/base.rb
@@ -7,82 +7,82 @@ require 'puppet/file_serving'
# The base class for Content and Metadata; provides common
# functionality like the behaviour around links.
class Puppet::FileServing::Base
- # This is for external consumers to store the source that was used
- # to retrieve the metadata.
- attr_accessor :source
+ # This is for external consumers to store the source that was used
+ # to retrieve the metadata.
+ attr_accessor :source
- # Does our file exist?
- def exist?
- stat
- return true
- rescue => detail
- return false
- end
+ # Does our file exist?
+ def exist?
+ stat
+ return true
+ rescue => detail
+ return false
+ end
- # Return the full path to our file. Fails if there's no path set.
- def full_path(dummy_argument=:work_arround_for_ruby_GC_bug)
- (if relative_path.nil? or relative_path == "" or relative_path == "."
- path
- else
- File.join(path, relative_path)
- end).gsub(%r{/+}, "/")
- end
+ # Return the full path to our file. Fails if there's no path set.
+ def full_path(dummy_argument=:work_arround_for_ruby_GC_bug)
+ (if relative_path.nil? or relative_path == "" or relative_path == "."
+ path
+ else
+ File.join(path, relative_path)
+ end).gsub(%r{/+}, "/")
+ end
- def initialize(path, options = {})
- self.path = path
- @links = :manage
+ def initialize(path, options = {})
+ self.path = path
+ @links = :manage
- options.each do |param, value|
- begin
- send param.to_s + "=", value
- rescue NoMethodError
- raise ArgumentError, "Invalid option #{param} for #{self.class}"
- end
- end
+ options.each do |param, value|
+ begin
+ send param.to_s + "=", value
+ rescue NoMethodError
+ raise ArgumentError, "Invalid option #{param} for #{self.class}"
+ end
end
+ end
- # Determine how we deal with links.
- attr_reader :links
- def links=(value)
- value = value.to_sym
- value = :manage if value == :ignore
- raise(ArgumentError, ":links can only be set to :manage or :follow") unless [:manage, :follow].include?(value)
- @links = value
- end
+ # Determine how we deal with links.
+ attr_reader :links
+ def links=(value)
+ value = value.to_sym
+ value = :manage if value == :ignore
+ raise(ArgumentError, ":links can only be set to :manage or :follow") unless [:manage, :follow].include?(value)
+ @links = value
+ end
- # Set our base path.
- attr_reader :path
- def path=(path)
- raise ArgumentError.new("Paths must be fully qualified") unless path =~ /^#{::File::SEPARATOR}/
- @path = path
- end
+ # Set our base path.
+ attr_reader :path
+ def path=(path)
+ raise ArgumentError.new("Paths must be fully qualified") unless path =~ /^#{::File::SEPARATOR}/
+ @path = path
+ end
- # Set a relative path; this is used for recursion, and sets
- # the file's path relative to the initial recursion point.
- attr_reader :relative_path
- def relative_path=(path)
- raise ArgumentError.new("Relative paths must not be fully qualified") if path =~ /^#{::File::SEPARATOR}/
- @relative_path = path
- end
+ # Set a relative path; this is used for recursion, and sets
+ # the file's path relative to the initial recursion point.
+ attr_reader :relative_path
+ def relative_path=(path)
+ raise ArgumentError.new("Relative paths must not be fully qualified") if path =~ /^#{::File::SEPARATOR}/
+ @relative_path = path
+ end
- # Stat our file, using the appropriate link-sensitive method.
- def stat
- @stat_method ||= self.links == :manage ? :lstat : :stat
- File.send(@stat_method, full_path)
- end
+ # Stat our file, using the appropriate link-sensitive method.
+ def stat
+ @stat_method ||= self.links == :manage ? :lstat : :stat
+ File.send(@stat_method, full_path)
+ end
- def to_pson_data_hash
- {
- # No 'document_type' since we don't send these bare
- 'data' => {
- 'path' => @path,
- 'relative_path' => @relative_path,
- 'links' => @links
- },
- 'metadata' => {
- 'api_version' => 1
- }
+ def to_pson_data_hash
+ {
+ # No 'document_type' since we don't send these bare
+ 'data' => {
+ 'path' => @path,
+ 'relative_path' => @relative_path,
+ 'links' => @links
+ },
+ 'metadata' => {
+ 'api_version' => 1
}
- end
+ }
+ end
end
diff --git a/lib/puppet/file_serving/configuration.rb b/lib/puppet/file_serving/configuration.rb
index 425213e77..78e4de6cb 100644
--- a/lib/puppet/file_serving/configuration.rb
+++ b/lib/puppet/file_serving/configuration.rb
@@ -11,117 +11,117 @@ require 'puppet/file_serving/mount/plugins'
require 'puppet/util/cacher'
class Puppet::FileServing::Configuration
- require 'puppet/file_serving/configuration/parser'
+ require 'puppet/file_serving/configuration/parser'
- class << self
- include Puppet::Util::Cacher
- cached_attr(:configuration) { new }
- end
-
- Mount = Puppet::FileServing::Mount
+ class << self
+ include Puppet::Util::Cacher
+ cached_attr(:configuration) { new }
+ end
- # Create our singleton configuration.
- def self.create
- configuration
- end
+ Mount = Puppet::FileServing::Mount
- private_class_method :new
+ # Create our singleton configuration.
+ def self.create
+ configuration
+ end
- attr_reader :mounts
- #private :mounts
+ private_class_method :new
- # Find the right mount. Does some shenanigans to support old-style module
- # mounts.
- def find_mount(mount_name, environment)
- # Reparse the configuration if necessary.
- readconfig
+ attr_reader :mounts
+ #private :mounts
- if mount = mounts[mount_name]
- return mount
- end
+ # Find the right mount. Does some shenanigans to support old-style module
+ # mounts.
+ def find_mount(mount_name, environment)
+ # Reparse the configuration if necessary.
+ readconfig
- if environment.module(mount_name)
- Puppet::Util::Warnings.notice_once "DEPRECATION NOTICE: Files found in modules without specifying 'modules' in file path will be deprecated in the next major release. Please fix module '#{mount_name}' when no 0.24.x clients are present"
- return mounts["modules"]
- end
-
- # This can be nil.
- mounts[mount_name]
+ if mount = mounts[mount_name]
+ return mount
end
- def initialize
- @mounts = {}
- @config_file = nil
-
- # We don't check to see if the file is modified the first time,
- # because we always want to parse at first.
- readconfig(false)
+ if environment.module(mount_name)
+ Puppet::Util::Warnings.notice_once "DEPRECATION NOTICE: Files found in modules without specifying 'modules' in file path will be deprecated in the next major release. Please fix module '#{mount_name}' when no 0.24.x clients are present"
+ return mounts["modules"]
end
- # Is a given mount available?
- def mounted?(name)
- @mounts.include?(name)
- end
+ # This can be nil.
+ mounts[mount_name]
+ end
+
+ def initialize
+ @mounts = {}
+ @config_file = nil
- # Split the path into the separate mount point and path.
- def split_path(request)
- # Reparse the configuration if necessary.
- readconfig
+ # We don't check to see if the file is modified the first time,
+ # because we always want to parse at first.
+ readconfig(false)
+ end
- mount_name, path = request.key.split(File::Separator, 2)
+ # Is a given mount available?
+ def mounted?(name)
+ @mounts.include?(name)
+ end
- raise(ArgumentError, "Cannot find file: Invalid path '#{mount_name}'") unless mount_name =~ %r{^[-\w]+$}
+ # Split the path into the separate mount point and path.
+ def split_path(request)
+ # Reparse the configuration if necessary.
+ readconfig
- return nil unless mount = find_mount(mount_name, request.environment)
- if mount.name == "modules" and mount_name != "modules"
- # yay backward-compatibility
- path = "#{mount_name}/#{path}"
- end
+ mount_name, path = request.key.split(File::Separator, 2)
- if path == ""
- path = nil
- elsif path
- # Remove any double slashes that might have occurred
- path = path.gsub(/\/+/, "/")
- end
+ raise(ArgumentError, "Cannot find file: Invalid path '#{mount_name}'") unless mount_name =~ %r{^[-\w]+$}
- return mount, path
+ return nil unless mount = find_mount(mount_name, request.environment)
+ if mount.name == "modules" and mount_name != "modules"
+ # yay backward-compatibility
+ path = "#{mount_name}/#{path}"
end
- def umount(name)
- @mounts.delete(name) if @mounts.include? name
+ if path == ""
+ path = nil
+ elsif path
+ # Remove any double slashes that might have occurred
+ path = path.gsub(/\/+/, "/")
end
- private
+ return mount, path
+ end
- def mk_default_mounts
- @mounts["modules"] ||= Mount::Modules.new("modules")
- @mounts["modules"].allow('*') if @mounts["modules"].empty?
- @mounts["plugins"] ||= Mount::Plugins.new("plugins")
- @mounts["plugins"].allow('*') if @mounts["plugins"].empty?
- end
+ def umount(name)
+ @mounts.delete(name) if @mounts.include? name
+ end
- # Read the configuration file.
- def readconfig(check = true)
- config = Puppet[:fileserverconfig]
+ private
- return unless FileTest.exists?(config)
+ def mk_default_mounts
+ @mounts["modules"] ||= Mount::Modules.new("modules")
+ @mounts["modules"].allow('*') if @mounts["modules"].empty?
+ @mounts["plugins"] ||= Mount::Plugins.new("plugins")
+ @mounts["plugins"].allow('*') if @mounts["plugins"].empty?
+ end
- @parser ||= Puppet::FileServing::Configuration::Parser.new(config)
+ # Read the configuration file.
+ def readconfig(check = true)
+ config = Puppet[:fileserverconfig]
- return if check and ! @parser.changed?
+ return unless FileTest.exists?(config)
- # Don't assign the mounts hash until we're sure the parsing succeeded.
- begin
- newmounts = @parser.parse
- @mounts = newmounts
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Error parsing fileserver configuration: #{detail}; using old configuration"
- end
+ @parser ||= Puppet::FileServing::Configuration::Parser.new(config)
- ensure
- # Make sure we've got our plugins and modules.
- mk_default_mounts
+ return if check and ! @parser.changed?
+
+ # Don't assign the mounts hash until we're sure the parsing succeeded.
+ begin
+ newmounts = @parser.parse
+ @mounts = newmounts
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Error parsing fileserver configuration: #{detail}; using old configuration"
end
+
+ ensure
+ # Make sure we've got our plugins and modules.
+ mk_default_mounts
+ end
end
diff --git a/lib/puppet/file_serving/configuration/parser.rb b/lib/puppet/file_serving/configuration/parser.rb
index 8e25933e4..334201d37 100644
--- a/lib/puppet/file_serving/configuration/parser.rb
+++ b/lib/puppet/file_serving/configuration/parser.rb
@@ -2,121 +2,121 @@ require 'puppet/file_serving/configuration'
require 'puppet/util/loadedfile'
class Puppet::FileServing::Configuration::Parser < Puppet::Util::LoadedFile
- Mount = Puppet::FileServing::Mount
- MODULES = 'modules'
+ Mount = Puppet::FileServing::Mount
+ MODULES = 'modules'
- # Parse our configuration file.
- def parse
- raise("File server configuration #{self.file} does not exist") unless FileTest.exists?(self.file)
- raise("Cannot read file server configuration #{self.file}") unless FileTest.readable?(self.file)
+ # Parse our configuration file.
+ def parse
+ raise("File server configuration #{self.file} does not exist") unless FileTest.exists?(self.file)
+ raise("Cannot read file server configuration #{self.file}") unless FileTest.readable?(self.file)
- @mounts = {}
- @count = 0
+ @mounts = {}
+ @count = 0
- File.open(self.file) { |f|
- mount = nil
- f.each { |line|
- # Have the count increment at the top, in case we throw exceptions.
- @count += 1
+ File.open(self.file) { |f|
+ mount = nil
+ f.each { |line|
+ # Have the count increment at the top, in case we throw exceptions.
+ @count += 1
- case line
- when /^\s*#/; next # skip comments
- when /^\s*$/; next # skip blank lines
- when /\[([-\w]+)\]/
- mount = newmount($1)
- when /^\s*(\w+)\s+(.+)$/
- var = $1
- value = $2
- raise(ArgumentError, "Fileserver configuration file does not use '=' as a separator") if value =~ /^=/
- case var
- when "path"
- path(mount, value)
- when "allow"
- allow(mount, value)
- when "deny"
- deny(mount, value)
- else
- raise ArgumentError.new("Invalid argument '#{var}'", @count, file)
- end
- else
- raise ArgumentError.new("Invalid line '#{line.chomp}'", @count, file)
- end
- }
- }
+ case line
+ when /^\s*#/; next # skip comments
+ when /^\s*$/; next # skip blank lines
+ when /\[([-\w]+)\]/
+ mount = newmount($1)
+ when /^\s*(\w+)\s+(.+)$/
+ var = $1
+ value = $2
+ raise(ArgumentError, "Fileserver configuration file does not use '=' as a separator") if value =~ /^=/
+ case var
+ when "path"
+ path(mount, value)
+ when "allow"
+ allow(mount, value)
+ when "deny"
+ deny(mount, value)
+ else
+ raise ArgumentError.new("Invalid argument '#{var}'", @count, file)
+ end
+ else
+ raise ArgumentError.new("Invalid line '#{line.chomp}'", @count, file)
+ end
+ }
+ }
- validate
+ validate
- @mounts
- end
+ @mounts
+ end
- private
+ private
- # Allow a given pattern access to a mount.
- def allow(mount, value)
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = value.split(/\s*,\s*/).each { |val|
- begin
- mount.info "allowing #{val} access"
- mount.allow(val)
- rescue AuthStoreError => detail
+ # Allow a given pattern access to a mount.
+ def allow(mount, value)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = value.split(/\s*,\s*/).each { |val|
+ begin
+ mount.info "allowing #{val} access"
+ mount.allow(val)
+ rescue AuthStoreError => detail
- raise ArgumentError.new(
- detail.to_s,
+ raise ArgumentError.new(
+ detail.to_s,
- @count, file)
- end
- }
- end
+ @count, file)
+ end
+ }
+ end
- # Deny a given pattern access to a mount.
- def deny(mount, value)
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = value.split(/\s*,\s*/).each { |val|
- begin
- mount.info "denying #{val} access"
- mount.deny(val)
- rescue AuthStoreError => detail
+ # Deny a given pattern access to a mount.
+ def deny(mount, value)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = value.split(/\s*,\s*/).each { |val|
+ begin
+ mount.info "denying #{val} access"
+ mount.deny(val)
+ rescue AuthStoreError => detail
- raise ArgumentError.new(
- detail.to_s,
+ raise ArgumentError.new(
+ detail.to_s,
- @count, file)
- end
- }
- end
+ @count, file)
+ end
+ }
+ end
- # Create a new mount.
- def newmount(name)
- raise ArgumentError, "#{@mounts[name]} is already mounted at #{name}", @count, file if @mounts.include?(name)
- case name
- when "modules"
- mount = Mount::Modules.new(name)
- when "plugins"
- mount = Mount::Plugins.new(name)
- else
- mount = Mount::File.new(name)
- end
- @mounts[name] = mount
- mount
+ # Create a new mount.
+ def newmount(name)
+ raise ArgumentError, "#{@mounts[name]} is already mounted at #{name}", @count, file if @mounts.include?(name)
+ case name
+ when "modules"
+ mount = Mount::Modules.new(name)
+ when "plugins"
+ mount = Mount::Plugins.new(name)
+ else
+ mount = Mount::File.new(name)
end
+ @mounts[name] = mount
+ mount
+ end
- # Set the path for a mount.
- def path(mount, value)
- if mount.respond_to?(:path=)
- begin
- mount.path = value
- rescue ArgumentError => detail
- Puppet.err "Removing mount #{mount.name}: #{detail}"
- @mounts.delete(mount.name)
- end
- else
- Puppet.warning "The '#{mount.name}' module can not have a path. Ignoring attempt to set it"
- end
+ # Set the path for a mount.
+ def path(mount, value)
+ if mount.respond_to?(:path=)
+ begin
+ mount.path = value
+ rescue ArgumentError => detail
+ Puppet.err "Removing mount #{mount.name}: #{detail}"
+ @mounts.delete(mount.name)
+ end
+ else
+ Puppet.warning "The '#{mount.name}' module can not have a path. Ignoring attempt to set it"
end
+ end
- # Make sure all of our mounts are valid. We have to do this after the fact
- # because details are added over time as the file is parsed.
- def validate
- @mounts.each { |name, mount| mount.validate }
- end
+ # Make sure all of our mounts are valid. We have to do this after the fact
+ # because details are added over time as the file is parsed.
+ def validate
+ @mounts.each { |name, mount| mount.validate }
+ end
end
diff --git a/lib/puppet/file_serving/content.rb b/lib/puppet/file_serving/content.rb
index a7fd2045d..9cfae7ded 100644
--- a/lib/puppet/file_serving/content.rb
+++ b/lib/puppet/file_serving/content.rb
@@ -11,40 +11,40 @@ require 'puppet/file_serving/indirection_hooks'
# It only reads the file when its content is specifically
# asked for.
class Puppet::FileServing::Content < Puppet::FileServing::Base
- extend Puppet::Indirector
- indirects :file_content, :extend => Puppet::FileServing::IndirectionHooks
-
- attr_writer :content
-
- def self.supported_formats
- [:raw]
- end
-
- def self.from_raw(content)
- instance = new("/this/is/a/fake/path")
- instance.content = content
- instance
- end
-
- # BF: we used to fetch the file content here, but this is counter-productive
- # for puppetmaster streaming of file content. So collect just returns itself
- def collect
- return if stat.ftype == "directory"
- self
+ extend Puppet::Indirector
+ indirects :file_content, :extend => Puppet::FileServing::IndirectionHooks
+
+ attr_writer :content
+
+ def self.supported_formats
+ [:raw]
+ end
+
+ def self.from_raw(content)
+ instance = new("/this/is/a/fake/path")
+ instance.content = content
+ instance
+ end
+
+ # BF: we used to fetch the file content here, but this is counter-productive
+ # for puppetmaster streaming of file content. So collect just returns itself
+ def collect
+ return if stat.ftype == "directory"
+ self
+ end
+
+ # Read the content of our file in.
+ def content
+ unless @content
+ # This stat can raise an exception, too.
+ raise(ArgumentError, "Cannot read the contents of links unless following links") if stat.ftype == "symlink"
+
+ @content = ::File.read(full_path)
end
+ @content
+ end
- # Read the content of our file in.
- def content
- unless @content
- # This stat can raise an exception, too.
- raise(ArgumentError, "Cannot read the contents of links unless following links") if stat.ftype == "symlink"
-
- @content = ::File.read(full_path)
- end
- @content
- end
-
- def to_raw
- File.new(full_path, "r")
- end
+ def to_raw
+ File.new(full_path, "r")
+ end
end
diff --git a/lib/puppet/file_serving/fileset.rb b/lib/puppet/file_serving/fileset.rb
index 15d9f9a22..fdbcf93a3 100644
--- a/lib/puppet/file_serving/fileset.rb
+++ b/lib/puppet/file_serving/fileset.rb
@@ -8,164 +8,164 @@ require 'puppet/file_serving/metadata'
# Operate recursively on a path, returning a set of file paths.
class Puppet::FileServing::Fileset
- attr_reader :path, :ignore, :links
- attr_accessor :recurse, :recurselimit, :checksum_type
-
- # Produce a hash of files, with merged so that earlier files
- # with the same postfix win. E.g., /dir1/subfile beats /dir2/subfile.
- # It's a hash because we need to know the relative path of each file,
- # and the base directory.
- # This will probably only ever be used for searching for plugins.
- def self.merge(*filesets)
- result = {}
-
- filesets.each do |fileset|
- fileset.files.each do |file|
- result[file] ||= fileset.path
- end
- end
-
- result
+ attr_reader :path, :ignore, :links
+ attr_accessor :recurse, :recurselimit, :checksum_type
+
+ # Produce a hash of files, with merged so that earlier files
+ # with the same postfix win. E.g., /dir1/subfile beats /dir2/subfile.
+ # It's a hash because we need to know the relative path of each file,
+ # and the base directory.
+ # This will probably only ever be used for searching for plugins.
+ def self.merge(*filesets)
+ result = {}
+
+ filesets.each do |fileset|
+ fileset.files.each do |file|
+ result[file] ||= fileset.path
+ end
end
- # Return a list of all files in our fileset. This is different from the
- # normal definition of find in that we support specific levels
- # of recursion, which means we need to know when we're going another
- # level deep, which Find doesn't do.
- def files
- files = perform_recursion
+ result
+ end
- # Now strip off the leading path, so each file becomes relative, and remove
- # any slashes that might end up at the beginning of the path.
- result = files.collect { |file| file.sub(%r{^#{Regexp.escape(@path)}/*}, '') }
+ # Return a list of all files in our fileset. This is different from the
+ # normal definition of find in that we support specific levels
+ # of recursion, which means we need to know when we're going another
+ # level deep, which Find doesn't do.
+ def files
+ files = perform_recursion
- # And add the path itself.
- result.unshift(".")
+ # Now strip off the leading path, so each file becomes relative, and remove
+ # any slashes that might end up at the beginning of the path.
+ result = files.collect { |file| file.sub(%r{^#{Regexp.escape(@path)}/*}, '') }
- result
- end
-
- # Should we ignore this path?
- def ignore?(path)
- return false if @ignore == [nil]
+ # And add the path itself.
+ result.unshift(".")
- # 'detect' normally returns the found result, whereas we just want true/false.
- ! @ignore.detect { |pattern| File.fnmatch?(pattern, path) }.nil?
- end
-
- def ignore=(values)
- values = [values] unless values.is_a?(Array)
- @ignore = values
- end
+ result
+ end
- def initialize(path, options = {})
- raise ArgumentError.new("Fileset paths must be fully qualified") unless File.expand_path(path) == path
+ # Should we ignore this path?
+ def ignore?(path)
+ return false if @ignore == [nil]
- @path = path
+ # 'detect' normally returns the found result, whereas we just want true/false.
+ ! @ignore.detect { |pattern| File.fnmatch?(pattern, path) }.nil?
+ end
- # Set our defaults.
- @ignore = []
- @links = :manage
- @recurse = false
- @recurselimit = :infinite
+ def ignore=(values)
+ values = [values] unless values.is_a?(Array)
+ @ignore = values
+ end
- if options.is_a?(Puppet::Indirector::Request)
- initialize_from_request(options)
- else
- initialize_from_hash(options)
- end
+ def initialize(path, options = {})
+ raise ArgumentError.new("Fileset paths must be fully qualified") unless File.expand_path(path) == path
- raise ArgumentError.new("Fileset paths must exist") unless stat = stat(path)
- raise ArgumentError.new("Fileset recurse parameter must not be a number anymore, please use recurselimit") if @recurse.is_a?(Integer)
- end
+ @path = path
- def links=(links)
- links = links.to_sym
- raise(ArgumentError, "Invalid :links value '#{links}'") unless [:manage, :follow].include?(links)
- @links = links
- @stat_method = links == :manage ? :lstat : :stat
- end
+ # Set our defaults.
+ @ignore = []
+ @links = :manage
+ @recurse = false
+ @recurselimit = :infinite
- # Should we recurse further? This is basically a single
- # place for all of the logic around recursion.
- def recurse?(depth)
- # recurse if told to, and infinite recursion or current depth not at the limit
- self.recurse and (self.recurselimit == :infinite or depth <= self.recurselimit)
+ if options.is_a?(Puppet::Indirector::Request)
+ initialize_from_request(options)
+ else
+ initialize_from_hash(options)
end
- def initialize_from_hash(options)
- options.each do |option, value|
- method = option.to_s + "="
- begin
- send(method, value)
- rescue NoMethodError
- raise ArgumentError, "Invalid option '#{option}'"
- end
- end
+ raise ArgumentError.new("Fileset paths must exist") unless stat = stat(path)
+ raise ArgumentError.new("Fileset recurse parameter must not be a number anymore, please use recurselimit") if @recurse.is_a?(Integer)
+ end
+
+ def links=(links)
+ links = links.to_sym
+ raise(ArgumentError, "Invalid :links value '#{links}'") unless [:manage, :follow].include?(links)
+ @links = links
+ @stat_method = links == :manage ? :lstat : :stat
+ end
+
+ # Should we recurse further? This is basically a single
+ # place for all of the logic around recursion.
+ def recurse?(depth)
+ # recurse if told to, and infinite recursion or current depth not at the limit
+ self.recurse and (self.recurselimit == :infinite or depth <= self.recurselimit)
+ end
+
+ def initialize_from_hash(options)
+ options.each do |option, value|
+ method = option.to_s + "="
+ begin
+ send(method, value)
+ rescue NoMethodError
+ raise ArgumentError, "Invalid option '#{option}'"
+ end
end
-
- def initialize_from_request(request)
- [:links, :ignore, :recurse, :recurselimit, :checksum_type].each do |param|
- if request.options.include?(param) # use 'include?' so the values can be false
- value = request.options[param]
- elsif request.options.include?(param.to_s)
- value = request.options[param.to_s]
- end
- next if value.nil?
- value = true if value == "true"
- value = false if value == "false"
- value = Integer(value) if value.is_a?(String) and value =~ /^\d+$/
- send(param.to_s + "=", value)
- end
+ end
+
+ def initialize_from_request(request)
+ [:links, :ignore, :recurse, :recurselimit, :checksum_type].each do |param|
+ if request.options.include?(param) # use 'include?' so the values can be false
+ value = request.options[param]
+ elsif request.options.include?(param.to_s)
+ value = request.options[param.to_s]
+ end
+ next if value.nil?
+ value = true if value == "true"
+ value = false if value == "false"
+ value = Integer(value) if value.is_a?(String) and value =~ /^\d+$/
+ send(param.to_s + "=", value)
end
+ end
- private
+ private
- # Pull the recursion logic into one place. It's moderately hairy, and this
- # allows us to keep the hairiness apart from what we do with the files.
- def perform_recursion
- # Start out with just our base directory.
- current_dirs = [@path]
+ # Pull the recursion logic into one place. It's moderately hairy, and this
+ # allows us to keep the hairiness apart from what we do with the files.
+ def perform_recursion
+ # Start out with just our base directory.
+ current_dirs = [@path]
- next_dirs = []
+ next_dirs = []
- depth = 1
+ depth = 1
- result = []
- return result unless recurse?(depth)
+ result = []
+ return result unless recurse?(depth)
- while dir_path = current_dirs.shift or ((depth += 1) and recurse?(depth) and current_dirs = next_dirs and next_dirs = [] and dir_path = current_dirs.shift)
- next unless stat = stat(dir_path)
- next unless stat.directory?
+ while dir_path = current_dirs.shift or ((depth += 1) and recurse?(depth) and current_dirs = next_dirs and next_dirs = [] and dir_path = current_dirs.shift)
+ next unless stat = stat(dir_path)
+ next unless stat.directory?
- Dir.entries(dir_path).each do |file_path|
- next if [".", ".."].include?(file_path)
+ Dir.entries(dir_path).each do |file_path|
+ next if [".", ".."].include?(file_path)
- # Note that this also causes matching directories not
- # to be recursed into.
- next if ignore?(file_path)
+ # Note that this also causes matching directories not
+ # to be recursed into.
+ next if ignore?(file_path)
- # Add it to our list of files to return
- result << File.join(dir_path, file_path)
+ # Add it to our list of files to return
+ result << File.join(dir_path, file_path)
- # And to our list of files/directories to iterate over.
- next_dirs << File.join(dir_path, file_path)
- end
- end
-
- result
+ # And to our list of files/directories to iterate over.
+ next_dirs << File.join(dir_path, file_path)
+ end
end
- public
- # Stat a given file, using the links-appropriate method.
- def stat(path)
- @stat_method ||= self.links == :manage ? :lstat : :stat
-
- begin
- return File.send(@stat_method, path)
- rescue
- # If this happens, it is almost surely because we're
- # trying to manage a link to a file that does not exist.
- return nil
- end
+
+ result
+ end
+ public
+ # Stat a given file, using the links-appropriate method.
+ def stat(path)
+ @stat_method ||= self.links == :manage ? :lstat : :stat
+
+ begin
+ return File.send(@stat_method, path)
+ rescue
+ # If this happens, it is almost surely because we're
+ # trying to manage a link to a file that does not exist.
+ return nil
end
+ end
end
diff --git a/lib/puppet/file_serving/indirection_hooks.rb b/lib/puppet/file_serving/indirection_hooks.rb
index f6f7d6664..7e0c17916 100644
--- a/lib/puppet/file_serving/indirection_hooks.rb
+++ b/lib/puppet/file_serving/indirection_hooks.rb
@@ -9,26 +9,26 @@ require 'puppet/file_serving'
# in file-serving indirections. This is necessary because
# the terminus varies based on the URI asked for.
module Puppet::FileServing::IndirectionHooks
- PROTOCOL_MAP = {"puppet" => :rest, "file" => :file}
+ PROTOCOL_MAP = {"puppet" => :rest, "file" => :file}
- # Pick an appropriate terminus based on the protocol.
- def select_terminus(request)
- # We rely on the request's parsing of the URI.
+ # Pick an appropriate terminus based on the protocol.
+ def select_terminus(request)
+ # We rely on the request's parsing of the URI.
- # Short-circuit to :file if it's a fully-qualified path or specifies a 'file' protocol.
- return PROTOCOL_MAP["file"] if request.key =~ /^#{::File::SEPARATOR}/
- return PROTOCOL_MAP["file"] if request.protocol == "file"
+ # Short-circuit to :file if it's a fully-qualified path or specifies a 'file' protocol.
+ return PROTOCOL_MAP["file"] if request.key =~ /^#{::File::SEPARATOR}/
+ return PROTOCOL_MAP["file"] if request.protocol == "file"
- # We're heading over the wire the protocol is 'puppet' and we've got a server name or we're not named 'puppet'
- if request.protocol == "puppet" and (request.server or Puppet.settings[:name] != "puppet")
- return PROTOCOL_MAP["puppet"]
- end
-
- if request.protocol and PROTOCOL_MAP[request.protocol].nil?
- raise(ArgumentError, "URI protocol '#{request.protocol}' is not currently supported for file serving")
- end
+ # We're heading over the wire the protocol is 'puppet' and we've got a server name or we're not named 'puppet'
+ if request.protocol == "puppet" and (request.server or Puppet.settings[:name] != "puppet")
+ return PROTOCOL_MAP["puppet"]
+ end
- # If we're still here, we're using the file_server or modules.
- :file_server
+ if request.protocol and PROTOCOL_MAP[request.protocol].nil?
+ raise(ArgumentError, "URI protocol '#{request.protocol}' is not currently supported for file serving")
end
+
+ # If we're still here, we're using the file_server or modules.
+ :file_server
+ end
end
diff --git a/lib/puppet/file_serving/metadata.rb b/lib/puppet/file_serving/metadata.rb
index ca58669ac..6656b124a 100644
--- a/lib/puppet/file_serving/metadata.rb
+++ b/lib/puppet/file_serving/metadata.rb
@@ -12,107 +12,107 @@ require 'puppet/file_serving/indirection_hooks'
# A class that handles retrieving file metadata.
class Puppet::FileServing::Metadata < Puppet::FileServing::Base
- include Puppet::Util::Checksums
-
- extend Puppet::Indirector
- indirects :file_metadata, :extend => Puppet::FileServing::IndirectionHooks
-
- attr_reader :path, :owner, :group, :mode, :checksum_type, :checksum, :ftype, :destination
-
- PARAM_ORDER = [:mode, :ftype, :owner, :group]
-
- def attributes_with_tabs
- raise(ArgumentError, "Cannot manage files of type #{ftype}") unless ['file','directory','link'].include? ftype
- desc = []
- PARAM_ORDER.each { |check|
- check = :ftype if check == :type
- desc << send(check)
- }
-
- desc << checksum
- desc << @destination rescue nil if ftype == 'link'
-
- desc.join("\t")
+ include Puppet::Util::Checksums
+
+ extend Puppet::Indirector
+ indirects :file_metadata, :extend => Puppet::FileServing::IndirectionHooks
+
+ attr_reader :path, :owner, :group, :mode, :checksum_type, :checksum, :ftype, :destination
+
+ PARAM_ORDER = [:mode, :ftype, :owner, :group]
+
+ def attributes_with_tabs
+ raise(ArgumentError, "Cannot manage files of type #{ftype}") unless ['file','directory','link'].include? ftype
+ desc = []
+ PARAM_ORDER.each { |check|
+ check = :ftype if check == :type
+ desc << send(check)
+ }
+
+ desc << checksum
+ desc << @destination rescue nil if ftype == 'link'
+
+ desc.join("\t")
+ end
+
+ def checksum_type=(type)
+ raise(ArgumentError, "Unsupported checksum type #{type}") unless respond_to?("#{type}_file")
+
+ @checksum_type = type
+ end
+
+ # Retrieve the attributes for this file, relative to a base directory.
+ # Note that File.stat raises Errno::ENOENT if the file is absent and this
+ # method does not catch that exception.
+ def collect
+ real_path = full_path
+ stat = stat()
+ @owner = stat.uid
+ @group = stat.gid
+ @ftype = stat.ftype
+
+
+ # We have to mask the mode, yay.
+ @mode = stat.mode & 007777
+
+ case stat.ftype
+ when "file"
+ @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", real_path).to_s
+ when "directory" # Always just timestamp the directory.
+ @checksum_type = "ctime"
+ @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", path).to_s
+ when "link"
+ @destination = File.readlink(real_path)
+ @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", real_path).to_s rescue nil
+ else
+ raise ArgumentError, "Cannot manage files of type #{stat.ftype}"
end
-
- def checksum_type=(type)
- raise(ArgumentError, "Unsupported checksum type #{type}") unless respond_to?("#{type}_file")
-
- @checksum_type = type
+ end
+
+ def initialize(path,data={})
+ @owner = data.delete('owner')
+ @group = data.delete('group')
+ @mode = data.delete('mode')
+ if checksum = data.delete('checksum')
+ @checksum_type = checksum['type']
+ @checksum = checksum['value']
end
-
- # Retrieve the attributes for this file, relative to a base directory.
- # Note that File.stat raises Errno::ENOENT if the file is absent and this
- # method does not catch that exception.
- def collect
- real_path = full_path
- stat = stat()
- @owner = stat.uid
- @group = stat.gid
- @ftype = stat.ftype
-
-
- # We have to mask the mode, yay.
- @mode = stat.mode & 007777
-
- case stat.ftype
- when "file"
- @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", real_path).to_s
- when "directory" # Always just timestamp the directory.
- @checksum_type = "ctime"
- @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", path).to_s
- when "link"
- @destination = File.readlink(real_path)
- @checksum = ("{#{@checksum_type}}") + send("#{@checksum_type}_file", real_path).to_s rescue nil
- else
- raise ArgumentError, "Cannot manage files of type #{stat.ftype}"
- end
- end
-
- def initialize(path,data={})
- @owner = data.delete('owner')
- @group = data.delete('group')
- @mode = data.delete('mode')
- if checksum = data.delete('checksum')
- @checksum_type = checksum['type']
- @checksum = checksum['value']
- end
- @checksum_type ||= "md5"
- @ftype = data.delete('type')
- @destination = data.delete('destination')
- super(path,data)
- end
-
- PSON.register_document_type('FileMetadata',self)
- def to_pson_data_hash
- {
- 'document_type' => 'FileMetadata',
-
- 'data' => super['data'].update(
- {
- 'owner' => owner,
- 'group' => group,
- 'mode' => mode,
- 'checksum' => {
- 'type' => checksum_type,
- 'value' => checksum
- },
- 'type' => ftype,
- 'destination' => destination,
-
- }),
- 'metadata' => {
- 'api_version' => 1
- }
+ @checksum_type ||= "md5"
+ @ftype = data.delete('type')
+ @destination = data.delete('destination')
+ super(path,data)
+ end
+
+ PSON.register_document_type('FileMetadata',self)
+ def to_pson_data_hash
+ {
+ 'document_type' => 'FileMetadata',
+
+ 'data' => super['data'].update(
+ {
+ 'owner' => owner,
+ 'group' => group,
+ 'mode' => mode,
+ 'checksum' => {
+ 'type' => checksum_type,
+ 'value' => checksum
+ },
+ 'type' => ftype,
+ 'destination' => destination,
+
+ }),
+ 'metadata' => {
+ 'api_version' => 1
}
- end
+ }
+ end
- def to_pson(*args)
- to_pson_data_hash.to_pson(*args)
- end
+ def to_pson(*args)
+ to_pson_data_hash.to_pson(*args)
+ end
- def self.from_pson(data)
- new(data.delete('path'), data)
- end
+ def self.from_pson(data)
+ new(data.delete('path'), data)
+ end
end
diff --git a/lib/puppet/file_serving/mount.rb b/lib/puppet/file_serving/mount.rb
index 420b6f73e..37dd89537 100644
--- a/lib/puppet/file_serving/mount.rb
+++ b/lib/puppet/file_serving/mount.rb
@@ -12,33 +12,33 @@ require 'puppet/file_serving/content'
# Broker access to the filesystem, converting local URIs into metadata
# or content objects.
class Puppet::FileServing::Mount < Puppet::Network::AuthStore
- include Puppet::Util::Logging
+ include Puppet::Util::Logging
- attr_reader :name
+ attr_reader :name
- def find(path, options)
- raise NotImplementedError
- end
-
- # Create our object. It must have a name.
- def initialize(name)
- unless name =~ %r{^[-\w]+$}
- raise ArgumentError, "Invalid mount name format '#{name}'"
- end
- @name = name
+ def find(path, options)
+ raise NotImplementedError
+ end
- super()
+ # Create our object. It must have a name.
+ def initialize(name)
+ unless name =~ %r{^[-\w]+$}
+ raise ArgumentError, "Invalid mount name format '#{name}'"
end
+ @name = name
- def search(path, options)
- raise NotImplementedError
- end
+ super()
+ end
- def to_s
- "mount[#{@name}]"
- end
+ def search(path, options)
+ raise NotImplementedError
+ end
- # A noop.
- def validate
- end
+ def to_s
+ "mount[#{@name}]"
+ end
+
+ # A noop.
+ def validate
+ end
end
diff --git a/lib/puppet/file_serving/mount/file.rb b/lib/puppet/file_serving/mount/file.rb
index 1daaceaed..7d622e4bf 100644
--- a/lib/puppet/file_serving/mount/file.rb
+++ b/lib/puppet/file_serving/mount/file.rb
@@ -3,122 +3,122 @@ require 'puppet/util/cacher'
require 'puppet/file_serving/mount'
class Puppet::FileServing::Mount::File < Puppet::FileServing::Mount
- class << self
- include Puppet::Util::Cacher
-
- cached_attr(:localmap) do
- { "h" => Facter.value("hostname"),
- "H" => [Facter.value("hostname"),
- Facter.value("domain")].join("."),
- "d" => Facter.value("domain")
- }
- end
+ class << self
+ include Puppet::Util::Cacher
+
+ cached_attr(:localmap) do
+ { "h" => Facter.value("hostname"),
+ "H" => [Facter.value("hostname"),
+ Facter.value("domain")].join("."),
+ "d" => Facter.value("domain")
+ }
end
+ end
- def complete_path(relative_path, node)
- full_path = path(node)
+ def complete_path(relative_path, node)
+ full_path = path(node)
- raise ArgumentError.new("Mounts without paths are not usable") unless full_path
+ raise ArgumentError.new("Mounts without paths are not usable") unless full_path
- # If there's no relative path name, then we're serving the mount itself.
- return full_path unless relative_path
+ # If there's no relative path name, then we're serving the mount itself.
+ return full_path unless relative_path
- file = ::File.join(full_path, relative_path)
+ file = ::File.join(full_path, relative_path)
- if !(FileTest.exist?(file) or FileTest.symlink?(file))
- Puppet.info("File does not exist or is not accessible: #{file}")
- return nil
- end
-
- file
+ if !(FileTest.exist?(file) or FileTest.symlink?(file))
+ Puppet.info("File does not exist or is not accessible: #{file}")
+ return nil
end
- # Return an instance of the appropriate class.
- def find(short_file, request)
- complete_path(short_file, request.node)
- end
+ file
+ end
- # Return the path as appropriate, expanding as necessary.
- def path(node = nil)
- if expandable?
- return expand(@path, node)
- else
- return @path
- end
- end
-
- # Set the path.
- def path=(path)
- # FIXME: For now, just don't validate paths with replacement
- # patterns in them.
- if path =~ /%./
- # Mark that we're expandable.
- @expandable = true
- else
- raise ArgumentError, "#{path} does not exist or is not a directory" unless FileTest.directory?(path)
- raise ArgumentError, "#{path} is not readable" unless FileTest.readable?(path)
- @expandable = false
- end
- @path = path
- end
+ # Return an instance of the appropriate class.
+ def find(short_file, request)
+ complete_path(short_file, request.node)
+ end
- def search(path, request)
- return nil unless path = complete_path(path, request.node)
- [path]
+ # Return the path as appropriate, expanding as necessary.
+ def path(node = nil)
+ if expandable?
+ return expand(@path, node)
+ else
+ return @path
end
-
- # Verify our configuration is valid. This should really check to
- # make sure at least someone will be allowed, but, eh.
- def validate
- raise ArgumentError.new("Mounts without paths are not usable") if @path.nil?
+ end
+
+ # Set the path.
+ def path=(path)
+ # FIXME: For now, just don't validate paths with replacement
+ # patterns in them.
+ if path =~ /%./
+ # Mark that we're expandable.
+ @expandable = true
+ else
+ raise ArgumentError, "#{path} does not exist or is not a directory" unless FileTest.directory?(path)
+ raise ArgumentError, "#{path} is not readable" unless FileTest.readable?(path)
+ @expandable = false
end
-
- private
-
- # Create a map for a specific node.
- def clientmap(node)
- {
- "h" => node.sub(/\..*$/, ""),
- "H" => node,
- "d" => node.sub(/[^.]+\./, "") # domain name
- }
+ @path = path
+ end
+
+ def search(path, request)
+ return nil unless path = complete_path(path, request.node)
+ [path]
+ end
+
+ # Verify our configuration is valid. This should really check to
+ # make sure at least someone will be allowed, but, eh.
+ def validate
+ raise ArgumentError.new("Mounts without paths are not usable") if @path.nil?
+ end
+
+ private
+
+ # Create a map for a specific node.
+ def clientmap(node)
+ {
+ "h" => node.sub(/\..*$/, ""),
+ "H" => node,
+ "d" => node.sub(/[^.]+\./, "") # domain name
+ }
+ end
+
+ # Replace % patterns as appropriate.
+ def expand(path, node = nil)
+ # This map should probably be moved into a method.
+ map = nil
+
+ if node
+ map = clientmap(node)
+ else
+ Puppet.notice "No client; expanding '#{path}' with local host"
+ # Else, use the local information
+ map = localmap
end
- # Replace % patterns as appropriate.
- def expand(path, node = nil)
- # This map should probably be moved into a method.
- map = nil
-
- if node
- map = clientmap(node)
- else
- Puppet.notice "No client; expanding '#{path}' with local host"
- # Else, use the local information
- map = localmap
- end
-
- path.gsub(/%(.)/) do |v|
- key = $1
- if key == "%"
- "%"
- else
- map[key] || v
- end
- end
+ path.gsub(/%(.)/) do |v|
+ key = $1
+ if key == "%"
+ "%"
+ else
+ map[key] || v
+ end
end
-
- # Do we have any patterns in our path, yo?
- def expandable?
- if defined?(@expandable)
- @expandable
- else
- false
- end
+ end
+
+ # Do we have any patterns in our path, yo?
+ def expandable?
+ if defined?(@expandable)
+ @expandable
+ else
+ false
end
+ end
- # Cache this manufactured map, since if it's used it's likely
- # to get used a lot.
- def localmap
- self.class.localmap
- end
+ # Cache this manufactured map, since if it's used it's likely
+ # to get used a lot.
+ def localmap
+ self.class.localmap
+ end
end
diff --git a/lib/puppet/file_serving/mount/modules.rb b/lib/puppet/file_serving/mount/modules.rb
index e5fe56661..86b5e1cdd 100644
--- a/lib/puppet/file_serving/mount/modules.rb
+++ b/lib/puppet/file_serving/mount/modules.rb
@@ -3,23 +3,23 @@ require 'puppet/file_serving/mount'
# This is the modules-specific mount: it knows how to search through
# modules for files. Yay.
class Puppet::FileServing::Mount::Modules < Puppet::FileServing::Mount
- # Return an instance of the appropriate class.
- def find(path, request)
- module_name, relative_path = path.split("/", 2)
- return nil unless mod = request.environment.module(module_name)
+ # Return an instance of the appropriate class.
+ def find(path, request)
+ module_name, relative_path = path.split("/", 2)
+ return nil unless mod = request.environment.module(module_name)
- mod.file(relative_path)
- end
+ mod.file(relative_path)
+ end
- def search(path, request)
- module_name, relative_path = path.split("/", 2)
- return nil unless mod = request.environment.module(module_name)
+ def search(path, request)
+ module_name, relative_path = path.split("/", 2)
+ return nil unless mod = request.environment.module(module_name)
- return nil unless path = mod.file(relative_path)
- [path]
- end
+ return nil unless path = mod.file(relative_path)
+ [path]
+ end
- def valid?
- true
- end
+ def valid?
+ true
+ end
end
diff --git a/lib/puppet/file_serving/mount/plugins.rb b/lib/puppet/file_serving/mount/plugins.rb
index 5e9e49ab2..d21d6e92e 100644
--- a/lib/puppet/file_serving/mount/plugins.rb
+++ b/lib/puppet/file_serving/mount/plugins.rb
@@ -4,23 +4,23 @@ require 'puppet/file_serving/mount'
# This is a very strange mount because it merges
# many directories into one.
class Puppet::FileServing::Mount::Plugins < Puppet::FileServing::Mount
- # Return an instance of the appropriate class.
- def find(relative_path, request)
- return nil unless mod = request.environment.modules.find { |mod| mod.plugin(relative_path) }
+ # Return an instance of the appropriate class.
+ def find(relative_path, request)
+ return nil unless mod = request.environment.modules.find { |mod| mod.plugin(relative_path) }
- path = mod.plugin(relative_path)
+ path = mod.plugin(relative_path)
- path
- end
+ path
+ end
- def search(relative_path, request)
- # We currently only support one kind of search on plugins - return
- # them all.
- paths = request.environment.modules.find_all { |mod| mod.plugins? }.collect { |mod| mod.plugin_directory }
- return(paths.empty? ? nil : paths)
- end
+ def search(relative_path, request)
+ # We currently only support one kind of search on plugins - return
+ # them all.
+ paths = request.environment.modules.find_all { |mod| mod.plugins? }.collect { |mod| mod.plugin_directory }
+ return(paths.empty? ? nil : paths)
+ end
- def valid?
- true
- end
+ def valid?
+ true
+ end
end
diff --git a/lib/puppet/file_serving/terminus_helper.rb b/lib/puppet/file_serving/terminus_helper.rb
index 6f5d52b25..4da285258 100644
--- a/lib/puppet/file_serving/terminus_helper.rb
+++ b/lib/puppet/file_serving/terminus_helper.rb
@@ -7,19 +7,19 @@ require 'puppet/file_serving/fileset'
# Define some common methods for FileServing termini.
module Puppet::FileServing::TerminusHelper
- # Create model instances for all files in a fileset.
- def path2instances(request, *paths)
- filesets = paths.collect do |path|
- # Filesets support indirector requests as an options collection
- Puppet::FileServing::Fileset.new(path, request)
- end
+ # Create model instances for all files in a fileset.
+ def path2instances(request, *paths)
+ filesets = paths.collect do |path|
+ # Filesets support indirector requests as an options collection
+ Puppet::FileServing::Fileset.new(path, request)
+ end
- Puppet::FileServing::Fileset.merge(*filesets).collect do |file, base_path|
- inst = model.new(base_path, :relative_path => file)
- inst.checksum_type = request.options[:checksum_type] if request.options[:checksum_type]
- inst.links = request.options[:links] if request.options[:links]
- inst.collect
- inst
- end
+ Puppet::FileServing::Fileset.merge(*filesets).collect do |file, base_path|
+ inst = model.new(base_path, :relative_path => file)
+ inst.checksum_type = request.options[:checksum_type] if request.options[:checksum_type]
+ inst.links = request.options[:links] if request.options[:links]
+ inst.collect
+ inst
end
+ end
end
diff --git a/lib/puppet/indirector.rb b/lib/puppet/indirector.rb
index 1caad6c4b..5b737578b 100644
--- a/lib/puppet/indirector.rb
+++ b/lib/puppet/indirector.rb
@@ -4,64 +4,64 @@
# +indirects+ method, which will be called by the class extending itself
# with this module.
module Puppet::Indirector
- # LAK:FIXME We need to figure out how to handle documentation for the
- # different indirection types.
+ # LAK:FIXME We need to figure out how to handle documentation for the
+ # different indirection types.
- require 'puppet/indirector/indirection'
- require 'puppet/indirector/terminus'
- require 'puppet/indirector/envelope'
- require 'puppet/network/format_handler'
+ require 'puppet/indirector/indirection'
+ require 'puppet/indirector/terminus'
+ require 'puppet/indirector/envelope'
+ require 'puppet/network/format_handler'
- # Declare that the including class indirects its methods to
- # this terminus. The terminus name must be the name of a Puppet
- # default, not the value -- if it's the value, then it gets
- # evaluated at parse time, which is before the user has had a chance
- # to override it.
- def indirects(indirection, options = {})
- raise(ArgumentError, "Already handling indirection for #{@indirection.name}; cannot also handle #{indirection}") if @indirection
- # populate this class with the various new methods
- extend ClassMethods
- include InstanceMethods
- include Puppet::Indirector::Envelope
- extend Puppet::Network::FormatHandler
+ # Declare that the including class indirects its methods to
+ # this terminus. The terminus name must be the name of a Puppet
+ # default, not the value -- if it's the value, then it gets
+ # evaluated at parse time, which is before the user has had a chance
+ # to override it.
+ def indirects(indirection, options = {})
+ raise(ArgumentError, "Already handling indirection for #{@indirection.name}; cannot also handle #{indirection}") if @indirection
+ # populate this class with the various new methods
+ extend ClassMethods
+ include InstanceMethods
+ include Puppet::Indirector::Envelope
+ extend Puppet::Network::FormatHandler
- # instantiate the actual Terminus for that type and this name (:ldap, w/ args :node)
- # & hook the instantiated Terminus into this class (Node: @indirection = terminus)
- @indirection = Puppet::Indirector::Indirection.new(self, indirection, options)
- end
+ # instantiate the actual Terminus for that type and this name (:ldap, w/ args :node)
+ # & hook the instantiated Terminus into this class (Node: @indirection = terminus)
+ @indirection = Puppet::Indirector::Indirection.new(self, indirection, options)
+ end
- module ClassMethods
- attr_reader :indirection
+ module ClassMethods
+ attr_reader :indirection
- def cache_class=(klass)
- indirection.cache_class = klass
- end
+ def cache_class=(klass)
+ indirection.cache_class = klass
+ end
- def terminus_class=(klass)
- indirection.terminus_class = klass
- end
+ def terminus_class=(klass)
+ indirection.terminus_class = klass
+ end
- # Expire any cached instance.
- def expire(*args)
- indirection.expire(*args)
- end
+ # Expire any cached instance.
+ def expire(*args)
+ indirection.expire(*args)
+ end
- def find(*args)
- indirection.find(*args)
- end
+ def find(*args)
+ indirection.find(*args)
+ end
- def destroy(*args)
- indirection.destroy(*args)
- end
+ def destroy(*args)
+ indirection.destroy(*args)
+ end
- def search(*args)
- indirection.search(*args)
- end
+ def search(*args)
+ indirection.search(*args)
end
+ end
- module InstanceMethods
- def save(key = nil)
- self.class.indirection.save key, self
- end
+ module InstanceMethods
+ def save(key = nil)
+ self.class.indirection.save key, self
end
+ end
end
diff --git a/lib/puppet/indirector/active_record.rb b/lib/puppet/indirector/active_record.rb
index 531109a18..a9f05d683 100644
--- a/lib/puppet/indirector/active_record.rb
+++ b/lib/puppet/indirector/active_record.rb
@@ -1,28 +1,28 @@
require 'puppet/indirector'
class Puppet::Indirector::ActiveRecord < Puppet::Indirector::Terminus
- class << self
- attr_accessor :ar_model
- end
+ class << self
+ attr_accessor :ar_model
+ end
- def self.use_ar_model(klass)
- self.ar_model = klass
- end
+ def self.use_ar_model(klass)
+ self.ar_model = klass
+ end
- def ar_model
- self.class.ar_model
- end
+ def ar_model
+ self.class.ar_model
+ end
- def initialize
- Puppet::Rails.init
- end
+ def initialize
+ Puppet::Rails.init
+ end
- def find(request)
- return nil unless instance = ar_model.find_by_name(request.key)
- instance.to_puppet
- end
+ def find(request)
+ return nil unless instance = ar_model.find_by_name(request.key)
+ instance.to_puppet
+ end
- def save(request)
- ar_model.from_puppet(request.instance).save
- end
+ def save(request)
+ ar_model.from_puppet(request.instance).save
+ end
end
diff --git a/lib/puppet/indirector/catalog/active_record.rb b/lib/puppet/indirector/catalog/active_record.rb
index 575ce72fb..fabb08eb9 100644
--- a/lib/puppet/indirector/catalog/active_record.rb
+++ b/lib/puppet/indirector/catalog/active_record.rb
@@ -3,39 +3,39 @@ require 'puppet/indirector/active_record'
require 'puppet/resource/catalog'
class Puppet::Resource::Catalog::ActiveRecord < Puppet::Indirector::ActiveRecord
- use_ar_model Puppet::Rails::Host
+ use_ar_model Puppet::Rails::Host
- # If we can find the host, then return a catalog with the host's resources
- # as the vertices.
- def find(request)
- return nil unless request.options[:cache_integration_hack]
- return nil unless host = ar_model.find_by_name(request.key)
+ # If we can find the host, then return a catalog with the host's resources
+ # as the vertices.
+ def find(request)
+ return nil unless request.options[:cache_integration_hack]
+ return nil unless host = ar_model.find_by_name(request.key)
- catalog = Puppet::Resource::Catalog.new(host.name)
+ catalog = Puppet::Resource::Catalog.new(host.name)
- host.resources.each do |resource|
- catalog.add_resource resource.to_transportable
- end
-
- catalog
+ host.resources.each do |resource|
+ catalog.add_resource resource.to_transportable
end
- # Save the values from a Facts instance as the facts on a Rails Host instance.
- def save(request)
- catalog = request.instance
+ catalog
+ end
+
+ # Save the values from a Facts instance as the facts on a Rails Host instance.
+ def save(request)
+ catalog = request.instance
- host = ar_model.find_by_name(catalog.name) || ar_model.create(:name => catalog.name)
+ host = ar_model.find_by_name(catalog.name) || ar_model.create(:name => catalog.name)
- host.railsmark "Saved catalog to database" do
- host.merge_resources(catalog.vertices)
- host.last_compile = Time.now
+ host.railsmark "Saved catalog to database" do
+ host.merge_resources(catalog.vertices)
+ host.last_compile = Time.now
- if node = Puppet::Node.find(catalog.name)
- host.ip = node.parameters["ipaddress"]
- host.environment = node.environment
- end
+ if node = Puppet::Node.find(catalog.name)
+ host.ip = node.parameters["ipaddress"]
+ host.environment = node.environment
+ end
- host.save
- end
+ host.save
end
+ end
end
diff --git a/lib/puppet/indirector/catalog/compiler.rb b/lib/puppet/indirector/catalog/compiler.rb
index 4ceb25a97..e85608ed1 100644
--- a/lib/puppet/indirector/catalog/compiler.rb
+++ b/lib/puppet/indirector/catalog/compiler.rb
@@ -4,163 +4,163 @@ require 'puppet/indirector/code'
require 'yaml'
class Puppet::Resource::Catalog::Compiler < Puppet::Indirector::Code
- desc "Puppet's catalog compilation interface, and its back-end is
- Puppet's compiler"
+ desc "Puppet's catalog compilation interface, and its back-end is
+ Puppet's compiler"
- include Puppet::Util
+ include Puppet::Util
- attr_accessor :code
+ attr_accessor :code
- def extract_facts_from_request(request)
- return unless text_facts = request.options[:facts]
- raise ArgumentError, "Facts but no fact format provided for #{request.name}" unless format = request.options[:facts_format]
+ def extract_facts_from_request(request)
+ return unless text_facts = request.options[:facts]
+ raise ArgumentError, "Facts but no fact format provided for #{request.name}" unless format = request.options[:facts_format]
- # If the facts were encoded as yaml, then the param reconstitution system
- # in Network::HTTP::Handler will automagically deserialize the value.
- if text_facts.is_a?(Puppet::Node::Facts)
- facts = text_facts
- else
- facts = Puppet::Node::Facts.convert_from(format, text_facts)
- end
- facts.save
+ # If the facts were encoded as yaml, then the param reconstitution system
+ # in Network::HTTP::Handler will automagically deserialize the value.
+ if text_facts.is_a?(Puppet::Node::Facts)
+ facts = text_facts
+ else
+ facts = Puppet::Node::Facts.convert_from(format, text_facts)
end
+ facts.save
+ end
- # Compile a node's catalog.
- def find(request)
- extract_facts_from_request(request)
+ # Compile a node's catalog.
+ def find(request)
+ extract_facts_from_request(request)
- node = node_from_request(request)
+ node = node_from_request(request)
- if catalog = compile(node)
- return catalog
- else
- # This shouldn't actually happen; we should either return
- # a config or raise an exception.
- return nil
- end
+ if catalog = compile(node)
+ return catalog
+ else
+ # This shouldn't actually happen; we should either return
+ # a config or raise an exception.
+ return nil
end
-
- # filter-out a catalog to remove exported resources
- def filter(catalog)
- return catalog.filter { |r| r.virtual? } if catalog.respond_to?(:filter)
- catalog
- end
-
- def initialize
- set_server_facts
- setup_database_backend if Puppet[:storeconfigs]
- end
-
- # Is our compiler part of a network, or are we just local?
- def networked?
- Puppet.run_mode.master?
- end
-
- private
-
- # Add any extra data necessary to the node.
- def add_node_data(node)
- # Merge in our server-side facts, so they can be used during compilation.
- node.merge(@server_facts)
+ end
+
+ # filter-out a catalog to remove exported resources
+ def filter(catalog)
+ return catalog.filter { |r| r.virtual? } if catalog.respond_to?(:filter)
+ catalog
+ end
+
+ def initialize
+ set_server_facts
+ setup_database_backend if Puppet[:storeconfigs]
+ end
+
+ # Is our compiler part of a network, or are we just local?
+ def networked?
+ Puppet.run_mode.master?
+ end
+
+ private
+
+ # Add any extra data necessary to the node.
+ def add_node_data(node)
+ # Merge in our server-side facts, so they can be used during compilation.
+ node.merge(@server_facts)
+ end
+
+ # Compile the actual catalog.
+ def compile(node)
+ str = "Compiled catalog for #{node.name}"
+ str += " in environment #{node.environment}" if node.environment
+ config = nil
+
+ loglevel = networked? ? :notice : :none
+
+ benchmark(loglevel, "Compiled catalog for #{node.name}") do
+ begin
+ return Puppet::Parser::Compiler.compile(node)
+ rescue Puppet::Error => detail
+ Puppet.err(detail.to_s) if networked?
+ raise
+ end
end
- # Compile the actual catalog.
- def compile(node)
- str = "Compiled catalog for #{node.name}"
- str += " in environment #{node.environment}" if node.environment
- config = nil
-
- loglevel = networked? ? :notice : :none
+ config
+ end
- benchmark(loglevel, "Compiled catalog for #{node.name}") do
- begin
- return Puppet::Parser::Compiler.compile(node)
- rescue Puppet::Error => detail
- Puppet.err(detail.to_s) if networked?
- raise
- end
- end
-
- config
+ # Turn our host name into a node object.
+ def find_node(name)
+ begin
+ return nil unless node = Puppet::Node.find(name)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Failed when searching for node #{name}: #{detail}"
end
- # Turn our host name into a node object.
- def find_node(name)
- begin
- return nil unless node = Puppet::Node.find(name)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Failed when searching for node #{name}: #{detail}"
- end
+ # Add any external data to the node.
+ add_node_data(node)
- # Add any external data to the node.
- add_node_data(node)
+ node
+ end
- node
+ # Extract the node from the request, or use the request
+ # to find the node.
+ def node_from_request(request)
+ if node = request.options[:use_node]
+ return node
end
- # Extract the node from the request, or use the request
- # to find the node.
- def node_from_request(request)
- if node = request.options[:use_node]
- return node
- end
-
- # If the request is authenticated, then the 'node' info will
- # be available; if not, then we use the passed-in key. We rely
- # on our authorization system to determine whether this is allowed.
- name = request.node || request.key
- if node = find_node(name)
- return node
- end
-
- raise ArgumentError, "Could not find node '#{name}'; cannot compile"
+ # If the request is authenticated, then the 'node' info will
+ # be available; if not, then we use the passed-in key. We rely
+ # on our authorization system to determine whether this is allowed.
+ name = request.node || request.key
+ if node = find_node(name)
+ return node
end
- # Initialize our server fact hash; we add these to each client, and they
- # won't change while we're running, so it's safe to cache the values.
- def set_server_facts
- @server_facts = {}
-
- # Add our server version to the fact list
- @server_facts["serverversion"] = Puppet.version.to_s
-
- # And then add the server name and IP
- {"servername" => "fqdn",
- "serverip" => "ipaddress"
- }.each do |var, fact|
- if value = Facter.value(fact)
- @server_facts[var] = value
- else
- Puppet.warning "Could not retrieve fact #{fact}"
- end
- end
-
- if @server_facts["servername"].nil?
- host = Facter.value(:hostname)
- if domain = Facter.value(:domain)
- @server_facts["servername"] = [host, domain].join(".")
- else
- @server_facts["servername"] = host
- end
- end
+ raise ArgumentError, "Could not find node '#{name}'; cannot compile"
+ end
+
+ # Initialize our server fact hash; we add these to each client, and they
+ # won't change while we're running, so it's safe to cache the values.
+ def set_server_facts
+ @server_facts = {}
+
+ # Add our server version to the fact list
+ @server_facts["serverversion"] = Puppet.version.to_s
+
+ # And then add the server name and IP
+ {"servername" => "fqdn",
+ "serverip" => "ipaddress"
+ }.each do |var, fact|
+ if value = Facter.value(fact)
+ @server_facts[var] = value
+ else
+ Puppet.warning "Could not retrieve fact #{fact}"
+ end
end
- def setup_database_backend
- raise Puppet::Error, "Rails is missing; cannot store configurations" unless Puppet.features.rails?
- Puppet::Rails.init
+ if @server_facts["servername"].nil?
+ host = Facter.value(:hostname)
+ if domain = Facter.value(:domain)
+ @server_facts["servername"] = [host, domain].join(".")
+ else
+ @server_facts["servername"] = host
+ end
end
-
- # Mark that the node has checked in. LAK:FIXME this needs to be moved into
- # the Node class, or somewhere that's got abstract backends.
- def update_node_check(node)
- if Puppet.features.rails? and Puppet[:storeconfigs]
- Puppet::Rails.connect
-
- host = Puppet::Rails::Host.find_or_create_by_name(node.name)
- host.last_freshcheck = Time.now
- host.save
- end
+ end
+
+ def setup_database_backend
+ raise Puppet::Error, "Rails is missing; cannot store configurations" unless Puppet.features.rails?
+ Puppet::Rails.init
+ end
+
+ # Mark that the node has checked in. LAK:FIXME this needs to be moved into
+ # the Node class, or somewhere that's got abstract backends.
+ def update_node_check(node)
+ if Puppet.features.rails? and Puppet[:storeconfigs]
+ Puppet::Rails.connect
+
+ host = Puppet::Rails::Host.find_or_create_by_name(node.name)
+ host.last_freshcheck = Time.now
+ host.save
end
+ end
end
diff --git a/lib/puppet/indirector/catalog/rest.rb b/lib/puppet/indirector/catalog/rest.rb
index b70775be2..b7a00a321 100644
--- a/lib/puppet/indirector/catalog/rest.rb
+++ b/lib/puppet/indirector/catalog/rest.rb
@@ -2,5 +2,5 @@ require 'puppet/resource/catalog'
require 'puppet/indirector/rest'
class Puppet::Resource::Catalog::Rest < Puppet::Indirector::REST
- desc "Find resource catalogs over HTTP via REST."
+ desc "Find resource catalogs over HTTP via REST."
end
diff --git a/lib/puppet/indirector/catalog/yaml.rb b/lib/puppet/indirector/catalog/yaml.rb
index d6fc9b81d..177b4e23e 100644
--- a/lib/puppet/indirector/catalog/yaml.rb
+++ b/lib/puppet/indirector/catalog/yaml.rb
@@ -2,21 +2,21 @@ require 'puppet/resource/catalog'
require 'puppet/indirector/yaml'
class Puppet::Resource::Catalog::Yaml < Puppet::Indirector::Yaml
- desc "Store catalogs as flat files, serialized using YAML."
+ desc "Store catalogs as flat files, serialized using YAML."
- private
+ private
- # Override these, because yaml doesn't want to convert our self-referential
- # objects. This is hackish, but eh.
- def from_yaml(text)
- if config = YAML.load(text)
- return config
- end
+ # Override these, because yaml doesn't want to convert our self-referential
+ # objects. This is hackish, but eh.
+ def from_yaml(text)
+ if config = YAML.load(text)
+ return config
end
+ end
- def to_yaml(config)
- # We can't yaml-dump classes.
- #config.edgelist_class = nil
- YAML.dump(config)
- end
+ def to_yaml(config)
+ # We can't yaml-dump classes.
+ #config.edgelist_class = nil
+ YAML.dump(config)
+ end
end
diff --git a/lib/puppet/indirector/certificate/ca.rb b/lib/puppet/indirector/certificate/ca.rb
index b64080e16..563bd3c02 100644
--- a/lib/puppet/indirector/certificate/ca.rb
+++ b/lib/puppet/indirector/certificate/ca.rb
@@ -2,8 +2,8 @@ require 'puppet/indirector/ssl_file'
require 'puppet/ssl/certificate'
class Puppet::SSL::Certificate::Ca < Puppet::Indirector::SslFile
- desc "Manage the CA collection of signed SSL certificates on disk."
+ desc "Manage the CA collection of signed SSL certificates on disk."
- store_in :signeddir
- store_ca_at :cacert
+ store_in :signeddir
+ store_ca_at :cacert
end
diff --git a/lib/puppet/indirector/certificate/file.rb b/lib/puppet/indirector/certificate/file.rb
index c19d001f4..4ce18f81a 100644
--- a/lib/puppet/indirector/certificate/file.rb
+++ b/lib/puppet/indirector/certificate/file.rb
@@ -2,8 +2,8 @@ require 'puppet/indirector/ssl_file'
require 'puppet/ssl/certificate'
class Puppet::SSL::Certificate::File < Puppet::Indirector::SslFile
- desc "Manage SSL certificates on disk."
+ desc "Manage SSL certificates on disk."
- store_in :certdir
- store_ca_at :localcacert
+ store_in :certdir
+ store_ca_at :localcacert
end
diff --git a/lib/puppet/indirector/certificate/rest.rb b/lib/puppet/indirector/certificate/rest.rb
index 6f47c25ba..921b85790 100644
--- a/lib/puppet/indirector/certificate/rest.rb
+++ b/lib/puppet/indirector/certificate/rest.rb
@@ -2,14 +2,14 @@ require 'puppet/ssl/certificate'
require 'puppet/indirector/rest'
class Puppet::SSL::Certificate::Rest < Puppet::Indirector::REST
- desc "Find and save certificates over HTTP via REST."
+ desc "Find and save certificates over HTTP via REST."
- use_server_setting(:ca_server)
- use_port_setting(:ca_port)
+ use_server_setting(:ca_server)
+ use_port_setting(:ca_port)
- def find(request)
- return nil unless result = super
- result.name = request.key unless result.name == request.key
- result
- end
+ def find(request)
+ return nil unless result = super
+ result.name = request.key unless result.name == request.key
+ result
+ end
end
diff --git a/lib/puppet/indirector/certificate_request/ca.rb b/lib/puppet/indirector/certificate_request/ca.rb
index 25680fb9b..f4c924fe1 100644
--- a/lib/puppet/indirector/certificate_request/ca.rb
+++ b/lib/puppet/indirector/certificate_request/ca.rb
@@ -2,13 +2,13 @@ require 'puppet/indirector/ssl_file'
require 'puppet/ssl/certificate_request'
class Puppet::SSL::CertificateRequest::Ca < Puppet::Indirector::SslFile
- desc "Manage the CA collection of certificate requests on disk."
+ desc "Manage the CA collection of certificate requests on disk."
- store_in :csrdir
+ store_in :csrdir
- def save(request)
- result = super
- Puppet.notice "#{request.key} has a waiting certificate request"
- result
- end
+ def save(request)
+ result = super
+ Puppet.notice "#{request.key} has a waiting certificate request"
+ result
+ end
end
diff --git a/lib/puppet/indirector/certificate_request/file.rb b/lib/puppet/indirector/certificate_request/file.rb
index 274311e2c..9510e362b 100644
--- a/lib/puppet/indirector/certificate_request/file.rb
+++ b/lib/puppet/indirector/certificate_request/file.rb
@@ -2,7 +2,7 @@ require 'puppet/indirector/ssl_file'
require 'puppet/ssl/certificate_request'
class Puppet::SSL::CertificateRequest::File < Puppet::Indirector::SslFile
- desc "Manage the collection of certificate requests on disk."
+ desc "Manage the collection of certificate requests on disk."
- store_in :requestdir
+ store_in :requestdir
end
diff --git a/lib/puppet/indirector/certificate_request/rest.rb b/lib/puppet/indirector/certificate_request/rest.rb
index eb9e8a9ce..81810551f 100644
--- a/lib/puppet/indirector/certificate_request/rest.rb
+++ b/lib/puppet/indirector/certificate_request/rest.rb
@@ -2,8 +2,8 @@ require 'puppet/ssl/certificate_request'
require 'puppet/indirector/rest'
class Puppet::SSL::CertificateRequest::Rest < Puppet::Indirector::REST
- desc "Find and save certificate requests over HTTP via REST."
+ desc "Find and save certificate requests over HTTP via REST."
- use_server_setting(:ca_server)
- use_port_setting(:ca_port)
+ use_server_setting(:ca_server)
+ use_port_setting(:ca_port)
end
diff --git a/lib/puppet/indirector/certificate_revocation_list/ca.rb b/lib/puppet/indirector/certificate_revocation_list/ca.rb
index 66cc23e50..1e2be6e0c 100644
--- a/lib/puppet/indirector/certificate_revocation_list/ca.rb
+++ b/lib/puppet/indirector/certificate_revocation_list/ca.rb
@@ -2,7 +2,7 @@ require 'puppet/indirector/ssl_file'
require 'puppet/ssl/certificate_revocation_list'
class Puppet::SSL::CertificateRevocationList::Ca < Puppet::Indirector::SslFile
- desc "Manage the CA collection of certificate requests on disk."
+ desc "Manage the CA collection of certificate requests on disk."
- store_at :cacrl
+ store_at :cacrl
end
diff --git a/lib/puppet/indirector/certificate_revocation_list/file.rb b/lib/puppet/indirector/certificate_revocation_list/file.rb
index 037aa6b8c..fbc437474 100644
--- a/lib/puppet/indirector/certificate_revocation_list/file.rb
+++ b/lib/puppet/indirector/certificate_revocation_list/file.rb
@@ -2,7 +2,7 @@ require 'puppet/indirector/ssl_file'
require 'puppet/ssl/certificate_revocation_list'
class Puppet::SSL::CertificateRevocationList::File < Puppet::Indirector::SslFile
- desc "Manage the global certificate revocation list."
+ desc "Manage the global certificate revocation list."
- store_at :hostcrl
+ store_at :hostcrl
end
diff --git a/lib/puppet/indirector/certificate_revocation_list/rest.rb b/lib/puppet/indirector/certificate_revocation_list/rest.rb
index 6d97ce1e2..06cbb19f2 100644
--- a/lib/puppet/indirector/certificate_revocation_list/rest.rb
+++ b/lib/puppet/indirector/certificate_revocation_list/rest.rb
@@ -2,8 +2,8 @@ require 'puppet/ssl/certificate_revocation_list'
require 'puppet/indirector/rest'
class Puppet::SSL::CertificateRevocationList::Rest < Puppet::Indirector::REST
- desc "Find and save certificate revocation lists over HTTP via REST."
+ desc "Find and save certificate revocation lists over HTTP via REST."
- use_server_setting(:ca_server)
- use_port_setting(:ca_port)
+ use_server_setting(:ca_server)
+ use_port_setting(:ca_port)
end
diff --git a/lib/puppet/indirector/couch.rb b/lib/puppet/indirector/couch.rb
index 417d6f977..fae934fd8 100644
--- a/lib/puppet/indirector/couch.rb
+++ b/lib/puppet/indirector/couch.rb
@@ -3,74 +3,74 @@ raise "Couch terminus not supported without couchrest gem" unless Puppet.feature
require 'couchrest'
class Puppet::Indirector::Couch < Puppet::Indirector::Terminus
- # The CouchRest database instance. One database instance per Puppet runtime
- # should be sufficient.
- #
- def self.db; @db ||= CouchRest.database! Puppet[:couchdb_url] end
- def db; self.class.db end
+ # The CouchRest database instance. One database instance per Puppet runtime
+ # should be sufficient.
+ #
+ def self.db; @db ||= CouchRest.database! Puppet[:couchdb_url] end
+ def db; self.class.db end
- def find(request)
- attributes_of get(request)
- end
+ def find(request)
+ attributes_of get(request)
+ end
- # Create or update the couchdb document with the request's data hash.
- #
- def save(request)
- raise ArgumentError, "PUT does not accept options" unless request.options.empty?
- update(request) || create(request)
- end
+ # Create or update the couchdb document with the request's data hash.
+ #
+ def save(request)
+ raise ArgumentError, "PUT does not accept options" unless request.options.empty?
+ update(request) || create(request)
+ end
- private
+ private
- # RKH:TODO: Do not depend on error handling, check if the document exists
- # first. (Does couchrest support this?)
- #
- def get(request)
- db.get(id_for(request))
- rescue RestClient::ResourceNotFound
- Puppet.debug "No couchdb document with id: #{id_for(request)}"
- return nil
- end
+ # RKH:TODO: Do not depend on error handling, check if the document exists
+ # first. (Does couchrest support this?)
+ #
+ def get(request)
+ db.get(id_for(request))
+ rescue RestClient::ResourceNotFound
+ Puppet.debug "No couchdb document with id: #{id_for(request)}"
+ return nil
+ end
- def update(request)
- doc = get request
- return unless doc
- doc.merge!(hash_from(request))
- doc.save
- true
- end
+ def update(request)
+ doc = get request
+ return unless doc
+ doc.merge!(hash_from(request))
+ doc.save
+ true
+ end
- def create(request)
- db.save_doc hash_from(request)
- end
+ def create(request)
+ db.save_doc hash_from(request)
+ end
- # The attributes hash that is serialized to CouchDB as JSON. It includes
- # metadata that is used to help aggregate data in couchdb. Add
- # model-specific attributes in subclasses.
- #
- def hash_from(request)
- {
- "_id" => id_for(request),
- "puppet_type" => document_type_for(request)
- }
- end
+ # The attributes hash that is serialized to CouchDB as JSON. It includes
+ # metadata that is used to help aggregate data in couchdb. Add
+ # model-specific attributes in subclasses.
+ #
+ def hash_from(request)
+ {
+ "_id" => id_for(request),
+ "puppet_type" => document_type_for(request)
+ }
+ end
- # The couchdb response stripped of metadata, used to instantiate the model
- # instance that is returned by save.
- #
- def attributes_of(response)
- response && response.reject{|k,v| k =~ /^(_rev|puppet_)/ }
- end
+ # The couchdb response stripped of metadata, used to instantiate the model
+ # instance that is returned by save.
+ #
+ def attributes_of(response)
+ response && response.reject{|k,v| k =~ /^(_rev|puppet_)/ }
+ end
- def document_type_for(request)
- request.indirection_name
- end
+ def document_type_for(request)
+ request.indirection_name
+ end
- # The id used to store the object in couchdb. Implemented in subclasses.
- #
- def id_for(request)
- raise NotImplementedError
- end
+ # The id used to store the object in couchdb. Implemented in subclasses.
+ #
+ def id_for(request)
+ raise NotImplementedError
+ end
end
diff --git a/lib/puppet/indirector/direct_file_server.rb b/lib/puppet/indirector/direct_file_server.rb
index ba5c7c435..80c84eab5 100644
--- a/lib/puppet/indirector/direct_file_server.rb
+++ b/lib/puppet/indirector/direct_file_server.rb
@@ -7,17 +7,17 @@ require 'puppet/indirector/terminus'
class Puppet::Indirector::DirectFileServer < Puppet::Indirector::Terminus
- include Puppet::FileServing::TerminusHelper
+ include Puppet::FileServing::TerminusHelper
- def find(request)
- return nil unless FileTest.exists?(request.key)
- instance = model.new(request.key)
- instance.links = request.options[:links] if request.options[:links]
- instance
- end
+ def find(request)
+ return nil unless FileTest.exists?(request.key)
+ instance = model.new(request.key)
+ instance.links = request.options[:links] if request.options[:links]
+ instance
+ end
- def search(request)
- return nil unless FileTest.exists?(request.key)
- path2instances(request, request.key)
- end
+ def search(request)
+ return nil unless FileTest.exists?(request.key)
+ path2instances(request, request.key)
+ end
end
diff --git a/lib/puppet/indirector/envelope.rb b/lib/puppet/indirector/envelope.rb
index 5fdea7081..73c33e9d4 100644
--- a/lib/puppet/indirector/envelope.rb
+++ b/lib/puppet/indirector/envelope.rb
@@ -3,9 +3,9 @@ require 'puppet/indirector'
# Provide any attributes or functionality needed for indirected
# instances.
module Puppet::Indirector::Envelope
- attr_accessor :expiration
+ attr_accessor :expiration
- def expired?
- expiration and expiration < Time.now
- end
+ def expired?
+ expiration and expiration < Time.now
+ end
end
diff --git a/lib/puppet/indirector/exec.rb b/lib/puppet/indirector/exec.rb
index 9d90d092d..fa789442b 100644
--- a/lib/puppet/indirector/exec.rb
+++ b/lib/puppet/indirector/exec.rb
@@ -2,48 +2,48 @@ require 'puppet/indirector/terminus'
require 'puppet/util'
class Puppet::Indirector::Exec < Puppet::Indirector::Terminus
- # Look for external node definitions.
- def find(request)
- # Run the command.
- unless output = query(request.key)
- return nil
- end
-
- # Translate the output to ruby.
- output
+ # Look for external node definitions.
+ def find(request)
+ # Run the command.
+ unless output = query(request.key)
+ return nil
end
- private
+ # Translate the output to ruby.
+ output
+ end
- # Proxy the execution, so it's easier to test.
- def execute(command)
- Puppet::Util.execute(command)
+ private
+
+ # Proxy the execution, so it's easier to test.
+ def execute(command)
+ Puppet::Util.execute(command)
+ end
+
+ # Call the external command and see if it returns our output.
+ def query(name)
+ external_command = command
+
+ # Make sure it's an arry
+ raise Puppet::DevError, "Exec commands must be an array" unless external_command.is_a?(Array)
+
+ # Make sure it's fully qualified.
+ raise ArgumentError, "You must set the exec parameter to a fully qualified command" unless external_command[0][0] == File::SEPARATOR[0]
+
+ # Add our name to it.
+ external_command << name
+ begin
+ output = execute(external_command)
+ rescue Puppet::ExecutionFailure => detail
+ Puppet.err "Failed to find #{name} via exec: #{detail}"
+ return nil
end
- # Call the external command and see if it returns our output.
- def query(name)
- external_command = command
-
- # Make sure it's an arry
- raise Puppet::DevError, "Exec commands must be an array" unless external_command.is_a?(Array)
-
- # Make sure it's fully qualified.
- raise ArgumentError, "You must set the exec parameter to a fully qualified command" unless external_command[0][0] == File::SEPARATOR[0]
-
- # Add our name to it.
- external_command << name
- begin
- output = execute(external_command)
- rescue Puppet::ExecutionFailure => detail
- Puppet.err "Failed to find #{name} via exec: #{detail}"
- return nil
- end
-
- if output =~ /\A\s*\Z/ # all whitespace
- Puppet.debug "Empty response for #{name} from exec #{self.name} terminus"
- return nil
- else
- return output
- end
+ if output =~ /\A\s*\Z/ # all whitespace
+ Puppet.debug "Empty response for #{name} from exec #{self.name} terminus"
+ return nil
+ else
+ return output
end
+ end
end
diff --git a/lib/puppet/indirector/facts/active_record.rb b/lib/puppet/indirector/facts/active_record.rb
index a2d3e7758..96ed800da 100644
--- a/lib/puppet/indirector/facts/active_record.rb
+++ b/lib/puppet/indirector/facts/active_record.rb
@@ -4,33 +4,33 @@ require 'puppet/rails/host'
require 'puppet/indirector/active_record'
class Puppet::Node::Facts::ActiveRecord < Puppet::Indirector::ActiveRecord
- use_ar_model Puppet::Rails::Host
-
- # Find the Rails host and pull its facts as a Facts instance.
- def find(request)
- return nil unless host = ar_model.find_by_name(request.key, :include => {:fact_values => :fact_name})
-
- facts = Puppet::Node::Facts.new(host.name)
- facts.values = host.get_facts_hash.inject({}) do |hash, ary|
- # Convert all single-member arrays into plain values.
- param = ary[0]
- values = ary[1].collect { |v| v.value }
- values = values[0] if values.length == 1
- hash[param] = values
- hash
- end
-
- facts
+ use_ar_model Puppet::Rails::Host
+
+ # Find the Rails host and pull its facts as a Facts instance.
+ def find(request)
+ return nil unless host = ar_model.find_by_name(request.key, :include => {:fact_values => :fact_name})
+
+ facts = Puppet::Node::Facts.new(host.name)
+ facts.values = host.get_facts_hash.inject({}) do |hash, ary|
+ # Convert all single-member arrays into plain values.
+ param = ary[0]
+ values = ary[1].collect { |v| v.value }
+ values = values[0] if values.length == 1
+ hash[param] = values
+ hash
end
- # Save the values from a Facts instance as the facts on a Rails Host instance.
- def save(request)
- facts = request.instance
+ facts
+ end
- host = ar_model.find_by_name(facts.name) || ar_model.create(:name => facts.name)
+ # Save the values from a Facts instance as the facts on a Rails Host instance.
+ def save(request)
+ facts = request.instance
- host.merge_facts(facts.values)
+ host = ar_model.find_by_name(facts.name) || ar_model.create(:name => facts.name)
- host.save
- end
+ host.merge_facts(facts.values)
+
+ host.save
+ end
end
diff --git a/lib/puppet/indirector/facts/couch.rb b/lib/puppet/indirector/facts/couch.rb
index 522fe3350..fda2b9191 100644
--- a/lib/puppet/indirector/facts/couch.rb
+++ b/lib/puppet/indirector/facts/couch.rb
@@ -2,30 +2,30 @@ require 'puppet/node/facts'
require 'puppet/indirector/couch'
class Puppet::Node::Facts::Couch < Puppet::Indirector::Couch
- # Return the facts object or nil if there is no document
- def find(request)
- doc = super
- doc ? model.new(doc['_id'], doc['facts']) : nil
- end
+ # Return the facts object or nil if there is no document
+ def find(request)
+ doc = super
+ doc ? model.new(doc['_id'], doc['facts']) : nil
+ end
- private
+ private
- # Facts values are stored to the document's 'facts' attribute. Hostname is
- # stored to 'name'
- #
- def hash_from(request)
- super.merge('facts' => request.instance.values)
- end
+ # Facts values are stored to the document's 'facts' attribute. Hostname is
+ # stored to 'name'
+ #
+ def hash_from(request)
+ super.merge('facts' => request.instance.values)
+ end
- # Facts are stored to the 'node' document.
- def document_type_for(request)
- 'node'
- end
+ # Facts are stored to the 'node' document.
+ def document_type_for(request)
+ 'node'
+ end
- # The id used to store the object in couchdb.
- def id_for(request)
- request.key.to_s
- end
+ # The id used to store the object in couchdb.
+ def id_for(request)
+ request.key.to_s
+ end
end
diff --git a/lib/puppet/indirector/facts/facter.rb b/lib/puppet/indirector/facts/facter.rb
index a3ce79b06..ab7378a34 100644
--- a/lib/puppet/indirector/facts/facter.rb
+++ b/lib/puppet/indirector/facts/facter.rb
@@ -2,82 +2,82 @@ require 'puppet/node/facts'
require 'puppet/indirector/code'
class Puppet::Node::Facts::Facter < Puppet::Indirector::Code
- desc "Retrieve facts from Facter. This provides a somewhat abstract interface
- between Puppet and Facter. It's only `somewhat` abstract because it always
- returns the local host's facts, regardless of what you attempt to find."
+ desc "Retrieve facts from Facter. This provides a somewhat abstract interface
+ between Puppet and Facter. It's only `somewhat` abstract because it always
+ returns the local host's facts, regardless of what you attempt to find."
- def self.load_fact_plugins
- # Add any per-module fact directories to the factpath
- module_fact_dirs = Puppet[:modulepath].split(":").collect do |d|
- ["lib", "plugins"].map do |subdirectory|
- Dir.glob("#{d}/*/#{subdirectory}/facter")
- end
- end.flatten
- dirs = module_fact_dirs + Puppet[:factpath].split(":")
- x = dirs.each do |dir|
- load_facts_in_dir(dir)
- end
+ def self.load_fact_plugins
+ # Add any per-module fact directories to the factpath
+ module_fact_dirs = Puppet[:modulepath].split(":").collect do |d|
+ ["lib", "plugins"].map do |subdirectory|
+ Dir.glob("#{d}/*/#{subdirectory}/facter")
+ end
+ end.flatten
+ dirs = module_fact_dirs + Puppet[:factpath].split(":")
+ x = dirs.each do |dir|
+ load_facts_in_dir(dir)
end
+ end
- def self.load_facts_in_dir(dir)
- return unless FileTest.directory?(dir)
+ def self.load_facts_in_dir(dir)
+ return unless FileTest.directory?(dir)
- Dir.chdir(dir) do
- Dir.glob("*.rb").each do |file|
- fqfile = ::File.join(dir, file)
- begin
- Puppet.info "Loading facts in #{::File.basename(file.sub(".rb",''))}"
- Timeout::timeout(self.timeout) do
- load file
- end
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- Puppet.warning "Could not load fact file #{fqfile}: #{detail}"
- end
- end
+ Dir.chdir(dir) do
+ Dir.glob("*.rb").each do |file|
+ fqfile = ::File.join(dir, file)
+ begin
+ Puppet.info "Loading facts in #{::File.basename(file.sub(".rb",''))}"
+ Timeout::timeout(self.timeout) do
+ load file
+ end
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ Puppet.warning "Could not load fact file #{fqfile}: #{detail}"
end
+ end
end
+ end
- def self.timeout
- timeout = Puppet[:configtimeout]
- case timeout
- when String
- if timeout =~ /^\d+$/
- timeout = Integer(timeout)
- else
- raise ArgumentError, "Configuration timeout must be an integer"
- end
- when Integer # nothing
- else
- raise ArgumentError, "Configuration timeout must be an integer"
- end
-
- timeout
+ def self.timeout
+ timeout = Puppet[:configtimeout]
+ case timeout
+ when String
+ if timeout =~ /^\d+$/
+ timeout = Integer(timeout)
+ else
+ raise ArgumentError, "Configuration timeout must be an integer"
+ end
+ when Integer # nothing
+ else
+ raise ArgumentError, "Configuration timeout must be an integer"
end
- def initialize(*args)
- super
- self.class.load_fact_plugins
- end
+ timeout
+ end
- def destroy(facts)
- raise Puppet::DevError, "You cannot destroy facts in the code store; it is only used for getting facts from Facter"
- end
+ def initialize(*args)
+ super
+ self.class.load_fact_plugins
+ end
- # Look a host's facts up in Facter.
- def find(request)
- result = Puppet::Node::Facts.new(request.key, Facter.to_hash)
+ def destroy(facts)
+ raise Puppet::DevError, "You cannot destroy facts in the code store; it is only used for getting facts from Facter"
+ end
- result.add_local_facts
- result.stringify
- result.downcase_if_necessary
+ # Look a host's facts up in Facter.
+ def find(request)
+ result = Puppet::Node::Facts.new(request.key, Facter.to_hash)
- result
- end
+ result.add_local_facts
+ result.stringify
+ result.downcase_if_necessary
- def save(facts)
- raise Puppet::DevError, "You cannot save facts to the code store; it is only used for getting facts from Facter"
- end
+ result
+ end
+
+ def save(facts)
+ raise Puppet::DevError, "You cannot save facts to the code store; it is only used for getting facts from Facter"
+ end
end
diff --git a/lib/puppet/indirector/facts/memory.rb b/lib/puppet/indirector/facts/memory.rb
index 3c10d5964..c4ca19da5 100644
--- a/lib/puppet/indirector/facts/memory.rb
+++ b/lib/puppet/indirector/facts/memory.rb
@@ -2,8 +2,8 @@ require 'puppet/node/facts'
require 'puppet/indirector/memory'
class Puppet::Node::Facts::Memory < Puppet::Indirector::Memory
- desc "Keep track of facts in memory but nowhere else. This is used for
- one-time compiles, such as what the stand-alone ``puppet`` does.
- To use this terminus, you must load it with the data you want it
- to contain."
+ desc "Keep track of facts in memory but nowhere else. This is used for
+ one-time compiles, such as what the stand-alone ``puppet`` does.
+ To use this terminus, you must load it with the data you want it
+ to contain."
end
diff --git a/lib/puppet/indirector/facts/rest.rb b/lib/puppet/indirector/facts/rest.rb
index cf26fba11..07491fc77 100644
--- a/lib/puppet/indirector/facts/rest.rb
+++ b/lib/puppet/indirector/facts/rest.rb
@@ -2,5 +2,5 @@ require 'puppet/node/facts'
require 'puppet/indirector/rest'
class Puppet::Node::Facts::Rest < Puppet::Indirector::REST
- desc "Find and save facts about nodes over HTTP via REST."
+ desc "Find and save facts about nodes over HTTP via REST."
end
diff --git a/lib/puppet/indirector/facts/yaml.rb b/lib/puppet/indirector/facts/yaml.rb
index b8a8e3163..89feaf2ab 100644
--- a/lib/puppet/indirector/facts/yaml.rb
+++ b/lib/puppet/indirector/facts/yaml.rb
@@ -2,6 +2,6 @@ require 'puppet/node/facts'
require 'puppet/indirector/yaml'
class Puppet::Node::Facts::Yaml < Puppet::Indirector::Yaml
- desc "Store client facts as flat files, serialized using YAML, or
- return deserialized facts from disk."
+ desc "Store client facts as flat files, serialized using YAML, or
+ return deserialized facts from disk."
end
diff --git a/lib/puppet/indirector/file.rb b/lib/puppet/indirector/file.rb
index dab8fc720..b3746b792 100644
--- a/lib/puppet/indirector/file.rb
+++ b/lib/puppet/indirector/file.rb
@@ -2,78 +2,78 @@ require 'puppet/indirector/terminus'
# Store instances as files, usually serialized using some format.
class Puppet::Indirector::File < Puppet::Indirector::Terminus
- # Where do we store our data?
- def data_directory
- name = Puppet.run_mode.master? ? :server_datadir : :client_datadir
-
- File.join(Puppet.settings[name], self.class.indirection_name.to_s)
- end
-
- def file_format(path)
- path =~ /\.(\w+)$/ and return $1
- end
-
- def file_path(request)
- File.join(data_directory, request.key + ".#{serialization_format}")
- end
-
- def latest_path(request)
- files = Dir.glob(File.join(data_directory, request.key + ".*"))
- return nil if files.empty?
-
- # Return the newest file.
- files.sort { |a, b| File.stat(b).mtime <=> File.stat(a).mtime }[0]
- end
-
- def serialization_format
- model.default_format
+ # Where do we store our data?
+ def data_directory
+ name = Puppet.run_mode.master? ? :server_datadir : :client_datadir
+
+ File.join(Puppet.settings[name], self.class.indirection_name.to_s)
+ end
+
+ def file_format(path)
+ path =~ /\.(\w+)$/ and return $1
+ end
+
+ def file_path(request)
+ File.join(data_directory, request.key + ".#{serialization_format}")
+ end
+
+ def latest_path(request)
+ files = Dir.glob(File.join(data_directory, request.key + ".*"))
+ return nil if files.empty?
+
+ # Return the newest file.
+ files.sort { |a, b| File.stat(b).mtime <=> File.stat(a).mtime }[0]
+ end
+
+ def serialization_format
+ model.default_format
+ end
+
+ # Remove files on disk.
+ def destroy(request)
+ begin
+ removed = false
+ Dir.glob(File.join(data_directory, request.key.to_s + ".*")).each do |file|
+ removed = true
+ File.unlink(file)
+ end
+ rescue => detail
+ raise Puppet::Error, "Could not remove #{request.key}: #{detail}"
end
- # Remove files on disk.
- def destroy(request)
- begin
- removed = false
- Dir.glob(File.join(data_directory, request.key.to_s + ".*")).each do |file|
- removed = true
- File.unlink(file)
- end
- rescue => detail
- raise Puppet::Error, "Could not remove #{request.key}: #{detail}"
- end
-
- raise Puppet::Error, "Could not find files for #{request.key} to remove" unless removed
- end
+ raise Puppet::Error, "Could not find files for #{request.key} to remove" unless removed
+ end
- # Return a model instance for a given file on disk.
- def find(request)
- return nil unless path = latest_path(request)
- format = file_format(path)
+ # Return a model instance for a given file on disk.
+ def find(request)
+ return nil unless path = latest_path(request)
+ format = file_format(path)
- raise ArgumentError, "File format #{format} is not supported by #{self.class.indirection_name}" unless model.support_format?(format)
+ raise ArgumentError, "File format #{format} is not supported by #{self.class.indirection_name}" unless model.support_format?(format)
- begin
- return model.convert_from(format, File.read(path))
- rescue => detail
- raise Puppet::Error, "Could not convert path #{path} into a #{self.class.indirection_name}: #{detail}"
- end
+ begin
+ return model.convert_from(format, File.read(path))
+ rescue => detail
+ raise Puppet::Error, "Could not convert path #{path} into a #{self.class.indirection_name}: #{detail}"
end
+ end
- # Save a new file to disk.
- def save(request)
- path = file_path(request)
+ # Save a new file to disk.
+ def save(request)
+ path = file_path(request)
- dir = File.dirname(path)
+ dir = File.dirname(path)
- raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} does not exist") unless File.directory?(dir)
+ raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} does not exist") unless File.directory?(dir)
- begin
- File.open(path, "w") { |f| f.print request.instance.render(serialization_format) }
- rescue => detail
- raise Puppet::Error, "Could not write #{request.key}: #{detail}" % [request.key, detail]
- end
+ begin
+ File.open(path, "w") { |f| f.print request.instance.render(serialization_format) }
+ rescue => detail
+ raise Puppet::Error, "Could not write #{request.key}: #{detail}" % [request.key, detail]
end
+ end
- def path(key)
- key
- end
+ def path(key)
+ key
+ end
end
diff --git a/lib/puppet/indirector/file_bucket_file/file.rb b/lib/puppet/indirector/file_bucket_file/file.rb
index ed978695e..318858aaf 100644
--- a/lib/puppet/indirector/file_bucket_file/file.rb
+++ b/lib/puppet/indirector/file_bucket_file/file.rb
@@ -4,143 +4,143 @@ require 'puppet/util/checksums'
require 'fileutils'
module Puppet::FileBucketFile
- class File < Puppet::Indirector::Code
- include Puppet::Util::Checksums
+ class File < Puppet::Indirector::Code
+ include Puppet::Util::Checksums
- desc "Store files in a directory set based on their checksums."
+ desc "Store files in a directory set based on their checksums."
- def initialize
- Puppet.settings.use(:filebucket)
- end
-
- def find( request )
- checksum, path = request_to_checksum_and_path( request )
- find_by_checksum( checksum, request.options )
- end
+ def initialize
+ Puppet.settings.use(:filebucket)
+ end
- def save( request )
- checksum, path = request_to_checksum_and_path( request )
+ def find( request )
+ checksum, path = request_to_checksum_and_path( request )
+ find_by_checksum( checksum, request.options )
+ end
- instance = request.instance
- instance.checksum = checksum if checksum
- instance.path = path if path
+ def save( request )
+ checksum, path = request_to_checksum_and_path( request )
- save_to_disk(instance)
- instance.to_s
- end
+ instance = request.instance
+ instance.checksum = checksum if checksum
+ instance.path = path if path
- private
+ save_to_disk(instance)
+ instance.to_s
+ end
- def find_by_checksum( checksum, options )
- model.new( nil, :checksum => checksum ) do |bucket_file|
- bucket_file.bucket_path = options[:bucket_path]
- filename = contents_path_for( bucket_file )
+ private
- return nil if ! ::File.exist? filename
+ def find_by_checksum( checksum, options )
+ model.new( nil, :checksum => checksum ) do |bucket_file|
+ bucket_file.bucket_path = options[:bucket_path]
+ filename = contents_path_for( bucket_file )
- begin
- contents = ::File.read filename
- Puppet.info "FileBucket read #{bucket_file.checksum}"
- rescue RuntimeError => e
- raise Puppet::Error, "file could not be read: #{e.message}"
- end
+ return nil if ! ::File.exist? filename
- if ::File.exist?(paths_path_for( bucket_file) )
- ::File.open(paths_path_for( bucket_file) ) do |f|
- bucket_file.paths = f.readlines.map { |l| l.chomp }
- end
- end
+ begin
+ contents = ::File.read filename
+ Puppet.info "FileBucket read #{bucket_file.checksum}"
+ rescue RuntimeError => e
+ raise Puppet::Error, "file could not be read: #{e.message}"
+ end
- bucket_file.contents = contents
- end
+ if ::File.exist?(paths_path_for( bucket_file) )
+ ::File.open(paths_path_for( bucket_file) ) do |f|
+ bucket_file.paths = f.readlines.map { |l| l.chomp }
+ end
end
- def save_to_disk( bucket_file )
- # If the file already exists, just return the md5 sum.
- if ::File.exist?(contents_path_for( bucket_file) )
- verify_identical_file!(bucket_file)
- else
- # Make the directories if necessary.
- unless ::File.directory?( path_for( bucket_file) )
- Puppet::Util.withumask(0007) do
- ::FileUtils.mkdir_p( path_for( bucket_file) )
- end
- end
-
- Puppet.info "FileBucket adding #{bucket_file.path} as #{bucket_file.checksum}"
-
- # Write the file to disk.
- Puppet::Util.withumask(0007) do
- ::File.open(contents_path_for(bucket_file), ::File::WRONLY|::File::CREAT, 0440) do |of|
- of.print bucket_file.contents
- end
- end
- end
-
- save_path_to_paths_file(bucket_file)
- bucket_file.checksum_data
+ bucket_file.contents = contents
+ end
+ end
+
+ def save_to_disk( bucket_file )
+ # If the file already exists, just return the md5 sum.
+ if ::File.exist?(contents_path_for( bucket_file) )
+ verify_identical_file!(bucket_file)
+ else
+ # Make the directories if necessary.
+ unless ::File.directory?( path_for( bucket_file) )
+ Puppet::Util.withumask(0007) do
+ ::FileUtils.mkdir_p( path_for( bucket_file) )
+ end
end
- def request_to_checksum_and_path( request )
- return [request.key, nil] if checksum?(request.key)
+ Puppet.info "FileBucket adding #{bucket_file.path} as #{bucket_file.checksum}"
- checksum_type, checksum, path = request.key.split(/\//, 3)
- return(checksum_type.to_s == "" ? nil : [ "{#{checksum_type}}#{checksum}", path ])
+ # Write the file to disk.
+ Puppet::Util.withumask(0007) do
+ ::File.open(contents_path_for(bucket_file), ::File::WRONLY|::File::CREAT, 0440) do |of|
+ of.print bucket_file.contents
+ end
end
+ end
- def path_for(bucket_file, subfile = nil)
- bucket_path = bucket_file.bucket_path || Puppet[:bucketdir]
- digest = bucket_file.checksum_data
+ save_path_to_paths_file(bucket_file)
+ bucket_file.checksum_data
+ end
- dir = ::File.join(digest[0..7].split(""))
- basedir = ::File.join(bucket_path, dir, digest)
+ def request_to_checksum_and_path( request )
+ return [request.key, nil] if checksum?(request.key)
- return basedir unless subfile
- ::File.join(basedir, subfile)
- end
+ checksum_type, checksum, path = request.key.split(/\//, 3)
+ return(checksum_type.to_s == "" ? nil : [ "{#{checksum_type}}#{checksum}", path ])
+ end
- def contents_path_for(bucket_file)
- path_for(bucket_file, "contents")
- end
+ def path_for(bucket_file, subfile = nil)
+ bucket_path = bucket_file.bucket_path || Puppet[:bucketdir]
+ digest = bucket_file.checksum_data
- def paths_path_for(bucket_file)
- path_for(bucket_file, "paths")
- end
+ dir = ::File.join(digest[0..7].split(""))
+ basedir = ::File.join(bucket_path, dir, digest)
- def content_check?
- true
- end
+ return basedir unless subfile
+ ::File.join(basedir, subfile)
+ end
- # If conflict_check is enabled, verify that the passed text is
- # the same as the text in our file.
- def verify_identical_file!(bucket_file)
- return unless content_check?
- disk_contents = ::File.read(contents_path_for(bucket_file))
-
- # If the contents don't match, then we've found a conflict.
- # Unlikely, but quite bad.
- if disk_contents != bucket_file.contents
- raise Puppet::FileBucket::BucketError, "Got passed new contents for sum #{bucket_file.checksum}", caller
- else
- Puppet.info "FileBucket got a duplicate file #{bucket_file.path} (#{bucket_file.checksum})"
- end
- end
+ def contents_path_for(bucket_file)
+ path_for(bucket_file, "contents")
+ end
- def save_path_to_paths_file(bucket_file)
- return unless bucket_file.path
+ def paths_path_for(bucket_file)
+ path_for(bucket_file, "paths")
+ end
+
+ def content_check?
+ true
+ end
- # check for dupes
- if ::File.exist?(paths_path_for( bucket_file) )
- ::File.open(paths_path_for( bucket_file) ) do |f|
- return if f.readlines.collect { |l| l.chomp }.include?(bucket_file.path)
- end
- end
+ # If conflict_check is enabled, verify that the passed text is
+ # the same as the text in our file.
+ def verify_identical_file!(bucket_file)
+ return unless content_check?
+ disk_contents = ::File.read(contents_path_for(bucket_file))
+
+ # If the contents don't match, then we've found a conflict.
+ # Unlikely, but quite bad.
+ if disk_contents != bucket_file.contents
+ raise Puppet::FileBucket::BucketError, "Got passed new contents for sum #{bucket_file.checksum}", caller
+ else
+ Puppet.info "FileBucket got a duplicate file #{bucket_file.path} (#{bucket_file.checksum})"
+ end
+ end
+
+ def save_path_to_paths_file(bucket_file)
+ return unless bucket_file.path
- # if it's a new file, or if our path isn't in the file yet, add it
- ::File.open(paths_path_for(bucket_file), ::File::WRONLY|::File::CREAT|::File::APPEND) do |of|
- of.puts bucket_file.path
- end
+ # check for dupes
+ if ::File.exist?(paths_path_for( bucket_file) )
+ ::File.open(paths_path_for( bucket_file) ) do |f|
+ return if f.readlines.collect { |l| l.chomp }.include?(bucket_file.path)
end
+ end
+ # if it's a new file, or if our path isn't in the file yet, add it
+ ::File.open(paths_path_for(bucket_file), ::File::WRONLY|::File::CREAT|::File::APPEND) do |of|
+ of.puts bucket_file.path
+ end
end
+
+ end
end
diff --git a/lib/puppet/indirector/file_bucket_file/rest.rb b/lib/puppet/indirector/file_bucket_file/rest.rb
index 15e4f331d..783d43586 100644
--- a/lib/puppet/indirector/file_bucket_file/rest.rb
+++ b/lib/puppet/indirector/file_bucket_file/rest.rb
@@ -2,7 +2,7 @@ require 'puppet/indirector/rest'
require 'puppet/file_bucket/file'
module Puppet::FileBucketFile
- class Rest < Puppet::Indirector::REST
- desc "This is a REST based mechanism to send/retrieve file to/from the filebucket"
- end
+ class Rest < Puppet::Indirector::REST
+ desc "This is a REST based mechanism to send/retrieve file to/from the filebucket"
+ end
end
diff --git a/lib/puppet/indirector/file_content/file.rb b/lib/puppet/indirector/file_content/file.rb
index 30c79583c..75fc9981c 100644
--- a/lib/puppet/indirector/file_content/file.rb
+++ b/lib/puppet/indirector/file_content/file.rb
@@ -7,5 +7,5 @@ require 'puppet/indirector/file_content'
require 'puppet/indirector/direct_file_server'
class Puppet::Indirector::FileContent::File < Puppet::Indirector::DirectFileServer
- desc "Retrieve file contents from disk."
+ desc "Retrieve file contents from disk."
end
diff --git a/lib/puppet/indirector/file_content/file_server.rb b/lib/puppet/indirector/file_content/file_server.rb
index 2f50fcc23..21cfe7324 100644
--- a/lib/puppet/indirector/file_content/file_server.rb
+++ b/lib/puppet/indirector/file_content/file_server.rb
@@ -7,5 +7,5 @@ require 'puppet/indirector/file_content'
require 'puppet/indirector/file_server'
class Puppet::Indirector::FileContent::FileServer < Puppet::Indirector::FileServer
- desc "Retrieve file contents using Puppet's fileserver."
+ desc "Retrieve file contents using Puppet's fileserver."
end
diff --git a/lib/puppet/indirector/file_content/rest.rb b/lib/puppet/indirector/file_content/rest.rb
index 7b3cade8e..2fd39b7e5 100644
--- a/lib/puppet/indirector/file_content/rest.rb
+++ b/lib/puppet/indirector/file_content/rest.rb
@@ -7,5 +7,5 @@ require 'puppet/indirector/file_content'
require 'puppet/indirector/rest'
class Puppet::Indirector::FileContent::Rest < Puppet::Indirector::REST
- desc "Retrieve file contents via a REST HTTP interface."
+ desc "Retrieve file contents via a REST HTTP interface."
end
diff --git a/lib/puppet/indirector/file_metadata/file.rb b/lib/puppet/indirector/file_metadata/file.rb
index 94047485f..4d6b0b335 100644
--- a/lib/puppet/indirector/file_metadata/file.rb
+++ b/lib/puppet/indirector/file_metadata/file.rb
@@ -7,20 +7,20 @@ require 'puppet/indirector/file_metadata'
require 'puppet/indirector/direct_file_server'
class Puppet::Indirector::FileMetadata::File < Puppet::Indirector::DirectFileServer
- desc "Retrieve file metadata directly from the local filesystem."
+ desc "Retrieve file metadata directly from the local filesystem."
- def find(request)
- return unless data = super
- data.collect
+ def find(request)
+ return unless data = super
+ data.collect
- data
- end
+ data
+ end
- def search(request)
- return unless result = super
+ def search(request)
+ return unless result = super
- result.each { |instance| instance.collect }
+ result.each { |instance| instance.collect }
- result
- end
+ result
+ end
end
diff --git a/lib/puppet/indirector/file_metadata/file_server.rb b/lib/puppet/indirector/file_metadata/file_server.rb
index 0b2e78908..cef81f0a5 100644
--- a/lib/puppet/indirector/file_metadata/file_server.rb
+++ b/lib/puppet/indirector/file_metadata/file_server.rb
@@ -7,5 +7,5 @@ require 'puppet/indirector/file_metadata'
require 'puppet/indirector/file_server'
class Puppet::Indirector::FileMetadata::FileServer < Puppet::Indirector::FileServer
- desc "Retrieve file metadata using Puppet's fileserver."
+ desc "Retrieve file metadata using Puppet's fileserver."
end
diff --git a/lib/puppet/indirector/file_metadata/rest.rb b/lib/puppet/indirector/file_metadata/rest.rb
index 8cbf91049..023edb8ff 100644
--- a/lib/puppet/indirector/file_metadata/rest.rb
+++ b/lib/puppet/indirector/file_metadata/rest.rb
@@ -7,5 +7,5 @@ require 'puppet/indirector/file_metadata'
require 'puppet/indirector/rest'
class Puppet::Indirector::FileMetadata::Rest < Puppet::Indirector::REST
- desc "Retrieve file metadata via a REST HTTP interface."
+ desc "Retrieve file metadata via a REST HTTP interface."
end
diff --git a/lib/puppet/indirector/file_server.rb b/lib/puppet/indirector/file_server.rb
index 833fc6f82..46a08c97d 100644
--- a/lib/puppet/indirector/file_server.rb
+++ b/lib/puppet/indirector/file_server.rb
@@ -9,61 +9,61 @@ require 'puppet/indirector/terminus'
# Look files up using the file server.
class Puppet::Indirector::FileServer < Puppet::Indirector::Terminus
- include Puppet::FileServing::TerminusHelper
+ include Puppet::FileServing::TerminusHelper
- # Is the client authorized to perform this action?
- def authorized?(request)
- return false unless [:find, :search].include?(request.method)
+ # Is the client authorized to perform this action?
+ def authorized?(request)
+ return false unless [:find, :search].include?(request.method)
- mount, file_path = configuration.split_path(request)
+ mount, file_path = configuration.split_path(request)
- # If we're not serving this mount, then access is denied.
- return false unless mount
- mount.allowed?(request.node, request.ip)
- end
+ # If we're not serving this mount, then access is denied.
+ return false unless mount
+ mount.allowed?(request.node, request.ip)
+ end
- # Find our key using the fileserver.
- def find(request)
- mount, relative_path = configuration.split_path(request)
+ # Find our key using the fileserver.
+ def find(request)
+ mount, relative_path = configuration.split_path(request)
- return nil unless mount
+ return nil unless mount
- # The mount checks to see if the file exists, and returns nil
- # if not.
- return nil unless path = mount.find(relative_path, request)
- result = model.new(path)
- result.links = request.options[:links] if request.options[:links]
- result.collect
- result
- end
+ # The mount checks to see if the file exists, and returns nil
+ # if not.
+ return nil unless path = mount.find(relative_path, request)
+ result = model.new(path)
+ result.links = request.options[:links] if request.options[:links]
+ result.collect
+ result
+ end
- # Search for files. This returns an array rather than a single
- # file.
- def search(request)
- mount, relative_path = configuration.split_path(request)
+ # Search for files. This returns an array rather than a single
+ # file.
+ def search(request)
+ mount, relative_path = configuration.split_path(request)
- unless mount and paths = mount.search(relative_path, request)
- Puppet.info "Could not find filesystem info for file '#{request.key}' in environment #{request.environment}"
- return nil
- end
+ unless mount and paths = mount.search(relative_path, request)
+ Puppet.info "Could not find filesystem info for file '#{request.key}' in environment #{request.environment}"
+ return nil
+ end
- filesets = paths.collect do |path|
- # Filesets support indirector requests as an options collection
- Puppet::FileServing::Fileset.new(path, request)
- end
+ filesets = paths.collect do |path|
+ # Filesets support indirector requests as an options collection
+ Puppet::FileServing::Fileset.new(path, request)
+ end
- Puppet::FileServing::Fileset.merge(*filesets).collect do |file, base_path|
- inst = model.new(base_path, :relative_path => file)
- inst.links = request.options[:links] if request.options[:links]
- inst.collect
- inst
- end
+ Puppet::FileServing::Fileset.merge(*filesets).collect do |file, base_path|
+ inst = model.new(base_path, :relative_path => file)
+ inst.links = request.options[:links] if request.options[:links]
+ inst.collect
+ inst
end
+ end
- private
+ private
- # Our fileserver configuration, if needed.
- def configuration
- Puppet::FileServing::Configuration.create
- end
+ # Our fileserver configuration, if needed.
+ def configuration
+ Puppet::FileServing::Configuration.create
+ end
end
diff --git a/lib/puppet/indirector/indirection.rb b/lib/puppet/indirector/indirection.rb
index 2b7da22ec..309eed7b6 100644
--- a/lib/puppet/indirector/indirection.rb
+++ b/lib/puppet/indirector/indirection.rb
@@ -7,302 +7,302 @@ require 'puppet/util/cacher'
# back-ends. Each indirection has a set of associated terminus classes,
# each of which is a subclass of Puppet::Indirector::Terminus.
class Puppet::Indirector::Indirection
- include Puppet::Util::Cacher
- include Puppet::Util::Docs
-
- @@indirections = []
-
- # Find an indirection by name. This is provided so that Terminus classes
- # can specifically hook up with the indirections they are associated with.
- def self.instance(name)
- @@indirections.find { |i| i.name == name }
+ include Puppet::Util::Cacher
+ include Puppet::Util::Docs
+
+ @@indirections = []
+
+ # Find an indirection by name. This is provided so that Terminus classes
+ # can specifically hook up with the indirections they are associated with.
+ def self.instance(name)
+ @@indirections.find { |i| i.name == name }
+ end
+
+ # Return a list of all known indirections. Used to generate the
+ # reference.
+ def self.instances
+ @@indirections.collect { |i| i.name }
+ end
+
+ # Find an indirected model by name. This is provided so that Terminus classes
+ # can specifically hook up with the indirections they are associated with.
+ def self.model(name)
+ return nil unless match = @@indirections.find { |i| i.name == name }
+ match.model
+ end
+
+ attr_accessor :name, :model
+
+ # Create and return our cache terminus.
+ def cache
+ raise(Puppet::DevError, "Tried to cache when no cache class was set") unless cache_class
+ terminus(cache_class)
+ end
+
+ # Should we use a cache?
+ def cache?
+ cache_class ? true : false
+ end
+
+ attr_reader :cache_class
+ # Define a terminus class to be used for caching.
+ def cache_class=(class_name)
+ validate_terminus_class(class_name) if class_name
+ @cache_class = class_name
+ end
+
+ # This is only used for testing.
+ def delete
+ @@indirections.delete(self) if @@indirections.include?(self)
+ end
+
+ # Set the time-to-live for instances created through this indirection.
+ def ttl=(value)
+ raise ArgumentError, "Indirection TTL must be an integer" unless value.is_a?(Fixnum)
+ @ttl = value
+ end
+
+ # Default to the runinterval for the ttl.
+ def ttl
+ @ttl ||= Puppet[:runinterval].to_i
+ end
+
+ # Calculate the expiration date for a returned instance.
+ def expiration
+ Time.now + ttl
+ end
+
+ # Generate the full doc string.
+ def doc
+ text = ""
+
+ text += scrub(@doc) + "\n\n" if @doc
+
+ if s = terminus_setting
+ text += "* **Terminus Setting**: #{terminus_setting}"
end
- # Return a list of all known indirections. Used to generate the
- # reference.
- def self.instances
- @@indirections.collect { |i| i.name }
- end
+ text
+ end
- # Find an indirected model by name. This is provided so that Terminus classes
- # can specifically hook up with the indirections they are associated with.
- def self.model(name)
- return nil unless match = @@indirections.find { |i| i.name == name }
- match.model
- end
-
- attr_accessor :name, :model
-
- # Create and return our cache terminus.
- def cache
- raise(Puppet::DevError, "Tried to cache when no cache class was set") unless cache_class
- terminus(cache_class)
- end
+ def initialize(model, name, options = {})
+ @model = model
+ @name = name
- # Should we use a cache?
- def cache?
- cache_class ? true : false
- end
+ @cache_class = nil
+ @terminus_class = nil
- attr_reader :cache_class
- # Define a terminus class to be used for caching.
- def cache_class=(class_name)
- validate_terminus_class(class_name) if class_name
- @cache_class = class_name
- end
+ raise(ArgumentError, "Indirection #{@name} is already defined") if @@indirections.find { |i| i.name == @name }
+ @@indirections << self
- # This is only used for testing.
- def delete
- @@indirections.delete(self) if @@indirections.include?(self)
+ if mod = options[:extend]
+ extend(mod)
+ options.delete(:extend)
end
- # Set the time-to-live for instances created through this indirection.
- def ttl=(value)
- raise ArgumentError, "Indirection TTL must be an integer" unless value.is_a?(Fixnum)
- @ttl = value
+ # This is currently only used for cache_class and terminus_class.
+ options.each do |name, value|
+ begin
+ send(name.to_s + "=", value)
+ rescue NoMethodError
+ raise ArgumentError, "#{name} is not a valid Indirection parameter"
+ end
end
-
- # Default to the runinterval for the ttl.
- def ttl
- @ttl ||= Puppet[:runinterval].to_i
+ end
+
+ # Set up our request object.
+ def request(*args)
+ Puppet::Indirector::Request.new(self.name, *args)
+ end
+
+ # Return the singleton terminus for this indirection.
+ def terminus(terminus_name = nil)
+ # Get the name of the terminus.
+ raise Puppet::DevError, "No terminus specified for #{self.name}; cannot redirect" unless terminus_name ||= terminus_class
+
+ termini[terminus_name] ||= make_terminus(terminus_name)
+ end
+
+ # This can be used to select the terminus class.
+ attr_accessor :terminus_setting
+
+ # Determine the terminus class.
+ def terminus_class
+ unless @terminus_class
+ if setting = self.terminus_setting
+ self.terminus_class = Puppet.settings[setting].to_sym
+ else
+ raise Puppet::DevError, "No terminus class nor terminus setting was provided for indirection #{self.name}"
+ end
end
-
- # Calculate the expiration date for a returned instance.
- def expiration
- Time.now + ttl
+ @terminus_class
+ end
+
+ def reset_terminus_class
+ @terminus_class = nil
+ end
+
+ # Specify the terminus class to use.
+ def terminus_class=(klass)
+ validate_terminus_class(klass)
+ @terminus_class = klass
+ end
+
+ # This is used by terminus_class= and cache=.
+ def validate_terminus_class(terminus_class)
+ raise ArgumentError, "Invalid terminus name #{terminus_class.inspect}" unless terminus_class and terminus_class.to_s != ""
+ unless Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
+ raise ArgumentError, "Could not find terminus #{terminus_class} for indirection #{self.name}"
end
+ end
- # Generate the full doc string.
- def doc
- text = ""
+ # Expire a cached object, if one is cached. Note that we don't actually
+ # remove it, we expire it and write it back out to disk. This way people
+ # can still use the expired object if they want.
+ def expire(key, *args)
+ request = request(:expire, key, *args)
- text += scrub(@doc) + "\n\n" if @doc
+ return nil unless cache?
- if s = terminus_setting
- text += "* **Terminus Setting**: #{terminus_setting}"
- end
+ return nil unless instance = cache.find(request(:find, key, *args))
- text
- end
+ Puppet.info "Expiring the #{self.name} cache of #{instance.name}"
- def initialize(model, name, options = {})
- @model = model
- @name = name
-
- @cache_class = nil
- @terminus_class = nil
-
- raise(ArgumentError, "Indirection #{@name} is already defined") if @@indirections.find { |i| i.name == @name }
- @@indirections << self
-
- if mod = options[:extend]
- extend(mod)
- options.delete(:extend)
- end
-
- # This is currently only used for cache_class and terminus_class.
- options.each do |name, value|
- begin
- send(name.to_s + "=", value)
- rescue NoMethodError
- raise ArgumentError, "#{name} is not a valid Indirection parameter"
- end
- end
- end
+ # Set an expiration date in the past
+ instance.expiration = Time.now - 60
- # Set up our request object.
- def request(*args)
- Puppet::Indirector::Request.new(self.name, *args)
- end
+ cache.save(request(:save, instance, *args))
+ end
- # Return the singleton terminus for this indirection.
- def terminus(terminus_name = nil)
- # Get the name of the terminus.
- raise Puppet::DevError, "No terminus specified for #{self.name}; cannot redirect" unless terminus_name ||= terminus_class
+ # Search for an instance in the appropriate terminus, caching the
+ # results if caching is configured..
+ def find(key, *args)
+ request = request(:find, key, *args)
+ terminus = prepare(request)
- termini[terminus_name] ||= make_terminus(terminus_name)
+ begin
+ if result = find_in_cache(request)
+ return result
+ end
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Cached #{self.name} for #{request.key} failed: #{detail}"
end
- # This can be used to select the terminus class.
- attr_accessor :terminus_setting
-
- # Determine the terminus class.
- def terminus_class
- unless @terminus_class
- if setting = self.terminus_setting
- self.terminus_class = Puppet.settings[setting].to_sym
- else
- raise Puppet::DevError, "No terminus class nor terminus setting was provided for indirection #{self.name}"
- end
- end
- @terminus_class
- end
+ # Otherwise, return the result from the terminus, caching if appropriate.
+ if ! request.ignore_terminus? and result = terminus.find(request)
+ result.expiration ||= self.expiration
+ if cache? and request.use_cache?
+ Puppet.info "Caching #{self.name} for #{request.key}"
+ cache.save request(:save, result, *args)
+ end
- def reset_terminus_class
- @terminus_class = nil
+ return terminus.respond_to?(:filter) ? terminus.filter(result) : result
end
- # Specify the terminus class to use.
- def terminus_class=(klass)
- validate_terminus_class(klass)
- @terminus_class = klass
- end
+ nil
+ end
- # This is used by terminus_class= and cache=.
- def validate_terminus_class(terminus_class)
- raise ArgumentError, "Invalid terminus name #{terminus_class.inspect}" unless terminus_class and terminus_class.to_s != ""
- unless Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
- raise ArgumentError, "Could not find terminus #{terminus_class} for indirection #{self.name}"
- end
+ def find_in_cache(request)
+ # See if our instance is in the cache and up to date.
+ return nil unless cache? and ! request.ignore_cache? and cached = cache.find(request)
+ if cached.expired?
+ Puppet.info "Not using expired #{self.name} for #{request.key} from cache; expired at #{cached.expiration}"
+ return nil
end
- # Expire a cached object, if one is cached. Note that we don't actually
- # remove it, we expire it and write it back out to disk. This way people
- # can still use the expired object if they want.
- def expire(key, *args)
- request = request(:expire, key, *args)
-
- return nil unless cache?
-
- return nil unless instance = cache.find(request(:find, key, *args))
+ Puppet.debug "Using cached #{self.name} for #{request.key}"
+ cached
+ end
- Puppet.info "Expiring the #{self.name} cache of #{instance.name}"
+ # Remove something via the terminus.
+ def destroy(key, *args)
+ request = request(:destroy, key, *args)
+ terminus = prepare(request)
- # Set an expiration date in the past
- instance.expiration = Time.now - 60
+ result = terminus.destroy(request)
- cache.save(request(:save, instance, *args))
+ if cache? and cached = cache.find(request(:find, key, *args))
+ # Reuse the existing request, since it's equivalent.
+ cache.destroy(request)
end
- # Search for an instance in the appropriate terminus, caching the
- # results if caching is configured..
- def find(key, *args)
- request = request(:find, key, *args)
- terminus = prepare(request)
-
- begin
- if result = find_in_cache(request)
- return result
- end
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Cached #{self.name} for #{request.key} failed: #{detail}"
- end
-
- # Otherwise, return the result from the terminus, caching if appropriate.
- if ! request.ignore_terminus? and result = terminus.find(request)
- result.expiration ||= self.expiration
- if cache? and request.use_cache?
- Puppet.info "Caching #{self.name} for #{request.key}"
- cache.save request(:save, result, *args)
- end
-
- return terminus.respond_to?(:filter) ? terminus.filter(result) : result
- end
-
- nil
- end
+ result
+ end
- def find_in_cache(request)
- # See if our instance is in the cache and up to date.
- return nil unless cache? and ! request.ignore_cache? and cached = cache.find(request)
- if cached.expired?
- Puppet.info "Not using expired #{self.name} for #{request.key} from cache; expired at #{cached.expiration}"
- return nil
- end
+ # Search for more than one instance. Should always return an array.
+ def search(key, *args)
+ request = request(:search, key, *args)
+ terminus = prepare(request)
- Puppet.debug "Using cached #{self.name} for #{request.key}"
- cached
+ if result = terminus.search(request)
+ raise Puppet::DevError, "Search results from terminus #{terminus.name} are not an array" unless result.is_a?(Array)
+ result.each do |instance|
+ instance.expiration ||= self.expiration
+ end
+ return result
end
+ end
- # Remove something via the terminus.
- def destroy(key, *args)
- request = request(:destroy, key, *args)
- terminus = prepare(request)
-
- result = terminus.destroy(request)
+ # Save the instance in the appropriate terminus. This method is
+ # normally an instance method on the indirected class.
+ def save(key, instance = nil)
+ request = request(:save, key, instance)
+ terminus = prepare(request)
- if cache? and cached = cache.find(request(:find, key, *args))
- # Reuse the existing request, since it's equivalent.
- cache.destroy(request)
- end
+ result = terminus.save(request)
- result
- end
+ # If caching is enabled, save our document there
+ cache.save(request) if cache?
- # Search for more than one instance. Should always return an array.
- def search(key, *args)
- request = request(:search, key, *args)
- terminus = prepare(request)
-
- if result = terminus.search(request)
- raise Puppet::DevError, "Search results from terminus #{terminus.name} are not an array" unless result.is_a?(Array)
- result.each do |instance|
- instance.expiration ||= self.expiration
- end
- return result
- end
- end
+ result
+ end
- # Save the instance in the appropriate terminus. This method is
- # normally an instance method on the indirected class.
- def save(key, instance = nil)
- request = request(:save, key, instance)
- terminus = prepare(request)
+ private
- result = terminus.save(request)
+ # Check authorization if there's a hook available; fail if there is one
+ # and it returns false.
+ def check_authorization(request, terminus)
+ # At this point, we're assuming authorization makes no sense without
+ # client information.
+ return unless request.node
- # If caching is enabled, save our document there
- cache.save(request) if cache?
+ # This is only to authorize via a terminus-specific authorization hook.
+ return unless terminus.respond_to?(:authorized?)
- result
+ unless terminus.authorized?(request)
+ msg = "Not authorized to call #{request.method} on #{request}"
+ msg += " with #{request.options.inspect}" unless request.options.empty?
+ raise ArgumentError, msg
end
-
- private
-
- # Check authorization if there's a hook available; fail if there is one
- # and it returns false.
- def check_authorization(request, terminus)
- # At this point, we're assuming authorization makes no sense without
- # client information.
- return unless request.node
-
- # This is only to authorize via a terminus-specific authorization hook.
- return unless terminus.respond_to?(:authorized?)
-
- unless terminus.authorized?(request)
- msg = "Not authorized to call #{request.method} on #{request}"
- msg += " with #{request.options.inspect}" unless request.options.empty?
- raise ArgumentError, msg
- end
+ end
+
+ # Setup a request, pick the appropriate terminus, check the request's authorization, and return it.
+ def prepare(request)
+ # Pick our terminus.
+ if respond_to?(:select_terminus)
+ unless terminus_name = select_terminus(request)
+ raise ArgumentError, "Could not determine appropriate terminus for #{request}"
+ end
+ else
+ terminus_name = terminus_class
end
- # Setup a request, pick the appropriate terminus, check the request's authorization, and return it.
- def prepare(request)
- # Pick our terminus.
- if respond_to?(:select_terminus)
- unless terminus_name = select_terminus(request)
- raise ArgumentError, "Could not determine appropriate terminus for #{request}"
- end
- else
- terminus_name = terminus_class
- end
-
- dest_terminus = terminus(terminus_name)
- check_authorization(request, dest_terminus)
-
- dest_terminus
- end
+ dest_terminus = terminus(terminus_name)
+ check_authorization(request, dest_terminus)
+
+ dest_terminus
+ end
- # Create a new terminus instance.
- def make_terminus(terminus_class)
- # Load our terminus class.
- unless klass = Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
- raise ArgumentError, "Could not find terminus #{terminus_class} for indirection #{self.name}"
- end
- klass.new
+ # Create a new terminus instance.
+ def make_terminus(terminus_class)
+ # Load our terminus class.
+ unless klass = Puppet::Indirector::Terminus.terminus_class(self.name, terminus_class)
+ raise ArgumentError, "Could not find terminus #{terminus_class} for indirection #{self.name}"
end
+ klass.new
+ end
- # Cache our terminus instances indefinitely, but make it easy to clean them up.
- cached_attr(:termini) { Hash.new }
+ # Cache our terminus instances indefinitely, but make it easy to clean them up.
+ cached_attr(:termini) { Hash.new }
end
diff --git a/lib/puppet/indirector/key/ca.rb b/lib/puppet/indirector/key/ca.rb
index 62dd77589..056d037dd 100644
--- a/lib/puppet/indirector/key/ca.rb
+++ b/lib/puppet/indirector/key/ca.rb
@@ -2,11 +2,11 @@ require 'puppet/indirector/ssl_file'
require 'puppet/ssl/key'
class Puppet::SSL::Key::Ca < Puppet::Indirector::SslFile
- desc "Manage the CA's private on disk. This terminus *only* works
- with the CA key, because that's the only key that the CA ever interacts
- with."
+ desc "Manage the CA's private on disk. This terminus *only* works
+ with the CA key, because that's the only key that the CA ever interacts
+ with."
- store_in :privatekeydir
+ store_in :privatekeydir
- store_ca_at :cakey
+ store_ca_at :cakey
end
diff --git a/lib/puppet/indirector/key/file.rb b/lib/puppet/indirector/key/file.rb
index 51b5cfd3d..1990f1a46 100644
--- a/lib/puppet/indirector/key/file.rb
+++ b/lib/puppet/indirector/key/file.rb
@@ -2,41 +2,41 @@ require 'puppet/indirector/ssl_file'
require 'puppet/ssl/key'
class Puppet::SSL::Key::File < Puppet::Indirector::SslFile
- desc "Manage SSL private and public keys on disk."
-
- store_in :privatekeydir
- store_ca_at :cakey
-
- # Where should we store the public key?
- def public_key_path(name)
- if ca?(name)
- Puppet[:capub]
- else
- File.join(Puppet[:publickeydir], name.to_s + ".pem")
- end
+ desc "Manage SSL private and public keys on disk."
+
+ store_in :privatekeydir
+ store_ca_at :cakey
+
+ # Where should we store the public key?
+ def public_key_path(name)
+ if ca?(name)
+ Puppet[:capub]
+ else
+ File.join(Puppet[:publickeydir], name.to_s + ".pem")
end
+ end
- # Remove the public key, in addition to the private key
- def destroy(request)
- super
+ # Remove the public key, in addition to the private key
+ def destroy(request)
+ super
- return unless FileTest.exist?(public_key_path(request.key))
+ return unless FileTest.exist?(public_key_path(request.key))
- begin
- File.unlink(public_key_path(request.key))
- rescue => detail
- raise Puppet::Error, "Could not remove #{request.key} public key: #{detail}"
- end
+ begin
+ File.unlink(public_key_path(request.key))
+ rescue => detail
+ raise Puppet::Error, "Could not remove #{request.key} public key: #{detail}"
end
+ end
- # Save the public key, in addition to the private key.
- def save(request)
- super
+ # Save the public key, in addition to the private key.
+ def save(request)
+ super
- begin
- Puppet.settings.writesub(:publickeydir, public_key_path(request.key)) { |f| f.print request.instance.content.public_key.to_pem }
- rescue => detail
- raise Puppet::Error, "Could not write #{request.key}: #{detail}"
- end
+ begin
+ Puppet.settings.writesub(:publickeydir, public_key_path(request.key)) { |f| f.print request.instance.content.public_key.to_pem }
+ rescue => detail
+ raise Puppet::Error, "Could not write #{request.key}: #{detail}"
end
+ end
end
diff --git a/lib/puppet/indirector/ldap.rb b/lib/puppet/indirector/ldap.rb
index 3ccb21d52..8d7cd076a 100644
--- a/lib/puppet/indirector/ldap.rb
+++ b/lib/puppet/indirector/ldap.rb
@@ -2,77 +2,77 @@ require 'puppet/indirector/terminus'
require 'puppet/util/ldap/connection'
class Puppet::Indirector::Ldap < Puppet::Indirector::Terminus
- # Perform our ldap search and process the result.
- def find(request)
- ldapsearch(search_filter(request.key)) { |entry| return process(entry) } || nil
- end
+ # Perform our ldap search and process the result.
+ def find(request)
+ ldapsearch(search_filter(request.key)) { |entry| return process(entry) } || nil
+ end
- # Process the found entry. We assume that we don't just want the
- # ldap object.
- def process(entry)
- raise Puppet::DevError, "The 'process' method has not been overridden for the LDAP terminus for #{self.name}"
- end
+ # Process the found entry. We assume that we don't just want the
+ # ldap object.
+ def process(entry)
+ raise Puppet::DevError, "The 'process' method has not been overridden for the LDAP terminus for #{self.name}"
+ end
- # Default to all attributes.
- def search_attributes
- nil
- end
+ # Default to all attributes.
+ def search_attributes
+ nil
+ end
- def search_base
- Puppet[:ldapbase]
- end
+ def search_base
+ Puppet[:ldapbase]
+ end
- # The ldap search filter to use.
- def search_filter(name)
- raise Puppet::DevError, "No search string set for LDAP terminus for #{self.name}"
- end
-
- # Find the ldap node, return the class list and parent node specially,
- # and everything else in a parameter hash.
- def ldapsearch(filter)
- raise ArgumentError.new("You must pass a block to ldapsearch") unless block_given?
+ # The ldap search filter to use.
+ def search_filter(name)
+ raise Puppet::DevError, "No search string set for LDAP terminus for #{self.name}"
+ end
- found = false
- count = 0
+ # Find the ldap node, return the class list and parent node specially,
+ # and everything else in a parameter hash.
+ def ldapsearch(filter)
+ raise ArgumentError.new("You must pass a block to ldapsearch") unless block_given?
- begin
- connection.search(search_base, 2, filter, search_attributes) do |entry|
- found = true
- yield entry
- end
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- if count == 0
- # Try reconnecting to ldap if we get an exception and we haven't yet retried.
- count += 1
- @connection = nil
- Puppet.warning "Retrying LDAP connection"
- retry
- else
- error = Puppet::Error.new("LDAP Search failed")
- error.set_backtrace(detail.backtrace)
- raise error
- end
- end
+ found = false
+ count = 0
- found
+ begin
+ connection.search(search_base, 2, filter, search_attributes) do |entry|
+ found = true
+ yield entry
+ end
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ if count == 0
+ # Try reconnecting to ldap if we get an exception and we haven't yet retried.
+ count += 1
+ @connection = nil
+ Puppet.warning "Retrying LDAP connection"
+ retry
+ else
+ error = Puppet::Error.new("LDAP Search failed")
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
end
- # Create an ldap connection.
- def connection
- unless @connection
- raise Puppet::Error, "Could not set up LDAP Connection: Missing ruby/ldap libraries" unless Puppet.features.ldap?
- begin
- conn = Puppet::Util::Ldap::Connection.instance
- conn.start
- @connection = conn.connection
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not connect to LDAP: #{detail}"
- end
- end
+ found
+ end
- @connection
+ # Create an ldap connection.
+ def connection
+ unless @connection
+ raise Puppet::Error, "Could not set up LDAP Connection: Missing ruby/ldap libraries" unless Puppet.features.ldap?
+ begin
+ conn = Puppet::Util::Ldap::Connection.instance
+ conn.start
+ @connection = conn.connection
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Could not connect to LDAP: #{detail}"
+ end
end
+
+ @connection
+ end
end
diff --git a/lib/puppet/indirector/memory.rb b/lib/puppet/indirector/memory.rb
index 332e95bcb..c44d62de2 100644
--- a/lib/puppet/indirector/memory.rb
+++ b/lib/puppet/indirector/memory.rb
@@ -2,20 +2,20 @@ require 'puppet/indirector/terminus'
# Manage a memory-cached list of instances.
class Puppet::Indirector::Memory < Puppet::Indirector::Terminus
- def initialize
- @instances = {}
- end
+ def initialize
+ @instances = {}
+ end
- def destroy(request)
- raise ArgumentError.new("Could not find #{request.key} to destroy") unless @instances.include?(request.key)
- @instances.delete(request.key)
- end
+ def destroy(request)
+ raise ArgumentError.new("Could not find #{request.key} to destroy") unless @instances.include?(request.key)
+ @instances.delete(request.key)
+ end
- def find(request)
- @instances[request.key]
- end
+ def find(request)
+ @instances[request.key]
+ end
- def save(request)
- @instances[request.key] = request.instance
- end
+ def save(request)
+ @instances[request.key] = request.instance
+ end
end
diff --git a/lib/puppet/indirector/node/active_record.rb b/lib/puppet/indirector/node/active_record.rb
index 7b1ef9242..08bc7e67a 100644
--- a/lib/puppet/indirector/node/active_record.rb
+++ b/lib/puppet/indirector/node/active_record.rb
@@ -3,11 +3,11 @@ require 'puppet/indirector/active_record'
require 'puppet/node'
class Puppet::Node::ActiveRecord < Puppet::Indirector::ActiveRecord
- use_ar_model Puppet::Rails::Host
+ use_ar_model Puppet::Rails::Host
- def find(request)
- node = super
- node.fact_merge
- node
- end
+ def find(request)
+ node = super
+ node.fact_merge
+ node
+ end
end
diff --git a/lib/puppet/indirector/node/exec.rb b/lib/puppet/indirector/node/exec.rb
index a30b7557f..c3e690943 100644
--- a/lib/puppet/indirector/node/exec.rb
+++ b/lib/puppet/indirector/node/exec.rb
@@ -2,47 +2,47 @@ require 'puppet/node'
require 'puppet/indirector/exec'
class Puppet::Node::Exec < Puppet::Indirector::Exec
- desc "Call an external program to get node information. See
- the `ExternalNodes`:trac: page for more information."
- include Puppet::Util
-
- def command
- command = Puppet[:external_nodes]
- raise ArgumentError, "You must set the 'external_nodes' parameter to use the external node terminus" unless command != "none"
- command.split
+ desc "Call an external program to get node information. See
+ the `ExternalNodes`:trac: page for more information."
+ include Puppet::Util
+
+ def command
+ command = Puppet[:external_nodes]
+ raise ArgumentError, "You must set the 'external_nodes' parameter to use the external node terminus" unless command != "none"
+ command.split
+ end
+
+ # Look for external node definitions.
+ def find(request)
+ output = super or return nil
+
+ # Translate the output to ruby.
+ result = translate(request.key, output)
+
+ create_node(request.key, result)
+ end
+
+ private
+
+ # Turn our outputted objects into a Puppet::Node instance.
+ def create_node(name, result)
+ node = Puppet::Node.new(name)
+ set = false
+ [:parameters, :classes, :environment].each do |param|
+ if value = result[param]
+ node.send(param.to_s + "=", value)
+ set = true
+ end
end
- # Look for external node definitions.
- def find(request)
- output = super or return nil
+ node.fact_merge
+ node
+ end
- # Translate the output to ruby.
- result = translate(request.key, output)
-
- create_node(request.key, result)
- end
-
- private
-
- # Turn our outputted objects into a Puppet::Node instance.
- def create_node(name, result)
- node = Puppet::Node.new(name)
- set = false
- [:parameters, :classes, :environment].each do |param|
- if value = result[param]
- node.send(param.to_s + "=", value)
- set = true
- end
- end
-
- node.fact_merge
- node
- end
-
- # Translate the yaml string into Ruby objects.
- def translate(name, output)
- YAML.load(output).inject({}) { |hash, data| hash[symbolize(data[0])] = data[1]; hash }
- rescue => detail
- raise Puppet::Error, "Could not load external node results for #{name}: #{detail}"
- end
+ # Translate the yaml string into Ruby objects.
+ def translate(name, output)
+ YAML.load(output).inject({}) { |hash, data| hash[symbolize(data[0])] = data[1]; hash }
+ rescue => detail
+ raise Puppet::Error, "Could not load external node results for #{name}: #{detail}"
+ end
end
diff --git a/lib/puppet/indirector/node/ldap.rb b/lib/puppet/indirector/node/ldap.rb
index 9e4326273..b9fe35575 100644
--- a/lib/puppet/indirector/node/ldap.rb
+++ b/lib/puppet/indirector/node/ldap.rb
@@ -2,299 +2,299 @@ require 'puppet/node'
require 'puppet/indirector/ldap'
class Puppet::Node::Ldap < Puppet::Indirector::Ldap
- desc "Search in LDAP for node configuration information. See
- the `LdapNodes`:trac: page for more information. This will first
- search for whatever the certificate name is, then (if that name
- contains a '.') for the short name, then 'default'."
-
- # The attributes that Puppet class information is stored in.
- def class_attributes
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = Puppet[:ldapclassattrs].split(/\s*,\s*/)
+ desc "Search in LDAP for node configuration information. See
+ the `LdapNodes`:trac: page for more information. This will first
+ search for whatever the certificate name is, then (if that name
+ contains a '.') for the short name, then 'default'."
+
+ # The attributes that Puppet class information is stored in.
+ def class_attributes
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet[:ldapclassattrs].split(/\s*,\s*/)
+ end
+
+ # Separate this out so it's relatively atomic. It's tempting to call
+ # process instead of name2hash() here, but it ends up being
+ # difficult to test because all exceptions get caught by ldapsearch.
+ # LAK:NOTE Unfortunately, the ldap support is too stupid to throw anything
+ # but LDAP::ResultError, even on bad connections, so we are rough handed
+ # with our error handling.
+ def name2hash(name,name_env,node_type)
+ info = nil
+ ldapsearch(search_filter(name)) {
+ |entry| info = entry2hash(entry)
+ if info[:environment]
+ if name_env == info[:environment]
+ return info
+ else
+ info = nil
+ end
+ else
+ info_env = "production"
+ if name_env == info[:environment]
+ return info
+ else
+ info = nil
+ end
+ end
+ }
+ if node_type == 'parent'
+ raise Puppet::Error.new("Could not find node '#{name}' with environment '#{name_env}'")
end
- # Separate this out so it's relatively atomic. It's tempting to call
- # process instead of name2hash() here, but it ends up being
- # difficult to test because all exceptions get caught by ldapsearch.
- # LAK:NOTE Unfortunately, the ldap support is too stupid to throw anything
- # but LDAP::ResultError, even on bad connections, so we are rough handed
- # with our error handling.
- def name2hash(name,name_env,node_type)
- info = nil
- ldapsearch(search_filter(name)) {
- |entry| info = entry2hash(entry)
- if info[:environment]
- if name_env == info[:environment]
- return info
- else
- info = nil
- end
- else
- info_env = "production"
- if name_env == info[:environment]
- return info
- else
- info = nil
- end
- end
- }
- if node_type == 'parent'
- raise Puppet::Error.new("Could not find node '#{name}' with environment '#{name_env}'")
- end
-
- info = name2hash('default',name_env,'parent')
+ info = name2hash('default',name_env,'parent')
+ end
+
+ # Look for our node in ldap.
+ def find(request)
+ names = [request.key]
+ names << request.key.sub(/\..+/, '') if request.key.include?(".") # we assume it's an fqdn
+ names << "default"
+
+ node = nil
+ names.each do |name|
+ facts = Puppet::Node::Facts.find(name)
+ if facts.values["environment"]
+ name_env = facts.values["environment"]
+ else
+ name_env = "production"
+ end
+ info = name2hash(name,name_env,'child')
+ next if info == nil
+
+ if info
+ break if node = info2node(request.key, info)
+ end
end
- # Look for our node in ldap.
- def find(request)
- names = [request.key]
- names << request.key.sub(/\..+/, '') if request.key.include?(".") # we assume it's an fqdn
- names << "default"
-
- node = nil
- names.each do |name|
- facts = Puppet::Node::Facts.find(name)
- if facts.values["environment"]
- name_env = facts.values["environment"]
- else
- name_env = "production"
- end
- info = name2hash(name,name_env,'child')
- next if info == nil
-
- if info
- break if node = info2node(request.key, info)
- end
- end
-
- node
+ node
+ end
+
+ # Find more than one node. LAK:NOTE This is a bit of a clumsy API, because the 'search'
+ # method currently *requires* a key. It seems appropriate in some cases but not others,
+ # and I don't really know how to get rid of it as a requirement but allow it when desired.
+ def search(request)
+ if classes = request.options[:class]
+ classes = [classes] unless classes.is_a?(Array)
+ filter = "(&(objectclass=puppetClient)(puppetclass=" + classes.join(")(puppetclass=") + "))"
+ else
+ filter = "(objectclass=puppetClient)"
end
- # Find more than one node. LAK:NOTE This is a bit of a clumsy API, because the 'search'
- # method currently *requires* a key. It seems appropriate in some cases but not others,
- # and I don't really know how to get rid of it as a requirement but allow it when desired.
- def search(request)
- if classes = request.options[:class]
- classes = [classes] unless classes.is_a?(Array)
- filter = "(&(objectclass=puppetClient)(puppetclass=" + classes.join(")(puppetclass=") + "))"
- else
- filter = "(objectclass=puppetClient)"
- end
+ infos = []
+ ldapsearch(filter) { |entry| infos << entry2hash(entry, request.options[:fqdn]) }
- infos = []
- ldapsearch(filter) { |entry| infos << entry2hash(entry, request.options[:fqdn]) }
-
- return infos.collect do |info|
- info2node(info[:name], info)
- end
+ return infos.collect do |info|
+ info2node(info[:name], info)
end
-
- # The parent attribute, if we have one.
- def parent_attribute
- if pattr = Puppet[:ldapparentattr] and ! pattr.empty?
- pattr
- else
- nil
- end
+ end
+
+ # The parent attribute, if we have one.
+ def parent_attribute
+ if pattr = Puppet[:ldapparentattr] and ! pattr.empty?
+ pattr
+ else
+ nil
end
-
- # The attributes that Puppet will stack as array over the full
- # hierarchy.
- def stacked_attributes(dummy_argument=:work_arround_for_ruby_GC_bug)
- Puppet[:ldapstackedattrs].split(/\s*,\s*/)
+ end
+
+ # The attributes that Puppet will stack as array over the full
+ # hierarchy.
+ def stacked_attributes(dummy_argument=:work_arround_for_ruby_GC_bug)
+ Puppet[:ldapstackedattrs].split(/\s*,\s*/)
+ end
+
+ # Convert the found entry into a simple hash.
+ def entry2hash(entry, fqdn = false)
+ result = {}
+
+ cn = entry.dn[ /cn\s*=\s*([^,\s]+)/i,1]
+ dcs = entry.dn.scan(/dc\s*=\s*([^,\s]+)/i)
+ result[:name] = fqdn ? ([cn]+dcs).join('.') : cn
+ result[:parent] = get_parent_from_entry(entry) if parent_attribute
+ result[:classes] = get_classes_from_entry(entry)
+ result[:stacked] = get_stacked_values_from_entry(entry)
+ result[:parameters] = get_parameters_from_entry(entry)
+
+ result[:environment] = result[:parameters]["environment"] if result[:parameters]["environment"]
+
+ result[:stacked_parameters] = {}
+
+ if result[:stacked]
+ result[:stacked].each do |value|
+ param = value.split('=', 2)
+ result[:stacked_parameters][param[0]] = param[1]
+ end
end
- # Convert the found entry into a simple hash.
- def entry2hash(entry, fqdn = false)
- result = {}
-
- cn = entry.dn[ /cn\s*=\s*([^,\s]+)/i,1]
- dcs = entry.dn.scan(/dc\s*=\s*([^,\s]+)/i)
- result[:name] = fqdn ? ([cn]+dcs).join('.') : cn
- result[:parent] = get_parent_from_entry(entry) if parent_attribute
- result[:classes] = get_classes_from_entry(entry)
- result[:stacked] = get_stacked_values_from_entry(entry)
- result[:parameters] = get_parameters_from_entry(entry)
+ if result[:stacked_parameters]
+ result[:stacked_parameters].each do |param, value|
+ result[:parameters][param] = value unless result[:parameters].include?(param)
+ end
+ end
- result[:environment] = result[:parameters]["environment"] if result[:parameters]["environment"]
+ result[:parameters] = convert_parameters(result[:parameters])
- result[:stacked_parameters] = {}
+ result
+ end
- if result[:stacked]
- result[:stacked].each do |value|
- param = value.split('=', 2)
- result[:stacked_parameters][param[0]] = param[1]
- end
- end
+ # Default to all attributes.
+ def search_attributes
+ ldapattrs = Puppet[:ldapattrs]
- if result[:stacked_parameters]
- result[:stacked_parameters].each do |param, value|
- result[:parameters][param] = value unless result[:parameters].include?(param)
- end
- end
+ # results in everything getting returned
+ return nil if ldapattrs == "all"
- result[:parameters] = convert_parameters(result[:parameters])
+ search_attrs = class_attributes + ldapattrs.split(/\s*,\s*/)
- result
+ if pattr = parent_attribute
+ search_attrs << pattr
end
- # Default to all attributes.
- def search_attributes
- ldapattrs = Puppet[:ldapattrs]
-
- # results in everything getting returned
- return nil if ldapattrs == "all"
+ search_attrs
+ end
- search_attrs = class_attributes + ldapattrs.split(/\s*,\s*/)
+ # The ldap search filter to use.
+ def search_filter(name)
+ filter = Puppet[:ldapstring]
- if pattr = parent_attribute
- search_attrs << pattr
- end
-
- search_attrs
+ if filter.include? "%s"
+ # Don't replace the string in-line, since that would hard-code our node
+ # info.
+ filter = filter.gsub('%s', name)
end
-
- # The ldap search filter to use.
- def search_filter(name)
- filter = Puppet[:ldapstring]
-
- if filter.include? "%s"
- # Don't replace the string in-line, since that would hard-code our node
- # info.
- filter = filter.gsub('%s', name)
- end
- filter
+ filter
+ end
+
+ private
+
+ # Add our hash of ldap information to the node instance.
+ def add_to_node(node, information)
+ node.classes = information[:classes].uniq unless information[:classes].nil? or information[:classes].empty?
+ node.parameters = information[:parameters] unless information[:parameters].nil? or information[:parameters].empty?
+ node.environment = information[:environment] if information[:environment]
+ end
+
+ def convert_parameters(parameters)
+ result = {}
+ parameters.each do |param, value|
+ if value.is_a?(Array)
+ result[param] = value.collect { |v| convert(v) }
+ else
+ result[param] = convert(value)
+ end
end
+ result
+ end
+
+ # Convert any values if necessary.
+ def convert(value)
+ case value
+ when Integer, Fixnum, Bignum; value
+ when "true"; true
+ when "false"; false
+ else
+ value
+ end
+ end
- private
+ # Find information for our parent and merge it into the current info.
+ def find_and_merge_parent(parent, information)
- # Add our hash of ldap information to the node instance.
- def add_to_node(node, information)
- node.classes = information[:classes].uniq unless information[:classes].nil? or information[:classes].empty?
- node.parameters = information[:parameters] unless information[:parameters].nil? or information[:parameters].empty?
- node.environment = information[:environment] if information[:environment]
+ if information[:environment]
+ name_env = information[:environment]
+ else
+ name_env = 'production'
end
- def convert_parameters(parameters)
- result = {}
- parameters.each do |param, value|
- if value.is_a?(Array)
- result[param] = value.collect { |v| convert(v) }
- else
- result[param] = convert(value)
- end
- end
- result
+ parent_info = name2hash(parent,name_env,'parent')
+ if parent_info
+ information[:classes] += parent_info[:classes]
+ parent_info[:parameters].each do |param, value|
+ # Specifically test for whether it's set, so false values are handled
+ # correctly.
+ information[:parameters][param] = value unless information[:parameters].include?(param)
end
- # Convert any values if necessary.
- def convert(value)
- case value
- when Integer, Fixnum, Bignum; value
- when "true"; true
- when "false"; false
- else
- value
- end
+ information[:environment] ||= parent_info[:environment]
+ parent_info[:parent]
+ else
+ raise Puppet::Error.new("Could not find parent node '#{parent}'")
+ nil
end
- # Find information for our parent and merge it into the current info.
- def find_and_merge_parent(parent, information)
+ end
- if information[:environment]
- name_env = information[:environment]
- else
- name_env = 'production'
- end
-
- parent_info = name2hash(parent,name_env,'parent')
- if parent_info
- information[:classes] += parent_info[:classes]
- parent_info[:parameters].each do |param, value|
- # Specifically test for whether it's set, so false values are handled
- # correctly.
- information[:parameters][param] = value unless information[:parameters].include?(param)
- end
-
- information[:environment] ||= parent_info[:environment]
- parent_info[:parent]
- else
- raise Puppet::Error.new("Could not find parent node '#{parent}'")
- nil
- end
+ # Take a name and a hash, and return a node instance.
+ def info2node(name, info)
+ merge_parent(info) if info[:parent]
- end
+ node = Puppet::Node.new(name)
- # Take a name and a hash, and return a node instance.
- def info2node(name, info)
- merge_parent(info) if info[:parent]
+ add_to_node(node, info)
- node = Puppet::Node.new(name)
+ node.fact_merge
- add_to_node(node, info)
+ node
+ end
- node.fact_merge
+ def merge_parent(info)
+ parent_info = nil
+ parent = info[:parent]
- node
+ # Preload the parent array with the node name.
+ parents = [info[:name]]
+ while parent
+ raise ArgumentError, "Found loop in LDAP node parents; #{parent} appears twice" if parents.include?(parent)
+ parents << parent
+ parent = find_and_merge_parent(parent, info)
end
- def merge_parent(info)
- parent_info = nil
- parent = info[:parent]
-
- # Preload the parent array with the node name.
- parents = [info[:name]]
- while parent
- raise ArgumentError, "Found loop in LDAP node parents; #{parent} appears twice" if parents.include?(parent)
- parents << parent
- parent = find_and_merge_parent(parent, info)
- end
-
- info
- end
+ info
+ end
- def get_classes_from_entry(entry)
- result = class_attributes.inject([]) do |array, attr|
- if values = entry.vals(attr)
- values.each do |v| array << v end
- end
- array
- end
- result.uniq
+ def get_classes_from_entry(entry)
+ result = class_attributes.inject([]) do |array, attr|
+ if values = entry.vals(attr)
+ values.each do |v| array << v end
+ end
+ array
end
-
- def get_parameters_from_entry(entry)
- stacked_params = stacked_attributes
- entry.to_hash.inject({}) do |hash, ary|
- unless stacked_params.include?(ary[0]) # don't add our stacked parameters to the main param list
- if ary[1].length == 1
- hash[ary[0]] = ary[1].shift
- else
- hash[ary[0]] = ary[1]
- end
- end
- hash
+ result.uniq
+ end
+
+ def get_parameters_from_entry(entry)
+ stacked_params = stacked_attributes
+ entry.to_hash.inject({}) do |hash, ary|
+ unless stacked_params.include?(ary[0]) # don't add our stacked parameters to the main param list
+ if ary[1].length == 1
+ hash[ary[0]] = ary[1].shift
+ else
+ hash[ary[0]] = ary[1]
end
+ end
+ hash
end
+ end
- def get_parent_from_entry(entry)
- pattr = parent_attribute
+ def get_parent_from_entry(entry)
+ pattr = parent_attribute
- return nil unless values = entry.vals(pattr)
+ return nil unless values = entry.vals(pattr)
- if values.length > 1
- raise Puppet::Error,
- "Node entry #{entry.dn} specifies more than one parent: #{values.inspect}"
- end
- return(values.empty? ? nil : values.shift)
+ if values.length > 1
+ raise Puppet::Error,
+ "Node entry #{entry.dn} specifies more than one parent: #{values.inspect}"
end
-
- def get_stacked_values_from_entry(entry)
- stacked_attributes.inject([]) do |result, attr|
- if values = entry.vals(attr)
- result += values
- end
- result
- end
+ return(values.empty? ? nil : values.shift)
+ end
+
+ def get_stacked_values_from_entry(entry)
+ stacked_attributes.inject([]) do |result, attr|
+ if values = entry.vals(attr)
+ result += values
+ end
+ result
end
+ end
end
diff --git a/lib/puppet/indirector/node/memory.rb b/lib/puppet/indirector/node/memory.rb
index de0ed8ab2..ce4a52a8f 100644
--- a/lib/puppet/indirector/node/memory.rb
+++ b/lib/puppet/indirector/node/memory.rb
@@ -2,9 +2,9 @@ require 'puppet/node'
require 'puppet/indirector/memory'
class Puppet::Node::Memory < Puppet::Indirector::Memory
- desc "Keep track of nodes in memory but nowhere else. This is used for
- one-time compiles, such as what the stand-alone ``puppet`` does.
- To use this terminus, you must load it with the data you want it
- to contain; it is only useful for developers and should generally not
- be chosen by a normal user."
+ desc "Keep track of nodes in memory but nowhere else. This is used for
+ one-time compiles, such as what the stand-alone ``puppet`` does.
+ To use this terminus, you must load it with the data you want it
+ to contain; it is only useful for developers and should generally not
+ be chosen by a normal user."
end
diff --git a/lib/puppet/indirector/node/plain.rb b/lib/puppet/indirector/node/plain.rb
index 37ceb064d..d648cce8d 100644
--- a/lib/puppet/indirector/node/plain.rb
+++ b/lib/puppet/indirector/node/plain.rb
@@ -2,18 +2,18 @@ require 'puppet/node'
require 'puppet/indirector/plain'
class Puppet::Node::Plain < Puppet::Indirector::Plain
- desc "Always return an empty node object. Assumes you keep track of nodes
- in flat file manifests. You should use it when you don't have some other,
- functional source you want to use, as the compiler will not work without a
- valid node terminus.
+ desc "Always return an empty node object. Assumes you keep track of nodes
+ in flat file manifests. You should use it when you don't have some other,
+ functional source you want to use, as the compiler will not work without a
+ valid node terminus.
- Note that class is responsible for merging the node's facts into the
- node instance before it is returned."
+ Note that class is responsible for merging the node's facts into the
+ node instance before it is returned."
- # Just return an empty node.
- def find(request)
- node = super
- node.fact_merge
- node
- end
+ # Just return an empty node.
+ def find(request)
+ node = super
+ node.fact_merge
+ node
+ end
end
diff --git a/lib/puppet/indirector/node/rest.rb b/lib/puppet/indirector/node/rest.rb
index d8b75f6e7..6aa8025a6 100644
--- a/lib/puppet/indirector/node/rest.rb
+++ b/lib/puppet/indirector/node/rest.rb
@@ -2,6 +2,6 @@ require 'puppet/node'
require 'puppet/indirector/rest'
class Puppet::Node::Rest < Puppet::Indirector::REST
- desc "This will eventually be a REST-based mechanism for finding nodes. It is currently non-functional."
- # TODO/FIXME
+ desc "This will eventually be a REST-based mechanism for finding nodes. It is currently non-functional."
+ # TODO/FIXME
end
diff --git a/lib/puppet/indirector/node/yaml.rb b/lib/puppet/indirector/node/yaml.rb
index f2873479d..5a316b62e 100644
--- a/lib/puppet/indirector/node/yaml.rb
+++ b/lib/puppet/indirector/node/yaml.rb
@@ -2,6 +2,6 @@ require 'puppet/node'
require 'puppet/indirector/yaml'
class Puppet::Node::Yaml < Puppet::Indirector::Yaml
- desc "Store node information as flat files, serialized using YAML,
- or deserialize stored YAML nodes."
+ desc "Store node information as flat files, serialized using YAML,
+ or deserialize stored YAML nodes."
end
diff --git a/lib/puppet/indirector/plain.rb b/lib/puppet/indirector/plain.rb
index 2caa0946d..e11fc68c8 100644
--- a/lib/puppet/indirector/plain.rb
+++ b/lib/puppet/indirector/plain.rb
@@ -2,8 +2,8 @@ require 'puppet/indirector/terminus'
# An empty terminus type, meant to just return empty objects.
class Puppet::Indirector::Plain < Puppet::Indirector::Terminus
- # Just return nothing.
- def find(request)
- indirection.model.new(request.key)
- end
+ # Just return nothing.
+ def find(request)
+ indirection.model.new(request.key)
+ end
end
diff --git a/lib/puppet/indirector/queue.rb b/lib/puppet/indirector/queue.rb
index b831cd658..fd089f431 100644
--- a/lib/puppet/indirector/queue.rb
+++ b/lib/puppet/indirector/queue.rb
@@ -19,63 +19,63 @@ require 'puppet/util'
# client library to handle queue creation as necessary (for a number of popular queuing solutions, queue
# creation is automatic and not a concern).
class Puppet::Indirector::Queue < Puppet::Indirector::Terminus
- extend ::Puppet::Util::Queue
- include Puppet::Util
+ extend ::Puppet::Util::Queue
+ include Puppet::Util
- def initialize(*args)
- super
- raise ArgumentError, "Queueing requires pson support" unless Puppet.features.pson?
- end
+ def initialize(*args)
+ super
+ raise ArgumentError, "Queueing requires pson support" unless Puppet.features.pson?
+ end
- # Queue has no idiomatic "find"
- def find(request)
- nil
- end
+ # Queue has no idiomatic "find"
+ def find(request)
+ nil
+ end
- # Place the request on the queue
- def save(request)
- result = nil
- benchmark :info, "Queued #{indirection.name} for #{request.key}" do
- result = client.send_message(queue, request.instance.render(:pson))
- end
- result
- rescue => detail
- raise Puppet::Error, "Could not write #{request.key} to queue: #{detail}\nInstance::#{request.instance}\n client : #{client}"
- end
+ # Place the request on the queue
+ def save(request)
+ result = nil
+ benchmark :info, "Queued #{indirection.name} for #{request.key}" do
+ result = client.send_message(queue, request.instance.render(:pson))
+ end
+ result
+ rescue => detail
+ raise Puppet::Error, "Could not write #{request.key} to queue: #{detail}\nInstance::#{request.instance}\n client : #{client}"
+ end
- def self.queue
- indirection_name
- end
+ def self.queue
+ indirection_name
+ end
- def queue
- self.class.queue
- end
+ def queue
+ self.class.queue
+ end
- # Returns the singleton queue client object.
- def client
- self.class.client
- end
+ # Returns the singleton queue client object.
+ def client
+ self.class.client
+ end
- # converts the _message_ from deserialized format to an actual model instance.
- def self.intern(message)
- result = nil
- benchmark :info, "Loaded queued #{indirection.name}" do
- result = model.convert_from(:pson, message)
- end
- result
+ # converts the _message_ from deserialized format to an actual model instance.
+ def self.intern(message)
+ result = nil
+ benchmark :info, "Loaded queued #{indirection.name}" do
+ result = model.convert_from(:pson, message)
end
+ result
+ end
- # Provides queue subscription functionality; for a given indirection, use this method on the terminus
- # to subscribe to the indirection-specific queue. Your _block_ will be executed per new indirection
- # model received from the queue, with _obj_ being the model instance.
- def self.subscribe
- client.subscribe(queue) do |msg|
- begin
- yield(self.intern(msg))
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Error occured with subscription to queue #{queue} for indirection #{indirection_name}: #{detail}"
- end
- end
+ # Provides queue subscription functionality; for a given indirection, use this method on the terminus
+ # to subscribe to the indirection-specific queue. Your _block_ will be executed per new indirection
+ # model received from the queue, with _obj_ being the model instance.
+ def self.subscribe
+ client.subscribe(queue) do |msg|
+ begin
+ yield(self.intern(msg))
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Error occured with subscription to queue #{queue} for indirection #{indirection_name}: #{detail}"
+ end
end
+ end
end
diff --git a/lib/puppet/indirector/report/processor.rb b/lib/puppet/indirector/report/processor.rb
index 2f8e9f3c1..88fe4b487 100644
--- a/lib/puppet/indirector/report/processor.rb
+++ b/lib/puppet/indirector/report/processor.rb
@@ -3,46 +3,46 @@ require 'puppet/indirector/code'
require 'puppet/reports'
class Puppet::Transaction::Report::Processor < Puppet::Indirector::Code
- desc "Puppet's report processor. Processes the report with each of
- the report types listed in the 'reports' setting."
+ desc "Puppet's report processor. Processes the report with each of
+ the report types listed in the 'reports' setting."
- def initialize
- Puppet.settings.use(:main, :reporting, :metrics)
- end
+ def initialize
+ Puppet.settings.use(:main, :reporting, :metrics)
+ end
- def save(request)
- process(request.instance)
- end
+ def save(request)
+ process(request.instance)
+ end
- private
+ private
- # Process the report with each of the configured report types.
- # LAK:NOTE This isn't necessarily the best design, but it's backward
- # compatible and that's good enough for now.
- def process(report)
- return if Puppet[:reports] == "none"
+ # Process the report with each of the configured report types.
+ # LAK:NOTE This isn't necessarily the best design, but it's backward
+ # compatible and that's good enough for now.
+ def process(report)
+ return if Puppet[:reports] == "none"
- reports.each do |name|
- if mod = Puppet::Reports.report(name)
- # We have to use a dup because we're including a module in the
- # report.
- newrep = report.dup
- begin
- newrep.extend(mod)
- newrep.process
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Report #{name} failed: #{detail}"
- end
- else
- Puppet.warning "No report named '#{name}'"
- end
+ reports.each do |name|
+ if mod = Puppet::Reports.report(name)
+ # We have to use a dup because we're including a module in the
+ # report.
+ newrep = report.dup
+ begin
+ newrep.extend(mod)
+ newrep.process
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Report #{name} failed: #{detail}"
end
+ else
+ Puppet.warning "No report named '#{name}'"
+ end
end
+ end
- # Handle the parsing of the reports attribute.
- def reports
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
- end
+ # Handle the parsing of the reports attribute.
+ def reports
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
+ end
end
diff --git a/lib/puppet/indirector/report/rest.rb b/lib/puppet/indirector/report/rest.rb
index f92d1edd3..601da9edb 100644
--- a/lib/puppet/indirector/report/rest.rb
+++ b/lib/puppet/indirector/report/rest.rb
@@ -1,7 +1,7 @@
require 'puppet/indirector/rest'
class Puppet::Transaction::Report::Rest < Puppet::Indirector::REST
- desc "Get server report over HTTP via REST."
- use_server_setting(:report_server)
- use_port_setting(:report_port)
+ desc "Get server report over HTTP via REST."
+ use_server_setting(:report_server)
+ use_port_setting(:report_port)
end
diff --git a/lib/puppet/indirector/request.rb b/lib/puppet/indirector/request.rb
index 759b44211..fd8d654dd 100644
--- a/lib/puppet/indirector/request.rb
+++ b/lib/puppet/indirector/request.rb
@@ -6,194 +6,194 @@ require 'puppet/indirector'
# Indirection call, and as a a result also handles REST calls. It's somewhat
# analogous to an HTTP Request object, except tuned for our Indirector.
class Puppet::Indirector::Request
- attr_accessor :key, :method, :options, :instance, :node, :ip, :authenticated, :ignore_cache, :ignore_terminus
+ attr_accessor :key, :method, :options, :instance, :node, :ip, :authenticated, :ignore_cache, :ignore_terminus
- attr_accessor :server, :port, :uri, :protocol
+ attr_accessor :server, :port, :uri, :protocol
- attr_reader :indirection_name
+ attr_reader :indirection_name
- OPTION_ATTRIBUTES = [:ip, :node, :authenticated, :ignore_terminus, :ignore_cache, :instance, :environment]
+ OPTION_ATTRIBUTES = [:ip, :node, :authenticated, :ignore_terminus, :ignore_cache, :instance, :environment]
- # Is this an authenticated request?
- def authenticated?
- # Double negative, so we just get true or false
- ! ! authenticated
- end
-
- def environment
- @environment ||= Puppet::Node::Environment.new
- end
+ # Is this an authenticated request?
+ def authenticated?
+ # Double negative, so we just get true or false
+ ! ! authenticated
+ end
- def environment=(env)
- @environment = if env.is_a?(Puppet::Node::Environment)
- env
- else
- Puppet::Node::Environment.new(env)
- end
- end
+ def environment
+ @environment ||= Puppet::Node::Environment.new
+ end
+
+ def environment=(env)
+ @environment = if env.is_a?(Puppet::Node::Environment)
+ env
+ else
+ Puppet::Node::Environment.new(env)
+ end
+ end
+
+ def escaped_key
+ URI.escape(key)
+ end
+
+ # LAK:NOTE This is a messy interface to the cache, and it's only
+ # used by the Configurer class. I decided it was better to implement
+ # it now and refactor later, when we have a better design, than
+ # to spend another month coming up with a design now that might
+ # not be any better.
+ def ignore_cache?
+ ignore_cache
+ end
+
+ def ignore_terminus?
+ ignore_terminus
+ end
+
+ def initialize(indirection_name, method, key_or_instance, options_or_instance = {})
+ if options_or_instance.is_a? Hash
+ options = options_or_instance
+ @instance = nil
+ else
+ options = {}
+ @instance = options_or_instance
+ end
+
+ self.indirection_name = indirection_name
+ self.method = method
+
+ set_attributes(options)
+
+ @options = options.inject({}) { |hash, ary| hash[ary[0].to_sym] = ary[1]; hash }
+
+ if key_or_instance.is_a?(String) || key_or_instance.is_a?(Symbol)
+ key = key_or_instance
+ else
+ @instance ||= key_or_instance
+ end
+
+ if key
+ # If the request key is a URI, then we need to treat it specially,
+ # because it rewrites the key. We could otherwise strip server/port/etc
+ # info out in the REST class, but it seemed bad design for the REST
+ # class to rewrite the key.
+ if key.to_s =~ /^\w+:\/\// # it's a URI
+ set_uri_key(key)
+ else
+ @key = key
+ end
+ end
+
+ @key = @instance.name if ! @key and @instance
+ end
+
+ # Look up the indirection based on the name provided.
+ def indirection
+ Puppet::Indirector::Indirection.instance(indirection_name)
+ end
- def escaped_key
- URI.escape(key)
- end
+ def indirection_name=(name)
+ @indirection_name = name.to_sym
+ end
- # LAK:NOTE This is a messy interface to the cache, and it's only
- # used by the Configurer class. I decided it was better to implement
- # it now and refactor later, when we have a better design, than
- # to spend another month coming up with a design now that might
- # not be any better.
- def ignore_cache?
- ignore_cache
- end
- def ignore_terminus?
- ignore_terminus
- end
-
- def initialize(indirection_name, method, key_or_instance, options_or_instance = {})
- if options_or_instance.is_a? Hash
- options = options_or_instance
- @instance = nil
- else
- options = {}
- @instance = options_or_instance
- end
-
- self.indirection_name = indirection_name
- self.method = method
-
- set_attributes(options)
-
- @options = options.inject({}) { |hash, ary| hash[ary[0].to_sym] = ary[1]; hash }
-
- if key_or_instance.is_a?(String) || key_or_instance.is_a?(Symbol)
- key = key_or_instance
- else
- @instance ||= key_or_instance
- end
-
- if key
- # If the request key is a URI, then we need to treat it specially,
- # because it rewrites the key. We could otherwise strip server/port/etc
- # info out in the REST class, but it seemed bad design for the REST
- # class to rewrite the key.
- if key.to_s =~ /^\w+:\/\// # it's a URI
- set_uri_key(key)
- else
- @key = key
- end
- end
-
- @key = @instance.name if ! @key and @instance
- end
-
- # Look up the indirection based on the name provided.
- def indirection
- Puppet::Indirector::Indirection.instance(indirection_name)
- end
+ def model
+ raise ArgumentError, "Could not find indirection '#{indirection_name}'" unless i = indirection
+ i.model
+ end
- def indirection_name=(name)
- @indirection_name = name.to_sym
+ # Should we allow use of the cached object?
+ def use_cache?
+ if defined?(@use_cache)
+ ! ! use_cache
+ else
+ true
end
+ end
+ # Are we trying to interact with multiple resources, or just one?
+ def plural?
+ method == :search
+ end
+
+ # Create the query string, if options are present.
+ def query_string
+ return "" unless options and ! options.empty?
+ "?" + options.collect do |key, value|
+ case value
+ when nil; next
+ when true, false; value = value.to_s
+ when Fixnum, Bignum, Float; value = value # nothing
+ when String; value = CGI.escape(value)
+ when Symbol; value = CGI.escape(value.to_s)
+ when Array; value = CGI.escape(YAML.dump(value))
+ else
+ raise ArgumentError, "HTTP REST queries cannot handle values of type '#{value.class}'"
+ end
- def model
- raise ArgumentError, "Could not find indirection '#{indirection_name}'" unless i = indirection
- i.model
+ "#{key}=#{value}"
+ end.join("&")
+ end
+
+ def to_hash
+ result = options.dup
+
+ OPTION_ATTRIBUTES.each do |attribute|
+ if value = send(attribute)
+ result[attribute] = value
+ end
end
+ result
+ end
- # Should we allow use of the cached object?
- def use_cache?
- if defined?(@use_cache)
- ! ! use_cache
- else
- true
- end
- end
-
- # Are we trying to interact with multiple resources, or just one?
- def plural?
- method == :search
- end
-
- # Create the query string, if options are present.
- def query_string
- return "" unless options and ! options.empty?
- "?" + options.collect do |key, value|
- case value
- when nil; next
- when true, false; value = value.to_s
- when Fixnum, Bignum, Float; value = value # nothing
- when String; value = CGI.escape(value)
- when Symbol; value = CGI.escape(value.to_s)
- when Array; value = CGI.escape(YAML.dump(value))
- else
- raise ArgumentError, "HTTP REST queries cannot handle values of type '#{value.class}'"
- end
-
- "#{key}=#{value}"
- end.join("&")
- end
-
- def to_hash
- result = options.dup
-
- OPTION_ATTRIBUTES.each do |attribute|
- if value = send(attribute)
- result[attribute] = value
- end
- end
- result
- end
-
- def to_s
- return(uri ? uri : "/#{indirection_name}/#{key}")
- end
+ def to_s
+ return(uri ? uri : "/#{indirection_name}/#{key}")
+ end
- private
+ private
- def set_attributes(options)
- OPTION_ATTRIBUTES.each do |attribute|
- if options.include?(attribute)
- send(attribute.to_s + "=", options[attribute])
- options.delete(attribute)
- end
- end
+ def set_attributes(options)
+ OPTION_ATTRIBUTES.each do |attribute|
+ if options.include?(attribute)
+ send(attribute.to_s + "=", options[attribute])
+ options.delete(attribute)
+ end
end
+ end
- # Parse the key as a URI, setting attributes appropriately.
- def set_uri_key(key)
- @uri = key
- begin
- uri = URI.parse(URI.escape(key))
- rescue => detail
- raise ArgumentError, "Could not understand URL #{key}: #{detail}"
- end
-
- # Just short-circuit these to full paths
- if uri.scheme == "file"
- @key = URI.unescape(uri.path)
- return
- end
-
- @server = uri.host if uri.host
-
- # If the URI class can look up the scheme, it will provide a port,
- # otherwise it will default to '0'.
- if uri.port.to_i == 0 and uri.scheme == "puppet"
- @port = Puppet.settings[:masterport].to_i
- else
- @port = uri.port.to_i
- end
-
- @protocol = uri.scheme
-
- if uri.scheme == 'puppet'
- @key = URI.unescape(uri.path.sub(/^\//, ''))
- return
- end
-
- env, indirector, @key = URI.unescape(uri.path.sub(/^\//, '')).split('/',3)
- @key ||= ''
- self.environment = env unless env == ''
+ # Parse the key as a URI, setting attributes appropriately.
+ def set_uri_key(key)
+ @uri = key
+ begin
+ uri = URI.parse(URI.escape(key))
+ rescue => detail
+ raise ArgumentError, "Could not understand URL #{key}: #{detail}"
+ end
+
+ # Just short-circuit these to full paths
+ if uri.scheme == "file"
+ @key = URI.unescape(uri.path)
+ return
+ end
+
+ @server = uri.host if uri.host
+
+ # If the URI class can look up the scheme, it will provide a port,
+ # otherwise it will default to '0'.
+ if uri.port.to_i == 0 and uri.scheme == "puppet"
+ @port = Puppet.settings[:masterport].to_i
+ else
+ @port = uri.port.to_i
+ end
+
+ @protocol = uri.scheme
+
+ if uri.scheme == 'puppet'
+ @key = URI.unescape(uri.path.sub(/^\//, ''))
+ return
end
+
+ env, indirector, @key = URI.unescape(uri.path.sub(/^\//, '')).split('/',3)
+ @key ||= ''
+ self.environment = env unless env == ''
+ end
end
diff --git a/lib/puppet/indirector/resource/ral.rb b/lib/puppet/indirector/resource/ral.rb
index 7a97fcc58..1c2ab14ae 100644
--- a/lib/puppet/indirector/resource/ral.rb
+++ b/lib/puppet/indirector/resource/ral.rb
@@ -1,48 +1,48 @@
class Puppet::Resource::Ral < Puppet::Indirector::Code
- def find( request )
- # find by name
- res = type(request).instances.find { |o| o.name == resource_name(request) }
- res ||= type(request).new(:name => resource_name(request), :audit => type(request).properties.collect { |s| s.name })
-
- res.to_resource
+ def find( request )
+ # find by name
+ res = type(request).instances.find { |o| o.name == resource_name(request) }
+ res ||= type(request).new(:name => resource_name(request), :audit => type(request).properties.collect { |s| s.name })
+
+ res.to_resource
+ end
+
+ def search( request )
+ conditions = request.options.dup
+ conditions[:name] = resource_name(request) if resource_name(request)
+
+ type(request).instances.map do |res|
+ res.to_resource
+ end.find_all do |res|
+ conditions.all? {|property, value| res.to_resource[property].to_s == value.to_s}
+ end.sort do |a,b|
+ a.title <=> b.title
end
+ end
- def search( request )
- conditions = request.options.dup
- conditions[:name] = resource_name(request) if resource_name(request)
-
- type(request).instances.map do |res|
- res.to_resource
- end.find_all do |res|
- conditions.all? {|property, value| res.to_resource[property].to_s == value.to_s}
- end.sort do |a,b|
- a.title <=> b.title
- end
- end
+ def save( request )
+ # In RAL-land, to "save" means to actually try to change machine state
+ res = request.instance
+ ral_res = res.to_ral
- def save( request )
- # In RAL-land, to "save" means to actually try to change machine state
- res = request.instance
- ral_res = res.to_ral
+ catalog = Puppet::Resource::Catalog.new
+ catalog.add_resource ral_res
+ catalog.apply
- catalog = Puppet::Resource::Catalog.new
- catalog.add_resource ral_res
- catalog.apply
+ ral_res.to_resource
+ end
- ral_res.to_resource
- end
+ private
- private
+ def type_name( request )
+ request.key.split('/')[0]
+ end
- def type_name( request )
- request.key.split('/')[0]
- end
+ def resource_name( request )
+ request.key.split('/')[1]
+ end
- def resource_name( request )
- request.key.split('/')[1]
- end
-
- def type( request )
- Puppet::Type.type(type_name(request)) or raise Puppet::Error, "Could not find type #{type}"
- end
+ def type( request )
+ Puppet::Type.type(type_name(request)) or raise Puppet::Error, "Could not find type #{type}"
+ end
end
diff --git a/lib/puppet/indirector/resource_type/parser.rb b/lib/puppet/indirector/resource_type/parser.rb
index 81ec1bf76..8b1bed0a9 100644
--- a/lib/puppet/indirector/resource_type/parser.rb
+++ b/lib/puppet/indirector/resource_type/parser.rb
@@ -3,25 +3,25 @@ require 'puppet/indirector/code'
require 'puppet/indirector/resource_type'
class Puppet::Indirector::ResourceType::Parser < Puppet::Indirector::Code
- desc "Return the data-form of a resource type."
+ desc "Return the data-form of a resource type."
- def find(request)
- krt = request.environment.known_resource_types
+ def find(request)
+ krt = request.environment.known_resource_types
- # This is a bit ugly.
- [:hostclass, :definition, :node].each do |type|
- if r = krt.send(type, request.key)
- return r
- end
- end
- nil
+ # This is a bit ugly.
+ [:hostclass, :definition, :node].each do |type|
+ if r = krt.send(type, request.key)
+ return r
+ end
end
+ nil
+ end
- def search(request)
- raise ArgumentError, "Only '*' is acceptable as a search request" unless request.key == "*"
- krt = request.environment.known_resource_types
- result = [krt.hostclasses.values, krt.definitions.values, krt.nodes.values].flatten
- return nil if result.empty?
- result
- end
+ def search(request)
+ raise ArgumentError, "Only '*' is acceptable as a search request" unless request.key == "*"
+ krt = request.environment.known_resource_types
+ result = [krt.hostclasses.values, krt.definitions.values, krt.nodes.values].flatten
+ return nil if result.empty?
+ result
+ end
end
diff --git a/lib/puppet/indirector/resource_type/rest.rb b/lib/puppet/indirector/resource_type/rest.rb
index 66d332011..f372ecc87 100644
--- a/lib/puppet/indirector/resource_type/rest.rb
+++ b/lib/puppet/indirector/resource_type/rest.rb
@@ -3,5 +3,5 @@ require 'puppet/indirector/rest'
require 'puppet/indirector/resource_type'
class Puppet::Indirector::ResourceType::Rest < Puppet::Indirector::REST
- desc "Retrieve resource types via a REST HTTP interface."
+ desc "Retrieve resource types via a REST HTTP interface."
end
diff --git a/lib/puppet/indirector/rest.rb b/lib/puppet/indirector/rest.rb
index 127eb7110..eb41ff3b1 100644
--- a/lib/puppet/indirector/rest.rb
+++ b/lib/puppet/indirector/rest.rb
@@ -7,92 +7,92 @@ require 'puppet/network/http/compression'
# Access objects via REST
class Puppet::Indirector::REST < Puppet::Indirector::Terminus
- include Puppet::Network::HTTP::API::V1
- include Puppet::Network::HTTP::Compression.module
-
- class << self
- attr_reader :server_setting, :port_setting
- end
-
- # Specify the setting that we should use to get the server name.
- def self.use_server_setting(setting)
- @server_setting = setting
+ include Puppet::Network::HTTP::API::V1
+ include Puppet::Network::HTTP::Compression.module
+
+ class << self
+ attr_reader :server_setting, :port_setting
+ end
+
+ # Specify the setting that we should use to get the server name.
+ def self.use_server_setting(setting)
+ @server_setting = setting
+ end
+
+ def self.server
+ Puppet.settings[server_setting || :server]
+ end
+
+ # Specify the setting that we should use to get the port.
+ def self.use_port_setting(setting)
+ @port_setting = setting
+ end
+
+ def self.port
+ Puppet.settings[port_setting || :masterport].to_i
+ end
+
+ # Figure out the content type, turn that into a format, and use the format
+ # to extract the body of the response.
+ def deserialize(response, multiple = false)
+ case response.code
+ when "404"
+ return nil
+ when /^2/
+ raise "No content type in http response; cannot parse" unless response['content-type']
+
+ content_type = response['content-type'].gsub(/\s*;.*$/,'') # strip any appended charset
+
+ body = uncompress_body(response)
+
+ # Convert the response to a deserialized object.
+ if multiple
+ model.convert_from_multiple(content_type, body)
+ else
+ model.convert_from(content_type, body)
+ end
+ else
+ # Raise the http error if we didn't get a 'success' of some kind.
+ message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
+ raise Net::HTTPError.new(message, response)
end
-
- def self.server
- Puppet.settings[server_setting || :server]
+ end
+
+ # Provide appropriate headers.
+ def headers
+ add_accept_encoding({"Accept" => model.supported_formats.join(", ")})
+ end
+
+ def network(request)
+ Puppet::Network::HttpPool.http_instance(request.server || self.class.server, request.port || self.class.port)
+ end
+
+ def find(request)
+ return nil unless result = deserialize(network(request).get(indirection2uri(request), headers))
+ result.name = request.key if result.respond_to?(:name=)
+ result
+ end
+
+ def search(request)
+ unless result = deserialize(network(request).get(indirection2uri(request), headers), true)
+ return []
end
+ result
+ end
- # Specify the setting that we should use to get the port.
- def self.use_port_setting(setting)
- @port_setting = setting
- end
+ def destroy(request)
+ raise ArgumentError, "DELETE does not accept options" unless request.options.empty?
+ deserialize network(request).delete(indirection2uri(request), headers)
+ end
- def self.port
- Puppet.settings[port_setting || :masterport].to_i
- end
+ def save(request)
+ raise ArgumentError, "PUT does not accept options" unless request.options.empty?
+ deserialize network(request).put(indirection2uri(request), request.instance.render, headers.merge({ "Content-Type" => request.instance.mime }))
+ end
- # Figure out the content type, turn that into a format, and use the format
- # to extract the body of the response.
- def deserialize(response, multiple = false)
- case response.code
- when "404"
- return nil
- when /^2/
- raise "No content type in http response; cannot parse" unless response['content-type']
-
- content_type = response['content-type'].gsub(/\s*;.*$/,'') # strip any appended charset
-
- body = uncompress_body(response)
-
- # Convert the response to a deserialized object.
- if multiple
- model.convert_from_multiple(content_type, body)
- else
- model.convert_from(content_type, body)
- end
- else
- # Raise the http error if we didn't get a 'success' of some kind.
- message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
- raise Net::HTTPError.new(message, response)
- end
- end
-
- # Provide appropriate headers.
- def headers
- add_accept_encoding({"Accept" => model.supported_formats.join(", ")})
- end
-
- def network(request)
- Puppet::Network::HttpPool.http_instance(request.server || self.class.server, request.port || self.class.port)
- end
+ private
- def find(request)
- return nil unless result = deserialize(network(request).get(indirection2uri(request), headers))
- result.name = request.key if result.respond_to?(:name=)
- result
- end
-
- def search(request)
- unless result = deserialize(network(request).get(indirection2uri(request), headers), true)
- return []
- end
- result
- end
-
- def destroy(request)
- raise ArgumentError, "DELETE does not accept options" unless request.options.empty?
- deserialize network(request).delete(indirection2uri(request), headers)
- end
-
- def save(request)
- raise ArgumentError, "PUT does not accept options" unless request.options.empty?
- deserialize network(request).put(indirection2uri(request), request.instance.render, headers.merge({ "Content-Type" => request.instance.mime }))
- end
-
- private
-
- def environment
- Puppet::Node::Environment.new
- end
+ def environment
+ Puppet::Node::Environment.new
+ end
end
diff --git a/lib/puppet/indirector/run/local.rb b/lib/puppet/indirector/run/local.rb
index 5e8f349ee..8cf65d179 100644
--- a/lib/puppet/indirector/run/local.rb
+++ b/lib/puppet/indirector/run/local.rb
@@ -2,7 +2,7 @@ require 'puppet/run'
require 'puppet/indirector/code'
class Puppet::Run::Local < Puppet::Indirector::Code
- def save( request )
- request.instance.run
- end
+ def save( request )
+ request.instance.run
+ end
end
diff --git a/lib/puppet/indirector/run/rest.rb b/lib/puppet/indirector/run/rest.rb
index 7cf6411f1..cbd34814a 100644
--- a/lib/puppet/indirector/run/rest.rb
+++ b/lib/puppet/indirector/run/rest.rb
@@ -2,5 +2,5 @@ require 'puppet/run'
require 'puppet/indirector/rest'
class Puppet::Run::Rest < Puppet::Indirector::REST
- desc "Trigger Agent runs via REST."
+ desc "Trigger Agent runs via REST."
end
diff --git a/lib/puppet/indirector/ssl_file.rb b/lib/puppet/indirector/ssl_file.rb
index 3aeff3a7a..531180f5b 100644
--- a/lib/puppet/indirector/ssl_file.rb
+++ b/lib/puppet/indirector/ssl_file.rb
@@ -1,171 +1,171 @@
require 'puppet/ssl'
class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus
- # Specify the directory in which multiple files are stored.
- def self.store_in(setting)
- @directory_setting = setting
- end
-
- # Specify a single file location for storing just one file.
- # This is used for things like the CRL.
- def self.store_at(setting)
- @file_setting = setting
- end
-
- # Specify where a specific ca file should be stored.
- def self.store_ca_at(setting)
- @ca_setting = setting
- end
-
- class << self
- attr_reader :directory_setting, :file_setting, :ca_setting
- end
-
- # The full path to where we should store our files.
- def self.collection_directory
- return nil unless directory_setting
- Puppet.settings[directory_setting]
- end
-
- # The full path to an individual file we would be managing.
- def self.file_location
- return nil unless file_setting
- Puppet.settings[file_setting]
- end
-
- # The full path to a ca file we would be managing.
- def self.ca_location
- return nil unless ca_setting
- Puppet.settings[ca_setting]
- end
-
- # We assume that all files named 'ca' are pointing to individual ca files,
- # rather than normal host files. It's a bit hackish, but all the other
- # solutions seemed even more hackish.
- def ca?(name)
- name == Puppet::SSL::Host.ca_name
- end
-
- def initialize
- Puppet.settings.use(:main, :ssl)
-
- (collection_directory || file_location) or raise Puppet::DevError, "No file or directory setting provided; terminus #{self.class.name} cannot function"
- end
-
- # Use a setting to determine our path.
- def path(name)
- if ca?(name) and ca_location
- ca_location
- elsif collection_directory
- File.join(collection_directory, name.to_s + ".pem")
- else
- file_location
- end
- end
-
- # Remove our file.
- def destroy(request)
- path = path(request.key)
- return false unless FileTest.exist?(path)
-
- Puppet.notice "Removing file #{model} #{request.key} at '#{path}'"
- begin
- File.unlink(path)
- rescue => detail
- raise Puppet::Error, "Could not remove #{request.key}: #{detail}"
- end
- end
-
- # Find the file on disk, returning an instance of the model.
- def find(request)
- path = path(request.key)
-
- return nil unless FileTest.exist?(path) or rename_files_with_uppercase(path)
-
- result = model.new(request.key)
- result.read(path)
- result
- end
-
- # Save our file to disk.
- def save(request)
- path = path(request.key)
- dir = File.dirname(path)
-
- raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} does not exist") unless FileTest.directory?(dir)
- raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} is not writable") unless FileTest.writable?(dir)
-
- write(request.key, path) { |f| f.print request.instance.to_s }
- end
-
- # Search for more than one file. At this point, it just returns
- # an instance for every file in the directory.
- def search(request)
- dir = collection_directory
- Dir.entries(dir).reject { |file| file !~ /\.pem$/ }.collect do |file|
- name = file.sub(/\.pem$/, '')
- result = model.new(name)
- result.read(File.join(dir, file))
- result
- end
- end
-
- private
-
- # Demeterish pointers to class info.
- def collection_directory
- self.class.collection_directory
- end
-
- def file_location
- self.class.file_location
- end
-
- def ca_location
- self.class.ca_location
- end
-
- # A hack method to deal with files that exist with a different case.
- # Just renames it; doesn't read it in or anything.
- # LAK:NOTE This is a copy of the method in sslcertificates/support.rb,
- # which we'll be EOL'ing at some point. This method was added at 20080702
- # and should be removed at some point.
- def rename_files_with_uppercase(file)
- dir, short = File.split(file)
- return nil unless FileTest.exist?(dir)
-
- raise ArgumentError, "Tried to fix SSL files to a file containing uppercase" unless short.downcase == short
- real_file = Dir.entries(dir).reject { |f| f =~ /^\./ }.find do |other|
- other.downcase == short
- end
-
- return nil unless real_file
-
- full_file = File.join(dir, real_file)
-
- Puppet.notice "Fixing case in #{full_file}; renaming to #{file}"
- File.rename(full_file, file)
-
- true
- end
-
- # Yield a filehandle set up appropriately, either with our settings doing
- # the work or opening a filehandle manually.
- def write(name, path)
- if ca?(name) and ca_location
- Puppet.settings.write(self.class.ca_setting) { |f| yield f }
- elsif file_location
- Puppet.settings.write(self.class.file_setting) { |f| yield f }
- elsif setting = self.class.directory_setting
- begin
- Puppet.settings.writesub(setting, path) { |f| yield f }
- rescue => detail
- raise Puppet::Error, "Could not write #{path} to #{setting}: #{detail}"
- end
- else
- raise Puppet::DevError, "You must provide a setting to determine where the files are stored"
- end
- end
+ # Specify the directory in which multiple files are stored.
+ def self.store_in(setting)
+ @directory_setting = setting
+ end
+
+ # Specify a single file location for storing just one file.
+ # This is used for things like the CRL.
+ def self.store_at(setting)
+ @file_setting = setting
+ end
+
+ # Specify where a specific ca file should be stored.
+ def self.store_ca_at(setting)
+ @ca_setting = setting
+ end
+
+ class << self
+ attr_reader :directory_setting, :file_setting, :ca_setting
+ end
+
+ # The full path to where we should store our files.
+ def self.collection_directory
+ return nil unless directory_setting
+ Puppet.settings[directory_setting]
+ end
+
+ # The full path to an individual file we would be managing.
+ def self.file_location
+ return nil unless file_setting
+ Puppet.settings[file_setting]
+ end
+
+ # The full path to a ca file we would be managing.
+ def self.ca_location
+ return nil unless ca_setting
+ Puppet.settings[ca_setting]
+ end
+
+ # We assume that all files named 'ca' are pointing to individual ca files,
+ # rather than normal host files. It's a bit hackish, but all the other
+ # solutions seemed even more hackish.
+ def ca?(name)
+ name == Puppet::SSL::Host.ca_name
+ end
+
+ def initialize
+ Puppet.settings.use(:main, :ssl)
+
+ (collection_directory || file_location) or raise Puppet::DevError, "No file or directory setting provided; terminus #{self.class.name} cannot function"
+ end
+
+ # Use a setting to determine our path.
+ def path(name)
+ if ca?(name) and ca_location
+ ca_location
+ elsif collection_directory
+ File.join(collection_directory, name.to_s + ".pem")
+ else
+ file_location
+ end
+ end
+
+ # Remove our file.
+ def destroy(request)
+ path = path(request.key)
+ return false unless FileTest.exist?(path)
+
+ Puppet.notice "Removing file #{model} #{request.key} at '#{path}'"
+ begin
+ File.unlink(path)
+ rescue => detail
+ raise Puppet::Error, "Could not remove #{request.key}: #{detail}"
+ end
+ end
+
+ # Find the file on disk, returning an instance of the model.
+ def find(request)
+ path = path(request.key)
+
+ return nil unless FileTest.exist?(path) or rename_files_with_uppercase(path)
+
+ result = model.new(request.key)
+ result.read(path)
+ result
+ end
+
+ # Save our file to disk.
+ def save(request)
+ path = path(request.key)
+ dir = File.dirname(path)
+
+ raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} does not exist") unless FileTest.directory?(dir)
+ raise Puppet::Error.new("Cannot save #{request.key}; parent directory #{dir} is not writable") unless FileTest.writable?(dir)
+
+ write(request.key, path) { |f| f.print request.instance.to_s }
+ end
+
+ # Search for more than one file. At this point, it just returns
+ # an instance for every file in the directory.
+ def search(request)
+ dir = collection_directory
+ Dir.entries(dir).reject { |file| file !~ /\.pem$/ }.collect do |file|
+ name = file.sub(/\.pem$/, '')
+ result = model.new(name)
+ result.read(File.join(dir, file))
+ result
+ end
+ end
+
+ private
+
+ # Demeterish pointers to class info.
+ def collection_directory
+ self.class.collection_directory
+ end
+
+ def file_location
+ self.class.file_location
+ end
+
+ def ca_location
+ self.class.ca_location
+ end
+
+ # A hack method to deal with files that exist with a different case.
+ # Just renames it; doesn't read it in or anything.
+ # LAK:NOTE This is a copy of the method in sslcertificates/support.rb,
+ # which we'll be EOL'ing at some point. This method was added at 20080702
+ # and should be removed at some point.
+ def rename_files_with_uppercase(file)
+ dir, short = File.split(file)
+ return nil unless FileTest.exist?(dir)
+
+ raise ArgumentError, "Tried to fix SSL files to a file containing uppercase" unless short.downcase == short
+ real_file = Dir.entries(dir).reject { |f| f =~ /^\./ }.find do |other|
+ other.downcase == short
+ end
+
+ return nil unless real_file
+
+ full_file = File.join(dir, real_file)
+
+ Puppet.notice "Fixing case in #{full_file}; renaming to #{file}"
+ File.rename(full_file, file)
+
+ true
+ end
+
+ # Yield a filehandle set up appropriately, either with our settings doing
+ # the work or opening a filehandle manually.
+ def write(name, path)
+ if ca?(name) and ca_location
+ Puppet.settings.write(self.class.ca_setting) { |f| yield f }
+ elsif file_location
+ Puppet.settings.write(self.class.file_setting) { |f| yield f }
+ elsif setting = self.class.directory_setting
+ begin
+ Puppet.settings.writesub(setting, path) { |f| yield f }
+ rescue => detail
+ raise Puppet::Error, "Could not write #{path} to #{setting}: #{detail}"
+ end
+ else
+ raise Puppet::DevError, "You must provide a setting to determine where the files are stored"
+ end
+ end
end
# LAK:NOTE This has to be at the end, because classes like SSL::Key use this
diff --git a/lib/puppet/indirector/status/local.rb b/lib/puppet/indirector/status/local.rb
index f9a7fc578..9951f7e22 100644
--- a/lib/puppet/indirector/status/local.rb
+++ b/lib/puppet/indirector/status/local.rb
@@ -1,7 +1,7 @@
require 'puppet/indirector/status'
class Puppet::Indirector::Status::Local < Puppet::Indirector::Code
- def find( *anything )
- model.new
- end
+ def find( *anything )
+ model.new
+ end
end
diff --git a/lib/puppet/indirector/terminus.rb b/lib/puppet/indirector/terminus.rb
index 546f83524..4ebd0d004 100644
--- a/lib/puppet/indirector/terminus.rb
+++ b/lib/puppet/indirector/terminus.rb
@@ -4,145 +4,145 @@ require 'puppet/util/instance_loader'
# A simple class that can function as the base class for indirected types.
class Puppet::Indirector::Terminus
- require 'puppet/util/docs'
- extend Puppet::Util::Docs
-
- class << self
- include Puppet::Util::InstanceLoader
-
- attr_accessor :name, :terminus_type
- attr_reader :abstract_terminus, :indirection
-
- # Are we an abstract terminus type, rather than an instance with an
- # associated indirection?
- def abstract_terminus?
- abstract_terminus
- end
-
- # Convert a constant to a short name.
- def const2name(const)
- const.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_#{i.downcase}" }.intern
- end
-
- # Look up the indirection if we were only provided a name.
- def indirection=(name)
- if name.is_a?(Puppet::Indirector::Indirection)
- @indirection = name
- elsif ind = Puppet::Indirector::Indirection.instance(name)
- @indirection = ind
- else
- raise ArgumentError, "Could not find indirection instance #{name} for #{self.name}"
- end
- end
-
- def indirection_name
- @indirection.name
- end
-
- # Register our subclass with the appropriate indirection.
- # This follows the convention that our terminus is named after the
- # indirection.
- def inherited(subclass)
- longname = subclass.to_s
- if longname =~ /#<Class/
- raise Puppet::DevError, "Terminus subclasses must have associated constants"
- end
- names = longname.split("::")
-
- # Convert everything to a lower-case symbol, converting camelcase to underscore word separation.
- name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_#{i.downcase}" }.intern
-
- subclass.name = name
-
- # Short-circuit the abstract types, which are those that directly subclass
- # the Terminus class.
- if self == Puppet::Indirector::Terminus
- subclass.mark_as_abstract_terminus
- return
- end
-
- # Set the terminus type to be the name of the abstract terminus type.
- # Yay, class/instance confusion.
- subclass.terminus_type = self.name
-
- # Our subclass is specifically associated with an indirection.
- raise("Invalid name #{longname}") unless names.length > 0
- indirection_name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_#{i.downcase}" }.intern
-
- if indirection_name == "" or indirection_name.nil?
- raise Puppet::DevError, "Could not discern indirection model from class constant"
- end
-
- # This will throw an exception if the indirection instance cannot be found.
- # Do this last, because it also registers the terminus type with the indirection,
- # which needs the above information.
- subclass.indirection = indirection_name
-
- # And add this instance to the instance hash.
- Puppet::Indirector::Terminus.register_terminus_class(subclass)
- end
-
- # Mark that this instance is abstract.
- def mark_as_abstract_terminus
- @abstract_terminus = true
- end
-
- def model
- indirection.model
- end
-
- # Convert a short name to a constant.
- def name2const(name)
- name.to_s.capitalize.sub(/_(.)/) { |i| $1.upcase }
- end
-
- # Register a class, probably autoloaded.
- def register_terminus_class(klass)
- setup_instance_loading klass.indirection_name
- instance_hash(klass.indirection_name)[klass.name] = klass
- end
-
- # Return a terminus by name, using the autoloader.
- def terminus_class(indirection_name, terminus_type)
- setup_instance_loading indirection_name
- loaded_instance(indirection_name, terminus_type)
- end
-
- # Return all terminus classes for a given indirection.
- def terminus_classes(indirection_name)
- setup_instance_loading indirection_name
-
- # Load them all.
- instance_loader(indirection_name).loadall
-
- # And return the list of names.
- loaded_instances(indirection_name)
- end
-
- private
-
- def setup_instance_loading(type)
- instance_load type, "puppet/indirector/#{type}" unless instance_loading?(type)
- end
+ require 'puppet/util/docs'
+ extend Puppet::Util::Docs
+
+ class << self
+ include Puppet::Util::InstanceLoader
+
+ attr_accessor :name, :terminus_type
+ attr_reader :abstract_terminus, :indirection
+
+ # Are we an abstract terminus type, rather than an instance with an
+ # associated indirection?
+ def abstract_terminus?
+ abstract_terminus
+ end
+
+ # Convert a constant to a short name.
+ def const2name(const)
+ const.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_#{i.downcase}" }.intern
+ end
+
+ # Look up the indirection if we were only provided a name.
+ def indirection=(name)
+ if name.is_a?(Puppet::Indirector::Indirection)
+ @indirection = name
+ elsif ind = Puppet::Indirector::Indirection.instance(name)
+ @indirection = ind
+ else
+ raise ArgumentError, "Could not find indirection instance #{name} for #{self.name}"
+ end
+ end
+
+ def indirection_name
+ @indirection.name
end
- def indirection
- self.class.indirection
+ # Register our subclass with the appropriate indirection.
+ # This follows the convention that our terminus is named after the
+ # indirection.
+ def inherited(subclass)
+ longname = subclass.to_s
+ if longname =~ /#<Class/
+ raise Puppet::DevError, "Terminus subclasses must have associated constants"
+ end
+ names = longname.split("::")
+
+ # Convert everything to a lower-case symbol, converting camelcase to underscore word separation.
+ name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_#{i.downcase}" }.intern
+
+ subclass.name = name
+
+ # Short-circuit the abstract types, which are those that directly subclass
+ # the Terminus class.
+ if self == Puppet::Indirector::Terminus
+ subclass.mark_as_abstract_terminus
+ return
+ end
+
+ # Set the terminus type to be the name of the abstract terminus type.
+ # Yay, class/instance confusion.
+ subclass.terminus_type = self.name
+
+ # Our subclass is specifically associated with an indirection.
+ raise("Invalid name #{longname}") unless names.length > 0
+ indirection_name = names.pop.sub(/^[A-Z]/) { |i| i.downcase }.gsub(/[A-Z]/) { |i| "_#{i.downcase}" }.intern
+
+ if indirection_name == "" or indirection_name.nil?
+ raise Puppet::DevError, "Could not discern indirection model from class constant"
+ end
+
+ # This will throw an exception if the indirection instance cannot be found.
+ # Do this last, because it also registers the terminus type with the indirection,
+ # which needs the above information.
+ subclass.indirection = indirection_name
+
+ # And add this instance to the instance hash.
+ Puppet::Indirector::Terminus.register_terminus_class(subclass)
end
- def initialize
- raise Puppet::DevError, "Cannot create instances of abstract terminus types" if self.class.abstract_terminus?
+ # Mark that this instance is abstract.
+ def mark_as_abstract_terminus
+ @abstract_terminus = true
end
def model
- self.class.model
+ indirection.model
end
- def name
- self.class.name
+ # Convert a short name to a constant.
+ def name2const(name)
+ name.to_s.capitalize.sub(/_(.)/) { |i| $1.upcase }
end
- def terminus_type
- self.class.terminus_type
+ # Register a class, probably autoloaded.
+ def register_terminus_class(klass)
+ setup_instance_loading klass.indirection_name
+ instance_hash(klass.indirection_name)[klass.name] = klass
end
+
+ # Return a terminus by name, using the autoloader.
+ def terminus_class(indirection_name, terminus_type)
+ setup_instance_loading indirection_name
+ loaded_instance(indirection_name, terminus_type)
+ end
+
+ # Return all terminus classes for a given indirection.
+ def terminus_classes(indirection_name)
+ setup_instance_loading indirection_name
+
+ # Load them all.
+ instance_loader(indirection_name).loadall
+
+ # And return the list of names.
+ loaded_instances(indirection_name)
+ end
+
+ private
+
+ def setup_instance_loading(type)
+ instance_load type, "puppet/indirector/#{type}" unless instance_loading?(type)
+ end
+ end
+
+ def indirection
+ self.class.indirection
+ end
+
+ def initialize
+ raise Puppet::DevError, "Cannot create instances of abstract terminus types" if self.class.abstract_terminus?
+ end
+
+ def model
+ self.class.model
+ end
+
+ def name
+ self.class.name
+ end
+
+ def terminus_type
+ self.class.terminus_type
+ end
end
diff --git a/lib/puppet/indirector/yaml.rb b/lib/puppet/indirector/yaml.rb
index 826a8ae9d..c7c053f4b 100644
--- a/lib/puppet/indirector/yaml.rb
+++ b/lib/puppet/indirector/yaml.rb
@@ -3,66 +3,66 @@ require 'puppet/util/file_locking'
# The base class for YAML indirection termini.
class Puppet::Indirector::Yaml < Puppet::Indirector::Terminus
- include Puppet::Util::FileLocking
+ include Puppet::Util::FileLocking
- # Read a given name's file in and convert it from YAML.
- def find(request)
- file = path(request.key)
- return nil unless FileTest.exist?(file)
+ # Read a given name's file in and convert it from YAML.
+ def find(request)
+ file = path(request.key)
+ return nil unless FileTest.exist?(file)
- yaml = nil
- begin
- readlock(file) { |fh| yaml = fh.read }
- rescue => detail
- raise Puppet::Error, "Could not read YAML data for #{indirection.name} #{request.key}: #{detail}"
- end
- begin
- return from_yaml(yaml)
- rescue => detail
- raise Puppet::Error, "Could not parse YAML data for #{indirection.name} #{request.key}: #{detail}"
- end
+ yaml = nil
+ begin
+ readlock(file) { |fh| yaml = fh.read }
+ rescue => detail
+ raise Puppet::Error, "Could not read YAML data for #{indirection.name} #{request.key}: #{detail}"
end
+ begin
+ return from_yaml(yaml)
+ rescue => detail
+ raise Puppet::Error, "Could not parse YAML data for #{indirection.name} #{request.key}: #{detail}"
+ end
+ end
- # Convert our object to YAML and store it to the disk.
- def save(request)
- raise ArgumentError.new("You can only save objects that respond to :name") unless request.instance.respond_to?(:name)
+ # Convert our object to YAML and store it to the disk.
+ def save(request)
+ raise ArgumentError.new("You can only save objects that respond to :name") unless request.instance.respond_to?(:name)
- file = path(request.key)
+ file = path(request.key)
- basedir = File.dirname(file)
+ basedir = File.dirname(file)
- # This is quite likely a bad idea, since we're not managing ownership or modes.
- Dir.mkdir(basedir) unless FileTest.exist?(basedir)
+ # This is quite likely a bad idea, since we're not managing ownership or modes.
+ Dir.mkdir(basedir) unless FileTest.exist?(basedir)
- begin
- writelock(file, 0660) { |f| f.print to_yaml(request.instance) }
- rescue TypeError => detail
- Puppet.err "Could not save #{self.name} #{request.key}: #{detail}"
- end
+ begin
+ writelock(file, 0660) { |f| f.print to_yaml(request.instance) }
+ rescue TypeError => detail
+ Puppet.err "Could not save #{self.name} #{request.key}: #{detail}"
end
+ end
- # Get the yaml directory
- def base
- Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir]
- end
+ # Get the yaml directory
+ def base
+ Puppet.run_mode.master? ? Puppet[:yamldir] : Puppet[:clientyamldir]
+ end
- # Return the path to a given node's file.
- def path(name)
- File.join(base, self.class.indirection_name.to_s, name.to_s + ".yaml")
- end
+ # Return the path to a given node's file.
+ def path(name)
+ File.join(base, self.class.indirection_name.to_s, name.to_s + ".yaml")
+ end
- # Do a glob on the yaml directory, loading each file found
- def search(request)
- Dir.glob(File.join(base, self.class.indirection_name.to_s, request.key)).collect { |f| YAML.load_file(f) }
- end
+ # Do a glob on the yaml directory, loading each file found
+ def search(request)
+ Dir.glob(File.join(base, self.class.indirection_name.to_s, request.key)).collect { |f| YAML.load_file(f) }
+ end
- private
+ private
- def from_yaml(text)
- YAML.load(text)
- end
+ def from_yaml(text)
+ YAML.load(text)
+ end
- def to_yaml(object)
- YAML.dump(object)
- end
+ def to_yaml(object)
+ YAML.dump(object)
+ end
end
diff --git a/lib/puppet/metatype/manager.rb b/lib/puppet/metatype/manager.rb
index 51068f6be..12cbf645c 100644
--- a/lib/puppet/metatype/manager.rb
+++ b/lib/puppet/metatype/manager.rb
@@ -5,143 +5,143 @@ require 'puppet/util/classgen'
# Puppet::Type class, it's just split out here for clarity.
module Puppet::MetaType
module Manager
- include Puppet::Util::ClassGen
-
- # remove all type instances; this is mostly only useful for testing
- def allclear
- @types.each { |name, type|
- type.clear
- }
+ include Puppet::Util::ClassGen
+
+ # remove all type instances; this is mostly only useful for testing
+ def allclear
+ @types.each { |name, type|
+ type.clear
+ }
+ end
+
+ # iterate across all of the subclasses of Type
+ def eachtype
+ @types.each do |name, type|
+ # Only consider types that have names
+ #if ! type.parameters.empty? or ! type.validproperties.empty?
+ yield type
+ #end
end
-
- # iterate across all of the subclasses of Type
- def eachtype
- @types.each do |name, type|
- # Only consider types that have names
- #if ! type.parameters.empty? or ! type.validproperties.empty?
- yield type
- #end
- end
+ end
+
+ # Load all types. Only currently used for documentation.
+ def loadall
+ typeloader.loadall
+ end
+
+ # Define a new type.
+ def newtype(name, options = {}, &block)
+ # Handle backward compatibility
+ unless options.is_a?(Hash)
+ Puppet.warning "Puppet::Type.newtype(#{name}) now expects a hash as the second argument, not #{options.inspect}"
+ options = {:parent => options}
end
- # Load all types. Only currently used for documentation.
- def loadall
- typeloader.loadall
- end
+ # First make sure we don't have a method sitting around
+ name = symbolize(name)
+ newmethod = "new#{name.to_s}"
- # Define a new type.
- def newtype(name, options = {}, &block)
- # Handle backward compatibility
- unless options.is_a?(Hash)
- Puppet.warning "Puppet::Type.newtype(#{name}) now expects a hash as the second argument, not #{options.inspect}"
- options = {:parent => options}
- end
+ # Used for method manipulation.
+ selfobj = singleton_class
- # First make sure we don't have a method sitting around
- name = symbolize(name)
- newmethod = "new#{name.to_s}"
+ @types ||= {}
- # Used for method manipulation.
- selfobj = singleton_class
+ if @types.include?(name)
+ if self.respond_to?(newmethod)
+ # Remove the old newmethod
+ selfobj.send(:remove_method,newmethod)
+ end
+ end
- @types ||= {}
+ options = symbolize_options(options)
- if @types.include?(name)
- if self.respond_to?(newmethod)
- # Remove the old newmethod
- selfobj.send(:remove_method,newmethod)
- end
- end
+ if parent = options[:parent]
+ options.delete(:parent)
+ end
- options = symbolize_options(options)
+ # Then create the class.
- if parent = options[:parent]
- options.delete(:parent)
- end
+ klass = genclass(
+ name,
+ :parent => (parent || Puppet::Type),
+
+ :overwrite => true,
+ :hash => @types,
+ :attributes => options,
+ &block
+ )
+
+ # Now define a "new<type>" method for convenience.
+ if self.respond_to? newmethod
+ # Refuse to overwrite existing methods like 'newparam' or 'newtype'.
+ Puppet.warning "'new#{name.to_s}' method already exists; skipping"
+ else
+ selfobj.send(:define_method, newmethod) do |*args|
+ klass.new(*args)
+ end
+ end
- # Then create the class.
+ # If they've got all the necessary methods defined and they haven't
+ # already added the property, then do so now.
+ klass.ensurable if klass.ensurable? and ! klass.validproperty?(:ensure)
- klass = genclass(
- name,
- :parent => (parent || Puppet::Type),
-
- :overwrite => true,
- :hash => @types,
- :attributes => options,
- &block
- )
-
- # Now define a "new<type>" method for convenience.
- if self.respond_to? newmethod
- # Refuse to overwrite existing methods like 'newparam' or 'newtype'.
- Puppet.warning "'new#{name.to_s}' method already exists; skipping"
- else
- selfobj.send(:define_method, newmethod) do |*args|
- klass.new(*args)
- end
- end
-
- # If they've got all the necessary methods defined and they haven't
- # already added the property, then do so now.
- klass.ensurable if klass.ensurable? and ! klass.validproperty?(:ensure)
-
- # Now set up autoload any providers that might exist for this type.
-
- klass.providerloader = Puppet::Util::Autoload.new(
- klass,
+ # Now set up autoload any providers that might exist for this type.
+
+ klass.providerloader = Puppet::Util::Autoload.new(
+ klass,
- "puppet/provider/#{klass.name.to_s}"
- )
+ "puppet/provider/#{klass.name.to_s}"
+ )
- # We have to load everything so that we can figure out the default type.
- klass.providerloader.loadall
+ # We have to load everything so that we can figure out the default type.
+ klass.providerloader.loadall
- klass
- end
+ klass
+ end
- # Remove an existing defined type. Largely used for testing.
- def rmtype(name)
- # Then create the class.
+ # Remove an existing defined type. Largely used for testing.
+ def rmtype(name)
+ # Then create the class.
- klass = rmclass(
- name,
+ klass = rmclass(
+ name,
- :hash => @types
- )
+ :hash => @types
+ )
- singleton_class.send(:remove_method, "new#{name}") if respond_to?("new#{name}")
- end
+ singleton_class.send(:remove_method, "new#{name}") if respond_to?("new#{name}")
+ end
- # Return a Type instance by name.
- def type(name)
- @types ||= {}
+ # Return a Type instance by name.
+ def type(name)
+ @types ||= {}
- name = name.to_s.downcase.to_sym
+ name = name.to_s.downcase.to_sym
- if t = @types[name]
- return t
- else
- if typeloader.load(name)
- Puppet.warning "Loaded puppet/type/#{name} but no class was created" unless @types.include? name
- end
+ if t = @types[name]
+ return t
+ else
+ if typeloader.load(name)
+ Puppet.warning "Loaded puppet/type/#{name} but no class was created" unless @types.include? name
+ end
- return @types[name]
- end
+ return @types[name]
end
+ end
- # Create a loader for Puppet types.
- def typeloader
- unless defined?(@typeloader)
+ # Create a loader for Puppet types.
+ def typeloader
+ unless defined?(@typeloader)
- @typeloader = Puppet::Util::Autoload.new(
- self,
+ @typeloader = Puppet::Util::Autoload.new(
+ self,
- "puppet/type", :wrap => false
- )
- end
-
- @typeloader
+ "puppet/type", :wrap => false
+ )
end
+
+ @typeloader
+ end
end
end
diff --git a/lib/puppet/module.rb b/lib/puppet/module.rb
index b4184dde5..83561449a 100644
--- a/lib/puppet/module.rb
+++ b/lib/puppet/module.rb
@@ -2,203 +2,203 @@ require 'puppet/util/logging'
# Support for modules
class Puppet::Module
- class Error < Puppet::Error; end
- class MissingModule < Error; end
- class IncompatibleModule < Error; end
- class UnsupportedPlatform < Error; end
- class IncompatiblePlatform < Error; end
- class MissingMetadata < Error; end
- class InvalidName < Error; end
-
- include Puppet::Util::Logging
-
- TEMPLATES = "templates"
- FILES = "files"
- MANIFESTS = "manifests"
- PLUGINS = "plugins"
-
- FILETYPES = [MANIFESTS, FILES, TEMPLATES, PLUGINS]
-
- # Return an array of paths by splitting the +modulepath+ config
- # parameter. Only consider paths that are absolute and existing
- # directories
- def self.modulepath(environment = nil)
- Puppet::Node::Environment.new(environment).modulepath
- end
-
- # Find and return the +module+ that +path+ belongs to. If +path+ is
- # absolute, or if there is no module whose name is the first component
- # of +path+, return +nil+
- def self.find(modname, environment = nil)
- return nil unless modname
- Puppet::Node::Environment.new(environment).module(modname)
- end
-
- attr_reader :name, :environment
- attr_writer :environment
-
- attr_accessor :source, :author, :version, :license, :puppetversion, :summary, :description, :project_page
-
- def has_metadata?
- return false unless metadata_file
-
- FileTest.exist?(metadata_file)
- end
-
- def initialize(name, environment = nil)
- @name = name
-
- assert_validity
-
- if environment.is_a?(Puppet::Node::Environment)
- @environment = environment
- else
- @environment = Puppet::Node::Environment.new(environment)
- end
-
- load_metadata if has_metadata?
-
- validate_puppet_version
- validate_dependencies
- end
+ class Error < Puppet::Error; end
+ class MissingModule < Error; end
+ class IncompatibleModule < Error; end
+ class UnsupportedPlatform < Error; end
+ class IncompatiblePlatform < Error; end
+ class MissingMetadata < Error; end
+ class InvalidName < Error; end
+
+ include Puppet::Util::Logging
+
+ TEMPLATES = "templates"
+ FILES = "files"
+ MANIFESTS = "manifests"
+ PLUGINS = "plugins"
+
+ FILETYPES = [MANIFESTS, FILES, TEMPLATES, PLUGINS]
+
+ # Return an array of paths by splitting the +modulepath+ config
+ # parameter. Only consider paths that are absolute and existing
+ # directories
+ def self.modulepath(environment = nil)
+ Puppet::Node::Environment.new(environment).modulepath
+ end
+
+ # Find and return the +module+ that +path+ belongs to. If +path+ is
+ # absolute, or if there is no module whose name is the first component
+ # of +path+, return +nil+
+ def self.find(modname, environment = nil)
+ return nil unless modname
+ Puppet::Node::Environment.new(environment).module(modname)
+ end
+
+ attr_reader :name, :environment
+ attr_writer :environment
+
+ attr_accessor :source, :author, :version, :license, :puppetversion, :summary, :description, :project_page
+
+ def has_metadata?
+ return false unless metadata_file
+
+ FileTest.exist?(metadata_file)
+ end
+
+ def initialize(name, environment = nil)
+ @name = name
+
+ assert_validity
+
+ if environment.is_a?(Puppet::Node::Environment)
+ @environment = environment
+ else
+ @environment = Puppet::Node::Environment.new(environment)
+ end
+
+ load_metadata if has_metadata?
+
+ validate_puppet_version
+ validate_dependencies
+ end
+
+ FILETYPES.each do |type|
+ # A boolean method to let external callers determine if
+ # we have files of a given type.
+ define_method(type +'?') do
+ return false unless path
+ return false unless FileTest.exist?(subpath(type))
+ return true
+ end
+
+ # A method for returning a given file of a given type.
+ # e.g., file = mod.manifest("my/manifest.pp")
+ #
+ # If the file name is nil, then the base directory for the
+ # file type is passed; this is used for fileserving.
+ define_method(type.to_s.sub(/s$/, '')) do |file|
+ return nil unless path
+
+ # If 'file' is nil then they're asking for the base path.
+ # This is used for things like fileserving.
+ if file
+ full_path = File.join(subpath(type), file)
+ else
+ full_path = subpath(type)
+ end
+
+ return nil unless FileTest.exist?(full_path)
+ return full_path
+ end
+ end
+
+ def exist?
+ ! path.nil?
+ end
+
+ # Find the first 'files' directory. This is used by the XMLRPC fileserver.
+ def file_directory
+ subpath("files")
+ end
+
+ def license_file
+ return @license_file if defined?(@license_file)
+
+ return @license_file = nil unless path
+ @license_file = File.join(path, "License")
+ end
- FILETYPES.each do |type|
- # A boolean method to let external callers determine if
- # we have files of a given type.
- define_method(type +'?') do
- return false unless path
- return false unless FileTest.exist?(subpath(type))
- return true
+ def load_metadata
+ data = PSON.parse File.read(metadata_file)
+ [:source, :author, :version, :license, :puppetversion].each do |attr|
+ unless value = data[attr.to_s]
+ unless attr == :puppetversion
+ raise MissingMetadata, "No #{attr} module metadata provided for #{self.name}"
end
-
- # A method for returning a given file of a given type.
- # e.g., file = mod.manifest("my/manifest.pp")
- #
- # If the file name is nil, then the base directory for the
- # file type is passed; this is used for fileserving.
- define_method(type.to_s.sub(/s$/, '')) do |file|
- return nil unless path
-
- # If 'file' is nil then they're asking for the base path.
- # This is used for things like fileserving.
- if file
- full_path = File.join(subpath(type), file)
- else
- full_path = subpath(type)
- end
-
- return nil unless FileTest.exist?(full_path)
- return full_path
- end
- end
-
- def exist?
- ! path.nil?
- end
-
- # Find the first 'files' directory. This is used by the XMLRPC fileserver.
- def file_directory
- subpath("files")
- end
-
- def license_file
- return @license_file if defined?(@license_file)
-
- return @license_file = nil unless path
- @license_file = File.join(path, "License")
- end
-
- def load_metadata
- data = PSON.parse File.read(metadata_file)
- [:source, :author, :version, :license, :puppetversion].each do |attr|
- unless value = data[attr.to_s]
- unless attr == :puppetversion
- raise MissingMetadata, "No #{attr} module metadata provided for #{self.name}"
- end
- end
- send(attr.to_s + "=", value)
- end
- end
-
- # Return the list of manifests matching the given glob pattern,
- # defaulting to 'init.{pp,rb}' for empty modules.
- def match_manifests(rest)
- pat = File.join(path, MANIFESTS, rest || 'init')
- Dir.
- glob(pat + (File.extname(pat).empty? ? '.{pp,rb}' : '')).
- reject { |f| FileTest.directory?(f) }
- end
-
- def metadata_file
- return @metadata_file if defined?(@metadata_file)
-
- return @metadata_file = nil unless path
- @metadata_file = File.join(path, "metadata.json")
- end
-
- # Find this module in the modulepath.
- def path
- environment.modulepath.collect { |path| File.join(path, name) }.find { |d| FileTest.exist?(d) }
- end
-
- # Find all plugin directories. This is used by the Plugins fileserving mount.
- def plugin_directory
- subpath("plugins")
- end
-
- def requires(name, version = nil)
- @requires ||= []
- @requires << [name, version]
- end
-
- def supports(name, version = nil)
- @supports ||= []
- @supports << [name, version]
- end
-
- def to_s
- result = "Module #{name}"
- result += "(#{path})" if path
- result
- end
-
- def validate_dependencies
- return unless defined?(@requires)
-
- @requires.each do |name, version|
- unless mod = environment.module(name)
- raise MissingModule, "Missing module #{name} required by #{self.name}"
- end
-
- if version and mod.version != version
- raise IncompatibleModule, "Required module #{name} is version #{mod.version} but #{self.name} requires #{version}"
- end
- end
- end
-
- def validate_puppet_version
- return unless puppetversion and puppetversion != Puppet.version
- raise IncompatibleModule, "Module #{self.name} is only compatible with Puppet version #{puppetversion}, not #{Puppet.version}"
- end
-
- private
-
- def subpath(type)
- return File.join(path, type) unless type.to_s == "plugins"
-
- backward_compatible_plugins_dir
- end
-
- def backward_compatible_plugins_dir
- if dir = File.join(path, "plugins") and FileTest.exist?(dir)
- warning "using the deprecated 'plugins' directory for ruby extensions; please move to 'lib'"
- return dir
- else
- return File.join(path, "lib")
- end
- end
-
- def assert_validity
- raise InvalidName, "Invalid module name; module names must be alphanumeric (plus '-'), not '#{name}'" unless name =~ /^[-\w]+$/
- end
+ end
+ send(attr.to_s + "=", value)
+ end
+ end
+
+ # Return the list of manifests matching the given glob pattern,
+ # defaulting to 'init.{pp,rb}' for empty modules.
+ def match_manifests(rest)
+ pat = File.join(path, MANIFESTS, rest || 'init')
+ Dir.
+ glob(pat + (File.extname(pat).empty? ? '.{pp,rb}' : '')).
+ reject { |f| FileTest.directory?(f) }
+ end
+
+ def metadata_file
+ return @metadata_file if defined?(@metadata_file)
+
+ return @metadata_file = nil unless path
+ @metadata_file = File.join(path, "metadata.json")
+ end
+
+ # Find this module in the modulepath.
+ def path
+ environment.modulepath.collect { |path| File.join(path, name) }.find { |d| FileTest.exist?(d) }
+ end
+
+ # Find all plugin directories. This is used by the Plugins fileserving mount.
+ def plugin_directory
+ subpath("plugins")
+ end
+
+ def requires(name, version = nil)
+ @requires ||= []
+ @requires << [name, version]
+ end
+
+ def supports(name, version = nil)
+ @supports ||= []
+ @supports << [name, version]
+ end
+
+ def to_s
+ result = "Module #{name}"
+ result += "(#{path})" if path
+ result
+ end
+
+ def validate_dependencies
+ return unless defined?(@requires)
+
+ @requires.each do |name, version|
+ unless mod = environment.module(name)
+ raise MissingModule, "Missing module #{name} required by #{self.name}"
+ end
+
+ if version and mod.version != version
+ raise IncompatibleModule, "Required module #{name} is version #{mod.version} but #{self.name} requires #{version}"
+ end
+ end
+ end
+
+ def validate_puppet_version
+ return unless puppetversion and puppetversion != Puppet.version
+ raise IncompatibleModule, "Module #{self.name} is only compatible with Puppet version #{puppetversion}, not #{Puppet.version}"
+ end
+
+ private
+
+ def subpath(type)
+ return File.join(path, type) unless type.to_s == "plugins"
+
+ backward_compatible_plugins_dir
+ end
+
+ def backward_compatible_plugins_dir
+ if dir = File.join(path, "plugins") and FileTest.exist?(dir)
+ warning "using the deprecated 'plugins' directory for ruby extensions; please move to 'lib'"
+ return dir
+ else
+ return File.join(path, "lib")
+ end
+ end
+
+ def assert_validity
+ raise InvalidName, "Invalid module name; module names must be alphanumeric (plus '-'), not '#{name}'" unless name =~ /^[-\w]+$/
+ end
end
diff --git a/lib/puppet/network/authconfig.rb b/lib/puppet/network/authconfig.rb
index ba2caa473..4ba89fa71 100644
--- a/lib/puppet/network/authconfig.rb
+++ b/lib/puppet/network/authconfig.rb
@@ -2,171 +2,171 @@ require 'puppet/util/loadedfile'
require 'puppet/network/rights'
module Puppet
- class ConfigurationError < Puppet::Error; end
- class Network::AuthConfig < Puppet::Util::LoadedFile
+ class ConfigurationError < Puppet::Error; end
+ class Network::AuthConfig < Puppet::Util::LoadedFile
- def self.main
- @main ||= self.new
- end
+ def self.main
+ @main ||= self.new
+ end
- # Just proxy the setting methods to our rights stuff
- [:allow, :deny].each do |method|
- define_method(method) do |*args|
- @rights.send(method, *args)
- end
- end
+ # Just proxy the setting methods to our rights stuff
+ [:allow, :deny].each do |method|
+ define_method(method) do |*args|
+ @rights.send(method, *args)
+ end
+ end
- # Here we add a little bit of semantics. They can set auth on a whole
- # namespace or on just a single method in the namespace.
- def allowed?(request)
- name = request.call.intern
- namespace = request.handler.intern
- method = request.method.intern
+ # Here we add a little bit of semantics. They can set auth on a whole
+ # namespace or on just a single method in the namespace.
+ def allowed?(request)
+ name = request.call.intern
+ namespace = request.handler.intern
+ method = request.method.intern
+
+ read
+
+ if @rights.include?(name)
+ return @rights[name].allowed?(request.name, request.ip)
+ elsif @rights.include?(namespace)
+ return @rights[namespace].allowed?(request.name, request.ip)
+ end
+ false
+ end
- read
+ # Does the file exist? Puppetmasterd does not require it, but
+ # puppet agent does.
+ def exists?
+ FileTest.exists?(@file)
+ end
- if @rights.include?(name)
- return @rights[name].allowed?(request.name, request.ip)
- elsif @rights.include?(namespace)
- return @rights[namespace].allowed?(request.name, request.ip)
- end
- false
- end
+ def initialize(file = nil, parsenow = true)
+ @file = file || Puppet[:authconfig]
- # Does the file exist? Puppetmasterd does not require it, but
- # puppet agent does.
- def exists?
- FileTest.exists?(@file)
- end
+ raise Puppet::DevError, "No authconfig file defined" unless @file
+ return unless self.exists?
+ super(@file)
+ @rights = Puppet::Network::Rights.new
+ @configstamp = @configstatted = nil
+ @configtimeout = 60
- def initialize(file = nil, parsenow = true)
- @file = file || Puppet[:authconfig]
+ read if parsenow
+ end
- raise Puppet::DevError, "No authconfig file defined" unless @file
- return unless self.exists?
- super(@file)
- @rights = Puppet::Network::Rights.new
- @configstamp = @configstatted = nil
- @configtimeout = 60
+ # Read the configuration file.
+ def read
+ return unless FileTest.exists?(@file)
- read if parsenow
- end
+ if @configstamp
+ if @configtimeout and @configstatted
+ if Time.now - @configstatted > @configtimeout
+ @configstatted = Time.now
+ tmp = File.stat(@file).ctime
- # Read the configuration file.
- def read
- return unless FileTest.exists?(@file)
-
- if @configstamp
- if @configtimeout and @configstatted
- if Time.now - @configstatted > @configtimeout
- @configstatted = Time.now
- tmp = File.stat(@file).ctime
-
- if tmp == @configstamp
- return
- else
- Puppet.notice "#{tmp} vs #{@configstamp}"
- end
- else
- return
- end
- else
- Puppet.notice "#{@configtimeout} and #{@configstatted}"
- end
+ if tmp == @configstamp
+ return
+ else
+ Puppet.notice "#{tmp} vs #{@configstamp}"
end
-
- parse
-
- @configstamp = File.stat(@file).ctime
- @configstatted = Time.now
+ else
+ return
+ end
+ else
+ Puppet.notice "#{@configtimeout} and #{@configstatted}"
end
+ end
- private
-
- def parse
- newrights = Puppet::Network::Rights.new
- begin
- File.open(@file) { |f|
- right = nil
- count = 1
- f.each { |line|
- case line
- when /^\s*#/ # skip comments
- count += 1
- next
- when /^\s*$/ # skip blank lines
- count += 1
- next
- when /^(?:(\[[\w.]+\])|(path)\s+((?:~\s+)?[^ ]+))\s*$/ # "namespace" or "namespace.method" or "path /path" or "path ~ regex"
- name = $1
- name = $3 if $2 == "path"
- name.chomp!
- right = newrights.newright(name, count, @file)
- when /^\s*(allow|deny|method|environment|auth(?:enticated)?)\s+(.+)$/
- parse_right_directive(right, $1, $2, count)
- else
- raise ConfigurationError, "Invalid line #{count}: #{line}"
- end
- count += 1
- }
- }
- rescue Errno::EACCES => detail
- Puppet.err "Configuration error: Cannot read #{@file}; cannot serve"
- #raise Puppet::Error, "Cannot read #{@config}"
- rescue Errno::ENOENT => detail
- Puppet.err "Configuration error: '#{@file}' does not exit; cannot serve"
- #raise Puppet::Error, "#{@config} does not exit"
- #rescue FileServerError => detail
- # Puppet.err "FileServer error: #{detail}"
- end
+ parse
- # Verify each of the rights are valid.
- # We let the check raise an error, so that it can raise an error
- # pointing to the specific problem.
- newrights.each { |name, right|
- right.valid?
- }
- @rights = newrights
- end
+ @configstamp = File.stat(@file).ctime
+ @configstatted = Time.now
+ end
- def parse_right_directive(right, var, value, count)
- case var
- when "allow"
- modify_right(right, :allow, value, "allowing %s access", count)
- when "deny"
- modify_right(right, :deny, value, "denying %s access", count)
- when "method"
- unless right.acl_type == :regex
- raise ConfigurationError, "'method' directive not allowed in namespace ACL at line #{count} of #{@config}"
- end
- modify_right(right, :restrict_method, value, "allowing 'method' %s", count)
- when "environment"
- unless right.acl_type == :regex
- raise ConfigurationError, "'environment' directive not allowed in namespace ACL at line #{count} of #{@config}"
- end
- modify_right(right, :restrict_environment, value, "adding environment %s", count)
- when /auth(?:enticated)?/
- unless right.acl_type == :regex
- raise ConfigurationError, "'authenticated' directive not allowed in namespace ACL at line #{count} of #{@config}"
- end
- modify_right(right, :restrict_authenticated, value, "adding authentication %s", count)
+ private
+
+ def parse
+ newrights = Puppet::Network::Rights.new
+ begin
+ File.open(@file) { |f|
+ right = nil
+ count = 1
+ f.each { |line|
+ case line
+ when /^\s*#/ # skip comments
+ count += 1
+ next
+ when /^\s*$/ # skip blank lines
+ count += 1
+ next
+ when /^(?:(\[[\w.]+\])|(path)\s+((?:~\s+)?[^ ]+))\s*$/ # "namespace" or "namespace.method" or "path /path" or "path ~ regex"
+ name = $1
+ name = $3 if $2 == "path"
+ name.chomp!
+ right = newrights.newright(name, count, @file)
+ when /^\s*(allow|deny|method|environment|auth(?:enticated)?)\s+(.+)$/
+ parse_right_directive(right, $1, $2, count)
else
- raise ConfigurationError,
- "Invalid argument '#{var}' at line #{count}"
+ raise ConfigurationError, "Invalid line #{count}: #{line}"
end
- end
+ count += 1
+ }
+ }
+ rescue Errno::EACCES => detail
+ Puppet.err "Configuration error: Cannot read #{@file}; cannot serve"
+ #raise Puppet::Error, "Cannot read #{@config}"
+ rescue Errno::ENOENT => detail
+ Puppet.err "Configuration error: '#{@file}' does not exit; cannot serve"
+ #raise Puppet::Error, "#{@config} does not exit"
+ #rescue FileServerError => detail
+ # Puppet.err "FileServer error: #{detail}"
+ end
+
+ # Verify each of the rights are valid.
+ # We let the check raise an error, so that it can raise an error
+ # pointing to the specific problem.
+ newrights.each { |name, right|
+ right.valid?
+ }
+ @rights = newrights
+ end
- def modify_right(right, method, value, msg, count)
- value.split(/\s*,\s*/).each do |val|
- begin
- right.info msg % val
- right.send(method, val)
- rescue AuthStoreError => detail
- raise ConfigurationError, "#{detail} at line #{count} of #{@file}"
- end
- end
+ def parse_right_directive(right, var, value, count)
+ case var
+ when "allow"
+ modify_right(right, :allow, value, "allowing %s access", count)
+ when "deny"
+ modify_right(right, :deny, value, "denying %s access", count)
+ when "method"
+ unless right.acl_type == :regex
+ raise ConfigurationError, "'method' directive not allowed in namespace ACL at line #{count} of #{@config}"
+ end
+ modify_right(right, :restrict_method, value, "allowing 'method' %s", count)
+ when "environment"
+ unless right.acl_type == :regex
+ raise ConfigurationError, "'environment' directive not allowed in namespace ACL at line #{count} of #{@config}"
+ end
+ modify_right(right, :restrict_environment, value, "adding environment %s", count)
+ when /auth(?:enticated)?/
+ unless right.acl_type == :regex
+ raise ConfigurationError, "'authenticated' directive not allowed in namespace ACL at line #{count} of #{@config}"
end
+ modify_right(right, :restrict_authenticated, value, "adding authentication %s", count)
+ else
+ raise ConfigurationError,
+ "Invalid argument '#{var}' at line #{count}"
+ end
+ end
+ def modify_right(right, method, value, msg, count)
+ value.split(/\s*,\s*/).each do |val|
+ begin
+ right.info msg % val
+ right.send(method, val)
+ rescue AuthStoreError => detail
+ raise ConfigurationError, "#{detail} at line #{count} of #{@file}"
+ end
+ end
end
+
+ end
end
diff --git a/lib/puppet/network/authorization.rb b/lib/puppet/network/authorization.rb
index 12459a5d1..b9cab2132 100644
--- a/lib/puppet/network/authorization.rb
+++ b/lib/puppet/network/authorization.rb
@@ -2,75 +2,75 @@ require 'puppet/network/client_request'
require 'puppet/network/authconfig'
module Puppet::Network
- # Most of our subclassing is just so that we can get
- # access to information from the request object, like
- # the client name and IP address.
- class InvalidClientRequest < Puppet::Error; end
- module Authorization
- # Create our config object if necessary. This works even if
- # there's no configuration file.
- def authconfig
- @authconfig ||= Puppet::Network::AuthConfig.main
+ # Most of our subclassing is just so that we can get
+ # access to information from the request object, like
+ # the client name and IP address.
+ class InvalidClientRequest < Puppet::Error; end
+ module Authorization
+ # Create our config object if necessary. This works even if
+ # there's no configuration file.
+ def authconfig
+ @authconfig ||= Puppet::Network::AuthConfig.main
- @authconfig
- end
+ @authconfig
+ end
- # Verify that our client has access. We allow untrusted access to
- # puppetca methods but no others.
- def authorized?(request)
- msg = "#{request.authenticated? ? "authenticated" : "unauthenticated"} client #{request} access to #{request.call}"
+ # Verify that our client has access. We allow untrusted access to
+ # puppetca methods but no others.
+ def authorized?(request)
+ msg = "#{request.authenticated? ? "authenticated" : "unauthenticated"} client #{request} access to #{request.call}"
- if request.authenticated?
- if authconfig.exists?
- if authconfig.allowed?(request)
- Puppet.debug "Allowing #{msg}"
- return true
- else
- Puppet.notice "Denying #{msg}"
- return false
- end
- else
- if Puppet.run_mode.master?
- Puppet.debug "Allowing #{msg}"
- return true
- else
- Puppet.notice "Denying #{msg}"
- return false
- end
- end
- else
- if request.handler == "puppetca"
- Puppet.notice "Allowing #{msg}"
- else
- Puppet.notice "Denying #{msg}"
- return false
- end
- end
+ if request.authenticated?
+ if authconfig.exists?
+ if authconfig.allowed?(request)
+ Puppet.debug "Allowing #{msg}"
+ return true
+ else
+ Puppet.notice "Denying #{msg}"
+ return false
+ end
+ else
+ if Puppet.run_mode.master?
+ Puppet.debug "Allowing #{msg}"
+ return true
+ else
+ Puppet.notice "Denying #{msg}"
+ return false
+ end
end
-
- # Is this functionality available?
- def available?(request)
- if handler_loaded?(request.handler)
- return true
- else
- Puppet.warning "Client #{request} requested unavailable functionality #{request.handler}"
- return false
- end
+ else
+ if request.handler == "puppetca"
+ Puppet.notice "Allowing #{msg}"
+ else
+ Puppet.notice "Denying #{msg}"
+ return false
end
+ end
+ end
- # Make sure that this method is available and authorized.
- def verify(request)
- unless available?(request)
- raise InvalidClientRequest.new(
- "Functionality #{request.handler} not available"
- )
- end
- unless authorized?(request)
- raise InvalidClientRequest.new(
- "Host #{request} not authorized to call #{request.call}"
- )
- end
- end
+ # Is this functionality available?
+ def available?(request)
+ if handler_loaded?(request.handler)
+ return true
+ else
+ Puppet.warning "Client #{request} requested unavailable functionality #{request.handler}"
+ return false
+ end
+ end
+
+ # Make sure that this method is available and authorized.
+ def verify(request)
+ unless available?(request)
+ raise InvalidClientRequest.new(
+ "Functionality #{request.handler} not available"
+ )
+ end
+ unless authorized?(request)
+ raise InvalidClientRequest.new(
+ "Host #{request} not authorized to call #{request.call}"
+ )
+ end
end
+ end
end
diff --git a/lib/puppet/network/authstore.rb b/lib/puppet/network/authstore.rb
index 720145ed8..4ddd14feb 100755
--- a/lib/puppet/network/authstore.rb
+++ b/lib/puppet/network/authstore.rb
@@ -5,246 +5,246 @@ require 'ipaddr'
require 'puppet/util/logging'
module Puppet
- class AuthStoreError < Puppet::Error; end
- class AuthorizationError < Puppet::Error; end
-
- class Network::AuthStore
- include Puppet::Util::Logging
-
- # Mark a given pattern as allowed.
- def allow(pattern)
- # a simple way to allow anyone at all to connect
- if pattern == "*"
- @globalallow = true
- else
- store(:allow, pattern)
- end
-
- nil
- end
+ class AuthStoreError < Puppet::Error; end
+ class AuthorizationError < Puppet::Error; end
+
+ class Network::AuthStore
+ include Puppet::Util::Logging
+
+ # Mark a given pattern as allowed.
+ def allow(pattern)
+ # a simple way to allow anyone at all to connect
+ if pattern == "*"
+ @globalallow = true
+ else
+ store(:allow, pattern)
+ end
+
+ nil
+ end
- # Is a given combination of name and ip address allowed? If either input
- # is non-nil, then both inputs must be provided. If neither input
- # is provided, then the authstore is considered local and defaults to "true".
- def allowed?(name, ip)
- if name or ip
- # This is probably unnecessary, and can cause some weirdnesses in
- # cases where we're operating over localhost but don't have a real
- # IP defined.
- raise Puppet::DevError, "Name and IP must be passed to 'allowed?'" unless name and ip
- # else, we're networked and such
- else
- # we're local
- return true
- end
-
- # yay insecure overrides
- return true if globalallow?
-
- if decl = declarations.find { |d| d.match?(name, ip) }
- return decl.result
- end
-
- info "defaulting to no access for #{name}"
- false
- end
+ # Is a given combination of name and ip address allowed? If either input
+ # is non-nil, then both inputs must be provided. If neither input
+ # is provided, then the authstore is considered local and defaults to "true".
+ def allowed?(name, ip)
+ if name or ip
+ # This is probably unnecessary, and can cause some weirdnesses in
+ # cases where we're operating over localhost but don't have a real
+ # IP defined.
+ raise Puppet::DevError, "Name and IP must be passed to 'allowed?'" unless name and ip
+ # else, we're networked and such
+ else
+ # we're local
+ return true
+ end
+
+ # yay insecure overrides
+ return true if globalallow?
+
+ if decl = declarations.find { |d| d.match?(name, ip) }
+ return decl.result
+ end
+
+ info "defaulting to no access for #{name}"
+ false
+ end
- # Deny a given pattern.
- def deny(pattern)
- store(:deny, pattern)
- end
+ # Deny a given pattern.
+ def deny(pattern)
+ store(:deny, pattern)
+ end
- # Is global allow enabled?
- def globalallow?
- @globalallow
- end
+ # Is global allow enabled?
+ def globalallow?
+ @globalallow
+ end
- # does this auth store has any rules?
- def empty?
- @globalallow.nil? && @declarations.size == 0
- end
+ # does this auth store has any rules?
+ def empty?
+ @globalallow.nil? && @declarations.size == 0
+ end
- def initialize
- @globalallow = nil
- @declarations = []
- end
+ def initialize
+ @globalallow = nil
+ @declarations = []
+ end
- def to_s
- "authstore"
- end
+ def to_s
+ "authstore"
+ end
- def interpolate(match)
- Thread.current[:declarations] = @declarations.collect { |ace| ace.interpolate(match) }.sort
- end
+ def interpolate(match)
+ Thread.current[:declarations] = @declarations.collect { |ace| ace.interpolate(match) }.sort
+ end
- def reset_interpolation
- Thread.current[:declarations] = nil
- end
+ def reset_interpolation
+ Thread.current[:declarations] = nil
+ end
- private
+ private
- # returns our ACEs list, but if we have a modification of it
- # in our current thread, let's return it
- # this is used if we want to override the this purely immutable list
- # by a modified version in a multithread safe way.
- def declarations
- Thread.current[:declarations] || @declarations
- end
+ # returns our ACEs list, but if we have a modification of it
+ # in our current thread, let's return it
+ # this is used if we want to override the this purely immutable list
+ # by a modified version in a multithread safe way.
+ def declarations
+ Thread.current[:declarations] || @declarations
+ end
- # Store the results of a pattern into our hash. Basically just
- # converts the pattern and sticks it into the hash.
- def store(type, pattern)
- @declarations << Declaration.new(type, pattern)
- @declarations.sort!
+ # Store the results of a pattern into our hash. Basically just
+ # converts the pattern and sticks it into the hash.
+ def store(type, pattern)
+ @declarations << Declaration.new(type, pattern)
+ @declarations.sort!
- nil
- end
+ nil
+ end
- # A single declaration. Stores the info for a given declaration,
- # provides the methods for determining whether a declaration matches,
- # and handles sorting the declarations appropriately.
- class Declaration
- include Puppet::Util
- include Comparable
-
- # The type of declaration: either :allow or :deny
- attr_reader :type
-
- # The name: :ip or :domain
- attr_accessor :name
-
- # The pattern we're matching against. Can be an IPAddr instance,
- # or an array of strings, resulting from reversing a hostname
- # or domain name.
- attr_reader :pattern
-
- # The length. Only used for iprange and domain.
- attr_accessor :length
-
- # Sort the declarations most specific first.
- def <=>(other)
- compare(exact?, other.exact?) ||
- compare(ip?, other.ip?) ||
- ((length != other.length) && (other.length <=> length)) ||
- compare(deny?, other.deny?) ||
- ( ip? ? pattern.to_s <=> other.pattern.to_s : pattern <=> other.pattern)
- end
-
- def deny?
- type == :deny
- end
-
- def exact?
- @exact == :exact
- end
-
- def initialize(type, pattern)
- self.type = type
- self.pattern = pattern
- end
-
- # Are we an IP type?
- def ip?
- name == :ip
- end
-
- # Does this declaration match the name/ip combo?
- def match?(name, ip)
- ip? ? pattern.include?(IPAddr.new(ip)) : matchname?(name)
- end
-
- # Set the pattern appropriately. Also sets the name and length.
- def pattern=(pattern)
- parse(pattern)
- @orig = pattern
- end
-
- # Mapping a type of statement into a return value.
- def result
- type == :allow
- end
-
- def to_s
- "#{type}: #{pattern}"
- end
-
- # Set the declaration type. Either :allow or :deny.
- def type=(type)
- type = symbolize(type)
- raise ArgumentError, "Invalid declaration type #{type}" unless [:allow, :deny].include?(type)
- @type = type
- end
-
- # interpolate a pattern to replace any
- # backreferences by the given match
- # for instance if our pattern is $1.reductivelabs.com
- # and we're called with a MatchData whose capture 1 is puppet
- # we'll return a pattern of puppet.reductivelabs.com
- def interpolate(match)
- clone = dup
- clone.pattern = clone.pattern.reverse.collect do |p|
- p.gsub(/\$(\d)/) { |m| match[$1.to_i] }
- end.join(".")
- clone
- end
-
- private
-
- # Returns nil if both values are true or both are false, returns
- # -1 if the first is true, and 1 if the second is true. Used
- # in the <=> operator.
- def compare(me, them)
- (me and them) ? nil : me ? -1 : them ? 1 : nil
- end
-
- # Does the name match our pattern?
- def matchname?(name)
- name = munge_name(name)
- (pattern == name) or (not exact? and pattern.zip(name).all? { |p,n| p == n })
- end
-
- # Convert the name to a common pattern.
- def munge_name(name)
- # LAK:NOTE http://snurl.com/21zf8 [groups_google_com]
- # Change to name.downcase.split(".",-1).reverse for FQDN support
- name.downcase.split(".").reverse
- end
-
- # Parse our input pattern and figure out what kind of allowal
- # statement it is. The output of this is used for later matching.
- Octet = '(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])'
- IPv4 = "#{Octet}\.#{Octet}\.#{Octet}\.#{Octet}"
- IPv6_full = "_:_:_:_:_:_:_:_|_:_:_:_:_:_::_?|_:_:_:_:_::((_:)?_)?|_:_:_:_::((_:){0,2}_)?|_:_:_::((_:){0,3}_)?|_:_::((_:){0,4}_)?|_::((_:){0,5}_)?|::((_:){0,6}_)?"
- IPv6_partial = "_:_:_:_:_:_:|_:_:_:_::(_:)?|_:_::(_:){0,2}|_::(_:){0,3}"
- # It should be:
- # IP = "#{IPv4}|#{IPv6_full}|(#{IPv6_partial}#{IPv4})".gsub(/_/,'([0-9a-fA-F]{1,4})').gsub(/\(/,'(?:')
- # but ruby's ipaddr lib doesn't support the hybrid format
- IP = "#{IPv4}|#{IPv6_full}".gsub(/_/,'([0-9a-fA-F]{1,4})').gsub(/\(/,'(?:')
- def parse(value)
- @name,@exact,@length,@pattern = *case value
- when /^(?:#{IP})\/(\d+)$/ # 12.34.56.78/24, a001:b002::efff/120, c444:1000:2000::9:192.168.0.1/112
- [:ip,:inexact,$1.to_i,IPAddr.new(value)]
- when /^(#{IP})$/ # 10.20.30.40,
- [:ip,:exact,nil,IPAddr.new(value)]
- when /^(#{Octet}\.){1,3}\*$/ # an ip address with a '*' at the end
- segments = value.split(".")[0..-2]
- bits = 8*segments.length
- [:ip,:inexact,bits,IPAddr.new((segments+[0,0,0])[0,4].join(".") + "/#{bits}")]
- when /^(\w[-\w]*\.)+[-\w]+$/ # a full hostname
- # Change to /^(\w[-\w]*\.)+[-\w]+\.?$/ for FQDN support
- [:domain,:exact,nil,munge_name(value)]
- when /^\*(\.(\w[-\w]*)){1,}$/ # *.domain.com
- host_sans_star = munge_name(value)[0..-2]
- [:domain,:inexact,host_sans_star.length,host_sans_star]
- when /\$\d+/ # a backreference pattern ala $1.reductivelabs.com or 192.168.0.$1 or $1.$2
- [:dynamic,:exact,nil,munge_name(value)]
- when /^\w[-.@\w]*$/ # ? Just like a host name but allow '@'s and ending '.'s
- [:opaque,:exact,nil,[value]]
- else
- raise AuthStoreError, "Invalid pattern #{value}"
- end
- end
+ # A single declaration. Stores the info for a given declaration,
+ # provides the methods for determining whether a declaration matches,
+ # and handles sorting the declarations appropriately.
+ class Declaration
+ include Puppet::Util
+ include Comparable
+
+ # The type of declaration: either :allow or :deny
+ attr_reader :type
+
+ # The name: :ip or :domain
+ attr_accessor :name
+
+ # The pattern we're matching against. Can be an IPAddr instance,
+ # or an array of strings, resulting from reversing a hostname
+ # or domain name.
+ attr_reader :pattern
+
+ # The length. Only used for iprange and domain.
+ attr_accessor :length
+
+ # Sort the declarations most specific first.
+ def <=>(other)
+ compare(exact?, other.exact?) ||
+ compare(ip?, other.ip?) ||
+ ((length != other.length) && (other.length <=> length)) ||
+ compare(deny?, other.deny?) ||
+ ( ip? ? pattern.to_s <=> other.pattern.to_s : pattern <=> other.pattern)
+ end
+
+ def deny?
+ type == :deny
+ end
+
+ def exact?
+ @exact == :exact
+ end
+
+ def initialize(type, pattern)
+ self.type = type
+ self.pattern = pattern
+ end
+
+ # Are we an IP type?
+ def ip?
+ name == :ip
+ end
+
+ # Does this declaration match the name/ip combo?
+ def match?(name, ip)
+ ip? ? pattern.include?(IPAddr.new(ip)) : matchname?(name)
+ end
+
+ # Set the pattern appropriately. Also sets the name and length.
+ def pattern=(pattern)
+ parse(pattern)
+ @orig = pattern
+ end
+
+ # Mapping a type of statement into a return value.
+ def result
+ type == :allow
+ end
+
+ def to_s
+ "#{type}: #{pattern}"
+ end
+
+ # Set the declaration type. Either :allow or :deny.
+ def type=(type)
+ type = symbolize(type)
+ raise ArgumentError, "Invalid declaration type #{type}" unless [:allow, :deny].include?(type)
+ @type = type
+ end
+
+ # interpolate a pattern to replace any
+ # backreferences by the given match
+ # for instance if our pattern is $1.reductivelabs.com
+ # and we're called with a MatchData whose capture 1 is puppet
+ # we'll return a pattern of puppet.reductivelabs.com
+ def interpolate(match)
+ clone = dup
+ clone.pattern = clone.pattern.reverse.collect do |p|
+ p.gsub(/\$(\d)/) { |m| match[$1.to_i] }
+ end.join(".")
+ clone
+ end
+
+ private
+
+ # Returns nil if both values are true or both are false, returns
+ # -1 if the first is true, and 1 if the second is true. Used
+ # in the <=> operator.
+ def compare(me, them)
+ (me and them) ? nil : me ? -1 : them ? 1 : nil
+ end
+
+ # Does the name match our pattern?
+ def matchname?(name)
+ name = munge_name(name)
+ (pattern == name) or (not exact? and pattern.zip(name).all? { |p,n| p == n })
+ end
+
+ # Convert the name to a common pattern.
+ def munge_name(name)
+ # LAK:NOTE http://snurl.com/21zf8 [groups_google_com]
+ # Change to name.downcase.split(".",-1).reverse for FQDN support
+ name.downcase.split(".").reverse
+ end
+
+ # Parse our input pattern and figure out what kind of allowal
+ # statement it is. The output of this is used for later matching.
+ Octet = '(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])'
+ IPv4 = "#{Octet}\.#{Octet}\.#{Octet}\.#{Octet}"
+ IPv6_full = "_:_:_:_:_:_:_:_|_:_:_:_:_:_::_?|_:_:_:_:_::((_:)?_)?|_:_:_:_::((_:){0,2}_)?|_:_:_::((_:){0,3}_)?|_:_::((_:){0,4}_)?|_::((_:){0,5}_)?|::((_:){0,6}_)?"
+ IPv6_partial = "_:_:_:_:_:_:|_:_:_:_::(_:)?|_:_::(_:){0,2}|_::(_:){0,3}"
+ # It should be:
+ # IP = "#{IPv4}|#{IPv6_full}|(#{IPv6_partial}#{IPv4})".gsub(/_/,'([0-9a-fA-F]{1,4})').gsub(/\(/,'(?:')
+ # but ruby's ipaddr lib doesn't support the hybrid format
+ IP = "#{IPv4}|#{IPv6_full}".gsub(/_/,'([0-9a-fA-F]{1,4})').gsub(/\(/,'(?:')
+ def parse(value)
+ @name,@exact,@length,@pattern = *case value
+ when /^(?:#{IP})\/(\d+)$/ # 12.34.56.78/24, a001:b002::efff/120, c444:1000:2000::9:192.168.0.1/112
+ [:ip,:inexact,$1.to_i,IPAddr.new(value)]
+ when /^(#{IP})$/ # 10.20.30.40,
+ [:ip,:exact,nil,IPAddr.new(value)]
+ when /^(#{Octet}\.){1,3}\*$/ # an ip address with a '*' at the end
+ segments = value.split(".")[0..-2]
+ bits = 8*segments.length
+ [:ip,:inexact,bits,IPAddr.new((segments+[0,0,0])[0,4].join(".") + "/#{bits}")]
+ when /^(\w[-\w]*\.)+[-\w]+$/ # a full hostname
+ # Change to /^(\w[-\w]*\.)+[-\w]+\.?$/ for FQDN support
+ [:domain,:exact,nil,munge_name(value)]
+ when /^\*(\.(\w[-\w]*)){1,}$/ # *.domain.com
+ host_sans_star = munge_name(value)[0..-2]
+ [:domain,:inexact,host_sans_star.length,host_sans_star]
+ when /\$\d+/ # a backreference pattern ala $1.reductivelabs.com or 192.168.0.$1 or $1.$2
+ [:dynamic,:exact,nil,munge_name(value)]
+ when /^\w[-.@\w]*$/ # ? Just like a host name but allow '@'s and ending '.'s
+ [:opaque,:exact,nil,[value]]
+ else
+ raise AuthStoreError, "Invalid pattern #{value}"
end
+ end
end
+ end
end
diff --git a/lib/puppet/network/client.rb b/lib/puppet/network/client.rb
index e406ae8cf..cd88b9d84 100644
--- a/lib/puppet/network/client.rb
+++ b/lib/puppet/network/client.rb
@@ -13,167 +13,167 @@ require 'net/http'
# Some versions of ruby don't have this method defined, which basically causes
# us to never use ssl. Yay.
class Net::HTTP
- def use_ssl?
- if defined?(@use_ssl)
- @use_ssl
- else
- false
- end
+ def use_ssl?
+ if defined?(@use_ssl)
+ @use_ssl
+ else
+ false
end
+ end
- # JJM: This is a "backport" of sorts to older ruby versions which
- # do not have this accessor. See #896 for more information.
- attr_accessor :enable_post_connection_check unless Net::HTTP.instance_methods.include? "enable_post_connection_check"
+ # JJM: This is a "backport" of sorts to older ruby versions which
+ # do not have this accessor. See #896 for more information.
+ attr_accessor :enable_post_connection_check unless Net::HTTP.instance_methods.include? "enable_post_connection_check"
end
# The base class for all of the clients. Many clients just directly
# call methods, but some of them need to do some extra work or
# provide a different interface.
class Puppet::Network::Client
- Client = self
- include Puppet::Util
- extend Puppet::Util::SubclassLoader
- include Puppet::Util::MethodHelper
-
- # This handles reading in the key and such-like.
- include Puppet::SSLCertificates::Support
-
- attr_accessor :schedule, :lastrun, :local, :stopping
-
- attr_reader :driver
-
- # Set up subclass loading
- handle_subclasses :client, "puppet/network/client"
-
- # Determine what clients look for when being passed an object for local
- # client/server stuff. E.g., you could call Client::CA.new(:CA => ca).
- def self.drivername
- @drivername ||= self.name
+ Client = self
+ include Puppet::Util
+ extend Puppet::Util::SubclassLoader
+ include Puppet::Util::MethodHelper
+
+ # This handles reading in the key and such-like.
+ include Puppet::SSLCertificates::Support
+
+ attr_accessor :schedule, :lastrun, :local, :stopping
+
+ attr_reader :driver
+
+ # Set up subclass loading
+ handle_subclasses :client, "puppet/network/client"
+
+ # Determine what clients look for when being passed an object for local
+ # client/server stuff. E.g., you could call Client::CA.new(:CA => ca).
+ def self.drivername
+ @drivername ||= self.name
+ end
+
+ # Figure out the handler for our client.
+ def self.handler
+ @handler ||= Puppet::Network::Handler.handler(self.name)
+ end
+
+ # The class that handles xmlrpc interaction for us.
+ def self.xmlrpc_client
+ @xmlrpc_client ||= Puppet::Network::XMLRPCClient.handler_class(self.handler)
+ end
+
+ # Create our client.
+ def initialize(hash)
+ # to whom do we connect?
+ @server = nil
+
+ if hash.include?(:Cache)
+ @cache = hash[:Cache]
+ else
+ @cache = true
end
- # Figure out the handler for our client.
- def self.handler
- @handler ||= Puppet::Network::Handler.handler(self.name)
+ driverparam = self.class.drivername
+ if hash.include?(:Server)
+ args = {:Server => hash[:Server]}
+ @server = hash[:Server]
+ args[:Port] = hash[:Port] || Puppet[:masterport]
+
+ @driver = self.class.xmlrpc_client.new(args)
+
+ self.read_cert
+
+ # We have to start the HTTP connection manually before we start
+ # sending it requests or keep-alive won't work. Note that with #1010,
+ # we don't currently actually want keep-alive.
+ @driver.start if @driver.respond_to? :start and Puppet::Network::HttpPool.keep_alive?
+
+ @local = false
+ elsif hash.include?(driverparam)
+ @driver = hash[driverparam]
+ if @driver == true
+ @driver = self.class.handler.new
+ end
+ @local = true
+ else
+ raise Puppet::Network::ClientError, "#{self.class} must be passed a Server or #{driverparam}"
end
-
- # The class that handles xmlrpc interaction for us.
- def self.xmlrpc_client
- @xmlrpc_client ||= Puppet::Network::XMLRPCClient.handler_class(self.handler)
+ end
+
+ # Are we a local client?
+ def local?
+ if @local
+ true
+ else
+ false
end
-
- # Create our client.
- def initialize(hash)
- # to whom do we connect?
- @server = nil
-
- if hash.include?(:Cache)
- @cache = hash[:Cache]
- else
- @cache = true
- end
-
- driverparam = self.class.drivername
- if hash.include?(:Server)
- args = {:Server => hash[:Server]}
- @server = hash[:Server]
- args[:Port] = hash[:Port] || Puppet[:masterport]
-
- @driver = self.class.xmlrpc_client.new(args)
-
- self.read_cert
-
- # We have to start the HTTP connection manually before we start
- # sending it requests or keep-alive won't work. Note that with #1010,
- # we don't currently actually want keep-alive.
- @driver.start if @driver.respond_to? :start and Puppet::Network::HttpPool.keep_alive?
-
- @local = false
- elsif hash.include?(driverparam)
- @driver = hash[driverparam]
- if @driver == true
- @driver = self.class.handler.new
- end
- @local = true
- else
- raise Puppet::Network::ClientError, "#{self.class} must be passed a Server or #{driverparam}"
- end
+ end
+
+ # Make sure we set the driver up when we read the cert in.
+ def recycle_connection
+ @driver.recycle_connection if @driver.respond_to?(:recycle_connection)
+ end
+
+ # A wrapper method to run and then store the last run time
+ def runnow
+ if self.stopping
+ Puppet.notice "In shutdown progress; skipping run"
+ return
end
-
- # Are we a local client?
- def local?
- if @local
- true
- else
- false
- end
+ begin
+ self.run
+ self.lastrun = Time.now.to_i
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not run #{self.class}: #{detail}"
end
+ end
- # Make sure we set the driver up when we read the cert in.
- def recycle_connection
- @driver.recycle_connection if @driver.respond_to?(:recycle_connection)
- end
+ def run
+ raise Puppet::DevError, "Client type #{self.class} did not override run"
+ end
- # A wrapper method to run and then store the last run time
- def runnow
- if self.stopping
- Puppet.notice "In shutdown progress; skipping run"
- return
- end
- begin
- self.run
- self.lastrun = Time.now.to_i
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not run #{self.class}: #{detail}"
- end
+ def scheduled?
+ if sched = self.schedule
+ return sched.match?(self.lastrun)
+ else
+ return true
end
-
- def run
- raise Puppet::DevError, "Client type #{self.class} did not override run"
+ end
+
+ def shutdown
+ if self.stopping
+ Puppet.notice "Already in shutdown"
+ else
+ self.stopping = true
+ Puppet::Util::Storage.store if self.respond_to? :running? and self.running?
+ rmpidfile
end
+ end
- def scheduled?
- if sched = self.schedule
- return sched.match?(self.lastrun)
- else
- return true
- end
- end
+ # Start listening for events. We're pretty much just listening for
+ # timer events here.
+ def start
+ # Create our timer. Puppet will handle observing it and such.
- def shutdown
- if self.stopping
- Puppet.notice "Already in shutdown"
- else
- self.stopping = true
- Puppet::Util::Storage.store if self.respond_to? :running? and self.running?
- rmpidfile
- end
- end
-
- # Start listening for events. We're pretty much just listening for
- # timer events here.
- def start
- # Create our timer. Puppet will handle observing it and such.
-
- timer = Puppet.newtimer(
+ timer = Puppet.newtimer(
- :interval => Puppet[:runinterval],
- :tolerance => 1,
+ :interval => Puppet[:runinterval],
+ :tolerance => 1,
- :start? => true
- ) do
- begin
- self.runnow if self.scheduled?
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not run client; got otherwise uncaught exception: #{detail}"
- end
- end
-
- # Run once before we start following the timer
- self.runnow
+ :start? => true
+ ) do
+ begin
+ self.runnow if self.scheduled?
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not run client; got otherwise uncaught exception: #{detail}"
+ end
end
- require 'puppet/network/client/proxy'
+ # Run once before we start following the timer
+ self.runnow
+ end
+
+ require 'puppet/network/client/proxy'
end
diff --git a/lib/puppet/network/client/ca.rb b/lib/puppet/network/client/ca.rb
index ca5c7d5cd..4c0177dfe 100644
--- a/lib/puppet/network/client/ca.rb
+++ b/lib/puppet/network/client/ca.rb
@@ -2,55 +2,55 @@ require 'puppet/network/client'
# Request a certificate from the remote system.
class Puppet::Network::Client::CA < Puppet::Network::Client
- class InvalidCertificate < Puppet::Error; end
-
- def initialize(options = {})
- options = symbolize_options(options)
- unless options.include?(:Server) or options.include?(:CA)
- options[:Server] = Puppet[:ca_server]
- options[:Port] = Puppet[:ca_port]
- end
- super(options)
+ class InvalidCertificate < Puppet::Error; end
+
+ def initialize(options = {})
+ options = symbolize_options(options)
+ unless options.include?(:Server) or options.include?(:CA)
+ options[:Server] = Puppet[:ca_server]
+ options[:Port] = Puppet[:ca_port]
+ end
+ super(options)
+ end
+
+ # This client is really only able to request certificates for the
+ # current host. It uses the Puppet.settings settings to figure everything out.
+ def request_cert
+ Puppet.settings.use(:main, :ssl)
+
+ if cert = read_cert
+ return cert
+ end
+
+ begin
+ cert, cacert = @driver.getcert(csr.to_pem)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error.new("Certificate retrieval failed: #{detail}")
end
- # This client is really only able to request certificates for the
- # current host. It uses the Puppet.settings settings to figure everything out.
- def request_cert
- Puppet.settings.use(:main, :ssl)
-
- if cert = read_cert
- return cert
- end
-
- begin
- cert, cacert = @driver.getcert(csr.to_pem)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error.new("Certificate retrieval failed: #{detail}")
- end
-
- if cert.nil? or cert == ""
- return nil
- end
-
- begin
- @cert = OpenSSL::X509::Certificate.new(cert)
- @cacert = OpenSSL::X509::Certificate.new(cacert)
- rescue => detail
- raise InvalidCertificate.new(
- "Invalid certificate: #{detail}"
- )
- end
-
- unless @cert.check_private_key(key)
- raise InvalidCertificate, "Certificate does not match private key. Try 'puppetca --clean #{Puppet[:certname]}' on the server."
- end
-
- # Only write the cert out if it passes validating.
- Puppet.settings.write(:hostcert) do |f| f.print cert end
- Puppet.settings.write(:localcacert) do |f| f.print cacert end
-
- @cert
+ if cert.nil? or cert == ""
+ return nil
end
+
+ begin
+ @cert = OpenSSL::X509::Certificate.new(cert)
+ @cacert = OpenSSL::X509::Certificate.new(cacert)
+ rescue => detail
+ raise InvalidCertificate.new(
+ "Invalid certificate: #{detail}"
+ )
+ end
+
+ unless @cert.check_private_key(key)
+ raise InvalidCertificate, "Certificate does not match private key. Try 'puppetca --clean #{Puppet[:certname]}' on the server."
+ end
+
+ # Only write the cert out if it passes validating.
+ Puppet.settings.write(:hostcert) do |f| f.print cert end
+ Puppet.settings.write(:localcacert) do |f| f.print cacert end
+
+ @cert
+ end
end
diff --git a/lib/puppet/network/client/file.rb b/lib/puppet/network/client/file.rb
index 6dd2adab2..caafb750c 100644
--- a/lib/puppet/network/client/file.rb
+++ b/lib/puppet/network/client/file.rb
@@ -1,6 +1,6 @@
class Puppet::Network::Client::File < Puppet::Network::Client::ProxyClient
- @handler = Puppet::Network::Handler.handler(:fileserver)
- @drivername = :FileServer
- self.mkmethods
+ @handler = Puppet::Network::Handler.handler(:fileserver)
+ @drivername = :FileServer
+ self.mkmethods
end
diff --git a/lib/puppet/network/client/proxy.rb b/lib/puppet/network/client/proxy.rb
index d3fc9d142..1d565a83a 100644
--- a/lib/puppet/network/client/proxy.rb
+++ b/lib/puppet/network/client/proxy.rb
@@ -2,26 +2,26 @@
# is basically just a proxy class -- it calls its methods on the driver
# and that's about it
class Puppet::Network::Client::ProxyClient < Puppet::Network::Client
- def self.mkmethods
- interface = self.handler.interface
- namespace = interface.prefix
+ def self.mkmethods
+ interface = self.handler.interface
+ namespace = interface.prefix
- interface.methods.each { |ary|
- method = ary[0]
- Puppet.debug "#{self}: defining #{namespace}.#{method}"
- define_method(method) { |*args|
- begin
- @driver.send(method, *args)
- rescue XMLRPC::FaultException => detail
- #Puppet.err "Could not call %s.%s: %s" %
- # [namespace, method, detail.faultString]
- #raise NetworkClientError,
- # "XMLRPC Error: #{detail.faultString}"
- raise NetworkClientError, detail.faultString
- end
- }
- }
- end
+ interface.methods.each { |ary|
+ method = ary[0]
+ Puppet.debug "#{self}: defining #{namespace}.#{method}"
+ define_method(method) { |*args|
+ begin
+ @driver.send(method, *args)
+ rescue XMLRPC::FaultException => detail
+ #Puppet.err "Could not call %s.%s: %s" %
+ # [namespace, method, detail.faultString]
+ #raise NetworkClientError,
+ # "XMLRPC Error: #{detail.faultString}"
+ raise NetworkClientError, detail.faultString
+ end
+ }
+ }
+ end
end
diff --git a/lib/puppet/network/client/report.rb b/lib/puppet/network/client/report.rb
index f4a9cdaa7..c9afaf969 100644
--- a/lib/puppet/network/client/report.rb
+++ b/lib/puppet/network/client/report.rb
@@ -1,26 +1,26 @@
class Puppet::Network::Client::Report < Puppet::Network::Client
- @handler = Puppet::Network::Handler.handler(:report)
+ @handler = Puppet::Network::Handler.handler(:report)
- def initialize(hash = {})
- hash[:Report] = self.class.handler.new if hash.include?(:Report)
+ def initialize(hash = {})
+ hash[:Report] = self.class.handler.new if hash.include?(:Report)
- super(hash)
- end
-
- # Send our report. We get the transaction report and convert it to YAML
- # as appropriate.
- def report(transreport)
- report = YAML.dump(transreport)
+ super(hash)
+ end
- report = CGI.escape(report) unless self.local
+ # Send our report. We get the transaction report and convert it to YAML
+ # as appropriate.
+ def report(transreport)
+ report = YAML.dump(transreport)
- # Now send the report
- file = nil
- benchmark(:info, "Sent transaction report") do
- file = @driver.report(report)
- end
+ report = CGI.escape(report) unless self.local
- file
+ # Now send the report
+ file = nil
+ benchmark(:info, "Sent transaction report") do
+ file = @driver.report(report)
end
+
+ file
+ end
end
diff --git a/lib/puppet/network/client/runner.rb b/lib/puppet/network/client/runner.rb
index 68005c9f0..a4596a753 100644
--- a/lib/puppet/network/client/runner.rb
+++ b/lib/puppet/network/client/runner.rb
@@ -1,10 +1,10 @@
class Puppet::Network::Client::Runner < Puppet::Network::Client::ProxyClient
- self.mkmethods
+ self.mkmethods
- def initialize(hash = {})
- hash[:Runner] = self.class.handler.new if hash.include?(:Runner)
+ def initialize(hash = {})
+ hash[:Runner] = self.class.handler.new if hash.include?(:Runner)
- super(hash)
- end
+ super(hash)
+ end
end
diff --git a/lib/puppet/network/client/status.rb b/lib/puppet/network/client/status.rb
index 9dc22b606..c24c7e3d0 100644
--- a/lib/puppet/network/client/status.rb
+++ b/lib/puppet/network/client/status.rb
@@ -1,4 +1,4 @@
class Puppet::Network::Client::Status < Puppet::Network::Client::ProxyClient
- self.mkmethods
+ self.mkmethods
end
diff --git a/lib/puppet/network/client_request.rb b/lib/puppet/network/client_request.rb
index f914bad09..e3df471f4 100644
--- a/lib/puppet/network/client_request.rb
+++ b/lib/puppet/network/client_request.rb
@@ -1,29 +1,29 @@
module Puppet::Network # :nodoc:
- # A struct-like class for passing around a client request. It's mostly
- # just used for validation and authorization.
- class ClientRequest
- attr_accessor :name, :ip, :authenticated, :handler, :method
+ # A struct-like class for passing around a client request. It's mostly
+ # just used for validation and authorization.
+ class ClientRequest
+ attr_accessor :name, :ip, :authenticated, :handler, :method
- def authenticated?
- self.authenticated
- end
+ def authenticated?
+ self.authenticated
+ end
- # A common way of talking about the full call. Individual servers
- # are responsible for setting the values correctly, but this common
- # format makes it possible to check rights.
- def call
- raise ArgumentError, "Request is not set up; cannot build call" unless handler and method
+ # A common way of talking about the full call. Individual servers
+ # are responsible for setting the values correctly, but this common
+ # format makes it possible to check rights.
+ def call
+ raise ArgumentError, "Request is not set up; cannot build call" unless handler and method
- [handler, method].join(".")
- end
+ [handler, method].join(".")
+ end
- def initialize(name, ip, authenticated)
- @name, @ip, @authenticated = name, ip, authenticated
- end
+ def initialize(name, ip, authenticated)
+ @name, @ip, @authenticated = name, ip, authenticated
+ end
- def to_s
- "#{self.name}(#{self.ip})"
- end
+ def to_s
+ "#{self.name}(#{self.ip})"
end
+ end
end
diff --git a/lib/puppet/network/format.rb b/lib/puppet/network/format.rb
index 2b5b89279..9cd6cf0b5 100644
--- a/lib/puppet/network/format.rb
+++ b/lib/puppet/network/format.rb
@@ -4,108 +4,108 @@ require 'puppet/provider/confiner'
# A simple class for modeling encoding formats for moving
# instances around the network.
class Puppet::Network::Format
- include Puppet::Provider::Confiner
-
- attr_reader :name, :mime
- attr_accessor :intern_method, :render_method, :intern_multiple_method, :render_multiple_method, :weight, :required_methods, :extension
-
- def init_attribute(name, default)
- if value = @options[name]
- @options.delete(name)
- else
- value = default
- end
- self.send(name.to_s + "=", value)
- end
-
- def initialize(name, options = {}, &block)
- @name = name.to_s.downcase.intern
+ include Puppet::Provider::Confiner
- @options = options
+ attr_reader :name, :mime
+ attr_accessor :intern_method, :render_method, :intern_multiple_method, :render_multiple_method, :weight, :required_methods, :extension
- # This must be done early the values can be used to set required_methods
- define_method_names
+ def init_attribute(name, default)
+ if value = @options[name]
+ @options.delete(name)
+ else
+ value = default
+ end
+ self.send(name.to_s + "=", value)
+ end
- method_list = {
- :intern_method => "from_#{name}",
- :intern_multiple_method => "from_multiple_#{name}",
- :render_multiple_method => "to_multiple_#{name}",
- :render_method => "to_#{name}"
- }
+ def initialize(name, options = {}, &block)
+ @name = name.to_s.downcase.intern
- init_attribute(:mime, "text/#{name}")
- init_attribute(:weight, 5)
- init_attribute(:required_methods, method_list.keys)
- init_attribute(:extension, name.to_s)
+ @options = options
- method_list.each do |method, value|
- init_attribute(method, value)
- end
+ # This must be done early the values can be used to set required_methods
+ define_method_names
- raise ArgumentError, "Unsupported option(s) #{@options.keys}" unless @options.empty?
+ method_list = {
+ :intern_method => "from_#{name}",
+ :intern_multiple_method => "from_multiple_#{name}",
+ :render_multiple_method => "to_multiple_#{name}",
+ :render_method => "to_#{name}"
+ }
- @options = nil
+ init_attribute(:mime, "text/#{name}")
+ init_attribute(:weight, 5)
+ init_attribute(:required_methods, method_list.keys)
+ init_attribute(:extension, name.to_s)
- instance_eval(&block) if block_given?
+ method_list.each do |method, value|
+ init_attribute(method, value)
end
- def intern(klass, text)
- return klass.send(intern_method, text) if klass.respond_to?(intern_method)
- raise NotImplementedError, "#{klass} does not respond to #{intern_method}; can not intern instances from #{mime}"
- end
+ raise ArgumentError, "Unsupported option(s) #{@options.keys}" unless @options.empty?
- def intern_multiple(klass, text)
- return klass.send(intern_multiple_method, text) if klass.respond_to?(intern_multiple_method)
- raise NotImplementedError, "#{klass} does not respond to #{intern_multiple_method}; can not intern multiple instances from #{mime}"
- end
+ @options = nil
- def mime=(mime)
- @mime = mime.to_s.downcase
- end
+ instance_eval(&block) if block_given?
+ end
- def render(instance)
- return instance.send(render_method) if instance.respond_to?(render_method)
- raise NotImplementedError, "#{instance.class} does not respond to #{render_method}; can not render instances to #{mime}"
- end
+ def intern(klass, text)
+ return klass.send(intern_method, text) if klass.respond_to?(intern_method)
+ raise NotImplementedError, "#{klass} does not respond to #{intern_method}; can not intern instances from #{mime}"
+ end
- def render_multiple(instances)
- # This method implicitly assumes that all instances are of the same type.
- return instances[0].class.send(render_multiple_method, instances) if instances[0].class.respond_to?(render_multiple_method)
- raise NotImplementedError, "#{instances[0].class} does not respond to #{render_multiple_method}; can not intern multiple instances to #{mime}"
- end
+ def intern_multiple(klass, text)
+ return klass.send(intern_multiple_method, text) if klass.respond_to?(intern_multiple_method)
+ raise NotImplementedError, "#{klass} does not respond to #{intern_multiple_method}; can not intern multiple instances from #{mime}"
+ end
- def required_methods_present?(klass)
- [:intern_method, :intern_multiple_method, :render_multiple_method].each do |name|
- return false unless required_method_present?(name, klass, :class)
- end
+ def mime=(mime)
+ @mime = mime.to_s.downcase
+ end
- return false unless required_method_present?(:render_method, klass, :instance)
+ def render(instance)
+ return instance.send(render_method) if instance.respond_to?(render_method)
+ raise NotImplementedError, "#{instance.class} does not respond to #{render_method}; can not render instances to #{mime}"
+ end
- true
- end
+ def render_multiple(instances)
+ # This method implicitly assumes that all instances are of the same type.
+ return instances[0].class.send(render_multiple_method, instances) if instances[0].class.respond_to?(render_multiple_method)
+ raise NotImplementedError, "#{instances[0].class} does not respond to #{render_multiple_method}; can not intern multiple instances to #{mime}"
+ end
- def supported?(klass)
- suitable? and required_methods_present?(klass)
+ def required_methods_present?(klass)
+ [:intern_method, :intern_multiple_method, :render_multiple_method].each do |name|
+ return false unless required_method_present?(name, klass, :class)
end
- def to_s
- "Puppet::Network::Format[#{name}]"
- end
+ return false unless required_method_present?(:render_method, klass, :instance)
- private
+ true
+ end
- def define_method_names
- @intern_method = "from_#{name}"
- @render_method = "to_#{name}"
- @intern_multiple_method = "from_multiple_#{name}"
- @render_multiple_method = "to_multiple_#{name}"
- end
+ def supported?(klass)
+ suitable? and required_methods_present?(klass)
+ end
- def required_method_present?(name, klass, type)
- return true unless required_methods.include?(name)
+ def to_s
+ "Puppet::Network::Format[#{name}]"
+ end
- method = send(name)
+ private
- return(type == :class ? klass.respond_to?(method) : klass.instance_methods.include?(method))
- end
+ def define_method_names
+ @intern_method = "from_#{name}"
+ @render_method = "to_#{name}"
+ @intern_multiple_method = "from_multiple_#{name}"
+ @render_multiple_method = "to_multiple_#{name}"
+ end
+
+ def required_method_present?(name, klass, type)
+ return true unless required_methods.include?(name)
+
+ method = send(name)
+
+ return(type == :class ? klass.respond_to?(method) : klass.instance_methods.include?(method))
+ end
end
diff --git a/lib/puppet/network/format_handler.rb b/lib/puppet/network/format_handler.rb
index b5817d544..d378ad6a1 100644
--- a/lib/puppet/network/format_handler.rb
+++ b/lib/puppet/network/format_handler.rb
@@ -3,173 +3,173 @@ require 'puppet/network'
require 'puppet/network/format'
module Puppet::Network::FormatHandler
- class FormatError < Puppet::Error; end
+ class FormatError < Puppet::Error; end
+
+ class FormatProtector
+ attr_reader :format
+
+ def protect(method, args)
+ Puppet::Network::FormatHandler.format(format).send(method, *args)
+ rescue => details
+ direction = method.to_s.include?("intern") ? "from" : "to"
+ error = FormatError.new("Could not #{method} #{direction} #{format}: #{details}")
+ error.set_backtrace(details.backtrace)
+ raise error
+ end
- class FormatProtector
- attr_reader :format
+ def initialize(format)
+ @format = format
+ end
- def protect(method, args)
- Puppet::Network::FormatHandler.format(format).send(method, *args)
- rescue => details
- direction = method.to_s.include?("intern") ? "from" : "to"
- error = FormatError.new("Could not #{method} #{direction} #{format}: #{details}")
- error.set_backtrace(details.backtrace)
- raise error
- end
+ [:intern, :intern_multiple, :render, :render_multiple, :mime].each do |method|
+ define_method(method) do |*args|
+ protect(method, args)
+ end
+ end
+ end
- def initialize(format)
- @format = format
- end
+ @formats = {}
+ def self.create(*args, &block)
+ instance = Puppet::Network::Format.new(*args)
+ instance.instance_eval(&block) if block_given?
- [:intern, :intern_multiple, :render, :render_multiple, :mime].each do |method|
- define_method(method) do |*args|
- protect(method, args)
- end
- end
- end
+ @formats[instance.name] = instance
+ instance
+ end
- @formats = {}
- def self.create(*args, &block)
- instance = Puppet::Network::Format.new(*args)
- instance.instance_eval(&block) if block_given?
+ def self.extended(klass)
+ klass.extend(ClassMethods)
- @formats[instance.name] = instance
- instance
- end
+ # LAK:NOTE This won't work in 1.9 ('send' won't be able to send
+ # private methods, but I don't know how else to do it.
+ klass.send(:include, InstanceMethods)
+ end
- def self.extended(klass)
- klass.extend(ClassMethods)
+ def self.format(name)
+ @formats[name.to_s.downcase.intern]
+ end
- # LAK:NOTE This won't work in 1.9 ('send' won't be able to send
- # private methods, but I don't know how else to do it.
- klass.send(:include, InstanceMethods)
+ def self.format_by_extension(ext)
+ @formats.each do |name, format|
+ return format if format.extension == ext
end
-
- def self.format(name)
- @formats[name.to_s.downcase.intern]
+ nil
+ end
+
+ # Provide a list of all formats.
+ def self.formats
+ @formats.keys
+ end
+
+ # Return a format capable of handling the provided mime type.
+ def self.mime(mimetype)
+ mimetype = mimetype.to_s.downcase
+ @formats.values.find { |format| format.mime == mimetype }
+ end
+
+ # Use a delegator to make sure any exceptions generated by our formats are
+ # handled intelligently.
+ def self.protected_format(name)
+ name = format_to_canonical_name(name)
+ @format_protectors ||= {}
+ @format_protectors[name] ||= FormatProtector.new(name)
+ @format_protectors[name]
+ end
+
+ # Return a format name given:
+ # * a format name
+ # * a mime-type
+ # * a format instance
+ def self.format_to_canonical_name(format)
+ case format
+ when Puppet::Network::Format
+ out = format
+ when %r{\w+/\w+}
+ out = mime(format)
+ else
+ out = format(format)
end
+ raise ArgumentError, "No format match the given format name or mime-type (#{format})" if out.nil?
+ out.name
+ end
- def self.format_by_extension(ext)
- @formats.each do |name, format|
- return format if format.extension == ext
- end
- nil
+ module ClassMethods
+ def format_handler
+ Puppet::Network::FormatHandler
end
- # Provide a list of all formats.
- def self.formats
- @formats.keys
+ def convert_from(format, data)
+ format_handler.protected_format(format).intern(self, data)
end
- # Return a format capable of handling the provided mime type.
- def self.mime(mimetype)
- mimetype = mimetype.to_s.downcase
- @formats.values.find { |format| format.mime == mimetype }
+ def convert_from_multiple(format, data)
+ format_handler.protected_format(format).intern_multiple(self, data)
end
- # Use a delegator to make sure any exceptions generated by our formats are
- # handled intelligently.
- def self.protected_format(name)
- name = format_to_canonical_name(name)
- @format_protectors ||= {}
- @format_protectors[name] ||= FormatProtector.new(name)
- @format_protectors[name]
+ def render_multiple(format, instances)
+ format_handler.protected_format(format).render_multiple(instances)
end
- # Return a format name given:
- # * a format name
- # * a mime-type
- # * a format instance
- def self.format_to_canonical_name(format)
- case format
- when Puppet::Network::Format
- out = format
- when %r{\w+/\w+}
- out = mime(format)
- else
- out = format(format)
- end
- raise ArgumentError, "No format match the given format name or mime-type (#{format})" if out.nil?
- out.name
+ def default_format
+ supported_formats[0]
end
- module ClassMethods
- def format_handler
- Puppet::Network::FormatHandler
- end
-
- def convert_from(format, data)
- format_handler.protected_format(format).intern(self, data)
- end
+ def support_format?(name)
+ Puppet::Network::FormatHandler.format(name).supported?(self)
+ end
- def convert_from_multiple(format, data)
- format_handler.protected_format(format).intern_multiple(self, data)
- end
+ def supported_formats
+ result = format_handler.formats.collect { |f| format_handler.format(f) }.find_all { |f| f.supported?(self) }.collect { |f| f.name }.sort do |a, b|
+ # It's an inverse sort -- higher weight formats go first.
+ format_handler.format(b).weight <=> format_handler.format(a).weight
+ end
- def render_multiple(format, instances)
- format_handler.protected_format(format).render_multiple(instances)
- end
+ result = put_preferred_format_first(result)
- def default_format
- supported_formats[0]
- end
+ Puppet.debug "#{friendly_name} supports formats: #{result.map{ |f| f.to_s }.sort.join(' ')}; using #{result.first}"
- def support_format?(name)
- Puppet::Network::FormatHandler.format(name).supported?(self)
- end
+ result
+ end
- def supported_formats
- result = format_handler.formats.collect { |f| format_handler.format(f) }.find_all { |f| f.supported?(self) }.collect { |f| f.name }.sort do |a, b|
- # It's an inverse sort -- higher weight formats go first.
- format_handler.format(b).weight <=> format_handler.format(a).weight
- end
+ private
- result = put_preferred_format_first(result)
+ def friendly_name
+ if self.respond_to? :indirection
+ indirection.name
+ else
+ self
+ end
+ end
- Puppet.debug "#{friendly_name} supports formats: #{result.map{ |f| f.to_s }.sort.join(' ')}; using #{result.first}"
+ def put_preferred_format_first(list)
+ preferred_format = Puppet.settings[:preferred_serialization_format].to_sym
+ if list.include?(preferred_format)
+ list.delete(preferred_format)
+ list.unshift(preferred_format)
+ else
+ Puppet.debug "Value of 'preferred_serialization_format' (#{preferred_format}) is invalid for #{friendly_name}, using default (#{list.first})"
+ end
+ list
+ end
+ end
- result
- end
+ module InstanceMethods
+ def render(format = nil)
+ format ||= self.class.default_format
- private
+ Puppet::Network::FormatHandler.protected_format(format).render(self)
+ end
- def friendly_name
- if self.respond_to? :indirection
- indirection.name
- else
- self
- end
- end
+ def mime(format = nil)
+ format ||= self.class.default_format
- def put_preferred_format_first(list)
- preferred_format = Puppet.settings[:preferred_serialization_format].to_sym
- if list.include?(preferred_format)
- list.delete(preferred_format)
- list.unshift(preferred_format)
- else
- Puppet.debug "Value of 'preferred_serialization_format' (#{preferred_format}) is invalid for #{friendly_name}, using default (#{list.first})"
- end
- list
- end
+ Puppet::Network::FormatHandler.protected_format(format).mime
end
- module InstanceMethods
- def render(format = nil)
- format ||= self.class.default_format
-
- Puppet::Network::FormatHandler.protected_format(format).render(self)
- end
-
- def mime(format = nil)
- format ||= self.class.default_format
-
- Puppet::Network::FormatHandler.protected_format(format).mime
- end
-
- def support_format?(name)
- self.class.support_format?(name)
- end
+ def support_format?(name)
+ self.class.support_format?(name)
end
+ end
end
require 'puppet/network/formats'
diff --git a/lib/puppet/network/formats.rb b/lib/puppet/network/formats.rb
index 2d519aea6..8a61ee62a 100644
--- a/lib/puppet/network/formats.rb
+++ b/lib/puppet/network/formats.rb
@@ -1,161 +1,161 @@
require 'puppet/network/format_handler'
Puppet::Network::FormatHandler.create(:yaml, :mime => "text/yaml") do
- # Yaml doesn't need the class name; it's serialized.
- def intern(klass, text)
- YAML.load(text)
- end
-
- # Yaml doesn't need the class name; it's serialized.
- def intern_multiple(klass, text)
- YAML.load(text)
- end
-
- def render(instance)
- instance.to_yaml
- end
-
- # Yaml monkey-patches Array, so this works.
- def render_multiple(instances)
- instances.to_yaml
- end
-
- # Unlike core's yaml, ZAML should support 1.8.1 just fine
- def supported?(klass)
- true
- end
+ # Yaml doesn't need the class name; it's serialized.
+ def intern(klass, text)
+ YAML.load(text)
+ end
+
+ # Yaml doesn't need the class name; it's serialized.
+ def intern_multiple(klass, text)
+ YAML.load(text)
+ end
+
+ def render(instance)
+ instance.to_yaml
+ end
+
+ # Yaml monkey-patches Array, so this works.
+ def render_multiple(instances)
+ instances.to_yaml
+ end
+
+ # Unlike core's yaml, ZAML should support 1.8.1 just fine
+ def supported?(klass)
+ true
+ end
end
# This is a "special" format which is used for the moment only when sending facts
# as REST GET parameters (see Puppet::Configurer::FactHandler).
# This format combines a yaml serialization, then zlib compression and base64 encoding.
Puppet::Network::FormatHandler.create(:b64_zlib_yaml, :mime => "text/b64_zlib_yaml") do
- require 'base64'
+ require 'base64'
- def use_zlib?
- Puppet.features.zlib? && Puppet[:zlib]
- end
+ def use_zlib?
+ Puppet.features.zlib? && Puppet[:zlib]
+ end
- def requiring_zlib
- if use_zlib?
- yield
- else
- raise Puppet::Error, "the zlib library is not installed or is disabled."
- end
+ def requiring_zlib
+ if use_zlib?
+ yield
+ else
+ raise Puppet::Error, "the zlib library is not installed or is disabled."
end
+ end
- def intern(klass, text)
- decode(text)
- end
+ def intern(klass, text)
+ decode(text)
+ end
- def intern_multiple(klass, text)
- decode(text)
- end
+ def intern_multiple(klass, text)
+ decode(text)
+ end
- def render(instance)
- encode(instance.to_yaml)
- end
+ def render(instance)
+ encode(instance.to_yaml)
+ end
- def render_multiple(instances)
- encode(instances.to_yaml)
- end
+ def render_multiple(instances)
+ encode(instances.to_yaml)
+ end
- def supported?(klass)
- true
- end
+ def supported?(klass)
+ true
+ end
- def encode(text)
- requiring_zlib do
- Base64.encode64(Zlib::Deflate.deflate(text, Zlib::BEST_COMPRESSION))
- end
+ def encode(text)
+ requiring_zlib do
+ Base64.encode64(Zlib::Deflate.deflate(text, Zlib::BEST_COMPRESSION))
end
+ end
- def decode(yaml)
- requiring_zlib do
- YAML.load(Zlib::Inflate.inflate(Base64.decode64(yaml)))
- end
+ def decode(yaml)
+ requiring_zlib do
+ YAML.load(Zlib::Inflate.inflate(Base64.decode64(yaml)))
end
+ end
end
Puppet::Network::FormatHandler.create(:marshal, :mime => "text/marshal") do
- # Marshal doesn't need the class name; it's serialized.
- def intern(klass, text)
- Marshal.load(text)
- end
-
- # Marshal doesn't need the class name; it's serialized.
- def intern_multiple(klass, text)
- Marshal.load(text)
- end
-
- def render(instance)
- Marshal.dump(instance)
- end
-
- # Marshal monkey-patches Array, so this works.
- def render_multiple(instances)
- Marshal.dump(instances)
- end
-
- # Everything's supported
- def supported?(klass)
- true
- end
+ # Marshal doesn't need the class name; it's serialized.
+ def intern(klass, text)
+ Marshal.load(text)
+ end
+
+ # Marshal doesn't need the class name; it's serialized.
+ def intern_multiple(klass, text)
+ Marshal.load(text)
+ end
+
+ def render(instance)
+ Marshal.dump(instance)
+ end
+
+ # Marshal monkey-patches Array, so this works.
+ def render_multiple(instances)
+ Marshal.dump(instances)
+ end
+
+ # Everything's supported
+ def supported?(klass)
+ true
+ end
end
Puppet::Network::FormatHandler.create(:s, :mime => "text/plain", :extension => "txt")
# A very low-weight format so it'll never get chosen automatically.
Puppet::Network::FormatHandler.create(:raw, :mime => "application/x-raw", :weight => 1) do
- def intern_multiple(klass, text)
- raise NotImplementedError
- end
-
- def render_multiple(instances)
- raise NotImplementedError
- end
-
- # LAK:NOTE The format system isn't currently flexible enough to handle
- # what I need to support raw formats just for individual instances (rather
- # than both individual and collections), but we don't yet have enough data
- # to make a "correct" design.
- # So, we hack it so it works for singular but fail if someone tries it
- # on plurals.
- def supported?(klass)
- true
- end
+ def intern_multiple(klass, text)
+ raise NotImplementedError
+ end
+
+ def render_multiple(instances)
+ raise NotImplementedError
+ end
+
+ # LAK:NOTE The format system isn't currently flexible enough to handle
+ # what I need to support raw formats just for individual instances (rather
+ # than both individual and collections), but we don't yet have enough data
+ # to make a "correct" design.
+ # So, we hack it so it works for singular but fail if someone tries it
+ # on plurals.
+ def supported?(klass)
+ true
+ end
end
Puppet::Network::FormatHandler.create(:pson, :mime => "text/pson", :weight => 10, :required_methods => [:render_method, :intern_method]) do
- confine :true => Puppet.features.pson?
-
- def intern(klass, text)
- data_to_instance(klass, PSON.parse(text))
- end
-
- def intern_multiple(klass, text)
- PSON.parse(text).collect do |data|
- data_to_instance(klass, data)
- end
- end
-
- # PSON monkey-patches Array, so this works.
- def render_multiple(instances)
- instances.to_pson
- end
-
- # If they pass class information, we want to ignore it. By default,
- # we'll include class information but we won't rely on it - we don't
- # want class names to be required because we then can't change our
- # internal class names, which is bad.
- def data_to_instance(klass, data)
- if data.is_a?(Hash) and d = data['data']
- data = d
- end
- return data if data.is_a?(klass)
- klass.from_pson(data)
- end
+ confine :true => Puppet.features.pson?
+
+ def intern(klass, text)
+ data_to_instance(klass, PSON.parse(text))
+ end
+
+ def intern_multiple(klass, text)
+ PSON.parse(text).collect do |data|
+ data_to_instance(klass, data)
+ end
+ end
+
+ # PSON monkey-patches Array, so this works.
+ def render_multiple(instances)
+ instances.to_pson
+ end
+
+ # If they pass class information, we want to ignore it. By default,
+ # we'll include class information but we won't rely on it - we don't
+ # want class names to be required because we then can't change our
+ # internal class names, which is bad.
+ def data_to_instance(klass, data)
+ if data.is_a?(Hash) and d = data['data']
+ data = d
+ end
+ return data if data.is_a?(klass)
+ klass.from_pson(data)
+ end
end
# This is really only ever going to be used for Catalogs.
diff --git a/lib/puppet/network/handler.rb b/lib/puppet/network/handler.rb
index 4b741eb0f..3cad3872f 100644
--- a/lib/puppet/network/handler.rb
+++ b/lib/puppet/network/handler.rb
@@ -2,49 +2,49 @@ require 'puppet/util/docs'
require 'puppet/util/subclass_loader'
module Puppet::Network
- # The base class for the different handlers. The handlers are each responsible
- # for separate xmlrpc namespaces.
- class Handler
- extend Puppet::Util::Docs
-
- # This is so that the handlers can subclass just 'Handler', rather
- # then having to specify the full class path.
- Handler = self
- attr_accessor :server, :local
-
- extend Puppet::Util::SubclassLoader
- extend Puppet::Util
-
- handle_subclasses :handler, "puppet/network/handler"
-
- # Return the xmlrpc interface.
- def self.interface
- if defined?(@interface)
- return @interface
- else
- raise Puppet::DevError, "Handler #{self} has no defined interface"
- end
- end
-
- # Set/Determine whether we're a client- or server-side handler.
- def self.side(side = nil)
- if side
- side = side.intern if side.is_a?(String)
- raise ArgumentError, "Invalid side registration '#{side}' for #{self.name}" unless [:client, :server].include?(side)
- @side = side
- else
- @side ||= :server
- return @side
- end
- end
-
- # Create an empty init method with the same signature.
- def initialize(hash = {})
- end
-
- def local?
- self.local
- end
+ # The base class for the different handlers. The handlers are each responsible
+ # for separate xmlrpc namespaces.
+ class Handler
+ extend Puppet::Util::Docs
+
+ # This is so that the handlers can subclass just 'Handler', rather
+ # then having to specify the full class path.
+ Handler = self
+ attr_accessor :server, :local
+
+ extend Puppet::Util::SubclassLoader
+ extend Puppet::Util
+
+ handle_subclasses :handler, "puppet/network/handler"
+
+ # Return the xmlrpc interface.
+ def self.interface
+ if defined?(@interface)
+ return @interface
+ else
+ raise Puppet::DevError, "Handler #{self} has no defined interface"
+ end
end
+
+ # Set/Determine whether we're a client- or server-side handler.
+ def self.side(side = nil)
+ if side
+ side = side.intern if side.is_a?(String)
+ raise ArgumentError, "Invalid side registration '#{side}' for #{self.name}" unless [:client, :server].include?(side)
+ @side = side
+ else
+ @side ||= :server
+ return @side
+ end
+ end
+
+ # Create an empty init method with the same signature.
+ def initialize(hash = {})
+ end
+
+ def local?
+ self.local
+ end
+ end
end
diff --git a/lib/puppet/network/handler/ca.rb b/lib/puppet/network/handler/ca.rb
index 101cf6f8e..ebb6fc427 100644
--- a/lib/puppet/network/handler/ca.rb
+++ b/lib/puppet/network/handler/ca.rb
@@ -7,145 +7,145 @@ require 'xmlrpc/server'
# http://segment7.net/projects/ruby/QuickCert/
class Puppet::Network::Handler
- class CA < Handler
- attr_reader :ca
-
- desc "Provides an interface for signing CSRs. Accepts a CSR and returns
- the CA certificate and the signed certificate, or returns nil if
- the cert is not signed."
+ class CA < Handler
+ attr_reader :ca
+
+ desc "Provides an interface for signing CSRs. Accepts a CSR and returns
+ the CA certificate and the signed certificate, or returns nil if
+ the cert is not signed."
+
+ @interface = XMLRPC::Service::Interface.new("puppetca") { |iface|
+ iface.add_method("array getcert(csr)")
+ }
+
+ def autosign
+ if defined?(@autosign)
+ @autosign
+ else
+ Puppet[:autosign]
+ end
+ end
- @interface = XMLRPC::Service::Interface.new("puppetca") { |iface|
- iface.add_method("array getcert(csr)")
+ # FIXME autosign? should probably accept both hostnames and IP addresses
+ def autosign?(hostname)
+ # simple values are easy
+ if autosign == true or autosign == false
+ return autosign
+ end
+
+ # we only otherwise know how to handle files
+ unless autosign =~ /^\//
+ raise Puppet::Error, "Invalid autosign value #{autosign.inspect}"
+ end
+
+ unless FileTest.exists?(autosign)
+ unless defined?(@@warnedonautosign)
+ @@warnedonautosign = true
+ Puppet.info "Autosign is enabled but #{autosign} is missing"
+ end
+ return false
+ end
+ auth = Puppet::Network::AuthStore.new
+ File.open(autosign) { |f|
+ f.each { |line|
+ next if line =~ /^\s*#/
+ next if line =~ /^\s*$/
+ auth.allow(line.chomp)
}
+ }
- def autosign
- if defined?(@autosign)
- @autosign
- else
- Puppet[:autosign]
- end
- end
+ # for now, just cheat and pass a fake IP address to allowed?
+ auth.allowed?(hostname, "127.1.1.1")
+ end
- # FIXME autosign? should probably accept both hostnames and IP addresses
- def autosign?(hostname)
- # simple values are easy
- if autosign == true or autosign == false
- return autosign
- end
-
- # we only otherwise know how to handle files
- unless autosign =~ /^\//
- raise Puppet::Error, "Invalid autosign value #{autosign.inspect}"
- end
-
- unless FileTest.exists?(autosign)
- unless defined?(@@warnedonautosign)
- @@warnedonautosign = true
- Puppet.info "Autosign is enabled but #{autosign} is missing"
- end
- return false
- end
- auth = Puppet::Network::AuthStore.new
- File.open(autosign) { |f|
- f.each { |line|
- next if line =~ /^\s*#/
- next if line =~ /^\s*$/
- auth.allow(line.chomp)
- }
- }
-
- # for now, just cheat and pass a fake IP address to allowed?
- auth.allowed?(hostname, "127.1.1.1")
- end
+ def initialize(hash = {})
+ Puppet.settings.use(:main, :ssl, :ca)
+ @autosign = hash[:autosign] if hash.include? :autosign
- def initialize(hash = {})
- Puppet.settings.use(:main, :ssl, :ca)
- @autosign = hash[:autosign] if hash.include? :autosign
+ @ca = Puppet::SSLCertificates::CA.new(hash)
+ end
- @ca = Puppet::SSLCertificates::CA.new(hash)
- end
+ # our client sends us a csr, and we either store it for later signing,
+ # or we sign it right away
+ def getcert(csrtext, client = nil, clientip = nil)
+ csr = OpenSSL::X509::Request.new(csrtext)
+
+ # Use the hostname from the CSR, not from the network.
+ subject = csr.subject
+
+ nameary = subject.to_a.find { |ary|
+ ary[0] == "CN"
+ }
- # our client sends us a csr, and we either store it for later signing,
- # or we sign it right away
- def getcert(csrtext, client = nil, clientip = nil)
- csr = OpenSSL::X509::Request.new(csrtext)
-
- # Use the hostname from the CSR, not from the network.
- subject = csr.subject
-
- nameary = subject.to_a.find { |ary|
- ary[0] == "CN"
- }
-
- if nameary.nil?
- Puppet.err(
- "Invalid certificate request: could not retrieve server name"
- )
- return "invalid"
- end
-
- hostname = nameary[1]
-
- unless @ca
- Puppet.notice "Host #{hostname} asked for signing from non-CA master"
- return ""
- end
-
- # We used to save the public key, but it's basically unnecessary
- # and it mucks with the permissions requirements.
- # save_pk(hostname, csr.public_key)
-
- certfile = File.join(Puppet[:certdir], [hostname, "pem"].join("."))
-
- # first check to see if we already have a signed cert for the host
- cert, cacert = ca.getclientcert(hostname)
- if cert and cacert
- Puppet.info "Retrieving existing certificate for #{hostname}"
- unless csr.public_key.to_s == cert.public_key.to_s
- raise Puppet::Error, "Certificate request does not match existing certificate; run 'puppetca --clean #{hostname}'."
- end
- return [cert.to_pem, cacert.to_pem]
- elsif @ca
- if self.autosign?(hostname) or client.nil?
- Puppet.info "Signing certificate for CA server" if client.nil?
- # okay, we don't have a signed cert
- # if we're a CA and autosign is turned on, then go ahead and sign
- # the csr and return the results
- Puppet.info "Signing certificate for #{hostname}"
- cert, cacert = @ca.sign(csr)
- #Puppet.info "Cert: #{cert.class}; Cacert: #{cacert.class}"
- return [cert.to_pem, cacert.to_pem]
- else # just write out the csr for later signing
- if @ca.getclientcsr(hostname)
- Puppet.info "Not replacing existing request from #{hostname}"
- else
- Puppet.notice "Host #{hostname} has a waiting certificate request"
- @ca.storeclientcsr(csr)
- end
- return ["", ""]
- end
- else
- raise "huh?"
- end
+ if nameary.nil?
+ Puppet.err(
+ "Invalid certificate request: could not retrieve server name"
+ )
+ return "invalid"
+ end
+
+ hostname = nameary[1]
+
+ unless @ca
+ Puppet.notice "Host #{hostname} asked for signing from non-CA master"
+ return ""
+ end
+
+ # We used to save the public key, but it's basically unnecessary
+ # and it mucks with the permissions requirements.
+ # save_pk(hostname, csr.public_key)
+
+ certfile = File.join(Puppet[:certdir], [hostname, "pem"].join("."))
+
+ # first check to see if we already have a signed cert for the host
+ cert, cacert = ca.getclientcert(hostname)
+ if cert and cacert
+ Puppet.info "Retrieving existing certificate for #{hostname}"
+ unless csr.public_key.to_s == cert.public_key.to_s
+ raise Puppet::Error, "Certificate request does not match existing certificate; run 'puppetca --clean #{hostname}'."
end
+ return [cert.to_pem, cacert.to_pem]
+ elsif @ca
+ if self.autosign?(hostname) or client.nil?
+ Puppet.info "Signing certificate for CA server" if client.nil?
+ # okay, we don't have a signed cert
+ # if we're a CA and autosign is turned on, then go ahead and sign
+ # the csr and return the results
+ Puppet.info "Signing certificate for #{hostname}"
+ cert, cacert = @ca.sign(csr)
+ #Puppet.info "Cert: #{cert.class}; Cacert: #{cacert.class}"
+ return [cert.to_pem, cacert.to_pem]
+ else # just write out the csr for later signing
+ if @ca.getclientcsr(hostname)
+ Puppet.info "Not replacing existing request from #{hostname}"
+ else
+ Puppet.notice "Host #{hostname} has a waiting certificate request"
+ @ca.storeclientcsr(csr)
+ end
+ return ["", ""]
+ end
+ else
+ raise "huh?"
+ end
+ end
+
+ private
- private
-
- # Save the public key.
- def save_pk(hostname, public_key)
- pkeyfile = File.join(Puppet[:publickeydir], [hostname, "pem"].join('.'))
-
- if FileTest.exists?(pkeyfile)
- currentkey = File.open(pkeyfile) { |k| k.read }
- unless currentkey == public_key.to_s
- raise Puppet::Error, "public keys for #{hostname} differ"
- end
- else
- File.open(pkeyfile, "w", 0644) { |f|
- f.print public_key.to_s
- }
- end
+ # Save the public key.
+ def save_pk(hostname, public_key)
+ pkeyfile = File.join(Puppet[:publickeydir], [hostname, "pem"].join('.'))
+
+ if FileTest.exists?(pkeyfile)
+ currentkey = File.open(pkeyfile) { |k| k.read }
+ unless currentkey == public_key.to_s
+ raise Puppet::Error, "public keys for #{hostname} differ"
end
+ else
+ File.open(pkeyfile, "w", 0644) { |f|
+ f.print public_key.to_s
+ }
+ end
end
+ end
end
diff --git a/lib/puppet/network/handler/filebucket.rb b/lib/puppet/network/handler/filebucket.rb
index c0693ad7a..6aaa2df1c 100755
--- a/lib/puppet/network/handler/filebucket.rb
+++ b/lib/puppet/network/handler/filebucket.rb
@@ -3,49 +3,49 @@ require 'digest/md5'
require 'puppet/external/base64'
class Puppet::Network::Handler # :nodoc:
- # Accept files and store them by md5 sum, returning the md5 sum back
- # to the client. Alternatively, accept an md5 sum and return the
- # associated content.
- class FileBucket < Handler
- desc "The interface to Puppet's FileBucket system. Can be used to store
- files in and retrieve files from a filebucket."
-
- @interface = XMLRPC::Service::Interface.new("puppetbucket") { |iface|
- iface.add_method("string addfile(string, string)")
- iface.add_method("string getfile(string)")
- }
-
- Puppet::Util.logmethods(self, true)
- attr_reader :name, :path
-
- def initialize(hash)
- @path = hash[:Path] || Puppet[:bucketdir]
- @name = "Filebucket[#{@path}]"
- end
-
- # Accept a file from a client and store it by md5 sum, returning
- # the sum.
- def addfile(contents, path, client = nil, clientip = nil)
- contents = Base64.decode64(contents) if client
- bucket = Puppet::FileBucket::File.new(contents)
- bucket.save
- end
-
- # Return the contents associated with a given md5 sum.
- def getfile(md5, client = nil, clientip = nil)
- bucket = Puppet::FileBucket::File.find("md5:#{md5}")
- contents = bucket.contents
-
- if client
- return Base64.encode64(contents)
- else
- return contents
- end
- end
-
- def to_s
- self.name
- end
+ # Accept files and store them by md5 sum, returning the md5 sum back
+ # to the client. Alternatively, accept an md5 sum and return the
+ # associated content.
+ class FileBucket < Handler
+ desc "The interface to Puppet's FileBucket system. Can be used to store
+ files in and retrieve files from a filebucket."
+
+ @interface = XMLRPC::Service::Interface.new("puppetbucket") { |iface|
+ iface.add_method("string addfile(string, string)")
+ iface.add_method("string getfile(string)")
+ }
+
+ Puppet::Util.logmethods(self, true)
+ attr_reader :name, :path
+
+ def initialize(hash)
+ @path = hash[:Path] || Puppet[:bucketdir]
+ @name = "Filebucket[#{@path}]"
end
+
+ # Accept a file from a client and store it by md5 sum, returning
+ # the sum.
+ def addfile(contents, path, client = nil, clientip = nil)
+ contents = Base64.decode64(contents) if client
+ bucket = Puppet::FileBucket::File.new(contents)
+ bucket.save
+ end
+
+ # Return the contents associated with a given md5 sum.
+ def getfile(md5, client = nil, clientip = nil)
+ bucket = Puppet::FileBucket::File.find("md5:#{md5}")
+ contents = bucket.contents
+
+ if client
+ return Base64.encode64(contents)
+ else
+ return contents
+ end
+ end
+
+ def to_s
+ self.name
+ end
+ end
end
diff --git a/lib/puppet/network/handler/fileserver.rb b/lib/puppet/network/handler/fileserver.rb
index 0a5082012..27b913ab9 100755
--- a/lib/puppet/network/handler/fileserver.rb
+++ b/lib/puppet/network/handler/fileserver.rb
@@ -9,717 +9,717 @@ require 'puppet/file_serving'
require 'puppet/file_serving/metadata'
class Puppet::Network::Handler
- AuthStoreError = Puppet::AuthStoreError
- class FileServerError < Puppet::Error; end
- class FileServer < Handler
- desc "The interface to Puppet's fileserving abilities."
+ AuthStoreError = Puppet::AuthStoreError
+ class FileServerError < Puppet::Error; end
+ class FileServer < Handler
+ desc "The interface to Puppet's fileserving abilities."
- attr_accessor :local
+ attr_accessor :local
- CHECKPARAMS = [:mode, :type, :owner, :group, :checksum]
+ CHECKPARAMS = [:mode, :type, :owner, :group, :checksum]
- # Special filserver module for puppet's module system
- MODULES = "modules"
- PLUGINS = "plugins"
+ # Special filserver module for puppet's module system
+ MODULES = "modules"
+ PLUGINS = "plugins"
- @interface = XMLRPC::Service::Interface.new("fileserver") { |iface|
- iface.add_method("string describe(string, string)")
- iface.add_method("string list(string, string, boolean, array)")
- iface.add_method("string retrieve(string, string)")
- }
+ @interface = XMLRPC::Service::Interface.new("fileserver") { |iface|
+ iface.add_method("string describe(string, string)")
+ iface.add_method("string list(string, string, boolean, array)")
+ iface.add_method("string retrieve(string, string)")
+ }
- def self.params
- CHECKPARAMS.dup
- end
+ def self.params
+ CHECKPARAMS.dup
+ end
- # If the configuration file exists, then create (if necessary) a LoadedFile
- # object to manage it; else, return nil.
- def configuration
- # Short-circuit the default case.
- return @configuration if defined?(@configuration)
+ # If the configuration file exists, then create (if necessary) a LoadedFile
+ # object to manage it; else, return nil.
+ def configuration
+ # Short-circuit the default case.
+ return @configuration if defined?(@configuration)
- config_path = @passed_configuration_path || Puppet[:fileserverconfig]
- return nil unless FileTest.exist?(config_path)
+ config_path = @passed_configuration_path || Puppet[:fileserverconfig]
+ return nil unless FileTest.exist?(config_path)
- # The file exists but we don't have a LoadedFile instance for it.
- @configuration = Puppet::Util::LoadedFile.new(config_path)
- end
+ # The file exists but we don't have a LoadedFile instance for it.
+ @configuration = Puppet::Util::LoadedFile.new(config_path)
+ end
- # Create our default mounts for modules and plugins. This is duplicated code,
- # but I'm not really worried about that.
- def create_default_mounts
- @mounts = {}
- Puppet.debug "No file server configuration file; autocreating #{MODULES} mount with default permissions"
- mount = Mount.new(MODULES)
- mount.allow("*")
- @mounts[MODULES] = mount
-
- Puppet.debug "No file server configuration file; autocreating #{PLUGINS} mount with default permissions"
- mount = PluginMount.new(PLUGINS)
- mount.allow("*")
- @mounts[PLUGINS] = mount
- end
+ # Create our default mounts for modules and plugins. This is duplicated code,
+ # but I'm not really worried about that.
+ def create_default_mounts
+ @mounts = {}
+ Puppet.debug "No file server configuration file; autocreating #{MODULES} mount with default permissions"
+ mount = Mount.new(MODULES)
+ mount.allow("*")
+ @mounts[MODULES] = mount
+
+ Puppet.debug "No file server configuration file; autocreating #{PLUGINS} mount with default permissions"
+ mount = PluginMount.new(PLUGINS)
+ mount.allow("*")
+ @mounts[PLUGINS] = mount
+ end
- # Describe a given file. This returns all of the manageable aspects
- # of that file.
- def describe(url, links = :follow, client = nil, clientip = nil)
- links = links.intern if links.is_a? String
+ # Describe a given file. This returns all of the manageable aspects
+ # of that file.
+ def describe(url, links = :follow, client = nil, clientip = nil)
+ links = links.intern if links.is_a? String
- mount, path = convert(url, client, clientip)
+ mount, path = convert(url, client, clientip)
- mount.debug("Describing #{url} for #{client}") if client
+ mount.debug("Describing #{url} for #{client}") if client
- # use the mount to resolve the path for us.
- return "" unless full_path = mount.file_path(path, client)
+ # use the mount to resolve the path for us.
+ return "" unless full_path = mount.file_path(path, client)
- metadata = Puppet::FileServing::Metadata.new(url, :path => full_path, :links => links)
+ metadata = Puppet::FileServing::Metadata.new(url, :path => full_path, :links => links)
- return "" unless metadata.exist?
+ return "" unless metadata.exist?
- begin
- metadata.collect
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err detail
- return ""
- end
+ begin
+ metadata.collect
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err detail
+ return ""
+ end
- metadata.attributes_with_tabs
- end
+ metadata.attributes_with_tabs
+ end
- # Create a new fileserving module.
- def initialize(hash = {})
- @mounts = {}
- @files = {}
+ # Create a new fileserving module.
+ def initialize(hash = {})
+ @mounts = {}
+ @files = {}
- @local = hash[:Local]
+ @local = hash[:Local]
- @noreadconfig = true if hash[:Config] == false
+ @noreadconfig = true if hash[:Config] == false
- @passed_configuration_path = hash[:Config]
+ @passed_configuration_path = hash[:Config]
- if hash.include?(:Mount)
- @passedconfig = true
- raise Puppet::DevError, "Invalid mount hash #{hash[:Mount].inspect}" unless hash[:Mount].is_a?(Hash)
+ if hash.include?(:Mount)
+ @passedconfig = true
+ raise Puppet::DevError, "Invalid mount hash #{hash[:Mount].inspect}" unless hash[:Mount].is_a?(Hash)
- hash[:Mount].each { |dir, name|
- self.mount(dir, name) if FileTest.exists?(dir)
- }
- self.mount(nil, MODULES)
- self.mount(nil, PLUGINS)
- else
- @passedconfig = false
- if configuration
- readconfig(false) # don't check the file the first time.
- else
- create_default_mounts
- end
- end
+ hash[:Mount].each { |dir, name|
+ self.mount(dir, name) if FileTest.exists?(dir)
+ }
+ self.mount(nil, MODULES)
+ self.mount(nil, PLUGINS)
+ else
+ @passedconfig = false
+ if configuration
+ readconfig(false) # don't check the file the first time.
+ else
+ create_default_mounts
end
+ end
+ end
- # List a specific directory's contents.
- def list(url, links = :ignore, recurse = false, ignore = false, client = nil, clientip = nil)
- mount, path = convert(url, client, clientip)
-
- mount.debug "Listing #{url} for #{client}" if client
+ # List a specific directory's contents.
+ def list(url, links = :ignore, recurse = false, ignore = false, client = nil, clientip = nil)
+ mount, path = convert(url, client, clientip)
- return "" unless mount.path_exists?(path, client)
+ mount.debug "Listing #{url} for #{client}" if client
- desc = mount.list(path, recurse, ignore, client)
+ return "" unless mount.path_exists?(path, client)
- if desc.length == 0
- mount.notice "Got no information on //#{mount}/#{path}"
- return ""
- end
-
- desc.collect { |sub| sub.join("\t") }.join("\n")
- end
+ desc = mount.list(path, recurse, ignore, client)
- def local?
- self.local
- end
+ if desc.length == 0
+ mount.notice "Got no information on //#{mount}/#{path}"
+ return ""
+ end
- # Is a given mount available?
- def mounted?(name)
- @mounts.include?(name)
- end
+ desc.collect { |sub| sub.join("\t") }.join("\n")
+ end
- # Mount a new directory with a name.
- def mount(path, name)
- if @mounts.include?(name)
- if @mounts[name] != path
- raise FileServerError, "#{@mounts[name].path} is already mounted at #{name}"
- else
- # it's already mounted; no problem
- return
- end
- end
+ def local?
+ self.local
+ end
- # Let the mounts do their own error-checking.
- @mounts[name] = Mount.new(name, path)
- @mounts[name].info "Mounted #{path}"
+ # Is a given mount available?
+ def mounted?(name)
+ @mounts.include?(name)
+ end
- @mounts[name]
+ # Mount a new directory with a name.
+ def mount(path, name)
+ if @mounts.include?(name)
+ if @mounts[name] != path
+ raise FileServerError, "#{@mounts[name].path} is already mounted at #{name}"
+ else
+ # it's already mounted; no problem
+ return
end
+ end
- # Retrieve a file from the local disk and pass it to the remote
- # client.
- def retrieve(url, links = :ignore, client = nil, clientip = nil)
- links = links.intern if links.is_a? String
-
- mount, path = convert(url, client, clientip)
+ # Let the mounts do their own error-checking.
+ @mounts[name] = Mount.new(name, path)
+ @mounts[name].info "Mounted #{path}"
- mount.info "Sending #{url} to #{client}" if client
-
- unless mount.path_exists?(path, client)
- mount.debug "#{mount} reported that #{path} does not exist"
- return ""
- end
-
- links = links.intern if links.is_a? String
+ @mounts[name]
+ end
- if links == :ignore and FileTest.symlink?(path)
- mount.debug "I think that #{path} is a symlink and we're ignoring them"
- return ""
- end
+ # Retrieve a file from the local disk and pass it to the remote
+ # client.
+ def retrieve(url, links = :ignore, client = nil, clientip = nil)
+ links = links.intern if links.is_a? String
- str = mount.read_file(path, client)
+ mount, path = convert(url, client, clientip)
- if @local
- return str
- else
- return CGI.escape(str)
- end
- end
+ mount.info "Sending #{url} to #{client}" if client
- def umount(name)
- @mounts.delete(name) if @mounts.include? name
- end
+ unless mount.path_exists?(path, client)
+ mount.debug "#{mount} reported that #{path} does not exist"
+ return ""
+ end
- private
+ links = links.intern if links.is_a? String
- def authcheck(file, mount, client, clientip)
- # If we're local, don't bother passing in information.
- if local?
- client = nil
- clientip = nil
- end
- unless mount.allowed?(client, clientip)
- mount.warning "#{client} cannot access #{file}"
- raise Puppet::AuthorizationError, "Cannot access #{mount}"
- end
- end
+ if links == :ignore and FileTest.symlink?(path)
+ mount.debug "I think that #{path} is a symlink and we're ignoring them"
+ return ""
+ end
- # Take a URL and some client info and return a mount and relative
- # path pair.
- #
- def convert(url, client, clientip)
- readconfig
+ str = mount.read_file(path, client)
- url = URI.unescape(url)
+ if @local
+ return str
+ else
+ return CGI.escape(str)
+ end
+ end
- mount, stub = splitpath(url, client)
+ def umount(name)
+ @mounts.delete(name) if @mounts.include? name
+ end
- authcheck(url, mount, client, clientip)
+ private
+
+ def authcheck(file, mount, client, clientip)
+ # If we're local, don't bother passing in information.
+ if local?
+ client = nil
+ clientip = nil
+ end
+ unless mount.allowed?(client, clientip)
+ mount.warning "#{client} cannot access #{file}"
+ raise Puppet::AuthorizationError, "Cannot access #{mount}"
+ end
+ end
- return mount, stub
- end
+ # Take a URL and some client info and return a mount and relative
+ # path pair.
+ #
+ def convert(url, client, clientip)
+ readconfig
- # Return the mount for the Puppet modules; allows file copying from
- # the modules.
- def modules_mount(module_name, client)
- # Find our environment, if we have one.
- unless hostname = (client || Facter.value("hostname"))
- raise ArgumentError, "Could not find hostname"
- end
- env = (node = Puppet::Node.find(hostname)) ? node.environment : nil
+ url = URI.unescape(url)
- # And use the environment to look up the module.
- (mod = Puppet::Node::Environment.new(env).module(module_name) and mod.files?) ? @mounts[MODULES].copy(mod.name, mod.file_directory) : nil
- end
+ mount, stub = splitpath(url, client)
- # Read the configuration file.
- def readconfig(check = true)
- return if @noreadconfig
-
- return unless configuration
-
- return if check and ! @configuration.changed?
-
- newmounts = {}
- begin
- File.open(@configuration.file) { |f|
- mount = nil
- count = 1
- f.each { |line|
- case line
- when /^\s*#/; next # skip comments
- when /^\s*$/; next # skip blank lines
- when /\[([-\w]+)\]/
- name = $1
- raise FileServerError, "#{newmounts[name]} is already mounted as #{name} in #{@configuration.file}" if newmounts.include?(name)
- mount = Mount.new(name)
- newmounts[name] = mount
- when /^\s*(\w+)\s+(.+)$/
- var = $1
- value = $2
- case var
- when "path"
- if mount.name == MODULES
- Puppet.warning "The '#{mount.name}' module can not have a path. Ignoring attempt to set it"
- else
- begin
- mount.path = value
- rescue FileServerError => detail
- Puppet.err "Removing mount #{mount.name}: #{detail}"
- newmounts.delete(mount.name)
- end
- end
- when "allow"
- value.split(/\s*,\s*/).each { |val|
- begin
- mount.info "allowing #{val} access"
- mount.allow(val)
- rescue AuthStoreError => detail
- puts detail.backtrace if Puppet[:trace]
-
- raise FileServerError.new(
- detail.to_s,
-
- count, @configuration.file)
- end
- }
- when "deny"
- value.split(/\s*,\s*/).each { |val|
- begin
- mount.info "denying #{val} access"
- mount.deny(val)
- rescue AuthStoreError => detail
-
- raise FileServerError.new(
- detail.to_s,
-
- count, @configuration.file)
- end
- }
- else
- raise FileServerError.new("Invalid argument '#{var}'", count, @configuration.file)
- end
- else
- raise FileServerError.new("Invalid line '#{line.chomp}'", count, @configuration.file)
- end
- count += 1
- }
- }
- rescue Errno::EACCES => detail
- Puppet.err "FileServer error: Cannot read #{@configuration}; cannot serve"
- #raise Puppet::Error, "Cannot read #{@configuration}"
- rescue Errno::ENOENT => detail
- Puppet.err "FileServer error: '#{@configuration}' does not exist; cannot serve"
- end
+ authcheck(url, mount, client, clientip)
- unless newmounts[MODULES]
- Puppet.debug "No #{MODULES} mount given; autocreating with default permissions"
- mount = Mount.new(MODULES)
- mount.allow("*")
- newmounts[MODULES] = mount
- end
-
- unless newmounts[PLUGINS]
- Puppet.debug "No #{PLUGINS} mount given; autocreating with default permissions"
- mount = PluginMount.new(PLUGINS)
- mount.allow("*")
- newmounts[PLUGINS] = mount
- end
-
- unless newmounts[PLUGINS].valid?
- Puppet.debug "No path given for #{PLUGINS} mount; creating a special PluginMount"
- # We end up here if the user has specified access rules for
- # the plugins mount, without specifying a path (which means
- # they want to have the default behaviour for the mount, but
- # special access control). So we need to move all the
- # user-specified access controls into the new PluginMount
- # object...
- mount = PluginMount.new(PLUGINS)
- # Yes, you're allowed to hate me for this.
-
- mount.instance_variable_set(
- :@declarations,
-
- newmounts[PLUGINS].instance_variable_get(:@declarations)
- )
- newmounts[PLUGINS] = mount
- end
+ return mount, stub
+ end
- # Verify each of the mounts are valid.
- # We let the check raise an error, so that it can raise an error
- # pointing to the specific problem.
- newmounts.each { |name, mount|
- raise FileServerError, "Invalid mount #{name}" unless mount.valid?
- }
- @mounts = newmounts
- end
+ # Return the mount for the Puppet modules; allows file copying from
+ # the modules.
+ def modules_mount(module_name, client)
+ # Find our environment, if we have one.
+ unless hostname = (client || Facter.value("hostname"))
+ raise ArgumentError, "Could not find hostname"
+ end
+ env = (node = Puppet::Node.find(hostname)) ? node.environment : nil
+
+ # And use the environment to look up the module.
+ (mod = Puppet::Node::Environment.new(env).module(module_name) and mod.files?) ? @mounts[MODULES].copy(mod.name, mod.file_directory) : nil
+ end
- # Split the path into the separate mount point and path.
- def splitpath(dir, client)
- # the dir is based on one of the mounts
- # so first retrieve the mount path
- mount = nil
- path = nil
- if dir =~ %r{/([-\w]+)}
- # Strip off the mount name.
- mount_name, path = dir.sub(%r{^/}, '').split(File::Separator, 2)
-
- unless mount = modules_mount(mount_name, client)
- unless mount = @mounts[mount_name]
- raise FileServerError, "Fileserver module '#{mount_name}' not mounted"
- end
+ # Read the configuration file.
+ def readconfig(check = true)
+ return if @noreadconfig
+
+ return unless configuration
+
+ return if check and ! @configuration.changed?
+
+ newmounts = {}
+ begin
+ File.open(@configuration.file) { |f|
+ mount = nil
+ count = 1
+ f.each { |line|
+ case line
+ when /^\s*#/; next # skip comments
+ when /^\s*$/; next # skip blank lines
+ when /\[([-\w]+)\]/
+ name = $1
+ raise FileServerError, "#{newmounts[name]} is already mounted as #{name} in #{@configuration.file}" if newmounts.include?(name)
+ mount = Mount.new(name)
+ newmounts[name] = mount
+ when /^\s*(\w+)\s+(.+)$/
+ var = $1
+ value = $2
+ case var
+ when "path"
+ if mount.name == MODULES
+ Puppet.warning "The '#{mount.name}' module can not have a path. Ignoring attempt to set it"
+ else
+ begin
+ mount.path = value
+ rescue FileServerError => detail
+ Puppet.err "Removing mount #{mount.name}: #{detail}"
+ newmounts.delete(mount.name)
+ end
end
+ when "allow"
+ value.split(/\s*,\s*/).each { |val|
+ begin
+ mount.info "allowing #{val} access"
+ mount.allow(val)
+ rescue AuthStoreError => detail
+ puts detail.backtrace if Puppet[:trace]
+
+ raise FileServerError.new(
+ detail.to_s,
+
+ count, @configuration.file)
+ end
+ }
+ when "deny"
+ value.split(/\s*,\s*/).each { |val|
+ begin
+ mount.info "denying #{val} access"
+ mount.deny(val)
+ rescue AuthStoreError => detail
+
+ raise FileServerError.new(
+ detail.to_s,
+
+ count, @configuration.file)
+ end
+ }
+ else
+ raise FileServerError.new("Invalid argument '#{var}'", count, @configuration.file)
+ end
else
- raise FileServerError, "Fileserver error: Invalid path '#{dir}'"
- end
-
- if path.nil? or path == ''
- path = '/'
- elsif path
- # Remove any double slashes that might have occurred
- path = URI.unescape(path.gsub(/\/\//, "/"))
+ raise FileServerError.new("Invalid line '#{line.chomp}'", count, @configuration.file)
end
+ count += 1
+ }
+ }
+ rescue Errno::EACCES => detail
+ Puppet.err "FileServer error: Cannot read #{@configuration}; cannot serve"
+ #raise Puppet::Error, "Cannot read #{@configuration}"
+ rescue Errno::ENOENT => detail
+ Puppet.err "FileServer error: '#{@configuration}' does not exist; cannot serve"
+ end
+
+ unless newmounts[MODULES]
+ Puppet.debug "No #{MODULES} mount given; autocreating with default permissions"
+ mount = Mount.new(MODULES)
+ mount.allow("*")
+ newmounts[MODULES] = mount
+ end
+
+ unless newmounts[PLUGINS]
+ Puppet.debug "No #{PLUGINS} mount given; autocreating with default permissions"
+ mount = PluginMount.new(PLUGINS)
+ mount.allow("*")
+ newmounts[PLUGINS] = mount
+ end
+
+ unless newmounts[PLUGINS].valid?
+ Puppet.debug "No path given for #{PLUGINS} mount; creating a special PluginMount"
+ # We end up here if the user has specified access rules for
+ # the plugins mount, without specifying a path (which means
+ # they want to have the default behaviour for the mount, but
+ # special access control). So we need to move all the
+ # user-specified access controls into the new PluginMount
+ # object...
+ mount = PluginMount.new(PLUGINS)
+ # Yes, you're allowed to hate me for this.
+
+ mount.instance_variable_set(
+ :@declarations,
+
+ newmounts[PLUGINS].instance_variable_get(:@declarations)
+ )
+ newmounts[PLUGINS] = mount
+ end
+
+ # Verify each of the mounts are valid.
+ # We let the check raise an error, so that it can raise an error
+ # pointing to the specific problem.
+ newmounts.each { |name, mount|
+ raise FileServerError, "Invalid mount #{name}" unless mount.valid?
+ }
+ @mounts = newmounts
+ end
- return mount, path
- end
-
- def to_s
- "fileserver"
+ # Split the path into the separate mount point and path.
+ def splitpath(dir, client)
+ # the dir is based on one of the mounts
+ # so first retrieve the mount path
+ mount = nil
+ path = nil
+ if dir =~ %r{/([-\w]+)}
+ # Strip off the mount name.
+ mount_name, path = dir.sub(%r{^/}, '').split(File::Separator, 2)
+
+ unless mount = modules_mount(mount_name, client)
+ unless mount = @mounts[mount_name]
+ raise FileServerError, "Fileserver module '#{mount_name}' not mounted"
+ end
end
+ else
+ raise FileServerError, "Fileserver error: Invalid path '#{dir}'"
+ end
+
+ if path.nil? or path == ''
+ path = '/'
+ elsif path
+ # Remove any double slashes that might have occurred
+ path = URI.unescape(path.gsub(/\/\//, "/"))
+ end
+
+ return mount, path
+ end
- # A simple class for wrapping mount points. Instances of this class
- # don't know about the enclosing object; they're mainly just used for
- # authorization.
- class Mount < Puppet::Network::AuthStore
- attr_reader :name
-
- @@syncs = {}
-
- @@files = {}
-
- Puppet::Util.logmethods(self, true)
-
- # Create a map for a specific client.
- def clientmap(client)
- {
- "h" => client.sub(/\..*$/, ""),
- "H" => client,
- "d" => client.sub(/[^.]+\./, "") # domain name
- }
- end
-
- # Replace % patterns as appropriate.
- def expand(path, client = nil)
- # This map should probably be moved into a method.
- map = nil
-
- if client
- map = clientmap(client)
- else
- Puppet.notice "No client; expanding '#{path}' with local host"
- # Else, use the local information
- map = localmap
- end
- path.gsub(/%(.)/) do |v|
- key = $1
- if key == "%"
- "%"
- else
- map[key] || v
- end
- end
- end
-
- # Do we have any patterns in our path, yo?
- def expandable?
- if defined?(@expandable)
- @expandable
- else
- false
- end
- end
-
- # Return a fully qualified path, given a short path and
- # possibly a client name.
- def file_path(relative_path, node = nil)
- full_path = path(node)
-
- unless full_path
- p self
- raise ArgumentError.new("Mounts without paths are not usable") unless full_path
- end
-
- # If there's no relative path name, then we're serving the mount itself.
- return full_path unless relative_path and relative_path != "/"
-
- File.join(full_path, relative_path)
- end
-
- # Create out object. It must have a name.
- def initialize(name, path = nil)
- unless name =~ %r{^[-\w]+$}
- raise FileServerError, "Invalid name format '#{name}'"
- end
- @name = name
-
- if path
- self.path = path
- else
- @path = nil
- end
-
- @files = {}
-
- super()
- end
-
- def fileobj(path, links, client)
- obj = nil
- if obj = @files[file_path(path, client)]
- # This can only happen in local fileserving, but it's an
- # important one. It'd be nice if we didn't just set
- # the check params every time, but I'm not sure it's worth
- # the effort.
- obj[:audit] = CHECKPARAMS
- else
-
- obj = Puppet::Type.type(:file).new(
-
- :name => file_path(path, client),
-
- :audit => CHECKPARAMS
- )
- @files[file_path(path, client)] = obj
- end
-
- if links == :manage
- links = :follow
- end
+ def to_s
+ "fileserver"
+ end
- # This, ah, might be completely redundant
- obj[:links] = links unless obj[:links] == links
+ # A simple class for wrapping mount points. Instances of this class
+ # don't know about the enclosing object; they're mainly just used for
+ # authorization.
+ class Mount < Puppet::Network::AuthStore
+ attr_reader :name
- obj
- end
+ @@syncs = {}
- # Read the contents of the file at the relative path given.
- def read_file(relpath, client)
- File.read(file_path(relpath, client))
- end
+ @@files = {}
- # Cache this manufactured map, since if it's used it's likely
- # to get used a lot.
- def localmap
- unless defined?(@@localmap)
- @@localmap = {
- "h" => Facter.value("hostname"),
- "H" => [Facter.value("hostname"),
- Facter.value("domain")].join("."),
- "d" => Facter.value("domain")
- }
- end
- @@localmap
- end
-
- # Return the path as appropriate, expanding as necessary.
- def path(client = nil)
- if expandable?
- return expand(@path, client)
- else
- return @path
- end
- end
+ Puppet::Util.logmethods(self, true)
- # Set the path.
- def path=(path)
- # FIXME: For now, just don't validate paths with replacement
- # patterns in them.
- if path =~ /%./
- # Mark that we're expandable.
- @expandable = true
- else
- raise FileServerError, "#{path} does not exist" unless FileTest.exists?(path)
- raise FileServerError, "#{path} is not a directory" unless FileTest.directory?(path)
- raise FileServerError, "#{path} is not readable" unless FileTest.readable?(path)
- @expandable = false
- end
- @path = path
- end
-
- # Verify that the path given exists within this mount's subtree.
- #
- def path_exists?(relpath, client = nil)
- File.exists?(file_path(relpath, client))
- end
+ # Create a map for a specific client.
+ def clientmap(client)
+ {
+ "h" => client.sub(/\..*$/, ""),
+ "H" => client,
+ "d" => client.sub(/[^.]+\./, "") # domain name
+ }
+ end
+
+ # Replace % patterns as appropriate.
+ def expand(path, client = nil)
+ # This map should probably be moved into a method.
+ map = nil
+
+ if client
+ map = clientmap(client)
+ else
+ Puppet.notice "No client; expanding '#{path}' with local host"
+ # Else, use the local information
+ map = localmap
+ end
+ path.gsub(/%(.)/) do |v|
+ key = $1
+ if key == "%"
+ "%"
+ else
+ map[key] || v
+ end
+ end
+ end
+
+ # Do we have any patterns in our path, yo?
+ def expandable?
+ if defined?(@expandable)
+ @expandable
+ else
+ false
+ end
+ end
- # Return the current values for the object.
- def properties(obj)
- obj.retrieve.inject({}) { |props, ary| props[ary[0].name] = ary[1]; props }
- end
+ # Return a fully qualified path, given a short path and
+ # possibly a client name.
+ def file_path(relative_path, node = nil)
+ full_path = path(node)
- # Retrieve a specific directory relative to a mount point.
- # If they pass in a client, then expand as necessary.
- def subdir(dir = nil, client = nil)
- basedir = self.path(client)
+ unless full_path
+ p self
+ raise ArgumentError.new("Mounts without paths are not usable") unless full_path
+ end
- dirname = if dir
- File.join(basedir, *dir.split("/"))
- else
- basedir
- end
+ # If there's no relative path name, then we're serving the mount itself.
+ return full_path unless relative_path and relative_path != "/"
- dirname
- end
+ File.join(full_path, relative_path)
+ end
- def sync(path)
- @@syncs[path] ||= Sync.new
- @@syncs[path]
- end
+ # Create out object. It must have a name.
+ def initialize(name, path = nil)
+ unless name =~ %r{^[-\w]+$}
+ raise FileServerError, "Invalid name format '#{name}'"
+ end
+ @name = name
- def to_s
- "mount[#{@name}]"
- end
+ if path
+ self.path = path
+ else
+ @path = nil
+ end
- # Verify our configuration is valid. This should really check to
- # make sure at least someone will be allowed, but, eh.
- def valid?
- if name == MODULES
- return @path.nil?
- else
- return ! @path.nil?
- end
- end
+ @files = {}
- # Return a new mount with the same properties as +self+, except
- # with a different name and path.
- def copy(name, path)
- result = self.clone
- result.path = path
- result.instance_variable_set(:@name, name)
- result
- end
+ super()
+ end
- # List the contents of the relative path +relpath+ of this mount.
- #
- # +recurse+ is the number of levels to recurse into the tree,
- # or false to provide no recursion or true if you just want to
- # go for broke.
- #
- # +ignore+ is an array of filenames to ignore when traversing
- # the list.
- #
- # The return value of this method is a complex nest of arrays,
- # which describes a directory tree. Each file or directory is
- # represented by an array, where the first element is the path
- # of the file (relative to the root of the mount), and the
- # second element is the type. A directory is represented by an
- # array as well, where the first element is a "directory" array,
- # while the remaining elements are other file or directory
- # arrays. Confusing? Hell yes. As an added bonus, all names
- # must start with a slash, because... well, I'm fairly certain
- # a complete explanation would involve the words "crack pipe"
- # and "bad batch".
- #
- def list(relpath, recurse, ignore, client = nil)
- abspath = file_path(relpath, client)
- if FileTest.exists?(abspath)
- if FileTest.directory?(abspath) and recurse
- return reclist(abspath, recurse, ignore)
- else
- return [["/", File.stat(abspath).ftype]]
- end
- end
- nil
- end
+ def fileobj(path, links, client)
+ obj = nil
+ if obj = @files[file_path(path, client)]
+ # This can only happen in local fileserving, but it's an
+ # important one. It'd be nice if we didn't just set
+ # the check params every time, but I'm not sure it's worth
+ # the effort.
+ obj[:audit] = CHECKPARAMS
+ else
- def reclist(abspath, recurse, ignore)
- require 'puppet/file_serving'
- require 'puppet/file_serving/fileset'
- if recurse.is_a?(Fixnum)
- args = { :recurse => true, :recurselimit => recurse, :links => :follow }
- else
- args = { :recurse => recurse, :links => :follow }
- end
- args[:ignore] = ignore if ignore
- fs = Puppet::FileServing::Fileset.new(abspath, args)
- ary = fs.files.collect do |file|
- if file == "."
- file = "/"
- else
- file = File.join("/", file )
- end
- stat = fs.stat(File.join(abspath, file))
- next if stat.nil?
- [ file, stat.ftype ]
- end
+ obj = Puppet::Type.type(:file).new(
- ary.compact
- end
+ :name => file_path(path, client),
+ :audit => CHECKPARAMS
+ )
+ @files[file_path(path, client)] = obj
end
- # A special mount class specifically for the plugins mount -- just
- # has some magic to effectively do a union mount of the 'plugins'
- # directory of all modules.
- #
- class PluginMount < Mount
- def path(client)
- ''
- end
-
- def mod_path_exists?(mod, relpath, client = nil)
- ! mod.plugin(relpath).nil?
- end
+ if links == :manage
+ links = :follow
+ end
- def path_exists?(relpath, client = nil)
- !valid_modules(client).find { |mod| mod.plugin(relpath) }.nil?
- end
+ # This, ah, might be completely redundant
+ obj[:links] = links unless obj[:links] == links
+
+ obj
+ end
+
+ # Read the contents of the file at the relative path given.
+ def read_file(relpath, client)
+ File.read(file_path(relpath, client))
+ end
+
+ # Cache this manufactured map, since if it's used it's likely
+ # to get used a lot.
+ def localmap
+ unless defined?(@@localmap)
+ @@localmap = {
+ "h" => Facter.value("hostname"),
+ "H" => [Facter.value("hostname"),
+ Facter.value("domain")].join("."),
+ "d" => Facter.value("domain")
+ }
+ end
+ @@localmap
+ end
+
+ # Return the path as appropriate, expanding as necessary.
+ def path(client = nil)
+ if expandable?
+ return expand(@path, client)
+ else
+ return @path
+ end
+ end
+
+ # Set the path.
+ def path=(path)
+ # FIXME: For now, just don't validate paths with replacement
+ # patterns in them.
+ if path =~ /%./
+ # Mark that we're expandable.
+ @expandable = true
+ else
+ raise FileServerError, "#{path} does not exist" unless FileTest.exists?(path)
+ raise FileServerError, "#{path} is not a directory" unless FileTest.directory?(path)
+ raise FileServerError, "#{path} is not readable" unless FileTest.readable?(path)
+ @expandable = false
+ end
+ @path = path
+ end
+
+ # Verify that the path given exists within this mount's subtree.
+ #
+ def path_exists?(relpath, client = nil)
+ File.exists?(file_path(relpath, client))
+ end
+
+ # Return the current values for the object.
+ def properties(obj)
+ obj.retrieve.inject({}) { |props, ary| props[ary[0].name] = ary[1]; props }
+ end
+
+ # Retrieve a specific directory relative to a mount point.
+ # If they pass in a client, then expand as necessary.
+ def subdir(dir = nil, client = nil)
+ basedir = self.path(client)
+
+ dirname = if dir
+ File.join(basedir, *dir.split("/"))
+ else
+ basedir
+ end
- def valid?
- true
- end
+ dirname
+ end
+
+ def sync(path)
+ @@syncs[path] ||= Sync.new
+ @@syncs[path]
+ end
+
+ def to_s
+ "mount[#{@name}]"
+ end
+
+ # Verify our configuration is valid. This should really check to
+ # make sure at least someone will be allowed, but, eh.
+ def valid?
+ if name == MODULES
+ return @path.nil?
+ else
+ return ! @path.nil?
+ end
+ end
+
+ # Return a new mount with the same properties as +self+, except
+ # with a different name and path.
+ def copy(name, path)
+ result = self.clone
+ result.path = path
+ result.instance_variable_set(:@name, name)
+ result
+ end
+
+ # List the contents of the relative path +relpath+ of this mount.
+ #
+ # +recurse+ is the number of levels to recurse into the tree,
+ # or false to provide no recursion or true if you just want to
+ # go for broke.
+ #
+ # +ignore+ is an array of filenames to ignore when traversing
+ # the list.
+ #
+ # The return value of this method is a complex nest of arrays,
+ # which describes a directory tree. Each file or directory is
+ # represented by an array, where the first element is the path
+ # of the file (relative to the root of the mount), and the
+ # second element is the type. A directory is represented by an
+ # array as well, where the first element is a "directory" array,
+ # while the remaining elements are other file or directory
+ # arrays. Confusing? Hell yes. As an added bonus, all names
+ # must start with a slash, because... well, I'm fairly certain
+ # a complete explanation would involve the words "crack pipe"
+ # and "bad batch".
+ #
+ def list(relpath, recurse, ignore, client = nil)
+ abspath = file_path(relpath, client)
+ if FileTest.exists?(abspath)
+ if FileTest.directory?(abspath) and recurse
+ return reclist(abspath, recurse, ignore)
+ else
+ return [["/", File.stat(abspath).ftype]]
+ end
+ end
+ nil
+ end
+
+ def reclist(abspath, recurse, ignore)
+ require 'puppet/file_serving'
+ require 'puppet/file_serving/fileset'
+ if recurse.is_a?(Fixnum)
+ args = { :recurse => true, :recurselimit => recurse, :links => :follow }
+ else
+ args = { :recurse => recurse, :links => :follow }
+ end
+ args[:ignore] = ignore if ignore
+ fs = Puppet::FileServing::Fileset.new(abspath, args)
+ ary = fs.files.collect do |file|
+ if file == "."
+ file = "/"
+ else
+ file = File.join("/", file )
+ end
+ stat = fs.stat(File.join(abspath, file))
+ next if stat.nil?
+ [ file, stat.ftype ]
+ end
- def mod_file_path(mod, relpath, client = nil)
- File.join(mod, PLUGINS, relpath)
- end
+ ary.compact
+ end
- def file_path(relpath, client = nil)
- return nil unless mod = valid_modules(client).find { |m| m.plugin(relpath) }
- mod.plugin(relpath)
- end
+ end
- # create a list of files by merging all modules
- def list(relpath, recurse, ignore, client = nil)
- result = []
- valid_modules(client).each do |mod|
- if modpath = mod.plugin(relpath)
- if FileTest.directory?(modpath) and recurse
- ary = reclist(modpath, recurse, ignore)
- ary ||= []
- result += ary
- else
- result += [["/", File.stat(modpath).ftype]]
- end
- end
- end
- result
+ # A special mount class specifically for the plugins mount -- just
+ # has some magic to effectively do a union mount of the 'plugins'
+ # directory of all modules.
+ #
+ class PluginMount < Mount
+ def path(client)
+ ''
+ end
+
+ def mod_path_exists?(mod, relpath, client = nil)
+ ! mod.plugin(relpath).nil?
+ end
+
+ def path_exists?(relpath, client = nil)
+ !valid_modules(client).find { |mod| mod.plugin(relpath) }.nil?
+ end
+
+ def valid?
+ true
+ end
+
+ def mod_file_path(mod, relpath, client = nil)
+ File.join(mod, PLUGINS, relpath)
+ end
+
+ def file_path(relpath, client = nil)
+ return nil unless mod = valid_modules(client).find { |m| m.plugin(relpath) }
+ mod.plugin(relpath)
+ end
+
+ # create a list of files by merging all modules
+ def list(relpath, recurse, ignore, client = nil)
+ result = []
+ valid_modules(client).each do |mod|
+ if modpath = mod.plugin(relpath)
+ if FileTest.directory?(modpath) and recurse
+ ary = reclist(modpath, recurse, ignore)
+ ary ||= []
+ result += ary
+ else
+ result += [["/", File.stat(modpath).ftype]]
end
+ end
+ end
+ result
+ end
- private
- def valid_modules(client)
- Puppet::Node::Environment.new.modules.find_all { |mod| mod.exist? }
- end
+ private
+ def valid_modules(client)
+ Puppet::Node::Environment.new.modules.find_all { |mod| mod.exist? }
+ end
- def add_to_filetree(f, filetree)
- first, rest = f.split(File::SEPARATOR, 2)
- end
- end
+ def add_to_filetree(f, filetree)
+ first, rest = f.split(File::SEPARATOR, 2)
+ end
end
+ end
end
diff --git a/lib/puppet/network/handler/master.rb b/lib/puppet/network/handler/master.rb
index 6696df448..c21aafafc 100644
--- a/lib/puppet/network/handler/master.rb
+++ b/lib/puppet/network/handler/master.rb
@@ -5,85 +5,85 @@ require 'xmlrpc/server'
require 'yaml'
class Puppet::Network::Handler
- class MasterError < Puppet::Error; end
- class Master < Handler
- desc "Puppet's configuration interface. Used for all interactions related to
- generating client configurations."
+ class MasterError < Puppet::Error; end
+ class Master < Handler
+ desc "Puppet's configuration interface. Used for all interactions related to
+ generating client configurations."
- include Puppet::Util
+ include Puppet::Util
- attr_accessor :ast
- attr_reader :ca
+ attr_accessor :ast
+ attr_reader :ca
- @interface = XMLRPC::Service::Interface.new("puppetmaster") { |iface|
- iface.add_method("string getconfig(string)")
- iface.add_method("int freshness()")
- }
+ @interface = XMLRPC::Service::Interface.new("puppetmaster") { |iface|
+ iface.add_method("string getconfig(string)")
+ iface.add_method("int freshness()")
+ }
- # Tell a client whether there's a fresh config for it
- def freshness(client = nil, clientip = nil)
- # Always force a recompile. Newer clients shouldn't do this (as of April 2008).
- Time.now.to_i
- end
+ # Tell a client whether there's a fresh config for it
+ def freshness(client = nil, clientip = nil)
+ # Always force a recompile. Newer clients shouldn't do this (as of April 2008).
+ Time.now.to_i
+ end
- def initialize(hash = {})
- args = {}
+ def initialize(hash = {})
+ args = {}
- @local = hash[:Local]
+ @local = hash[:Local]
- args[:Local] = true
+ args[:Local] = true
- @ca = (hash.include?(:CA) and hash[:CA]) ? Puppet::SSLCertificates::CA.new : nil
+ @ca = (hash.include?(:CA) and hash[:CA]) ? Puppet::SSLCertificates::CA.new : nil
- # This is only used by the cfengine module, or if --loadclasses was
- # specified in +puppet+.
- args[:Classes] = hash[:Classes] if hash.include?(:Classes)
- end
+ # This is only used by the cfengine module, or if --loadclasses was
+ # specified in +puppet+.
+ args[:Classes] = hash[:Classes] if hash.include?(:Classes)
+ end
- # Call our various handlers; this handler is getting deprecated.
- def getconfig(facts, format = "marshal", client = nil, clientip = nil)
- facts = decode_facts(facts)
+ # Call our various handlers; this handler is getting deprecated.
+ def getconfig(facts, format = "marshal", client = nil, clientip = nil)
+ facts = decode_facts(facts)
- client ||= facts["hostname"]
+ client ||= facts["hostname"]
- # Pass the facts to the fact handler
- Puppet::Node::Facts.new(client, facts).save unless local?
+ # Pass the facts to the fact handler
+ Puppet::Node::Facts.new(client, facts).save unless local?
- catalog = Puppet::Resource::Catalog.find(client)
+ catalog = Puppet::Resource::Catalog.find(client)
- case format
- when "yaml"
- return CGI.escape(catalog.extract.to_yaml)
- when "marshal"
- return CGI.escape(Marshal.dump(catalog.extract))
- else
- raise "Invalid markup format '#{format}'"
- end
- end
+ case format
+ when "yaml"
+ return CGI.escape(catalog.extract.to_yaml)
+ when "marshal"
+ return CGI.escape(Marshal.dump(catalog.extract))
+ else
+ raise "Invalid markup format '#{format}'"
+ end
+ end
- #
- def decode_facts(facts)
- if @local
- # we don't need to do anything, since we should already
- # have raw objects
- Puppet.debug "Our client is local"
- else
- Puppet.debug "Our client is remote"
-
- begin
- facts = YAML.load(CGI.unescape(facts))
- rescue => detail
- raise XMLRPC::FaultException.new(
- 1, "Could not rebuild facts"
- )
- end
- end
-
- facts
+ #
+ def decode_facts(facts)
+ if @local
+ # we don't need to do anything, since we should already
+ # have raw objects
+ Puppet.debug "Our client is local"
+ else
+ Puppet.debug "Our client is remote"
+
+ begin
+ facts = YAML.load(CGI.unescape(facts))
+ rescue => detail
+ raise XMLRPC::FaultException.new(
+ 1, "Could not rebuild facts"
+ )
end
+ end
- # Translate our configuration appropriately for sending back to a client.
- def translate(config)
- end
+ facts
+ end
+
+ # Translate our configuration appropriately for sending back to a client.
+ def translate(config)
end
+ end
end
diff --git a/lib/puppet/network/handler/report.rb b/lib/puppet/network/handler/report.rb
index d935d3822..cdd6c8be4 100755
--- a/lib/puppet/network/handler/report.rb
+++ b/lib/puppet/network/handler/report.rb
@@ -3,78 +3,78 @@ require 'puppet/reports'
# A simple server for triggering a new run on a Puppet client.
class Puppet::Network::Handler
- class Report < Handler
- desc "Accepts a Puppet transaction report and processes it."
+ class Report < Handler
+ desc "Accepts a Puppet transaction report and processes it."
- @interface = XMLRPC::Service::Interface.new("puppetreports") { |iface|
- iface.add_method("string report(array)")
- }
+ @interface = XMLRPC::Service::Interface.new("puppetreports") { |iface|
+ iface.add_method("string report(array)")
+ }
- # Add a new report type.
- def self.newreport(name, options = {}, &block)
- Puppet.warning "The interface for registering report types has changed; use Puppet::Reports.register_report for report type #{name}"
- Puppet::Reports.register_report(name, options, &block)
- end
+ # Add a new report type.
+ def self.newreport(name, options = {}, &block)
+ Puppet.warning "The interface for registering report types has changed; use Puppet::Reports.register_report for report type #{name}"
+ Puppet::Reports.register_report(name, options, &block)
+ end
- def initialize(*args)
- super
- Puppet.settings.use(:main, :reporting, :metrics)
- end
+ def initialize(*args)
+ super
+ Puppet.settings.use(:main, :reporting, :metrics)
+ end
- # Accept a report from a client.
- def report(report, client = nil, clientip = nil)
- # Unescape the report
- report = CGI.unescape(report) unless @local
+ # Accept a report from a client.
+ def report(report, client = nil, clientip = nil)
+ # Unescape the report
+ report = CGI.unescape(report) unless @local
- Puppet.info "Processing reports #{reports().join(", ")} for #{client}"
- begin
- process(report)
- rescue => detail
- Puppet.err "Could not process report for #{client}: #{detail}"
- puts detail.backtrace if Puppet[:trace]
- end
- end
+ Puppet.info "Processing reports #{reports().join(", ")} for #{client}"
+ begin
+ process(report)
+ rescue => detail
+ Puppet.err "Could not process report for #{client}: #{detail}"
+ puts detail.backtrace if Puppet[:trace]
+ end
+ end
- private
+ private
- # Process the report using all of the existing hooks.
- def process(yaml)
- return if Puppet[:reports] == "none"
+ # Process the report using all of the existing hooks.
+ def process(yaml)
+ return if Puppet[:reports] == "none"
- # First convert the report to real objects
- begin
- report = YAML.load(yaml)
- rescue => detail
- Puppet.warning "Could not load report: #{detail}"
- return
- end
+ # First convert the report to real objects
+ begin
+ report = YAML.load(yaml)
+ rescue => detail
+ Puppet.warning "Could not load report: #{detail}"
+ return
+ end
- # Used for those reports that accept yaml
- client = report.host
+ # Used for those reports that accept yaml
+ client = report.host
- reports.each do |name|
- if mod = Puppet::Reports.report(name)
- # We have to use a dup because we're including a module in the
- # report.
- newrep = report.dup
- begin
- newrep.extend(mod)
- newrep.process
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Report #{name} failed: #{detail}"
- end
- else
- Puppet.warning "No report named '#{name}'"
- end
- end
+ reports.each do |name|
+ if mod = Puppet::Reports.report(name)
+ # We have to use a dup because we're including a module in the
+ # report.
+ newrep = report.dup
+ begin
+ newrep.extend(mod)
+ newrep.process
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Report #{name} failed: #{detail}"
+ end
+ else
+ Puppet.warning "No report named '#{name}'"
end
+ end
+ end
- # Handle the parsing of the reports attribute.
- def reports
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
- end
+ # Handle the parsing of the reports attribute.
+ def reports
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = Puppet[:reports].gsub(/(^\s+)|(\s+$)/, '').split(/\s*,\s*/)
end
+ end
end
diff --git a/lib/puppet/network/handler/runner.rb b/lib/puppet/network/handler/runner.rb
index bc1a07ac5..b02d3a548 100755
--- a/lib/puppet/network/handler/runner.rb
+++ b/lib/puppet/network/handler/runner.rb
@@ -1,31 +1,31 @@
require 'puppet/run'
class Puppet::Network::Handler
- class MissingMasterError < RuntimeError; end # Cannot find the master client
- # A simple server for triggering a new run on a Puppet client.
- class Runner < Handler
- desc "An interface for triggering client configuration runs."
+ class MissingMasterError < RuntimeError; end # Cannot find the master client
+ # A simple server for triggering a new run on a Puppet client.
+ class Runner < Handler
+ desc "An interface for triggering client configuration runs."
- @interface = XMLRPC::Service::Interface.new("puppetrunner") { |iface|
- iface.add_method("string run(string, string)")
- }
+ @interface = XMLRPC::Service::Interface.new("puppetrunner") { |iface|
+ iface.add_method("string run(string, string)")
+ }
- side :client
+ side :client
- # Run the client configuration right now, optionally specifying
- # tags and whether to ignore schedules
- def run(tags = nil, ignoreschedules = false, fg = true, client = nil, clientip = nil)
- options = {}
- options[:tags] = tags if tags
- options[:ignoreschedules] = ignoreschedules if ignoreschedules
- options[:background] = !fg
+ # Run the client configuration right now, optionally specifying
+ # tags and whether to ignore schedules
+ def run(tags = nil, ignoreschedules = false, fg = true, client = nil, clientip = nil)
+ options = {}
+ options[:tags] = tags if tags
+ options[:ignoreschedules] = ignoreschedules if ignoreschedules
+ options[:background] = !fg
- runner = Puppet::Run.new(options)
+ runner = Puppet::Run.new(options)
- runner.run
+ runner.run
- runner.status
- end
+ runner.status
end
+ end
end
diff --git a/lib/puppet/network/handler/status.rb b/lib/puppet/network/handler/status.rb
index fe6c23dc3..ec6a402a6 100644
--- a/lib/puppet/network/handler/status.rb
+++ b/lib/puppet/network/handler/status.rb
@@ -1,16 +1,16 @@
class Puppet::Network::Handler
- class Status < Handler
- desc "A simple interface for testing Puppet connectivity."
+ class Status < Handler
+ desc "A simple interface for testing Puppet connectivity."
- side :client
+ side :client
- @interface = XMLRPC::Service::Interface.new("status") { |iface|
- iface.add_method("int status()")
- }
+ @interface = XMLRPC::Service::Interface.new("status") { |iface|
+ iface.add_method("int status()")
+ }
- def status(client = nil, clientip = nil)
- 1
- end
+ def status(client = nil, clientip = nil)
+ 1
end
+ end
end
diff --git a/lib/puppet/network/http.rb b/lib/puppet/network/http.rb
index ee6b70422..512055b63 100644
--- a/lib/puppet/network/http.rb
+++ b/lib/puppet/network/http.rb
@@ -1,15 +1,15 @@
module Puppet::Network::HTTP
- def self.server_class_by_type(kind)
- case kind.to_sym
- when :webrick
- require 'puppet/network/http/webrick'
- return Puppet::Network::HTTP::WEBrick
- when :mongrel
- raise ArgumentError, "Mongrel is not installed on this platform" unless Puppet.features.mongrel?
- require 'puppet/network/http/mongrel'
- return Puppet::Network::HTTP::Mongrel
- else
- raise ArgumentError, "Unknown HTTP server name [#{kind}]"
- end
+ def self.server_class_by_type(kind)
+ case kind.to_sym
+ when :webrick
+ require 'puppet/network/http/webrick'
+ return Puppet::Network::HTTP::WEBrick
+ when :mongrel
+ raise ArgumentError, "Mongrel is not installed on this platform" unless Puppet.features.mongrel?
+ require 'puppet/network/http/mongrel'
+ return Puppet::Network::HTTP::Mongrel
+ else
+ raise ArgumentError, "Unknown HTTP server name [#{kind}]"
end
+ end
end
diff --git a/lib/puppet/network/http/api/v1.rb b/lib/puppet/network/http/api/v1.rb
index 577328589..dd4612a14 100644
--- a/lib/puppet/network/http/api/v1.rb
+++ b/lib/puppet/network/http/api/v1.rb
@@ -1,70 +1,70 @@
require 'puppet/network/http/api'
module Puppet::Network::HTTP::API::V1
- # How we map http methods and the indirection name in the URI
- # to an indirection method.
- METHOD_MAP = {
- "GET" => {
- :plural => :search,
- :singular => :find
- },
- "PUT" => {
- :singular => :save
- },
- "DELETE" => {
- :singular => :destroy
- }
+ # How we map http methods and the indirection name in the URI
+ # to an indirection method.
+ METHOD_MAP = {
+ "GET" => {
+ :plural => :search,
+ :singular => :find
+ },
+ "PUT" => {
+ :singular => :save
+ },
+ "DELETE" => {
+ :singular => :destroy
}
+ }
- def uri2indirection(http_method, uri, params)
- environment, indirection, key = uri.split("/", 4)[1..-1] # the first field is always nil because of the leading slash
+ def uri2indirection(http_method, uri, params)
+ environment, indirection, key = uri.split("/", 4)[1..-1] # the first field is always nil because of the leading slash
- raise ArgumentError, "The environment must be purely alphanumeric, not '#{environment}'" unless environment =~ /^\w+$/
- raise ArgumentError, "The indirection name must be purely alphanumeric, not '#{indirection}'" unless indirection =~ /^\w+$/
+ raise ArgumentError, "The environment must be purely alphanumeric, not '#{environment}'" unless environment =~ /^\w+$/
+ raise ArgumentError, "The indirection name must be purely alphanumeric, not '#{indirection}'" unless indirection =~ /^\w+$/
- method = indirection_method(http_method, indirection)
+ method = indirection_method(http_method, indirection)
- params[:environment] = environment
+ params[:environment] = environment
- raise ArgumentError, "No request key specified in #{uri}" if key == "" or key.nil?
+ raise ArgumentError, "No request key specified in #{uri}" if key == "" or key.nil?
- key = URI.unescape(key)
+ key = URI.unescape(key)
- Puppet::Indirector::Request.new(indirection, method, key, params)
- end
-
- def indirection2uri(request)
- indirection = request.method == :search ? pluralize(request.indirection_name.to_s) : request.indirection_name.to_s
- "/#{request.environment.to_s}/#{indirection}/#{request.escaped_key}#{request.query_string}"
- end
+ Puppet::Indirector::Request.new(indirection, method, key, params)
+ end
- def indirection_method(http_method, indirection)
- raise ArgumentError, "No support for http method #{http_method}" unless METHOD_MAP[http_method]
+ def indirection2uri(request)
+ indirection = request.method == :search ? pluralize(request.indirection_name.to_s) : request.indirection_name.to_s
+ "/#{request.environment.to_s}/#{indirection}/#{request.escaped_key}#{request.query_string}"
+ end
- unless method = METHOD_MAP[http_method][plurality(indirection)]
- raise ArgumentError, "No support for plural #{http_method} operations"
- end
+ def indirection_method(http_method, indirection)
+ raise ArgumentError, "No support for http method #{http_method}" unless METHOD_MAP[http_method]
- method
+ unless method = METHOD_MAP[http_method][plurality(indirection)]
+ raise ArgumentError, "No support for plural #{http_method} operations"
end
- def pluralize(indirection)
- return(indirection == "status" ? "statuses" : indirection + "s")
- end
+ method
+ end
- def plurality(indirection)
- # NOTE This specific hook for facts is ridiculous, but it's a *many*-line
- # fix to not need this, and our goal is to move away from the complication
- # that leads to the fix being too long.
- return :singular if indirection == "facts"
+ def pluralize(indirection)
+ return(indirection == "status" ? "statuses" : indirection + "s")
+ end
- # "status" really is singular
- return :singular if indirection == "status"
+ def plurality(indirection)
+ # NOTE This specific hook for facts is ridiculous, but it's a *many*-line
+ # fix to not need this, and our goal is to move away from the complication
+ # that leads to the fix being too long.
+ return :singular if indirection == "facts"
- result = (indirection =~ /s$/) ? :plural : :singular
+ # "status" really is singular
+ return :singular if indirection == "status"
- indirection.sub!(/s$/, '') if result
+ result = (indirection =~ /s$/) ? :plural : :singular
- result
- end
+ indirection.sub!(/s$/, '') if result
+
+ result
+ end
end
diff --git a/lib/puppet/network/http/compression.rb b/lib/puppet/network/http/compression.rb
index bb06a5770..d9b56f184 100644
--- a/lib/puppet/network/http/compression.rb
+++ b/lib/puppet/network/http/compression.rb
@@ -2,110 +2,110 @@ require 'puppet/network/http'
module Puppet::Network::HTTP::Compression
- # this module function allows to use the right underlying
- # methods depending on zlib presence
- def module
- return(Puppet.features.zlib? ? Active : None)
+ # this module function allows to use the right underlying
+ # methods depending on zlib presence
+ def module
+ return(Puppet.features.zlib? ? Active : None)
+ end
+ module_function :module
+
+ module Active
+ require 'zlib'
+ require 'stringio'
+
+ # return an uncompressed body if the response has been
+ # compressed
+ def uncompress_body(response)
+ case response['content-encoding']
+ when 'gzip'
+ return Zlib::GzipReader.new(StringIO.new(response.body)).read
+ when 'deflate'
+ return Zlib::Inflate.new.inflate(response.body)
+ when nil, 'identity'
+ return response.body
+ else
+ raise Net::HTTPError.new("Unknown content encoding - #{response['content-encoding']}", response)
+ end
end
- module_function :module
-
- module Active
- require 'zlib'
- require 'stringio'
-
- # return an uncompressed body if the response has been
- # compressed
- def uncompress_body(response)
- case response['content-encoding']
- when 'gzip'
- return Zlib::GzipReader.new(StringIO.new(response.body)).read
- when 'deflate'
- return Zlib::Inflate.new.inflate(response.body)
- when nil, 'identity'
- return response.body
- else
- raise Net::HTTPError.new("Unknown content encoding - #{response['content-encoding']}", response)
- end
- end
-
- def uncompress(response)
- raise Net::HTTPError.new("No block passed") unless block_given?
-
- case response['content-encoding']
- when 'gzip','deflate'
- uncompressor = ZlibAdapter.new
- when nil, 'identity'
- uncompressor = IdentityAdapter.new
- else
- raise Net::HTTPError.new("Unknown content encoding - #{response['content-encoding']}", response)
- end
-
- yield uncompressor
-
- uncompressor.close
- end
-
- def add_accept_encoding(headers={})
- headers['accept-encoding'] = 'gzip; q=1.0, deflate; q=1.0; identity' if Puppet.settings[:http_compression]
- headers
- end
-
- # This adapters knows how to uncompress both 'zlib' stream (the deflate algorithm from Content-Encoding)
- # and GZip streams.
- class ZlibAdapter
- def initialize
- # Create an inflater that knows to parse GZip streams and zlib streams.
- # This uses a property of the C Zlib library, documented as follow:
- # windowBits can also be greater than 15 for optional gzip decoding. Add
- # 32 to windowBits to enable zlib and gzip decoding with automatic header
- # detection, or add 16 to decode only the gzip format (the zlib format will
- # return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
- # a crc32 instead of an adler32.
- @uncompressor = Zlib::Inflate.new(15 + 32)
- @first = true
- end
-
- def uncompress(chunk)
- out = @uncompressor.inflate(chunk)
- @first = false
- return out
- rescue Zlib::DataError => z
- # it can happen that we receive a raw deflate stream
- # which might make our inflate throw a data error.
- # in this case, we try with a verbatim (no header)
- # deflater.
- @uncompressor = Zlib::Inflate.new
- retry if @first
- raise
- end
-
- def close
- @uncompressor.finish
- @uncompressor.close
- end
- end
+
+ def uncompress(response)
+ raise Net::HTTPError.new("No block passed") unless block_given?
+
+ case response['content-encoding']
+ when 'gzip','deflate'
+ uncompressor = ZlibAdapter.new
+ when nil, 'identity'
+ uncompressor = IdentityAdapter.new
+ else
+ raise Net::HTTPError.new("Unknown content encoding - #{response['content-encoding']}", response)
+ end
+
+ yield uncompressor
+
+ uncompressor.close
end
- module None
- def uncompress_body(response)
- response.body
- end
+ def add_accept_encoding(headers={})
+ headers['accept-encoding'] = 'gzip; q=1.0, deflate; q=1.0; identity' if Puppet.settings[:http_compression]
+ headers
+ end
- def add_accept_encoding(headers)
- headers
- end
+ # This adapters knows how to uncompress both 'zlib' stream (the deflate algorithm from Content-Encoding)
+ # and GZip streams.
+ class ZlibAdapter
+ def initialize
+ # Create an inflater that knows to parse GZip streams and zlib streams.
+ # This uses a property of the C Zlib library, documented as follow:
+ # windowBits can also be greater than 15 for optional gzip decoding. Add
+ # 32 to windowBits to enable zlib and gzip decoding with automatic header
+ # detection, or add 16 to decode only the gzip format (the zlib format will
+ # return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
+ # a crc32 instead of an adler32.
+ @uncompressor = Zlib::Inflate.new(15 + 32)
+ @first = true
+ end
+
+ def uncompress(chunk)
+ out = @uncompressor.inflate(chunk)
+ @first = false
+ return out
+ rescue Zlib::DataError => z
+ # it can happen that we receive a raw deflate stream
+ # which might make our inflate throw a data error.
+ # in this case, we try with a verbatim (no header)
+ # deflater.
+ @uncompressor = Zlib::Inflate.new
+ retry if @first
+ raise
+ end
+
+ def close
+ @uncompressor.finish
+ @uncompressor.close
+ end
+ end
+ end
- def uncompress(response)
- yield IdentityAdapter.new
- end
+ module None
+ def uncompress_body(response)
+ response.body
end
- class IdentityAdapter
- def uncompress(chunk)
- chunk
- end
+ def add_accept_encoding(headers)
+ headers
+ end
+
+ def uncompress(response)
+ yield IdentityAdapter.new
+ end
+ end
+
+ class IdentityAdapter
+ def uncompress(chunk)
+ chunk
+ end
- def close
- end
+ def close
end
+ end
end
diff --git a/lib/puppet/network/http/handler.rb b/lib/puppet/network/http/handler.rb
index 9f467372c..03d24b3fe 100644
--- a/lib/puppet/network/http/handler.rb
+++ b/lib/puppet/network/http/handler.rb
@@ -7,223 +7,223 @@ require 'puppet/network/rights'
require 'resolv'
module Puppet::Network::HTTP::Handler
- include Puppet::Network::HTTP::API::V1
- include Puppet::Network::RestAuthorization
+ include Puppet::Network::HTTP::API::V1
+ include Puppet::Network::RestAuthorization
- attr_reader :server, :handler
+ attr_reader :server, :handler
- # Retrieve the accept header from the http request.
- def accept_header(request)
- raise NotImplementedError
- end
-
- # Retrieve the Content-Type header from the http request.
- def content_type_header(request)
- raise NotImplementedError
- end
-
- # Which format to use when serializing our response or interpreting the request.
- # IF the client provided a Content-Type use this, otherwise use the Accept header
- # and just pick the first value.
- def format_to_use(request)
- unless header = accept_header(request)
- raise ArgumentError, "An Accept header must be provided to pick the right format"
- end
-
- format = nil
- header.split(/,\s*/).each do |name|
- next unless format = Puppet::Network::FormatHandler.format(name)
- next unless format.suitable?
- return format
- end
-
- raise "No specified acceptable formats (#{header}) are functional on this machine"
- end
-
- def request_format(request)
- if header = content_type_header(request)
- header.gsub!(/\s*;.*$/,'') # strip any charset
- format = Puppet::Network::FormatHandler.mime(header)
- raise "Client sent a mime-type (#{header}) that doesn't correspond to a format we support" if format.nil?
- return format.name.to_s if format.suitable?
- end
-
- raise "No Content-Type header was received, it isn't possible to unserialize the request"
- end
-
- def format_to_mime(format)
- format.is_a?(Puppet::Network::Format) ? format.mime : format
- end
-
- def initialize_for_puppet(server)
- @server = server
- end
-
- # handle an HTTP request
- def process(request, response)
- indirection_request = uri2indirection(http_method(request), path(request), params(request))
-
- check_authorization(indirection_request)
-
- send("do_#{indirection_request.method}", indirection_request, request, response)
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => e
- return do_exception(response, e)
- end
-
- # Set the response up, with the body and status.
- def set_response(response, body, status = 200)
- raise NotImplementedError
- end
-
- # Set the specified format as the content type of the response.
- def set_content_type(response, format)
- raise NotImplementedError
- end
+ # Retrieve the accept header from the http request.
+ def accept_header(request)
+ raise NotImplementedError
+ end
- def do_exception(response, exception, status=400)
- if exception.is_a?(Puppet::Network::AuthorizationError)
- # make sure we return the correct status code
- # for authorization issues
- status = 403 if status == 400
- end
- if exception.is_a?(Exception)
- puts exception.backtrace if Puppet[:trace]
- Puppet.err(exception)
- end
- set_content_type(response, "text/plain")
- set_response(response, exception.to_s, status)
- end
-
- # Execute our find.
- def do_find(indirection_request, request, response)
- unless result = indirection_request.model.find(indirection_request.key, indirection_request.to_hash)
- Puppet.info("Could not find #{indirection_request.indirection_name} for '#{indirection_request.key}'")
- return do_exception(response, "Could not find #{indirection_request.indirection_name} #{indirection_request.key}", 404)
- end
-
- # The encoding of the result must include the format to use,
- # and it needs to be used for both the rendering and as
- # the content type.
- format = format_to_use(request)
- set_content_type(response, format)
-
- set_response(response, result.render(format))
- end
+ # Retrieve the Content-Type header from the http request.
+ def content_type_header(request)
+ raise NotImplementedError
+ end
- # Execute our search.
- def do_search(indirection_request, request, response)
- result = indirection_request.model.search(indirection_request.key, indirection_request.to_hash)
-
- if result.nil? or (result.is_a?(Array) and result.empty?)
- return do_exception(response, "Could not find instances in #{indirection_request.indirection_name} with '#{indirection_request.to_hash.inspect}'", 404)
- end
-
- format = format_to_use(request)
- set_content_type(response, format)
-
- set_response(response, indirection_request.model.render_multiple(format, result))
+ # Which format to use when serializing our response or interpreting the request.
+ # IF the client provided a Content-Type use this, otherwise use the Accept header
+ # and just pick the first value.
+ def format_to_use(request)
+ unless header = accept_header(request)
+ raise ArgumentError, "An Accept header must be provided to pick the right format"
end
- # Execute our destroy.
- def do_destroy(indirection_request, request, response)
- result = indirection_request.model.destroy(indirection_request.key, indirection_request.to_hash)
-
- return_yaml_response(response, result)
+ format = nil
+ header.split(/,\s*/).each do |name|
+ next unless format = Puppet::Network::FormatHandler.format(name)
+ next unless format.suitable?
+ return format
end
- # Execute our save.
- def do_save(indirection_request, request, response)
- data = body(request).to_s
- raise ArgumentError, "No data to save" if !data or data.empty?
-
- format = request_format(request)
- obj = indirection_request.model.convert_from(format, data)
- result = save_object(indirection_request, obj)
- return_yaml_response(response, result)
- end
+ raise "No specified acceptable formats (#{header}) are functional on this machine"
+ end
- # resolve node name from peer's ip address
- # this is used when the request is unauthenticated
- def resolve_node(result)
- begin
- return Resolv.getname(result[:ip])
- rescue => detail
- Puppet.err "Could not resolve #{result[:ip]}: #{detail}"
- end
- result[:ip]
+ def request_format(request)
+ if header = content_type_header(request)
+ header.gsub!(/\s*;.*$/,'') # strip any charset
+ format = Puppet::Network::FormatHandler.mime(header)
+ raise "Client sent a mime-type (#{header}) that doesn't correspond to a format we support" if format.nil?
+ return format.name.to_s if format.suitable?
end
- private
+ raise "No Content-Type header was received, it isn't possible to unserialize the request"
+ end
+
+ def format_to_mime(format)
+ format.is_a?(Puppet::Network::Format) ? format.mime : format
+ end
- def return_yaml_response(response, body)
- set_content_type(response, Puppet::Network::FormatHandler.format("yaml"))
- set_response(response, body.to_yaml)
- end
+ def initialize_for_puppet(server)
+ @server = server
+ end
- # LAK:NOTE This has to be here for testing; it's a stub-point so
- # we keep infinite recursion from happening.
- def save_object(ind_request, object)
- object.save(ind_request.key)
- end
+ # handle an HTTP request
+ def process(request, response)
+ indirection_request = uri2indirection(http_method(request), path(request), params(request))
- def get?(request)
- http_method(request) == 'GET'
- end
+ check_authorization(indirection_request)
- def put?(request)
- http_method(request) == 'PUT'
- end
+ send("do_#{indirection_request.method}", indirection_request, request, response)
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => e
+ return do_exception(response, e)
+ end
- def delete?(request)
- http_method(request) == 'DELETE'
- end
+ # Set the response up, with the body and status.
+ def set_response(response, body, status = 200)
+ raise NotImplementedError
+ end
- # methods to be overridden by the including web server class
+ # Set the specified format as the content type of the response.
+ def set_content_type(response, format)
+ raise NotImplementedError
+ end
- def http_method(request)
- raise NotImplementedError
+ def do_exception(response, exception, status=400)
+ if exception.is_a?(Puppet::Network::AuthorizationError)
+ # make sure we return the correct status code
+ # for authorization issues
+ status = 403 if status == 400
end
-
- def path(request)
- raise NotImplementedError
+ if exception.is_a?(Exception)
+ puts exception.backtrace if Puppet[:trace]
+ Puppet.err(exception)
end
+ set_content_type(response, "text/plain")
+ set_response(response, exception.to_s, status)
+ end
- def request_key(request)
- raise NotImplementedError
+ # Execute our find.
+ def do_find(indirection_request, request, response)
+ unless result = indirection_request.model.find(indirection_request.key, indirection_request.to_hash)
+ Puppet.info("Could not find #{indirection_request.indirection_name} for '#{indirection_request.key}'")
+ return do_exception(response, "Could not find #{indirection_request.indirection_name} #{indirection_request.key}", 404)
end
- def body(request)
- raise NotImplementedError
- end
+ # The encoding of the result must include the format to use,
+ # and it needs to be used for both the rendering and as
+ # the content type.
+ format = format_to_use(request)
+ set_content_type(response, format)
- def params(request)
- raise NotImplementedError
- end
+ set_response(response, result.render(format))
+ end
- def decode_params(params)
- params.inject({}) do |result, ary|
- param, value = ary
- next result if param.nil? || param.empty?
-
- param = param.to_sym
-
- # These shouldn't be allowed to be set by clients
- # in the query string, for security reasons.
- next result if param == :node
- next result if param == :ip
- value = CGI.unescape(value)
- if value =~ /^---/
- value = YAML.load(value)
- else
- value = true if value == "true"
- value = false if value == "false"
- value = Integer(value) if value =~ /^\d+$/
- value = value.to_f if value =~ /^\d+\.\d+$/
- end
- result[param] = value
- result
- end
- end
+ # Execute our search.
+ def do_search(indirection_request, request, response)
+ result = indirection_request.model.search(indirection_request.key, indirection_request.to_hash)
+
+ if result.nil? or (result.is_a?(Array) and result.empty?)
+ return do_exception(response, "Could not find instances in #{indirection_request.indirection_name} with '#{indirection_request.to_hash.inspect}'", 404)
+ end
+
+ format = format_to_use(request)
+ set_content_type(response, format)
+
+ set_response(response, indirection_request.model.render_multiple(format, result))
+ end
+
+ # Execute our destroy.
+ def do_destroy(indirection_request, request, response)
+ result = indirection_request.model.destroy(indirection_request.key, indirection_request.to_hash)
+
+ return_yaml_response(response, result)
+ end
+
+ # Execute our save.
+ def do_save(indirection_request, request, response)
+ data = body(request).to_s
+ raise ArgumentError, "No data to save" if !data or data.empty?
+
+ format = request_format(request)
+ obj = indirection_request.model.convert_from(format, data)
+ result = save_object(indirection_request, obj)
+ return_yaml_response(response, result)
+ end
+
+ # resolve node name from peer's ip address
+ # this is used when the request is unauthenticated
+ def resolve_node(result)
+ begin
+ return Resolv.getname(result[:ip])
+ rescue => detail
+ Puppet.err "Could not resolve #{result[:ip]}: #{detail}"
+ end
+ result[:ip]
+ end
+
+ private
+
+ def return_yaml_response(response, body)
+ set_content_type(response, Puppet::Network::FormatHandler.format("yaml"))
+ set_response(response, body.to_yaml)
+ end
+
+ # LAK:NOTE This has to be here for testing; it's a stub-point so
+ # we keep infinite recursion from happening.
+ def save_object(ind_request, object)
+ object.save(ind_request.key)
+ end
+
+ def get?(request)
+ http_method(request) == 'GET'
+ end
+
+ def put?(request)
+ http_method(request) == 'PUT'
+ end
+
+ def delete?(request)
+ http_method(request) == 'DELETE'
+ end
+
+ # methods to be overridden by the including web server class
+
+ def http_method(request)
+ raise NotImplementedError
+ end
+
+ def path(request)
+ raise NotImplementedError
+ end
+
+ def request_key(request)
+ raise NotImplementedError
+ end
+
+ def body(request)
+ raise NotImplementedError
+ end
+
+ def params(request)
+ raise NotImplementedError
+ end
+
+ def decode_params(params)
+ params.inject({}) do |result, ary|
+ param, value = ary
+ next result if param.nil? || param.empty?
+
+ param = param.to_sym
+
+ # These shouldn't be allowed to be set by clients
+ # in the query string, for security reasons.
+ next result if param == :node
+ next result if param == :ip
+ value = CGI.unescape(value)
+ if value =~ /^---/
+ value = YAML.load(value)
+ else
+ value = true if value == "true"
+ value = false if value == "false"
+ value = Integer(value) if value =~ /^\d+$/
+ value = value.to_f if value =~ /^\d+\.\d+$/
+ end
+ result[param] = value
+ result
+ end
+ end
end
diff --git a/lib/puppet/network/http/mongrel.rb b/lib/puppet/network/http/mongrel.rb
index 88494eea8..2a638b229 100644
--- a/lib/puppet/network/http/mongrel.rb
+++ b/lib/puppet/network/http/mongrel.rb
@@ -3,53 +3,53 @@ require 'mongrel' if Puppet.features.mongrel?
require 'puppet/network/http/mongrel/rest'
class Puppet::Network::HTTP::Mongrel
- def initialize(args = {})
- @listening = false
- end
-
- def listen(args = {})
- raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
- raise ArgumentError, ":address must be specified." unless args[:address]
- raise ArgumentError, ":port must be specified." unless args[:port]
- raise "Mongrel server is already listening" if listening?
-
- @protocols = args[:protocols]
- @xmlrpc_handlers = args[:xmlrpc_handlers]
- @server = Mongrel::HttpServer.new(args[:address], args[:port])
- setup_handlers
-
- @listening = true
- @server.run
- end
-
- def unlisten
- raise "Mongrel server is not listening" unless listening?
- @server.stop
- @server = nil
- @listening = false
- end
-
- def listening?
- @listening
- end
-
- private
-
- def setup_handlers
- # Register our REST support at /
- klass = class_for_protocol(:rest)
- @server.register('/', klass.new(:server => @server))
-
- setup_xmlrpc_handlers if @protocols.include?(:xmlrpc) and ! @xmlrpc_handlers.empty?
- end
-
- # Use our existing code to provide the xmlrpc backward compatibility.
- def setup_xmlrpc_handlers
- @server.register('/RPC2', Puppet::Network::HTTPServer::Mongrel.new(@xmlrpc_handlers))
- end
-
- def class_for_protocol(protocol)
- return Puppet::Network::HTTP::MongrelREST if protocol.to_sym == :rest
- raise ArgumentError, "Unknown protocol [#{protocol}]."
- end
+ def initialize(args = {})
+ @listening = false
+ end
+
+ def listen(args = {})
+ raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
+ raise ArgumentError, ":address must be specified." unless args[:address]
+ raise ArgumentError, ":port must be specified." unless args[:port]
+ raise "Mongrel server is already listening" if listening?
+
+ @protocols = args[:protocols]
+ @xmlrpc_handlers = args[:xmlrpc_handlers]
+ @server = Mongrel::HttpServer.new(args[:address], args[:port])
+ setup_handlers
+
+ @listening = true
+ @server.run
+ end
+
+ def unlisten
+ raise "Mongrel server is not listening" unless listening?
+ @server.stop
+ @server = nil
+ @listening = false
+ end
+
+ def listening?
+ @listening
+ end
+
+ private
+
+ def setup_handlers
+ # Register our REST support at /
+ klass = class_for_protocol(:rest)
+ @server.register('/', klass.new(:server => @server))
+
+ setup_xmlrpc_handlers if @protocols.include?(:xmlrpc) and ! @xmlrpc_handlers.empty?
+ end
+
+ # Use our existing code to provide the xmlrpc backward compatibility.
+ def setup_xmlrpc_handlers
+ @server.register('/RPC2', Puppet::Network::HTTPServer::Mongrel.new(@xmlrpc_handlers))
+ end
+
+ def class_for_protocol(protocol)
+ return Puppet::Network::HTTP::MongrelREST if protocol.to_sym == :rest
+ raise ArgumentError, "Unknown protocol [#{protocol}]."
+ end
end
diff --git a/lib/puppet/network/http/mongrel/rest.rb b/lib/puppet/network/http/mongrel/rest.rb
index 60367a1e8..7ef13f046 100644
--- a/lib/puppet/network/http/mongrel/rest.rb
+++ b/lib/puppet/network/http/mongrel/rest.rb
@@ -2,91 +2,91 @@ require 'puppet/network/http/handler'
class Puppet::Network::HTTP::MongrelREST < Mongrel::HttpHandler
- include Puppet::Network::HTTP::Handler
+ include Puppet::Network::HTTP::Handler
- ACCEPT_HEADER = "HTTP_ACCEPT".freeze # yay, zed's a crazy-man
+ ACCEPT_HEADER = "HTTP_ACCEPT".freeze # yay, zed's a crazy-man
- def initialize(args={})
- super()
- initialize_for_puppet(args)
- end
+ def initialize(args={})
+ super()
+ initialize_for_puppet(args)
+ end
- def accept_header(request)
- request.params[ACCEPT_HEADER]
- end
+ def accept_header(request)
+ request.params[ACCEPT_HEADER]
+ end
- def content_type_header(request)
- request.params["HTTP_CONTENT_TYPE"]
- end
+ def content_type_header(request)
+ request.params["HTTP_CONTENT_TYPE"]
+ end
- # which HTTP verb was used in this request
- def http_method(request)
- request.params[Mongrel::Const::REQUEST_METHOD]
- end
+ # which HTTP verb was used in this request
+ def http_method(request)
+ request.params[Mongrel::Const::REQUEST_METHOD]
+ end
- # Return the query params for this request. We had to expose this method for
- # testing purposes.
- def params(request)
- params = Mongrel::HttpRequest.query_parse(request.params["QUERY_STRING"])
- params = decode_params(params)
- params.merge(client_info(request))
- end
+ # Return the query params for this request. We had to expose this method for
+ # testing purposes.
+ def params(request)
+ params = Mongrel::HttpRequest.query_parse(request.params["QUERY_STRING"])
+ params = decode_params(params)
+ params.merge(client_info(request))
+ end
- # what path was requested?
- def path(request)
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- #x = '/' + request.params[Mongrel::Const::REQUEST_PATH]
- request.params[Mongrel::Const::REQUEST_PATH]
- end
+ # what path was requested?
+ def path(request)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ #x = '/' + request.params[Mongrel::Const::REQUEST_PATH]
+ request.params[Mongrel::Const::REQUEST_PATH]
+ end
- # return the request body
- def body(request)
- request.body.read
- end
+ # return the request body
+ def body(request)
+ request.body.read
+ end
- def set_content_type(response, format)
- response.header['Content-Type'] = format_to_mime(format)
- end
+ def set_content_type(response, format)
+ response.header['Content-Type'] = format_to_mime(format)
+ end
- # produce the body of the response
- def set_response(response, result, status = 200)
- # Set the 'reason' (or 'message', as it's called in Webrick), when
- # we have a failure, unless we're on a version of mongrel that doesn't
- # support this.
- if status < 300
- unless result.is_a?(File)
- response.start(status) { |head, body| body.write(result) }
- else
- response.start(status) { |head, body| }
- response.send_status(result.stat.size)
- response.send_header
- response.send_file(result.path)
- end
- else
- begin
- response.start(status,false,result) { |head, body| body.write(result) }
- rescue ArgumentError
- response.start(status) { |head, body| body.write(result) }
- end
- end
+ # produce the body of the response
+ def set_response(response, result, status = 200)
+ # Set the 'reason' (or 'message', as it's called in Webrick), when
+ # we have a failure, unless we're on a version of mongrel that doesn't
+ # support this.
+ if status < 300
+ unless result.is_a?(File)
+ response.start(status) { |head, body| body.write(result) }
+ else
+ response.start(status) { |head, body| }
+ response.send_status(result.stat.size)
+ response.send_header
+ response.send_file(result.path)
+ end
+ else
+ begin
+ response.start(status,false,result) { |head, body| body.write(result) }
+ rescue ArgumentError
+ response.start(status) { |head, body| body.write(result) }
+ end
end
+ end
- def client_info(request)
- result = {}
- params = request.params
- result[:ip] = params["HTTP_X_FORWARDED_FOR"] ? params["HTTP_X_FORWARDED_FOR"].split(',').last.strip : params["REMOTE_ADDR"]
+ def client_info(request)
+ result = {}
+ params = request.params
+ result[:ip] = params["HTTP_X_FORWARDED_FOR"] ? params["HTTP_X_FORWARDED_FOR"].split(',').last.strip : params["REMOTE_ADDR"]
- # JJM #906 The following dn.match regular expression is forgiving
- # enough to match the two Distinguished Name string contents
- # coming from Apache, Pound or other reverse SSL proxies.
- if dn = params[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
- result[:node] = dn_matchdata[1].to_str
- result[:authenticated] = (params[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
- else
- result[:node] = resolve_node(result)
- result[:authenticated] = false
- end
-
- result
+ # JJM #906 The following dn.match regular expression is forgiving
+ # enough to match the two Distinguished Name string contents
+ # coming from Apache, Pound or other reverse SSL proxies.
+ if dn = params[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
+ result[:node] = dn_matchdata[1].to_str
+ result[:authenticated] = (params[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
+ else
+ result[:node] = resolve_node(result)
+ result[:authenticated] = false
end
+
+ result
+ end
end
diff --git a/lib/puppet/network/http/rack.rb b/lib/puppet/network/http/rack.rb
index b7da1fcf7..c18a07559 100644
--- a/lib/puppet/network/http/rack.rb
+++ b/lib/puppet/network/http/rack.rb
@@ -6,57 +6,57 @@ require 'puppet/network/http/rack/xmlrpc'
# An rack application, for running the Puppet HTTP Server.
class Puppet::Network::HTTP::Rack
- def initialize(args)
- raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
- protocols = args[:protocols]
+ def initialize(args)
+ raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
+ protocols = args[:protocols]
- # Always prepare a REST handler
- @rest_http_handler = Puppet::Network::HTTP::RackREST.new
- protocols.delete :rest
+ # Always prepare a REST handler
+ @rest_http_handler = Puppet::Network::HTTP::RackREST.new
+ protocols.delete :rest
- # Prepare the XMLRPC handler, for backward compatibility (if requested)
- @xmlrpc_path = '/RPC2'
- if args[:protocols].include?(:xmlrpc)
- raise ArgumentError, "XMLRPC was requested, but no handlers were given" if !args.include?(:xmlrpc_handlers)
+ # Prepare the XMLRPC handler, for backward compatibility (if requested)
+ @xmlrpc_path = '/RPC2'
+ if args[:protocols].include?(:xmlrpc)
+ raise ArgumentError, "XMLRPC was requested, but no handlers were given" if !args.include?(:xmlrpc_handlers)
- @xmlrpc_http_handler = Puppet::Network::HTTP::RackXMLRPC.new(args[:xmlrpc_handlers])
- protocols.delete :xmlrpc
- end
+ @xmlrpc_http_handler = Puppet::Network::HTTP::RackXMLRPC.new(args[:xmlrpc_handlers])
+ protocols.delete :xmlrpc
+ end
- raise ArgumentError, "there were unknown :protocols specified." if !protocols.empty?
+ raise ArgumentError, "there were unknown :protocols specified." if !protocols.empty?
+ end
+
+ # The real rack application (which needs to respond to call).
+ # The work we need to do, roughly is:
+ # * Read request (from env) and prepare a response
+ # * Route the request to the correct handler
+ # * Return the response (in rack-format) to our caller.
+ def call(env)
+ request = Rack::Request.new(env)
+ response = Rack::Response.new
+ Puppet.debug 'Handling request: %s %s' % [request.request_method, request.fullpath]
+
+ # if we shall serve XMLRPC, have /RPC2 go to the xmlrpc handler
+ if @xmlrpc_http_handler and @xmlrpc_path == request.path_info[0, @xmlrpc_path.size]
+ handler = @xmlrpc_http_handler
+ else
+ # everything else is handled by the new REST handler
+ handler = @rest_http_handler
end
- # The real rack application (which needs to respond to call).
- # The work we need to do, roughly is:
- # * Read request (from env) and prepare a response
- # * Route the request to the correct handler
- # * Return the response (in rack-format) to our caller.
- def call(env)
- request = Rack::Request.new(env)
- response = Rack::Response.new
- Puppet.debug 'Handling request: %s %s' % [request.request_method, request.fullpath]
-
- # if we shall serve XMLRPC, have /RPC2 go to the xmlrpc handler
- if @xmlrpc_http_handler and @xmlrpc_path == request.path_info[0, @xmlrpc_path.size]
- handler = @xmlrpc_http_handler
- else
- # everything else is handled by the new REST handler
- handler = @rest_http_handler
- end
-
- begin
- handler.process(request, response)
- rescue => detail
- # Send a Status 500 Error on unhandled exceptions.
- response.status = 500
- response['Content-Type'] = 'text/plain'
- response.write 'Internal Server Error: "%s"' % detail.message
- # log what happened
- Puppet.err "Puppet Server (Rack): Internal Server Error: Unhandled Exception: \"%s\"" % detail.message
- Puppet.err "Backtrace:"
- detail.backtrace.each { |line| Puppet.err " > #{line}" }
- end
- response.finish
+ begin
+ handler.process(request, response)
+ rescue => detail
+ # Send a Status 500 Error on unhandled exceptions.
+ response.status = 500
+ response['Content-Type'] = 'text/plain'
+ response.write 'Internal Server Error: "%s"' % detail.message
+ # log what happened
+ Puppet.err "Puppet Server (Rack): Internal Server Error: Unhandled Exception: \"%s\"" % detail.message
+ Puppet.err "Backtrace:"
+ detail.backtrace.each { |line| Puppet.err " > #{line}" }
end
+ response.finish
+ end
end
diff --git a/lib/puppet/network/http/rack/httphandler.rb b/lib/puppet/network/http/rack/httphandler.rb
index fed06f880..c54062357 100644
--- a/lib/puppet/network/http/rack/httphandler.rb
+++ b/lib/puppet/network/http/rack/httphandler.rb
@@ -3,14 +3,14 @@ require 'puppet/ssl/certificate'
class Puppet::Network::HTTP::RackHttpHandler
- def initialize
- end
+ def initialize
+ end
- # do something useful with request (a Rack::Request) and use
- # response to fill your Rack::Response
- def process(request, response)
- raise NotImplementedError, "Your RackHttpHandler subclass is supposed to override service(request)"
- end
+ # do something useful with request (a Rack::Request) and use
+ # response to fill your Rack::Response
+ def process(request, response)
+ raise NotImplementedError, "Your RackHttpHandler subclass is supposed to override service(request)"
+ end
end
diff --git a/lib/puppet/network/http/rack/rest.rb b/lib/puppet/network/http/rack/rest.rb
index 5245275dd..e5f50c465 100644
--- a/lib/puppet/network/http/rack/rest.rb
+++ b/lib/puppet/network/http/rack/rest.rb
@@ -3,100 +3,100 @@ require 'puppet/network/http/rack/httphandler'
class Puppet::Network::HTTP::RackREST < Puppet::Network::HTTP::RackHttpHandler
- include Puppet::Network::HTTP::Handler
+ include Puppet::Network::HTTP::Handler
- HEADER_ACCEPT = 'HTTP_ACCEPT'.freeze
- ContentType = 'Content-Type'.freeze
+ HEADER_ACCEPT = 'HTTP_ACCEPT'.freeze
+ ContentType = 'Content-Type'.freeze
- CHUNK_SIZE = 8192
+ CHUNK_SIZE = 8192
- class RackFile
- def initialize(file)
- @file = file
- end
-
- def each
- while chunk = @file.read(CHUNK_SIZE)
- yield chunk
- end
- end
-
- def close
- @file.close
- end
- end
-
- def initialize(args={})
- super()
- initialize_for_puppet(args)
+ class RackFile
+ def initialize(file)
+ @file = file
end
- def set_content_type(response, format)
- response[ContentType] = format_to_mime(format)
+ def each
+ while chunk = @file.read(CHUNK_SIZE)
+ yield chunk
+ end
end
- # produce the body of the response
- def set_response(response, result, status = 200)
- response.status = status
- unless result.is_a?(File)
- response.write result
- else
- response["Content-Length"] = result.stat.size
- response.body = RackFile.new(result)
- end
+ def close
+ @file.close
end
-
- # Retrieve the accept header from the http request.
- def accept_header(request)
- request.env[HEADER_ACCEPT]
- end
-
- # Retrieve the accept header from the http request.
- def content_type_header(request)
- request.content_type
+ end
+
+ def initialize(args={})
+ super()
+ initialize_for_puppet(args)
+ end
+
+ def set_content_type(response, format)
+ response[ContentType] = format_to_mime(format)
+ end
+
+ # produce the body of the response
+ def set_response(response, result, status = 200)
+ response.status = status
+ unless result.is_a?(File)
+ response.write result
+ else
+ response["Content-Length"] = result.stat.size
+ response.body = RackFile.new(result)
end
-
- # Return which HTTP verb was used in this request.
- def http_method(request)
- request.request_method
+ end
+
+ # Retrieve the accept header from the http request.
+ def accept_header(request)
+ request.env[HEADER_ACCEPT]
+ end
+
+ # Retrieve the accept header from the http request.
+ def content_type_header(request)
+ request.content_type
+ end
+
+ # Return which HTTP verb was used in this request.
+ def http_method(request)
+ request.request_method
+ end
+
+ # Return the query params for this request.
+ def params(request)
+ result = decode_params(request.params)
+ result.merge(extract_client_info(request))
+ end
+
+ # what path was requested? (this is, without any query parameters)
+ def path(request)
+ request.path
+ end
+
+ # return the request body
+ # request.body has some limitiations, so we need to concat it back
+ # into a regular string, which is something puppet can use.
+ def body(request)
+ body = ''
+ request.body.each { |part| body += part }
+ body
+ end
+
+ def extract_client_info(request)
+ result = {}
+ result[:ip] = request.ip
+
+ # if we find SSL info in the headers, use them to get a hostname.
+ # try this with :ssl_client_header, which defaults should work for
+ # Apache with StdEnvVars.
+ if dn = request.env[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
+ result[:node] = dn_matchdata[1].to_str
+ result[:authenticated] = (request.env[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
+ else
+ result[:node] = resolve_node(result)
+ result[:authenticated] = false
end
- # Return the query params for this request.
- def params(request)
- result = decode_params(request.params)
- result.merge(extract_client_info(request))
- end
-
- # what path was requested? (this is, without any query parameters)
- def path(request)
- request.path
- end
-
- # return the request body
- # request.body has some limitiations, so we need to concat it back
- # into a regular string, which is something puppet can use.
- def body(request)
- body = ''
- request.body.each { |part| body += part }
- body
- end
-
- def extract_client_info(request)
- result = {}
- result[:ip] = request.ip
-
- # if we find SSL info in the headers, use them to get a hostname.
- # try this with :ssl_client_header, which defaults should work for
- # Apache with StdEnvVars.
- if dn = request.env[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
- result[:node] = dn_matchdata[1].to_str
- result[:authenticated] = (request.env[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
- else
- result[:node] = resolve_node(result)
- result[:authenticated] = false
- end
-
- result
- end
+ result
+ end
end
diff --git a/lib/puppet/network/http/rack/xmlrpc.rb b/lib/puppet/network/http/rack/xmlrpc.rb
index c3209a686..f75342783 100644
--- a/lib/puppet/network/http/rack/xmlrpc.rb
+++ b/lib/puppet/network/http/rack/xmlrpc.rb
@@ -3,63 +3,63 @@ require 'puppet/network/xmlrpc/server'
require 'resolv'
class Puppet::Network::HTTP::RackXMLRPC < Puppet::Network::HTTP::RackHttpHandler
- def initialize(handlers)
- @xmlrpc_server = Puppet::Network::XMLRPCServer.new
- handlers.each do |name|
- Puppet.debug " -> register xmlrpc namespace #{name}"
- unless handler = Puppet::Network::Handler.handler(name)
- raise ArgumentError, "Invalid XMLRPC handler #{name}"
- end
- @xmlrpc_server.add_handler(handler.interface, handler.new({}))
- end
- super()
+ def initialize(handlers)
+ @xmlrpc_server = Puppet::Network::XMLRPCServer.new
+ handlers.each do |name|
+ Puppet.debug " -> register xmlrpc namespace #{name}"
+ unless handler = Puppet::Network::Handler.handler(name)
+ raise ArgumentError, "Invalid XMLRPC handler #{name}"
+ end
+ @xmlrpc_server.add_handler(handler.interface, handler.new({}))
end
+ super()
+ end
- def process(request, response)
- # errors are sent as text/plain
- response['Content-Type'] = 'text/plain'
- if not request.post?
- response.status = 405
- response.write 'Method Not Allowed'
- return
- end
- if request.media_type != "text/xml"
- response.status = 400
- response.write 'Bad Request'
- return
- end
+ def process(request, response)
+ # errors are sent as text/plain
+ response['Content-Type'] = 'text/plain'
+ if not request.post?
+ response.status = 405
+ response.write 'Method Not Allowed'
+ return
+ end
+ if request.media_type != "text/xml"
+ response.status = 400
+ response.write 'Bad Request'
+ return
+ end
- # get auth/certificate data
- client_request = build_client_request(request)
+ # get auth/certificate data
+ client_request = build_client_request(request)
- response_body = @xmlrpc_server.process(request.body.read, client_request)
+ response_body = @xmlrpc_server.process(request.body.read, client_request)
- response.status = 200
- response['Content-Type'] = 'text/xml; charset=utf-8'
- response.write response_body
- end
+ response.status = 200
+ response['Content-Type'] = 'text/xml; charset=utf-8'
+ response.write response_body
+ end
- def build_client_request(request)
- ip = request.ip
+ def build_client_request(request)
+ ip = request.ip
- # if we find SSL info in the headers, use them to get a hostname.
- # try this with :ssl_client_header, which defaults should work for
- # Apache with StdEnvVars.
- if dn = request.env[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
- node = dn_matchdata[1].to_str
- authenticated = (request.env[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
- else
- begin
- node = Resolv.getname(ip)
- rescue => detail
- Puppet.err "Could not resolve #{ip}: #{detail}"
- node = "unknown"
- end
- authenticated = false
- end
-
- Puppet::Network::ClientRequest.new(node, ip, authenticated)
+ # if we find SSL info in the headers, use them to get a hostname.
+ # try this with :ssl_client_header, which defaults should work for
+ # Apache with StdEnvVars.
+ if dn = request.env[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
+ node = dn_matchdata[1].to_str
+ authenticated = (request.env[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
+ else
+ begin
+ node = Resolv.getname(ip)
+ rescue => detail
+ Puppet.err "Could not resolve #{ip}: #{detail}"
+ node = "unknown"
+ end
+ authenticated = false
end
+ Puppet::Network::ClientRequest.new(node, ip, authenticated)
+ end
+
end
diff --git a/lib/puppet/network/http/webrick.rb b/lib/puppet/network/http/webrick.rb
index 66932ad2c..8ed0b28ca 100644
--- a/lib/puppet/network/http/webrick.rb
+++ b/lib/puppet/network/http/webrick.rb
@@ -8,132 +8,132 @@ require 'puppet/ssl/certificate'
require 'puppet/ssl/certificate_revocation_list'
class Puppet::Network::HTTP::WEBrick
- def initialize(args = {})
- @listening = false
- @mutex = Mutex.new
+ def initialize(args = {})
+ @listening = false
+ @mutex = Mutex.new
+ end
+
+ def self.class_for_protocol(protocol)
+ return Puppet::Network::HTTP::WEBrickREST if protocol.to_sym == :rest
+ raise "Unknown protocol [#{protocol}]."
+ end
+
+ def listen(args = {})
+ raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
+ raise ArgumentError, ":address must be specified." unless args[:address]
+ raise ArgumentError, ":port must be specified." unless args[:port]
+
+ @protocols = args[:protocols]
+ @xmlrpc_handlers = args[:xmlrpc_handlers]
+
+ arguments = {:BindAddress => args[:address], :Port => args[:port]}
+ arguments.merge!(setup_logger)
+ arguments.merge!(setup_ssl)
+
+ @server = WEBrick::HTTPServer.new(arguments)
+ @server.listeners.each { |l| l.start_immediately = false }
+
+ setup_handlers
+
+ @mutex.synchronize do
+ raise "WEBrick server is already listening" if @listening
+ @listening = true
+ @thread = Thread.new {
+ @server.start { |sock|
+ raise "Client disconnected before connection could be established" unless IO.select([sock],nil,nil,0.1)
+ sock.accept
+ @server.run(sock)
+ }
+ }
+ sleep 0.1 until @server.status == :Running
end
-
- def self.class_for_protocol(protocol)
- return Puppet::Network::HTTP::WEBrickREST if protocol.to_sym == :rest
- raise "Unknown protocol [#{protocol}]."
+ end
+
+ def unlisten
+ @mutex.synchronize do
+ raise "WEBrick server is not listening" unless @listening
+ @server.shutdown
+ @thread.join
+ @server = nil
+ @listening = false
end
+ end
- def listen(args = {})
- raise ArgumentError, ":protocols must be specified." if !args[:protocols] or args[:protocols].empty?
- raise ArgumentError, ":address must be specified." unless args[:address]
- raise ArgumentError, ":port must be specified." unless args[:port]
-
- @protocols = args[:protocols]
- @xmlrpc_handlers = args[:xmlrpc_handlers]
-
- arguments = {:BindAddress => args[:address], :Port => args[:port]}
- arguments.merge!(setup_logger)
- arguments.merge!(setup_ssl)
-
- @server = WEBrick::HTTPServer.new(arguments)
- @server.listeners.each { |l| l.start_immediately = false }
-
- setup_handlers
-
- @mutex.synchronize do
- raise "WEBrick server is already listening" if @listening
- @listening = true
- @thread = Thread.new {
- @server.start { |sock|
- raise "Client disconnected before connection could be established" unless IO.select([sock],nil,nil,0.1)
- sock.accept
- @server.run(sock)
- }
- }
- sleep 0.1 until @server.status == :Running
- end
+ def listening?
+ @mutex.synchronize do
+ @listening
end
+ end
- def unlisten
- @mutex.synchronize do
- raise "WEBrick server is not listening" unless @listening
- @server.shutdown
- @thread.join
- @server = nil
- @listening = false
- end
- end
+ # Configure our http log file.
+ def setup_logger
+ # Make sure the settings are all ready for us.
+ Puppet.settings.use(:main, :ssl, Puppet[:name])
- def listening?
- @mutex.synchronize do
- @listening
- end
+ if Puppet.run_mode.master?
+ file = Puppet[:masterhttplog]
+ else
+ file = Puppet[:httplog]
end
- # Configure our http log file.
- def setup_logger
- # Make sure the settings are all ready for us.
- Puppet.settings.use(:main, :ssl, Puppet[:name])
-
- if Puppet.run_mode.master?
- file = Puppet[:masterhttplog]
- else
- file = Puppet[:httplog]
- end
-
- # open the log manually to prevent file descriptor leak
- file_io = ::File.open(file, "a+")
- file_io.sync
- file_io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
-
- args = [file_io]
- args << WEBrick::Log::DEBUG if Puppet::Util::Log.level == :debug
-
- logger = WEBrick::Log.new(*args)
- return :Logger => logger, :AccessLog => [
- [logger, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
- [logger, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
- ]
- end
+ # open the log manually to prevent file descriptor leak
+ file_io = ::File.open(file, "a+")
+ file_io.sync
+ file_io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
- # Add all of the ssl cert information.
- def setup_ssl
- results = {}
+ args = [file_io]
+ args << WEBrick::Log::DEBUG if Puppet::Util::Log.level == :debug
- # Get the cached copy. We know it's been generated, too.
- host = Puppet::SSL::Host.localhost
+ logger = WEBrick::Log.new(*args)
+ return :Logger => logger, :AccessLog => [
+ [logger, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
+ [logger, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
+ ]
+ end
- raise Puppet::Error, "Could not retrieve certificate for #{host.name} and not running on a valid certificate authority" unless host.certificate
+ # Add all of the ssl cert information.
+ def setup_ssl
+ results = {}
- results[:SSLPrivateKey] = host.key.content
- results[:SSLCertificate] = host.certificate.content
- results[:SSLStartImmediately] = true
- results[:SSLEnable] = true
+ # Get the cached copy. We know it's been generated, too.
+ host = Puppet::SSL::Host.localhost
- raise Puppet::Error, "Could not find CA certificate" unless Puppet::SSL::Certificate.find(Puppet::SSL::CA_NAME)
+ raise Puppet::Error, "Could not retrieve certificate for #{host.name} and not running on a valid certificate authority" unless host.certificate
- results[:SSLCACertificateFile] = Puppet[:localcacert]
- results[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
+ results[:SSLPrivateKey] = host.key.content
+ results[:SSLCertificate] = host.certificate.content
+ results[:SSLStartImmediately] = true
+ results[:SSLEnable] = true
- results[:SSLCertificateStore] = host.ssl_store
+ raise Puppet::Error, "Could not find CA certificate" unless Puppet::SSL::Certificate.find(Puppet::SSL::CA_NAME)
- results
- end
+ results[:SSLCACertificateFile] = Puppet[:localcacert]
+ results[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
- private
+ results[:SSLCertificateStore] = host.ssl_store
- def setup_handlers
- # Set up the new-style protocols.
- klass = self.class.class_for_protocol(:rest)
- @server.mount('/', klass, :this_value_is_apparently_necessary_but_unused)
+ results
+ end
- # And then set up xmlrpc, if configured.
- @server.mount("/RPC2", xmlrpc_servlet) if @protocols.include?(:xmlrpc) and ! @xmlrpc_handlers.empty?
- end
+ private
- # Create our xmlrpc servlet, which provides backward compatibility.
- def xmlrpc_servlet
- handlers = @xmlrpc_handlers.collect { |handler|
- unless hclass = Puppet::Network::Handler.handler(handler)
- raise "Invalid xmlrpc handler #{handler}"
- end
- hclass.new({})
- }
- Puppet::Network::XMLRPC::WEBrickServlet.new handlers
- end
+ def setup_handlers
+ # Set up the new-style protocols.
+ klass = self.class.class_for_protocol(:rest)
+ @server.mount('/', klass, :this_value_is_apparently_necessary_but_unused)
+
+ # And then set up xmlrpc, if configured.
+ @server.mount("/RPC2", xmlrpc_servlet) if @protocols.include?(:xmlrpc) and ! @xmlrpc_handlers.empty?
+ end
+
+ # Create our xmlrpc servlet, which provides backward compatibility.
+ def xmlrpc_servlet
+ handlers = @xmlrpc_handlers.collect { |handler|
+ unless hclass = Puppet::Network::Handler.handler(handler)
+ raise "Invalid xmlrpc handler #{handler}"
+ end
+ hclass.new({})
+ }
+ Puppet::Network::XMLRPC::WEBrickServlet.new handlers
+ end
end
diff --git a/lib/puppet/network/http/webrick/rest.rb b/lib/puppet/network/http/webrick/rest.rb
index 7526099ee..91008aa1a 100644
--- a/lib/puppet/network/http/webrick/rest.rb
+++ b/lib/puppet/network/http/webrick/rest.rb
@@ -3,78 +3,78 @@ require 'resolv'
class Puppet::Network::HTTP::WEBrickREST < WEBrick::HTTPServlet::AbstractServlet
- include Puppet::Network::HTTP::Handler
+ include Puppet::Network::HTTP::Handler
- def initialize(server, handler)
- raise ArgumentError, "server is required" unless server
- super(server)
- initialize_for_puppet(:server => server, :handler => handler)
- end
+ def initialize(server, handler)
+ raise ArgumentError, "server is required" unless server
+ super(server)
+ initialize_for_puppet(:server => server, :handler => handler)
+ end
- # Retrieve the request parameters, including authentication information.
- def params(request)
- result = request.query
- result = decode_params(result)
- result.merge(client_information(request))
- end
+ # Retrieve the request parameters, including authentication information.
+ def params(request)
+ result = request.query
+ result = decode_params(result)
+ result.merge(client_information(request))
+ end
- # WEBrick uses a service method to respond to requests. Simply delegate to the handler response method.
- def service(request, response)
- process(request, response)
- end
+ # WEBrick uses a service method to respond to requests. Simply delegate to the handler response method.
+ def service(request, response)
+ process(request, response)
+ end
- def accept_header(request)
- request["accept"]
- end
+ def accept_header(request)
+ request["accept"]
+ end
- def content_type_header(request)
- request["content-type"]
- end
+ def content_type_header(request)
+ request["content-type"]
+ end
- def http_method(request)
- request.request_method
- end
+ def http_method(request)
+ request.request_method
+ end
- def path(request)
- request.path
- end
+ def path(request)
+ request.path
+ end
- def body(request)
- request.body
- end
+ def body(request)
+ request.body
+ end
- # Set the specified format as the content type of the response.
- def set_content_type(response, format)
- response["content-type"] = format_to_mime(format)
- end
+ # Set the specified format as the content type of the response.
+ def set_content_type(response, format)
+ response["content-type"] = format_to_mime(format)
+ end
- def set_response(response, result, status = 200)
- response.status = status
- if status >= 200 and status != 304
- response.body = result
- response["content-length"] = result.stat.size if result.is_a?(File)
- end
- response.reason_phrase = result if status < 200 or status >= 300
+ def set_response(response, result, status = 200)
+ response.status = status
+ if status >= 200 and status != 304
+ response.body = result
+ response["content-length"] = result.stat.size if result.is_a?(File)
end
+ response.reason_phrase = result if status < 200 or status >= 300
+ end
- # Retrieve node/cert/ip information from the request object.
- def client_information(request)
- result = {}
- if peer = request.peeraddr and ip = peer[3]
- result[:ip] = ip
- end
-
- # If they have a certificate (which will almost always be true)
- # then we get the hostname from the cert, instead of via IP
- # info
- result[:authenticated] = false
- if cert = request.client_cert and nameary = cert.subject.to_a.find { |ary| ary[0] == "CN" }
- result[:node] = nameary[1]
- result[:authenticated] = true
- else
- result[:node] = resolve_node(result)
- end
+ # Retrieve node/cert/ip information from the request object.
+ def client_information(request)
+ result = {}
+ if peer = request.peeraddr and ip = peer[3]
+ result[:ip] = ip
+ end
- result
+ # If they have a certificate (which will almost always be true)
+ # then we get the hostname from the cert, instead of via IP
+ # info
+ result[:authenticated] = false
+ if cert = request.client_cert and nameary = cert.subject.to_a.find { |ary| ary[0] == "CN" }
+ result[:node] = nameary[1]
+ result[:authenticated] = true
+ else
+ result[:node] = resolve_node(result)
end
+
+ result
+ end
end
diff --git a/lib/puppet/network/http_pool.rb b/lib/puppet/network/http_pool.rb
index b4f40c6fe..a3b055572 100644
--- a/lib/puppet/network/http_pool.rb
+++ b/lib/puppet/network/http_pool.rb
@@ -6,111 +6,111 @@ module Puppet::Network; end
# Manage Net::HTTP instances for keep-alive.
module Puppet::Network::HttpPool
- class << self
- include Puppet::Util::Cacher
+ class << self
+ include Puppet::Util::Cacher
- private
+ private
- cached_attr(:http_cache) { Hash.new }
- end
+ cached_attr(:http_cache) { Hash.new }
+ end
- # Use the global localhost instance.
- def self.ssl_host
- Puppet::SSL::Host.localhost
- end
+ # Use the global localhost instance.
+ def self.ssl_host
+ Puppet::SSL::Host.localhost
+ end
- # 2008/03/23
- # LAK:WARNING: Enabling this has a high propability of
- # causing corrupt files and who knows what else. See #1010.
- HTTP_KEEP_ALIVE = false
+ # 2008/03/23
+ # LAK:WARNING: Enabling this has a high propability of
+ # causing corrupt files and who knows what else. See #1010.
+ HTTP_KEEP_ALIVE = false
- def self.keep_alive?
- HTTP_KEEP_ALIVE
- end
+ def self.keep_alive?
+ HTTP_KEEP_ALIVE
+ end
- # Clear our http cache, closing all connections.
- def self.clear_http_instances
- http_cache.each do |name, connection|
- connection.finish if connection.started?
- end
- Puppet::Util::Cacher.expire
+ # Clear our http cache, closing all connections.
+ def self.clear_http_instances
+ http_cache.each do |name, connection|
+ connection.finish if connection.started?
end
-
- # Make sure we set the driver up when we read the cert in.
- def self.read_cert
- if val = super # This calls read_cert from the Puppet::SSLCertificates::Support module.
- # Clear out all of our connections, since they previously had no cert and now they
- # should have them.
- clear_http_instances
- return val
- else
- return false
- end
+ Puppet::Util::Cacher.expire
+ end
+
+ # Make sure we set the driver up when we read the cert in.
+ def self.read_cert
+ if val = super # This calls read_cert from the Puppet::SSLCertificates::Support module.
+ # Clear out all of our connections, since they previously had no cert and now they
+ # should have them.
+ clear_http_instances
+ return val
+ else
+ return false
end
-
- # Use cert information from a Puppet client to set up the http object.
- def self.cert_setup(http)
- # Just no-op if we don't have certs.
- return false unless FileTest.exist?(Puppet[:hostcert]) and FileTest.exist?(Puppet[:localcacert])
-
- http.cert_store = ssl_host.ssl_store
- http.ca_file = Puppet[:localcacert]
- http.cert = ssl_host.certificate.content
- http.verify_mode = OpenSSL::SSL::VERIFY_PEER
- http.key = ssl_host.key.content
- http.verify_callback = self.method(:ssl_verify_callback).to_proc if Puppet[:debug]
+ end
+
+ # Use cert information from a Puppet client to set up the http object.
+ def self.cert_setup(http)
+ # Just no-op if we don't have certs.
+ return false unless FileTest.exist?(Puppet[:hostcert]) and FileTest.exist?(Puppet[:localcacert])
+
+ http.cert_store = ssl_host.ssl_store
+ http.ca_file = Puppet[:localcacert]
+ http.cert = ssl_host.certificate.content
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
+ http.key = ssl_host.key.content
+ http.verify_callback = self.method(:ssl_verify_callback).to_proc if Puppet[:debug]
+ end
+
+ def self.ssl_verify_callback(peer_ok, x509_store_ctx)
+ if not peer_ok
+ Puppet.debug "OpenSSL: Error(#{x509_store_ctx.error}): #{x509_store_ctx.error_string}"
+ Puppet.debug "OpenSSL: Cert: #{x509_store_ctx.current_cert.issuer}"
+ Puppet.debug "OpenSSL: Current CRL: #{x509_store_ctx.current_crl}"
+ Puppet.debug "OpenSSL: Chain:"
+ x509_store_ctx.chain.each_index { |i| Puppet.debug "OpenSSL: \t#{i} #{x509_store_ctx.chain[i].issuer}" }
end
-
- def self.ssl_verify_callback(peer_ok, x509_store_ctx)
- if not peer_ok
- Puppet.debug "OpenSSL: Error(#{x509_store_ctx.error}): #{x509_store_ctx.error_string}"
- Puppet.debug "OpenSSL: Cert: #{x509_store_ctx.current_cert.issuer}"
- Puppet.debug "OpenSSL: Current CRL: #{x509_store_ctx.current_crl}"
- Puppet.debug "OpenSSL: Chain:"
- x509_store_ctx.chain.each_index { |i| Puppet.debug "OpenSSL: \t#{i} #{x509_store_ctx.chain[i].issuer}" }
- end
- peer_ok
+ peer_ok
+ end
+
+ # Retrieve a cached http instance if caching is enabled, else return
+ # a new one.
+ def self.http_instance(host, port, reset = false)
+ # We overwrite the uninitialized @http here with a cached one.
+ key = "#{host}:#{port}"
+
+ # Return our cached instance if we've got a cache, as long as we're not
+ # resetting the instance.
+ if keep_alive?
+ return http_cache[key] if ! reset and http_cache[key]
+
+ # Clean up old connections if we have them.
+ if http = http_cache[key]
+ http_cache.delete(key)
+ http.finish if http.started?
+ end
end
- # Retrieve a cached http instance if caching is enabled, else return
- # a new one.
- def self.http_instance(host, port, reset = false)
- # We overwrite the uninitialized @http here with a cached one.
- key = "#{host}:#{port}"
-
- # Return our cached instance if we've got a cache, as long as we're not
- # resetting the instance.
- if keep_alive?
- return http_cache[key] if ! reset and http_cache[key]
-
- # Clean up old connections if we have them.
- if http = http_cache[key]
- http_cache.delete(key)
- http.finish if http.started?
- end
- end
-
- args = [host, port]
- if Puppet[:http_proxy_host] == "none"
- args << nil << nil
- else
- args << Puppet[:http_proxy_host] << Puppet[:http_proxy_port]
- end
- http = Net::HTTP.new(*args)
-
- # Pop open the http client a little; older versions of Net::HTTP(s) didn't
- # give us a reader for ca_file... Grr...
- class << http; attr_accessor :ca_file; end
-
- http.use_ssl = true
- # Use configured timeout (#1176)
- http.read_timeout = Puppet[:configtimeout]
- http.open_timeout = Puppet[:configtimeout]
-
- cert_setup(http)
-
- http_cache[key] = http if keep_alive?
-
- http
+ args = [host, port]
+ if Puppet[:http_proxy_host] == "none"
+ args << nil << nil
+ else
+ args << Puppet[:http_proxy_host] << Puppet[:http_proxy_port]
end
+ http = Net::HTTP.new(*args)
+
+ # Pop open the http client a little; older versions of Net::HTTP(s) didn't
+ # give us a reader for ca_file... Grr...
+ class << http; attr_accessor :ca_file; end
+
+ http.use_ssl = true
+ # Use configured timeout (#1176)
+ http.read_timeout = Puppet[:configtimeout]
+ http.open_timeout = Puppet[:configtimeout]
+
+ cert_setup(http)
+
+ http_cache[key] = http if keep_alive?
+
+ http
+ end
end
diff --git a/lib/puppet/network/http_server/mongrel.rb b/lib/puppet/network/http_server/mongrel.rb
index 0f81bf2a2..9bd949a08 100644
--- a/lib/puppet/network/http_server/mongrel.rb
+++ b/lib/puppet/network/http_server/mongrel.rb
@@ -49,102 +49,102 @@ require 'resolv'
# handler.xmlrpc_server.add_handler("my.add") { |a, b| a.to_i + b.to_i }
# </pre>
module Puppet::Network
- class HTTPServer::Mongrel < ::Mongrel::HttpHandler
- attr_reader :xmlrpc_server
-
- def initialize(handlers)
- if Puppet[:debug]
- $mongrel_debug_client = true
- Puppet.debug 'Mongrel client debugging enabled. [$mongrel_debug_client = true].'
- end
- # Create a new instance of BasicServer. We are supposed to subclass it
- # but that does not make sense since we would not introduce any new
- # behaviour and we have to subclass Mongrel::HttpHandler so our handler
- # works for Mongrel.
- @xmlrpc_server = Puppet::Network::XMLRPCServer.new
- handlers.each do |name|
- unless handler = Puppet::Network::Handler.handler(name)
- raise ArgumentError, "Invalid handler #{name}"
- end
- @xmlrpc_server.add_handler(handler.interface, handler.new({}))
- end
+ class HTTPServer::Mongrel < ::Mongrel::HttpHandler
+ attr_reader :xmlrpc_server
+
+ def initialize(handlers)
+ if Puppet[:debug]
+ $mongrel_debug_client = true
+ Puppet.debug 'Mongrel client debugging enabled. [$mongrel_debug_client = true].'
+ end
+ # Create a new instance of BasicServer. We are supposed to subclass it
+ # but that does not make sense since we would not introduce any new
+ # behaviour and we have to subclass Mongrel::HttpHandler so our handler
+ # works for Mongrel.
+ @xmlrpc_server = Puppet::Network::XMLRPCServer.new
+ handlers.each do |name|
+ unless handler = Puppet::Network::Handler.handler(name)
+ raise ArgumentError, "Invalid handler #{name}"
end
+ @xmlrpc_server.add_handler(handler.interface, handler.new({}))
+ end
+ end
- # This method produces the same results as XMLRPC::CGIServer.serve
- # from Ruby's stdlib XMLRPC implementation.
- def process(request, response)
- # Make sure this has been a POST as required for XMLRPC.
- request_method = request.params[Mongrel::Const::REQUEST_METHOD] || Mongrel::Const::GET
- if request_method != "POST"
- response.start(405) { |head, out| out.write("Method Not Allowed") }
- return
- end
-
- # Make sure the user has sent text/xml data.
- request_mime = request.params["CONTENT_TYPE"] || "text/plain"
- if parse_content_type(request_mime).first != "text/xml"
- response.start(400) { |head, out| out.write("Bad Request") }
- return
- end
-
- # Make sure there is data in the body at all.
- length = request.params[Mongrel::Const::CONTENT_LENGTH].to_i
- if length <= 0
- response.start(411) { |head, out| out.write("Length Required") }
- return
- end
-
- # Check the body to be valid.
- if request.body.nil? or request.body.size != length
- response.start(400) { |head, out| out.write("Bad Request") }
- return
- end
-
- info = client_info(request)
-
- # All checks above passed through
- response.start(200) do |head, out|
- head["Content-Type"] = "text/xml; charset=utf-8"
- begin
- out.write(@xmlrpc_server.process(request.body, info))
- rescue => detail
- puts detail.backtrace
- raise
- end
- end
+ # This method produces the same results as XMLRPC::CGIServer.serve
+ # from Ruby's stdlib XMLRPC implementation.
+ def process(request, response)
+ # Make sure this has been a POST as required for XMLRPC.
+ request_method = request.params[Mongrel::Const::REQUEST_METHOD] || Mongrel::Const::GET
+ if request_method != "POST"
+ response.start(405) { |head, out| out.write("Method Not Allowed") }
+ return
+ end
+
+ # Make sure the user has sent text/xml data.
+ request_mime = request.params["CONTENT_TYPE"] || "text/plain"
+ if parse_content_type(request_mime).first != "text/xml"
+ response.start(400) { |head, out| out.write("Bad Request") }
+ return
+ end
+
+ # Make sure there is data in the body at all.
+ length = request.params[Mongrel::Const::CONTENT_LENGTH].to_i
+ if length <= 0
+ response.start(411) { |head, out| out.write("Length Required") }
+ return
+ end
+
+ # Check the body to be valid.
+ if request.body.nil? or request.body.size != length
+ response.start(400) { |head, out| out.write("Bad Request") }
+ return
+ end
+
+ info = client_info(request)
+
+ # All checks above passed through
+ response.start(200) do |head, out|
+ head["Content-Type"] = "text/xml; charset=utf-8"
+ begin
+ out.write(@xmlrpc_server.process(request.body, info))
+ rescue => detail
+ puts detail.backtrace
+ raise
end
+ end
+ end
- private
-
- def client_info(request)
- params = request.params
- ip = params["HTTP_X_FORWARDED_FOR"] ? params["HTTP_X_FORWARDED_FOR"].split(',').last.strip : params["REMOTE_ADDR"]
- # JJM #906 The following dn.match regular expression is forgiving
- # enough to match the two Distinguished Name string contents
- # coming from Apache, Pound or other reverse SSL proxies.
- if dn = params[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
- client = dn_matchdata[1].to_str
- valid = (params[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
- else
- begin
- client = Resolv.getname(ip)
- rescue => detail
- Puppet.err "Could not resolve #{ip}: #{detail}"
- client = "unknown"
- end
- valid = false
- end
-
- info = Puppet::Network::ClientRequest.new(client, ip, valid)
-
- info
+ private
+
+ def client_info(request)
+ params = request.params
+ ip = params["HTTP_X_FORWARDED_FOR"] ? params["HTTP_X_FORWARDED_FOR"].split(',').last.strip : params["REMOTE_ADDR"]
+ # JJM #906 The following dn.match regular expression is forgiving
+ # enough to match the two Distinguished Name string contents
+ # coming from Apache, Pound or other reverse SSL proxies.
+ if dn = params[Puppet[:ssl_client_header]] and dn_matchdata = dn.match(/^.*?CN\s*=\s*(.*)/)
+ client = dn_matchdata[1].to_str
+ valid = (params[Puppet[:ssl_client_verify_header]] == 'SUCCESS')
+ else
+ begin
+ client = Resolv.getname(ip)
+ rescue => detail
+ Puppet.err "Could not resolve #{ip}: #{detail}"
+ client = "unknown"
end
+ valid = false
+ end
- # Taken from XMLRPC::ParseContentType
- def parse_content_type(str)
- a, *b = str.split(";")
- return a.strip, *b
- end
+ info = Puppet::Network::ClientRequest.new(client, ip, valid)
+
+ info
+ end
+
+ # Taken from XMLRPC::ParseContentType
+ def parse_content_type(str)
+ a, *b = str.split(";")
+ return a.strip, *b
end
+ end
end
diff --git a/lib/puppet/network/http_server/webrick.rb b/lib/puppet/network/http_server/webrick.rb
index e622b7127..1f4b3b0e7 100644
--- a/lib/puppet/network/http_server/webrick.rb
+++ b/lib/puppet/network/http_server/webrick.rb
@@ -10,146 +10,146 @@ require 'puppet/network/client'
require 'puppet/network/handler'
module Puppet
- class ServerError < RuntimeError; end
- module Network
- # The old-school, pure ruby webrick server, which is the default serving
- # mechanism.
- class HTTPServer::WEBrick < WEBrick::HTTPServer
- include Puppet::SSLCertificates::Support
-
- # Read the CA cert and CRL and populate an OpenSSL::X509::Store
- # with them, with flags appropriate for checking client
- # certificates for revocation
- def x509store
- unless File.exist?(Puppet[:cacrl])
- # No CRL, no store needed
- return nil
- end
- crl = OpenSSL::X509::CRL.new(File.read(Puppet[:cacrl]))
- store = OpenSSL::X509::Store.new
- store.purpose = OpenSSL::X509::PURPOSE_ANY
- store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
- raise Puppet::Error, "Could not find CA certificate" unless self.ca_cert
-
- store.add_file(Puppet[:localcacert])
- store.add_crl(crl)
- store
- end
-
- # Set up the http log.
- def httplog
- args = []
-
- # yuck; separate http logs
- file = nil
- Puppet.settings.use(:main, :ssl, Puppet[:name])
- if Puppet.run_mode.master?
- file = Puppet[:masterhttplog]
- else
- file = Puppet[:httplog]
- end
-
- # open the log manually to prevent file descriptor leak
- file_io = open(file, "a+")
- file_io.sync
- file_io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
-
- args << file_io
- args << WEBrick::Log::DEBUG if Puppet[:debug]
-
- log = WEBrick::Log.new(*args)
-
-
- log
- end
-
- # Create our server, yo.
- def initialize(hash = {})
- Puppet.info "Starting server for Puppet version #{Puppet.version}"
-
- if handlers = hash[:Handlers]
- handler_instances = setup_handlers(handlers)
- else
- raise ServerError, "A server must have handlers"
- end
-
- unless self.read_cert
- if ca = handler_instances.find { |handler| handler.is_a?(Puppet::Network::Handler.ca) }
- request_cert(ca)
- else
- raise Puppet::Error, "No certificate and no CA; cannot get cert"
- end
- end
-
- setup_webrick(hash)
-
- begin
- super(hash)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not start WEBrick: #{detail}"
- end
-
- # make sure children don't inherit the sockets
- listeners.each { |sock|
- sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
- }
-
- Puppet.info "Listening on port #{hash[:Port]}"
-
- # this creates a new servlet for every connection,
- # but all servlets have the same list of handlers
- # thus, the servlets can have their own state -- passing
- # around the requests and such -- but the handlers
- # have a global state
-
- # mount has to be called after the server is initialized
- servlet = Puppet::Network::XMLRPC::WEBrickServlet.new( handler_instances)
- self.mount("/RPC2", servlet)
- end
-
- # Create a ca client to set up our cert for us.
- def request_cert(ca)
- client = Puppet::Network::Client.ca.new(:CA => ca)
- raise Puppet::Error, "Could get certificate" unless client.request_cert
- end
-
- # Create all of our handler instances.
- def setup_handlers(handlers)
- raise ServerError, "Handlers must have arguments" unless handlers.is_a?(Hash)
-
- handlers.collect { |handler, args|
- hclass = nil
- unless hclass = Puppet::Network::Handler.handler(handler)
- raise ServerError, "Invalid handler #{handler}"
- end
- hclass.new(args)
- }
- end
-
- # Handle all of the many webrick arguments.
- def setup_webrick(hash)
- hash[:Port] ||= Puppet[:masterport]
- hash[:Logger] ||= self.httplog
- hash[:AccessLog] ||= [
- [ self.httplog, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
- [ self.httplog, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
- ]
-
- hash[:SSLCertificateStore] = x509store
- hash[:SSLCertificate] = self.cert
- hash[:SSLPrivateKey] = self.key
- hash[:SSLStartImmediately] = true
- hash[:SSLEnable] = true
- hash[:SSLCACertificateFile] = Puppet[:localcacert]
- hash[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
- hash[:SSLCertName] = nil
-
- if addr = Puppet[:bindaddress] and addr != ""
- hash[:BindAddress] = addr
- end
- end
+ class ServerError < RuntimeError; end
+ module Network
+ # The old-school, pure ruby webrick server, which is the default serving
+ # mechanism.
+ class HTTPServer::WEBrick < WEBrick::HTTPServer
+ include Puppet::SSLCertificates::Support
+
+ # Read the CA cert and CRL and populate an OpenSSL::X509::Store
+ # with them, with flags appropriate for checking client
+ # certificates for revocation
+ def x509store
+ unless File.exist?(Puppet[:cacrl])
+ # No CRL, no store needed
+ return nil
end
+ crl = OpenSSL::X509::CRL.new(File.read(Puppet[:cacrl]))
+ store = OpenSSL::X509::Store.new
+ store.purpose = OpenSSL::X509::PURPOSE_ANY
+ store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
+ raise Puppet::Error, "Could not find CA certificate" unless self.ca_cert
+
+ store.add_file(Puppet[:localcacert])
+ store.add_crl(crl)
+ store
+ end
+
+ # Set up the http log.
+ def httplog
+ args = []
+
+ # yuck; separate http logs
+ file = nil
+ Puppet.settings.use(:main, :ssl, Puppet[:name])
+ if Puppet.run_mode.master?
+ file = Puppet[:masterhttplog]
+ else
+ file = Puppet[:httplog]
+ end
+
+ # open the log manually to prevent file descriptor leak
+ file_io = open(file, "a+")
+ file_io.sync
+ file_io.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+
+ args << file_io
+ args << WEBrick::Log::DEBUG if Puppet[:debug]
+
+ log = WEBrick::Log.new(*args)
+
+
+ log
+ end
+
+ # Create our server, yo.
+ def initialize(hash = {})
+ Puppet.info "Starting server for Puppet version #{Puppet.version}"
+
+ if handlers = hash[:Handlers]
+ handler_instances = setup_handlers(handlers)
+ else
+ raise ServerError, "A server must have handlers"
+ end
+
+ unless self.read_cert
+ if ca = handler_instances.find { |handler| handler.is_a?(Puppet::Network::Handler.ca) }
+ request_cert(ca)
+ else
+ raise Puppet::Error, "No certificate and no CA; cannot get cert"
+ end
+ end
+
+ setup_webrick(hash)
+
+ begin
+ super(hash)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Could not start WEBrick: #{detail}"
+ end
+
+ # make sure children don't inherit the sockets
+ listeners.each { |sock|
+ sock.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
+ }
+
+ Puppet.info "Listening on port #{hash[:Port]}"
+
+ # this creates a new servlet for every connection,
+ # but all servlets have the same list of handlers
+ # thus, the servlets can have their own state -- passing
+ # around the requests and such -- but the handlers
+ # have a global state
+
+ # mount has to be called after the server is initialized
+ servlet = Puppet::Network::XMLRPC::WEBrickServlet.new( handler_instances)
+ self.mount("/RPC2", servlet)
+ end
+
+ # Create a ca client to set up our cert for us.
+ def request_cert(ca)
+ client = Puppet::Network::Client.ca.new(:CA => ca)
+ raise Puppet::Error, "Could get certificate" unless client.request_cert
+ end
+
+ # Create all of our handler instances.
+ def setup_handlers(handlers)
+ raise ServerError, "Handlers must have arguments" unless handlers.is_a?(Hash)
+
+ handlers.collect { |handler, args|
+ hclass = nil
+ unless hclass = Puppet::Network::Handler.handler(handler)
+ raise ServerError, "Invalid handler #{handler}"
+ end
+ hclass.new(args)
+ }
+ end
+
+ # Handle all of the many webrick arguments.
+ def setup_webrick(hash)
+ hash[:Port] ||= Puppet[:masterport]
+ hash[:Logger] ||= self.httplog
+ hash[:AccessLog] ||= [
+ [ self.httplog, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
+ [ self.httplog, WEBrick::AccessLog::REFERER_LOG_FORMAT ]
+ ]
+
+ hash[:SSLCertificateStore] = x509store
+ hash[:SSLCertificate] = self.cert
+ hash[:SSLPrivateKey] = self.key
+ hash[:SSLStartImmediately] = true
+ hash[:SSLEnable] = true
+ hash[:SSLCACertificateFile] = Puppet[:localcacert]
+ hash[:SSLVerifyClient] = OpenSSL::SSL::VERIFY_PEER
+ hash[:SSLCertName] = nil
+
+ if addr = Puppet[:bindaddress] and addr != ""
+ hash[:BindAddress] = addr
+ end
+ end
end
+ end
end
diff --git a/lib/puppet/network/rest_authconfig.rb b/lib/puppet/network/rest_authconfig.rb
index d233c8775..38a8f9a09 100644
--- a/lib/puppet/network/rest_authconfig.rb
+++ b/lib/puppet/network/rest_authconfig.rb
@@ -1,94 +1,94 @@
require 'puppet/network/authconfig'
module Puppet
- class Network::RestAuthConfig < Network::AuthConfig
+ class Network::RestAuthConfig < Network::AuthConfig
- attr_accessor :rights
+ attr_accessor :rights
- DEFAULT_ACL = [
- { :acl => "~ ^\/catalog\/([^\/]+)$", :method => :find, :allow => '$1', :authenticated => true },
- # this one will allow all file access, and thus delegate
- # to fileserver.conf
- { :acl => "/file" },
- { :acl => "/certificate_revocation_list/ca", :method => :find, :authenticated => true },
- { :acl => "/report", :method => :save, :authenticated => true },
- { :acl => "/certificate/ca", :method => :find, :authenticated => false },
- { :acl => "/certificate/", :method => :find, :authenticated => false },
- { :acl => "/certificate_request", :method => [:find, :save], :authenticated => false },
- { :acl => "/status", :method => [:find], :authenticated => true },
- { :acl => "/resource", :method => [:find, :save, :search], :authenticated => true },
- ]
+ DEFAULT_ACL = [
+ { :acl => "~ ^\/catalog\/([^\/]+)$", :method => :find, :allow => '$1', :authenticated => true },
+ # this one will allow all file access, and thus delegate
+ # to fileserver.conf
+ { :acl => "/file" },
+ { :acl => "/certificate_revocation_list/ca", :method => :find, :authenticated => true },
+ { :acl => "/report", :method => :save, :authenticated => true },
+ { :acl => "/certificate/ca", :method => :find, :authenticated => false },
+ { :acl => "/certificate/", :method => :find, :authenticated => false },
+ { :acl => "/certificate_request", :method => [:find, :save], :authenticated => false },
+ { :acl => "/status", :method => [:find], :authenticated => true },
+ { :acl => "/resource", :method => [:find, :save, :search], :authenticated => true },
+ ]
- def self.main
- add_acl = @main.nil?
- super
- @main.insert_default_acl if add_acl and !@main.exists?
- @main
- end
+ def self.main
+ add_acl = @main.nil?
+ super
+ @main.insert_default_acl if add_acl and !@main.exists?
+ @main
+ end
- # check wether this request is allowed in our ACL
- # raise an Puppet::Network::AuthorizedError if the request
- # is denied.
- def allowed?(request)
- read
+ # check wether this request is allowed in our ACL
+ # raise an Puppet::Network::AuthorizedError if the request
+ # is denied.
+ def allowed?(request)
+ read
- # we're splitting the request in part because
- # fail_on_deny could as well be called in the XMLRPC context
- # with a ClientRequest.
+ # we're splitting the request in part because
+ # fail_on_deny could as well be called in the XMLRPC context
+ # with a ClientRequest.
- @rights.fail_on_deny(
- build_uri(request),
+ @rights.fail_on_deny(
+ build_uri(request),
- :node => request.node,
- :ip => request.ip,
- :method => request.method,
- :environment => request.environment,
- :authenticated => request.authenticated)
- end
+ :node => request.node,
+ :ip => request.ip,
+ :method => request.method,
+ :environment => request.environment,
+ :authenticated => request.authenticated)
+ end
- def initialize(file = nil, parsenow = true)
- super(file || Puppet[:rest_authconfig], parsenow)
+ def initialize(file = nil, parsenow = true)
+ super(file || Puppet[:rest_authconfig], parsenow)
- # if we didn't read a file (ie it doesn't exist)
- # make sure we can create some default rights
- @rights ||= Puppet::Network::Rights.new
- end
+ # if we didn't read a file (ie it doesn't exist)
+ # make sure we can create some default rights
+ @rights ||= Puppet::Network::Rights.new
+ end
- def parse
- super()
- insert_default_acl
- end
+ def parse
+ super()
+ insert_default_acl
+ end
- # force regular ACLs to be present
- def insert_default_acl
- DEFAULT_ACL.each do |acl|
- unless rights[acl[:acl]]
- Puppet.info "Inserting default '#{acl[:acl]}'(#{acl[:authenticated] ? "auth" : "non-auth"}) acl because #{( !exists? ? "#{Puppet[:rest_authconfig]} doesn't exist" : "none where found in '#{@file}'")}"
- mk_acl(acl)
- end
- end
- # queue an empty (ie deny all) right for every other path
- # actually this is not strictly necessary as the rights system
- # denies not explicitely allowed paths
- unless rights["/"]
- rights.newright("/")
- rights.restrict_authenticated("/", :any)
- end
+ # force regular ACLs to be present
+ def insert_default_acl
+ DEFAULT_ACL.each do |acl|
+ unless rights[acl[:acl]]
+ Puppet.info "Inserting default '#{acl[:acl]}'(#{acl[:authenticated] ? "auth" : "non-auth"}) acl because #{( !exists? ? "#{Puppet[:rest_authconfig]} doesn't exist" : "none where found in '#{@file}'")}"
+ mk_acl(acl)
end
+ end
+ # queue an empty (ie deny all) right for every other path
+ # actually this is not strictly necessary as the rights system
+ # denies not explicitely allowed paths
+ unless rights["/"]
+ rights.newright("/")
+ rights.restrict_authenticated("/", :any)
+ end
+ end
- def mk_acl(acl)
- @rights.newright(acl[:acl])
- @rights.allow(acl[:acl], acl[:allow] || "*")
+ def mk_acl(acl)
+ @rights.newright(acl[:acl])
+ @rights.allow(acl[:acl], acl[:allow] || "*")
- if method = acl[:method]
- method = [method] unless method.is_a?(Array)
- method.each { |m| @rights.restrict_method(acl[:acl], m) }
- end
- @rights.restrict_authenticated(acl[:acl], acl[:authenticated]) unless acl[:authenticated].nil?
- end
+ if method = acl[:method]
+ method = [method] unless method.is_a?(Array)
+ method.each { |m| @rights.restrict_method(acl[:acl], m) }
+ end
+ @rights.restrict_authenticated(acl[:acl], acl[:authenticated]) unless acl[:authenticated].nil?
+ end
- def build_uri(request)
- "/#{request.indirection_name}/#{request.key}"
- end
+ def build_uri(request)
+ "/#{request.indirection_name}/#{request.key}"
end
+ end
end
diff --git a/lib/puppet/network/rest_authorization.rb b/lib/puppet/network/rest_authorization.rb
index d9a837050..e052245eb 100644
--- a/lib/puppet/network/rest_authorization.rb
+++ b/lib/puppet/network/rest_authorization.rb
@@ -3,21 +3,21 @@ require 'puppet/network/rest_authconfig'
module Puppet::Network
- module RestAuthorization
+ module RestAuthorization
- # Create our config object if necessary. If there's no configuration file
- # we install our defaults
- def authconfig
- @authconfig ||= Puppet::Network::RestAuthConfig.main
+ # Create our config object if necessary. If there's no configuration file
+ # we install our defaults
+ def authconfig
+ @authconfig ||= Puppet::Network::RestAuthConfig.main
- @authconfig
- end
+ @authconfig
+ end
- # Verify that our client has access.
- def check_authorization(request)
- authconfig.allowed?(request)
- end
+ # Verify that our client has access.
+ def check_authorization(request)
+ authconfig.allowed?(request)
end
+ end
end
diff --git a/lib/puppet/network/rights.rb b/lib/puppet/network/rights.rb
index a57260aa3..e3cd3179a 100755
--- a/lib/puppet/network/rights.rb
+++ b/lib/puppet/network/rights.rb
@@ -12,256 +12,256 @@ class AuthorizationError < Puppet::Error; end
# * path based rights (which are matched on a longest prefix basis)
class Rights
- # We basically just proxy directly to our rights. Each Right stores
- # its own auth abilities.
- [:allow, :deny, :restrict_method, :restrict_environment, :restrict_authenticated].each do |method|
- define_method(method) do |name, *args|
- if obj = self[name]
- obj.send(method, *args)
- else
- raise ArgumentError, "Unknown right '#{name}'"
- end
- end
+ # We basically just proxy directly to our rights. Each Right stores
+ # its own auth abilities.
+ [:allow, :deny, :restrict_method, :restrict_environment, :restrict_authenticated].each do |method|
+ define_method(method) do |name, *args|
+ if obj = self[name]
+ obj.send(method, *args)
+ else
+ raise ArgumentError, "Unknown right '#{name}'"
+ end
end
-
- # Check that name is allowed or not
- def allowed?(name, *args)
- begin
- fail_on_deny(name, :node => args[0], :ip => args[1])
- rescue AuthorizationError
- return false
- rescue ArgumentError
- # the namespace contract says we should raise this error
- # if we didn't find the right acl
- raise
- end
- true
+ end
+
+ # Check that name is allowed or not
+ def allowed?(name, *args)
+ begin
+ fail_on_deny(name, :node => args[0], :ip => args[1])
+ rescue AuthorizationError
+ return false
+ rescue ArgumentError
+ # the namespace contract says we should raise this error
+ # if we didn't find the right acl
+ raise
end
-
- def fail_on_deny(name, args = {})
- res = :nomatch
- right = @rights.find do |acl|
- found = false
- # an acl can return :dunno, which means "I'm not qualified to answer your question,
- # please ask someone else". This is used when for instance an acl matches, but not for the
- # current rest method, where we might think some other acl might be more specific.
- if match = acl.match?(name)
- args[:match] = match
- if (res = acl.allowed?(args[:node], args[:ip], args)) != :dunno
- # return early if we're allowed
- return if res
- # we matched, select this acl
- found = true
- end
- end
- found
- end
-
- # if we end here, then that means we either didn't match
- # or failed, in any case will throw an error to the outside world
- if name =~ /^\// or right
- # we're a patch ACL, let's fail
- msg = "#{(args[:node].nil? ? args[:ip] : "#{args[:node]}(#{args[:ip]})")} access to #{name} [#{args[:method]}]"
-
- msg += " authenticated " if args[:authenticated]
-
- error = AuthorizationError.new("Forbidden request: #{msg}")
- if right
- error.file = right.file
- error.line = right.line
- end
- Puppet.warning("Denying access: #{error}")
- else
- # there were no rights allowing/denying name
- # if name is not a path, let's throw
- error = ArgumentError.new "Unknown namespace right '#{name}'"
+ true
+ end
+
+ def fail_on_deny(name, args = {})
+ res = :nomatch
+ right = @rights.find do |acl|
+ found = false
+ # an acl can return :dunno, which means "I'm not qualified to answer your question,
+ # please ask someone else". This is used when for instance an acl matches, but not for the
+ # current rest method, where we might think some other acl might be more specific.
+ if match = acl.match?(name)
+ args[:match] = match
+ if (res = acl.allowed?(args[:node], args[:ip], args)) != :dunno
+ # return early if we're allowed
+ return if res
+ # we matched, select this acl
+ found = true
end
- raise error
+ end
+ found
end
- def initialize
- @rights = []
+ # if we end here, then that means we either didn't match
+ # or failed, in any case will throw an error to the outside world
+ if name =~ /^\// or right
+ # we're a patch ACL, let's fail
+ msg = "#{(args[:node].nil? ? args[:ip] : "#{args[:node]}(#{args[:ip]})")} access to #{name} [#{args[:method]}]"
+
+ msg += " authenticated " if args[:authenticated]
+
+ error = AuthorizationError.new("Forbidden request: #{msg}")
+ if right
+ error.file = right.file
+ error.line = right.line
+ end
+ Puppet.warning("Denying access: #{error}")
+ else
+ # there were no rights allowing/denying name
+ # if name is not a path, let's throw
+ error = ArgumentError.new "Unknown namespace right '#{name}'"
end
+ raise error
+ end
- def [](name)
- @rights.find { |acl| acl == name }
- end
+ def initialize
+ @rights = []
+ end
- def include?(name)
- @rights.include?(name)
- end
+ def [](name)
+ @rights.find { |acl| acl == name }
+ end
- def each
- @rights.each { |r| yield r.name,r }
- end
+ def include?(name)
+ @rights.include?(name)
+ end
- # Define a new right to which access can be provided.
- def newright(name, line=nil, file=nil)
- add_right( Right.new(name, line, file) )
- end
+ def each
+ @rights.each { |r| yield r.name,r }
+ end
- private
+ # Define a new right to which access can be provided.
+ def newright(name, line=nil, file=nil)
+ add_right( Right.new(name, line, file) )
+ end
- def add_right(right)
- if right.acl_type == :name and include?(right.key)
- raise ArgumentError, "Right '%s' already exists"
- end
- @rights << right
- sort_rights
- right
- end
+ private
- def sort_rights
- @rights.sort!
+ def add_right(right)
+ if right.acl_type == :name and include?(right.key)
+ raise ArgumentError, "Right '%s' already exists"
end
-
- # Retrieve a right by name.
- def right(name)
- self[name]
+ @rights << right
+ sort_rights
+ right
+ end
+
+ def sort_rights
+ @rights.sort!
+ end
+
+ # Retrieve a right by name.
+ def right(name)
+ self[name]
+ end
+
+ # A right.
+ class Right < Puppet::Network::AuthStore
+ include Puppet::FileCollection::Lookup
+
+ attr_accessor :name, :key, :acl_type
+ attr_accessor :methods, :environment, :authentication
+
+ ALL = [:save, :destroy, :find, :search]
+
+ Puppet::Util.logmethods(self, true)
+
+ def initialize(name, line, file)
+ @methods = []
+ @environment = []
+ @authentication = true # defaults to authenticated
+ @name = name
+ @line = line || 0
+ @file = file
+
+ case name
+ when Symbol
+ @acl_type = :name
+ @key = name
+ when /^\[(.+)\]$/
+ @acl_type = :name
+ @key = $1.intern if name.is_a?(String)
+ when /^\//
+ @acl_type = :regex
+ @key = Regexp.new("^" + Regexp.escape(name))
+ @methods = ALL
+ when /^~/ # this is a regex
+ @acl_type = :regex
+ @name = name.gsub(/^~\s+/,'')
+ @key = Regexp.new(@name)
+ @methods = ALL
+ else
+ raise ArgumentError, "Unknown right type '#{name}'"
+ end
+ super()
end
- # A right.
- class Right < Puppet::Network::AuthStore
- include Puppet::FileCollection::Lookup
-
- attr_accessor :name, :key, :acl_type
- attr_accessor :methods, :environment, :authentication
-
- ALL = [:save, :destroy, :find, :search]
-
- Puppet::Util.logmethods(self, true)
-
- def initialize(name, line, file)
- @methods = []
- @environment = []
- @authentication = true # defaults to authenticated
- @name = name
- @line = line || 0
- @file = file
-
- case name
- when Symbol
- @acl_type = :name
- @key = name
- when /^\[(.+)\]$/
- @acl_type = :name
- @key = $1.intern if name.is_a?(String)
- when /^\//
- @acl_type = :regex
- @key = Regexp.new("^" + Regexp.escape(name))
- @methods = ALL
- when /^~/ # this is a regex
- @acl_type = :regex
- @name = name.gsub(/^~\s+/,'')
- @key = Regexp.new(@name)
- @methods = ALL
- else
- raise ArgumentError, "Unknown right type '#{name}'"
- end
- super()
- end
-
- def to_s
- "access[#{@name}]"
- end
-
- # There's no real check to do at this point
- def valid?
- true
- end
+ def to_s
+ "access[#{@name}]"
+ end
- def regex?
- acl_type == :regex
- end
+ # There's no real check to do at this point
+ def valid?
+ true
+ end
- # does this right is allowed for this triplet?
- # if this right is too restrictive (ie we don't match this access method)
- # then return :dunno so that upper layers have a chance to try another right
- # tailored to the given method
- def allowed?(name, ip, args = {})
- return :dunno if acl_type == :regex and not @methods.include?(args[:method])
- return :dunno if acl_type == :regex and @environment.size > 0 and not @environment.include?(args[:environment])
- return :dunno if acl_type == :regex and not @authentication.nil? and args[:authenticated] != @authentication
-
- begin
- # make sure any capture are replaced if needed
- interpolate(args[:match]) if acl_type == :regex and args[:match]
- res = super(name,ip)
- ensure
- reset_interpolation if acl_type == :regex
- end
- res
- end
+ def regex?
+ acl_type == :regex
+ end
- # restrict this right to some method only
- def restrict_method(m)
- m = m.intern if m.is_a?(String)
+ # does this right is allowed for this triplet?
+ # if this right is too restrictive (ie we don't match this access method)
+ # then return :dunno so that upper layers have a chance to try another right
+ # tailored to the given method
+ def allowed?(name, ip, args = {})
+ return :dunno if acl_type == :regex and not @methods.include?(args[:method])
+ return :dunno if acl_type == :regex and @environment.size > 0 and not @environment.include?(args[:environment])
+ return :dunno if acl_type == :regex and not @authentication.nil? and args[:authenticated] != @authentication
+
+ begin
+ # make sure any capture are replaced if needed
+ interpolate(args[:match]) if acl_type == :regex and args[:match]
+ res = super(name,ip)
+ ensure
+ reset_interpolation if acl_type == :regex
+ end
+ res
+ end
- raise ArgumentError, "'#{m}' is not an allowed value for method directive" unless ALL.include?(m)
+ # restrict this right to some method only
+ def restrict_method(m)
+ m = m.intern if m.is_a?(String)
- # if we were allowing all methods, then starts from scratch
- if @methods === ALL
- @methods = []
- end
+ raise ArgumentError, "'#{m}' is not an allowed value for method directive" unless ALL.include?(m)
- raise ArgumentError, "'#{m}' is already in the '#{name}' ACL" if @methods.include?(m)
+ # if we were allowing all methods, then starts from scratch
+ if @methods === ALL
+ @methods = []
+ end
- @methods << m
- end
+ raise ArgumentError, "'#{m}' is already in the '#{name}' ACL" if @methods.include?(m)
- def restrict_environment(env)
- env = Puppet::Node::Environment.new(env)
- raise ArgumentError, "'#{env}' is already in the '#{name}' ACL" if @environment.include?(env)
+ @methods << m
+ end
- @environment << env
- end
+ def restrict_environment(env)
+ env = Puppet::Node::Environment.new(env)
+ raise ArgumentError, "'#{env}' is already in the '#{name}' ACL" if @environment.include?(env)
- def restrict_authenticated(authentication)
- case authentication
- when "yes", "on", "true", true
- authentication = true
- when "no", "off", "false", false
- authentication = false
- when "all","any", :all, :any
- authentication = nil
- else
- raise ArgumentError, "'#{name}' incorrect authenticated value: #{authentication}"
- end
- @authentication = authentication
- end
+ @environment << env
+ end
- def match?(key)
- # if we are a namespace compare directly
- return self.key == namespace_to_key(key) if acl_type == :name
+ def restrict_authenticated(authentication)
+ case authentication
+ when "yes", "on", "true", true
+ authentication = true
+ when "no", "off", "false", false
+ authentication = false
+ when "all","any", :all, :any
+ authentication = nil
+ else
+ raise ArgumentError, "'#{name}' incorrect authenticated value: #{authentication}"
+ end
+ @authentication = authentication
+ end
- # otherwise match with the regex
- self.key.match(key)
- end
+ def match?(key)
+ # if we are a namespace compare directly
+ return self.key == namespace_to_key(key) if acl_type == :name
- def namespace_to_key(key)
- key = key.intern if key.is_a?(String)
- key
- end
+ # otherwise match with the regex
+ self.key.match(key)
+ end
- # this is where all the magic happens.
- # we're sorting the rights array with this scheme:
- # * namespace rights are all in front
- # * regex path rights are then all queued in file order
- def <=>(rhs)
- # move namespace rights at front
- return self.acl_type == :name ? -1 : 1 if self.acl_type != rhs.acl_type
-
- # sort by creation order (ie first match appearing in the file will win)
- # that is don't sort, in which case the sort algorithm will order in the
- # natural array order (ie the creation order)
- 0
- end
+ def namespace_to_key(key)
+ key = key.intern if key.is_a?(String)
+ key
+ end
- def ==(name)
- return(acl_type == :name ? self.key == namespace_to_key(name) : self.name == name.gsub(/^~\s+/,''))
- end
+ # this is where all the magic happens.
+ # we're sorting the rights array with this scheme:
+ # * namespace rights are all in front
+ # * regex path rights are then all queued in file order
+ def <=>(rhs)
+ # move namespace rights at front
+ return self.acl_type == :name ? -1 : 1 if self.acl_type != rhs.acl_type
+
+ # sort by creation order (ie first match appearing in the file will win)
+ # that is don't sort, in which case the sort algorithm will order in the
+ # natural array order (ie the creation order)
+ 0
+ end
+ def ==(name)
+ return(acl_type == :name ? self.key == namespace_to_key(name) : self.name == name.gsub(/^~\s+/,''))
end
+ end
+
end
end
diff --git a/lib/puppet/network/server.rb b/lib/puppet/network/server.rb
index e4945bec9..d424b9c4a 100644
--- a/lib/puppet/network/server.rb
+++ b/lib/puppet/network/server.rb
@@ -2,164 +2,164 @@ require 'puppet/network/http'
require 'puppet/util/pidlock'
class Puppet::Network::Server
- attr_reader :server_type, :protocols, :address, :port
-
- # Put the daemon into the background.
- def daemonize
- if pid = fork
- Process.detach(pid)
- exit(0)
- end
-
- # Get rid of console logging
- Puppet::Util::Log.close(:console)
-
- Process.setsid
- Dir.chdir("/")
- begin
- $stdin.reopen "/dev/null"
- $stdout.reopen "/dev/null", "a"
- $stderr.reopen $stdout
- Puppet::Util::Log.reopen
- rescue => detail
- Puppet::Util.secure_open("/tmp/daemonout", "w") { |f|
- f.puts "Could not start #{Puppet[:name]}: #{detail}"
- }
- raise "Could not start #{Puppet[:name]}: #{detail}"
- end
+ attr_reader :server_type, :protocols, :address, :port
+
+ # Put the daemon into the background.
+ def daemonize
+ if pid = fork
+ Process.detach(pid)
+ exit(0)
+ end
+
+ # Get rid of console logging
+ Puppet::Util::Log.close(:console)
+
+ Process.setsid
+ Dir.chdir("/")
+ begin
+ $stdin.reopen "/dev/null"
+ $stdout.reopen "/dev/null", "a"
+ $stderr.reopen $stdout
+ Puppet::Util::Log.reopen
+ rescue => detail
+ Puppet::Util.secure_open("/tmp/daemonout", "w") { |f|
+ f.puts "Could not start #{Puppet[:name]}: #{detail}"
+ }
+ raise "Could not start #{Puppet[:name]}: #{detail}"
end
+ end
- # Create a pidfile for our daemon, so we can be stopped and others
- # don't try to start.
- def create_pidfile
- Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
- raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock
- end
- end
-
- # Remove the pid file for our daemon.
- def remove_pidfile
- Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
- locker = Puppet::Util::Pidlock.new(pidfile)
- locker.unlock or Puppet.err "Could not remove PID file #{pidfile}" if locker.locked?
- end
- end
+ # Create a pidfile for our daemon, so we can be stopped and others
+ # don't try to start.
+ def create_pidfile
+ Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
+ raise "Could not create PID file: #{pidfile}" unless Puppet::Util::Pidlock.new(pidfile).lock
+ end
+ end
- # Provide the path to our pidfile.
- def pidfile
- Puppet[:pidfile]
- end
+ # Remove the pid file for our daemon.
+ def remove_pidfile
+ Puppet::Util.sync(Puppet[:name]).synchronize(Sync::EX) do
+ locker = Puppet::Util::Pidlock.new(pidfile)
+ locker.unlock or Puppet.err "Could not remove PID file #{pidfile}" if locker.locked?
+ end
+ end
+
+ # Provide the path to our pidfile.
+ def pidfile
+ Puppet[:pidfile]
+ end
+
+ def initialize(args = {})
+ valid_args = [:handlers, :xmlrpc_handlers, :port]
+ bad_args = args.keys.find_all { |p| ! valid_args.include?(p) }.collect { |p| p.to_s }.join(",")
+ raise ArgumentError, "Invalid argument(s) #{bad_args}" unless bad_args == ""
+ @server_type = Puppet[:servertype] or raise "No servertype configuration found." # e.g., WEBrick, Mongrel, etc.
+ http_server_class || raise(ArgumentError, "Could not determine HTTP Server class for server type [#{@server_type}]")
- def initialize(args = {})
- valid_args = [:handlers, :xmlrpc_handlers, :port]
- bad_args = args.keys.find_all { |p| ! valid_args.include?(p) }.collect { |p| p.to_s }.join(",")
- raise ArgumentError, "Invalid argument(s) #{bad_args}" unless bad_args == ""
- @server_type = Puppet[:servertype] or raise "No servertype configuration found." # e.g., WEBrick, Mongrel, etc.
- http_server_class || raise(ArgumentError, "Could not determine HTTP Server class for server type [#{@server_type}]")
-
- @port = args[:port] || Puppet[:masterport] || raise(ArgumentError, "Must specify :port or configure Puppet :masterport")
- @address = determine_bind_address
-
- @protocols = [ :rest, :xmlrpc ]
- @listening = false
- @routes = {}
- @xmlrpc_routes = {}
- self.register(args[:handlers]) if args[:handlers]
- self.register_xmlrpc(args[:xmlrpc_handlers]) if args[:xmlrpc_handlers]
-
- # Make sure we have all of the directories we need to function.
- Puppet.settings.use(:main, :ssl, Puppet[:name])
- end
+ @port = args[:port] || Puppet[:masterport] || raise(ArgumentError, "Must specify :port or configure Puppet :masterport")
+ @address = determine_bind_address
+
+ @protocols = [ :rest, :xmlrpc ]
+ @listening = false
+ @routes = {}
+ @xmlrpc_routes = {}
+ self.register(args[:handlers]) if args[:handlers]
+ self.register_xmlrpc(args[:xmlrpc_handlers]) if args[:xmlrpc_handlers]
+
+ # Make sure we have all of the directories we need to function.
+ Puppet.settings.use(:main, :ssl, Puppet[:name])
+ end
+
+ # Register handlers for REST networking, based on the Indirector.
+ def register(*indirections)
+ raise ArgumentError, "Indirection names are required." if indirections.empty?
+ indirections.flatten.each do |name|
+ Puppet::Indirector::Indirection.model(name) || raise(ArgumentError, "Cannot locate indirection '#{name}'.")
+ @routes[name.to_sym] = true
+ end
+ end
+
+ # Unregister Indirector handlers.
+ def unregister(*indirections)
+ raise "Cannot unregister indirections while server is listening." if listening?
+ indirections = @routes.keys if indirections.empty?
+
+ indirections.flatten.each do |i|
+ raise(ArgumentError, "Indirection [#{i}] is unknown.") unless @routes[i.to_sym]
+ end
+
+ indirections.flatten.each do |i|
+ @routes.delete(i.to_sym)
+ end
+ end
+
+ # Register xmlrpc handlers for backward compatibility.
+ def register_xmlrpc(*namespaces)
+ raise ArgumentError, "XMLRPC namespaces are required." if namespaces.empty?
+ namespaces.flatten.each do |name|
+ Puppet::Network::Handler.handler(name) || raise(ArgumentError, "Cannot locate XMLRPC handler for namespace '#{name}'.")
+ @xmlrpc_routes[name.to_sym] = true
+ end
+ end
+
+ # Unregister xmlrpc handlers.
+ def unregister_xmlrpc(*namespaces)
+ raise "Cannot unregister xmlrpc handlers while server is listening." if listening?
+ namespaces = @xmlrpc_routes.keys if namespaces.empty?
+
+ namespaces.flatten.each do |i|
+ raise(ArgumentError, "XMLRPC handler '#{i}' is unknown.") unless @xmlrpc_routes[i.to_sym]
+ end
+
+ namespaces.flatten.each do |i|
+ @xmlrpc_routes.delete(i.to_sym)
+ end
+ end
+
+ def listening?
+ @listening
+ end
+
+ def listen
+ raise "Cannot listen -- already listening." if listening?
+ @listening = true
+ http_server.listen(:address => address, :port => port, :handlers => @routes.keys, :xmlrpc_handlers => @xmlrpc_routes.keys, :protocols => protocols)
+ end
- # Register handlers for REST networking, based on the Indirector.
- def register(*indirections)
- raise ArgumentError, "Indirection names are required." if indirections.empty?
- indirections.flatten.each do |name|
- Puppet::Indirector::Indirection.model(name) || raise(ArgumentError, "Cannot locate indirection '#{name}'.")
- @routes[name.to_sym] = true
- end
- end
+ def unlisten
+ raise "Cannot unlisten -- not currently listening." unless listening?
+ http_server.unlisten
+ @listening = false
+ end
- # Unregister Indirector handlers.
- def unregister(*indirections)
- raise "Cannot unregister indirections while server is listening." if listening?
- indirections = @routes.keys if indirections.empty?
+ def http_server_class
+ http_server_class_by_type(@server_type)
+ end
- indirections.flatten.each do |i|
- raise(ArgumentError, "Indirection [#{i}] is unknown.") unless @routes[i.to_sym]
- end
+ def start
+ create_pidfile
+ listen
+ end
- indirections.flatten.each do |i|
- @routes.delete(i.to_sym)
- end
- end
+ def stop
+ unlisten
+ remove_pidfile
+ end
+
+ private
- # Register xmlrpc handlers for backward compatibility.
- def register_xmlrpc(*namespaces)
- raise ArgumentError, "XMLRPC namespaces are required." if namespaces.empty?
- namespaces.flatten.each do |name|
- Puppet::Network::Handler.handler(name) || raise(ArgumentError, "Cannot locate XMLRPC handler for namespace '#{name}'.")
- @xmlrpc_routes[name.to_sym] = true
- end
- end
+ def http_server
+ @http_server ||= http_server_class.new
+ end
- # Unregister xmlrpc handlers.
- def unregister_xmlrpc(*namespaces)
- raise "Cannot unregister xmlrpc handlers while server is listening." if listening?
- namespaces = @xmlrpc_routes.keys if namespaces.empty?
-
- namespaces.flatten.each do |i|
- raise(ArgumentError, "XMLRPC handler '#{i}' is unknown.") unless @xmlrpc_routes[i.to_sym]
- end
-
- namespaces.flatten.each do |i|
- @xmlrpc_routes.delete(i.to_sym)
- end
- end
-
- def listening?
- @listening
- end
-
- def listen
- raise "Cannot listen -- already listening." if listening?
- @listening = true
- http_server.listen(:address => address, :port => port, :handlers => @routes.keys, :xmlrpc_handlers => @xmlrpc_routes.keys, :protocols => protocols)
- end
+ def http_server_class_by_type(kind)
+ Puppet::Network::HTTP.server_class_by_type(kind)
+ end
- def unlisten
- raise "Cannot unlisten -- not currently listening." unless listening?
- http_server.unlisten
- @listening = false
- end
-
- def http_server_class
- http_server_class_by_type(@server_type)
- end
-
- def start
- create_pidfile
- listen
- end
-
- def stop
- unlisten
- remove_pidfile
- end
-
- private
-
- def http_server
- @http_server ||= http_server_class.new
- end
-
- def http_server_class_by_type(kind)
- Puppet::Network::HTTP.server_class_by_type(kind)
- end
-
- def determine_bind_address
- tmp = Puppet[:bindaddress]
- return tmp if tmp != ""
- server_type.to_s == "webrick" ? "0.0.0.0" : "127.0.0.1"
- end
+ def determine_bind_address
+ tmp = Puppet[:bindaddress]
+ return tmp if tmp != ""
+ server_type.to_s == "webrick" ? "0.0.0.0" : "127.0.0.1"
+ end
end
diff --git a/lib/puppet/network/xmlrpc/client.rb b/lib/puppet/network/xmlrpc/client.rb
index 3afd1dcc7..ca6ac60ef 100644
--- a/lib/puppet/network/xmlrpc/client.rb
+++ b/lib/puppet/network/xmlrpc/client.rb
@@ -8,204 +8,204 @@ require 'net/https'
require 'yaml'
module Puppet::Network
- class ClientError < Puppet::Error; end
- class XMLRPCClientError < Puppet::Error; end
- class XMLRPCClient < ::XMLRPC::Client
-
- attr_accessor :puppet_server, :puppet_port
- @clients = {}
-
- class << self
- include Puppet::Util
- include Puppet::Util::ClassGen
- end
-
- # Create a netclient for each handler
- def self.mkclient(handler)
- interface = handler.interface
- namespace = interface.prefix
-
- # Create a subclass for every client type. This is
- # so that all of the methods are on their own class,
- # so that their namespaces can define the same methods if
- # they want.
- constant = handler.name.to_s.capitalize
- name = namespace.downcase
- newclient = genclass(name, :hash => @clients, :constant => constant)
-
- interface.methods.each { |ary|
- method = ary[0]
- newclient.send(:define_method,method) { |*args|
- make_rpc_call(namespace, method, *args)
- }
- }
-
- newclient
- end
-
- def self.handler_class(handler)
- @clients[handler] || self.mkclient(handler)
- end
-
- class ErrorHandler
- def initialize(&block)
- singleton_class.define_method(:execute, &block)
- end
- end
-
- # Use a class variable so all subclasses have access to it.
- @@error_handlers = {}
-
- def self.error_handler(exception)
- if handler = @@error_handlers[exception.class]
- return handler
- else
- return @@error_handlers[:default]
- end
- end
-
- def self.handle_error(*exceptions, &block)
- handler = ErrorHandler.new(&block)
-
- exceptions.each do |exception|
- @@error_handlers[exception] = handler
- end
- end
-
- handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
- if detail.message =~ /bad write retry/
- Puppet.warning "Transient SSL write error; restarting connection and retrying"
- client.recycle_connection
- return :retry
- end
- ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
- Puppet.warning "Certificate validation failed; consider using the certname configuration option" if detail.message.include?(str)
- end
- raise XMLRPCClientError, "Certificates were not trusted: #{detail}"
- end
-
- handle_error(:default) do |client, detail, namespace, method|
- if detail.message.to_s =~ /^Wrong size\. Was \d+, should be \d+$/
- Puppet.warning "XMLRPC returned wrong size. Retrying."
- return :retry
- end
- Puppet.err "Could not call #{namespace}.#{method}: #{detail.inspect}"
- error = XMLRPCClientError.new(detail.to_s)
- error.set_backtrace detail.backtrace
- raise error
- end
-
- handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
- if detail.message =~ /bad write retry/
- Puppet.warning "Transient SSL write error; restarting connection and retrying"
- client.recycle_connection
- return :retry
- end
- ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
- Puppet.warning "Certificate validation failed; consider using the certname configuration option" if detail.message.include?(str)
- end
- raise XMLRPCClientError, "Certificates were not trusted: #{detail}"
- end
-
- handle_error(::XMLRPC::FaultException) do |client, detail, namespace, method|
- raise XMLRPCClientError, detail.faultString
- end
-
- handle_error(Errno::ECONNREFUSED) do |client, detail, namespace, method|
- msg = "Could not connect to #{client.host} on port #{client.port}"
- raise XMLRPCClientError, msg
- end
-
- handle_error(SocketError) do |client, detail, namespace, method|
- Puppet.err "Could not find server #{@host}: #{detail}"
- error = XMLRPCClientError.new("Could not find server #{client.host}")
- error.set_backtrace detail.backtrace
- raise error
- end
-
- handle_error(Errno::EPIPE, EOFError) do |client, detail, namespace, method|
- Puppet.info "Other end went away; restarting connection and retrying"
- client.recycle_connection
- return :retry
- end
-
- handle_error(Timeout::Error) do |client, detail, namespace, method|
- Puppet.err "Connection timeout calling #{namespace}.#{method}: #{detail}"
- error = XMLRPCClientError.new("Connection Timeout")
- error.set_backtrace(detail.backtrace)
- raise error
- end
-
- def make_rpc_call(namespace, method, *args)
- Puppet.debug "Calling #{namespace}.#{method}"
- begin
- call("#{namespace}.#{method}",*args)
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- retry if self.class.error_handler(detail).execute(self, detail, namespace, method) == :retry
- end
- ensure
- http.finish if http.started?
- end
-
- def http
- @http ||= Puppet::Network::HttpPool.http_instance(host, port, true)
- end
-
- attr_reader :host, :port
-
- def initialize(hash = {})
- hash[:Path] ||= "/RPC2"
- hash[:Server] ||= Puppet[:server]
- hash[:Port] ||= Puppet[:masterport]
- hash[:HTTPProxyHost] ||= Puppet[:http_proxy_host]
- hash[:HTTPProxyPort] ||= Puppet[:http_proxy_port]
-
- if "none" == hash[:HTTPProxyHost]
- hash[:HTTPProxyHost] = nil
- hash[:HTTPProxyPort] = nil
- end
-
-
- super(
+ class ClientError < Puppet::Error; end
+ class XMLRPCClientError < Puppet::Error; end
+ class XMLRPCClient < ::XMLRPC::Client
+
+ attr_accessor :puppet_server, :puppet_port
+ @clients = {}
+
+ class << self
+ include Puppet::Util
+ include Puppet::Util::ClassGen
+ end
+
+ # Create a netclient for each handler
+ def self.mkclient(handler)
+ interface = handler.interface
+ namespace = interface.prefix
+
+ # Create a subclass for every client type. This is
+ # so that all of the methods are on their own class,
+ # so that their namespaces can define the same methods if
+ # they want.
+ constant = handler.name.to_s.capitalize
+ name = namespace.downcase
+ newclient = genclass(name, :hash => @clients, :constant => constant)
+
+ interface.methods.each { |ary|
+ method = ary[0]
+ newclient.send(:define_method,method) { |*args|
+ make_rpc_call(namespace, method, *args)
+ }
+ }
+
+ newclient
+ end
+
+ def self.handler_class(handler)
+ @clients[handler] || self.mkclient(handler)
+ end
+
+ class ErrorHandler
+ def initialize(&block)
+ singleton_class.define_method(:execute, &block)
+ end
+ end
+
+ # Use a class variable so all subclasses have access to it.
+ @@error_handlers = {}
+
+ def self.error_handler(exception)
+ if handler = @@error_handlers[exception.class]
+ return handler
+ else
+ return @@error_handlers[:default]
+ end
+ end
+
+ def self.handle_error(*exceptions, &block)
+ handler = ErrorHandler.new(&block)
+
+ exceptions.each do |exception|
+ @@error_handlers[exception] = handler
+ end
+ end
+
+ handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
+ if detail.message =~ /bad write retry/
+ Puppet.warning "Transient SSL write error; restarting connection and retrying"
+ client.recycle_connection
+ return :retry
+ end
+ ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
+ Puppet.warning "Certificate validation failed; consider using the certname configuration option" if detail.message.include?(str)
+ end
+ raise XMLRPCClientError, "Certificates were not trusted: #{detail}"
+ end
+
+ handle_error(:default) do |client, detail, namespace, method|
+ if detail.message.to_s =~ /^Wrong size\. Was \d+, should be \d+$/
+ Puppet.warning "XMLRPC returned wrong size. Retrying."
+ return :retry
+ end
+ Puppet.err "Could not call #{namespace}.#{method}: #{detail.inspect}"
+ error = XMLRPCClientError.new(detail.to_s)
+ error.set_backtrace detail.backtrace
+ raise error
+ end
+
+ handle_error(OpenSSL::SSL::SSLError) do |client, detail, namespace, method|
+ if detail.message =~ /bad write retry/
+ Puppet.warning "Transient SSL write error; restarting connection and retrying"
+ client.recycle_connection
+ return :retry
+ end
+ ["certificate verify failed", "hostname was not match", "hostname not match"].each do |str|
+ Puppet.warning "Certificate validation failed; consider using the certname configuration option" if detail.message.include?(str)
+ end
+ raise XMLRPCClientError, "Certificates were not trusted: #{detail}"
+ end
+
+ handle_error(::XMLRPC::FaultException) do |client, detail, namespace, method|
+ raise XMLRPCClientError, detail.faultString
+ end
+
+ handle_error(Errno::ECONNREFUSED) do |client, detail, namespace, method|
+ msg = "Could not connect to #{client.host} on port #{client.port}"
+ raise XMLRPCClientError, msg
+ end
+
+ handle_error(SocketError) do |client, detail, namespace, method|
+ Puppet.err "Could not find server #{@host}: #{detail}"
+ error = XMLRPCClientError.new("Could not find server #{client.host}")
+ error.set_backtrace detail.backtrace
+ raise error
+ end
+
+ handle_error(Errno::EPIPE, EOFError) do |client, detail, namespace, method|
+ Puppet.info "Other end went away; restarting connection and retrying"
+ client.recycle_connection
+ return :retry
+ end
+
+ handle_error(Timeout::Error) do |client, detail, namespace, method|
+ Puppet.err "Connection timeout calling #{namespace}.#{method}: #{detail}"
+ error = XMLRPCClientError.new("Connection Timeout")
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
+
+ def make_rpc_call(namespace, method, *args)
+ Puppet.debug "Calling #{namespace}.#{method}"
+ begin
+ call("#{namespace}.#{method}",*args)
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ retry if self.class.error_handler(detail).execute(self, detail, namespace, method) == :retry
+ end
+ ensure
+ http.finish if http.started?
+ end
+
+ def http
+ @http ||= Puppet::Network::HttpPool.http_instance(host, port, true)
+ end
+
+ attr_reader :host, :port
+
+ def initialize(hash = {})
+ hash[:Path] ||= "/RPC2"
+ hash[:Server] ||= Puppet[:server]
+ hash[:Port] ||= Puppet[:masterport]
+ hash[:HTTPProxyHost] ||= Puppet[:http_proxy_host]
+ hash[:HTTPProxyPort] ||= Puppet[:http_proxy_port]
+
+ if "none" == hash[:HTTPProxyHost]
+ hash[:HTTPProxyHost] = nil
+ hash[:HTTPProxyPort] = nil
+ end
+
+
+ super(
- hash[:Server],
- hash[:Path],
- hash[:Port],
- hash[:HTTPProxyHost],
- hash[:HTTPProxyPort],
+ hash[:Server],
+ hash[:Path],
+ hash[:Port],
+ hash[:HTTPProxyHost],
+ hash[:HTTPProxyPort],
- nil, # user
- nil, # password
- true, # use_ssl
- Puppet[:configtimeout] # use configured timeout (#1176)
- )
- @http = Puppet::Network::HttpPool.http_instance(@host, @port)
- end
-
- # Get rid of our existing connection, replacing it with a new one.
- # This should only happen if we lose our connection somehow (e.g., an EPIPE)
- # or we've just downloaded certs and we need to create new http instances
- # with the certs added.
- def recycle_connection
- http.finish if http.started?
- @http = nil
- self.http # force a new one
- end
-
- def start
- @http.start unless @http.started?
- rescue => detail
- Puppet.err "Could not connect to server: #{detail}"
- end
-
- def local
- false
- end
-
- def local?
- false
- end
+ nil, # user
+ nil, # password
+ true, # use_ssl
+ Puppet[:configtimeout] # use configured timeout (#1176)
+ )
+ @http = Puppet::Network::HttpPool.http_instance(@host, @port)
+ end
+
+ # Get rid of our existing connection, replacing it with a new one.
+ # This should only happen if we lose our connection somehow (e.g., an EPIPE)
+ # or we've just downloaded certs and we need to create new http instances
+ # with the certs added.
+ def recycle_connection
+ http.finish if http.started?
+ @http = nil
+ self.http # force a new one
+ end
+
+ def start
+ @http.start unless @http.started?
+ rescue => detail
+ Puppet.err "Could not connect to server: #{detail}"
+ end
+
+ def local
+ false
+ end
+
+ def local?
+ false
end
+ end
end
diff --git a/lib/puppet/network/xmlrpc/processor.rb b/lib/puppet/network/xmlrpc/processor.rb
index 9d3904fce..dea8a02fa 100644
--- a/lib/puppet/network/xmlrpc/processor.rb
+++ b/lib/puppet/network/xmlrpc/processor.rb
@@ -3,84 +3,84 @@ require 'xmlrpc/server'
# Just silly.
class ::XMLRPC::FaultException
- def to_s
- self.message
- end
+ def to_s
+ self.message
+ end
end
module Puppet::Network
- # Most of our subclassing is just so that we can get
- # access to information from the request object, like
- # the client name and IP address.
- module XMLRPCProcessor
- include Puppet::Network::Authorization
+ # Most of our subclassing is just so that we can get
+ # access to information from the request object, like
+ # the client name and IP address.
+ module XMLRPCProcessor
+ include Puppet::Network::Authorization
- ERR_UNAUTHORIZED = 30
+ ERR_UNAUTHORIZED = 30
- def add_handler(interface, handler)
- @loadedhandlers << interface.prefix
- super(interface, handler)
- end
+ def add_handler(interface, handler)
+ @loadedhandlers << interface.prefix
+ super(interface, handler)
+ end
- def handler_loaded?(handler)
- @loadedhandlers.include?(handler.to_s)
- end
+ def handler_loaded?(handler)
+ @loadedhandlers.include?(handler.to_s)
+ end
- # Convert our data and client request into xmlrpc calls, and verify
- # they're authorized and such-like. This method differs from the
- # default in that it expects a ClientRequest object in addition to the
- # data.
- def process(data, request)
- call, params = parser.parseMethodCall(data)
- params << request.name << request.ip
- handler, method = call.split(".")
- request.handler = handler
- request.method = method
- begin
- verify(request)
- rescue InvalidClientRequest => detail
- raise ::XMLRPC::FaultException.new(ERR_UNAUTHORIZED, detail.to_s)
- end
- handle(request.call, *params)
- end
+ # Convert our data and client request into xmlrpc calls, and verify
+ # they're authorized and such-like. This method differs from the
+ # default in that it expects a ClientRequest object in addition to the
+ # data.
+ def process(data, request)
+ call, params = parser.parseMethodCall(data)
+ params << request.name << request.ip
+ handler, method = call.split(".")
+ request.handler = handler
+ request.method = method
+ begin
+ verify(request)
+ rescue InvalidClientRequest => detail
+ raise ::XMLRPC::FaultException.new(ERR_UNAUTHORIZED, detail.to_s)
+ end
+ handle(request.call, *params)
+ end
- private
+ private
- # Provide error handling for method calls.
- def protect_service(obj, *args)
- begin
- obj.call(*args)
- rescue ::XMLRPC::FaultException
- raise
- rescue Puppet::AuthorizationError => detail
- Puppet.err "Permission denied: #{detail}"
- raise ::XMLRPC::FaultException.new(
- 1, detail.to_s
- )
- rescue Puppet::Error => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err detail.to_s
- error = ::XMLRPC::FaultException.new(
- 1, detail.to_s
- )
- error.set_backtrace detail.backtrace
- raise error
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not call: #{detail}"
- error = ::XMLRPC::FaultException.new(1, detail.to_s)
- error.set_backtrace detail.backtrace
- raise error
- end
- end
+ # Provide error handling for method calls.
+ def protect_service(obj, *args)
+ begin
+ obj.call(*args)
+ rescue ::XMLRPC::FaultException
+ raise
+ rescue Puppet::AuthorizationError => detail
+ Puppet.err "Permission denied: #{detail}"
+ raise ::XMLRPC::FaultException.new(
+ 1, detail.to_s
+ )
+ rescue Puppet::Error => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err detail.to_s
+ error = ::XMLRPC::FaultException.new(
+ 1, detail.to_s
+ )
+ error.set_backtrace detail.backtrace
+ raise error
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not call: #{detail}"
+ error = ::XMLRPC::FaultException.new(1, detail.to_s)
+ error.set_backtrace detail.backtrace
+ raise error
+ end
+ end
- # Set up our service hook and init our handler list.
- def setup_processor
- @loadedhandlers = []
- self.set_service_hook do |obj, *args|
- protect_service(obj, *args)
- end
- end
+ # Set up our service hook and init our handler list.
+ def setup_processor
+ @loadedhandlers = []
+ self.set_service_hook do |obj, *args|
+ protect_service(obj, *args)
+ end
end
+ end
end
diff --git a/lib/puppet/network/xmlrpc/server.rb b/lib/puppet/network/xmlrpc/server.rb
index 8fdf02b2c..e54881756 100644
--- a/lib/puppet/network/xmlrpc/server.rb
+++ b/lib/puppet/network/xmlrpc/server.rb
@@ -3,17 +3,17 @@ require 'puppet/network/authorization'
require 'puppet/network/xmlrpc/processor'
module Puppet::Network
- # Most of our subclassing is just so that we can get
- # access to information from the request object, like
- # the client name and IP address.
- class XMLRPCServer < ::XMLRPC::BasicServer
- include Puppet::Util
- include Puppet::Network::XMLRPCProcessor
+ # Most of our subclassing is just so that we can get
+ # access to information from the request object, like
+ # the client name and IP address.
+ class XMLRPCServer < ::XMLRPC::BasicServer
+ include Puppet::Util
+ include Puppet::Network::XMLRPCProcessor
- def initialize
- super()
- setup_processor
- end
+ def initialize
+ super()
+ setup_processor
end
+ end
end
diff --git a/lib/puppet/network/xmlrpc/webrick_servlet.rb b/lib/puppet/network/xmlrpc/webrick_servlet.rb
index 035448a86..c538cf74c 100644
--- a/lib/puppet/network/xmlrpc/webrick_servlet.rb
+++ b/lib/puppet/network/xmlrpc/webrick_servlet.rb
@@ -3,112 +3,112 @@ require 'puppet/network/authorization'
require 'puppet/network/xmlrpc/processor'
module Puppet::Network::XMLRPC
- class ServletError < RuntimeError; end
- class WEBrickServlet < ::XMLRPC::WEBrickServlet
- include Puppet::Network::XMLRPCProcessor
-
- # This is a hackish way to avoid an auth message every time we have a
- # normal operation
- def self.log(msg)
- @logs ||= {}
- if @logs.include?(msg)
- @logs[msg] += 1
- else
- Puppet.info msg
- @logs[msg] = 1
- end
- end
+ class ServletError < RuntimeError; end
+ class WEBrickServlet < ::XMLRPC::WEBrickServlet
+ include Puppet::Network::XMLRPCProcessor
+
+ # This is a hackish way to avoid an auth message every time we have a
+ # normal operation
+ def self.log(msg)
+ @logs ||= {}
+ if @logs.include?(msg)
+ @logs[msg] += 1
+ else
+ Puppet.info msg
+ @logs[msg] = 1
+ end
+ end
- # Accept a list of handlers and register them all.
- def initialize(handlers)
- # the servlet base class does not consume any arguments
- # and its BasicServer base class only accepts a 'class_delim'
- # option which won't change in Puppet at all
- # thus, we don't need to pass any args to our base class,
- # and we can consume them all ourselves
- super()
-
- setup_processor
-
- # Set up each of the passed handlers.
- handlers.each do |handler|
- add_handler(handler.class.interface, handler)
- end
- end
+ # Accept a list of handlers and register them all.
+ def initialize(handlers)
+ # the servlet base class does not consume any arguments
+ # and its BasicServer base class only accepts a 'class_delim'
+ # option which won't change in Puppet at all
+ # thus, we don't need to pass any args to our base class,
+ # and we can consume them all ourselves
+ super()
+
+ setup_processor
+
+ # Set up each of the passed handlers.
+ handlers.each do |handler|
+ add_handler(handler.class.interface, handler)
+ end
+ end
- # Handle the actual request. We can't use the super() method, because
- # we need to pass a ClientRequest object to process so we can do
- # authorization. It's the only way to stay thread-safe.
- def service(request, response)
- if @valid_ip
- raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip }
- end
+ # Handle the actual request. We can't use the super() method, because
+ # we need to pass a ClientRequest object to process so we can do
+ # authorization. It's the only way to stay thread-safe.
+ def service(request, response)
+ if @valid_ip
+ raise WEBrick::HTTPStatus::Forbidden unless @valid_ip.any? { |ip| request.peeraddr[3] =~ ip }
+ end
- if request.request_method != "POST"
- raise WEBrick::HTTPStatus::MethodNotAllowed,
- "unsupported method `#{request.request_method}'."
- end
+ if request.request_method != "POST"
+ raise WEBrick::HTTPStatus::MethodNotAllowed,
+ "unsupported method `#{request.request_method}'."
+ end
- raise WEBrick::HTTPStatus::BadRequest if parse_content_type(request['Content-type']).first != "text/xml"
+ raise WEBrick::HTTPStatus::BadRequest if parse_content_type(request['Content-type']).first != "text/xml"
- length = (request['Content-length'] || 0).to_i
+ length = (request['Content-length'] || 0).to_i
- raise WEBrick::HTTPStatus::LengthRequired unless length > 0
+ raise WEBrick::HTTPStatus::LengthRequired unless length > 0
- data = request.body
+ data = request.body
- raise WEBrick::HTTPStatus::BadRequest if data.nil? or data.size != length
+ raise WEBrick::HTTPStatus::BadRequest if data.nil? or data.size != length
- resp = process(data, client_request(request))
- raise WEBrick::HTTPStatus::InternalServerError if resp.nil? or resp.size <= 0
+ resp = process(data, client_request(request))
+ raise WEBrick::HTTPStatus::InternalServerError if resp.nil? or resp.size <= 0
- response.status = 200
- response['Content-Length'] = resp.size
- response['Content-Type'] = "text/xml; charset=utf-8"
- response.body = resp
- end
+ response.status = 200
+ response['Content-Length'] = resp.size
+ response['Content-Type'] = "text/xml; charset=utf-8"
+ response.body = resp
+ end
- private
+ private
- # Generate a ClientRequest object for later validation.
- def client_request(request)
- if peer = request.peeraddr
- client = peer[2]
- clientip = peer[3]
- else
+ # Generate a ClientRequest object for later validation.
+ def client_request(request)
+ if peer = request.peeraddr
+ client = peer[2]
+ clientip = peer[3]
+ else
- raise ::XMLRPC::FaultException.new(
+ raise ::XMLRPC::FaultException.new(
- ERR_UNCAUGHT_EXCEPTION,
+ ERR_UNCAUGHT_EXCEPTION,
- "Could not retrieve client information"
- )
- end
-
- # If they have a certificate (which will almost always be true)
- # then we get the hostname from the cert, instead of via IP
- # info
- valid = false
- if cert = request.client_cert
- nameary = cert.subject.to_a.find { |ary|
- ary[0] == "CN"
- }
-
- if nameary.nil?
- Puppet.warning "Could not retrieve server name from cert"
- else
- unless client == nameary[1]
- Puppet.debug "Overriding #{client} with cert name #{nameary[1]}"
- client = nameary[1]
- end
- valid = true
- end
- end
-
- info = Puppet::Network::ClientRequest.new(client, clientip, valid)
-
- info
+ "Could not retrieve client information"
+ )
+ end
+
+ # If they have a certificate (which will almost always be true)
+ # then we get the hostname from the cert, instead of via IP
+ # info
+ valid = false
+ if cert = request.client_cert
+ nameary = cert.subject.to_a.find { |ary|
+ ary[0] == "CN"
+ }
+
+ if nameary.nil?
+ Puppet.warning "Could not retrieve server name from cert"
+ else
+ unless client == nameary[1]
+ Puppet.debug "Overriding #{client} with cert name #{nameary[1]}"
+ client = nameary[1]
+ end
+ valid = true
end
+ end
+
+ info = Puppet::Network::ClientRequest.new(client, clientip, valid)
+
+ info
end
+ end
end
diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb
index 81d88d088..1fc615410 100644
--- a/lib/puppet/node.rb
+++ b/lib/puppet/node.rb
@@ -2,118 +2,118 @@ require 'puppet/indirector'
# A class for managing nodes, including their facts and environment.
class Puppet::Node
- require 'puppet/node/facts'
- require 'puppet/node/environment'
+ require 'puppet/node/facts'
+ require 'puppet/node/environment'
- # Set up indirection, so that nodes can be looked for in
- # the node sources.
- extend Puppet::Indirector
+ # Set up indirection, so that nodes can be looked for in
+ # the node sources.
+ extend Puppet::Indirector
- # Adds the environment getter and setter, with some instance/string conversion
- include Puppet::Node::Environment::Helper
+ # Adds the environment getter and setter, with some instance/string conversion
+ include Puppet::Node::Environment::Helper
- # Use the node source as the indirection terminus.
- indirects :node, :terminus_setting => :node_terminus, :doc => "Where to find node information.
- A node is composed of its name, its facts, and its environment."
+ # Use the node source as the indirection terminus.
+ indirects :node, :terminus_setting => :node_terminus, :doc => "Where to find node information.
+ A node is composed of its name, its facts, and its environment."
- attr_accessor :name, :classes, :source, :ipaddress
- attr_reader :time, :parameters
+ attr_accessor :name, :classes, :source, :ipaddress
+ attr_reader :time, :parameters
- def environment
- return super if @environment
+ def environment
+ return super if @environment
- if env = parameters["environment"]
- self.environment = env
- return super
- end
+ if env = parameters["environment"]
+ self.environment = env
+ return super
+ end
- # Else, return the default
- Puppet::Node::Environment.new
+ # Else, return the default
+ Puppet::Node::Environment.new
+ end
+
+ def initialize(name, options = {})
+ raise ArgumentError, "Node names cannot be nil" unless name
+ @name = name
+
+ if classes = options[:classes]
+ if classes.is_a?(String)
+ @classes = [classes]
+ else
+ @classes = classes
+ end
+ else
+ @classes = []
end
- def initialize(name, options = {})
- raise ArgumentError, "Node names cannot be nil" unless name
- @name = name
+ @parameters = options[:parameters] || {}
- if classes = options[:classes]
- if classes.is_a?(String)
- @classes = [classes]
- else
- @classes = classes
- end
- else
- @classes = []
- end
+ if env = options[:environment]
+ self.environment = env
+ end
- @parameters = options[:parameters] || {}
+ @time = Time.now
+ end
+
+ # Merge the node facts with parameters from the node source.
+ def fact_merge
+ if facts = Puppet::Node::Facts.find(name)
+ merge(facts.values)
+ end
+ rescue => detail
+ error = Puppet::Error.new("Could not retrieve facts for #{name}: #{detail}")
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
+
+ # Merge any random parameters into our parameter list.
+ def merge(params)
+ params.each do |name, value|
+ @parameters[name] = value unless @parameters.include?(name)
+ end
- if env = options[:environment]
- self.environment = env
- end
+ @parameters["environment"] ||= self.environment.name.to_s if self.environment
+ end
- @time = Time.now
- end
+ # Calculate the list of names we might use for looking
+ # up our node. This is only used for AST nodes.
+ def names
+ return [name] if Puppet.settings[:strict_hostname_checking]
- # Merge the node facts with parameters from the node source.
- def fact_merge
- if facts = Puppet::Node::Facts.find(name)
- merge(facts.values)
- end
- rescue => detail
- error = Puppet::Error.new("Could not retrieve facts for #{name}: #{detail}")
- error.set_backtrace(detail.backtrace)
- raise error
- end
+ names = []
- # Merge any random parameters into our parameter list.
- def merge(params)
- params.each do |name, value|
- @parameters[name] = value unless @parameters.include?(name)
- end
+ names += split_name(name) if name.include?(".")
- @parameters["environment"] ||= self.environment.name.to_s if self.environment
+ # First, get the fqdn
+ unless fqdn = parameters["fqdn"]
+ if parameters["hostname"] and parameters["domain"]
+ fqdn = parameters["hostname"] + "." + parameters["domain"]
+ else
+ Puppet.warning "Host is missing hostname and/or domain: #{name}"
+ end
end
- # Calculate the list of names we might use for looking
- # up our node. This is only used for AST nodes.
- def names
- return [name] if Puppet.settings[:strict_hostname_checking]
-
- names = []
-
- names += split_name(name) if name.include?(".")
-
- # First, get the fqdn
- unless fqdn = parameters["fqdn"]
- if parameters["hostname"] and parameters["domain"]
- fqdn = parameters["hostname"] + "." + parameters["domain"]
- else
- Puppet.warning "Host is missing hostname and/or domain: #{name}"
- end
- end
-
- # Now that we (might) have the fqdn, add each piece to the name
- # list to search, in order of longest to shortest.
- names += split_name(fqdn) if fqdn
-
- # And make sure the node name is first, since that's the most
- # likely usage.
- # The name is usually the Certificate CN, but it can be
- # set to the 'facter' hostname instead.
- if Puppet[:node_name] == 'cert'
- names.unshift name
- else
- names.unshift parameters["hostname"]
- end
- names.uniq
+ # Now that we (might) have the fqdn, add each piece to the name
+ # list to search, in order of longest to shortest.
+ names += split_name(fqdn) if fqdn
+
+ # And make sure the node name is first, since that's the most
+ # likely usage.
+ # The name is usually the Certificate CN, but it can be
+ # set to the 'facter' hostname instead.
+ if Puppet[:node_name] == 'cert'
+ names.unshift name
+ else
+ names.unshift parameters["hostname"]
end
-
- def split_name(name)
- list = name.split(".")
- tmp = []
- list.each_with_index do |short, i|
- tmp << list[0..i].join(".")
- end
- tmp.reverse
+ names.uniq
+ end
+
+ def split_name(name)
+ list = name.split(".")
+ tmp = []
+ list.each_with_index do |short, i|
+ tmp << list[0..i].join(".")
end
+ tmp.reverse
+ end
end
diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb
index 4f3ef2dad..44c764025 100644
--- a/lib/puppet/node/environment.rb
+++ b/lib/puppet/node/environment.rb
@@ -7,124 +7,124 @@ end
# Model the environment that a node can operate in. This class just
# provides a simple wrapper for the functionality around environments.
class Puppet::Node::Environment
- module Helper
- def environment
- Puppet::Node::Environment.new(@environment)
- end
-
- def environment=(env)
- if env.is_a?(String) or env.is_a?(Symbol)
- @environment = env
- else
- @environment = env.name
- end
- end
+ module Helper
+ def environment
+ Puppet::Node::Environment.new(@environment)
end
- include Puppet::Util::Cacher
-
- @seen = {}
+ def environment=(env)
+ if env.is_a?(String) or env.is_a?(Symbol)
+ @environment = env
+ else
+ @environment = env.name
+ end
+ end
+ end
- # Return an existing environment instance, or create a new one.
- def self.new(name = nil)
- return name if name.is_a?(self)
- name ||= Puppet.settings.value(:environment)
+ include Puppet::Util::Cacher
- raise ArgumentError, "Environment name must be specified" unless name
+ @seen = {}
- symbol = name.to_sym
+ # Return an existing environment instance, or create a new one.
+ def self.new(name = nil)
+ return name if name.is_a?(self)
+ name ||= Puppet.settings.value(:environment)
- return @seen[symbol] if @seen[symbol]
+ raise ArgumentError, "Environment name must be specified" unless name
- obj = self.allocate
- obj.send :initialize, symbol
- @seen[symbol] = obj
- end
-
- def self.current
- Thread.current[:environment] || root
- end
-
- def self.current=(env)
- Thread.current[:environment] = new(env)
- end
-
- def self.root
- @root
- end
+ symbol = name.to_sym
- # This is only used for testing.
- def self.clear
- @seen.clear
- end
+ return @seen[symbol] if @seen[symbol]
- attr_reader :name
+ obj = self.allocate
+ obj.send :initialize, symbol
+ @seen[symbol] = obj
+ end
- # Return an environment-specific setting.
- def [](param)
- Puppet.settings.value(param, self.name)
- end
+ def self.current
+ Thread.current[:environment] || root
+ end
- def initialize(name)
- @name = name
- end
+ def self.current=(env)
+ Thread.current[:environment] = new(env)
+ end
- def known_resource_types
- if @known_resource_types.nil? or @known_resource_types.stale?
- @known_resource_types = Puppet::Resource::TypeCollection.new(self)
- @known_resource_types.perform_initial_import
- end
- @known_resource_types
- end
+ def self.root
+ @root
+ end
- def module(name)
- mod = Puppet::Module.new(name, self)
- return nil unless mod.exist?
- mod
- end
+ # This is only used for testing.
+ def self.clear
+ @seen.clear
+ end
- # Cache the modulepath, so that we aren't searching through
- # all known directories all the time.
- cached_attr(:modulepath, :ttl => Puppet[:filetimeout]) do
- dirs = self[:modulepath].split(File::PATH_SEPARATOR)
- dirs = ENV["PUPPETLIB"].split(File::PATH_SEPARATOR) + dirs if ENV["PUPPETLIB"]
- validate_dirs(dirs)
- end
+ attr_reader :name
- # Return all modules from this environment.
- # Cache the list, because it can be expensive to create.
- cached_attr(:modules, :ttl => Puppet[:filetimeout]) do
- module_names = modulepath.collect { |path| Dir.entries(path) }.flatten.uniq
- module_names.collect do |path|
- begin
- Puppet::Module.new(path, self)
- rescue Puppet::Module::Error => e
- nil
- end
- end.compact
- end
+ # Return an environment-specific setting.
+ def [](param)
+ Puppet.settings.value(param, self.name)
+ end
- # Cache the manifestdir, so that we aren't searching through
- # all known directories all the time.
- cached_attr(:manifestdir, :ttl => Puppet[:filetimeout]) do
- validate_dirs(self[:manifestdir].split(File::PATH_SEPARATOR))
- end
+ def initialize(name)
+ @name = name
+ end
- def to_s
- name.to_s
+ def known_resource_types
+ if @known_resource_types.nil? or @known_resource_types.stale?
+ @known_resource_types = Puppet::Resource::TypeCollection.new(self)
+ @known_resource_types.perform_initial_import
end
-
- def validate_dirs(dirs)
- dirs.collect do |dir|
- if dir !~ /^#{File::SEPARATOR}/
- File.join(Dir.getwd, dir)
- else
- dir
- end
- end.find_all do |p|
- p =~ /^#{File::SEPARATOR}/ && FileTest.directory?(p)
- end
+ @known_resource_types
+ end
+
+ def module(name)
+ mod = Puppet::Module.new(name, self)
+ return nil unless mod.exist?
+ mod
+ end
+
+ # Cache the modulepath, so that we aren't searching through
+ # all known directories all the time.
+ cached_attr(:modulepath, :ttl => Puppet[:filetimeout]) do
+ dirs = self[:modulepath].split(File::PATH_SEPARATOR)
+ dirs = ENV["PUPPETLIB"].split(File::PATH_SEPARATOR) + dirs if ENV["PUPPETLIB"]
+ validate_dirs(dirs)
+ end
+
+ # Return all modules from this environment.
+ # Cache the list, because it can be expensive to create.
+ cached_attr(:modules, :ttl => Puppet[:filetimeout]) do
+ module_names = modulepath.collect { |path| Dir.entries(path) }.flatten.uniq
+ module_names.collect do |path|
+ begin
+ Puppet::Module.new(path, self)
+ rescue Puppet::Module::Error => e
+ nil
+ end
+ end.compact
+ end
+
+ # Cache the manifestdir, so that we aren't searching through
+ # all known directories all the time.
+ cached_attr(:manifestdir, :ttl => Puppet[:filetimeout]) do
+ validate_dirs(self[:manifestdir].split(File::PATH_SEPARATOR))
+ end
+
+ def to_s
+ name.to_s
+ end
+
+ def validate_dirs(dirs)
+ dirs.collect do |dir|
+ if dir !~ /^#{File::SEPARATOR}/
+ File.join(Dir.getwd, dir)
+ else
+ dir
+ end
+ end.find_all do |p|
+ p =~ /^#{File::SEPARATOR}/ && FileTest.directory?(p)
end
+ end
- @root = new(:'*root*')
+ @root = new(:'*root*')
end
diff --git a/lib/puppet/node/facts.rb b/lib/puppet/node/facts.rb
index 0b9fc5879..b77ad22d5 100755
--- a/lib/puppet/node/facts.rb
+++ b/lib/puppet/node/facts.rb
@@ -4,67 +4,67 @@ require 'puppet/indirector'
# Manage a given node's facts. This either accepts facts and stores them, or
# returns facts for a given node.
class Puppet::Node::Facts
- # Set up indirection, so that nodes can be looked for in
- # the node sources.
- extend Puppet::Indirector
+ # Set up indirection, so that nodes can be looked for in
+ # the node sources.
+ extend Puppet::Indirector
- # We want to expire any cached nodes if the facts are saved.
- module NodeExpirer
- def save(key, instance)
- Puppet::Node.expire(instance.name)
- super
- end
+ # We want to expire any cached nodes if the facts are saved.
+ module NodeExpirer
+ def save(key, instance)
+ Puppet::Node.expire(instance.name)
+ super
end
+ end
- indirects :facts, :terminus_setting => :facts_terminus, :extend => NodeExpirer
+ indirects :facts, :terminus_setting => :facts_terminus, :extend => NodeExpirer
- attr_accessor :name, :values
+ attr_accessor :name, :values
- def add_local_facts
- values["clientcert"] = Puppet.settings[:certname]
- values["clientversion"] = Puppet.version.to_s
- values["environment"] ||= Puppet.settings[:environment]
- end
+ def add_local_facts
+ values["clientcert"] = Puppet.settings[:certname]
+ values["clientversion"] = Puppet.version.to_s
+ values["environment"] ||= Puppet.settings[:environment]
+ end
- def initialize(name, values = {})
- @name = name
- @values = values
+ def initialize(name, values = {})
+ @name = name
+ @values = values
- add_internal
- end
+ add_internal
+ end
- def downcase_if_necessary
- return unless Puppet.settings[:downcasefacts]
+ def downcase_if_necessary
+ return unless Puppet.settings[:downcasefacts]
- Puppet.warning "DEPRECATION NOTICE: Fact downcasing is deprecated; please disable (20080122)"
- values.each do |fact, value|
- values[fact] = value.downcase if value.is_a?(String)
- end
+ Puppet.warning "DEPRECATION NOTICE: Fact downcasing is deprecated; please disable (20080122)"
+ values.each do |fact, value|
+ values[fact] = value.downcase if value.is_a?(String)
end
+ end
- # Convert all fact values into strings.
- def stringify
- values.each do |fact, value|
- values[fact] = value.to_s
- end
+ # Convert all fact values into strings.
+ def stringify
+ values.each do |fact, value|
+ values[fact] = value.to_s
end
+ end
- def ==(other)
- return false unless self.name == other.name
- strip_internal == other.send(:strip_internal)
- end
+ def ==(other)
+ return false unless self.name == other.name
+ strip_internal == other.send(:strip_internal)
+ end
- private
+ private
- # Add internal data to the facts for storage.
- def add_internal
- self.values[:_timestamp] = Time.now
- end
+ # Add internal data to the facts for storage.
+ def add_internal
+ self.values[:_timestamp] = Time.now
+ end
- # Strip out that internal data.
- def strip_internal
- newvals = values.dup
- newvals.find_all { |name, value| name.to_s =~ /^_/ }.each { |name, value| newvals.delete(name) }
- newvals
- end
+ # Strip out that internal data.
+ def strip_internal
+ newvals = values.dup
+ newvals.find_all { |name, value| name.to_s =~ /^_/ }.each { |name, value| newvals.delete(name) }
+ newvals
+ end
end
diff --git a/lib/puppet/parameter.rb b/lib/puppet/parameter.rb
index be44b3e5b..ff7cab22b 100644
--- a/lib/puppet/parameter.rb
+++ b/lib/puppet/parameter.rb
@@ -5,298 +5,298 @@ require 'puppet/util/docs'
require 'puppet/util/cacher'
class Puppet::Parameter
- include Puppet::Util
- include Puppet::Util::Errors
- include Puppet::Util::LogPaths
- include Puppet::Util::Logging
- include Puppet::Util::MethodHelper
- include Puppet::Util::Cacher
-
- require 'puppet/parameter/value_collection'
-
- class << self
- include Puppet::Util
- include Puppet::Util::Docs
- attr_reader :validater, :munger, :name, :default, :required_features, :value_collection
- attr_accessor :metaparam
-
- # Define the default value for a given parameter or parameter. This
- # means that 'nil' is an invalid default value. This defines
- # the 'default' instance method.
- def defaultto(value = nil, &block)
- if block
- define_method(:default, &block)
- else
- if value.nil?
- raise Puppet::DevError,
- "Either a default value or block must be provided"
- end
- define_method(:default) do value end
- end
- end
-
- # Return a documentation string. If there are valid values,
- # then tack them onto the string.
- def doc
- @doc ||= ""
-
- unless defined?(@addeddocvals)
- @doc += value_collection.doc
+ include Puppet::Util
+ include Puppet::Util::Errors
+ include Puppet::Util::LogPaths
+ include Puppet::Util::Logging
+ include Puppet::Util::MethodHelper
+ include Puppet::Util::Cacher
- if f = self.required_features
- @doc += " Requires features #{f.flatten.collect { |f| f.to_s }.join(" ")}."
- end
- @addeddocvals = true
- end
+ require 'puppet/parameter/value_collection'
- @doc
- end
-
- def nodefault
- undef_method :default if public_method_defined? :default
- end
-
- # Store documentation for this parameter.
- def desc(str)
- @doc = str
- end
-
- def initvars
- @value_collection = ValueCollection.new
- end
-
- # This is how we munge the value. Basically, this is our
- # opportunity to convert the value from one form into another.
- def munge(&block)
- # I need to wrap the unsafe version in begin/rescue parameterments,
- # but if I directly call the block then it gets bound to the
- # class's context, not the instance's, thus the two methods,
- # instead of just one.
- define_method(:unsafe_munge, &block)
- end
-
- # Does the parameter supports reverse munge?
- # This will be called when something wants to access the parameter
- # in a canonical form different to what the storage form is.
- def unmunge(&block)
- define_method(:unmunge, &block)
- end
-
- # Mark whether we're the namevar.
- def isnamevar
- @isnamevar = true
- @required = true
- end
-
- # Is this parameter the namevar? Defaults to false.
- def isnamevar?
- @isnamevar
- end
-
- # This parameter is required.
- def isrequired
- @required = true
- end
-
- # Specify features that are required for this parameter to work.
- def required_features=(*args)
- @required_features = args.flatten.collect { |a| a.to_s.downcase.intern }
+ class << self
+ include Puppet::Util
+ include Puppet::Util::Docs
+ attr_reader :validater, :munger, :name, :default, :required_features, :value_collection
+ attr_accessor :metaparam
+
+ # Define the default value for a given parameter or parameter. This
+ # means that 'nil' is an invalid default value. This defines
+ # the 'default' instance method.
+ def defaultto(value = nil, &block)
+ if block
+ define_method(:default, &block)
+ else
+ if value.nil?
+ raise Puppet::DevError,
+ "Either a default value or block must be provided"
end
+ define_method(:default) do value end
+ end
+ end
- # Is this parameter required? Defaults to false.
- def required?
- @required
- end
+ # Return a documentation string. If there are valid values,
+ # then tack them onto the string.
+ def doc
+ @doc ||= ""
- # Verify that we got a good value
- def validate(&block)
- define_method(:unsafe_validate, &block)
- end
+ unless defined?(@addeddocvals)
+ @doc += value_collection.doc
- # Define a new value for our parameter.
- def newvalues(*names)
- @value_collection.newvalues(*names)
+ if f = self.required_features
+ @doc += " Requires features #{f.flatten.collect { |f| f.to_s }.join(" ")}."
end
+ @addeddocvals = true
+ end
- def aliasvalue(name, other)
- @value_collection.aliasvalue(name, other)
- end
+ @doc
end
- # Just a simple method to proxy instance methods to class methods
- def self.proxymethods(*values)
- values.each { |val|
- define_method(val) do
- self.class.send(val)
- end
- }
+ def nodefault
+ undef_method :default if public_method_defined? :default
end
- # And then define one of these proxies for each method in our
- # ParamHandler class.
- proxymethods("required?", "isnamevar?")
-
- attr_accessor :resource
- # LAK 2007-05-09: Keep the @parent around for backward compatibility.
- attr_accessor :parent
-
- [:line, :file, :version].each do |param|
- define_method(param) do
- resource.send(param)
- end
+ # Store documentation for this parameter.
+ def desc(str)
+ @doc = str
end
- def devfail(msg)
- self.fail(Puppet::DevError, msg)
+ def initvars
+ @value_collection = ValueCollection.new
end
- def expirer
- resource.catalog
+ # This is how we munge the value. Basically, this is our
+ # opportunity to convert the value from one form into another.
+ def munge(&block)
+ # I need to wrap the unsafe version in begin/rescue parameterments,
+ # but if I directly call the block then it gets bound to the
+ # class's context, not the instance's, thus the two methods,
+ # instead of just one.
+ define_method(:unsafe_munge, &block)
end
- def fail(*args)
- type = nil
- if args[0].is_a?(Class)
- type = args.shift
- else
- type = Puppet::Error
- end
-
- error = type.new(args.join(" "))
-
- error.line = @resource.line if @resource and @resource.line
-
- error.file = @resource.file if @resource and @resource.file
-
- raise error
+ # Does the parameter supports reverse munge?
+ # This will be called when something wants to access the parameter
+ # in a canonical form different to what the storage form is.
+ def unmunge(&block)
+ define_method(:unmunge, &block)
end
- # Basic parameter initialization.
- def initialize(options = {})
- options = symbolize_options(options)
- if resource = options[:resource]
- self.resource = resource
- options.delete(:resource)
- else
- raise Puppet::DevError, "No resource set for #{self.class.name}"
- end
-
- set_options(options)
+ # Mark whether we're the namevar.
+ def isnamevar
+ @isnamevar = true
+ @required = true
end
- def log(msg)
- send_log(resource[:loglevel], msg)
+ # Is this parameter the namevar? Defaults to false.
+ def isnamevar?
+ @isnamevar
end
- # Is this parameter a metaparam?
- def metaparam?
- self.class.metaparam
+ # This parameter is required.
+ def isrequired
+ @required = true
end
- # each parameter class must define the name method, and parameter
- # instances do not change that name this implicitly means that a given
- # object can only have one parameter instance of a given parameter
- # class
- def name
- self.class.name
+ # Specify features that are required for this parameter to work.
+ def required_features=(*args)
+ @required_features = args.flatten.collect { |a| a.to_s.downcase.intern }
end
- # for testing whether we should actually do anything
- def noop
- @noop ||= false
- tmp = @noop || self.resource.noop || Puppet[:noop] || false
- #debug "noop is #{tmp}"
- tmp
+ # Is this parameter required? Defaults to false.
+ def required?
+ @required
end
- # return the full path to us, for logging and rollback; not currently
- # used
- def pathbuilder
- if @resource
- return [@resource.pathbuilder, self.name]
- else
- return [self.name]
- end
+ # Verify that we got a good value
+ def validate(&block)
+ define_method(:unsafe_validate, &block)
end
- # If the specified value is allowed, then munge appropriately.
- # If the developer uses a 'munge' hook, this method will get overridden.
- def unsafe_munge(value)
- self.class.value_collection.munge(value)
+ # Define a new value for our parameter.
+ def newvalues(*names)
+ @value_collection.newvalues(*names)
end
- # no unmunge by default
- def unmunge(value)
- value
+ def aliasvalue(name, other)
+ @value_collection.aliasvalue(name, other)
end
-
- # A wrapper around our munging that makes sure we raise useful exceptions.
- def munge(value)
- begin
- ret = unsafe_munge(value)
- rescue Puppet::Error => detail
- Puppet.debug "Reraising #{detail}"
- raise
- rescue => detail
- raise Puppet::DevError, "Munging failed for value #{value.inspect} in class #{self.name}: #{detail}", detail.backtrace
- end
- ret
+ end
+
+ # Just a simple method to proxy instance methods to class methods
+ def self.proxymethods(*values)
+ values.each { |val|
+ define_method(val) do
+ self.class.send(val)
+ end
+ }
+ end
+
+ # And then define one of these proxies for each method in our
+ # ParamHandler class.
+ proxymethods("required?", "isnamevar?")
+
+ attr_accessor :resource
+ # LAK 2007-05-09: Keep the @parent around for backward compatibility.
+ attr_accessor :parent
+
+ [:line, :file, :version].each do |param|
+ define_method(param) do
+ resource.send(param)
end
-
- # Verify that the passed value is valid.
- # If the developer uses a 'validate' hook, this method will get overridden.
- def unsafe_validate(value)
- self.class.value_collection.validate(value)
+ end
+
+ def devfail(msg)
+ self.fail(Puppet::DevError, msg)
+ end
+
+ def expirer
+ resource.catalog
+ end
+
+ def fail(*args)
+ type = nil
+ if args[0].is_a?(Class)
+ type = args.shift
+ else
+ type = Puppet::Error
end
- # A protected validation method that only ever raises useful exceptions.
- def validate(value)
- begin
- unsafe_validate(value)
- rescue ArgumentError => detail
- fail detail.to_s
- rescue Puppet::Error, TypeError
- raise
- rescue => detail
- raise Puppet::DevError, "Validate method failed for class #{self.name}: #{detail}", detail.backtrace
- end
- end
+ error = type.new(args.join(" "))
- def remove
- @resource = nil
- end
+ error.line = @resource.line if @resource and @resource.line
- def value
- unmunge(@value) unless @value.nil?
- end
+ error.file = @resource.file if @resource and @resource.file
- # Store the value provided. All of the checking should possibly be
- # late-binding (e.g., users might not exist when the value is assigned
- # but might when it is asked for).
- def value=(value)
- validate(value)
+ raise error
+ end
- @value = munge(value)
+ # Basic parameter initialization.
+ def initialize(options = {})
+ options = symbolize_options(options)
+ if resource = options[:resource]
+ self.resource = resource
+ options.delete(:resource)
+ else
+ raise Puppet::DevError, "No resource set for #{self.class.name}"
end
- # Retrieve the resource's provider. Some types don't have providers, in which
- # case we return the resource object itself.
- def provider
- @resource.provider
+ set_options(options)
+ end
+
+ def log(msg)
+ send_log(resource[:loglevel], msg)
+ end
+
+ # Is this parameter a metaparam?
+ def metaparam?
+ self.class.metaparam
+ end
+
+ # each parameter class must define the name method, and parameter
+ # instances do not change that name this implicitly means that a given
+ # object can only have one parameter instance of a given parameter
+ # class
+ def name
+ self.class.name
+ end
+
+ # for testing whether we should actually do anything
+ def noop
+ @noop ||= false
+ tmp = @noop || self.resource.noop || Puppet[:noop] || false
+ #debug "noop is #{tmp}"
+ tmp
+ end
+
+ # return the full path to us, for logging and rollback; not currently
+ # used
+ def pathbuilder
+ if @resource
+ return [@resource.pathbuilder, self.name]
+ else
+ return [self.name]
end
-
- # The properties need to return tags so that logs correctly collect them.
- def tags
- unless defined?(@tags)
- @tags = []
- # This might not be true in testing
- @tags = @resource.tags if @resource.respond_to? :tags
- @tags << self.name.to_s
- end
- @tags
+ end
+
+ # If the specified value is allowed, then munge appropriately.
+ # If the developer uses a 'munge' hook, this method will get overridden.
+ def unsafe_munge(value)
+ self.class.value_collection.munge(value)
+ end
+
+ # no unmunge by default
+ def unmunge(value)
+ value
+ end
+
+ # A wrapper around our munging that makes sure we raise useful exceptions.
+ def munge(value)
+ begin
+ ret = unsafe_munge(value)
+ rescue Puppet::Error => detail
+ Puppet.debug "Reraising #{detail}"
+ raise
+ rescue => detail
+ raise Puppet::DevError, "Munging failed for value #{value.inspect} in class #{self.name}: #{detail}", detail.backtrace
end
-
- def to_s
- name.to_s
+ ret
+ end
+
+ # Verify that the passed value is valid.
+ # If the developer uses a 'validate' hook, this method will get overridden.
+ def unsafe_validate(value)
+ self.class.value_collection.validate(value)
+ end
+
+ # A protected validation method that only ever raises useful exceptions.
+ def validate(value)
+ begin
+ unsafe_validate(value)
+ rescue ArgumentError => detail
+ fail detail.to_s
+ rescue Puppet::Error, TypeError
+ raise
+ rescue => detail
+ raise Puppet::DevError, "Validate method failed for class #{self.name}: #{detail}", detail.backtrace
+ end
+ end
+
+ def remove
+ @resource = nil
+ end
+
+ def value
+ unmunge(@value) unless @value.nil?
+ end
+
+ # Store the value provided. All of the checking should possibly be
+ # late-binding (e.g., users might not exist when the value is assigned
+ # but might when it is asked for).
+ def value=(value)
+ validate(value)
+
+ @value = munge(value)
+ end
+
+ # Retrieve the resource's provider. Some types don't have providers, in which
+ # case we return the resource object itself.
+ def provider
+ @resource.provider
+ end
+
+ # The properties need to return tags so that logs correctly collect them.
+ def tags
+ unless defined?(@tags)
+ @tags = []
+ # This might not be true in testing
+ @tags = @resource.tags if @resource.respond_to? :tags
+ @tags << self.name.to_s
end
+ @tags
+ end
+
+ def to_s
+ name.to_s
+ end
end
diff --git a/lib/puppet/parameter/value.rb b/lib/puppet/parameter/value.rb
index 3482c2c03..d9bfbafe2 100644
--- a/lib/puppet/parameter/value.rb
+++ b/lib/puppet/parameter/value.rb
@@ -2,62 +2,62 @@ require 'puppet/parameter/value_collection'
# An individual Value class.
class Puppet::Parameter::Value
- attr_reader :name, :options, :event
- attr_accessor :block, :call, :method, :required_features
-
- # Add an alias for this value.
- def alias(name)
- @aliases << convert(name)
- end
-
- # Return all aliases.
- def aliases
- @aliases.dup
- end
-
- # Store the event that our value generates, if it does so.
- def event=(value)
- @event = convert(value)
+ attr_reader :name, :options, :event
+ attr_accessor :block, :call, :method, :required_features
+
+ # Add an alias for this value.
+ def alias(name)
+ @aliases << convert(name)
+ end
+
+ # Return all aliases.
+ def aliases
+ @aliases.dup
+ end
+
+ # Store the event that our value generates, if it does so.
+ def event=(value)
+ @event = convert(value)
+ end
+
+ def initialize(name)
+ if name.is_a?(Regexp)
+ @name = name
+ else
+ # Convert to a string and then a symbol, so things like true/false
+ # still show up as symbols.
+ @name = convert(name)
end
- def initialize(name)
- if name.is_a?(Regexp)
- @name = name
- else
- # Convert to a string and then a symbol, so things like true/false
- # still show up as symbols.
- @name = convert(name)
- end
+ @aliases = []
- @aliases = []
+ @call = :instead
+ end
- @call = :instead
+ # Does a provided value match our value?
+ def match?(value)
+ if regex?
+ return true if name =~ value.to_s
+ else
+ return(name == convert(value) ? true : @aliases.include?(convert(value)))
end
-
- # Does a provided value match our value?
- def match?(value)
- if regex?
- return true if name =~ value.to_s
- else
- return(name == convert(value) ? true : @aliases.include?(convert(value)))
- end
- end
-
- # Is our value a regex?
- def regex?
- @name.is_a?(Regexp)
- end
-
- private
-
- # A standard way of converting all of our values, so we're always
- # comparing apples to apples.
- def convert(value)
- if value == ''
- # We can't intern an empty string, yay.
- value
- else
- value.to_s.to_sym
- end
+ end
+
+ # Is our value a regex?
+ def regex?
+ @name.is_a?(Regexp)
+ end
+
+ private
+
+ # A standard way of converting all of our values, so we're always
+ # comparing apples to apples.
+ def convert(value)
+ if value == ''
+ # We can't intern an empty string, yay.
+ value
+ else
+ value.to_s.to_sym
end
+ end
end
diff --git a/lib/puppet/parameter/value_collection.rb b/lib/puppet/parameter/value_collection.rb
index eabeb30f1..a9fd20233 100644
--- a/lib/puppet/parameter/value_collection.rb
+++ b/lib/puppet/parameter/value_collection.rb
@@ -4,140 +4,140 @@ require 'puppet/parameter/value'
# what values are allowed in a given parameter.
class Puppet::Parameter::ValueCollection
- def aliasvalue(name, other)
- other = other.to_sym
- unless value = match?(other)
- raise Puppet::DevError, "Cannot alias nonexistent value #{other}"
- end
-
- value.alias(name)
+ def aliasvalue(name, other)
+ other = other.to_sym
+ unless value = match?(other)
+ raise Puppet::DevError, "Cannot alias nonexistent value #{other}"
end
- # Return a doc string for all of the values in this parameter/property.
- def doc
- unless defined?(@doc)
- @doc = ""
- unless values.empty?
- @doc += " Valid values are "
- @doc += @strings.collect do |value|
- if aliases = value.aliases and ! aliases.empty?
- "``#{value.name}`` (also called ``#{aliases.join(", ")}``)"
- else
- "``#{value.name}``"
- end
- end.join(", ") + "."
- end
-
- @doc += " Values can match ``" + regexes.join("``, ``") + "``." unless regexes.empty?
- end
-
- @doc
+ value.alias(name)
+ end
+
+ # Return a doc string for all of the values in this parameter/property.
+ def doc
+ unless defined?(@doc)
+ @doc = ""
+ unless values.empty?
+ @doc += " Valid values are "
+ @doc += @strings.collect do |value|
+ if aliases = value.aliases and ! aliases.empty?
+ "``#{value.name}`` (also called ``#{aliases.join(", ")}``)"
+ else
+ "``#{value.name}``"
+ end
+ end.join(", ") + "."
+ end
+
+ @doc += " Values can match ``" + regexes.join("``, ``") + "``." unless regexes.empty?
end
- # Does this collection contain any value definitions?
- def empty?
- @values.empty?
+ @doc
+ end
+
+ # Does this collection contain any value definitions?
+ def empty?
+ @values.empty?
+ end
+
+ def initialize
+ # We often look values up by name, so a hash makes more sense.
+ @values = {}
+
+ # However, we want to retain the ability to match values in order,
+ # but we always prefer directly equality (i.e., strings) over regex matches.
+ @regexes = []
+ @strings = []
+ end
+
+ # Can we match a given value?
+ def match?(test_value)
+ # First look for normal values
+ if value = @strings.find { |v| v.match?(test_value) }
+ return value
end
- def initialize
- # We often look values up by name, so a hash makes more sense.
- @values = {}
-
- # However, we want to retain the ability to match values in order,
- # but we always prefer directly equality (i.e., strings) over regex matches.
- @regexes = []
- @strings = []
+ # Then look for a regex match
+ @regexes.find { |v| v.match?(test_value) }
+ end
+
+ # If the specified value is allowed, then munge appropriately.
+ def munge(value)
+ return value if empty?
+
+ if instance = match?(value)
+ if instance.regex?
+ return value
+ else
+ return instance.name
+ end
+ else
+ return value
end
-
- # Can we match a given value?
- def match?(test_value)
- # First look for normal values
- if value = @strings.find { |v| v.match?(test_value) }
- return value
- end
-
- # Then look for a regex match
- @regexes.find { |v| v.match?(test_value) }
+ end
+
+ # Define a new valid value for a property. You must provide the value itself,
+ # usually as a symbol, or a regex to match the value.
+ #
+ # The first argument to the method is either the value itself or a regex.
+ # The second argument is an option hash; valid options are:
+ # * <tt>:event</tt>: The event that should be returned when this value is set.
+ # * <tt>:call</tt>: When to call any associated block. The default value
+ # is ``instead``, which means to call the value instead of calling the
+ # provider. You can also specify ``before`` or ``after``, which will
+ # call both the block and the provider, according to the order you specify
+ # (the ``first`` refers to when the block is called, not the provider).
+ def newvalue(name, options = {}, &block)
+ value = Puppet::Parameter::Value.new(name)
+ @values[value.name] = value
+ if value.regex?
+ @regexes << value
+ else
+ @strings << value
end
- # If the specified value is allowed, then munge appropriately.
- def munge(value)
- return value if empty?
-
- if instance = match?(value)
- if instance.regex?
- return value
- else
- return instance.name
- end
- else
- return value
- end
+ options.each { |opt, arg| value.send(opt.to_s + "=", arg) }
+ if block_given?
+ value.block = block
+ else
+ value.call = options[:call] || :none
end
- # Define a new valid value for a property. You must provide the value itself,
- # usually as a symbol, or a regex to match the value.
- #
- # The first argument to the method is either the value itself or a regex.
- # The second argument is an option hash; valid options are:
- # * <tt>:event</tt>: The event that should be returned when this value is set.
- # * <tt>:call</tt>: When to call any associated block. The default value
- # is ``instead``, which means to call the value instead of calling the
- # provider. You can also specify ``before`` or ``after``, which will
- # call both the block and the provider, according to the order you specify
- # (the ``first`` refers to when the block is called, not the provider).
- def newvalue(name, options = {}, &block)
- value = Puppet::Parameter::Value.new(name)
- @values[value.name] = value
- if value.regex?
- @regexes << value
- else
- @strings << value
- end
-
- options.each { |opt, arg| value.send(opt.to_s + "=", arg) }
- if block_given?
- value.block = block
- else
- value.call = options[:call] || :none
- end
-
- value.method ||= "set_#{value.name}" if block_given? and ! value.regex?
-
- value
- end
+ value.method ||= "set_#{value.name}" if block_given? and ! value.regex?
- # Define one or more new values for our parameter.
- def newvalues(*names)
- names.each { |name| newvalue(name) }
- end
+ value
+ end
- def regexes
- @regexes.collect { |r| r.name.inspect }
- end
+ # Define one or more new values for our parameter.
+ def newvalues(*names)
+ names.each { |name| newvalue(name) }
+ end
- # Verify that the passed value is valid.
- def validate(value)
- return if empty?
+ def regexes
+ @regexes.collect { |r| r.name.inspect }
+ end
- unless @values.detect { |name, v| v.match?(value) }
- str = "Invalid value #{value.inspect}. "
+ # Verify that the passed value is valid.
+ def validate(value)
+ return if empty?
- str += "Valid values are #{values.join(", ")}. " unless values.empty?
+ unless @values.detect { |name, v| v.match?(value) }
+ str = "Invalid value #{value.inspect}. "
- str += "Valid values match #{regexes.join(", ")}." unless regexes.empty?
+ str += "Valid values are #{values.join(", ")}. " unless values.empty?
- raise ArgumentError, str
- end
- end
+ str += "Valid values match #{regexes.join(", ")}." unless regexes.empty?
- # Return a single value instance.
- def value(name)
- @values[name]
+ raise ArgumentError, str
end
+ end
- # Return the list of valid values.
- def values
- @strings.collect { |s| s.name }
- end
+ # Return a single value instance.
+ def value(name)
+ @values[name]
+ end
+
+ # Return the list of valid values.
+ def values
+ @strings.collect { |s| s.name }
+ end
end
diff --git a/lib/puppet/parser/ast.rb b/lib/puppet/parser/ast.rb
index dffc30a8a..2773a240e 100644
--- a/lib/puppet/parser/ast.rb
+++ b/lib/puppet/parser/ast.rb
@@ -8,85 +8,85 @@ require 'puppet/file_collection/lookup'
# Handles things like file name, line #, and also does the initialization
# for all of the parameters of all of the child objects.
class Puppet::Parser::AST
- # Do this so I don't have to type the full path in all of the subclasses
- AST = Puppet::Parser::AST
+ # Do this so I don't have to type the full path in all of the subclasses
+ AST = Puppet::Parser::AST
- include Puppet::FileCollection::Lookup
+ include Puppet::FileCollection::Lookup
- include Puppet::Util::Errors
- include Puppet::Util::MethodHelper
- include Puppet::Util::Docs
+ include Puppet::Util::Errors
+ include Puppet::Util::MethodHelper
+ include Puppet::Util::Docs
- attr_accessor :parent, :scope
+ attr_accessor :parent, :scope
- # don't fetch lexer comment by default
- def use_docs
- self.class.use_docs
- end
+ # don't fetch lexer comment by default
+ def use_docs
+ self.class.use_docs
+ end
- # allow our subclass to specify they want documentation
- class << self
- attr_accessor :use_docs
- def associates_doc
- self.use_docs = true
- end
+ # allow our subclass to specify they want documentation
+ class << self
+ attr_accessor :use_docs
+ def associates_doc
+ self.use_docs = true
end
+ end
- # Does this ast object set something? If so, it gets evaluated first.
- def self.settor?
- if defined?(@settor)
- @settor
- else
- false
- end
+ # Does this ast object set something? If so, it gets evaluated first.
+ def self.settor?
+ if defined?(@settor)
+ @settor
+ else
+ false
end
+ end
- # Evaluate the current object. Just a stub method, since the subclass
- # should override this method.
- # of the contained children and evaluates them in turn, returning a
- # list of all of the collected values, rejecting nil values
- def evaluate(*options)
- raise Puppet::DevError, "Did not override #evaluate in #{self.class}"
- end
+ # Evaluate the current object. Just a stub method, since the subclass
+ # should override this method.
+ # of the contained children and evaluates them in turn, returning a
+ # list of all of the collected values, rejecting nil values
+ def evaluate(*options)
+ raise Puppet::DevError, "Did not override #evaluate in #{self.class}"
+ end
- # Throw a parse error.
- def parsefail(message)
- self.fail(Puppet::ParseError, message)
- end
+ # Throw a parse error.
+ def parsefail(message)
+ self.fail(Puppet::ParseError, message)
+ end
- # Wrap a statemp in a reusable way so we always throw a parse error.
- def parsewrap
- exceptwrap :type => Puppet::ParseError do
- yield
- end
+ # Wrap a statemp in a reusable way so we always throw a parse error.
+ def parsewrap
+ exceptwrap :type => Puppet::ParseError do
+ yield
end
+ end
- # The version of the evaluate method that should be called, because it
- # correctly handles errors. It is critical to use this method because
- # it can enable you to catch the error where it happens, rather than
- # much higher up the stack.
- def safeevaluate(*options)
- # We duplicate code here, rather than using exceptwrap, because this
- # is called so many times during parsing.
- begin
- return self.evaluate(*options)
- rescue Puppet::Error => detail
- raise adderrorcontext(detail)
- rescue => detail
- error = Puppet::Error.new(detail.to_s)
- # We can't use self.fail here because it always expects strings,
- # not exceptions.
- raise adderrorcontext(error, detail)
- end
+ # The version of the evaluate method that should be called, because it
+ # correctly handles errors. It is critical to use this method because
+ # it can enable you to catch the error where it happens, rather than
+ # much higher up the stack.
+ def safeevaluate(*options)
+ # We duplicate code here, rather than using exceptwrap, because this
+ # is called so many times during parsing.
+ begin
+ return self.evaluate(*options)
+ rescue Puppet::Error => detail
+ raise adderrorcontext(detail)
+ rescue => detail
+ error = Puppet::Error.new(detail.to_s)
+ # We can't use self.fail here because it always expects strings,
+ # not exceptions.
+ raise adderrorcontext(error, detail)
end
+ end
- # Initialize the object. Requires a hash as the argument, and
- # takes each of the parameters of the hash and calls the settor
- # method for them. This is probably pretty inefficient and should
- # likely be changed at some point.
- def initialize(args)
- set_options(args)
- end
+ # Initialize the object. Requires a hash as the argument, and
+ # takes each of the parameters of the hash and calls the settor
+ # method for them. This is probably pretty inefficient and should
+ # likely be changed at some point.
+ def initialize(args)
+ set_options(args)
+ end
end
# And include all of the AST subclasses.
diff --git a/lib/puppet/parser/ast/arithmetic_operator.rb b/lib/puppet/parser/ast/arithmetic_operator.rb
index 6b9a6018c..33352d727 100644
--- a/lib/puppet/parser/ast/arithmetic_operator.rb
+++ b/lib/puppet/parser/ast/arithmetic_operator.rb
@@ -2,38 +2,38 @@ require 'puppet'
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- class ArithmeticOperator < AST::Branch
+ class ArithmeticOperator < AST::Branch
- attr_accessor :operator, :lval, :rval
+ attr_accessor :operator, :lval, :rval
- # Iterate across all of our children.
- def each
- [@lval,@rval,@operator].each { |child| yield child }
- end
+ # Iterate across all of our children.
+ def each
+ [@lval,@rval,@operator].each { |child| yield child }
+ end
- # Returns a boolean which is the result of the boolean operation
- # of lval and rval operands
- def evaluate(scope)
- # evaluate the operands, should return a boolean value
- lval = @lval.safeevaluate(scope)
- lval = Puppet::Parser::Scope.number?(lval)
- if lval == nil
- raise ArgumentError, "left operand of #{@operator} is not a number"
- end
- rval = @rval.safeevaluate(scope)
- rval = Puppet::Parser::Scope.number?(rval)
- if rval == nil
- raise ArgumentError, "right operand of #{@operator} is not a number"
- end
+ # Returns a boolean which is the result of the boolean operation
+ # of lval and rval operands
+ def evaluate(scope)
+ # evaluate the operands, should return a boolean value
+ lval = @lval.safeevaluate(scope)
+ lval = Puppet::Parser::Scope.number?(lval)
+ if lval == nil
+ raise ArgumentError, "left operand of #{@operator} is not a number"
+ end
+ rval = @rval.safeevaluate(scope)
+ rval = Puppet::Parser::Scope.number?(rval)
+ if rval == nil
+ raise ArgumentError, "right operand of #{@operator} is not a number"
+ end
- # compute result
- lval.send(@operator, rval)
- end
+ # compute result
+ lval.send(@operator, rval)
+ end
- def initialize(hash)
- super
+ def initialize(hash)
+ super
- raise ArgumentError, "Invalid arithmetic operator #{@operator}" unless %w{+ - * / << >>}.include?(@operator)
- end
+ raise ArgumentError, "Invalid arithmetic operator #{@operator}" unless %w{+ - * / << >>}.include?(@operator)
end
+ end
end
diff --git a/lib/puppet/parser/ast/astarray.rb b/lib/puppet/parser/ast/astarray.rb
index f0a0c5602..529998e3c 100644
--- a/lib/puppet/parser/ast/astarray.rb
+++ b/lib/puppet/parser/ast/astarray.rb
@@ -1,61 +1,61 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # The basic container class. This object behaves almost identically
- # to a normal array except at initialization time. Note that its name
- # is 'AST::ASTArray', rather than plain 'AST::Array'; I had too many
- # bugs when it was just 'AST::Array', because things like
- # 'object.is_a?(Array)' never behaved as I expected.
- class ASTArray < Branch
- include Enumerable
-
- # Return a child by index. Probably never used.
- def [](index)
- @children[index]
- end
+ # The basic container class. This object behaves almost identically
+ # to a normal array except at initialization time. Note that its name
+ # is 'AST::ASTArray', rather than plain 'AST::Array'; I had too many
+ # bugs when it was just 'AST::Array', because things like
+ # 'object.is_a?(Array)' never behaved as I expected.
+ class ASTArray < Branch
+ include Enumerable
+
+ # Return a child by index. Probably never used.
+ def [](index)
+ @children[index]
+ end
- # Evaluate our children.
- def evaluate(scope)
- # Make a new array, so we don't have to deal with the details of
- # flattening and such
- items = []
-
- # First clean out any AST::ASTArrays
- @children.each { |child|
- if child.instance_of?(AST::ASTArray)
- child.each do |ac|
- items << ac
- end
- else
- items << child
- end
- }
-
- rets = items.flatten.collect { |child|
- child.safeevaluate(scope)
- }
- rets.reject { |o| o.nil? }
+ # Evaluate our children.
+ def evaluate(scope)
+ # Make a new array, so we don't have to deal with the details of
+ # flattening and such
+ items = []
+
+ # First clean out any AST::ASTArrays
+ @children.each { |child|
+ if child.instance_of?(AST::ASTArray)
+ child.each do |ac|
+ items << ac
+ end
+ else
+ items << child
end
+ }
- def push(*ary)
- ary.each { |child|
- #Puppet.debug "adding %s(%s) of type %s to %s" %
- # [child, child.object_id, child.class.to_s.sub(/.+::/,''),
- # self.object_id]
- @children.push(child)
- }
+ rets = items.flatten.collect { |child|
+ child.safeevaluate(scope)
+ }
+ rets.reject { |o| o.nil? }
+ end
- self
- end
+ def push(*ary)
+ ary.each { |child|
+ #Puppet.debug "adding %s(%s) of type %s to %s" %
+ # [child, child.object_id, child.class.to_s.sub(/.+::/,''),
+ # self.object_id]
+ @children.push(child)
+ }
- def to_s
- "[" + @children.collect { |c| c.to_s }.join(', ') + "]"
- end
+ self
+ end
+
+ def to_s
+ "[" + @children.collect { |c| c.to_s }.join(', ') + "]"
end
+ end
- # A simple container class, containing the parameters for an object.
- # Used for abstracting the grammar declarations. Basically unnecessary
- # except that I kept finding bugs because I had too many arrays that
- # meant completely different things.
- class ResourceInstance < ASTArray; end
+ # A simple container class, containing the parameters for an object.
+ # Used for abstracting the grammar declarations. Basically unnecessary
+ # except that I kept finding bugs because I had too many arrays that
+ # meant completely different things.
+ class ResourceInstance < ASTArray; end
end
diff --git a/lib/puppet/parser/ast/asthash.rb b/lib/puppet/parser/ast/asthash.rb
index d16b7459f..ae81d35dd 100644
--- a/lib/puppet/parser/ast/asthash.rb
+++ b/lib/puppet/parser/ast/asthash.rb
@@ -1,37 +1,37 @@
require 'puppet/parser/ast/leaf'
class Puppet::Parser::AST
- class ASTHash < Leaf
- include Enumerable
+ class ASTHash < Leaf
+ include Enumerable
- # Evaluate our children.
- def evaluate(scope)
- items = {}
+ # Evaluate our children.
+ def evaluate(scope)
+ items = {}
- @value.each_pair do |k,v|
- key = k.respond_to?(:safeevaluate) ? k.safeevaluate(scope) : k
- items.merge!({ key => v.safeevaluate(scope) })
- end
+ @value.each_pair do |k,v|
+ key = k.respond_to?(:safeevaluate) ? k.safeevaluate(scope) : k
+ items.merge!({ key => v.safeevaluate(scope) })
+ end
- items
- end
+ items
+ end
- def merge(hash)
- case hash
- when ASTHash
- @value = @value.merge(hash.value)
- when Hash
- @value = @value.merge(hash)
- end
- end
+ def merge(hash)
+ case hash
+ when ASTHash
+ @value = @value.merge(hash.value)
+ when Hash
+ @value = @value.merge(hash)
+ end
+ end
- def to_s
- "{" + @value.collect { |v| v.collect { |a| a.to_s }.join(' => ') }.join(', ') + "}"
- end
+ def to_s
+ "{" + @value.collect { |v| v.collect { |a| a.to_s }.join(' => ') }.join(', ') + "}"
+ end
- def initialize(args)
- super(args)
- @value ||= {}
- end
+ def initialize(args)
+ super(args)
+ @value ||= {}
end
+ end
end
diff --git a/lib/puppet/parser/ast/boolean_operator.rb b/lib/puppet/parser/ast/boolean_operator.rb
index 0f7e21d2c..8481e4f8d 100644
--- a/lib/puppet/parser/ast/boolean_operator.rb
+++ b/lib/puppet/parser/ast/boolean_operator.rb
@@ -2,45 +2,45 @@ require 'puppet'
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- class BooleanOperator < AST::Branch
+ class BooleanOperator < AST::Branch
- attr_accessor :operator, :lval, :rval
+ attr_accessor :operator, :lval, :rval
- # Iterate across all of our children.
- def each
- [@lval,@rval,@operator].each { |child| yield child }
- end
+ # Iterate across all of our children.
+ def each
+ [@lval,@rval,@operator].each { |child| yield child }
+ end
- # Returns a boolean which is the result of the boolean operation
- # of lval and rval operands
- def evaluate(scope)
- # evaluate the first operand, should return a boolean value
- lval = @lval.safeevaluate(scope)
+ # Returns a boolean which is the result of the boolean operation
+ # of lval and rval operands
+ def evaluate(scope)
+ # evaluate the first operand, should return a boolean value
+ lval = @lval.safeevaluate(scope)
- # return result
- # lazy evaluate right operand
- case @operator
- when "and"
- if Puppet::Parser::Scope.true?(lval)
- rval = @rval.safeevaluate(scope)
- Puppet::Parser::Scope.true?(rval)
- else # false and false == false
- false
- end
- when "or"
- if Puppet::Parser::Scope.true?(lval)
- true
- else
- rval = @rval.safeevaluate(scope)
- Puppet::Parser::Scope.true?(rval)
- end
- end
+ # return result
+ # lazy evaluate right operand
+ case @operator
+ when "and"
+ if Puppet::Parser::Scope.true?(lval)
+ rval = @rval.safeevaluate(scope)
+ Puppet::Parser::Scope.true?(rval)
+ else # false and false == false
+ false
+ end
+ when "or"
+ if Puppet::Parser::Scope.true?(lval)
+ true
+ else
+ rval = @rval.safeevaluate(scope)
+ Puppet::Parser::Scope.true?(rval)
end
+ end
+ end
- def initialize(hash)
- super
+ def initialize(hash)
+ super
- raise ArgumentError, "Invalid boolean operator #{@operator}" unless %w{and or}.include?(@operator)
- end
+ raise ArgumentError, "Invalid boolean operator #{@operator}" unless %w{and or}.include?(@operator)
end
+ end
end
diff --git a/lib/puppet/parser/ast/branch.rb b/lib/puppet/parser/ast/branch.rb
index 96d065e4c..73a2f674b 100644
--- a/lib/puppet/parser/ast/branch.rb
+++ b/lib/puppet/parser/ast/branch.rb
@@ -1,37 +1,37 @@
class Puppet::Parser::AST
- # The parent class of all AST objects that contain other AST objects.
- # Everything but the really simple objects descend from this. It is
- # important to note that Branch objects contain other AST objects only --
- # if you want to contain values, use a descendent of the AST::Leaf class.
- class Branch < AST
- include Enumerable
- attr_accessor :pin, :children
+ # The parent class of all AST objects that contain other AST objects.
+ # Everything but the really simple objects descend from this. It is
+ # important to note that Branch objects contain other AST objects only --
+ # if you want to contain values, use a descendent of the AST::Leaf class.
+ class Branch < AST
+ include Enumerable
+ attr_accessor :pin, :children
- # Yield each contained AST node in turn. Used mostly by 'evaluate'.
- # This definition means that I don't have to override 'evaluate'
- # every time, but each child of Branch will likely need to override
- # this method.
- def each
- @children.each { |child|
- yield child
- }
- end
+ # Yield each contained AST node in turn. Used mostly by 'evaluate'.
+ # This definition means that I don't have to override 'evaluate'
+ # every time, but each child of Branch will likely need to override
+ # this method.
+ def each
+ @children.each { |child|
+ yield child
+ }
+ end
- # Initialize our object. Largely relies on the method from the base
- # class, but also does some verification.
- def initialize(arghash)
- super(arghash)
+ # Initialize our object. Largely relies on the method from the base
+ # class, but also does some verification.
+ def initialize(arghash)
+ super(arghash)
- # Create the hash, if it was not set at initialization time.
- @children ||= []
+ # Create the hash, if it was not set at initialization time.
+ @children ||= []
- # Verify that we only got valid AST nodes.
- @children.each { |child|
- unless child.is_a?(AST)
- raise Puppet::DevError,
- "child #{child} is a #{child.class} instead of ast"
- end
- }
+ # Verify that we only got valid AST nodes.
+ @children.each { |child|
+ unless child.is_a?(AST)
+ raise Puppet::DevError,
+ "child #{child} is a #{child.class} instead of ast"
end
+ }
end
+ end
end
diff --git a/lib/puppet/parser/ast/caseopt.rb b/lib/puppet/parser/ast/caseopt.rb
index 6cf36f94c..4e296e82f 100644
--- a/lib/puppet/parser/ast/caseopt.rb
+++ b/lib/puppet/parser/ast/caseopt.rb
@@ -1,64 +1,64 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # Each individual option in a case statement.
- class CaseOpt < AST::Branch
- attr_accessor :value, :statements
+ # Each individual option in a case statement.
+ class CaseOpt < AST::Branch
+ attr_accessor :value, :statements
- # CaseOpt is a bit special -- we just want the value first,
- # so that CaseStatement can compare, and then it will selectively
- # decide whether to fully evaluate this option
+ # CaseOpt is a bit special -- we just want the value first,
+ # so that CaseStatement can compare, and then it will selectively
+ # decide whether to fully evaluate this option
- def each
- [@value,@statements].each { |child| yield child }
- end
+ def each
+ [@value,@statements].each { |child| yield child }
+ end
- # Are we the default option?
- def default?
- # Cache the @default value.
- return @default if defined?(@default)
+ # Are we the default option?
+ def default?
+ # Cache the @default value.
+ return @default if defined?(@default)
- if @value.is_a?(AST::ASTArray)
- @value.each { |subval|
- if subval.is_a?(AST::Default)
- @default = true
- break
- end
- }
- else
- @default = true if @value.is_a?(AST::Default)
- end
+ if @value.is_a?(AST::ASTArray)
+ @value.each { |subval|
+ if subval.is_a?(AST::Default)
+ @default = true
+ break
+ end
+ }
+ else
+ @default = true if @value.is_a?(AST::Default)
+ end
- @default ||= false
+ @default ||= false
- @default
- end
+ @default
+ end
- # You can specify a list of values; return each in turn.
- def eachvalue(scope)
- if @value.is_a?(AST::ASTArray)
- @value.each { |subval|
- yield subval.safeevaluate(scope)
- }
- else
- yield @value.safeevaluate(scope)
- end
- end
+ # You can specify a list of values; return each in turn.
+ def eachvalue(scope)
+ if @value.is_a?(AST::ASTArray)
+ @value.each { |subval|
+ yield subval.safeevaluate(scope)
+ }
+ else
+ yield @value.safeevaluate(scope)
+ end
+ end
- def eachopt
- if @value.is_a?(AST::ASTArray)
- @value.each { |subval|
- yield subval
- }
- else
- yield @value
- end
- end
+ def eachopt
+ if @value.is_a?(AST::ASTArray)
+ @value.each { |subval|
+ yield subval
+ }
+ else
+ yield @value
+ end
+ end
- # Evaluate the actual statements; this only gets called if
- # our option matched.
- def evaluate(scope)
- @statements.safeevaluate(scope)
- end
+ # Evaluate the actual statements; this only gets called if
+ # our option matched.
+ def evaluate(scope)
+ @statements.safeevaluate(scope)
end
+ end
end
diff --git a/lib/puppet/parser/ast/casestatement.rb b/lib/puppet/parser/ast/casestatement.rb
index 0cddef0f0..8370d11f3 100644
--- a/lib/puppet/parser/ast/casestatement.rb
+++ b/lib/puppet/parser/ast/casestatement.rb
@@ -1,44 +1,44 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # The basic logical structure in Puppet. Supports a list of
- # tests and statement arrays.
- class CaseStatement < AST::Branch
- attr_accessor :test, :options, :default
+ # The basic logical structure in Puppet. Supports a list of
+ # tests and statement arrays.
+ class CaseStatement < AST::Branch
+ attr_accessor :test, :options, :default
- associates_doc
+ associates_doc
- # Short-curcuit evaluation. Return the value of the statements for
- # the first option that matches.
- def evaluate(scope)
- level = scope.ephemeral_level
+ # Short-curcuit evaluation. Return the value of the statements for
+ # the first option that matches.
+ def evaluate(scope)
+ level = scope.ephemeral_level
- value = @test.safeevaluate(scope)
+ value = @test.safeevaluate(scope)
- retvalue = nil
- found = false
+ retvalue = nil
+ found = false
- # Iterate across the options looking for a match.
- default = nil
- @options.each do |option|
- option.eachopt do |opt|
- return option.safeevaluate(scope) if opt.evaluate_match(value, scope)
- end
+ # Iterate across the options looking for a match.
+ default = nil
+ @options.each do |option|
+ option.eachopt do |opt|
+ return option.safeevaluate(scope) if opt.evaluate_match(value, scope)
+ end
- default = option if option.default?
- end
+ default = option if option.default?
+ end
- # Unless we found something, look for the default.
- return default.safeevaluate(scope) if default
+ # Unless we found something, look for the default.
+ return default.safeevaluate(scope) if default
- Puppet.debug "No true answers and no default"
- return nil
- ensure
- scope.unset_ephemeral_var(level)
- end
+ Puppet.debug "No true answers and no default"
+ return nil
+ ensure
+ scope.unset_ephemeral_var(level)
+ end
- def each
- [@test,@options].each { |child| yield child }
- end
+ def each
+ [@test,@options].each { |child| yield child }
end
+ end
end
diff --git a/lib/puppet/parser/ast/collection.rb b/lib/puppet/parser/ast/collection.rb
index 44f3b330c..09d5b4eb3 100644
--- a/lib/puppet/parser/ast/collection.rb
+++ b/lib/puppet/parser/ast/collection.rb
@@ -6,60 +6,60 @@ require 'puppet/parser/collector'
# them to the current host, yo.
class Puppet::Parser::AST
class Collection < AST::Branch
- attr_accessor :type, :query, :form
- attr_reader :override
+ attr_accessor :type, :query, :form
+ attr_reader :override
- associates_doc
+ associates_doc
- # We return an object that does a late-binding evaluation.
- def evaluate(scope)
- if self.query
- str, code = self.query.safeevaluate scope
- else
- str = code = nil
- end
+ # We return an object that does a late-binding evaluation.
+ def evaluate(scope)
+ if self.query
+ str, code = self.query.safeevaluate scope
+ else
+ str = code = nil
+ end
- newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form)
+ newcoll = Puppet::Parser::Collector.new(scope, @type, str, code, self.form)
- scope.compiler.add_collection(newcoll)
+ scope.compiler.add_collection(newcoll)
- # overrides if any
- # Evaluate all of the specified params.
- if @override
- params = @override.collect do |param|
- param.safeevaluate(scope)
- end
+ # overrides if any
+ # Evaluate all of the specified params.
+ if @override
+ params = @override.collect do |param|
+ param.safeevaluate(scope)
+ end
- newcoll.add_override(
+ newcoll.add_override(
- :parameters => params,
- :file => @file,
- :line => @line,
- :source => scope.source,
+ :parameters => params,
+ :file => @file,
+ :line => @line,
+ :source => scope.source,
- :scope => scope
- )
- end
-
- newcoll
+ :scope => scope
+ )
end
- # Handle our parameter ourselves
- def override=(override)
- if override.is_a?(AST::ASTArray)
- @override = override
- else
+ newcoll
+ end
+
+ # Handle our parameter ourselves
+ def override=(override)
+ if override.is_a?(AST::ASTArray)
+ @override = override
+ else
- @override = AST::ASTArray.new(
+ @override = AST::ASTArray.new(
- :line => override.line,
- :file => override.file,
+ :line => override.line,
+ :file => override.file,
- :children => [override]
- )
- end
+ :children => [override]
+ )
end
+ end
end
end
diff --git a/lib/puppet/parser/ast/collexpr.rb b/lib/puppet/parser/ast/collexpr.rb
index f71b53d46..f912b4b33 100644
--- a/lib/puppet/parser/ast/collexpr.rb
+++ b/lib/puppet/parser/ast/collexpr.rb
@@ -6,81 +6,81 @@ require 'puppet/parser/collector'
# them to the current host, yo.
class Puppet::Parser::AST
class CollExpr < AST::Branch
- attr_accessor :test1, :test2, :oper, :form, :type, :parens
+ attr_accessor :test1, :test2, :oper, :form, :type, :parens
- # We return an object that does a late-binding evaluation.
- def evaluate(scope)
- # Make sure our contained expressions have all the info they need.
- [@test1, @test2].each do |t|
- if t.is_a?(self.class)
- t.form ||= self.form
- t.type ||= self.type
- end
- end
-
- # The code is only used for virtual lookups
- str1, code1 = @test1.safeevaluate scope
- str2, code2 = @test2.safeevaluate scope
-
- # First build up the virtual code.
- # If we're a conjunction operator, then we're calling code. I did
- # some speed comparisons, and it's at least twice as fast doing these
- # case statements as doing an eval here.
- code = proc do |resource|
- case @oper
- when "and"; code1.call(resource) and code2.call(resource)
- when "or"; code1.call(resource) or code2.call(resource)
- when "=="
- if str1 == "tag"
- resource.tagged?(str2)
- else
- if resource[str1].is_a?(Array)
- resource[str1].include?(str2)
- else
- resource[str1] == str2
- end
- end
- when "!="; resource[str1] != str2
- end
- end
-
- # Now build up the rails conditions code
- if self.parens and self.form == :exported
- Puppet.warning "Parentheses are ignored in Rails searches"
- end
+ # We return an object that does a late-binding evaluation.
+ def evaluate(scope)
+ # Make sure our contained expressions have all the info they need.
+ [@test1, @test2].each do |t|
+ if t.is_a?(self.class)
+ t.form ||= self.form
+ t.type ||= self.type
+ end
+ end
- case @oper
- when "and", "or"
- if form == :exported
- raise Puppet::ParseError, "Puppet does not currently support collecting exported resources with more than one condition"
- end
- oper = @oper.upcase
- when "=="; oper = "="
- else
- oper = @oper
- end
+ # The code is only used for virtual lookups
+ str1, code1 = @test1.safeevaluate scope
+ str2, code2 = @test2.safeevaluate scope
- if oper == "=" or oper == "!="
- # Add the rails association info where necessary
- case str1
- when "title"
- str = "title #{oper} '#{str2}'"
- when "tag"
- str = "puppet_tags.name #{oper} '#{str2}'"
- else
- str = "param_values.value #{oper} '#{str2}' and param_names.name = '#{str1}'"
- end
+ # First build up the virtual code.
+ # If we're a conjunction operator, then we're calling code. I did
+ # some speed comparisons, and it's at least twice as fast doing these
+ # case statements as doing an eval here.
+ code = proc do |resource|
+ case @oper
+ when "and"; code1.call(resource) and code2.call(resource)
+ when "or"; code1.call(resource) or code2.call(resource)
+ when "=="
+ if str1 == "tag"
+ resource.tagged?(str2)
else
- str = "(#{str1}) #{oper} (#{str2})"
+ if resource[str1].is_a?(Array)
+ resource[str1].include?(str2)
+ else
+ resource[str1] == str2
+ end
end
+ when "!="; resource[str1] != str2
+ end
+ end
- return str, code
+ # Now build up the rails conditions code
+ if self.parens and self.form == :exported
+ Puppet.warning "Parentheses are ignored in Rails searches"
end
- def initialize(hash = {})
- super
+ case @oper
+ when "and", "or"
+ if form == :exported
+ raise Puppet::ParseError, "Puppet does not currently support collecting exported resources with more than one condition"
+ end
+ oper = @oper.upcase
+ when "=="; oper = "="
+ else
+ oper = @oper
+ end
- raise ArgumentError, "Invalid operator #{@oper}" unless %w{== != and or}.include?(@oper)
+ if oper == "=" or oper == "!="
+ # Add the rails association info where necessary
+ case str1
+ when "title"
+ str = "title #{oper} '#{str2}'"
+ when "tag"
+ str = "puppet_tags.name #{oper} '#{str2}'"
+ else
+ str = "param_values.value #{oper} '#{str2}' and param_names.name = '#{str1}'"
+ end
+ else
+ str = "(#{str1}) #{oper} (#{str2})"
end
+
+ return str, code
+ end
+
+ def initialize(hash = {})
+ super
+
+ raise ArgumentError, "Invalid operator #{@oper}" unless %w{== != and or}.include?(@oper)
+ end
end
end
diff --git a/lib/puppet/parser/ast/comparison_operator.rb b/lib/puppet/parser/ast/comparison_operator.rb
index e8b21d45f..c8694bbff 100644
--- a/lib/puppet/parser/ast/comparison_operator.rb
+++ b/lib/puppet/parser/ast/comparison_operator.rb
@@ -2,38 +2,38 @@ require 'puppet'
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- class ComparisonOperator < AST::Branch
-
- attr_accessor :operator, :lval, :rval
-
- # Iterate across all of our children.
- def each
- [@lval,@rval,@operator].each { |child| yield child }
- end
-
- # Returns a boolean which is the result of the boolean operation
- # of lval and rval operands
- def evaluate(scope)
- # evaluate the operands, should return a boolean value
- lval = @lval.safeevaluate(scope)
- rval = @rval.safeevaluate(scope)
-
- # convert to number if operands are number
- lval = Puppet::Parser::Scope.number?(lval) || lval
- rval = Puppet::Parser::Scope.number?(rval) || rval
-
- # return result
- unless @operator == '!='
- lval.send(@operator,rval)
- else
- lval != rval
- end
- end
-
- def initialize(hash)
- super
-
- raise ArgumentError, "Invalid comparison operator #{@operator}" unless %w{== != < > <= >=}.include?(@operator)
- end
+ class ComparisonOperator < AST::Branch
+
+ attr_accessor :operator, :lval, :rval
+
+ # Iterate across all of our children.
+ def each
+ [@lval,@rval,@operator].each { |child| yield child }
+ end
+
+ # Returns a boolean which is the result of the boolean operation
+ # of lval and rval operands
+ def evaluate(scope)
+ # evaluate the operands, should return a boolean value
+ lval = @lval.safeevaluate(scope)
+ rval = @rval.safeevaluate(scope)
+
+ # convert to number if operands are number
+ lval = Puppet::Parser::Scope.number?(lval) || lval
+ rval = Puppet::Parser::Scope.number?(rval) || rval
+
+ # return result
+ unless @operator == '!='
+ lval.send(@operator,rval)
+ else
+ lval != rval
+ end
+ end
+
+ def initialize(hash)
+ super
+
+ raise ArgumentError, "Invalid comparison operator #{@operator}" unless %w{== != < > <= >=}.include?(@operator)
end
+ end
end
diff --git a/lib/puppet/parser/ast/else.rb b/lib/puppet/parser/ast/else.rb
index 2da9191c8..172149116 100644
--- a/lib/puppet/parser/ast/else.rb
+++ b/lib/puppet/parser/ast/else.rb
@@ -1,22 +1,22 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # A separate ElseIf statement; can function as an 'else' if there's no
- # test.
- class Else < AST::Branch
+ # A separate ElseIf statement; can function as an 'else' if there's no
+ # test.
+ class Else < AST::Branch
- associates_doc
+ associates_doc
- attr_accessor :statements
+ attr_accessor :statements
- def each
- yield @statements
- end
+ def each
+ yield @statements
+ end
- # Evaluate the actual statements; this only gets called if
- # our test was true matched.
- def evaluate(scope)
- @statements.safeevaluate(scope)
- end
+ # Evaluate the actual statements; this only gets called if
+ # our test was true matched.
+ def evaluate(scope)
+ @statements.safeevaluate(scope)
end
+ end
end
diff --git a/lib/puppet/parser/ast/function.rb b/lib/puppet/parser/ast/function.rb
index 6f6c869f5..602016c75 100644
--- a/lib/puppet/parser/ast/function.rb
+++ b/lib/puppet/parser/ast/function.rb
@@ -1,51 +1,51 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # An AST object to call a function.
- class Function < AST::Branch
+ # An AST object to call a function.
+ class Function < AST::Branch
- associates_doc
+ associates_doc
- attr_accessor :name, :arguments
+ attr_accessor :name, :arguments
- @settor = true
+ @settor = true
- def evaluate(scope)
+ def evaluate(scope)
- # Make sure it's a defined function
- raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name)
+ # Make sure it's a defined function
+ raise Puppet::ParseError, "Unknown function #{@name}" unless Puppet::Parser::Functions.function(@name)
- # Now check that it's been used correctly
- case @ftype
- when :rvalue
- raise Puppet::ParseError, "Function '#{@name}' does not return a value" unless Puppet::Parser::Functions.rvalue?(@name)
- when :statement
- if Puppet::Parser::Functions.rvalue?(@name)
- raise Puppet::ParseError,
- "Function '#{@name}' must be the value of a statement"
- end
- else
- raise Puppet::DevError, "Invalid function type #{@ftype.inspect}"
- end
+ # Now check that it's been used correctly
+ case @ftype
+ when :rvalue
+ raise Puppet::ParseError, "Function '#{@name}' does not return a value" unless Puppet::Parser::Functions.rvalue?(@name)
+ when :statement
+ if Puppet::Parser::Functions.rvalue?(@name)
+ raise Puppet::ParseError,
+ "Function '#{@name}' must be the value of a statement"
+ end
+ else
+ raise Puppet::DevError, "Invalid function type #{@ftype.inspect}"
+ end
- # We don't need to evaluate the name, because it's plaintext
- args = @arguments.safeevaluate(scope)
+ # We don't need to evaluate the name, because it's plaintext
+ args = @arguments.safeevaluate(scope)
- scope.send("function_#{@name}", args)
- end
+ scope.send("function_#{@name}", args)
+ end
- def initialize(hash)
- @ftype = hash[:ftype] || :rvalue
- hash.delete(:ftype) if hash.include? :ftype
+ def initialize(hash)
+ @ftype = hash[:ftype] || :rvalue
+ hash.delete(:ftype) if hash.include? :ftype
- super(hash)
+ super(hash)
- # Lastly, check the parity
- end
+ # Lastly, check the parity
+ end
- def to_s
- args = arguments.is_a?(ASTArray) ? arguments.to_s.gsub(/\[(.*)\]/,'\1') : arguments
- "#{name}(#{args})"
- end
+ def to_s
+ args = arguments.is_a?(ASTArray) ? arguments.to_s.gsub(/\[(.*)\]/,'\1') : arguments
+ "#{name}(#{args})"
end
+ end
end
diff --git a/lib/puppet/parser/ast/ifstatement.rb b/lib/puppet/parser/ast/ifstatement.rb
index cbb61bf9c..7fd8a576a 100644
--- a/lib/puppet/parser/ast/ifstatement.rb
+++ b/lib/puppet/parser/ast/ifstatement.rb
@@ -1,34 +1,34 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # A basic 'if/elsif/else' statement.
- class IfStatement < AST::Branch
+ # A basic 'if/elsif/else' statement.
+ class IfStatement < AST::Branch
- associates_doc
+ associates_doc
- attr_accessor :test, :else, :statements
+ attr_accessor :test, :else, :statements
- def each
- [@test,@else,@statements].each { |child| yield child }
- end
+ def each
+ [@test,@else,@statements].each { |child| yield child }
+ end
- # Short-curcuit evaluation. If we're true, evaluate our statements,
- # else if there's an 'else' setting, evaluate it.
- # the first option that matches.
- def evaluate(scope)
- level = scope.ephemeral_level
- value = @test.safeevaluate(scope)
+ # Short-curcuit evaluation. If we're true, evaluate our statements,
+ # else if there's an 'else' setting, evaluate it.
+ # the first option that matches.
+ def evaluate(scope)
+ level = scope.ephemeral_level
+ value = @test.safeevaluate(scope)
- # let's emulate a new scope for each branches
- begin
- if Puppet::Parser::Scope.true?(value)
- return @statements.safeevaluate(scope)
- else
- return defined?(@else) ? @else.safeevaluate(scope) : nil
- end
- ensure
- scope.unset_ephemeral_var(level)
- end
+ # let's emulate a new scope for each branches
+ begin
+ if Puppet::Parser::Scope.true?(value)
+ return @statements.safeevaluate(scope)
+ else
+ return defined?(@else) ? @else.safeevaluate(scope) : nil
end
+ ensure
+ scope.unset_ephemeral_var(level)
+ end
end
+ end
end
diff --git a/lib/puppet/parser/ast/in_operator.rb b/lib/puppet/parser/ast/in_operator.rb
index 1b17b1006..2a163e726 100644
--- a/lib/puppet/parser/ast/in_operator.rb
+++ b/lib/puppet/parser/ast/in_operator.rb
@@ -2,23 +2,23 @@ require 'puppet'
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- class InOperator < AST::Branch
+ class InOperator < AST::Branch
- attr_accessor :lval, :rval
+ attr_accessor :lval, :rval
- # Returns a boolean which is the result of the 'in' operation
- # of lval and rval operands
- def evaluate(scope)
+ # Returns a boolean which is the result of the 'in' operation
+ # of lval and rval operands
+ def evaluate(scope)
- # evaluate the operands, should return a boolean value
- lval = @lval.safeevaluate(scope)
- raise ArgumentError, "'#{lval}' from left operand of 'in' expression is not a string" unless lval.is_a?(::String)
+ # evaluate the operands, should return a boolean value
+ lval = @lval.safeevaluate(scope)
+ raise ArgumentError, "'#{lval}' from left operand of 'in' expression is not a string" unless lval.is_a?(::String)
- rval = @rval.safeevaluate(scope)
- unless rval.respond_to?(:include?)
- raise ArgumentError, "'#{rval}' from right operand of 'in' expression is not of a supported type (string, array or hash)"
- end
- rval.include?(lval)
- end
+ rval = @rval.safeevaluate(scope)
+ unless rval.respond_to?(:include?)
+ raise ArgumentError, "'#{rval}' from right operand of 'in' expression is not of a supported type (string, array or hash)"
+ end
+ rval.include?(lval)
end
+ end
end
diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb
index a62edc61e..3b9163d9c 100644
--- a/lib/puppet/parser/ast/leaf.rb
+++ b/lib/puppet/parser/ast/leaf.rb
@@ -1,224 +1,224 @@
class Puppet::Parser::AST
- # The base class for all of the leaves of the parse trees. These
- # basically just have types and values. Both of these parameters
- # are simple values, not AST objects.
- class Leaf < AST
- attr_accessor :value, :type
-
- # Return our value.
- def evaluate(scope)
- @value
- end
-
- # evaluate ourselves, and match
- def evaluate_match(value, scope)
- obj = self.safeevaluate(scope)
+ # The base class for all of the leaves of the parse trees. These
+ # basically just have types and values. Both of these parameters
+ # are simple values, not AST objects.
+ class Leaf < AST
+ attr_accessor :value, :type
+
+ # Return our value.
+ def evaluate(scope)
+ @value
+ end
- obj = obj.downcase if obj.respond_to?(:downcase)
- value = value.downcase if value.respond_to?(:downcase)
+ # evaluate ourselves, and match
+ def evaluate_match(value, scope)
+ obj = self.safeevaluate(scope)
- # "" == undef for case/selector/if
- obj == value or (obj == "" and value == :undef)
- end
+ obj = obj.downcase if obj.respond_to?(:downcase)
+ value = value.downcase if value.respond_to?(:downcase)
- def match(value)
- @value == value
- end
+ # "" == undef for case/selector/if
+ obj == value or (obj == "" and value == :undef)
+ end
- def to_s
- @value.to_s unless @value.nil?
- end
+ def match(value)
+ @value == value
end
- # The boolean class. True or false. Converts the string it receives
- # to a Ruby boolean.
- class Boolean < AST::Leaf
+ def to_s
+ @value.to_s unless @value.nil?
+ end
+ end
- # Use the parent method, but then convert to a real boolean.
- def initialize(hash)
- super
+ # The boolean class. True or false. Converts the string it receives
+ # to a Ruby boolean.
+ class Boolean < AST::Leaf
- unless @value == true or @value == false
- raise Puppet::DevError,
- "'#{@value}' is not a boolean"
- end
- @value
- end
+ # Use the parent method, but then convert to a real boolean.
+ def initialize(hash)
+ super
- def to_s
- @value ? "true" : "false"
- end
+ unless @value == true or @value == false
+ raise Puppet::DevError,
+ "'#{@value}' is not a boolean"
+ end
+ @value
end
- # The base string class.
- class String < AST::Leaf
- def evaluate(scope)
- @value
- end
+ def to_s
+ @value ? "true" : "false"
+ end
+ end
- def to_s
- "\"#{@value}\""
- end
+ # The base string class.
+ class String < AST::Leaf
+ def evaluate(scope)
+ @value
end
- # An uninterpreted string.
- class FlatString < AST::Leaf
- def evaluate(scope)
- @value
- end
+ def to_s
+ "\"#{@value}\""
+ end
+ end
- def to_s
- "\"#{@value}\""
- end
+ # An uninterpreted string.
+ class FlatString < AST::Leaf
+ def evaluate(scope)
+ @value
end
- class Concat < AST::Leaf
- def evaluate(scope)
- @value.collect { |x| x.evaluate(scope) }.join
- end
+ def to_s
+ "\"#{@value}\""
+ end
+ end
- def to_s
- "concat(#{@value.join(',')})"
- end
+ class Concat < AST::Leaf
+ def evaluate(scope)
+ @value.collect { |x| x.evaluate(scope) }.join
end
- # The 'default' option on case statements and selectors.
- class Default < AST::Leaf; end
+ def to_s
+ "concat(#{@value.join(',')})"
+ end
+ end
- # Capitalized words; used mostly for type-defaults, but also
- # get returned by the lexer any other time an unquoted capitalized
- # word is found.
- class Type < AST::Leaf; end
+ # The 'default' option on case statements and selectors.
+ class Default < AST::Leaf; end
- # Lower-case words.
- class Name < AST::Leaf; end
+ # Capitalized words; used mostly for type-defaults, but also
+ # get returned by the lexer any other time an unquoted capitalized
+ # word is found.
+ class Type < AST::Leaf; end
- # double-colon separated class names
- class ClassName < AST::Leaf; end
+ # Lower-case words.
+ class Name < AST::Leaf; end
- # undef values; equiv to nil
- class Undef < AST::Leaf; end
+ # double-colon separated class names
+ class ClassName < AST::Leaf; end
- # Host names, either fully qualified or just the short name, or even a regex
- class HostName < AST::Leaf
- def initialize(hash)
- super
+ # undef values; equiv to nil
+ class Undef < AST::Leaf; end
- # Note that this is an AST::Regex, not a Regexp
- @value = @value.to_s.downcase unless @value.is_a?(Regex)
- if @value =~ /[^-\w.]/
- raise Puppet::DevError,
- "'#{@value}' is not a valid hostname"
- end
- end
+ # Host names, either fully qualified or just the short name, or even a regex
+ class HostName < AST::Leaf
+ def initialize(hash)
+ super
- # implementing eql? and hash so that when an HostName is stored
- # in a hash it has the same hashing properties as the underlying value
- def eql?(value)
- value = value.value if value.is_a?(HostName)
- @value.eql?(value)
- end
+ # Note that this is an AST::Regex, not a Regexp
+ @value = @value.to_s.downcase unless @value.is_a?(Regex)
+ if @value =~ /[^-\w.]/
+ raise Puppet::DevError,
+ "'#{@value}' is not a valid hostname"
+ end
+ end
- def hash
- @value.hash
- end
+ # implementing eql? and hash so that when an HostName is stored
+ # in a hash it has the same hashing properties as the underlying value
+ def eql?(value)
+ value = value.value if value.is_a?(HostName)
+ @value.eql?(value)
+ end
- def to_s
- @value.to_s
- end
+ def hash
+ @value.hash
end
- # A simple variable. This object is only used during interpolation;
- # the VarDef class is used for assignment.
- class Variable < Name
- # Looks up the value of the object in the scope tree (does
- # not include syntactical constructs, like '$' and '{}').
- def evaluate(scope)
- parsewrap do
- if (var = scope.lookupvar(@value, false)) == :undefined
- var = :undef
- end
- var
- end
- end
+ def to_s
+ @value.to_s
+ end
+ end
+
+ # A simple variable. This object is only used during interpolation;
+ # the VarDef class is used for assignment.
+ class Variable < Name
+ # Looks up the value of the object in the scope tree (does
+ # not include syntactical constructs, like '$' and '{}').
+ def evaluate(scope)
+ parsewrap do
+ if (var = scope.lookupvar(@value, false)) == :undefined
+ var = :undef
+ end
+ var
+ end
+ end
- def to_s
- "\$#{value}"
- end
+ def to_s
+ "\$#{value}"
end
+ end
- class HashOrArrayAccess < AST::Leaf
- attr_accessor :variable, :key
+ class HashOrArrayAccess < AST::Leaf
+ attr_accessor :variable, :key
- def evaluate_container(scope)
- container = variable.respond_to?(:evaluate) ? variable.safeevaluate(scope) : variable
- (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope.lookupvar(container)
- end
+ def evaluate_container(scope)
+ container = variable.respond_to?(:evaluate) ? variable.safeevaluate(scope) : variable
+ (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope.lookupvar(container)
+ end
- def evaluate_key(scope)
- key.respond_to?(:evaluate) ? key.safeevaluate(scope) : key
- end
+ def evaluate_key(scope)
+ key.respond_to?(:evaluate) ? key.safeevaluate(scope) : key
+ end
- def evaluate(scope)
- object = evaluate_container(scope)
+ def evaluate(scope)
+ object = evaluate_container(scope)
- raise Puppet::ParseError, "#{variable} is not an hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array)
+ raise Puppet::ParseError, "#{variable} is not an hash or array when accessing it with #{accesskey}" unless object.is_a?(Hash) or object.is_a?(Array)
- object[evaluate_key(scope)]
- end
+ object[evaluate_key(scope)]
+ end
- # Assign value to this hashkey or array index
- def assign(scope, value)
- object = evaluate_container(scope)
- accesskey = evaluate_key(scope)
+ # Assign value to this hashkey or array index
+ def assign(scope, value)
+ object = evaluate_container(scope)
+ accesskey = evaluate_key(scope)
- if object.is_a?(Hash) and object.include?(accesskey)
- raise Puppet::ParseError, "Assigning to the hash '#{variable}' with an existing key '#{accesskey}' is forbidden"
- end
+ if object.is_a?(Hash) and object.include?(accesskey)
+ raise Puppet::ParseError, "Assigning to the hash '#{variable}' with an existing key '#{accesskey}' is forbidden"
+ end
- # assign to hash or array
- object[accesskey] = value
- end
+ # assign to hash or array
+ object[accesskey] = value
+ end
- def to_s
- "\$#{variable.to_s}[#{key.to_s}]"
- end
+ def to_s
+ "\$#{variable.to_s}[#{key.to_s}]"
end
+ end
- class Regex < AST::Leaf
- def initialize(hash)
- super
- @value = Regexp.new(@value) unless @value.is_a?(Regexp)
- end
+ class Regex < AST::Leaf
+ def initialize(hash)
+ super
+ @value = Regexp.new(@value) unless @value.is_a?(Regexp)
+ end
- # we're returning self here to wrap the regexp and to be used in places
- # where a string would have been used, without modifying any client code.
- # For instance, in many places we have the following code snippet:
- # val = @val.safeevaluate(@scope)
- # if val.match(otherval)
- # ...
- # end
- # this way, we don't have to modify this test specifically for handling
- # regexes.
- def evaluate(scope)
- self
- end
+ # we're returning self here to wrap the regexp and to be used in places
+ # where a string would have been used, without modifying any client code.
+ # For instance, in many places we have the following code snippet:
+ # val = @val.safeevaluate(@scope)
+ # if val.match(otherval)
+ # ...
+ # end
+ # this way, we don't have to modify this test specifically for handling
+ # regexes.
+ def evaluate(scope)
+ self
+ end
- def evaluate_match(value, scope, options = {})
- value = value.is_a?(String) ? value : value.to_s
+ def evaluate_match(value, scope, options = {})
+ value = value.is_a?(String) ? value : value.to_s
- if matched = @value.match(value)
- scope.ephemeral_from(matched, options[:file], options[:line])
- end
- matched
- end
+ if matched = @value.match(value)
+ scope.ephemeral_from(matched, options[:file], options[:line])
+ end
+ matched
+ end
- def match(value)
- @value.match(value)
- end
+ def match(value)
+ @value.match(value)
+ end
- def to_s
- "/#{@value.source}/"
- end
+ def to_s
+ "/#{@value.source}/"
end
+ end
end
diff --git a/lib/puppet/parser/ast/match_operator.rb b/lib/puppet/parser/ast/match_operator.rb
index 2ab2befd4..6207a8c2c 100644
--- a/lib/puppet/parser/ast/match_operator.rb
+++ b/lib/puppet/parser/ast/match_operator.rb
@@ -2,27 +2,27 @@ require 'puppet'
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- class MatchOperator < AST::Branch
+ class MatchOperator < AST::Branch
- attr_accessor :lval, :rval, :operator
+ attr_accessor :lval, :rval, :operator
- # Iterate across all of our children.
- def each
- [@lval,@rval].each { |child| yield child }
- end
+ # Iterate across all of our children.
+ def each
+ [@lval,@rval].each { |child| yield child }
+ end
- # Returns a boolean which is the result of the boolean operation
- # of lval and rval operands
- def evaluate(scope)
- lval = @lval.safeevaluate(scope)
+ # Returns a boolean which is the result of the boolean operation
+ # of lval and rval operands
+ def evaluate(scope)
+ lval = @lval.safeevaluate(scope)
- return(rval.evaluate_match(lval, scope) ? @operator == "=~" : @operator == "!~")
- end
+ return(rval.evaluate_match(lval, scope) ? @operator == "=~" : @operator == "!~")
+ end
- def initialize(hash)
- super
+ def initialize(hash)
+ super
- raise ArgumentError, "Invalid regexp operator #{@operator}" unless %w{!~ =~}.include?(@operator)
- end
+ raise ArgumentError, "Invalid regexp operator #{@operator}" unless %w{!~ =~}.include?(@operator)
end
+ end
end
diff --git a/lib/puppet/parser/ast/minus.rb b/lib/puppet/parser/ast/minus.rb
index 40f64336c..d7a362aa1 100644
--- a/lib/puppet/parser/ast/minus.rb
+++ b/lib/puppet/parser/ast/minus.rb
@@ -4,20 +4,20 @@ require 'puppet/parser/ast/branch'
# An object that returns a boolean which is the boolean not
# of the given value.
class Puppet::Parser::AST
- class Minus < AST::Branch
- attr_accessor :value
+ class Minus < AST::Branch
+ attr_accessor :value
- def each
- yield @value
- end
+ def each
+ yield @value
+ end
- def evaluate(scope)
- val = @value.safeevaluate(scope)
- val = Puppet::Parser::Scope.number?(val)
- if val == nil
- raise ArgumentError, "minus operand #{val} is not a number"
- end
- -val
- end
+ def evaluate(scope)
+ val = @value.safeevaluate(scope)
+ val = Puppet::Parser::Scope.number?(val)
+ if val == nil
+ raise ArgumentError, "minus operand #{val} is not a number"
+ end
+ -val
end
+ end
end
diff --git a/lib/puppet/parser/ast/nop.rb b/lib/puppet/parser/ast/nop.rb
index ea5232043..bf35c6a5c 100644
--- a/lib/puppet/parser/ast/nop.rb
+++ b/lib/puppet/parser/ast/nop.rb
@@ -1,11 +1,11 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # This class is a no-op, it doesn't produce anything
- # when evaluated, hence it's name :-)
- class Nop < AST::Leaf
- def evaluate(scope)
- # nothing to do
- end
+ # This class is a no-op, it doesn't produce anything
+ # when evaluated, hence it's name :-)
+ class Nop < AST::Leaf
+ def evaluate(scope)
+ # nothing to do
end
+ end
end
diff --git a/lib/puppet/parser/ast/not.rb b/lib/puppet/parser/ast/not.rb
index 24d5e838b..30fa6d503 100644
--- a/lib/puppet/parser/ast/not.rb
+++ b/lib/puppet/parser/ast/not.rb
@@ -4,16 +4,16 @@ require 'puppet/parser/ast/branch'
# An object that returns a boolean which is the boolean not
# of the given value.
class Puppet::Parser::AST
- class Not < AST::Branch
- attr_accessor :value
+ class Not < AST::Branch
+ attr_accessor :value
- def each
- yield @value
- end
+ def each
+ yield @value
+ end
- def evaluate(scope)
- val = @value.safeevaluate(scope)
- ! Puppet::Parser::Scope.true?(val)
- end
+ def evaluate(scope)
+ val = @value.safeevaluate(scope)
+ ! Puppet::Parser::Scope.true?(val)
end
+ end
end
diff --git a/lib/puppet/parser/ast/relationship.rb b/lib/puppet/parser/ast/relationship.rb
index 9f9f6fc1d..a7134a04f 100644
--- a/lib/puppet/parser/ast/relationship.rb
+++ b/lib/puppet/parser/ast/relationship.rb
@@ -3,58 +3,58 @@ require 'puppet/parser/ast/branch'
require 'puppet/parser/relationship'
class Puppet::Parser::AST::Relationship < Puppet::Parser::AST::Branch
- RELATIONSHIP_TYPES = %w{-> <- ~> <~}
+ RELATIONSHIP_TYPES = %w{-> <- ~> <~}
- attr_accessor :left, :right, :arrow, :type
+ attr_accessor :left, :right, :arrow, :type
- def actual_left
- chained? ? left.right : left
- end
+ def actual_left
+ chained? ? left.right : left
+ end
- # Evaluate our object, but just return a simple array of the type
- # and name.
- def evaluate(scope)
- if chained?
- real_left = left.safeevaluate(scope)
- left_dep = left_dep.shift if left_dep.is_a?(Array)
- else
- real_left = left.safeevaluate(scope)
- end
- real_right = right.safeevaluate(scope)
-
- source, target = sides2edge(real_left, real_right)
- result = Puppet::Parser::Relationship.new(source, target, type)
- scope.compiler.add_relationship(result)
- real_right
+ # Evaluate our object, but just return a simple array of the type
+ # and name.
+ def evaluate(scope)
+ if chained?
+ real_left = left.safeevaluate(scope)
+ left_dep = left_dep.shift if left_dep.is_a?(Array)
+ else
+ real_left = left.safeevaluate(scope)
end
+ real_right = right.safeevaluate(scope)
- def initialize(left, right, arrow, args = {})
- super(args)
- unless RELATIONSHIP_TYPES.include?(arrow)
- raise ArgumentError, "Invalid relationship type #{arrow.inspect}; valid types are #{RELATIONSHIP_TYPES.collect { |r| r.to_s }.join(", ")}"
- end
- @left, @right, @arrow = left, right, arrow
- end
+ source, target = sides2edge(real_left, real_right)
+ result = Puppet::Parser::Relationship.new(source, target, type)
+ scope.compiler.add_relationship(result)
+ real_right
+ end
- def type
- subscription? ? :subscription : :relationship
+ def initialize(left, right, arrow, args = {})
+ super(args)
+ unless RELATIONSHIP_TYPES.include?(arrow)
+ raise ArgumentError, "Invalid relationship type #{arrow.inspect}; valid types are #{RELATIONSHIP_TYPES.collect { |r| r.to_s }.join(", ")}"
end
+ @left, @right, @arrow = left, right, arrow
+ end
- def sides2edge(left, right)
- out_edge? ? [left, right] : [right, left]
- end
+ def type
+ subscription? ? :subscription : :relationship
+ end
- private
+ def sides2edge(left, right)
+ out_edge? ? [left, right] : [right, left]
+ end
- def chained?
- left.is_a?(self.class)
- end
+ private
- def out_edge?
- ["->", "~>"].include?(arrow)
- end
+ def chained?
+ left.is_a?(self.class)
+ end
- def subscription?
- ["~>", "<~"].include?(arrow)
- end
+ def out_edge?
+ ["->", "~>"].include?(arrow)
+ end
+
+ def subscription?
+ ["~>", "<~"].include?(arrow)
+ end
end
diff --git a/lib/puppet/parser/ast/resource.rb b/lib/puppet/parser/ast/resource.rb
index 01b9370ff..1b063c984 100644
--- a/lib/puppet/parser/ast/resource.rb
+++ b/lib/puppet/parser/ast/resource.rb
@@ -5,73 +5,73 @@ require 'puppet/parser/ast/resource_reference'
class Puppet::Parser::AST
class Resource < AST::ResourceReference
- associates_doc
+ associates_doc
- attr_accessor :title, :type, :exported, :virtual
- attr_reader :parameters
+ attr_accessor :title, :type, :exported, :virtual
+ attr_reader :parameters
- # Does not actually return an object; instead sets an object
- # in the current scope.
- def evaluate(scope)
- # Evaluate all of the specified params.
- paramobjects = parameters.collect { |param|
- param.safeevaluate(scope)
- }
+ # Does not actually return an object; instead sets an object
+ # in the current scope.
+ def evaluate(scope)
+ # Evaluate all of the specified params.
+ paramobjects = parameters.collect { |param|
+ param.safeevaluate(scope)
+ }
- resource_titles = @title.safeevaluate(scope)
+ resource_titles = @title.safeevaluate(scope)
- # it's easier to always use an array, even for only one name
- resource_titles = [resource_titles] unless resource_titles.is_a?(Array)
+ # it's easier to always use an array, even for only one name
+ resource_titles = [resource_titles] unless resource_titles.is_a?(Array)
- # We want virtual to be true if exported is true. We can't
- # just set :virtual => self.virtual in the initialization,
- # because sometimes the :virtual attribute is set *after*
- # :exported, in which case it clobbers :exported if :exported
- # is true. Argh, this was a very tough one to track down.
- virt = self.virtual || self.exported
+ # We want virtual to be true if exported is true. We can't
+ # just set :virtual => self.virtual in the initialization,
+ # because sometimes the :virtual attribute is set *after*
+ # :exported, in which case it clobbers :exported if :exported
+ # is true. Argh, this was a very tough one to track down.
+ virt = self.virtual || self.exported
- # This is where our implicit iteration takes place; if someone
- # passed an array as the name, then we act just like the called us
- # many times.
- resource_titles.flatten.collect { |resource_title|
- exceptwrap :type => Puppet::ParseError do
+ # This is where our implicit iteration takes place; if someone
+ # passed an array as the name, then we act just like the called us
+ # many times.
+ resource_titles.flatten.collect { |resource_title|
+ exceptwrap :type => Puppet::ParseError do
- resource = Puppet::Parser::Resource.new(
- type, resource_title,
- :parameters => paramobjects,
- :file => self.file,
- :line => self.line,
- :exported => self.exported,
- :virtual => virt,
- :source => scope.source,
- :scope => scope,
+ resource = Puppet::Parser::Resource.new(
+ type, resource_title,
+ :parameters => paramobjects,
+ :file => self.file,
+ :line => self.line,
+ :exported => self.exported,
+ :virtual => virt,
+ :source => scope.source,
+ :scope => scope,
- :strict => true
- )
+ :strict => true
+ )
- # And then store the resource in the compiler.
- # At some point, we need to switch all of this to return
- # resources instead of storing them like this.
- scope.compiler.add_resource(scope, resource)
- resource
- end
- }.reject { |resource| resource.nil? }
- end
+ # And then store the resource in the compiler.
+ # At some point, we need to switch all of this to return
+ # resources instead of storing them like this.
+ scope.compiler.add_resource(scope, resource)
+ resource
+ end
+ }.reject { |resource| resource.nil? }
+ end
- # Set the parameters for our object.
- def parameters=(params)
- if params.is_a?(AST::ASTArray)
- @parameters = params
- else
+ # Set the parameters for our object.
+ def parameters=(params)
+ if params.is_a?(AST::ASTArray)
+ @parameters = params
+ else
- @parameters = AST::ASTArray.new(
+ @parameters = AST::ASTArray.new(
- :line => params.line,
- :file => params.file,
+ :line => params.line,
+ :file => params.file,
- :children => [params]
- )
- end
+ :children => [params]
+ )
end
+ end
end
end
diff --git a/lib/puppet/parser/ast/resource_defaults.rb b/lib/puppet/parser/ast/resource_defaults.rb
index aec86d02d..812b979e9 100644
--- a/lib/puppet/parser/ast/resource_defaults.rb
+++ b/lib/puppet/parser/ast/resource_defaults.rb
@@ -1,24 +1,24 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # A statement syntactically similar to an ResourceDef, but uses a
- # capitalized object type and cannot have a name.
- class ResourceDefaults < AST::Branch
- attr_accessor :type, :parameters
+ # A statement syntactically similar to an ResourceDef, but uses a
+ # capitalized object type and cannot have a name.
+ class ResourceDefaults < AST::Branch
+ attr_accessor :type, :parameters
- associates_doc
+ associates_doc
- # As opposed to ResourceDef, this stores each default for the given
- # object type.
- def evaluate(scope)
- # Use a resource reference to canonize the type
- ref = Puppet::Resource.new(@type, "whatever")
- type = ref.type
- params = @parameters.safeevaluate(scope)
+ # As opposed to ResourceDef, this stores each default for the given
+ # object type.
+ def evaluate(scope)
+ # Use a resource reference to canonize the type
+ ref = Puppet::Resource.new(@type, "whatever")
+ type = ref.type
+ params = @parameters.safeevaluate(scope)
- parsewrap do
- scope.setdefaults(type, params)
- end
- end
+ parsewrap do
+ scope.setdefaults(type, params)
+ end
end
+ end
end
diff --git a/lib/puppet/parser/ast/resource_override.rb b/lib/puppet/parser/ast/resource_override.rb
index 7f7047dd9..e0be889ff 100644
--- a/lib/puppet/parser/ast/resource_override.rb
+++ b/lib/puppet/parser/ast/resource_override.rb
@@ -1,68 +1,68 @@
require 'puppet/parser/ast/resource'
class Puppet::Parser::AST
- # Set a parameter on a resource specification created somewhere else in the
- # configuration. The object is responsible for verifying that this is allowed.
- class ResourceOverride < Resource
+ # Set a parameter on a resource specification created somewhere else in the
+ # configuration. The object is responsible for verifying that this is allowed.
+ class ResourceOverride < Resource
- associates_doc
+ associates_doc
- attr_accessor :object
- attr_reader :parameters
+ attr_accessor :object
+ attr_reader :parameters
- # Iterate across all of our children.
- def each
- [@object,@parameters].flatten.each { |param|
- #Puppet.debug("yielding param #{param}")
- yield param
- }
- end
+ # Iterate across all of our children.
+ def each
+ [@object,@parameters].flatten.each { |param|
+ #Puppet.debug("yielding param #{param}")
+ yield param
+ }
+ end
- # Does not actually return an object; instead sets an object
- # in the current scope.
- def evaluate(scope)
- # Get our object reference.
- resource = @object.safeevaluate(scope)
+ # Does not actually return an object; instead sets an object
+ # in the current scope.
+ def evaluate(scope)
+ # Get our object reference.
+ resource = @object.safeevaluate(scope)
- hash = {}
+ hash = {}
- # Evaluate all of the specified params.
- params = @parameters.collect { |param|
- param.safeevaluate(scope)
- }
+ # Evaluate all of the specified params.
+ params = @parameters.collect { |param|
+ param.safeevaluate(scope)
+ }
- # Now we just create a normal resource, but we call a very different
- # method on the scope.
- resource = [resource] unless resource.is_a?(Array)
+ # Now we just create a normal resource, but we call a very different
+ # method on the scope.
+ resource = [resource] unless resource.is_a?(Array)
- resource = resource.collect do |r|
+ resource = resource.collect do |r|
- res = Puppet::Parser::Resource.new(
- r.type, r.title,
- :parameters => params,
- :file => file,
- :line => line,
- :source => scope.source,
+ res = Puppet::Parser::Resource.new(
+ r.type, r.title,
+ :parameters => params,
+ :file => file,
+ :line => line,
+ :source => scope.source,
- :scope => scope
- )
+ :scope => scope
+ )
- # Now we tell the scope that it's an override, and it behaves as
- # necessary.
- scope.compiler.add_override(res)
+ # Now we tell the scope that it's an override, and it behaves as
+ # necessary.
+ scope.compiler.add_override(res)
- res
- end
- # decapsulate array in case of only one item
- return(resource.length == 1 ? resource.pop : resource)
- end
+ res
+ end
+ # decapsulate array in case of only one item
+ return(resource.length == 1 ? resource.pop : resource)
+ end
- # Create our ResourceDef. Handles type checking for us.
- def initialize(hash)
- @checked = false
- super
+ # Create our ResourceDef. Handles type checking for us.
+ def initialize(hash)
+ @checked = false
+ super
- #self.typecheck(@type.value)
- end
+ #self.typecheck(@type.value)
end
+ end
end
diff --git a/lib/puppet/parser/ast/resource_reference.rb b/lib/puppet/parser/ast/resource_reference.rb
index 37e82d568..5d8334335 100644
--- a/lib/puppet/parser/ast/resource_reference.rb
+++ b/lib/puppet/parser/ast/resource_reference.rb
@@ -2,20 +2,20 @@ require 'puppet/parser/ast'
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST::ResourceReference < Puppet::Parser::AST::Branch
- attr_accessor :title, :type
+ attr_accessor :title, :type
- # Evaluate our object, but just return a simple array of the type
- # and name.
- def evaluate(scope)
- titles = Array(title.safeevaluate(scope)).collect { |t| Puppet::Resource.new(type, t, :namespaces => scope.namespaces) }
- return(titles.length == 1 ? titles.pop : titles)
- end
+ # Evaluate our object, but just return a simple array of the type
+ # and name.
+ def evaluate(scope)
+ titles = Array(title.safeevaluate(scope)).collect { |t| Puppet::Resource.new(type, t, :namespaces => scope.namespaces) }
+ return(titles.length == 1 ? titles.pop : titles)
+ end
- def to_s
- if title.is_a?(Puppet::Parser::AST::ASTArray)
- "#{type.to_s.capitalize}#{title}"
- else
- "#{type.to_s.capitalize}[#{title}]"
- end
+ def to_s
+ if title.is_a?(Puppet::Parser::AST::ASTArray)
+ "#{type.to_s.capitalize}#{title}"
+ else
+ "#{type.to_s.capitalize}[#{title}]"
end
+ end
end
diff --git a/lib/puppet/parser/ast/resourceparam.rb b/lib/puppet/parser/ast/resourceparam.rb
index bf0a2258b..4073a197b 100644
--- a/lib/puppet/parser/ast/resourceparam.rb
+++ b/lib/puppet/parser/ast/resourceparam.rb
@@ -1,29 +1,29 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # The AST object for the parameters inside ResourceDefs and Selectors.
- class ResourceParam < AST::Branch
- attr_accessor :value, :param, :add
+ # The AST object for the parameters inside ResourceDefs and Selectors.
+ class ResourceParam < AST::Branch
+ attr_accessor :value, :param, :add
- def each
- [@param,@value].each { |child| yield child }
- end
+ def each
+ [@param,@value].each { |child| yield child }
+ end
- # Return the parameter and the value.
- def evaluate(scope)
+ # Return the parameter and the value.
+ def evaluate(scope)
- return Puppet::Parser::Resource::Param.new(
+ return Puppet::Parser::Resource::Param.new(
- :name => @param,
- :value => @value.safeevaluate(scope),
+ :name => @param,
+ :value => @value.safeevaluate(scope),
- :source => scope.source, :line => self.line, :file => self.file,
- :add => self.add
- )
- end
+ :source => scope.source, :line => self.line, :file => self.file,
+ :add => self.add
+ )
+ end
- def to_s
- "#{@param} => #{@value.to_s}"
- end
+ def to_s
+ "#{@param} => #{@value.to_s}"
end
+ end
end
diff --git a/lib/puppet/parser/ast/selector.rb b/lib/puppet/parser/ast/selector.rb
index cf6b8ac19..d6a4ea436 100644
--- a/lib/puppet/parser/ast/selector.rb
+++ b/lib/puppet/parser/ast/selector.rb
@@ -1,44 +1,44 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # The inline conditional operator. Unlike CaseStatement, which executes
- # code, we just return a value.
- class Selector < AST::Branch
- attr_accessor :param, :values
+ # The inline conditional operator. Unlike CaseStatement, which executes
+ # code, we just return a value.
+ class Selector < AST::Branch
+ attr_accessor :param, :values
- def each
- [@param,@values].each { |child| yield child }
- end
+ def each
+ [@param,@values].each { |child| yield child }
+ end
- # Find the value that corresponds with the test.
- def evaluate(scope)
- level = scope.ephemeral_level
- # Get our parameter.
- paramvalue = @param.safeevaluate(scope)
+ # Find the value that corresponds with the test.
+ def evaluate(scope)
+ level = scope.ephemeral_level
+ # Get our parameter.
+ paramvalue = @param.safeevaluate(scope)
- default = nil
+ default = nil
- @values = [@values] unless @values.instance_of? AST::ASTArray or @values.instance_of? Array
+ @values = [@values] unless @values.instance_of? AST::ASTArray or @values.instance_of? Array
- # Then look for a match in the options.
- @values.each do |obj|
- # short circuit asap if we have a match
- return obj.value.safeevaluate(scope) if obj.param.evaluate_match(paramvalue, scope)
+ # Then look for a match in the options.
+ @values.each do |obj|
+ # short circuit asap if we have a match
+ return obj.value.safeevaluate(scope) if obj.param.evaluate_match(paramvalue, scope)
- # Store the default, in case it's necessary.
- default = obj if obj.param.is_a?(Default)
- end
+ # Store the default, in case it's necessary.
+ default = obj if obj.param.is_a?(Default)
+ end
- # Unless we found something, look for the default.
- return default.value.safeevaluate(scope) if default
+ # Unless we found something, look for the default.
+ return default.value.safeevaluate(scope) if default
- self.fail Puppet::ParseError, "No matching value for selector param '#{paramvalue}'"
- ensure
- scope.unset_ephemeral_var(level)
- end
+ self.fail Puppet::ParseError, "No matching value for selector param '#{paramvalue}'"
+ ensure
+ scope.unset_ephemeral_var(level)
+ end
- def to_s
- param.to_s + " ? { " + values.collect { |v| v.to_s }.join(', ') + " }"
- end
+ def to_s
+ param.to_s + " ? { " + values.collect { |v| v.to_s }.join(', ') + " }"
end
+ end
end
diff --git a/lib/puppet/parser/ast/tag.rb b/lib/puppet/parser/ast/tag.rb
index 2909504a7..6f906a1c6 100644
--- a/lib/puppet/parser/ast/tag.rb
+++ b/lib/puppet/parser/ast/tag.rb
@@ -1,24 +1,24 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # The code associated with a class. This is different from components
- # in that each class is a singleton -- only one will exist for a given
- # node.
- class Tag < AST::Branch
- @name = :class
- attr_accessor :type
+ # The code associated with a class. This is different from components
+ # in that each class is a singleton -- only one will exist for a given
+ # node.
+ class Tag < AST::Branch
+ @name = :class
+ attr_accessor :type
- def evaluate(scope)
- types = @type.safeevaluate(scope)
+ def evaluate(scope)
+ types = @type.safeevaluate(scope)
- types = [types] unless types.is_a? Array
+ types = [types] unless types.is_a? Array
- types.each do |type|
- # Now set our class. We don't have to worry about checking
- # whether we've been evaluated because we're not evaluating
- # any code.
- scope.setclass(self.object_id, type)
- end
- end
+ types.each do |type|
+ # Now set our class. We don't have to worry about checking
+ # whether we've been evaluated because we're not evaluating
+ # any code.
+ scope.setclass(self.object_id, type)
+ end
end
+ end
end
diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb
index f103d49c3..6de1860c8 100644
--- a/lib/puppet/parser/ast/vardef.rb
+++ b/lib/puppet/parser/ast/vardef.rb
@@ -1,33 +1,33 @@
require 'puppet/parser/ast/branch'
class Puppet::Parser::AST
- # Define a variable. Stores the value in the current scope.
- class VarDef < AST::Branch
+ # Define a variable. Stores the value in the current scope.
+ class VarDef < AST::Branch
- associates_doc
+ associates_doc
- attr_accessor :name, :value, :append
+ attr_accessor :name, :value, :append
- @settor = true
+ @settor = true
- # Look up our name and value, and store them appropriately. The
- # lexer strips off the syntax stuff like '$'.
- def evaluate(scope)
- value = @value.safeevaluate(scope)
- if name.is_a?(HashOrArrayAccess)
- name.assign(scope, value)
- else
- name = @name.safeevaluate(scope)
+ # Look up our name and value, and store them appropriately. The
+ # lexer strips off the syntax stuff like '$'.
+ def evaluate(scope)
+ value = @value.safeevaluate(scope)
+ if name.is_a?(HashOrArrayAccess)
+ name.assign(scope, value)
+ else
+ name = @name.safeevaluate(scope)
- parsewrap do
- scope.setvar(name,value, :file => @file, :line => @line, :append => @append)
- end
- end
+ parsewrap do
+ scope.setvar(name,value, :file => @file, :line => @line, :append => @append)
end
+ end
+ end
- def each
- [@name,@value].each { |child| yield child }
- end
+ def each
+ [@name,@value].each { |child| yield child }
end
+ end
end
diff --git a/lib/puppet/parser/collector.rb b/lib/puppet/parser/collector.rb
index c03add304..de60cb170 100644
--- a/lib/puppet/parser/collector.rb
+++ b/lib/puppet/parser/collector.rb
@@ -1,223 +1,223 @@
# An object that collects stored objects from the central cache and returns
# them to the current host, yo.
class Puppet::Parser::Collector
- attr_accessor :type, :scope, :vquery, :equery, :form, :resources, :overrides, :collected
-
- # Call the collection method, mark all of the returned objects as non-virtual,
- # optionally applying parameter overrides. The collector can also delete himself
- # from the compiler if there is no more resources to collect (valid only for resource fixed-set collector
- # which get their resources from +collect_resources+ and not from the catalog)
- def evaluate
- # Shortcut if we're not using storeconfigs and they're trying to collect
- # exported resources.
- if form == :exported and Puppet[:storeconfigs] != true
- Puppet.warning "Not collecting exported resources without storeconfigs"
- return false
- end
+ attr_accessor :type, :scope, :vquery, :equery, :form, :resources, :overrides, :collected
+
+ # Call the collection method, mark all of the returned objects as non-virtual,
+ # optionally applying parameter overrides. The collector can also delete himself
+ # from the compiler if there is no more resources to collect (valid only for resource fixed-set collector
+ # which get their resources from +collect_resources+ and not from the catalog)
+ def evaluate
+ # Shortcut if we're not using storeconfigs and they're trying to collect
+ # exported resources.
+ if form == :exported and Puppet[:storeconfigs] != true
+ Puppet.warning "Not collecting exported resources without storeconfigs"
+ return false
+ end
- if self.resources
- unless objects = collect_resources and ! objects.empty?
- return false
- end
- else
- method = "collect_#{@form.to_s}"
- objects = send(method).each do |obj|
- obj.virtual = false
- end
- return false if objects.empty?
- end
+ if self.resources
+ unless objects = collect_resources and ! objects.empty?
+ return false
+ end
+ else
+ method = "collect_#{@form.to_s}"
+ objects = send(method).each do |obj|
+ obj.virtual = false
+ end
+ return false if objects.empty?
+ end
- # we have an override for the collected resources
- if @overrides and !objects.empty?
-
- # force the resource to be always child of any other resource
- overrides[:source].meta_def(:child_of?) do
- true
- end
-
- # tell the compiler we have some override for him unless we already
- # overrided those resources
- objects.each do |res|
- unless @collected.include?(res.ref)
-
- newres = Puppet::Parser::Resource.new(
- res.type, res.title,
- :parameters => overrides[:parameters],
- :file => overrides[:file],
- :line => overrides[:line],
- :source => overrides[:source],
+ # we have an override for the collected resources
+ if @overrides and !objects.empty?
+
+ # force the resource to be always child of any other resource
+ overrides[:source].meta_def(:child_of?) do
+ true
+ end
+
+ # tell the compiler we have some override for him unless we already
+ # overrided those resources
+ objects.each do |res|
+ unless @collected.include?(res.ref)
+
+ newres = Puppet::Parser::Resource.new(
+ res.type, res.title,
+ :parameters => overrides[:parameters],
+ :file => overrides[:file],
+ :line => overrides[:line],
+ :source => overrides[:source],
- :scope => overrides[:scope]
- )
+ :scope => overrides[:scope]
+ )
- scope.compiler.add_override(newres)
- end
- end
+ scope.compiler.add_override(newres)
end
+ end
+ end
- # filter out object that already have been collected by ourself
- objects.reject! { |o| @collected.include?(o.ref) }
+ # filter out object that already have been collected by ourself
+ objects.reject! { |o| @collected.include?(o.ref) }
- return false if objects.empty?
+ return false if objects.empty?
- # keep an eye on the resources we have collected
- objects.inject(@collected) { |c,o| c[o.ref]=o; c }
+ # keep an eye on the resources we have collected
+ objects.inject(@collected) { |c,o| c[o.ref]=o; c }
- # return our newly collected resources
- objects
- end
+ # return our newly collected resources
+ objects
+ end
- def initialize(scope, type, equery, vquery, form)
- @scope = scope
+ def initialize(scope, type, equery, vquery, form)
+ @scope = scope
- # initialisation
- @collected = {}
+ # initialisation
+ @collected = {}
- # Canonize the type
- @type = Puppet::Resource.new(type, "whatever").type
- @equery = equery
- @vquery = vquery
+ # Canonize the type
+ @type = Puppet::Resource.new(type, "whatever").type
+ @equery = equery
+ @vquery = vquery
- raise(ArgumentError, "Invalid query form #{form}") unless [:exported, :virtual].include?(form)
- @form = form
- end
+ raise(ArgumentError, "Invalid query form #{form}") unless [:exported, :virtual].include?(form)
+ @form = form
+ end
- # add a resource override to the soon to be exported/realized resources
- def add_override(hash)
- raise ArgumentError, "Exported resource try to override without parameters" unless hash[:parameters]
+ # add a resource override to the soon to be exported/realized resources
+ def add_override(hash)
+ raise ArgumentError, "Exported resource try to override without parameters" unless hash[:parameters]
- # schedule an override for an upcoming collection
- @overrides = hash
- end
-
- private
-
- # Create our active record query.
- def build_active_record_query
- Puppet::Rails.init unless ActiveRecord::Base.connected?
-
- raise Puppet::DevError, "Cannot collect resources for a nil host" unless @scope.host
- host = Puppet::Rails::Host.find_by_name(@scope.host)
-
- search = "(exported=? AND restype=?)"
- values = [true, @type]
-
- search += " AND (#{@equery})" if @equery
-
- # note:
- # we're not eagerly including any relations here because
- # it can creates so much objects we'll throw out later.
- # We used to eagerly include param_names/values but the way
- # the search filter is built ruined those efforts and we
- # were eagerly loading only the searched parameter and not
- # the other ones.
- query = {}
- case search
- when /puppet_tags/
- query = {:joins => {:resource_tags => :puppet_tag}}
- when /param_name/
- query = {:joins => {:param_values => :param_name}}
- end
+ # schedule an override for an upcoming collection
+ @overrides = hash
+ end
- # We're going to collect objects from rails, but we don't want any
- # objects from this host.
- search = ("host_id != ? AND #{search}") and values.unshift(host.id) if host
+ private
- query[:conditions] = [search, *values]
+ # Create our active record query.
+ def build_active_record_query
+ Puppet::Rails.init unless ActiveRecord::Base.connected?
- query
- end
+ raise Puppet::DevError, "Cannot collect resources for a nil host" unless @scope.host
+ host = Puppet::Rails::Host.find_by_name(@scope.host)
- # Collect exported objects.
- def collect_exported
- # First get everything from the export table. Just reuse our
- # collect_virtual method but tell it to use 'exported? for the test.
- resources = collect_virtual(true).reject { |r| ! r.virtual? }
-
- count = resources.length
-
- query = build_active_record_query
-
- # Now look them up in the rails db. When we support attribute comparison
- # and such, we'll need to vary the conditions, but this works with no
- # attributes, anyway.
- time = Puppet::Util.thinmark do
- Puppet::Rails::Resource.find(:all, query).each do |obj|
- if resource = exported_resource(obj)
- count += 1
- resources << resource
- end
- end
- end
+ search = "(exported=? AND restype=?)"
+ values = [true, @type]
- scope.debug("Collected %s %s resource%s in %.2f seconds" % [count, @type, count == 1 ? "" : "s", time])
+ search += " AND (#{@equery})" if @equery
- resources
+ # note:
+ # we're not eagerly including any relations here because
+ # it can creates so much objects we'll throw out later.
+ # We used to eagerly include param_names/values but the way
+ # the search filter is built ruined those efforts and we
+ # were eagerly loading only the searched parameter and not
+ # the other ones.
+ query = {}
+ case search
+ when /puppet_tags/
+ query = {:joins => {:resource_tags => :puppet_tag}}
+ when /param_name/
+ query = {:joins => {:param_values => :param_name}}
end
- def collect_resources
- @resources = [@resources] unless @resources.is_a?(Array)
- method = "collect_#{form.to_s}_resources"
- send(method)
- end
+ # We're going to collect objects from rails, but we don't want any
+ # objects from this host.
+ search = ("host_id != ? AND #{search}") and values.unshift(host.id) if host
- def collect_exported_resources
- raise Puppet::ParseError, "realize() is not yet implemented for exported resources"
- end
+ query[:conditions] = [search, *values]
- # Collect resources directly; this is the result of using 'realize',
- # which specifies resources, rather than using a normal collection.
- def collect_virtual_resources
- return [] unless defined?(@resources) and ! @resources.empty?
- result = @resources.dup.collect do |ref|
- if res = @scope.findresource(ref.to_s)
- @resources.delete(ref)
- res
- end
- end.reject { |r| r.nil? }.each do |res|
- res.virtual = false
- end
+ query
+ end
- # If there are no more resources to find, delete this from the list
- # of collections.
- @scope.compiler.delete_collection(self) if @resources.empty?
+ # Collect exported objects.
+ def collect_exported
+ # First get everything from the export table. Just reuse our
+ # collect_virtual method but tell it to use 'exported? for the test.
+ resources = collect_virtual(true).reject { |r| ! r.virtual? }
- result
- end
+ count = resources.length
- # Collect just virtual objects, from our local compiler.
- def collect_virtual(exported = false)
- scope.compiler.resources.find_all do |resource|
- resource.type == @type and (exported ? resource.exported? : true) and match?(resource)
+ query = build_active_record_query
+
+ # Now look them up in the rails db. When we support attribute comparison
+ # and such, we'll need to vary the conditions, but this works with no
+ # attributes, anyway.
+ time = Puppet::Util.thinmark do
+ Puppet::Rails::Resource.find(:all, query).each do |obj|
+ if resource = exported_resource(obj)
+ count += 1
+ resources << resource
end
+ end
end
- # Seek a specific exported resource.
- def exported_resource(obj)
- if existing = @scope.findresource(obj.restype, obj.title)
- # Next see if we've already collected this resource
- return nil if existing.rails_id == obj.id
+ scope.debug("Collected %s %s resource%s in %.2f seconds" % [count, @type, count == 1 ? "" : "s", time])
+
+ resources
+ end
+
+ def collect_resources
+ @resources = [@resources] unless @resources.is_a?(Array)
+ method = "collect_#{form.to_s}_resources"
+ send(method)
+ end
+
+ def collect_exported_resources
+ raise Puppet::ParseError, "realize() is not yet implemented for exported resources"
+ end
+
+ # Collect resources directly; this is the result of using 'realize',
+ # which specifies resources, rather than using a normal collection.
+ def collect_virtual_resources
+ return [] unless defined?(@resources) and ! @resources.empty?
+ result = @resources.dup.collect do |ref|
+ if res = @scope.findresource(ref.to_s)
+ @resources.delete(ref)
+ res
+ end
+ end.reject { |r| r.nil? }.each do |res|
+ res.virtual = false
+ end
- # This is the one we've already collected
- raise Puppet::ParseError, "Exported resource #{obj.ref} cannot override local resource"
- end
+ # If there are no more resources to find, delete this from the list
+ # of collections.
+ @scope.compiler.delete_collection(self) if @resources.empty?
- resource = obj.to_resource(self.scope)
+ result
+ end
- resource.exported = false
+ # Collect just virtual objects, from our local compiler.
+ def collect_virtual(exported = false)
+ scope.compiler.resources.find_all do |resource|
+ resource.type == @type and (exported ? resource.exported? : true) and match?(resource)
+ end
+ end
- scope.compiler.add_resource(scope, resource)
+ # Seek a specific exported resource.
+ def exported_resource(obj)
+ if existing = @scope.findresource(obj.restype, obj.title)
+ # Next see if we've already collected this resource
+ return nil if existing.rails_id == obj.id
- resource
+ # This is the one we've already collected
+ raise Puppet::ParseError, "Exported resource #{obj.ref} cannot override local resource"
end
- # Does the resource match our tests? We don't yet support tests,
- # so it's always true at the moment.
- def match?(resource)
- if self.vquery
- return self.vquery.call(resource)
- else
- return true
- end
+ resource = obj.to_resource(self.scope)
+
+ resource.exported = false
+
+ scope.compiler.add_resource(scope, resource)
+
+ resource
+ end
+
+ # Does the resource match our tests? We don't yet support tests,
+ # so it's always true at the moment.
+ def match?(resource)
+ if self.vquery
+ return self.vquery.call(resource)
+ else
+ return true
end
+ end
end
diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb
index 17b05baab..85980722c 100644
--- a/lib/puppet/parser/compiler.rb
+++ b/lib/puppet/parser/compiler.rb
@@ -10,484 +10,484 @@ require 'puppet/resource/type_collection_helper'
# Maintain a graph of scopes, along with a bunch of data
# about the individual catalog we're compiling.
class Puppet::Parser::Compiler
- include Puppet::Util
- include Puppet::Util::Errors
- include Puppet::Resource::TypeCollectionHelper
-
- def self.compile(node)
- new(node).compile.to_resource
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "#{detail} on node #{node.name}"
- end
-
- attr_reader :node, :facts, :collections, :catalog, :node_scope, :resources, :relationships
+ include Puppet::Util
+ include Puppet::Util::Errors
+ include Puppet::Resource::TypeCollectionHelper
- # Add a collection to the global list.
- def add_collection(coll)
- @collections << coll
- end
-
- def add_relationship(dep)
- @relationships << dep
- end
+ def self.compile(node)
+ new(node).compile.to_resource
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "#{detail} on node #{node.name}"
+ end
- # Store a resource override.
- def add_override(override)
- # If possible, merge the override in immediately.
- if resource = @catalog.resource(override.ref)
- resource.merge(override)
- else
- # Otherwise, store the override for later; these
- # get evaluated in Resource#finish.
- @resource_overrides[override.ref] << override
- end
- end
+ attr_reader :node, :facts, :collections, :catalog, :node_scope, :resources, :relationships
- # Store a resource in our resource table.
- def add_resource(scope, resource)
- @resources << resource
+ # Add a collection to the global list.
+ def add_collection(coll)
+ @collections << coll
+ end
- # Note that this will fail if the resource is not unique.
- @catalog.add_resource(resource)
+ def add_relationship(dep)
+ @relationships << dep
+ end
- set_container_resource(scope, resource)
+ # Store a resource override.
+ def add_override(override)
+ # If possible, merge the override in immediately.
+ if resource = @catalog.resource(override.ref)
+ resource.merge(override)
+ else
+ # Otherwise, store the override for later; these
+ # get evaluated in Resource#finish.
+ @resource_overrides[override.ref] << override
end
+ end
- # Add our container edge. If we're a class, then we get treated specially - we can
- # control the stage that the class is applied in. Otherwise, we just
- # get added to our parent container.
- def set_container_resource(scope, resource)
- return if resource.type.to_s.downcase == "stage"
-
- if resource.type.to_s.downcase != "class"
- raise ArgumentError, "Only classes can set 'stage'; normal resources like #{resource} cannot change run stage" if resource[:stage]
- return @catalog.add_edge(scope.resource, resource)
- end
-
- unless stage = @catalog.resource(:stage, resource[:stage] || :main)
- raise ArgumentError, "Could not find stage #{resource[:stage] || :main} specified by #{resource}"
- end
+ # Store a resource in our resource table.
+ def add_resource(scope, resource)
+ @resources << resource
- @catalog.add_edge(stage, resource)
- end
+ # Note that this will fail if the resource is not unique.
+ @catalog.add_resource(resource)
- private :set_container_resource
+ set_container_resource(scope, resource)
+ end
- # Do we use nodes found in the code, vs. the external node sources?
- def ast_nodes?
- known_resource_types.nodes?
- end
+ # Add our container edge. If we're a class, then we get treated specially - we can
+ # control the stage that the class is applied in. Otherwise, we just
+ # get added to our parent container.
+ def set_container_resource(scope, resource)
+ return if resource.type.to_s.downcase == "stage"
- # Store the fact that we've evaluated a class
- def add_class(name)
- @catalog.add_class(name) unless name == ""
+ if resource.type.to_s.downcase != "class"
+ raise ArgumentError, "Only classes can set 'stage'; normal resources like #{resource} cannot change run stage" if resource[:stage]
+ return @catalog.add_edge(scope.resource, resource)
end
-
- # Return a list of all of the defined classes.
- def classlist
- @catalog.classes
+ unless stage = @catalog.resource(:stage, resource[:stage] || :main)
+ raise ArgumentError, "Could not find stage #{resource[:stage] || :main} specified by #{resource}"
end
- # Compiler our catalog. This mostly revolves around finding and evaluating classes.
- # This is the main entry into our catalog.
- def compile
- # Set the client's parameters into the top scope.
- set_node_parameters
- create_settings_scope
+ @catalog.add_edge(stage, resource)
+ end
- evaluate_main
+ private :set_container_resource
+
+ # Do we use nodes found in the code, vs. the external node sources?
+ def ast_nodes?
+ known_resource_types.nodes?
+ end
- evaluate_ast_node
+ # Store the fact that we've evaluated a class
+ def add_class(name)
+ @catalog.add_class(name) unless name == ""
+ end
- evaluate_node_classes
- evaluate_generators
+ # Return a list of all of the defined classes.
+ def classlist
+ @catalog.classes
+ end
+
+ # Compiler our catalog. This mostly revolves around finding and evaluating classes.
+ # This is the main entry into our catalog.
+ def compile
+ # Set the client's parameters into the top scope.
+ set_node_parameters
+ create_settings_scope
+
+ evaluate_main
+
+ evaluate_ast_node
+
+ evaluate_node_classes
+
+ evaluate_generators
+
+ finish
+
+ fail_on_unevaluated
+
+ @catalog
+ end
+
+ # LAK:FIXME There are no tests for this.
+ def delete_collection(coll)
+ @collections.delete(coll) if @collections.include?(coll)
+ end
- finish
-
- fail_on_unevaluated
-
- @catalog
+ # Return the node's environment.
+ def environment
+ unless defined?(@environment)
+ @environment = (node.environment and node.environment != "") ? node.environment : nil
end
+ Puppet::Node::Environment.current = @environment
+ @environment
+ end
- # LAK:FIXME There are no tests for this.
- def delete_collection(coll)
- @collections.delete(coll) if @collections.include?(coll)
- end
+ # Evaluate all of the classes specified by the node.
+ def evaluate_node_classes
+ evaluate_classes(@node.classes, topscope)
+ end
- # Return the node's environment.
- def environment
- unless defined?(@environment)
- @environment = (node.environment and node.environment != "") ? node.environment : nil
- end
- Puppet::Node::Environment.current = @environment
- @environment
- end
+ # Evaluate each specified class in turn. If there are any classes we can't
+ # find, just tag the catalog and move on. This method really just
+ # creates resource objects that point back to the classes, and then the
+ # resources are themselves evaluated later in the process.
+ def evaluate_classes(classes, scope, lazy_evaluate = true)
+ raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source
+ found = []
+ classes.each do |name|
+ # If we can find the class, then make a resource that will evaluate it.
+ if klass = scope.find_hostclass(name)
+ found << name and next if scope.class_scope(klass)
- # Evaluate all of the classes specified by the node.
- def evaluate_node_classes
- evaluate_classes(@node.classes, topscope)
- end
-
- # Evaluate each specified class in turn. If there are any classes we can't
- # find, just tag the catalog and move on. This method really just
- # creates resource objects that point back to the classes, and then the
- # resources are themselves evaluated later in the process.
- def evaluate_classes(classes, scope, lazy_evaluate = true)
- raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source
- found = []
- classes.each do |name|
- # If we can find the class, then make a resource that will evaluate it.
- if klass = scope.find_hostclass(name)
- found << name and next if scope.class_scope(klass)
-
- resource = klass.mk_plain_resource(scope)
-
- # If they've disabled lazy evaluation (which the :include function does),
- # then evaluate our resource immediately.
- resource.evaluate unless lazy_evaluate
- found << name
- else
- Puppet.info "Could not find class #{name} for #{node.name}"
- @catalog.tag(name)
- end
- end
- found
- end
-
- def evaluate_relationships
- @relationships.each { |rel| rel.evaluate(catalog) }
- end
+ resource = klass.mk_plain_resource(scope)
- # Return a resource by either its ref or its type and title.
- def findresource(*args)
- @catalog.resource(*args)
+ # If they've disabled lazy evaluation (which the :include function does),
+ # then evaluate our resource immediately.
+ resource.evaluate unless lazy_evaluate
+ found << name
+ else
+ Puppet.info "Could not find class #{name} for #{node.name}"
+ @catalog.tag(name)
+ end
end
-
- def initialize(node, options = {})
- @node = node
-
- options.each do |param, value|
- begin
- send(param.to_s + "=", value)
- rescue NoMethodError
- raise ArgumentError, "Compiler objects do not accept #{param}"
- end
+ found
+ end
+
+ def evaluate_relationships
+ @relationships.each { |rel| rel.evaluate(catalog) }
+ end
+
+ # Return a resource by either its ref or its type and title.
+ def findresource(*args)
+ @catalog.resource(*args)
+ end
+
+ def initialize(node, options = {})
+ @node = node
+
+ options.each do |param, value|
+ begin
+ send(param.to_s + "=", value)
+ rescue NoMethodError
+ raise ArgumentError, "Compiler objects do not accept #{param}"
+ end
+ end
+
+ initvars
+ end
+
+ # Create a new scope, with either a specified parent scope or
+ # using the top scope.
+ def newscope(parent, options = {})
+ parent ||= topscope
+ options[:compiler] = self
+ scope = Puppet::Parser::Scope.new(options)
+ scope.parent = parent
+ scope
+ end
+
+ # Return any overrides for the given resource.
+ def resource_overrides(resource)
+ @resource_overrides[resource.ref]
+ end
+
+ # The top scope is usually the top-level scope, but if we're using AST nodes,
+ # then it is instead the node's scope.
+ def topscope
+ node_scope || @topscope
+ end
+
+ private
+
+ # If ast nodes are enabled, then see if we can find and evaluate one.
+ def evaluate_ast_node
+ return unless ast_nodes?
+
+ # Now see if we can find the node.
+ astnode = nil
+ @node.names.each do |name|
+ break if astnode = known_resource_types.node(name.to_s.downcase)
+ end
+
+ unless (astnode ||= known_resource_types.node("default"))
+ raise Puppet::ParseError, "Could not find default node or by name with '#{node.names.join(", ")}'"
+ end
+
+ # Create a resource to model this node, and then add it to the list
+ # of resources.
+ resource = astnode.mk_plain_resource(topscope)
+
+ resource.evaluate
+
+ # Now set the node scope appropriately, so that :topscope can
+ # behave differently.
+ @node_scope = topscope.class_scope(astnode)
+ end
+
+ # Evaluate our collections and return true if anything returned an object.
+ # The 'true' is used to continue a loop, so it's important.
+ def evaluate_collections
+ return false if @collections.empty?
+
+ found_something = false
+ exceptwrap do
+ # We have to iterate over a dup of the array because
+ # collections can delete themselves from the list, which
+ # changes its length and causes some collections to get missed.
+ @collections.dup.each do |collection|
+ found_something = true if collection.evaluate
+ end
+ end
+
+ found_something
+ end
+
+ # Make sure all of our resources have been evaluated into native resources.
+ # We return true if any resources have, so that we know to continue the
+ # evaluate_generators loop.
+ def evaluate_definitions
+ exceptwrap do
+ if ary = unevaluated_resources
+ evaluated = false
+ ary.each do |resource|
+ if not resource.virtual?
+ resource.evaluate
+ evaluated = true
+ end
end
-
- initvars
- end
-
- # Create a new scope, with either a specified parent scope or
- # using the top scope.
- def newscope(parent, options = {})
- parent ||= topscope
- options[:compiler] = self
- scope = Puppet::Parser::Scope.new(options)
- scope.parent = parent
- scope
- end
-
- # Return any overrides for the given resource.
- def resource_overrides(resource)
- @resource_overrides[resource.ref]
- end
-
- # The top scope is usually the top-level scope, but if we're using AST nodes,
- # then it is instead the node's scope.
- def topscope
- node_scope || @topscope
- end
-
- private
-
- # If ast nodes are enabled, then see if we can find and evaluate one.
- def evaluate_ast_node
- return unless ast_nodes?
-
- # Now see if we can find the node.
- astnode = nil
- @node.names.each do |name|
- break if astnode = known_resource_types.node(name.to_s.downcase)
- end
-
- unless (astnode ||= known_resource_types.node("default"))
- raise Puppet::ParseError, "Could not find default node or by name with '#{node.names.join(", ")}'"
+ # If we evaluated, let the loop know.
+ return evaluated
+ else
+ return false
+ end
+ end
+ end
+
+ # Iterate over collections and resources until we're sure that the whole
+ # compile is evaluated. This is necessary because both collections
+ # and defined resources can generate new resources, which themselves could
+ # be defined resources.
+ def evaluate_generators
+ count = 0
+ loop do
+ done = true
+
+ # Call collections first, then definitions.
+ done = false if evaluate_collections
+ done = false if evaluate_definitions
+ break if done
+
+ count += 1
+
+ if count > 1000
+ raise Puppet::ParseError, "Somehow looped more than 1000 times while evaluating host catalog"
+ end
+ end
+ end
+
+ # Find and evaluate our main object, if possible.
+ def evaluate_main
+ @main = known_resource_types.find_hostclass([""], "") || known_resource_types.add(Puppet::Resource::Type.new(:hostclass, ""))
+ @topscope.source = @main
+ @main_resource = Puppet::Parser::Resource.new("class", :main, :scope => @topscope, :source => @main)
+ @topscope.resource = @main_resource
+
+ @resources << @main_resource
+ @catalog.add_resource(@main_resource)
+
+ set_container_resource(@topscope, @main_resource)
+
+ @main_resource.evaluate
+ end
+
+ # Make sure the entire catalog is evaluated.
+ def fail_on_unevaluated
+ fail_on_unevaluated_overrides
+ fail_on_unevaluated_resource_collections
+ end
+
+ # If there are any resource overrides remaining, then we could
+ # not find the resource they were supposed to override, so we
+ # want to throw an exception.
+ def fail_on_unevaluated_overrides
+ remaining = []
+ @resource_overrides.each do |name, overrides|
+ remaining += overrides
+ end
+
+ unless remaining.empty?
+ fail Puppet::ParseError,
+ "Could not find resource(s) %s for overriding" % remaining.collect { |o|
+ o.ref
+ }.join(", ")
+ end
+ end
+
+ # Make sure we don't have any remaining collections that specifically
+ # look for resources, because we want to consider those to be
+ # parse errors.
+ def fail_on_unevaluated_resource_collections
+ remaining = []
+ @collections.each do |coll|
+ # We're only interested in the 'resource' collections,
+ # which result from direct calls of 'realize'. Anything
+ # else is allowed not to return resources.
+ # Collect all of them, so we have a useful error.
+ if r = coll.resources
+ if r.is_a?(Array)
+ remaining += r
+ else
+ remaining << r
end
-
- # Create a resource to model this node, and then add it to the list
- # of resources.
- resource = astnode.mk_plain_resource(topscope)
-
- resource.evaluate
-
- # Now set the node scope appropriately, so that :topscope can
- # behave differently.
- @node_scope = topscope.class_scope(astnode)
+ end
end
- # Evaluate our collections and return true if anything returned an object.
- # The 'true' is used to continue a loop, so it's important.
- def evaluate_collections
- return false if @collections.empty?
-
- found_something = false
- exceptwrap do
- # We have to iterate over a dup of the array because
- # collections can delete themselves from the list, which
- # changes its length and causes some collections to get missed.
- @collections.dup.each do |collection|
- found_something = true if collection.evaluate
- end
- end
+ raise Puppet::ParseError, "Failed to realize virtual resources #{remaining.join(', ')}" unless remaining.empty?
+ end
- found_something
- end
+ # Make sure all of our resources and such have done any last work
+ # necessary.
+ def finish
+ evaluate_relationships
- # Make sure all of our resources have been evaluated into native resources.
- # We return true if any resources have, so that we know to continue the
- # evaluate_generators loop.
- def evaluate_definitions
- exceptwrap do
- if ary = unevaluated_resources
- evaluated = false
- ary.each do |resource|
- if not resource.virtual?
- resource.evaluate
- evaluated = true
- end
- end
- # If we evaluated, let the loop know.
- return evaluated
- else
- return false
- end
+ resources.each do |resource|
+ # Add in any resource overrides.
+ if overrides = resource_overrides(resource)
+ overrides.each do |over|
+ resource.merge(over)
end
- end
- # Iterate over collections and resources until we're sure that the whole
- # compile is evaluated. This is necessary because both collections
- # and defined resources can generate new resources, which themselves could
- # be defined resources.
- def evaluate_generators
- count = 0
- loop do
- done = true
-
- # Call collections first, then definitions.
- done = false if evaluate_collections
- done = false if evaluate_definitions
- break if done
-
- count += 1
-
- if count > 1000
- raise Puppet::ParseError, "Somehow looped more than 1000 times while evaluating host catalog"
- end
- end
- end
-
- # Find and evaluate our main object, if possible.
- def evaluate_main
- @main = known_resource_types.find_hostclass([""], "") || known_resource_types.add(Puppet::Resource::Type.new(:hostclass, ""))
- @topscope.source = @main
- @main_resource = Puppet::Parser::Resource.new("class", :main, :scope => @topscope, :source => @main)
- @topscope.resource = @main_resource
-
- @resources << @main_resource
- @catalog.add_resource(@main_resource)
+ # Remove the overrides, so that the configuration knows there
+ # are none left.
+ overrides.clear
+ end
- set_container_resource(@topscope, @main_resource)
-
- @main_resource.evaluate
+ resource.finish if resource.respond_to?(:finish)
end
- # Make sure the entire catalog is evaluated.
- def fail_on_unevaluated
- fail_on_unevaluated_overrides
- fail_on_unevaluated_resource_collections
- end
+ add_resource_metaparams
+ end
- # If there are any resource overrides remaining, then we could
- # not find the resource they were supposed to override, so we
- # want to throw an exception.
- def fail_on_unevaluated_overrides
- remaining = []
- @resource_overrides.each do |name, overrides|
- remaining += overrides
- end
-
- unless remaining.empty?
- fail Puppet::ParseError,
- "Could not find resource(s) %s for overriding" % remaining.collect { |o|
- o.ref
- }.join(", ")
- end
+ def add_resource_metaparams
+ unless main = catalog.resource(:class, :main)
+ raise "Couldn't find main"
end
- # Make sure we don't have any remaining collections that specifically
- # look for resources, because we want to consider those to be
- # parse errors.
- def fail_on_unevaluated_resource_collections
- remaining = []
- @collections.each do |coll|
- # We're only interested in the 'resource' collections,
- # which result from direct calls of 'realize'. Anything
- # else is allowed not to return resources.
- # Collect all of them, so we have a useful error.
- if r = coll.resources
- if r.is_a?(Array)
- remaining += r
- else
- remaining << r
- end
- end
- end
-
- raise Puppet::ParseError, "Failed to realize virtual resources #{remaining.join(', ')}" unless remaining.empty?
+ names = []
+ Puppet::Type.eachmetaparam do |name|
+ next if Puppet::Parser::Resource.relationship_parameter?(name)
+ names << name
end
- # Make sure all of our resources and such have done any last work
- # necessary.
- def finish
- evaluate_relationships
-
- resources.each do |resource|
- # Add in any resource overrides.
- if overrides = resource_overrides(resource)
- overrides.each do |over|
- resource.merge(over)
- end
-
- # Remove the overrides, so that the configuration knows there
- # are none left.
- overrides.clear
- end
-
- resource.finish if resource.respond_to?(:finish)
+ data = {}
+ catalog.walk(main, :out) do |source, target|
+ if source_data = data[source] || metaparams_as_data(source, names)
+ # only store anything in the data hash if we've actually got
+ # data
+ data[source] ||= source_data
+ source_data.each do |param, value|
+ target[param] = value if target[param].nil?
end
+ data[target] = source_data.merge(metaparams_as_data(target, names))
+ end
- add_resource_metaparams
+ target.tag(*(source.tags))
end
+ end
- def add_resource_metaparams
- unless main = catalog.resource(:class, :main)
- raise "Couldn't find main"
- end
-
- names = []
- Puppet::Type.eachmetaparam do |name|
- next if Puppet::Parser::Resource.relationship_parameter?(name)
- names << name
- end
-
- data = {}
- catalog.walk(main, :out) do |source, target|
- if source_data = data[source] || metaparams_as_data(source, names)
- # only store anything in the data hash if we've actually got
- # data
- data[source] ||= source_data
- source_data.each do |param, value|
- target[param] = value if target[param].nil?
- end
- data[target] = source_data.merge(metaparams_as_data(target, names))
- end
-
- target.tag(*(source.tags))
- end
+ def metaparams_as_data(resource, params)
+ data = nil
+ params.each do |param|
+ unless resource[param].nil?
+ # Because we could be creating a hash for every resource,
+ # and we actually probably don't often have any data here at all,
+ # we're optimizing a bit by only creating a hash if there's
+ # any data to put in it.
+ data ||= {}
+ data[param] = resource[param]
+ end
end
+ data
+ end
- def metaparams_as_data(resource, params)
- data = nil
- params.each do |param|
- unless resource[param].nil?
- # Because we could be creating a hash for every resource,
- # and we actually probably don't often have any data here at all,
- # we're optimizing a bit by only creating a hash if there's
- # any data to put in it.
- data ||= {}
- data[param] = resource[param]
- end
- end
- data
- end
+ # Set up all of our internal variables.
+ def initvars
+ # The list of objects that will available for export.
+ @exported_resources = {}
- # Set up all of our internal variables.
- def initvars
- # The list of objects that will available for export.
- @exported_resources = {}
+ # The list of overrides. This is used to cache overrides on objects
+ # that don't exist yet. We store an array of each override.
+ @resource_overrides = Hash.new do |overs, ref|
+ overs[ref] = []
+ end
- # The list of overrides. This is used to cache overrides on objects
- # that don't exist yet. We store an array of each override.
- @resource_overrides = Hash.new do |overs, ref|
- overs[ref] = []
- end
+ # The list of collections that have been created. This is a global list,
+ # but they each refer back to the scope that created them.
+ @collections = []
- # The list of collections that have been created. This is a global list,
- # but they each refer back to the scope that created them.
- @collections = []
+ # The list of relationships to evaluate.
+ @relationships = []
- # The list of relationships to evaluate.
- @relationships = []
+ # For maintaining the relationship between scopes and their resources.
+ @catalog = Puppet::Resource::Catalog.new(@node.name)
+ @catalog.version = known_resource_types.version
- # For maintaining the relationship between scopes and their resources.
- @catalog = Puppet::Resource::Catalog.new(@node.name)
- @catalog.version = known_resource_types.version
+ # Create our initial scope and a resource that will evaluate main.
+ @topscope = Puppet::Parser::Scope.new(:compiler => self)
- # Create our initial scope and a resource that will evaluate main.
- @topscope = Puppet::Parser::Scope.new(:compiler => self)
+ @main_stage_resource = Puppet::Parser::Resource.new("stage", :main, :scope => @topscope)
+ @catalog.add_resource(@main_stage_resource)
- @main_stage_resource = Puppet::Parser::Resource.new("stage", :main, :scope => @topscope)
- @catalog.add_resource(@main_stage_resource)
+ # local resource array to maintain resource ordering
+ @resources = []
- # local resource array to maintain resource ordering
- @resources = []
+ # Make sure any external node classes are in our class list
+ @catalog.add_class(*@node.classes)
+ end
- # Make sure any external node classes are in our class list
- @catalog.add_class(*@node.classes)
+ # Set the node's parameters into the top-scope as variables.
+ def set_node_parameters
+ node.parameters.each do |param, value|
+ @topscope.setvar(param, value)
end
- # Set the node's parameters into the top-scope as variables.
- def set_node_parameters
- node.parameters.each do |param, value|
- @topscope.setvar(param, value)
- end
+ # These might be nil.
+ catalog.client_version = node.parameters["clientversion"]
+ catalog.server_version = node.parameters["serverversion"]
+ end
- # These might be nil.
- catalog.client_version = node.parameters["clientversion"]
- catalog.server_version = node.parameters["serverversion"]
+ def create_settings_scope
+ unless settings_type = environment.known_resource_types.hostclass("settings")
+ settings_type = Puppet::Resource::Type.new :hostclass, "settings"
+ environment.known_resource_types.add(settings_type)
end
- def create_settings_scope
- unless settings_type = environment.known_resource_types.hostclass("settings")
- settings_type = Puppet::Resource::Type.new :hostclass, "settings"
- environment.known_resource_types.add(settings_type)
- end
+ settings_resource = Puppet::Parser::Resource.new("class", "settings", :scope => @topscope)
+ settings_type.evaluate_code(settings_resource)
- settings_resource = Puppet::Parser::Resource.new("class", "settings", :scope => @topscope)
- settings_type.evaluate_code(settings_resource)
+ @catalog.add_resource(settings_resource)
- @catalog.add_resource(settings_resource)
+ scope = @topscope.class_scope(settings_type)
- scope = @topscope.class_scope(settings_type)
-
- Puppet.settings.each do |name, setting|
- next if name.to_s == "name"
- scope.setvar name.to_s, environment[name]
- end
+ Puppet.settings.each do |name, setting|
+ next if name.to_s == "name"
+ scope.setvar name.to_s, environment[name]
end
+ end
- # Return an array of all of the unevaluated resources. These will be definitions,
- # which need to get evaluated into native resources.
- def unevaluated_resources
- ary = resources.reject { |resource| resource.builtin? or resource.evaluated? }
+ # Return an array of all of the unevaluated resources. These will be definitions,
+ # which need to get evaluated into native resources.
+ def unevaluated_resources
+ ary = resources.reject { |resource| resource.builtin? or resource.evaluated? }
- if ary.empty?
- return nil
- else
- return ary
- end
+ if ary.empty?
+ return nil
+ else
+ return ary
end
+ end
end
diff --git a/lib/puppet/parser/files.rb b/lib/puppet/parser/files.rb
index 875a87826..749743493 100644
--- a/lib/puppet/parser/files.rb
+++ b/lib/puppet/parser/files.rb
@@ -6,83 +6,83 @@ require 'puppet/parser/parser'
# doesn't really belong in the Puppet::Module class,
# but it doesn't really belong anywhere else, either.
module Puppet::Parser::Files
- module_function
+ module_function
- # Return a list of manifests (as absolute filenames) that match +pat+
- # with the current directory set to +cwd+. If the first component of
- # +pat+ does not contain any wildcards and is an existing module, return
- # a list of manifests in that module matching the rest of +pat+
- # Otherwise, try to find manifests matching +pat+ relative to +cwd+
- def find_manifests(start, options = {})
- cwd = options[:cwd] || Dir.getwd
- module_name, pattern = split_file_path(start)
- begin
- if mod = Puppet::Module.find(module_name, options[:environment])
- return [mod.name, mod.match_manifests(pattern)]
- end
- rescue Puppet::Module::InvalidName
- # Than that would be a "no."
- end
- abspat = File::expand_path(start, cwd)
- [nil, Dir.glob(abspat + (File.extname(abspat).empty? ? '{,.pp,.rb}' : '' )).reject { |f| FileTest.directory?(f) }]
+ # Return a list of manifests (as absolute filenames) that match +pat+
+ # with the current directory set to +cwd+. If the first component of
+ # +pat+ does not contain any wildcards and is an existing module, return
+ # a list of manifests in that module matching the rest of +pat+
+ # Otherwise, try to find manifests matching +pat+ relative to +cwd+
+ def find_manifests(start, options = {})
+ cwd = options[:cwd] || Dir.getwd
+ module_name, pattern = split_file_path(start)
+ begin
+ if mod = Puppet::Module.find(module_name, options[:environment])
+ return [mod.name, mod.match_manifests(pattern)]
+ end
+ rescue Puppet::Module::InvalidName
+ # Than that would be a "no."
end
+ abspat = File::expand_path(start, cwd)
+ [nil, Dir.glob(abspat + (File.extname(abspat).empty? ? '{,.pp,.rb}' : '' )).reject { |f| FileTest.directory?(f) }]
+ end
- # Find the concrete file denoted by +file+. If +file+ is absolute,
- # return it directly. Otherwise try to find it as a template in a
- # module. If that fails, return it relative to the +templatedir+ config
- # param.
- # In all cases, an absolute path is returned, which does not
- # necessarily refer to an existing file
- def find_template(template, environment = nil)
- if template == File.expand_path(template)
- return template
- end
-
- if template_paths = templatepath(environment)
- # If we can find the template in :templatedir, we return that.
- template_paths.collect { |path|
- File::join(path, template)
- }.each do |f|
- return f if FileTest.exist?(f)
- end
- end
+ # Find the concrete file denoted by +file+. If +file+ is absolute,
+ # return it directly. Otherwise try to find it as a template in a
+ # module. If that fails, return it relative to the +templatedir+ config
+ # param.
+ # In all cases, an absolute path is returned, which does not
+ # necessarily refer to an existing file
+ def find_template(template, environment = nil)
+ if template == File.expand_path(template)
+ return template
+ end
- # check in the default template dir, if there is one
- if td_file = find_template_in_module(template, environment)
- return td_file
- end
+ if template_paths = templatepath(environment)
+ # If we can find the template in :templatedir, we return that.
+ template_paths.collect { |path|
+ File::join(path, template)
+ }.each do |f|
+ return f if FileTest.exist?(f)
+ end
+ end
- nil
+ # check in the default template dir, if there is one
+ if td_file = find_template_in_module(template, environment)
+ return td_file
end
- def find_template_in_module(template, environment = nil)
- path, file = split_file_path(template)
+ nil
+ end
- # Because templates don't have an assumed template name, like manifests do,
- # we treat templates with no name as being templates in the main template
- # directory.
- return nil unless file
+ def find_template_in_module(template, environment = nil)
+ path, file = split_file_path(template)
- if mod = Puppet::Module.find(path, environment) and t = mod.template(file)
- return t
- end
- nil
- end
+ # Because templates don't have an assumed template name, like manifests do,
+ # we treat templates with no name as being templates in the main template
+ # directory.
+ return nil unless file
- # Return an array of paths by splitting the +templatedir+ config
- # parameter.
- def templatepath(environment = nil)
- dirs = Puppet.settings.value(:templatedir, environment).split(File::PATH_SEPARATOR)
- dirs.select do |p|
- File::directory?(p)
- end
+ if mod = Puppet::Module.find(path, environment) and t = mod.template(file)
+ return t
end
+ nil
+ end
- # Split the path into the module and the rest of the path, or return
- # nil if the path is empty or absolute (starts with a /).
- # This method can return nil & anyone calling it needs to handle that.
- def split_file_path(path)
- path.split(File::SEPARATOR, 2) unless path == "" or path == File.expand_path(path)
+ # Return an array of paths by splitting the +templatedir+ config
+ # parameter.
+ def templatepath(environment = nil)
+ dirs = Puppet.settings.value(:templatedir, environment).split(File::PATH_SEPARATOR)
+ dirs.select do |p|
+ File::directory?(p)
end
+ end
+
+ # Split the path into the module and the rest of the path, or return
+ # nil if the path is empty or absolute (starts with a /).
+ # This method can return nil & anyone calling it needs to handle that.
+ def split_file_path(path)
+ path.split(File::SEPARATOR, 2) unless path == "" or path == File.expand_path(path)
+ end
end
diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb
index 3e56f2a95..c238da5d4 100644
--- a/lib/puppet/parser/functions.rb
+++ b/lib/puppet/parser/functions.rb
@@ -7,116 +7,116 @@ require 'monitor'
# class.
module Puppet::Parser::Functions
- (@functions = Hash.new { |h,k| h[k] = {} }).extend(MonitorMixin)
- (@modules = {} ).extend(MonitorMixin)
+ (@functions = Hash.new { |h,k| h[k] = {} }).extend(MonitorMixin)
+ (@modules = {} ).extend(MonitorMixin)
- class << self
- include Puppet::Util
- end
+ class << self
+ include Puppet::Util
+ end
- def self.autoloader
- unless defined?(@autoloader)
+ def self.autoloader
+ unless defined?(@autoloader)
- @autoloader = Puppet::Util::Autoload.new(
- self,
- "puppet/parser/functions",
+ @autoloader = Puppet::Util::Autoload.new(
+ self,
+ "puppet/parser/functions",
- :wrap => false
- )
- end
-
- @autoloader
+ :wrap => false
+ )
end
- Environment = Puppet::Node::Environment
+ @autoloader
+ end
- def self.environment_module(env = nil)
- @modules.synchronize {
- @modules[ env || Environment.current || Environment.root ] ||= Module.new
- }
- end
+ Environment = Puppet::Node::Environment
- # Create a new function type.
- def self.newfunction(name, options = {}, &block)
- name = symbolize(name)
+ def self.environment_module(env = nil)
+ @modules.synchronize {
+ @modules[ env || Environment.current || Environment.root ] ||= Module.new
+ }
+ end
- raise Puppet::DevError, "Function #{name} already defined" if functions.include?(name)
+ # Create a new function type.
+ def self.newfunction(name, options = {}, &block)
+ name = symbolize(name)
- ftype = options[:type] || :statement
+ raise Puppet::DevError, "Function #{name} already defined" if functions.include?(name)
- unless ftype == :statement or ftype == :rvalue
- raise Puppet::DevError, "Invalid statement type #{ftype.inspect}"
- end
+ ftype = options[:type] || :statement
- fname = "function_#{name}"
- environment_module.send(:define_method, fname, &block)
-
- # Someday we'll support specifying an arity, but for now, nope
- #functions[name] = {:arity => arity, :type => ftype}
- functions[name] = {:type => ftype, :name => fname}
- functions[name][:doc] = options[:doc] if options[:doc]
+ unless ftype == :statement or ftype == :rvalue
+ raise Puppet::DevError, "Invalid statement type #{ftype.inspect}"
end
- # Remove a function added by newfunction
- def self.rmfunction(name)
- name = symbolize(name)
+ fname = "function_#{name}"
+ environment_module.send(:define_method, fname, &block)
- raise Puppet::DevError, "Function #{name} is not defined" unless functions.include? name
+ # Someday we'll support specifying an arity, but for now, nope
+ #functions[name] = {:arity => arity, :type => ftype}
+ functions[name] = {:type => ftype, :name => fname}
+ functions[name][:doc] = options[:doc] if options[:doc]
+ end
- functions.delete name
+ # Remove a function added by newfunction
+ def self.rmfunction(name)
+ name = symbolize(name)
- fname = "function_#{name}"
- environment_module.send(:remove_method, fname)
- end
+ raise Puppet::DevError, "Function #{name} is not defined" unless functions.include? name
- # Determine if a given name is a function
- def self.function(name)
- name = symbolize(name)
+ functions.delete name
- unless functions.include?(name) or functions(Puppet::Node::Environment.root).include?(name)
- autoloader.load(name,Environment.current || Environment.root)
- end
+ fname = "function_#{name}"
+ environment_module.send(:remove_method, fname)
+ end
- ( functions(Environment.root)[name] || functions[name] || {:name => false} )[:name]
+ # Determine if a given name is a function
+ def self.function(name)
+ name = symbolize(name)
+
+ unless functions.include?(name) or functions(Puppet::Node::Environment.root).include?(name)
+ autoloader.load(name,Environment.current || Environment.root)
end
- def self.functiondocs
- autoloader.loadall
+ ( functions(Environment.root)[name] || functions[name] || {:name => false} )[:name]
+ end
- ret = ""
+ def self.functiondocs
+ autoloader.loadall
- functions.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, hash|
- #ret += "#{name}\n#{hash[:type]}\n"
- ret += "#{name}\n#{"-" * name.to_s.length}\n"
- if hash[:doc]
- ret += Puppet::Util::Docs.scrub(hash[:doc])
- else
- ret += "Undocumented.\n"
- end
+ ret = ""
- ret += "\n\n- **Type**: #{hash[:type]}\n\n"
- end
+ functions.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, hash|
+ #ret += "#{name}\n#{hash[:type]}\n"
+ ret += "#{name}\n#{"-" * name.to_s.length}\n"
+ if hash[:doc]
+ ret += Puppet::Util::Docs.scrub(hash[:doc])
+ else
+ ret += "Undocumented.\n"
+ end
- ret
+ ret += "\n\n- **Type**: #{hash[:type]}\n\n"
end
- def self.functions(env = nil)
- @functions.synchronize {
- @functions[ env || Environment.current || Environment.root ]
- }
- end
+ ret
+ end
- # Determine if a given function returns a value or not.
- def self.rvalue?(name)
- (functions[symbolize(name)] || {})[:type] == :rvalue
- end
+ def self.functions(env = nil)
+ @functions.synchronize {
+ @functions[ env || Environment.current || Environment.root ]
+ }
+ end
+
+ # Determine if a given function returns a value or not.
+ def self.rvalue?(name)
+ (functions[symbolize(name)] || {})[:type] == :rvalue
+ end
- # Runs a newfunction to create a function for each of the log levels
+ # Runs a newfunction to create a function for each of the log levels
- Puppet::Util::Log.levels.each do |level|
- newfunction(level, :doc => "Log a message on the server at level #{level.to_s}.") do |vals|
- send(level, vals.join(" "))
- end
+ Puppet::Util::Log.levels.each do |level|
+ newfunction(level, :doc => "Log a message on the server at level #{level.to_s}.") do |vals|
+ send(level, vals.join(" "))
end
+ end
end
diff --git a/lib/puppet/parser/functions/defined.rb b/lib/puppet/parser/functions/defined.rb
index 4d1d8c6fd..2930a65cc 100644
--- a/lib/puppet/parser/functions/defined.rb
+++ b/lib/puppet/parser/functions/defined.rb
@@ -1,27 +1,27 @@
# Test whether a given class or definition is defined
Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Determine whether a given
- type is defined, either as a native type or a defined type, or whether a class is defined.
- This is useful for checking whether a class is defined and only including it if it is.
- This function can also test whether a resource has been defined, using resource references
- (e.g., ``if defined(File['/tmp/myfile']) { ... }``). This function is unfortunately
- dependent on the parse order of the configuration when testing whether a resource is defined.") do |vals|
- result = false
- vals = [vals] unless vals.is_a?(Array)
- vals.each do |val|
- case val
- when String
- if Puppet::Type.type(val) or find_definition(val) or find_hostclass(val)
- result = true
- break
- end
- when Puppet::Resource
- if findresource(val.to_s)
- result = true
- break
- end
- else
- raise ArgumentError, "Invalid argument of type '#{val.class}' to 'defined'"
- end
+ type is defined, either as a native type or a defined type, or whether a class is defined.
+ This is useful for checking whether a class is defined and only including it if it is.
+ This function can also test whether a resource has been defined, using resource references
+ (e.g., ``if defined(File['/tmp/myfile']) { ... }``). This function is unfortunately
+ dependent on the parse order of the configuration when testing whether a resource is defined.") do |vals|
+ result = false
+ vals = [vals] unless vals.is_a?(Array)
+ vals.each do |val|
+ case val
+ when String
+ if Puppet::Type.type(val) or find_definition(val) or find_hostclass(val)
+ result = true
+ break
end
- result
+ when Puppet::Resource
+ if findresource(val.to_s)
+ result = true
+ break
+ end
+ else
+ raise ArgumentError, "Invalid argument of type '#{val.class}' to 'defined'"
+ end
+ end
+ result
end
diff --git a/lib/puppet/parser/functions/fail.rb b/lib/puppet/parser/functions/fail.rb
index 35b20ee92..5bef6c7e3 100644
--- a/lib/puppet/parser/functions/fail.rb
+++ b/lib/puppet/parser/functions/fail.rb
@@ -1,4 +1,4 @@
Puppet::Parser::Functions::newfunction(:fail, :doc => "Fail with a parse error.") do |vals|
- vals = vals.collect { |s| s.to_s }.join(" ") if vals.is_a? Array
- raise Puppet::ParseError, vals.to_s
+ vals = vals.collect { |s| s.to_s }.join(" ") if vals.is_a? Array
+ raise Puppet::ParseError, vals.to_s
end
diff --git a/lib/puppet/parser/functions/file.rb b/lib/puppet/parser/functions/file.rb
index d13b01ede..963111260 100644
--- a/lib/puppet/parser/functions/file.rb
+++ b/lib/puppet/parser/functions/file.rb
@@ -1,23 +1,23 @@
# Returns the contents of a file
- Puppet::Parser::Functions::newfunction(
- :file, :type => :rvalue,
+ Puppet::Parser::Functions::newfunction(
+ :file, :type => :rvalue,
- :doc => "Return the contents of a file. Multiple files
- can be passed, and the first file that exists will be read in.") do |vals|
- ret = nil
- vals.each do |file|
- unless file =~ /^#{File::SEPARATOR}/
- raise Puppet::ParseError, "Files must be fully qualified"
- end
- if FileTest.exists?(file)
- ret = File.read(file)
- break
- end
- end
- if ret
- ret
- else
- raise Puppet::ParseError, "Could not find any files from #{vals.join(", ")}"
- end
+ :doc => "Return the contents of a file. Multiple files
+ can be passed, and the first file that exists will be read in.") do |vals|
+ ret = nil
+ vals.each do |file|
+ unless file =~ /^#{File::SEPARATOR}/
+ raise Puppet::ParseError, "Files must be fully qualified"
+ end
+ if FileTest.exists?(file)
+ ret = File.read(file)
+ break
+ end
+ end
+ if ret
+ ret
+ else
+ raise Puppet::ParseError, "Could not find any files from #{vals.join(", ")}"
+ end
end
diff --git a/lib/puppet/parser/functions/fqdn_rand.rb b/lib/puppet/parser/functions/fqdn_rand.rb
index 27af2d7ca..3e7018ac4 100644
--- a/lib/puppet/parser/functions/fqdn_rand.rb
+++ b/lib/puppet/parser/functions/fqdn_rand.rb
@@ -1,9 +1,9 @@
Puppet::Parser::Functions::newfunction(:fqdn_rand, :type => :rvalue, :doc =>
- "Generates random numbers based on the node's fqdn. The first argument
- sets the range. Additional (optional) arguments may be used to further
- distinguish the seed.") do |args|
- require 'md5'
- max = args.shift
- srand MD5.new([lookupvar('fqdn'),args].join(':')).to_s.hex
- rand(max).to_s
+ "Generates random numbers based on the node's fqdn. The first argument
+ sets the range. Additional (optional) arguments may be used to further
+ distinguish the seed.") do |args|
+ require 'md5'
+ max = args.shift
+ srand MD5.new([lookupvar('fqdn'),args].join(':')).to_s.hex
+ rand(max).to_s
end
diff --git a/lib/puppet/parser/functions/generate.rb b/lib/puppet/parser/functions/generate.rb
index 8430f03a6..91f7b2240 100644
--- a/lib/puppet/parser/functions/generate.rb
+++ b/lib/puppet/parser/functions/generate.rb
@@ -1,31 +1,31 @@
# Runs an external command and returns the results
Puppet::Parser::Functions::newfunction(:generate, :type => :rvalue,
- :doc => "Calls an external command on the Puppet master and returns
- the results of the command. Any arguments are passed to the external command as
- arguments. If the generator does not exit with return code of 0,
- the generator is considered to have failed and a parse error is
- thrown. Generators can only have file separators, alphanumerics, dashes,
- and periods in them. This function will attempt to protect you from
- malicious generator calls (e.g., those with '..' in them), but it can
- never be entirely safe. No subshell is used to execute
- generators, so all shell metacharacters are passed directly to
- the generator.") do |args|
+ :doc => "Calls an external command on the Puppet master and returns
+ the results of the command. Any arguments are passed to the external command as
+ arguments. If the generator does not exit with return code of 0,
+ the generator is considered to have failed and a parse error is
+ thrown. Generators can only have file separators, alphanumerics, dashes,
+ and periods in them. This function will attempt to protect you from
+ malicious generator calls (e.g., those with '..' in them), but it can
+ never be entirely safe. No subshell is used to execute
+ generators, so all shell metacharacters are passed directly to
+ the generator.") do |args|
- raise Puppet::ParseError, "Generators must be fully qualified" unless args[0] =~ /^#{File::SEPARATOR}/
+ raise Puppet::ParseError, "Generators must be fully qualified" unless args[0] =~ /^#{File::SEPARATOR}/
- unless args[0] =~ /^[-#{File::SEPARATOR}\w.]+$/
- raise Puppet::ParseError,
- "Generators can only contain alphanumerics, file separators, and dashes"
- end
+ unless args[0] =~ /^[-#{File::SEPARATOR}\w.]+$/
+ raise Puppet::ParseError,
+ "Generators can only contain alphanumerics, file separators, and dashes"
+ end
- if args[0] =~ /\.\./
- raise Puppet::ParseError,
- "Can not use generators with '..' in them."
- end
+ if args[0] =~ /\.\./
+ raise Puppet::ParseError,
+ "Can not use generators with '..' in them."
+ end
- begin
- Dir.chdir(File.dirname(args[0])) { Puppet::Util.execute(args) }
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::ParseError, "Failed to execute generator #{args[0]}: #{detail}"
- end
+ begin
+ Dir.chdir(File.dirname(args[0])) { Puppet::Util.execute(args) }
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::ParseError, "Failed to execute generator #{args[0]}: #{detail}"
+ end
end
diff --git a/lib/puppet/parser/functions/include.rb b/lib/puppet/parser/functions/include.rb
index d1bafa54a..1e12a6a88 100644
--- a/lib/puppet/parser/functions/include.rb
+++ b/lib/puppet/parser/functions/include.rb
@@ -1,24 +1,24 @@
# Include the specified classes
Puppet::Parser::Functions::newfunction(:include, :doc => "Evaluate one or more classes.") do |vals|
- vals = [vals] unless vals.is_a?(Array)
+ vals = [vals] unless vals.is_a?(Array)
- # The 'false' disables lazy evaluation.
- klasses = compiler.evaluate_classes(vals, self, false)
+ # The 'false' disables lazy evaluation.
+ klasses = compiler.evaluate_classes(vals, self, false)
- missing = vals.find_all do |klass|
- ! klasses.include?(klass)
- end
+ missing = vals.find_all do |klass|
+ ! klasses.include?(klass)
+ end
- unless missing.empty?
- # Throw an error if we didn't evaluate all of the classes.
- str = "Could not find class"
- str += "es" if missing.length > 1
+ unless missing.empty?
+ # Throw an error if we didn't evaluate all of the classes.
+ str = "Could not find class"
+ str += "es" if missing.length > 1
- str += " " + missing.join(", ")
+ str += " " + missing.join(", ")
- if n = namespaces and ! n.empty? and n != [""]
- str += " in namespaces #{@namespaces.join(", ")}"
- end
- self.fail Puppet::ParseError, str
- end
+ if n = namespaces and ! n.empty? and n != [""]
+ str += " in namespaces #{@namespaces.join(", ")}"
+ end
+ self.fail Puppet::ParseError, str
+ end
end
diff --git a/lib/puppet/parser/functions/inline_template.rb b/lib/puppet/parser/functions/inline_template.rb
index 6c0485d1e..11d980fab 100644
--- a/lib/puppet/parser/functions/inline_template.rb
+++ b/lib/puppet/parser/functions/inline_template.rb
@@ -1,20 +1,20 @@
Puppet::Parser::Functions::newfunction(:inline_template, :type => :rvalue, :doc =>
- "Evaluate a template string and return its value. See `the templating docs
- </trac/puppet/wiki/PuppetTemplating>`_ for more information. Note that
- if multiple template strings are specified, their output is all concatenated
- and returned as the output of the function.") do |vals|
- require 'erb'
+ "Evaluate a template string and return its value. See `the templating docs
+ </trac/puppet/wiki/PuppetTemplating>`_ for more information. Note that
+ if multiple template strings are specified, their output is all concatenated
+ and returned as the output of the function.") do |vals|
+ require 'erb'
- vals.collect do |string|
- # Use a wrapper, so the template can't get access to the full
- # Scope object.
+ vals.collect do |string|
+ # Use a wrapper, so the template can't get access to the full
+ # Scope object.
- wrapper = Puppet::Parser::TemplateWrapper.new(self)
- begin
- wrapper.result(string)
- rescue => detail
- raise Puppet::ParseError,
- "Failed to parse inline template: #{detail}"
- end
- end.join("")
+ wrapper = Puppet::Parser::TemplateWrapper.new(self)
+ begin
+ wrapper.result(string)
+ rescue => detail
+ raise Puppet::ParseError,
+ "Failed to parse inline template: #{detail}"
+ end
+ end.join("")
end
diff --git a/lib/puppet/parser/functions/realize.rb b/lib/puppet/parser/functions/realize.rb
index 6aff19d29..4247b8af8 100644
--- a/lib/puppet/parser/functions/realize.rb
+++ b/lib/puppet/parser/functions/realize.rb
@@ -2,13 +2,13 @@
# be a good bit faster.
Puppet::Parser::Functions::newfunction(:realize, :doc => "Make a virtual object real. This is useful
- when you want to know the name of the virtual object and don't want to
- bother with a full collection. It is slightly faster than a collection,
- and, of course, is a bit shorter. You must pass the object using a
- reference; e.g.: ``realize User[luke]``." ) do |vals|
- coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual)
- vals = [vals] unless vals.is_a?(Array)
- coll.resources = vals.flatten
+ when you want to know the name of the virtual object and don't want to
+ bother with a full collection. It is slightly faster than a collection,
+ and, of course, is a bit shorter. You must pass the object using a
+ reference; e.g.: ``realize User[luke]``." ) do |vals|
+ coll = Puppet::Parser::Collector.new(self, :nomatter, nil, nil, :virtual)
+ vals = [vals] unless vals.is_a?(Array)
+ coll.resources = vals.flatten
- compiler.add_collection(coll)
+ compiler.add_collection(coll)
end
diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb
index c47c1654e..c0aeef222 100644
--- a/lib/puppet/parser/functions/regsubst.rb
+++ b/lib/puppet/parser/functions/regsubst.rb
@@ -1,10 +1,10 @@
module Puppet::Parser::Functions
- newfunction(
- :regsubst, :type => :rvalue,
+ newfunction(
+ :regsubst, :type => :rvalue,
- :doc => "
- Perform regexp replacement on a string or array of strings.
+ :doc => "
+ Perform regexp replacement on a string or array of strings.
- **Parameters** (in order):
@@ -16,85 +16,85 @@ module Puppet::Parser::Functions
:flags: Optional. String of single letter flags for how the regexp is interpreted:
- - **E** Extended regexps
- - **I** Ignore case in regexps
- - **M** Multiline regexps
- - **G** Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced.
+ - **E** Extended regexps
+ - **I** Ignore case in regexps
+ - **M** Multiline regexps
+ - **G** Global replacement; all occurrences of the regexp in each target string will be replaced. Without this, only the first occurrence will be replaced.
:lang: Optional. How to handle multibyte characters. A single-character string with the following values:
- - **N** None
- - **E** EUC
- - **S** SJIS
- - **U** UTF-8
+ - **N** None
+ - **E** EUC
+ - **S** SJIS
+ - **U** UTF-8
- **Examples**
Get the third octet from the node's IP address::
- $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3')
+ $i3 = regsubst($ipaddress,'^([0-9]+)[.]([0-9]+)[.]([0-9]+)[.]([0-9]+)$','\\3')
Put angle brackets around each octet in the node's IP address::
- $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G')
+ $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G')
") \
- do |args|
- unless args.length.between?(3, 5)
-
- raise(
- Puppet::ParseError,
-
- "regsubst(): got #{args.length} arguments, expected 3 to 5")
- end
- target, regexp, replacement, flags, lang = args
- reflags = 0
- operation = :sub
- if flags == nil
- flags = []
- elsif flags.respond_to?(:split)
- flags = flags.split('')
- else
-
- raise(
- Puppet::ParseError,
-
- "regsubst(): bad flags parameter #{flags.class}:`#{flags}'")
- end
- flags.each do |f|
- case f
- when 'G' then operation = :gsub
- when 'E' then reflags |= Regexp::EXTENDED
- when 'I' then reflags |= Regexp::IGNORECASE
- when 'M' then reflags |= Regexp::MULTILINE
- else raise(Puppet::ParseError, "regsubst(): bad flag `#{f}'")
- end
- end
- begin
- re = Regexp.compile(regexp, reflags, lang)
- rescue RegexpError, TypeError
-
- raise(
- Puppet::ParseError,
-
- "regsubst(): Bad regular expression `#{regexp}'")
- end
- if target.respond_to?(operation)
- # String parameter -> string result
- result = target.send(operation, re, replacement)
- elsif target.respond_to?(:collect) and
- target.respond_to?(:all?) and
- target.all? { |e| e.respond_to?(operation) }
- # Array parameter -> array result
- result = target.collect { |e|
- e.send(operation, re, replacement)
- }
- else
-
- raise(
- Puppet::ParseError,
-
- "regsubst(): bad target #{target.class}:`#{target}'")
- end
- return result
+ do |args|
+ unless args.length.between?(3, 5)
+
+ raise(
+ Puppet::ParseError,
+
+ "regsubst(): got #{args.length} arguments, expected 3 to 5")
+ end
+ target, regexp, replacement, flags, lang = args
+ reflags = 0
+ operation = :sub
+ if flags == nil
+ flags = []
+ elsif flags.respond_to?(:split)
+ flags = flags.split('')
+ else
+
+ raise(
+ Puppet::ParseError,
+
+ "regsubst(): bad flags parameter #{flags.class}:`#{flags}'")
+ end
+ flags.each do |f|
+ case f
+ when 'G' then operation = :gsub
+ when 'E' then reflags |= Regexp::EXTENDED
+ when 'I' then reflags |= Regexp::IGNORECASE
+ when 'M' then reflags |= Regexp::MULTILINE
+ else raise(Puppet::ParseError, "regsubst(): bad flag `#{f}'")
+ end
+ end
+ begin
+ re = Regexp.compile(regexp, reflags, lang)
+ rescue RegexpError, TypeError
+
+ raise(
+ Puppet::ParseError,
+
+ "regsubst(): Bad regular expression `#{regexp}'")
+ end
+ if target.respond_to?(operation)
+ # String parameter -> string result
+ result = target.send(operation, re, replacement)
+ elsif target.respond_to?(:collect) and
+ target.respond_to?(:all?) and
+ target.all? { |e| e.respond_to?(operation) }
+ # Array parameter -> array result
+ result = target.collect { |e|
+ e.send(operation, re, replacement)
+ }
+ else
+
+ raise(
+ Puppet::ParseError,
+
+ "regsubst(): bad target #{target.class}:`#{target}'")
end
+ return result
+ end
end
diff --git a/lib/puppet/parser/functions/require.rb b/lib/puppet/parser/functions/require.rb
index c5c4c851f..3f98c9523 100644
--- a/lib/puppet/parser/functions/require.rb
+++ b/lib/puppet/parser/functions/require.rb
@@ -1,9 +1,9 @@
# Requires the specified classes
- Puppet::Parser::Functions::newfunction(
- :require,
+ Puppet::Parser::Functions::newfunction(
+ :require,
- :doc =>"Evaluate one or more classes, adding the required class as a dependency.
+ :doc =>"Evaluate one or more classes, adding the required class as a dependency.
The relationship metaparameters work well for specifying relationships
between individual resources, but they can be clumsy for specifying
@@ -12,47 +12,47 @@ relationships between classes. This function is a superset of the
class depends on the required class.
Warning: using require in place of include can lead to unwanted dependency cycles.
- For instance the following manifest, with 'require' instead of 'include'
- would produce a nasty dependence cycle, because notify imposes a before
- between File[/foo] and Service[foo]::
+ For instance the following manifest, with 'require' instead of 'include'
+ would produce a nasty dependence cycle, because notify imposes a before
+ between File[/foo] and Service[foo]::
- class myservice {
- service { foo: ensure => running }
- }
+ class myservice {
+ service { foo: ensure => running }
+ }
- class otherstuff {
- include myservice
- file { '/foo': notify => Service[foo] }
- }
+ class otherstuff {
+ include myservice
+ file { '/foo': notify => Service[foo] }
+ }
Note that this function only works with clients 0.25 and later, and it will
fail if used with earlier clients.
") do |vals|
- # Verify that the 'include' function is loaded
- method = Puppet::Parser::Functions.function(:include)
-
- send(method, vals)
- if resource.metaparam_compatibility_mode?
- warning "The 'require' function is only compatible with clients at 0.25 and above; including class but not adding dependency"
- else
- vals = [vals] unless vals.is_a?(Array)
-
- vals.each do |klass|
- # lookup the class in the scopes
- if classobj = find_hostclass(klass)
- klass = classobj.name
- else
- raise Puppet::ParseError, "Could not find class #{klass}"
- end
-
- # This is a bit hackish, in some ways, but it's the only way
- # to configure a dependency that will make it to the client.
- # The 'obvious' way is just to add an edge in the catalog,
- # but that is considered a containment edge, not a dependency
- # edge, so it usually gets lost on the client.
- ref = Puppet::Resource.new(:class, klass)
- resource.set_parameter(:require, [resource[:require]].flatten.compact << ref)
- end
+ # Verify that the 'include' function is loaded
+ method = Puppet::Parser::Functions.function(:include)
+
+ send(method, vals)
+ if resource.metaparam_compatibility_mode?
+ warning "The 'require' function is only compatible with clients at 0.25 and above; including class but not adding dependency"
+ else
+ vals = [vals] unless vals.is_a?(Array)
+
+ vals.each do |klass|
+ # lookup the class in the scopes
+ if classobj = find_hostclass(klass)
+ klass = classobj.name
+ else
+ raise Puppet::ParseError, "Could not find class #{klass}"
+ end
+
+ # This is a bit hackish, in some ways, but it's the only way
+ # to configure a dependency that will make it to the client.
+ # The 'obvious' way is just to add an edge in the catalog,
+ # but that is considered a containment edge, not a dependency
+ # edge, so it usually gets lost on the client.
+ ref = Puppet::Resource.new(:class, klass)
+ resource.set_parameter(:require, [resource[:require]].flatten.compact << ref)
end
+ end
end
diff --git a/lib/puppet/parser/functions/search.rb b/lib/puppet/parser/functions/search.rb
index 87dd02d67..8a9c7c8be 100644
--- a/lib/puppet/parser/functions/search.rb
+++ b/lib/puppet/parser/functions/search.rb
@@ -1,7 +1,7 @@
Puppet::Parser::Functions::newfunction(:search, :doc => "Add another namespace for this class to search.
- This allows you to create classes with sets of definitions and add
- those classes to another class's search path.") do |vals|
- vals.each do |val|
- add_namespace(val)
- end
+ This allows you to create classes with sets of definitions and add
+ those classes to another class's search path.") do |vals|
+ vals.each do |val|
+ add_namespace(val)
+ end
end
diff --git a/lib/puppet/parser/functions/sha1.rb b/lib/puppet/parser/functions/sha1.rb
index 432825ee9..10cc55cfe 100644
--- a/lib/puppet/parser/functions/sha1.rb
+++ b/lib/puppet/parser/functions/sha1.rb
@@ -1,5 +1,5 @@
Puppet::Parser::Functions::newfunction(:sha1, :type => :rvalue, :doc => "Returns a SHA1 hash value from a provided string.") do |args|
- require 'sha1'
+ require 'sha1'
- Digest::SHA1.hexdigest(args[0])
+ Digest::SHA1.hexdigest(args[0])
end
diff --git a/lib/puppet/parser/functions/shellquote.rb b/lib/puppet/parser/functions/shellquote.rb
index 888b9769d..3ddb988f2 100644
--- a/lib/puppet/parser/functions/shellquote.rb
+++ b/lib/puppet/parser/functions/shellquote.rb
@@ -1,39 +1,39 @@
module Puppet::Parser::Functions
- Safe = 'a-zA-Z0-9@%_+=:,./-' # Safe unquoted
- Dangerous = '!"`$\\' # Unsafe inside double quotes
+ Safe = 'a-zA-Z0-9@%_+=:,./-' # Safe unquoted
+ Dangerous = '!"`$\\' # Unsafe inside double quotes
- newfunction(:shellquote, :type => :rvalue, :doc => "\
- Quote and concatenate arguments for use in Bourne shell.
+ newfunction(:shellquote, :type => :rvalue, :doc => "\
+ Quote and concatenate arguments for use in Bourne shell.
- Each argument is quoted separately, and then all are concatenated
- with spaces. If an argument is an array, the elements of that
- array is interpolated within the rest of the arguments; this makes
- it possible to have an array of arguments and pass that array to
- shellquote instead of having to specify each argument
- individually in the call.
- ") \
- do |args|
+ Each argument is quoted separately, and then all are concatenated
+ with spaces. If an argument is an array, the elements of that
+ array is interpolated within the rest of the arguments; this makes
+ it possible to have an array of arguments and pass that array to
+ shellquote instead of having to specify each argument
+ individually in the call.
+ ") \
+ do |args|
- result = []
- args.flatten.each do |word|
- if word.length != 0 and word.count(Safe) == word.length
- result << word
- elsif word.count(Dangerous) == 0
- result << ('"' + word + '"')
- elsif word.count("'") == 0
- result << ("'" + word + "'")
- else
- r = '"'
- word.each_byte do |c|
- r += "\\" if Dangerous.include?(c)
- r += c.chr
- end
- r += '"'
- result << r
- end
+ result = []
+ args.flatten.each do |word|
+ if word.length != 0 and word.count(Safe) == word.length
+ result << word
+ elsif word.count(Dangerous) == 0
+ result << ('"' + word + '"')
+ elsif word.count("'") == 0
+ result << ("'" + word + "'")
+ else
+ r = '"'
+ word.each_byte do |c|
+ r += "\\" if Dangerous.include?(c)
+ r += c.chr
end
-
- return result.join(" ")
+ r += '"'
+ result << r
+ end
end
+
+ return result.join(" ")
+ end
end
diff --git a/lib/puppet/parser/functions/split.rb b/lib/puppet/parser/functions/split.rb
index 09caa18aa..5d0a9dabc 100644
--- a/lib/puppet/parser/functions/split.rb
+++ b/lib/puppet/parser/functions/split.rb
@@ -1,17 +1,17 @@
module Puppet::Parser::Functions
- newfunction(
- :split, :type => :rvalue,
+ newfunction(
+ :split, :type => :rvalue,
- :doc => "\
+ :doc => "\
Split a string variable into an array using the specified split regexp.
- Usage::
+ Usage::
- $string = 'v1.v2:v3.v4'
- $array_var1 = split($string, ':')
- $array_var2 = split($string, '[.]')
- $array_var3 = split($string, '[.:]')
+ $string = 'v1.v2:v3.v4'
+ $array_var1 = split($string, ':')
+ $array_var2 = split($string, '[.]')
+ $array_var3 = split($string, '[.:]')
$array_var1 now holds the result ['v1.v2', 'v3.v4'],
while $array_var2 holds ['v1', 'v2:v3', 'v4'], and
@@ -22,8 +22,8 @@ a regexp meta-character (.), and that needs protection. A simple
way to do that for a single character is to enclose it in square
brackets.") do |args|
- raise Puppet::ParseError, ("split(): wrong number of arguments (#{args.length}; must be 2)") if args.length != 2
+ raise Puppet::ParseError, ("split(): wrong number of arguments (#{args.length}; must be 2)") if args.length != 2
- return args[0].split(Regexp.compile(args[1]))
- end
+ return args[0].split(Regexp.compile(args[1]))
+ end
end
diff --git a/lib/puppet/parser/functions/sprintf.rb b/lib/puppet/parser/functions/sprintf.rb
index af0a7213e..5ada0fed7 100644
--- a/lib/puppet/parser/functions/sprintf.rb
+++ b/lib/puppet/parser/functions/sprintf.rb
@@ -1,13 +1,13 @@
module Puppet::Parser::Functions
- newfunction(
- :sprintf, :type => :rvalue,
+ newfunction(
+ :sprintf, :type => :rvalue,
- :doc => "Perform printf-style formatting of text.
+ :doc => "Perform printf-style formatting of text.
- The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the ``Kernel::sprintf`` function in Ruby for all the details.") do |args|
- raise Puppet::ParseError, 'sprintf() needs at least one argument' if args.length < 1
- fmt = args.shift
- return sprintf(fmt, *args)
- end
+ The first parameter is format string describing how the rest of the parameters should be formatted. See the documentation for the ``Kernel::sprintf`` function in Ruby for all the details.") do |args|
+ raise Puppet::ParseError, 'sprintf() needs at least one argument' if args.length < 1
+ fmt = args.shift
+ return sprintf(fmt, *args)
+ end
end
diff --git a/lib/puppet/parser/functions/tag.rb b/lib/puppet/parser/functions/tag.rb
index 3e487feaf..84df175eb 100644
--- a/lib/puppet/parser/functions/tag.rb
+++ b/lib/puppet/parser/functions/tag.rb
@@ -1,6 +1,6 @@
# Tag the current scope with each passed name
Puppet::Parser::Functions::newfunction(:tag, :doc => "Add the specified tags to the containing class
- or definition. All contained objects will then acquire that tag, also.
- ") do |vals|
- self.resource.tag(*vals)
+ or definition. All contained objects will then acquire that tag, also.
+ ") do |vals|
+ self.resource.tag(*vals)
end
diff --git a/lib/puppet/parser/functions/tagged.rb b/lib/puppet/parser/functions/tagged.rb
index fccb13205..aaa2adfad 100644
--- a/lib/puppet/parser/functions/tagged.rb
+++ b/lib/puppet/parser/functions/tagged.rb
@@ -1,18 +1,18 @@
# Test whether a given tag is set. This functions as a big OR -- if any of the specified tags are unset, we return false.
Puppet::Parser::Functions::newfunction(:tagged, :type => :rvalue, :doc => "A boolean function that
- tells you whether the current container is tagged with the specified tags.
- The tags are ANDed, so that all of the specified tags must be included for
- the function to return true.") do |vals|
- configtags = compiler.catalog.tags
- resourcetags = resource.tags
+ tells you whether the current container is tagged with the specified tags.
+ The tags are ANDed, so that all of the specified tags must be included for
+ the function to return true.") do |vals|
+ configtags = compiler.catalog.tags
+ resourcetags = resource.tags
- retval = true
- vals.each do |val|
- unless configtags.include?(val) or resourcetags.include?(val)
- retval = false
- break
- end
- end
+ retval = true
+ vals.each do |val|
+ unless configtags.include?(val) or resourcetags.include?(val)
+ retval = false
+ break
+ end
+ end
- return retval
+ return retval
end
diff --git a/lib/puppet/parser/functions/template.rb b/lib/puppet/parser/functions/template.rb
index 6c4873efe..f51bcc1e2 100644
--- a/lib/puppet/parser/functions/template.rb
+++ b/lib/puppet/parser/functions/template.rb
@@ -1,22 +1,22 @@
Puppet::Parser::Functions::newfunction(:template, :type => :rvalue, :doc =>
- "Evaluate a template and return its value. See `the templating docs
- <http://docs.puppetlabs.com/guides/templating.html>`_ for more information.
- Note that if multiple templates are specified, their output is all
- concatenated and returned as the output of the function.") do |vals|
- require 'erb'
+ "Evaluate a template and return its value. See `the templating docs
+ <http://docs.puppetlabs.com/guides/templating.html>`_ for more information.
+ Note that if multiple templates are specified, their output is all
+ concatenated and returned as the output of the function.") do |vals|
+ require 'erb'
- vals.collect do |file|
- # Use a wrapper, so the template can't get access to the full
- # Scope object.
- debug "Retrieving template #{file}"
+ vals.collect do |file|
+ # Use a wrapper, so the template can't get access to the full
+ # Scope object.
+ debug "Retrieving template #{file}"
- wrapper = Puppet::Parser::TemplateWrapper.new(self)
- wrapper.file = file
- begin
- wrapper.result
- rescue => detail
- raise Puppet::ParseError,
- "Failed to parse template #{file}: #{detail}"
- end
- end.join("")
+ wrapper = Puppet::Parser::TemplateWrapper.new(self)
+ wrapper.file = file
+ begin
+ wrapper.result
+ rescue => detail
+ raise Puppet::ParseError,
+ "Failed to parse template #{file}: #{detail}"
+ end
+ end.join("")
end
diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb
index b8d39af96..b38406532 100644
--- a/lib/puppet/parser/functions/versioncmp.rb
+++ b/lib/puppet/parser/functions/versioncmp.rb
@@ -1,34 +1,34 @@
require 'puppet/util/package'
- Puppet::Parser::Functions::newfunction(
- :versioncmp, :type => :rvalue,
+ Puppet::Parser::Functions::newfunction(
+ :versioncmp, :type => :rvalue,
- :doc => "Compares two versions
+ :doc => "Compares two versions
Prototype::
- \$result = versioncmp(a, b)
+ \$result = versioncmp(a, b)
- where a and b are arbitrary version strings
+ where a and b are arbitrary version strings
This functions returns a number::
- * > 0 if version a is greater than version b
- * == 0 if both version are equals
- * < 0 if version a is less than version b
+ * > 0 if version a is greater than version b
+ * == 0 if both version are equals
+ * < 0 if version a is less than version b
Example::
- if versioncmp('2.6-1', '2.4.5') > 0 {
- notice('2.6-1 is > than 2.4.5')
- }
+ if versioncmp('2.6-1', '2.4.5') > 0 {
+ notice('2.6-1 is > than 2.4.5')
+ }
") do |args|
- unless args.length == 2
- raise Puppet::ParseError, "versioncmp should have 2 arguments"
- end
+ unless args.length == 2
+ raise Puppet::ParseError, "versioncmp should have 2 arguments"
+ end
- return Puppet::Util::Package.versioncmp(args[0], args[1])
+ return Puppet::Util::Package.versioncmp(args[0], args[1])
end
diff --git a/lib/puppet/parser/grammar.ra b/lib/puppet/parser/grammar.ra
index 9fa8f5069..7a316d4d7 100644
--- a/lib/puppet/parser/grammar.ra
+++ b/lib/puppet/parser/grammar.ra
@@ -15,73 +15,73 @@ token MATCH NOMATCH REGEX IN_EDGE OUT_EDGE IN_EDGE_SUB OUT_EDGE_SUB
token IN
prechigh
- right NOT
- nonassoc UMINUS
- left IN MATCH NOMATCH
- left TIMES DIV
- left MINUS PLUS
- left LSHIFT RSHIFT
- left NOTEQUAL ISEQUAL
- left GREATEREQUAL GREATERTHAN LESSTHAN LESSEQUAL
- left AND
- left OR
+ right NOT
+ nonassoc UMINUS
+ left IN MATCH NOMATCH
+ left TIMES DIV
+ left MINUS PLUS
+ left LSHIFT RSHIFT
+ left NOTEQUAL ISEQUAL
+ left GREATEREQUAL GREATERTHAN LESSTHAN LESSEQUAL
+ left AND
+ left OR
preclow
rule
program: statements {
- if val[0]
- # Make sure we always return an array.
- if val[0].is_a?(AST::ASTArray)
- if val[0].children.empty?
- result = nil
- else
- result = val[0]
- end
- else
- result = aryfy(val[0])
- end
- else
+ if val[0]
+ # Make sure we always return an array.
+ if val[0].is_a?(AST::ASTArray)
+ if val[0].children.empty?
result = nil
+ else
+ result = val[0]
+ end
+ else
+ result = aryfy(val[0])
end
+ else
+ result = nil
+ end
}
- | nil
+ | nil
statements: statement
- | statements statement {
- if val[0] and val[1]
- if val[0].instance_of?(AST::ASTArray)
- val[0].push(val[1])
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0],val[1]]
- end
- elsif obj = (val[0] || val[1])
- result = obj
- else result = nil
+ | statements statement {
+ if val[0] and val[1]
+ if val[0].instance_of?(AST::ASTArray)
+ val[0].push(val[1])
+ result = val[0]
+ else
+ result = ast AST::ASTArray, :children => [val[0],val[1]]
end
+ elsif obj = (val[0] || val[1])
+ result = obj
+ else result = nil
+ end
}
# The main list of valid statements
statement: resource
- | virtualresource
- | collection
- | assignment
- | casestatement
- | ifstatement_begin
- | import
- | fstatement
- | definition
- | hostclass
- | nodedef
- | resourceoverride
- | append
- | relationship
+ | virtualresource
+ | collection
+ | assignment
+ | casestatement
+ | ifstatement_begin
+ | import
+ | fstatement
+ | definition
+ | hostclass
+ | nodedef
+ | resourceoverride
+ | append
+ | relationship
relationship: relationship_side edge relationship_side {
- result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context)
+ result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context)
}
- | relationship edge relationship_side {
- result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context)
+ | relationship edge relationship_side {
+ result = AST::Relationship.new(val[0], val[2], val[1][:value], ast_context)
}
relationship_side: resource | resourceref | collection
@@ -89,411 +89,411 @@ relationship_side: resource | resourceref | collection
edge: IN_EDGE | OUT_EDGE | IN_EDGE_SUB | OUT_EDGE_SUB
fstatement: NAME LPAREN funcvalues RPAREN {
- args = aryfy(val[2])
- result = ast AST::Function,
- :name => val[0][:value],
- :line => val[0][:line],
- :arguments => args,
- :ftype => :statement
+ args = aryfy(val[2])
+ result = ast AST::Function,
+ :name => val[0][:value],
+ :line => val[0][:line],
+ :arguments => args,
+ :ftype => :statement
}
| NAME LPAREN funcvalues COMMA RPAREN {
- args = aryfy(val[2])
- result = ast AST::Function,
- :name => val[0][:value],
- :line => val[0][:line],
- :arguments => args,
- :ftype => :statement
+ args = aryfy(val[2])
+ result = ast AST::Function,
+ :name => val[0][:value],
+ :line => val[0][:line],
+ :arguments => args,
+ :ftype => :statement
} | NAME LPAREN RPAREN {
+ result = ast AST::Function,
+ :name => val[0][:value],
+ :line => val[0][:line],
+ :arguments => AST::ASTArray.new({}),
+ :ftype => :statement
+}
+ | NAME funcvalues {
+ args = aryfy(val[1])
result = ast AST::Function,
- :name => val[0][:value],
- :line => val[0][:line],
- :arguments => AST::ASTArray.new({}),
- :ftype => :statement
-}
- | NAME funcvalues {
- args = aryfy(val[1])
- result = ast AST::Function,
- :name => val[0][:value],
- :line => val[0][:line],
- :arguments => args,
- :ftype => :statement
+ :name => val[0][:value],
+ :line => val[0][:line],
+ :arguments => args,
+ :ftype => :statement
}
funcvalues: namestring
- | resourceref
- | funcvalues COMMA namestring {
- result = aryfy(val[0], val[2])
- result.line = @lexer.line
- result.file = @lexer.file
-}
- | funcvalues COMMA resourceref {
- unless val[0].is_a?(AST::ASTArray)
- val[0] = aryfy(val[0])
- end
+ | resourceref
+ | funcvalues COMMA namestring {
+ result = aryfy(val[0], val[2])
+ result.line = @lexer.line
+ result.file = @lexer.file
+}
+ | funcvalues COMMA resourceref {
+ unless val[0].is_a?(AST::ASTArray)
+ val[0] = aryfy(val[0])
+ end
- val[0].push(val[2])
+ val[0].push(val[2])
- result = val[0]
+ result = val[0]
}
# This is *almost* an rvalue, but I couldn't get a full
# rvalue to work without scads of shift/reduce conflicts.
namestring: name
- | variable
- | type
- | boolean
- | funcrvalue
- | selector
- | quotedtext
- | hasharrayaccesses
- | CLASSNAME {
- result = ast AST::Name, :value => val[0][:value]
- }
+ | variable
+ | type
+ | boolean
+ | funcrvalue
+ | selector
+ | quotedtext
+ | hasharrayaccesses
+ | CLASSNAME {
+ result = ast AST::Name, :value => val[0][:value]
+ }
resource: classname LBRACE resourceinstances endsemi RBRACE {
- @lexer.commentpop
- array = val[2]
- array = [array] if array.instance_of?(AST::ResourceInstance)
- result = ast AST::ASTArray
-
- # this iterates across each specified resourceinstance
- array.each { |instance|
- raise Puppet::Dev, "Got something that isn't an instance" unless instance.instance_of?(AST::ResourceInstance)
- # now, i need to somehow differentiate between those things with
- # arrays in their names, and normal things
-
- result.push ast(
- AST::Resource,
- :type => val[0],
- :title => instance[0],
-
- :parameters => instance[1])
- }
+ @lexer.commentpop
+ array = val[2]
+ array = [array] if array.instance_of?(AST::ResourceInstance)
+ result = ast AST::ASTArray
+
+ # this iterates across each specified resourceinstance
+ array.each { |instance|
+ raise Puppet::Dev, "Got something that isn't an instance" unless instance.instance_of?(AST::ResourceInstance)
+ # now, i need to somehow differentiate between those things with
+ # arrays in their names, and normal things
+
+ result.push ast(
+ AST::Resource,
+ :type => val[0],
+ :title => instance[0],
+
+ :parameters => instance[1])
+ }
} | classname LBRACE params endcomma RBRACE {
- # This is a deprecated syntax.
- error "All resource specifications require names"
+ # This is a deprecated syntax.
+ error "All resource specifications require names"
} | classref LBRACE params endcomma RBRACE {
- # a defaults setting for a type
- @lexer.commentpop
- result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2])
+ # a defaults setting for a type
+ @lexer.commentpop
+ result = ast(AST::ResourceDefaults, :type => val[0], :parameters => val[2])
}
# Override a value set elsewhere in the configuration.
resourceoverride: resourceref LBRACE anyparams endcomma RBRACE {
- @lexer.commentpop
- result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2]
+ @lexer.commentpop
+ result = ast AST::ResourceOverride, :object => val[0], :parameters => val[2]
}
# Exported and virtual resources; these don't get sent to the client
# unless they get collected elsewhere in the db.
virtualresource: at resource {
- type = val[0]
+ type = val[0]
- if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly]
- Puppet.warning addcontext("You cannot collect without storeconfigs being set")
- end
+ if (type == :exported and ! Puppet[:storeconfigs]) and ! Puppet[:parseonly]
+ Puppet.warning addcontext("You cannot collect without storeconfigs being set")
+ end
- error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults
+ error "Defaults are not virtualizable" if val[1].is_a? AST::ResourceDefaults
- method = type.to_s + "="
+ method = type.to_s + "="
- # Just mark our resources as exported and pass them through.
- if val[1].instance_of?(AST::ASTArray)
- val[1].each do |obj|
- obj.send(method, true)
- end
- else
- val[1].send(method, true)
+ # Just mark our resources as exported and pass them through.
+ if val[1].instance_of?(AST::ASTArray)
+ val[1].each do |obj|
+ obj.send(method, true)
end
+ else
+ val[1].send(method, true)
+ end
- result = val[1]
+ result = val[1]
}
at: AT { result = :virtual }
- | AT AT { result = :exported }
+ | AT AT { result = :exported }
# A collection statement. Currently supports no arguments at all, but eventually
# will, I assume.
collection: classref collectrhand LBRACE anyparams endcomma RBRACE {
- @lexer.commentpop
- Puppet.warning addcontext("Collection names must now be capitalized") if val[0] =~ /^[a-z]/
- type = val[0].downcase
- args = {:type => type}
-
- if val[1].is_a?(AST::CollExpr)
- args[:query] = val[1]
- args[:query].type = type
- args[:form] = args[:query].form
- else
- args[:form] = val[1]
- end
- if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly]
- Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored")
- end
- args[:override] = val[3]
- result = ast AST::Collection, args
-}
- | classref collectrhand {
- if val[0] =~ /^[a-z]/
- Puppet.warning addcontext("Collection names must now be capitalized")
- end
- type = val[0].downcase
- args = {:type => type }
-
- if val[1].is_a?(AST::CollExpr)
- args[:query] = val[1]
- args[:query].type = type
- args[:form] = args[:query].form
- else
- args[:form] = val[1]
- end
- if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly]
- Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored")
- end
- result = ast AST::Collection, args
+ @lexer.commentpop
+ Puppet.warning addcontext("Collection names must now be capitalized") if val[0] =~ /^[a-z]/
+ type = val[0].downcase
+ args = {:type => type}
+
+ if val[1].is_a?(AST::CollExpr)
+ args[:query] = val[1]
+ args[:query].type = type
+ args[:form] = args[:query].form
+ else
+ args[:form] = val[1]
+ end
+ if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly]
+ Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored")
+ end
+ args[:override] = val[3]
+ result = ast AST::Collection, args
+}
+ | classref collectrhand {
+ if val[0] =~ /^[a-z]/
+ Puppet.warning addcontext("Collection names must now be capitalized")
+ end
+ type = val[0].downcase
+ args = {:type => type }
+
+ if val[1].is_a?(AST::CollExpr)
+ args[:query] = val[1]
+ args[:query].type = type
+ args[:form] = args[:query].form
+ else
+ args[:form] = val[1]
+ end
+ if args[:form] == :exported and ! Puppet[:storeconfigs] and ! Puppet[:parseonly]
+ Puppet.warning addcontext("You cannot collect exported resources without storeconfigs being set; the collection will be ignored")
+ end
+ result = ast AST::Collection, args
}
collectrhand: LCOLLECT collstatements RCOLLECT {
- if val[1]
- result = val[1]
- result.form = :virtual
- else
- result = :virtual
- end
+ if val[1]
+ result = val[1]
+ result.form = :virtual
+ else
+ result = :virtual
+ end
}
- | LLCOLLECT collstatements RRCOLLECT {
- if val[1]
- result = val[1]
- result.form = :exported
- else
- result = :exported
- end
+ | LLCOLLECT collstatements RRCOLLECT {
+ if val[1]
+ result = val[1]
+ result.form = :exported
+ else
+ result = :exported
+ end
}
# A mini-language for handling collection comparisons. This is organized
# to avoid the need for precedence indications.
collstatements: nil
- | collstatement
- | collstatements colljoin collstatement {
- result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
+ | collstatement
+ | collstatements colljoin collstatement {
+ result = ast AST::CollExpr, :test1 => val[0], :oper => val[1], :test2 => val[2]
}
collstatement: collexpr
- | LPAREN collstatements RPAREN {
- result = val[1]
- result.parens = true
+ | LPAREN collstatements RPAREN {
+ result = val[1]
+ result.parens = true
}
colljoin: AND { result=val[0][:value] }
- | OR { result=val[0][:value] }
+ | OR { result=val[0][:value] }
collexpr: colllval ISEQUAL simplervalue {
+ result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2]
+ #result = ast AST::CollExpr
+ #result.push *val
+}
+ | colllval NOTEQUAL simplervalue {
result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2]
#result = ast AST::CollExpr
#result.push *val
}
- | colllval NOTEQUAL simplervalue {
- result = ast AST::CollExpr, :test1 => val[0], :oper => val[1][:value], :test2 => val[2]
- #result = ast AST::CollExpr
- #result.push *val
-}
colllval: variable
- | name
+ | name
resourceinst: resourcename COLON params endcomma {
- result = ast AST::ResourceInstance, :children => [val[0],val[2]]
+ result = ast AST::ResourceInstance, :children => [val[0],val[2]]
}
resourceinstances: resourceinst
- | resourceinstances SEMIC resourceinst {
- if val[0].instance_of?(AST::ResourceInstance)
- result = ast AST::ASTArray, :children => [val[0],val[2]]
- else
- val[0].push val[2]
- result = val[0]
- end
+ | resourceinstances SEMIC resourceinst {
+ if val[0].instance_of?(AST::ResourceInstance)
+ result = ast AST::ASTArray, :children => [val[0],val[2]]
+ else
+ val[0].push val[2]
+ result = val[0]
+ end
}
endsemi: # nothing
- | SEMIC
+ | SEMIC
undef: UNDEF {
- result = ast AST::Undef, :value => :undef
+ result = ast AST::Undef, :value => :undef
}
name: NAME {
- result = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
+ result = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
}
type: CLASSREF {
- result = ast AST::Type, :value => val[0][:value], :line => val[0][:line]
+ result = ast AST::Type, :value => val[0][:value], :line => val[0][:line]
}
resourcename: quotedtext
- | name
- | type
- | selector
- | variable
- | array
- | hasharrayaccesses
+ | name
+ | type
+ | selector
+ | variable
+ | array
+ | hasharrayaccesses
assignment: VARIABLE EQUALS expression {
- raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/
- # this is distinct from referencing a variable
- variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
- result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line]
+ raise Puppet::ParseError, "Cannot assign to variables in other namespaces" if val[0][:value] =~ /::/
+ # this is distinct from referencing a variable
+ variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
+ result = ast AST::VarDef, :name => variable, :value => val[2], :line => val[0][:line]
}
- | hasharrayaccess EQUALS expression {
- result = ast AST::VarDef, :name => val[0], :value => val[2]
+ | hasharrayaccess EQUALS expression {
+ result = ast AST::VarDef, :name => val[0], :value => val[2]
}
append: VARIABLE APPENDS expression {
- variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
- result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line]
+ variable = ast AST::Name, :value => val[0][:value], :line => val[0][:line]
+ result = ast AST::VarDef, :name => variable, :value => val[2], :append => true, :line => val[0][:line]
}
params: # nothing
{
- result = ast AST::ASTArray
+ result = ast AST::ASTArray
}
- | param { result = val[0] }
- | params COMMA param {
- if val[0].instance_of?(AST::ASTArray)
- val[0].push(val[2])
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0],val[2]]
- end
+ | param { result = val[0] }
+ | params COMMA param {
+ if val[0].instance_of?(AST::ASTArray)
+ val[0].push(val[2])
+ result = val[0]
+ else
+ result = ast AST::ASTArray, :children => [val[0],val[2]]
+ end
}
param: NAME FARROW rvalue {
- result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2]
+ result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2]
}
addparam: NAME PARROW rvalue {
- result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2],
- :add => true
+ result = ast AST::ResourceParam, :param => val[0][:value], :line => val[0][:line], :value => val[2],
+ :add => true
}
anyparam: param
- | addparam
+ | addparam
anyparams: # nothing
{
- result = ast AST::ASTArray
+ result = ast AST::ASTArray
}
- | anyparam { result = val[0] }
- | anyparams COMMA anyparam {
- if val[0].instance_of?(AST::ASTArray)
- val[0].push(val[2])
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0],val[2]]
- end
+ | anyparam { result = val[0] }
+ | anyparams COMMA anyparam {
+ if val[0].instance_of?(AST::ASTArray)
+ val[0].push(val[2])
+ result = val[0]
+ else
+ result = ast AST::ASTArray, :children => [val[0],val[2]]
+ end
}
rvalues: rvalue
- | rvalues comma rvalue {
- if val[0].instance_of?(AST::ASTArray)
- result = val[0].push(val[2])
- else
- result = ast AST::ASTArray, :children => [val[0],val[2]]
- end
+ | rvalues comma rvalue {
+ if val[0].instance_of?(AST::ASTArray)
+ result = val[0].push(val[2])
+ else
+ result = ast AST::ASTArray, :children => [val[0],val[2]]
+ end
}
simplervalue: quotedtext
- | name
- | type
- | boolean
- | selector
- | variable
+ | name
+ | type
+ | boolean
+ | selector
+ | variable
rvalue: quotedtext
- | name
- | type
- | boolean
- | selector
- | variable
- | array
- | hash
- | hasharrayaccesses
- | resourceref
- | funcrvalue
- | undef
+ | name
+ | type
+ | boolean
+ | selector
+ | variable
+ | array
+ | hash
+ | hasharrayaccesses
+ | resourceref
+ | funcrvalue
+ | undef
# We currently require arguments in these functions.
funcrvalue: NAME LPAREN funcvalues RPAREN {
- args = aryfy(val[2])
- result = ast AST::Function,
- :name => val[0][:value], :line => val[0][:line],
- :arguments => args,
- :ftype => :rvalue
+ args = aryfy(val[2])
+ result = ast AST::Function,
+ :name => val[0][:value], :line => val[0][:line],
+ :arguments => args,
+ :ftype => :rvalue
} | NAME LPAREN RPAREN {
- result = ast AST::Function,
- :name => val[0][:value], :line => val[0][:line],
- :arguments => AST::ASTArray.new({}),
- :ftype => :rvalue
+ result = ast AST::Function,
+ :name => val[0][:value], :line => val[0][:line],
+ :arguments => AST::ASTArray.new({}),
+ :ftype => :rvalue
}
quotedtext: STRING { result = ast AST::String, :value => val[0][:value], :line => val[0][:line] }
- | DQPRE dqrval { result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] }
+ | DQPRE dqrval { result = ast AST::Concat, :value => [ast(AST::String,val[0])]+val[1], :line => val[0][:line] }
dqrval: expression dqtail { result = [val[0]] + val[1] }
dqtail: DQPOST { result = [ast(AST::String,val[0])] }
- | DQMID dqrval { result = [ast(AST::String,val[0])] + val[1] }
+ | DQMID dqrval { result = [ast(AST::String,val[0])] + val[1] }
boolean: BOOLEAN {
- result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line]
+ result = ast AST::Boolean, :value => val[0][:value], :line => val[0][:line]
}
resourceref: NAME LBRACK rvalues RBRACK {
- Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized")
- result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2]
+ Puppet.warning addcontext("Deprecation notice: Resource references should now be capitalized")
+ result = ast AST::ResourceReference, :type => val[0][:value], :line => val[0][:line], :title => val[2]
} | classref LBRACK rvalues RBRACK {
- result = ast AST::ResourceReference, :type => val[0], :title => val[2]
+ result = ast AST::ResourceReference, :type => val[0], :title => val[2]
}
ifstatement_begin: IF ifstatement {
- result = val[1]
+ result = val[1]
}
ifstatement: expression LBRACE statements RBRACE else {
- @lexer.commentpop
- args = {
- :test => val[0],
- :statements => val[2]
- }
+ @lexer.commentpop
+ args = {
+ :test => val[0],
+ :statements => val[2]
+ }
- args[:else] = val[4] if val[4]
+ args[:else] = val[4] if val[4]
- result = ast AST::IfStatement, args
+ result = ast AST::IfStatement, args
}
- | expression LBRACE RBRACE else {
- @lexer.commentpop
- args = {
- :test => val[0],
- :statements => ast(AST::Nop)
- }
+ | expression LBRACE RBRACE else {
+ @lexer.commentpop
+ args = {
+ :test => val[0],
+ :statements => ast(AST::Nop)
+ }
- args[:else] = val[3] if val[3]
+ args[:else] = val[3] if val[3]
- result = ast AST::IfStatement, args
+ result = ast AST::IfStatement, args
}
else: # nothing
- | ELSIF ifstatement {
- result = ast AST::Else, :statements => val[1]
+ | ELSIF ifstatement {
+ result = ast AST::Else, :statements => val[1]
}
- | ELSE LBRACE statements RBRACE {
- @lexer.commentpop
- result = ast AST::Else, :statements => val[2]
+ | ELSE LBRACE statements RBRACE {
+ @lexer.commentpop
+ result = ast AST::Else, :statements => val[2]
}
- | ELSE LBRACE RBRACE {
- @lexer.commentpop
- result = ast AST::Else, :statements => ast(AST::Nop)
+ | ELSE LBRACE RBRACE {
+ @lexer.commentpop
+ result = ast AST::Else, :statements => ast(AST::Nop)
}
# Unlike yacc/bison, it seems racc
@@ -509,343 +509,343 @@ else: # nothing
# per operator :-(
expression: rvalue
- | expression IN rvalue {
- result = ast AST::InOperator, :lval => val[0], :rval => val[2]
+ | expression IN rvalue {
+ result = ast AST::InOperator, :lval => val[0], :rval => val[2]
}
- | expression MATCH regex {
- result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression MATCH regex {
+ result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression NOMATCH regex {
- result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression NOMATCH regex {
+ result = ast AST::MatchOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression PLUS expression {
- result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression PLUS expression {
+ result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression MINUS expression {
- result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression MINUS expression {
+ result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression DIV expression {
- result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression DIV expression {
+ result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression TIMES expression {
- result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression TIMES expression {
+ result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression LSHIFT expression {
- result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression LSHIFT expression {
+ result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression RSHIFT expression {
- result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression RSHIFT expression {
+ result = ast AST::ArithmeticOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | MINUS expression =UMINUS {
- result = ast AST::Minus, :value => val[1]
+ | MINUS expression =UMINUS {
+ result = ast AST::Minus, :value => val[1]
}
- | expression NOTEQUAL expression {
- result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression NOTEQUAL expression {
+ result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression ISEQUAL expression {
- result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression ISEQUAL expression {
+ result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression GREATERTHAN expression {
- result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression GREATERTHAN expression {
+ result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression GREATEREQUAL expression {
- result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression GREATEREQUAL expression {
+ result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression LESSTHAN expression {
- result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression LESSTHAN expression {
+ result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression LESSEQUAL expression {
- result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression LESSEQUAL expression {
+ result = ast AST::ComparisonOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | NOT expression {
- result = ast AST::Not, :value => val[1]
+ | NOT expression {
+ result = ast AST::Not, :value => val[1]
}
- | expression AND expression {
- result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression AND expression {
+ result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | expression OR expression {
- result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
+ | expression OR expression {
+ result = ast AST::BooleanOperator, :operator => val[1][:value], :lval => val[0], :rval => val[2]
}
- | LPAREN expression RPAREN {
- result = val[1]
+ | LPAREN expression RPAREN {
+ result = val[1]
}
casestatement: CASE rvalue LBRACE caseopts RBRACE {
- @lexer.commentpop
- options = val[3]
- options = ast AST::ASTArray, :children => [val[3]] unless options.instance_of?(AST::ASTArray)
- result = ast AST::CaseStatement, :test => val[1], :options => options
+ @lexer.commentpop
+ options = val[3]
+ options = ast AST::ASTArray, :children => [val[3]] unless options.instance_of?(AST::ASTArray)
+ result = ast AST::CaseStatement, :test => val[1], :options => options
}
caseopts: caseopt
- | caseopts caseopt {
- if val[0].instance_of?(AST::ASTArray)
- val[0].push val[1]
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0], val[1]]
- end
+ | caseopts caseopt {
+ if val[0].instance_of?(AST::ASTArray)
+ val[0].push val[1]
+ result = val[0]
+ else
+ result = ast AST::ASTArray, :children => [val[0], val[1]]
+ end
}
caseopt: casevalues COLON LBRACE statements RBRACE {
- @lexer.commentpop
- result = ast AST::CaseOpt, :value => val[0], :statements => val[3]
+ @lexer.commentpop
+ result = ast AST::CaseOpt, :value => val[0], :statements => val[3]
} | casevalues COLON LBRACE RBRACE {
- @lexer.commentpop
+ @lexer.commentpop
- result = ast(
- AST::CaseOpt,
- :value => val[0],
+ result = ast(
+ AST::CaseOpt,
+ :value => val[0],
- :statements => ast(AST::ASTArray)
- )
+ :statements => ast(AST::ASTArray)
+ )
}
casevalues: selectlhand
- | casevalues COMMA selectlhand {
- if val[0].instance_of?(AST::ASTArray)
- val[0].push(val[2])
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0],val[2]]
- end
+ | casevalues COMMA selectlhand {
+ if val[0].instance_of?(AST::ASTArray)
+ val[0].push(val[2])
+ result = val[0]
+ else
+ result = ast AST::ASTArray, :children => [val[0],val[2]]
+ end
}
selector: selectlhand QMARK svalues {
- result = ast AST::Selector, :param => val[0], :values => val[2]
+ result = ast AST::Selector, :param => val[0], :values => val[2]
}
svalues: selectval
- | LBRACE sintvalues endcomma RBRACE {
- @lexer.commentpop
- result = val[1]
+ | LBRACE sintvalues endcomma RBRACE {
+ @lexer.commentpop
+ result = val[1]
}
sintvalues: selectval
- | sintvalues comma selectval {
- if val[0].instance_of?(AST::ASTArray)
- val[0].push(val[2])
- result = val[0]
- else
- result = ast AST::ASTArray, :children => [val[0],val[2]]
- end
+ | sintvalues comma selectval {
+ if val[0].instance_of?(AST::ASTArray)
+ val[0].push(val[2])
+ result = val[0]
+ else
+ result = ast AST::ASTArray, :children => [val[0],val[2]]
+ end
}
selectval: selectlhand FARROW rvalue {
- result = ast AST::ResourceParam, :param => val[0], :value => val[2]
+ result = ast AST::ResourceParam, :param => val[0], :value => val[2]
}
selectlhand: name
- | type
- | quotedtext
- | variable
- | funcrvalue
- | boolean
- | undef
- | DEFAULT {
- result = ast AST::Default, :value => val[0][:value], :line => val[0][:line]
+ | type
+ | quotedtext
+ | variable
+ | funcrvalue
+ | boolean
+ | undef
+ | DEFAULT {
+ result = ast AST::Default, :value => val[0][:value], :line => val[0][:line]
}
- | regex
+ | regex
# These are only used for importing, and we don't interpolate there.
string: STRING { result = [val[0][:value]] }
strings: string
- | strings COMMA string { result = val[0] += val[2] }
+ | strings COMMA string { result = val[0] += val[2] }
import: IMPORT strings {
- val[1].each do |file|
- import(file)
- end
+ val[1].each do |file|
+ import(file)
+ end
- result = AST::ASTArray.new(:children => [])
+ result = AST::ASTArray.new(:children => [])
}
# Disable definition inheritance for now. 8/27/06, luke
#definition: DEFINE NAME argumentlist parent LBRACE statements RBRACE {
definition: DEFINE classname argumentlist LBRACE statements RBRACE {
- @lexer.commentpop
- newdefine classname(val[1]), :arguments => val[2], :code => val[4], :line => val[0][:line]
- @lexer.indefine = false
- result = nil
+ @lexer.commentpop
+ newdefine classname(val[1]), :arguments => val[2], :code => val[4], :line => val[0][:line]
+ @lexer.indefine = false
+ result = nil
#} | DEFINE NAME argumentlist parent LBRACE RBRACE {
} | DEFINE classname argumentlist LBRACE RBRACE {
- @lexer.commentpop
- newdefine classname(val[1]), :arguments => val[2], :line => val[0][:line]
- @lexer.indefine = false
- result = nil
+ @lexer.commentpop
+ newdefine classname(val[1]), :arguments => val[2], :line => val[0][:line]
+ @lexer.indefine = false
+ result = nil
}
#hostclass: CLASS NAME argumentlist parent LBRACE statements RBRACE {
hostclass: CLASS classname argumentlist classparent LBRACE statements RBRACE {
- @lexer.commentpop
- # Our class gets defined in the parent namespace, not our own.
- @lexer.namepop
- newclass classname(val[1]), :arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line]
- result = nil
+ @lexer.commentpop
+ # Our class gets defined in the parent namespace, not our own.
+ @lexer.namepop
+ newclass classname(val[1]), :arguments => val[2], :parent => val[3], :code => val[5], :line => val[0][:line]
+ result = nil
} | CLASS classname argumentlist classparent LBRACE RBRACE {
- @lexer.commentpop
- # Our class gets defined in the parent namespace, not our own.
- @lexer.namepop
- newclass classname(val[1]), :arguments => val[2], :parent => val[3], :line => val[0][:line]
- result = nil
+ @lexer.commentpop
+ # Our class gets defined in the parent namespace, not our own.
+ @lexer.namepop
+ newclass classname(val[1]), :arguments => val[2], :parent => val[3], :line => val[0][:line]
+ result = nil
}
nodedef: NODE hostnames nodeparent LBRACE statements RBRACE {
- @lexer.commentpop
- newnode val[1], :parent => val[2], :code => val[4], :line => val[0][:line]
- result = nil
+ @lexer.commentpop
+ newnode val[1], :parent => val[2], :code => val[4], :line => val[0][:line]
+ result = nil
} | NODE hostnames nodeparent LBRACE RBRACE {
- @lexer.commentpop
- newnode val[1], :parent => val[2], :line => val[0][:line]
- result = nil
+ @lexer.commentpop
+ newnode val[1], :parent => val[2], :line => val[0][:line]
+ result = nil
}
classref: CLASSREF { result = val[0][:value] }
classname: NAME { result = val[0][:value] }
- | CLASSNAME { result = val[0][:value] }
- | CLASS { result = "class" }
+ | CLASSNAME { result = val[0][:value] }
+ | CLASS { result = "class" }
# Multiple hostnames, as used for node names. These are all literal
# strings, not AST objects.
hostnames: nodename
- | hostnames COMMA nodename {
- result = val[0]
- result = [result] unless result.is_a?(Array)
- result << val[2]
+ | hostnames COMMA nodename {
+ result = val[0]
+ result = [result] unless result.is_a?(Array)
+ result << val[2]
}
nodename: hostname {
- result = ast AST::HostName, :value => val[0]
+ result = ast AST::HostName, :value => val[0]
}
hostname: NAME { result = val[0][:value] }
- | STRING { result = val[0][:value] }
- | DEFAULT { result = val[0][:value] }
- | regex
+ | STRING { result = val[0][:value] }
+ | DEFAULT { result = val[0][:value] }
+ | regex
nil: {
- result = nil
+ result = nil
}
nothing: {
- result = ast AST::ASTArray, :children => []
+ result = ast AST::ASTArray, :children => []
}
argumentlist: nil
- | LPAREN nothing RPAREN {
- result = nil
+ | LPAREN nothing RPAREN {
+ result = nil
}
- | LPAREN arguments RPAREN {
- result = val[1]
- result = [result] unless result[0].is_a?(Array)
+ | LPAREN arguments RPAREN {
+ result = val[1]
+ result = [result] unless result[0].is_a?(Array)
}
arguments: argument
- | arguments COMMA argument {
- result = val[0]
- result = [result] unless result[0].is_a?(Array)
- result << val[2]
+ | arguments COMMA argument {
+ result = val[0]
+ result = [result] unless result[0].is_a?(Array)
+ result << val[2]
}
argument: NAME EQUALS rvalue {
- Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype")
- result = [val[0][:value], val[2]]
+ Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype")
+ result = [val[0][:value], val[2]]
}
- | NAME {
- Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype")
- result = [val[0][:value]]
+ | NAME {
+ Puppet.warning addcontext("Deprecation notice: must now include '$' in prototype")
+ result = [val[0][:value]]
} | VARIABLE EQUALS rvalue {
- result = [val[0][:value], val[2]]
+ result = [val[0][:value], val[2]]
} | VARIABLE {
- result = [val[0][:value]]
+ result = [val[0][:value]]
}
nodeparent: nil
- | INHERITS hostname {
- result = val[1]
+ | INHERITS hostname {
+ result = val[1]
}
classparent: nil
- | INHERITS classnameordefault {
- result = val[1]
+ | INHERITS classnameordefault {
+ result = val[1]
}
classnameordefault: classname | DEFAULT
variable: VARIABLE {
- result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line]
+ result = ast AST::Variable, :value => val[0][:value], :line => val[0][:line]
}
array: LBRACK rvalues RBRACK {
- if val[1].instance_of?(AST::ASTArray)
- result = val[1]
- else
- result = ast AST::ASTArray, :children => [val[1]]
- end
+ if val[1].instance_of?(AST::ASTArray)
+ result = val[1]
+ else
+ result = ast AST::ASTArray, :children => [val[1]]
+ end
}
- | LBRACK rvalues COMMA RBRACK {
- if val[1].instance_of?(AST::ASTArray)
- result = val[1]
- else
- result = ast AST::ASTArray, :children => [val[1]]
- end
+ | LBRACK rvalues COMMA RBRACK {
+ if val[1].instance_of?(AST::ASTArray)
+ result = val[1]
+ else
+ result = ast AST::ASTArray, :children => [val[1]]
+ end
} | LBRACK RBRACK {
- result = ast AST::ASTArray
+ result = ast AST::ASTArray
}
comma: FARROW
- | COMMA
+ | COMMA
endcomma: # nothing
- | COMMA { result = nil }
+ | COMMA { result = nil }
regex: REGEX {
- result = ast AST::Regex, :value => val[0][:value]
+ result = ast AST::Regex, :value => val[0][:value]
}
hash: LBRACE hashpairs RBRACE {
- if val[1].instance_of?(AST::ASTHash)
- result = val[1]
- else
- result = ast AST::ASTHash, { :value => val[1] }
- end
+ if val[1].instance_of?(AST::ASTHash)
+ result = val[1]
+ else
+ result = ast AST::ASTHash, { :value => val[1] }
+ end
}
- | LBRACE hashpairs COMMA RBRACE {
- if val[1].instance_of?(AST::ASTHash)
- result = val[1]
- else
- result = ast AST::ASTHash, { :value => val[1] }
- end
+ | LBRACE hashpairs COMMA RBRACE {
+ if val[1].instance_of?(AST::ASTHash)
+ result = val[1]
+ else
+ result = ast AST::ASTHash, { :value => val[1] }
+ end
} | LBRACE RBRACE {
- result = ast AST::ASTHash
+ result = ast AST::ASTHash
}
hashpairs: hashpair
- | hashpairs COMMA hashpair {
- if val[0].instance_of?(AST::ASTHash)
- result = val[0].merge(val[2])
- else
- result = ast AST::ASTHash, :value => val[0]
- result.merge(val[2])
- end
+ | hashpairs COMMA hashpair {
+ if val[0].instance_of?(AST::ASTHash)
+ result = val[0].merge(val[2])
+ else
+ result = ast AST::ASTHash, :value => val[0]
+ result.merge(val[2])
+ end
}
hashpair: key FARROW rvalue {
- result = ast AST::ASTHash, { :value => { val[0] => val[2] } }
+ result = ast AST::ASTHash, { :value => { val[0] => val[2] } }
}
key: NAME { result = val[0][:value] }
- | quotedtext { result = val[0] }
+ | quotedtext { result = val[0] }
hasharrayaccess: VARIABLE LBRACK rvalue RBRACK {
- result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2]
+ result = ast AST::HashOrArrayAccess, :variable => val[0][:value], :key => val[2]
}
hasharrayaccesses: hasharrayaccess
- | hasharrayaccess LBRACK rvalue RBRACK {
- result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2]
+ | hasharrayaccess LBRACK rvalue RBRACK {
+ result = ast AST::HashOrArrayAccess, :variable => val[0], :key => val[2]
}
end
@@ -856,9 +856,9 @@ require 'puppet/parser/lexer'
require 'puppet/parser/ast'
module Puppet
- class ParseError < Puppet::Error; end
- class ImportError < Racc::ParseError; end
- class AlreadyImportedError < ImportError; end
+ class ParseError < Puppet::Error; end
+ class ImportError < Racc::ParseError; end
+ class AlreadyImportedError < ImportError; end
end
---- inner ----
diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb
index 0c95142f9..6a9f1cfc4 100644
--- a/lib/puppet/parser/lexer.rb
+++ b/lib/puppet/parser/lexer.rb
@@ -5,573 +5,573 @@ require 'puppet'
module Puppet
- class LexError < RuntimeError; end
+ class LexError < RuntimeError; end
end
module Puppet::Parser; end
class Puppet::Parser::Lexer
- attr_reader :last, :file, :lexing_context, :token_queue
+ attr_reader :last, :file, :lexing_context, :token_queue
- attr_accessor :line, :indefine
+ attr_accessor :line, :indefine
- def lex_error msg
- raise Puppet::LexError.new(msg)
- end
-
- class Token
- attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate
-
- def initialize(regex, name)
- if regex.is_a?(String)
- @name, @string = name, regex
- @regex = Regexp.new(Regexp.escape(@string))
- else
- @name, @regex = name, regex
- end
- end
-
- # MQR: Why not just alias?
- %w{skip accumulate}.each do |method|
- define_method(method+"?") do
- self.send(method)
- end
- end
-
- def to_s
- if self.string
- @string
- else
- @name.to_s
- end
- end
-
- def acceptable?(context={})
- # By default tokens are aceeptable in any context
- true
- end
- end
-
- # Maintain a list of tokens.
- class TokenList
- attr_reader :regex_tokens, :string_tokens
-
- def [](name)
- @tokens[name]
- end
-
- # Create a new token.
- def add_token(name, regex, options = {}, &block)
- token = Token.new(regex, name)
- raise(ArgumentError, "Token #{name} already exists") if @tokens.include?(name)
- @tokens[token.name] = token
- if token.string
- @string_tokens << token
- @tokens_by_string[token.string] = token
- else
- @regex_tokens << token
- end
-
- options.each do |name, option|
- token.send(name.to_s + "=", option)
- end
-
- token.meta_def(:convert, &block) if block_given?
-
- token
- end
-
- def initialize
- @tokens = {}
- @regex_tokens = []
- @string_tokens = []
- @tokens_by_string = {}
- end
-
- # Look up a token by its value, rather than name.
- def lookup(string)
- @tokens_by_string[string]
- end
-
- # Define more tokens.
- def add_tokens(hash)
- hash.each do |regex, name|
- add_token(name, regex)
- end
- end
-
- # Sort our tokens by length, so we know once we match, we're done.
- # This helps us avoid the O(n^2) nature of token matching.
- def sort_tokens
- @string_tokens.sort! { |a, b| b.string.length <=> a.string.length }
- end
- end
+ def lex_error msg
+ raise Puppet::LexError.new(msg)
+ end
- TOKENS = TokenList.new
-
- TOKENS.add_tokens(
-
- '[' => :LBRACK,
- ']' => :RBRACK,
- '{' => :LBRACE,
- '}' => :RBRACE,
- '(' => :LPAREN,
-
- ')' => :RPAREN,
- '=' => :EQUALS,
- '+=' => :APPENDS,
- '==' => :ISEQUAL,
- '>=' => :GREATEREQUAL,
- '>' => :GREATERTHAN,
- '<' => :LESSTHAN,
- '<=' => :LESSEQUAL,
- '!=' => :NOTEQUAL,
- '!' => :NOT,
- ',' => :COMMA,
- '.' => :DOT,
- ':' => :COLON,
- '@' => :AT,
- '<<|' => :LLCOLLECT,
- '->' => :IN_EDGE,
- '<-' => :OUT_EDGE,
- '~>' => :IN_EDGE_SUB,
- '<~' => :OUT_EDGE_SUB,
- '|>>' => :RRCOLLECT,
- '<|' => :LCOLLECT,
- '|>' => :RCOLLECT,
- ';' => :SEMIC,
- '?' => :QMARK,
- '\\' => :BACKSLASH,
- '=>' => :FARROW,
- '+>' => :PARROW,
- '+' => :PLUS,
- '-' => :MINUS,
- '/' => :DIV,
- '*' => :TIMES,
- '<<' => :LSHIFT,
- '>>' => :RSHIFT,
- '=~' => :MATCH,
- '!~' => :NOMATCH,
- %r{([a-z][-\w]*)?(::[a-z][-\w]*)+} => :CLASSNAME, # Require '::' in the class name, else we'd compete with NAME
- %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF,
- "<string>" => :STRING,
- "<dqstring up to first interpolation>" => :DQPRE,
- "<dqstring between two interpolations>" => :DQMID,
- "<dqstring after final interpolation>" => :DQPOST,
- "<boolean>" => :BOOLEAN
- )
-
- TOKENS.add_token :NUMBER, %r{\b(?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?)\b} do |lexer, value|
- [TOKENS[:NAME], value]
- end
- #:stopdoc: # Issue #4161
- def (TOKENS[:NUMBER]).acceptable?(context={})
- ![:DQPRE,:DQMID].include? context[:after]
- end
- #:startdoc:
+ class Token
+ attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate
- TOKENS.add_token :NAME, %r{[a-z0-9][-\w]*} do |lexer, value|
- string_token = self
- # we're looking for keywords here
- if tmp = KEYWORDS.lookup(value)
- string_token = tmp
- if [:TRUE, :FALSE].include?(string_token.name)
- value = eval(value)
- string_token = TOKENS[:BOOLEAN]
- end
- end
- [string_token, value]
+ def initialize(regex, name)
+ if regex.is_a?(String)
+ @name, @string = name, regex
+ @regex = Regexp.new(Regexp.escape(@string))
+ else
+ @name, @regex = name, regex
+ end
end
- [:NAME,:CLASSNAME,:CLASSREF].each { |name_token|
- #:stopdoc: # Issue #4161
- def (TOKENS[name_token]).acceptable?(context={})
- ![:DQPRE,:DQMID].include? context[:after]
- end
- #:startdoc:
- }
- TOKENS.add_token :COMMENT, %r{#.*}, :accumulate => true, :skip => true do |lexer,value|
- value.sub!(/# ?/,'')
- [self, value]
+ # MQR: Why not just alias?
+ %w{skip accumulate}.each do |method|
+ define_method(method+"?") do
+ self.send(method)
+ end
end
- TOKENS.add_token :MLCOMMENT, %r{/\*(.*?)\*/}m, :accumulate => true, :skip => true do |lexer, value|
- lexer.line += value.count("\n")
- value.sub!(/^\/\* ?/,'')
- value.sub!(/ ?\*\/$/,'')
- [self,value]
+ def to_s
+ if self.string
+ @string
+ else
+ @name.to_s
+ end
end
- TOKENS.add_token :REGEX, %r{/[^/\n]*/} do |lexer, value|
- # Make sure we haven't matched an escaped /
- while value[-2..-2] == '\\'
- other = lexer.scan_until(%r{/})
- value += other
- end
- regex = value.sub(%r{\A/}, "").sub(%r{/\Z}, '').gsub("\\/", "/")
- [self, Regexp.new(regex)]
- end
-
- #:stopdoc: # Issue #4161
- def (TOKENS[:REGEX]).acceptable?(context={})
- [:NODE,:LBRACE,:RBRACE,:MATCH,:NOMATCH,:COMMA].include? context[:after]
+ def acceptable?(context={})
+ # By default tokens are aceeptable in any context
+ true
end
- #:startdoc:
+ end
- TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true
+ # Maintain a list of tokens.
+ class TokenList
+ attr_reader :regex_tokens, :string_tokens
- TOKENS.add_token :SQUOTE, "'" do |lexer, value|
- [TOKENS[:STRING], lexer.slurpstring(value).first ]
+ def [](name)
+ @tokens[name]
end
- DQ_initial_token_types = {'$' => :DQPRE,'"' => :STRING}
- DQ_continuation_token_types = {'$' => :DQMID,'"' => :DQPOST}
+ # Create a new token.
+ def add_token(name, regex, options = {}, &block)
+ token = Token.new(regex, name)
+ raise(ArgumentError, "Token #{name} already exists") if @tokens.include?(name)
+ @tokens[token.name] = token
+ if token.string
+ @string_tokens << token
+ @tokens_by_string[token.string] = token
+ else
+ @regex_tokens << token
+ end
- TOKENS.add_token :DQUOTE, /"/ do |lexer, value|
- lexer.tokenize_interpolated_string(DQ_initial_token_types)
- end
+ options.each do |name, option|
+ token.send(name.to_s + "=", option)
+ end
- TOKENS.add_token :DQCONT, /\}/ do |lexer, value|
- lexer.tokenize_interpolated_string(DQ_continuation_token_types)
- end
- #:stopdoc: # Issue #4161
- def (TOKENS[:DQCONT]).acceptable?(context={})
- context[:string_interpolation_depth] > 0
- end
- #:startdoc:
+ token.meta_def(:convert, &block) if block_given?
- TOKENS.add_token :DOLLAR_VAR, %r{\$(\w*::)*\w+} do |lexer, value|
- [TOKENS[:VARIABLE],value[1..-1]]
+ token
end
- TOKENS.add_token :VARIABLE, %r{(\w*::)*\w+}
+ def initialize
+ @tokens = {}
+ @regex_tokens = []
+ @string_tokens = []
+ @tokens_by_string = {}
+ end
+
+ # Look up a token by its value, rather than name.
+ def lookup(string)
+ @tokens_by_string[string]
+ end
+
+ # Define more tokens.
+ def add_tokens(hash)
+ hash.each do |regex, name|
+ add_token(name, regex)
+ end
+ end
+
+ # Sort our tokens by length, so we know once we match, we're done.
+ # This helps us avoid the O(n^2) nature of token matching.
+ def sort_tokens
+ @string_tokens.sort! { |a, b| b.string.length <=> a.string.length }
+ end
+ end
+
+ TOKENS = TokenList.new
+
+ TOKENS.add_tokens(
+
+ '[' => :LBRACK,
+ ']' => :RBRACK,
+ '{' => :LBRACE,
+ '}' => :RBRACE,
+ '(' => :LPAREN,
+
+ ')' => :RPAREN,
+ '=' => :EQUALS,
+ '+=' => :APPENDS,
+ '==' => :ISEQUAL,
+ '>=' => :GREATEREQUAL,
+ '>' => :GREATERTHAN,
+ '<' => :LESSTHAN,
+ '<=' => :LESSEQUAL,
+ '!=' => :NOTEQUAL,
+ '!' => :NOT,
+ ',' => :COMMA,
+ '.' => :DOT,
+ ':' => :COLON,
+ '@' => :AT,
+ '<<|' => :LLCOLLECT,
+ '->' => :IN_EDGE,
+ '<-' => :OUT_EDGE,
+ '~>' => :IN_EDGE_SUB,
+ '<~' => :OUT_EDGE_SUB,
+ '|>>' => :RRCOLLECT,
+ '<|' => :LCOLLECT,
+ '|>' => :RCOLLECT,
+ ';' => :SEMIC,
+ '?' => :QMARK,
+ '\\' => :BACKSLASH,
+ '=>' => :FARROW,
+ '+>' => :PARROW,
+ '+' => :PLUS,
+ '-' => :MINUS,
+ '/' => :DIV,
+ '*' => :TIMES,
+ '<<' => :LSHIFT,
+ '>>' => :RSHIFT,
+ '=~' => :MATCH,
+ '!~' => :NOMATCH,
+ %r{([a-z][-\w]*)?(::[a-z][-\w]*)+} => :CLASSNAME, # Require '::' in the class name, else we'd compete with NAME
+ %r{((::){0,1}[A-Z][-\w]*)+} => :CLASSREF,
+ "<string>" => :STRING,
+ "<dqstring up to first interpolation>" => :DQPRE,
+ "<dqstring between two interpolations>" => :DQMID,
+ "<dqstring after final interpolation>" => :DQPOST,
+ "<boolean>" => :BOOLEAN
+ )
+
+ TOKENS.add_token :NUMBER, %r{\b(?:0[xX][0-9A-Fa-f]+|0?\d+(?:\.\d+)?(?:[eE]-?\d+)?)\b} do |lexer, value|
+ [TOKENS[:NAME], value]
+ end
+ #:stopdoc: # Issue #4161
+ def (TOKENS[:NUMBER]).acceptable?(context={})
+ ![:DQPRE,:DQMID].include? context[:after]
+ end
+ #:startdoc:
+
+ TOKENS.add_token :NAME, %r{[a-z0-9][-\w]*} do |lexer, value|
+ string_token = self
+ # we're looking for keywords here
+ if tmp = KEYWORDS.lookup(value)
+ string_token = tmp
+ if [:TRUE, :FALSE].include?(string_token.name)
+ value = eval(value)
+ string_token = TOKENS[:BOOLEAN]
+ end
+ end
+ [string_token, value]
+ end
+ [:NAME,:CLASSNAME,:CLASSREF].each { |name_token|
#:stopdoc: # Issue #4161
- def (TOKENS[:VARIABLE]).acceptable?(context={})
- [:DQPRE,:DQMID].include? context[:after]
+ def (TOKENS[name_token]).acceptable?(context={})
+ ![:DQPRE,:DQMID].include? context[:after]
end
#:startdoc:
-
-
- TOKENS.sort_tokens
-
- @@pairs = {
- "{" => "}",
- "(" => ")",
- "[" => "]",
- "<|" => "|>",
- "<<|" => "|>>"
+ }
+
+ TOKENS.add_token :COMMENT, %r{#.*}, :accumulate => true, :skip => true do |lexer,value|
+ value.sub!(/# ?/,'')
+ [self, value]
+ end
+
+ TOKENS.add_token :MLCOMMENT, %r{/\*(.*?)\*/}m, :accumulate => true, :skip => true do |lexer, value|
+ lexer.line += value.count("\n")
+ value.sub!(/^\/\* ?/,'')
+ value.sub!(/ ?\*\/$/,'')
+ [self,value]
+ end
+
+ TOKENS.add_token :REGEX, %r{/[^/\n]*/} do |lexer, value|
+ # Make sure we haven't matched an escaped /
+ while value[-2..-2] == '\\'
+ other = lexer.scan_until(%r{/})
+ value += other
+ end
+ regex = value.sub(%r{\A/}, "").sub(%r{/\Z}, '').gsub("\\/", "/")
+ [self, Regexp.new(regex)]
+ end
+
+ #:stopdoc: # Issue #4161
+ def (TOKENS[:REGEX]).acceptable?(context={})
+ [:NODE,:LBRACE,:RBRACE,:MATCH,:NOMATCH,:COMMA].include? context[:after]
+ end
+ #:startdoc:
+
+ TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true
+
+ TOKENS.add_token :SQUOTE, "'" do |lexer, value|
+ [TOKENS[:STRING], lexer.slurpstring(value).first ]
+ end
+
+ DQ_initial_token_types = {'$' => :DQPRE,'"' => :STRING}
+ DQ_continuation_token_types = {'$' => :DQMID,'"' => :DQPOST}
+
+ TOKENS.add_token :DQUOTE, /"/ do |lexer, value|
+ lexer.tokenize_interpolated_string(DQ_initial_token_types)
+ end
+
+ TOKENS.add_token :DQCONT, /\}/ do |lexer, value|
+ lexer.tokenize_interpolated_string(DQ_continuation_token_types)
+ end
+ #:stopdoc: # Issue #4161
+ def (TOKENS[:DQCONT]).acceptable?(context={})
+ context[:string_interpolation_depth] > 0
+ end
+ #:startdoc:
+
+ TOKENS.add_token :DOLLAR_VAR, %r{\$(\w*::)*\w+} do |lexer, value|
+ [TOKENS[:VARIABLE],value[1..-1]]
+ end
+
+ TOKENS.add_token :VARIABLE, %r{(\w*::)*\w+}
+ #:stopdoc: # Issue #4161
+ def (TOKENS[:VARIABLE]).acceptable?(context={})
+ [:DQPRE,:DQMID].include? context[:after]
+ end
+ #:startdoc:
+
+
+ TOKENS.sort_tokens
+
+ @@pairs = {
+ "{" => "}",
+ "(" => ")",
+ "[" => "]",
+ "<|" => "|>",
+ "<<|" => "|>>"
+ }
+
+ KEYWORDS = TokenList.new
+
+
+ KEYWORDS.add_tokens(
+
+ "case" => :CASE,
+ "class" => :CLASS,
+ "default" => :DEFAULT,
+ "define" => :DEFINE,
+ "import" => :IMPORT,
+ "if" => :IF,
+ "elsif" => :ELSIF,
+ "else" => :ELSE,
+ "inherits" => :INHERITS,
+ "node" => :NODE,
+ "and" => :AND,
+ "or" => :OR,
+ "undef" => :UNDEF,
+ "false" => :FALSE,
+ "true" => :TRUE,
+
+ "in" => :IN
+ )
+
+ def clear
+ initvars
+ end
+
+ def expected
+ return nil if @expected.empty?
+ name = @expected[-1]
+ TOKENS.lookup(name) or lex_error "Could not find expected token #{name}"
+ end
+
+ # scan the whole file
+ # basically just used for testing
+ def fullscan
+ array = []
+
+ self.scan { |token, str|
+ # Ignore any definition nesting problems
+ @indefine = false
+ array.push([token,str])
}
-
- KEYWORDS = TokenList.new
-
-
- KEYWORDS.add_tokens(
-
- "case" => :CASE,
- "class" => :CLASS,
- "default" => :DEFAULT,
- "define" => :DEFINE,
- "import" => :IMPORT,
- "if" => :IF,
- "elsif" => :ELSIF,
- "else" => :ELSE,
- "inherits" => :INHERITS,
- "node" => :NODE,
- "and" => :AND,
- "or" => :OR,
- "undef" => :UNDEF,
- "false" => :FALSE,
- "true" => :TRUE,
-
- "in" => :IN
- )
-
- def clear
- initvars
- end
-
- def expected
- return nil if @expected.empty?
- name = @expected[-1]
- TOKENS.lookup(name) or lex_error "Could not find expected token #{name}"
- end
-
- # scan the whole file
- # basically just used for testing
- def fullscan
- array = []
-
- self.scan { |token, str|
- # Ignore any definition nesting problems
- @indefine = false
- array.push([token,str])
- }
- array
- end
-
- def file=(file)
- @file = file
- @line = 1
- @scanner = StringScanner.new(File.read(file))
- end
-
- def shift_token
- @token_queue.shift
- end
-
- def find_string_token
- # We know our longest string token is three chars, so try each size in turn
- # until we either match or run out of chars. This way our worst-case is three
- # tries, where it is otherwise the number of string token we have. Also,
- # the lookups are optimized hash lookups, instead of regex scans.
- #
- s = @scanner.peek(3)
- token = TOKENS.lookup(s[0,3]) || TOKENS.lookup(s[0,2]) || TOKENS.lookup(s[0,1])
- [ token, token && @scanner.scan(token.regex) ]
- end
-
- # Find the next token that matches a regex. We look for these first.
- def find_regex_token
- @regex += 1
- best_token = nil
- best_length = 0
-
- # I tried optimizing based on the first char, but it had
- # a slightly negative affect and was a good bit more complicated.
- TOKENS.regex_tokens.each do |token|
- if length = @scanner.match?(token.regex) and token.acceptable?(lexing_context)
- # We've found a longer match
- if length > best_length
- best_length = length
- best_token = token
- end
- end
+ array
+ end
+
+ def file=(file)
+ @file = file
+ @line = 1
+ @scanner = StringScanner.new(File.read(file))
+ end
+
+ def shift_token
+ @token_queue.shift
+ end
+
+ def find_string_token
+ # We know our longest string token is three chars, so try each size in turn
+ # until we either match or run out of chars. This way our worst-case is three
+ # tries, where it is otherwise the number of string token we have. Also,
+ # the lookups are optimized hash lookups, instead of regex scans.
+ #
+ s = @scanner.peek(3)
+ token = TOKENS.lookup(s[0,3]) || TOKENS.lookup(s[0,2]) || TOKENS.lookup(s[0,1])
+ [ token, token && @scanner.scan(token.regex) ]
+ end
+
+ # Find the next token that matches a regex. We look for these first.
+ def find_regex_token
+ @regex += 1
+ best_token = nil
+ best_length = 0
+
+ # I tried optimizing based on the first char, but it had
+ # a slightly negative affect and was a good bit more complicated.
+ TOKENS.regex_tokens.each do |token|
+ if length = @scanner.match?(token.regex) and token.acceptable?(lexing_context)
+ # We've found a longer match
+ if length > best_length
+ best_length = length
+ best_token = token
end
+ end
+ end
- return best_token, @scanner.scan(best_token.regex) if best_token
- end
-
- # Find the next token, returning the string and the token.
- def find_token
- @find += 1
- shift_token || find_regex_token || find_string_token
- end
+ return best_token, @scanner.scan(best_token.regex) if best_token
+ end
- def indefine?
- if defined?(@indefine)
- @indefine
- else
- false
- end
- end
+ # Find the next token, returning the string and the token.
+ def find_token
+ @find += 1
+ shift_token || find_regex_token || find_string_token
+ end
- def initialize
- @find = 0
- @regex = 0
- initvars
+ def indefine?
+ if defined?(@indefine)
+ @indefine
+ else
+ false
end
+ end
- def initvars
- @line = 1
- @previous_token = nil
- @scanner = nil
- @file = nil
- # AAARRGGGG! okay, regexes in ruby are bloody annoying
- # no one else has "\n" =~ /\s/
- @skip = %r{[ \t\r]+}
-
- @namestack = []
- @token_queue = []
- @indefine = false
- @expected = []
- @commentstack = [ ['', @line] ]
- @lexing_context = {
- :after => nil,
- :start_of_line => true,
- :string_interpolation_depth => 0
- }
- end
+ def initialize
+ @find = 0
+ @regex = 0
+ initvars
+ end
- # Make any necessary changes to the token and/or value.
- def munge_token(token, value)
- @line += 1 if token.incr_line
+ def initvars
+ @line = 1
+ @previous_token = nil
+ @scanner = nil
+ @file = nil
+ # AAARRGGGG! okay, regexes in ruby are bloody annoying
+ # no one else has "\n" =~ /\s/
+ @skip = %r{[ \t\r]+}
- skip if token.skip_text
+ @namestack = []
+ @token_queue = []
+ @indefine = false
+ @expected = []
+ @commentstack = [ ['', @line] ]
+ @lexing_context = {
+ :after => nil,
+ :start_of_line => true,
+ :string_interpolation_depth => 0
+ }
+ end
- return if token.skip and not token.accumulate?
+ # Make any necessary changes to the token and/or value.
+ def munge_token(token, value)
+ @line += 1 if token.incr_line
- token, value = token.convert(self, value) if token.respond_to?(:convert)
+ skip if token.skip_text
- return unless token
+ return if token.skip and not token.accumulate?
- if token.accumulate?
- comment = @commentstack.pop
- comment[0] << value + "\n"
- @commentstack.push(comment)
- end
+ token, value = token.convert(self, value) if token.respond_to?(:convert)
- return if token.skip
+ return unless token
- return token, { :value => value, :line => @line }
+ if token.accumulate?
+ comment = @commentstack.pop
+ comment[0] << value + "\n"
+ @commentstack.push(comment)
end
- # Go up one in the namespace.
- def namepop
- @namestack.pop
- end
+ return if token.skip
- # Collect the current namespace.
- def namespace
- @namestack.join("::")
- end
+ return token, { :value => value, :line => @line }
+ end
- # This value might have :: in it, but we don't care -- it'll be
- # handled normally when joining, and when popping we want to pop
- # this full value, however long the namespace is.
- def namestack(value)
- @namestack << value
- end
-
- def rest
- @scanner.rest
- end
-
- # this is the heart of the lexer
- def scan
- #Puppet.debug("entering scan")
- lex_error "Invalid or empty string" unless @scanner
-
- # Skip any initial whitespace.
- skip
+ # Go up one in the namespace.
+ def namepop
+ @namestack.pop
+ end
- until token_queue.empty? and @scanner.eos? do
- yielded = false
- matched_token, value = find_token
+ # Collect the current namespace.
+ def namespace
+ @namestack.join("::")
+ end
- # error out if we didn't match anything at all
- lex_error "Could not match #{@scanner.rest[/^(\S+|\s+|.*)/]}" unless matched_token
+ # This value might have :: in it, but we don't care -- it'll be
+ # handled normally when joining, and when popping we want to pop
+ # this full value, however long the namespace is.
+ def namestack(value)
+ @namestack << value
+ end
- newline = matched_token.name == :RETURN
+ def rest
+ @scanner.rest
+ end
- # this matches a blank line; eat the previously accumulated comments
- getcomment if lexing_context[:start_of_line] and newline
- lexing_context[:start_of_line] = newline
+ # this is the heart of the lexer
+ def scan
+ #Puppet.debug("entering scan")
+ lex_error "Invalid or empty string" unless @scanner
- final_token, token_value = munge_token(matched_token, value)
+ # Skip any initial whitespace.
+ skip
- unless final_token
- skip
- next
- end
+ until token_queue.empty? and @scanner.eos? do
+ yielded = false
+ matched_token, value = find_token
- lexing_context[:after] = final_token.name unless newline
- lexing_context[:string_interpolation_depth] += 1 if final_token.name == :DQPRE
- lexing_context[:string_interpolation_depth] -= 1 if final_token.name == :DQPOST
+ # error out if we didn't match anything at all
+ lex_error "Could not match #{@scanner.rest[/^(\S+|\s+|.*)/]}" unless matched_token
- value = token_value[:value]
+ newline = matched_token.name == :RETURN
+
+ # this matches a blank line; eat the previously accumulated comments
+ getcomment if lexing_context[:start_of_line] and newline
+ lexing_context[:start_of_line] = newline
- if match = @@pairs[value] and final_token.name != :DQUOTE and final_token.name != :SQUOTE
- @expected << match
- elsif exp = @expected[-1] and exp == value and final_token.name != :DQUOTE and final_token.name != :SQUOTE
- @expected.pop
- end
+ final_token, token_value = munge_token(matched_token, value)
- if final_token.name == :LBRACE
- commentpush
- end
-
- yield [final_token.name, token_value]
+ unless final_token
+ skip
+ next
+ end
- if @previous_token
- namestack(value) if @previous_token.name == :CLASS
+ lexing_context[:after] = final_token.name unless newline
+ lexing_context[:string_interpolation_depth] += 1 if final_token.name == :DQPRE
+ lexing_context[:string_interpolation_depth] -= 1 if final_token.name == :DQPOST
- if @previous_token.name == :DEFINE
- if indefine?
- msg = "Cannot nest definition #{value} inside #{@indefine}"
- self.indefine = false
- raise Puppet::ParseError, msg
- end
+ value = token_value[:value]
- @indefine = value
- end
- end
- @previous_token = final_token
- skip
- end
- @scanner = nil
+ if match = @@pairs[value] and final_token.name != :DQUOTE and final_token.name != :SQUOTE
+ @expected << match
+ elsif exp = @expected[-1] and exp == value and final_token.name != :DQUOTE and final_token.name != :SQUOTE
+ @expected.pop
+ end
- # This indicates that we're done parsing.
- yield [false,false]
- end
+ if final_token.name == :LBRACE
+ commentpush
+ end
- # Skip any skipchars in our remaining string.
- def skip
- @scanner.skip(@skip)
- end
+ yield [final_token.name, token_value]
- # Provide some limited access to the scanner, for those
- # tokens that need it.
- def scan_until(regex)
- @scanner.scan_until(regex)
- end
+ if @previous_token
+ namestack(value) if @previous_token.name == :CLASS
- # we've encountered the start of a string...
- # slurp in the rest of the string and return it
- Valid_escapes_in_strings = %w{ \\ $ ' " n t s }+["\n"]
- def slurpstring(terminators)
- # we search for the next quote that isn't preceded by a
- # backslash; the caret is there to match empty strings
- str = @scanner.scan_until(/([^\\]|^)[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'"
- @line += str.count("\n") # literal carriage returns add to the line count.
- str.gsub!(/\\(.)/) {
- case ch=$1
- when 'n'; "\n"
- when 't'; "\t"
- when 's'; " "
- else
- if Valid_escapes_in_strings.include? ch and not (ch == '"' and terminators == "'")
- ch
- else
- Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}"
- "\\#{ch}"
- end
- end
- }
- [ str[0..-2],str[-1,1] ]
- end
+ if @previous_token.name == :DEFINE
+ if indefine?
+ msg = "Cannot nest definition #{value} inside #{@indefine}"
+ self.indefine = false
+ raise Puppet::ParseError, msg
+ end
- def tokenize_interpolated_string(token_type)
- value,terminator = slurpstring('"$')
- token_queue << [TOKENS[token_type[terminator]],value]
- while terminator == '$' and not @scanner.scan(/\{/)
- token_queue << [TOKENS[:VARIABLE],@scanner.scan(%r{(\w*::)*\w+|[0-9]})]
- value,terminator = slurpstring('"$')
- token_queue << [TOKENS[DQ_continuation_token_types[terminator]],value]
+ @indefine = value
end
- token_queue.shift
- end
-
- # just parse a string, not a whole file
- def string=(string)
- @scanner = StringScanner.new(string)
- end
-
- # returns the content of the currently accumulated content cache
- def commentpop
- @commentstack.pop[0]
- end
-
- def getcomment(line = nil)
- comment = @commentstack.last
- if line.nil? or comment[1] <= line
- @commentstack.pop
- @commentstack.push(['', @line])
- return comment[0]
+ end
+ @previous_token = final_token
+ skip
+ end
+ @scanner = nil
+
+ # This indicates that we're done parsing.
+ yield [false,false]
+ end
+
+ # Skip any skipchars in our remaining string.
+ def skip
+ @scanner.skip(@skip)
+ end
+
+ # Provide some limited access to the scanner, for those
+ # tokens that need it.
+ def scan_until(regex)
+ @scanner.scan_until(regex)
+ end
+
+ # we've encountered the start of a string...
+ # slurp in the rest of the string and return it
+ Valid_escapes_in_strings = %w{ \\ $ ' " n t s }+["\n"]
+ def slurpstring(terminators)
+ # we search for the next quote that isn't preceded by a
+ # backslash; the caret is there to match empty strings
+ str = @scanner.scan_until(/([^\\]|^)[#{terminators}]/) or lex_error "Unclosed quote after '#{last}' in '#{rest}'"
+ @line += str.count("\n") # literal carriage returns add to the line count.
+ str.gsub!(/\\(.)/) {
+ case ch=$1
+ when 'n'; "\n"
+ when 't'; "\t"
+ when 's'; " "
+ else
+ if Valid_escapes_in_strings.include? ch and not (ch == '"' and terminators == "'")
+ ch
+ else
+ Puppet.warning "Unrecognised escape sequence '\\#{ch}'#{file && " in file #{file}"}#{line && " at line #{line}"}"
+ "\\#{ch}"
end
- ''
- end
-
- def commentpush
- @commentstack.push(['', @line])
- end
+ end
+ }
+ [ str[0..-2],str[-1,1] ]
+ end
+
+ def tokenize_interpolated_string(token_type)
+ value,terminator = slurpstring('"$')
+ token_queue << [TOKENS[token_type[terminator]],value]
+ while terminator == '$' and not @scanner.scan(/\{/)
+ token_queue << [TOKENS[:VARIABLE],@scanner.scan(%r{(\w*::)*\w+|[0-9]})]
+ value,terminator = slurpstring('"$')
+ token_queue << [TOKENS[DQ_continuation_token_types[terminator]],value]
+ end
+ token_queue.shift
+ end
+
+ # just parse a string, not a whole file
+ def string=(string)
+ @scanner = StringScanner.new(string)
+ end
+
+ # returns the content of the currently accumulated content cache
+ def commentpop
+ @commentstack.pop[0]
+ end
+
+ def getcomment(line = nil)
+ comment = @commentstack.last
+ if line.nil? or comment[1] <= line
+ @commentstack.pop
+ @commentstack.push(['', @line])
+ return comment[0]
+ end
+ ''
+ end
+
+ def commentpush
+ @commentstack.push(['', @line])
+ end
end
diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb
index 8dd986bd5..4f3a4ddff 100644
--- a/lib/puppet/parser/parser_support.rb
+++ b/lib/puppet/parser/parser_support.rb
@@ -1,235 +1,235 @@
# I pulled this into a separate file, because I got
# tired of rebuilding the parser.rb file all the time.
class Puppet::Parser::Parser
- require 'puppet/parser/functions'
- require 'puppet/parser/files'
- require 'puppet/resource/type_collection'
- require 'puppet/resource/type_collection_helper'
- require 'puppet/resource/type'
- require 'monitor'
+ require 'puppet/parser/functions'
+ require 'puppet/parser/files'
+ require 'puppet/resource/type_collection'
+ require 'puppet/resource/type_collection_helper'
+ require 'puppet/resource/type'
+ require 'monitor'
- AST = Puppet::Parser::AST
+ AST = Puppet::Parser::AST
- include Puppet::Resource::TypeCollectionHelper
+ include Puppet::Resource::TypeCollectionHelper
- attr_reader :version, :environment
- attr_accessor :files
+ attr_reader :version, :environment
+ attr_accessor :files
- attr_accessor :lexer
-
- # Add context to a message; useful for error messages and such.
- def addcontext(message, obj = nil)
- obj ||= @lexer
-
- message += " on line #{obj.line}"
- if file = obj.file
- message += " in file #{file}"
- end
-
- message
- end
-
- # Create an AST array out of all of the args
- def aryfy(*args)
- if args[0].instance_of?(AST::ASTArray)
- result = args.shift
- args.each { |arg|
- result.push arg
- }
- else
- result = ast AST::ASTArray, :children => args
- end
-
- result
- end
-
- # Create an AST object, and automatically add the file and line information if
- # available.
- def ast(klass, hash = {})
- klass.new ast_context(klass.use_docs).merge(hash)
- end
-
- def ast_context(include_docs = false)
- result = {
- :line => lexer.line,
- :file => lexer.file
- }
- result[:doc] = lexer.getcomment(result[:line]) if include_docs
- result
- end
-
- # The fully qualifed name, with the full namespace.
- def classname(name)
- [@lexer.namespace, name].join("::").sub(/^::/, '')
- end
-
- def clear
- initvars
- end
-
- # Raise a Parse error.
- def error(message)
- if brace = @lexer.expected
- message += "; expected '%s'"
- end
- except = Puppet::ParseError.new(message)
- except.line = @lexer.line
- except.file = @lexer.file if @lexer.file
-
- raise except
- end
-
- def file
- @lexer.file
- end
-
- def file=(file)
- unless FileTest.exist?(file)
- unless file =~ /\.pp$/
- file = file + ".pp"
- end
- raise Puppet::Error, "Could not find file #{file}" unless FileTest.exist?(file)
- end
- raise Puppet::AlreadyImportedError, "Import loop detected" if known_resource_types.watching_file?(file)
-
- watch_file(file)
- @lexer.file = file
- end
-
- [:hostclass, :definition, :node, :nodes?].each do |method|
- define_method(method) do |*args|
- known_resource_types.send(method, *args)
- end
- end
-
- def find_hostclass(namespace, name)
- known_resource_types.find_or_load(namespace, name, :hostclass)
- end
-
- def find_definition(namespace, name)
- known_resource_types.find_or_load(namespace, name, :definition)
- end
-
- def import(file)
- known_resource_types.loader.import(file, @lexer.file)
- end
-
- def initialize(env)
- # The environment is needed to know how to find the resource type collection.
- @environment = env.is_a?(String) ? Puppet::Node::Environment.new(env) : env
- initvars
- end
-
- # Initialize or reset all of our variables.
- def initvars
- @lexer = Puppet::Parser::Lexer.new
- end
-
- # Split an fq name into a namespace and name
- def namesplit(fullname)
- ary = fullname.split("::")
- n = ary.pop || ""
- ns = ary.join("::")
- return ns, n
- end
-
- # Create a new class, or merge with an existing class.
- def newclass(name, options = {})
- known_resource_types.add Puppet::Resource::Type.new(:hostclass, name, ast_context(true).merge(options))
- end
-
- # Create a new definition.
- def newdefine(name, options = {})
- known_resource_types.add Puppet::Resource::Type.new(:definition, name, ast_context(true).merge(options))
- end
-
- # Create a new node. Nodes are special, because they're stored in a global
- # table, not according to namespaces.
- def newnode(names, options = {})
- names = [names] unless names.instance_of?(Array)
- context = ast_context(true)
- names.collect do |name|
- known_resource_types.add(Puppet::Resource::Type.new(:node, name, context.merge(options)))
- end
- end
-
- def on_error(token,value,stack)
- if token == 0 # denotes end of file
- value = 'end of file'
- else
- value = "'#{value[:value]}'"
- end
- error = "Syntax error at #{value}"
-
- if brace = @lexer.expected
- error += "; expected '#{brace}'"
- end
-
- except = Puppet::ParseError.new(error)
- except.line = @lexer.line
- except.file = @lexer.file if @lexer.file
-
- raise except
- end
-
- # how should I do error handling here?
- def parse(string = nil)
- return parse_ruby_file if self.file =~ /\.rb$/
- self.string = string if string
- begin
- @yydebug = false
- main = yyparse(@lexer,:scan)
- rescue Racc::ParseError => except
- error = Puppet::ParseError.new(except)
- error.line = @lexer.line
- error.file = @lexer.file
- error.set_backtrace except.backtrace
- raise error
- rescue Puppet::ParseError => except
- except.line ||= @lexer.line
- except.file ||= @lexer.file
- raise except
- rescue Puppet::Error => except
- # and this is a framework error
- except.line ||= @lexer.line
- except.file ||= @lexer.file
- raise except
- rescue Puppet::DevError => except
- except.line ||= @lexer.line
- except.file ||= @lexer.file
- raise except
- rescue => except
- error = Puppet::DevError.new(except.message)
- error.line = @lexer.line
- error.file = @lexer.file
- error.set_backtrace except.backtrace
- raise error
- end
- if main
- # Store the results as the top-level class.
- newclass("", :code => main)
- end
- return known_resource_types
- ensure
- @lexer.clear
- end
-
- def parse_ruby_file
- require self.file
- end
-
- def string=(string)
- @lexer.string = string
- end
-
- def version
- known_resource_types.version
- end
-
- # Add a new file to be checked when we're checking to see if we should be
- # reparsed. This is basically only used by the TemplateWrapper to let the
- # parser know about templates that should be parsed.
- def watch_file(filename)
- known_resource_types.watch_file(filename)
- end
+ attr_accessor :lexer
+
+ # Add context to a message; useful for error messages and such.
+ def addcontext(message, obj = nil)
+ obj ||= @lexer
+
+ message += " on line #{obj.line}"
+ if file = obj.file
+ message += " in file #{file}"
+ end
+
+ message
+ end
+
+ # Create an AST array out of all of the args
+ def aryfy(*args)
+ if args[0].instance_of?(AST::ASTArray)
+ result = args.shift
+ args.each { |arg|
+ result.push arg
+ }
+ else
+ result = ast AST::ASTArray, :children => args
+ end
+
+ result
+ end
+
+ # Create an AST object, and automatically add the file and line information if
+ # available.
+ def ast(klass, hash = {})
+ klass.new ast_context(klass.use_docs).merge(hash)
+ end
+
+ def ast_context(include_docs = false)
+ result = {
+ :line => lexer.line,
+ :file => lexer.file
+ }
+ result[:doc] = lexer.getcomment(result[:line]) if include_docs
+ result
+ end
+
+ # The fully qualifed name, with the full namespace.
+ def classname(name)
+ [@lexer.namespace, name].join("::").sub(/^::/, '')
+ end
+
+ def clear
+ initvars
+ end
+
+ # Raise a Parse error.
+ def error(message)
+ if brace = @lexer.expected
+ message += "; expected '%s'"
+ end
+ except = Puppet::ParseError.new(message)
+ except.line = @lexer.line
+ except.file = @lexer.file if @lexer.file
+
+ raise except
+ end
+
+ def file
+ @lexer.file
+ end
+
+ def file=(file)
+ unless FileTest.exist?(file)
+ unless file =~ /\.pp$/
+ file = file + ".pp"
+ end
+ raise Puppet::Error, "Could not find file #{file}" unless FileTest.exist?(file)
+ end
+ raise Puppet::AlreadyImportedError, "Import loop detected" if known_resource_types.watching_file?(file)
+
+ watch_file(file)
+ @lexer.file = file
+ end
+
+ [:hostclass, :definition, :node, :nodes?].each do |method|
+ define_method(method) do |*args|
+ known_resource_types.send(method, *args)
+ end
+ end
+
+ def find_hostclass(namespace, name)
+ known_resource_types.find_or_load(namespace, name, :hostclass)
+ end
+
+ def find_definition(namespace, name)
+ known_resource_types.find_or_load(namespace, name, :definition)
+ end
+
+ def import(file)
+ known_resource_types.loader.import(file, @lexer.file)
+ end
+
+ def initialize(env)
+ # The environment is needed to know how to find the resource type collection.
+ @environment = env.is_a?(String) ? Puppet::Node::Environment.new(env) : env
+ initvars
+ end
+
+ # Initialize or reset all of our variables.
+ def initvars
+ @lexer = Puppet::Parser::Lexer.new
+ end
+
+ # Split an fq name into a namespace and name
+ def namesplit(fullname)
+ ary = fullname.split("::")
+ n = ary.pop || ""
+ ns = ary.join("::")
+ return ns, n
+ end
+
+ # Create a new class, or merge with an existing class.
+ def newclass(name, options = {})
+ known_resource_types.add Puppet::Resource::Type.new(:hostclass, name, ast_context(true).merge(options))
+ end
+
+ # Create a new definition.
+ def newdefine(name, options = {})
+ known_resource_types.add Puppet::Resource::Type.new(:definition, name, ast_context(true).merge(options))
+ end
+
+ # Create a new node. Nodes are special, because they're stored in a global
+ # table, not according to namespaces.
+ def newnode(names, options = {})
+ names = [names] unless names.instance_of?(Array)
+ context = ast_context(true)
+ names.collect do |name|
+ known_resource_types.add(Puppet::Resource::Type.new(:node, name, context.merge(options)))
+ end
+ end
+
+ def on_error(token,value,stack)
+ if token == 0 # denotes end of file
+ value = 'end of file'
+ else
+ value = "'#{value[:value]}'"
+ end
+ error = "Syntax error at #{value}"
+
+ if brace = @lexer.expected
+ error += "; expected '#{brace}'"
+ end
+
+ except = Puppet::ParseError.new(error)
+ except.line = @lexer.line
+ except.file = @lexer.file if @lexer.file
+
+ raise except
+ end
+
+ # how should I do error handling here?
+ def parse(string = nil)
+ return parse_ruby_file if self.file =~ /\.rb$/
+ self.string = string if string
+ begin
+ @yydebug = false
+ main = yyparse(@lexer,:scan)
+ rescue Racc::ParseError => except
+ error = Puppet::ParseError.new(except)
+ error.line = @lexer.line
+ error.file = @lexer.file
+ error.set_backtrace except.backtrace
+ raise error
+ rescue Puppet::ParseError => except
+ except.line ||= @lexer.line
+ except.file ||= @lexer.file
+ raise except
+ rescue Puppet::Error => except
+ # and this is a framework error
+ except.line ||= @lexer.line
+ except.file ||= @lexer.file
+ raise except
+ rescue Puppet::DevError => except
+ except.line ||= @lexer.line
+ except.file ||= @lexer.file
+ raise except
+ rescue => except
+ error = Puppet::DevError.new(except.message)
+ error.line = @lexer.line
+ error.file = @lexer.file
+ error.set_backtrace except.backtrace
+ raise error
+ end
+ if main
+ # Store the results as the top-level class.
+ newclass("", :code => main)
+ end
+ return known_resource_types
+ ensure
+ @lexer.clear
+ end
+
+ def parse_ruby_file
+ require self.file
+ end
+
+ def string=(string)
+ @lexer.string = string
+ end
+
+ def version
+ known_resource_types.version
+ end
+
+ # Add a new file to be checked when we're checking to see if we should be
+ # reparsed. This is basically only used by the TemplateWrapper to let the
+ # parser know about templates that should be parsed.
+ def watch_file(filename)
+ known_resource_types.watch_file(filename)
+ end
end
diff --git a/lib/puppet/parser/relationship.rb b/lib/puppet/parser/relationship.rb
index 1d1bad76c..6190df52c 100644
--- a/lib/puppet/parser/relationship.rb
+++ b/lib/puppet/parser/relationship.rb
@@ -1,43 +1,43 @@
class Puppet::Parser::Relationship
- attr_accessor :source, :target, :type
+ attr_accessor :source, :target, :type
- PARAM_MAP = {:relationship => :before, :subscription => :notify}
+ PARAM_MAP = {:relationship => :before, :subscription => :notify}
- def evaluate(catalog)
- if source.is_a?(Puppet::Parser::Collector)
- sources = source.collected.values
- else
- sources = [source]
- end
- if target.is_a?(Puppet::Parser::Collector)
- targets = target.collected.values
- else
- targets = [target]
- end
- sources.each do |s|
- targets.each do |t|
- mk_relationship(s, t, catalog)
- end
- end
+ def evaluate(catalog)
+ if source.is_a?(Puppet::Parser::Collector)
+ sources = source.collected.values
+ else
+ sources = [source]
end
-
- def initialize(source, target, type)
- @source, @target, @type = source, target, type
+ if target.is_a?(Puppet::Parser::Collector)
+ targets = target.collected.values
+ else
+ targets = [target]
end
-
- def param_name
- PARAM_MAP[type] || raise(ArgumentError, "Invalid relationship type #{type}")
+ sources.each do |s|
+ targets.each do |t|
+ mk_relationship(s, t, catalog)
+ end
end
+ end
+
+ def initialize(source, target, type)
+ @source, @target, @type = source, target, type
+ end
- def mk_relationship(source, target, catalog)
- unless source_resource = catalog.resource(source.to_s)
- raise ArgumentError, "Could not find resource '#{source}' for relationship on '#{target}'"
- end
- unless target_resource = catalog.resource(target.to_s)
- raise ArgumentError, "Could not find resource '#{target}' for relationship from '#{source}'"
- end
- Puppet.debug "Adding relationship from #{source.to_s} to #{target.to_s} with '#{param_name}'"
- source_resource[param_name] ||= []
- source_resource[param_name] << target.to_s
+ def param_name
+ PARAM_MAP[type] || raise(ArgumentError, "Invalid relationship type #{type}")
+ end
+
+ def mk_relationship(source, target, catalog)
+ unless source_resource = catalog.resource(source.to_s)
+ raise ArgumentError, "Could not find resource '#{source}' for relationship on '#{target}'"
+ end
+ unless target_resource = catalog.resource(target.to_s)
+ raise ArgumentError, "Could not find resource '#{target}' for relationship from '#{source}'"
end
+ Puppet.debug "Adding relationship from #{source.to_s} to #{target.to_s} with '#{param_name}'"
+ source_resource[param_name] ||= []
+ source_resource[param_name] << target.to_s
+ end
end
diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb
index 2d31b40e7..3cccf4f3e 100644
--- a/lib/puppet/parser/resource.rb
+++ b/lib/puppet/parser/resource.rb
@@ -4,323 +4,323 @@ require 'puppet/resource'
# parent is that this class has rules on who can set
# parameters
class Puppet::Parser::Resource < Puppet::Resource
- require 'puppet/parser/resource/param'
- require 'puppet/util/tagging'
- require 'puppet/file_collection/lookup'
- require 'puppet/parser/yaml_trimmer'
- require 'puppet/resource/type_collection_helper'
-
- include Puppet::FileCollection::Lookup
- include Puppet::Resource::TypeCollectionHelper
-
- include Puppet::Util
- include Puppet::Util::MethodHelper
- include Puppet::Util::Errors
- include Puppet::Util::Logging
- include Puppet::Util::Tagging
- include Puppet::Parser::YamlTrimmer
-
- attr_accessor :source, :scope, :rails_id
- attr_accessor :virtual, :override, :translated, :catalog, :evaluated
-
- attr_reader :exported, :parameters
-
- # Determine whether the provided parameter name is a relationship parameter.
- def self.relationship_parameter?(name)
- @relationship_names ||= Puppet::Type.relationship_params.collect { |p| p.name }
- @relationship_names.include?(name)
+ require 'puppet/parser/resource/param'
+ require 'puppet/util/tagging'
+ require 'puppet/file_collection/lookup'
+ require 'puppet/parser/yaml_trimmer'
+ require 'puppet/resource/type_collection_helper'
+
+ include Puppet::FileCollection::Lookup
+ include Puppet::Resource::TypeCollectionHelper
+
+ include Puppet::Util
+ include Puppet::Util::MethodHelper
+ include Puppet::Util::Errors
+ include Puppet::Util::Logging
+ include Puppet::Util::Tagging
+ include Puppet::Parser::YamlTrimmer
+
+ attr_accessor :source, :scope, :rails_id
+ attr_accessor :virtual, :override, :translated, :catalog, :evaluated
+
+ attr_reader :exported, :parameters
+
+ # Determine whether the provided parameter name is a relationship parameter.
+ def self.relationship_parameter?(name)
+ @relationship_names ||= Puppet::Type.relationship_params.collect { |p| p.name }
+ @relationship_names.include?(name)
+ end
+
+ # Set up some boolean test methods
+ [:translated, :override, :evaluated].each do |method|
+ newmeth = (method.to_s + "?").intern
+ define_method(newmeth) do
+ self.send(method)
end
+ end
- # Set up some boolean test methods
- [:translated, :override, :evaluated].each do |method|
- newmeth = (method.to_s + "?").intern
- define_method(newmeth) do
- self.send(method)
- end
- end
-
- def [](param)
- param = symbolize(param)
- if param == :title
- return self.title
- end
- if @parameters.has_key?(param)
- @parameters[param].value
- else
- nil
- end
- end
-
- def []=(param, value)
- set_parameter(param, value)
+ def [](param)
+ param = symbolize(param)
+ if param == :title
+ return self.title
end
-
- def eachparam
- @parameters.each do |name, param|
- yield param
- end
+ if @parameters.has_key?(param)
+ @parameters[param].value
+ else
+ nil
end
+ end
- def environment
- scope.environment
- end
+ def []=(param, value)
+ set_parameter(param, value)
+ end
- # Retrieve the associated definition and evaluate it.
- def evaluate
- if klass = resource_type and ! builtin_type?
- finish
- return klass.evaluate_code(self)
- elsif builtin?
- devfail "Cannot evaluate a builtin type (#{type})"
- else
- self.fail "Cannot find definition #{type}"
- end
- ensure
- @evaluated = true
+ def eachparam
+ @parameters.each do |name, param|
+ yield param
end
-
- # Mark this resource as both exported and virtual,
- # or remove the exported mark.
- def exported=(value)
- if value
- @virtual = true
- @exported = value
- else
- @exported = value
- end
+ end
+
+ def environment
+ scope.environment
+ end
+
+ # Retrieve the associated definition and evaluate it.
+ def evaluate
+ if klass = resource_type and ! builtin_type?
+ finish
+ return klass.evaluate_code(self)
+ elsif builtin?
+ devfail "Cannot evaluate a builtin type (#{type})"
+ else
+ self.fail "Cannot find definition #{type}"
end
-
- # Do any finishing work on this object, called before evaluation or
- # before storage/translation.
- def finish
- return if finished?
- @finished = true
- add_defaults
- add_metaparams
- validate
+ ensure
+ @evaluated = true
+ end
+
+ # Mark this resource as both exported and virtual,
+ # or remove the exported mark.
+ def exported=(value)
+ if value
+ @virtual = true
+ @exported = value
+ else
+ @exported = value
end
-
- # Has this resource already been finished?
- def finished?
- @finished
+ end
+
+ # Do any finishing work on this object, called before evaluation or
+ # before storage/translation.
+ def finish
+ return if finished?
+ @finished = true
+ add_defaults
+ add_metaparams
+ validate
+ end
+
+ # Has this resource already been finished?
+ def finished?
+ @finished
+ end
+
+ def initialize(*args)
+ super
+
+ raise ArgumentError, "Resources require a scope" unless scope
+ @source ||= scope.source
+ end
+
+ # Is this resource modeling an isomorphic resource type?
+ def isomorphic?
+ if builtin_type?
+ return resource_type.isomorphic?
+ else
+ return true
end
-
- def initialize(*args)
- super
-
- raise ArgumentError, "Resources require a scope" unless scope
- @source ||= scope.source
+ end
+
+ # Merge an override resource in. This will throw exceptions if
+ # any overrides aren't allowed.
+ def merge(resource)
+ # Test the resource scope, to make sure the resource is even allowed
+ # to override.
+ unless self.source.object_id == resource.source.object_id || resource.source.child_of?(self.source)
+ raise Puppet::ParseError.new("Only subclasses can override parameters", resource.line, resource.file)
end
-
- # Is this resource modeling an isomorphic resource type?
- def isomorphic?
- if builtin_type?
- return resource_type.isomorphic?
- else
- return true
- end
+ # Some of these might fail, but they'll fail in the way we want.
+ resource.parameters.each do |name, param|
+ override_parameter(param)
end
-
- # Merge an override resource in. This will throw exceptions if
- # any overrides aren't allowed.
- def merge(resource)
- # Test the resource scope, to make sure the resource is even allowed
- # to override.
- unless self.source.object_id == resource.source.object_id || resource.source.child_of?(self.source)
- raise Puppet::ParseError.new("Only subclasses can override parameters", resource.line, resource.file)
- end
- # Some of these might fail, but they'll fail in the way we want.
- resource.parameters.each do |name, param|
- override_parameter(param)
- end
+ end
+
+ # Unless we're running >= 0.25, we're in compat mode.
+ def metaparam_compatibility_mode?
+ ! (catalog and ver = (catalog.client_version||'0.0.0').split(".") and (ver[0] > "0" or ver[1].to_i >= 25))
+ end
+
+ def name
+ self[:name] || self.title
+ end
+
+ def namespaces
+ scope.namespaces
+ end
+
+ # A temporary occasion, until I get paths in the scopes figured out.
+ def path
+ to_s
+ end
+
+ # Define a parameter in our resource.
+ # if we ever receive a parameter named 'tag', set
+ # the resource tags with its value.
+ def set_parameter(param, value = nil)
+ if ! value.nil?
+ param = Puppet::Parser::Resource::Param.new(
+ :name => param, :value => value, :source => self.source
+ )
+ elsif ! param.is_a?(Puppet::Parser::Resource::Param)
+ raise ArgumentError, "Must pass a parameter or all necessary values"
end
- # Unless we're running >= 0.25, we're in compat mode.
- def metaparam_compatibility_mode?
- ! (catalog and ver = (catalog.client_version||'0.0.0').split(".") and (ver[0] > "0" or ver[1].to_i >= 25))
- end
+ tag(*param.value) if param.name == :tag
- def name
- self[:name] || self.title
- end
+ # And store it in our parameter hash.
+ @parameters[param.name] = param
+ end
- def namespaces
- scope.namespaces
+ def to_hash
+ @parameters.inject({}) do |hash, ary|
+ param = ary[1]
+ # Skip "undef" values.
+ hash[param.name] = param.value if param.value != :undef
+ hash
end
-
- # A temporary occasion, until I get paths in the scopes figured out.
- def path
- to_s
- end
-
- # Define a parameter in our resource.
- # if we ever receive a parameter named 'tag', set
- # the resource tags with its value.
- def set_parameter(param, value = nil)
- if ! value.nil?
- param = Puppet::Parser::Resource::Param.new(
- :name => param, :value => value, :source => self.source
- )
- elsif ! param.is_a?(Puppet::Parser::Resource::Param)
- raise ArgumentError, "Must pass a parameter or all necessary values"
+ end
+
+
+ # Create a Puppet::Resource instance from this parser resource.
+ # We plan, at some point, on not needing to do this conversion, but
+ # it's sufficient for now.
+ def to_resource
+ result = Puppet::Resource.new(type, title)
+
+ to_hash.each do |p, v|
+ if v.is_a?(Puppet::Resource)
+ v = Puppet::Resource.new(v.type, v.title)
+ elsif v.is_a?(Array)
+ # flatten resource references arrays
+ v = v.flatten if v.flatten.find { |av| av.is_a?(Puppet::Resource) }
+ v = v.collect do |av|
+ av = Puppet::Resource.new(av.type, av.title) if av.is_a?(Puppet::Resource)
+ av
end
-
- tag(*param.value) if param.name == :tag
-
- # And store it in our parameter hash.
- @parameters[param.name] = param
+ end
+
+ # If the value is an array with only one value, then
+ # convert it to a single value. This is largely so that
+ # the database interaction doesn't have to worry about
+ # whether it returns an array or a string.
+ result[p] = if v.is_a?(Array) and v.length == 1
+ v[0]
+ else
+ v
+ end
end
- def to_hash
- @parameters.inject({}) do |hash, ary|
- param = ary[1]
- # Skip "undef" values.
- hash[param.name] = param.value if param.value != :undef
- hash
- end
- end
+ result.file = self.file
+ result.line = self.line
+ result.exported = self.exported
+ result.virtual = self.virtual
+ result.tag(*self.tags)
+ result
+ end
- # Create a Puppet::Resource instance from this parser resource.
- # We plan, at some point, on not needing to do this conversion, but
- # it's sufficient for now.
- def to_resource
- result = Puppet::Resource.new(type, title)
-
- to_hash.each do |p, v|
- if v.is_a?(Puppet::Resource)
- v = Puppet::Resource.new(v.type, v.title)
- elsif v.is_a?(Array)
- # flatten resource references arrays
- v = v.flatten if v.flatten.find { |av| av.is_a?(Puppet::Resource) }
- v = v.collect do |av|
- av = Puppet::Resource.new(av.type, av.title) if av.is_a?(Puppet::Resource)
- av
- end
- end
-
- # If the value is an array with only one value, then
- # convert it to a single value. This is largely so that
- # the database interaction doesn't have to worry about
- # whether it returns an array or a string.
- result[p] = if v.is_a?(Array) and v.length == 1
- v[0]
- else
- v
- end
- end
+ # Translate our object to a transportable object.
+ def to_trans
+ return nil if virtual?
- result.file = self.file
- result.line = self.line
- result.exported = self.exported
- result.virtual = self.virtual
- result.tag(*self.tags)
+ to_resource.to_trans
+ end
- result
- end
+ # Convert this resource to a RAL resource. We hackishly go via the
+ # transportable stuff.
+ def to_ral
+ to_resource.to_ral
+ end
- # Translate our object to a transportable object.
- def to_trans
- return nil if virtual?
+ private
- to_resource.to_trans
- end
+ # Add default values from our definition.
+ def add_defaults
+ scope.lookupdefaults(self.type).each do |name, param|
+ unless @parameters.include?(name)
+ self.debug "Adding default for #{name}"
- # Convert this resource to a RAL resource. We hackishly go via the
- # transportable stuff.
- def to_ral
- to_resource.to_ral
+ @parameters[name] = param.dup
+ end
end
+ end
- private
+ def add_backward_compatible_relationship_param(name)
+ # Skip metaparams for which we get no value.
+ return unless val = scope.lookupvar(name.to_s, false) and val != :undefined
- # Add default values from our definition.
- def add_defaults
- scope.lookupdefaults(self.type).each do |name, param|
- unless @parameters.include?(name)
- self.debug "Adding default for #{name}"
+ # The default case: just set the value
+ set_parameter(name, val) and return unless @parameters[name]
- @parameters[name] = param.dup
- end
- end
- end
+ # For relationship params, though, join the values (a la #446).
+ @parameters[name].value = [@parameters[name].value, val].flatten
+ end
- def add_backward_compatible_relationship_param(name)
- # Skip metaparams for which we get no value.
- return unless val = scope.lookupvar(name.to_s, false) and val != :undefined
+ # Add any metaparams defined in our scope. This actually adds any metaparams
+ # from any parent scope, and there's currently no way to turn that off.
+ def add_metaparams
+ compat_mode = metaparam_compatibility_mode?
- # The default case: just set the value
- set_parameter(name, val) and return unless @parameters[name]
-
- # For relationship params, though, join the values (a la #446).
- @parameters[name].value = [@parameters[name].value, val].flatten
+ Puppet::Type.eachmetaparam do |name|
+ next unless self.class.relationship_parameter?(name)
+ add_backward_compatible_relationship_param(name) if compat_mode
end
-
- # Add any metaparams defined in our scope. This actually adds any metaparams
- # from any parent scope, and there's currently no way to turn that off.
- def add_metaparams
- compat_mode = metaparam_compatibility_mode?
-
- Puppet::Type.eachmetaparam do |name|
- next unless self.class.relationship_parameter?(name)
- add_backward_compatible_relationship_param(name) if compat_mode
- end
+ end
+
+ # Accept a parameter from an override.
+ def override_parameter(param)
+ # This can happen if the override is defining a new parameter, rather
+ # than replacing an existing one.
+ (set_parameter(param) and return) unless current = @parameters[param.name]
+
+ # The parameter is already set. Fail if they're not allowed to override it.
+ unless param.source.child_of?(current.source)
+ puts caller if Puppet[:trace]
+ msg = "Parameter '#{param.name}' is already set on #{self}"
+ msg += " by #{current.source}" if current.source.to_s != ""
+ if current.file or current.line
+ fields = []
+ fields << current.file if current.file
+ fields << current.line.to_s if current.line
+ msg += " at #{fields.join(":")}"
+ end
+ msg += "; cannot redefine"
+ raise Puppet::ParseError.new(msg, param.line, param.file)
end
- # Accept a parameter from an override.
- def override_parameter(param)
- # This can happen if the override is defining a new parameter, rather
- # than replacing an existing one.
- (set_parameter(param) and return) unless current = @parameters[param.name]
-
- # The parameter is already set. Fail if they're not allowed to override it.
- unless param.source.child_of?(current.source)
- puts caller if Puppet[:trace]
- msg = "Parameter '#{param.name}' is already set on #{self}"
- msg += " by #{current.source}" if current.source.to_s != ""
- if current.file or current.line
- fields = []
- fields << current.file if current.file
- fields << current.line.to_s if current.line
- msg += " at #{fields.join(":")}"
- end
- msg += "; cannot redefine"
- raise Puppet::ParseError.new(msg, param.line, param.file)
- end
-
- # If we've gotten this far, we're allowed to override.
-
- # Merge with previous value, if the parameter was generated with the +>
- # syntax. It's important that we use a copy of the new param instance
- # here, not the old one, and not the original new one, so that the source
- # is registered correctly for later overrides but the values aren't
- # implcitly shared when multiple resources are overrriden at once (see
- # ticket #3556).
- if param.add
- param = param.dup
- param.value = [current.value, param.value].flatten
- end
-
- set_parameter(param)
+ # If we've gotten this far, we're allowed to override.
+
+ # Merge with previous value, if the parameter was generated with the +>
+ # syntax. It's important that we use a copy of the new param instance
+ # here, not the old one, and not the original new one, so that the source
+ # is registered correctly for later overrides but the values aren't
+ # implcitly shared when multiple resources are overrriden at once (see
+ # ticket #3556).
+ if param.add
+ param = param.dup
+ param.value = [current.value, param.value].flatten
end
- # Make sure the resource's parameters are all valid for the type.
- def validate
- @parameters.each do |name, param|
- validate_parameter(name)
- end
- rescue => detail
- fail Puppet::ParseError, detail.to_s
+ set_parameter(param)
+ end
+
+ # Make sure the resource's parameters are all valid for the type.
+ def validate
+ @parameters.each do |name, param|
+ validate_parameter(name)
end
+ rescue => detail
+ fail Puppet::ParseError, detail.to_s
+ end
- private
+ private
- def extract_parameters(params)
- params.each do |param|
- # Don't set the same parameter twice
- self.fail Puppet::ParseError, "Duplicate parameter '#{param.name}' for on #{self}" if @parameters[param.name]
+ def extract_parameters(params)
+ params.each do |param|
+ # Don't set the same parameter twice
+ self.fail Puppet::ParseError, "Duplicate parameter '#{param.name}' for on #{self}" if @parameters[param.name]
- set_parameter(param)
- end
+ set_parameter(param)
end
+ end
end
diff --git a/lib/puppet/parser/resource/param.rb b/lib/puppet/parser/resource/param.rb
index 7ca240df7..af2d98fe8 100644
--- a/lib/puppet/parser/resource/param.rb
+++ b/lib/puppet/parser/resource/param.rb
@@ -3,25 +3,25 @@ require 'puppet/parser/yaml_trimmer'
# The parameters we stick in Resources.
class Puppet::Parser::Resource::Param
- attr_accessor :name, :value, :source, :add
- include Puppet::Util
- include Puppet::Util::Errors
- include Puppet::Util::MethodHelper
+ attr_accessor :name, :value, :source, :add
+ include Puppet::Util
+ include Puppet::Util::Errors
+ include Puppet::Util::MethodHelper
- include Puppet::FileCollection::Lookup
- include Puppet::Parser::YamlTrimmer
+ include Puppet::FileCollection::Lookup
+ include Puppet::Parser::YamlTrimmer
- def initialize(hash)
- set_options(hash)
- requiredopts(:name, :value, :source)
- @name = symbolize(@name)
- end
+ def initialize(hash)
+ set_options(hash)
+ requiredopts(:name, :value, :source)
+ @name = symbolize(@name)
+ end
- def line_to_i
- line ? Integer(line) : nil
- end
+ def line_to_i
+ line ? Integer(line) : nil
+ end
- def to_s
- "#{self.name} => #{self.value}"
- end
+ def to_s
+ "#{self.name} => #{self.value}"
+ end
end
diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb
index 9b49ab680..ae0f9ea4a 100644
--- a/lib/puppet/parser/scope.rb
+++ b/lib/puppet/parser/scope.rb
@@ -9,475 +9,475 @@ require 'strscan'
require 'puppet/resource/type_collection_helper'
class Puppet::Parser::Scope
- include Puppet::Resource::TypeCollectionHelper
- require 'puppet/parser/resource'
-
- AST = Puppet::Parser::AST
-
- Puppet::Util.logmethods(self)
-
- include Enumerable
- include Puppet::Util::Errors
- attr_accessor :level, :source, :resource
- attr_accessor :base, :keyword
- attr_accessor :top, :translated, :compiler
- attr_accessor :parent
- attr_reader :namespaces
-
- # thin wrapper around an ephemeral
- # symbol table.
- # when a symbol
- class Ephemeral
- def initialize(parent=nil)
- @symbols = {}
- @parent = parent
+ include Puppet::Resource::TypeCollectionHelper
+ require 'puppet/parser/resource'
+
+ AST = Puppet::Parser::AST
+
+ Puppet::Util.logmethods(self)
+
+ include Enumerable
+ include Puppet::Util::Errors
+ attr_accessor :level, :source, :resource
+ attr_accessor :base, :keyword
+ attr_accessor :top, :translated, :compiler
+ attr_accessor :parent
+ attr_reader :namespaces
+
+ # thin wrapper around an ephemeral
+ # symbol table.
+ # when a symbol
+ class Ephemeral
+ def initialize(parent=nil)
+ @symbols = {}
+ @parent = parent
+ end
+
+ [:include?, :delete, :[]=].each do |m|
+ define_method(m) do |*args|
+ @symbols.send(m, *args)
+ end
+ end
+
+ def [](name)
+ unless @symbols.include?(name) or @parent.nil?
+ @parent[name]
+ else
+ @symbols[name]
+ end
+ end
+ end
+
+ # A demeterific shortcut to the catalog.
+ def catalog
+ compiler.catalog
+ end
+
+ def environment
+ compiler.environment
+ end
+
+ # Proxy accessors
+ def host
+ @compiler.node.name
+ end
+
+ # Is the value true? This allows us to control the definition of truth
+ # in one place.
+ def self.true?(value)
+ (value != false and value != "" and value != :undef)
+ end
+
+ # Is the value a number?, return the correct object or nil if not a number
+ def self.number?(value)
+ return nil unless value.is_a?(Fixnum) or value.is_a?(Bignum) or value.is_a?(Float) or value.is_a?(String)
+
+ if value.is_a?(String)
+ if value =~ /^-?\d+(:?\.\d+|(:?\.\d+)?e\d+)$/
+ return value.to_f
+ elsif value =~ /^0x[0-9a-f]+$/i
+ return value.to_i(16)
+ elsif value =~ /^0[0-7]+$/
+ return value.to_i(8)
+ elsif value =~ /^-?\d+$/
+ return value.to_i
+ else
+ return nil
+ end
+ end
+ # it is one of Fixnum,Bignum or Float
+ value
+ end
+
+ # Add to our list of namespaces.
+ def add_namespace(ns)
+ return false if @namespaces.include?(ns)
+ if @namespaces == [""]
+ @namespaces = [ns]
+ else
+ @namespaces << ns
+ end
+ end
+
+ # Remove this when rebasing
+ def environment
+ compiler.environment
+ end
+
+ # Are we the top scope?
+ def topscope?
+ @level == 1
+ end
+
+ def find_hostclass(name)
+ known_resource_types.find_hostclass(namespaces, name)
+ end
+
+ def find_definition(name)
+ known_resource_types.find_definition(namespaces, name)
+ end
+
+ def findresource(string, name = nil)
+ compiler.findresource(string, name)
+ end
+
+ # Initialize our new scope. Defaults to having no parent.
+ def initialize(hash = {})
+ if hash.include?(:namespace)
+ if n = hash[:namespace]
+ @namespaces = [n]
+ end
+ hash.delete(:namespace)
+ else
+ @namespaces = [""]
+ end
+ hash.each { |name, val|
+ method = name.to_s + "="
+ if self.respond_to? method
+ self.send(method, val)
+ else
+ raise Puppet::DevError, "Invalid scope argument #{name}"
+ end
+ }
+
+ extend_with_functions_module
+
+ @tags = []
+
+ # The symbol table for this scope. This is where we store variables.
+ @symtable = {}
+
+ # the ephemeral symbol tables
+ # those should not persist long, and are used for the moment only
+ # for $0..$xy capture variables of regexes
+ # this is actually implemented as a stack, with each ephemeral scope
+ # shadowing the previous one
+ @ephemeral = [ Ephemeral.new ]
+
+ # All of the defaults set for types. It's a hash of hashes,
+ # with the first key being the type, then the second key being
+ # the parameter.
+ @defaults = Hash.new { |dhash,type|
+ dhash[type] = {}
+ }
+
+ # The table for storing class singletons. This will only actually
+ # be used by top scopes and node scopes.
+ @class_scopes = {}
+ end
+
+ # Store the fact that we've evaluated a class, and store a reference to
+ # the scope in which it was evaluated, so that we can look it up later.
+ def class_set(name, scope)
+ return parent.class_set(name,scope) if parent
+ @class_scopes[name] = scope
+ end
+
+ # Return the scope associated with a class. This is just here so
+ # that subclasses can set their parent scopes to be the scope of
+ # their parent class, and it's also used when looking up qualified
+ # variables.
+ def class_scope(klass)
+ # They might pass in either the class or class name
+ k = klass.respond_to?(:name) ? klass.name : klass
+ @class_scopes[k] || (parent && parent.class_scope(k))
+ end
+
+ # Collect all of the defaults set at any higher scopes.
+ # This is a different type of lookup because it's additive --
+ # it collects all of the defaults, with defaults in closer scopes
+ # overriding those in later scopes.
+ def lookupdefaults(type)
+ values = {}
+
+ # first collect the values from the parents
+ unless parent.nil?
+ parent.lookupdefaults(type).each { |var,value|
+ values[var] = value
+ }
+ end
+
+ # then override them with any current values
+ # this should probably be done differently
+ if @defaults.include?(type)
+ @defaults[type].each { |var,value|
+ values[var] = value
+ }
+ end
+
+ #Puppet.debug "Got defaults for %s: %s" %
+ # [type,values.inspect]
+ values
+ end
+
+ # Look up a defined type.
+ def lookuptype(name)
+ find_definition(name) || find_hostclass(name)
+ end
+
+ def lookup_qualified_var(name, usestring)
+ parts = name.split(/::/)
+ shortname = parts.pop
+ klassname = parts.join("::")
+ klass = find_hostclass(klassname)
+ unless klass
+ warning "Could not look up qualified variable '#{name}'; class #{klassname} could not be found"
+ return usestring ? "" : :undefined
+ end
+ unless kscope = class_scope(klass)
+ warning "Could not look up qualified variable '#{name}'; class #{klassname} has not been evaluated"
+ return usestring ? "" : :undefined
+ end
+ kscope.lookupvar(shortname, usestring)
+ end
+
+ private :lookup_qualified_var
+
+ # Look up a variable. The simplest value search we do. Default to returning
+ # an empty string for missing values, but support returning a constant.
+ def lookupvar(name, usestring = true)
+ table = ephemeral?(name) ? @ephemeral.last : @symtable
+ # If the variable is qualified, then find the specified scope and look the variable up there instead.
+ if name =~ /::/
+ return lookup_qualified_var(name, usestring)
+ end
+ # We can't use "if table[name]" here because the value might be false
+ if ephemeral_include?(name) or table.include?(name)
+ if usestring and table[name] == :undef
+ return ""
+ else
+ return table[name]
+ end
+ elsif self.parent
+ return parent.lookupvar(name, usestring)
+ elsif usestring
+ return ""
+ else
+ return :undefined
+ end
+ end
+
+ # Return a hash containing our variables and their values, optionally (and
+ # by default) including the values defined in our parent. Local values
+ # shadow parent values.
+ def to_hash(recursive = true)
+ target = parent.to_hash(recursive) if recursive and parent
+ target ||= Hash.new
+ @symtable.keys.each { |name|
+ value = @symtable[name]
+ if value == :undef
+ target.delete(name)
+ else
+ target[name] = value
+ end
+ }
+ target
+ end
+
+ def namespaces
+ @namespaces.dup
+ end
+
+ # Create a new scope and set these options.
+ def newscope(options = {})
+ compiler.newscope(self, options)
+ end
+
+ def parent_module_name
+ return nil unless @parent
+ return nil unless @parent.source
+ @parent.source.module_name
+ end
+
+ # Return the list of scopes up to the top scope, ordered with our own first.
+ # This is used for looking up variables and defaults.
+ def scope_path
+ if parent
+ [self, parent.scope_path].flatten.compact
+ else
+ [self]
+ end
+ end
+
+ # Set defaults for a type. The typename should already be downcased,
+ # so that the syntax is isolated. We don't do any kind of type-checking
+ # here; instead we let the resource do it when the defaults are used.
+ def setdefaults(type, params)
+ table = @defaults[type]
+
+ # if we got a single param, it'll be in its own array
+ params = [params] unless params.is_a?(Array)
+
+ params.each { |param|
+ #Puppet.debug "Default for %s is %s => %s" %
+ # [type,ary[0].inspect,ary[1].inspect]
+ if table.include?(param.name)
+ raise Puppet::ParseError.new("Default already defined for #{type} { #{param.name} }; cannot redefine", param.line, param.file)
+ end
+ table[param.name] = param
+ }
+ end
+
+ # Set a variable in the current scope. This will override settings
+ # in scopes above, but will not allow variables in the current scope
+ # to be reassigned.
+ def setvar(name,value, options = {})
+ table = options[:ephemeral] ? @ephemeral.last : @symtable
+ #Puppet.debug "Setting %s to '%s' at level %s mode append %s" %
+ # [name.inspect,value,self.level, append]
+ if table.include?(name)
+ unless options[:append]
+ error = Puppet::ParseError.new("Cannot reassign variable #{name}")
+ else
+ error = Puppet::ParseError.new("Cannot append, variable #{name} is defined in this scope")
+ end
+ error.file = options[:file] if options[:file]
+ error.line = options[:line] if options[:line]
+ raise error
+ end
+
+ unless options[:append]
+ table[name] = value
+ else # append case
+ # lookup the value in the scope if it exists and insert the var
+ table[name] = lookupvar(name)
+ # concatenate if string, append if array, nothing for other types
+ case value
+ when Array
+ table[name] += value
+ when Hash
+ raise ArgumentError, "Trying to append to a hash with something which is not a hash is unsupported" unless value.is_a?(Hash)
+ table[name].merge!(value)
+ else
+ table[name] << value
+ end
+ end
+ end
+
+ # Return an interpolated string.
+ def strinterp(string, file = nil, line = nil)
+ # Most strings won't have variables in them.
+ ss = StringScanner.new(string)
+ out = ""
+ while not ss.eos?
+ if ss.scan(/^\$\{((\w*::)*\w+|[0-9]+)\}|^\$([0-9])|^\$((\w*::)*\w+)/)
+ # If it matches the backslash, then just retun the dollar sign.
+ if ss.matched == '\\$'
+ out << '$'
+ else # look the variable up
+ # make sure $0-$9 are lookupable only if ephemeral
+ var = ss[1] || ss[3] || ss[4]
+ if var and var =~ /^[0-9]+$/ and not ephemeral_include?(var)
+ next
+ end
+ out << lookupvar(var).to_s || ""
end
-
- [:include?, :delete, :[]=].each do |m|
- define_method(m) do |*args|
- @symbols.send(m, *args)
- end
- end
-
- def [](name)
- unless @symbols.include?(name) or @parent.nil?
- @parent[name]
- else
- @symbols[name]
- end
- end
- end
-
- # A demeterific shortcut to the catalog.
- def catalog
- compiler.catalog
- end
-
- def environment
- compiler.environment
- end
-
- # Proxy accessors
- def host
- @compiler.node.name
- end
-
- # Is the value true? This allows us to control the definition of truth
- # in one place.
- def self.true?(value)
- (value != false and value != "" and value != :undef)
- end
-
- # Is the value a number?, return the correct object or nil if not a number
- def self.number?(value)
- return nil unless value.is_a?(Fixnum) or value.is_a?(Bignum) or value.is_a?(Float) or value.is_a?(String)
-
- if value.is_a?(String)
- if value =~ /^-?\d+(:?\.\d+|(:?\.\d+)?e\d+)$/
- return value.to_f
- elsif value =~ /^0x[0-9a-f]+$/i
- return value.to_i(16)
- elsif value =~ /^0[0-7]+$/
- return value.to_i(8)
- elsif value =~ /^-?\d+$/
- return value.to_i
- else
- return nil
- end
- end
- # it is one of Fixnum,Bignum or Float
- value
- end
-
- # Add to our list of namespaces.
- def add_namespace(ns)
- return false if @namespaces.include?(ns)
- if @namespaces == [""]
- @namespaces = [ns]
+ elsif ss.scan(/^\\(.)/)
+ # Puppet.debug("Got escape: pos:%d; m:%s" % [ss.pos, ss.matched])
+ case ss[1]
+ when 'n'
+ out << "\n"
+ when 't'
+ out << "\t"
+ when 's'
+ out << " "
+ when '\\'
+ out << '\\'
+ when '$'
+ out << '$'
else
- @namespaces << ns
+ str = "Unrecognised escape sequence '#{ss.matched}'"
+ str += " in file #{file}" if file
+ str += " at line #{line}" if line
+ Puppet.warning str
+ out << ss.matched
end
- end
-
- # Remove this when rebasing
- def environment
- compiler.environment
- end
-
- # Are we the top scope?
- def topscope?
- @level == 1
- end
-
- def find_hostclass(name)
- known_resource_types.find_hostclass(namespaces, name)
- end
-
- def find_definition(name)
- known_resource_types.find_definition(namespaces, name)
- end
-
- def findresource(string, name = nil)
- compiler.findresource(string, name)
- end
-
- # Initialize our new scope. Defaults to having no parent.
- def initialize(hash = {})
- if hash.include?(:namespace)
- if n = hash[:namespace]
- @namespaces = [n]
- end
- hash.delete(:namespace)
- else
- @namespaces = [""]
+ elsif ss.scan(/^\$/)
+ out << '$'
+ elsif ss.scan(/^\\\n/) # an escaped carriage return
+ next
+ else
+ tmp = ss.scan(/[^\\$]+/)
+ # Puppet.debug("Got other: pos:%d; m:%s" % [ss.pos, tmp])
+ unless tmp
+ error = Puppet::ParseError.new("Could not parse string #{string.inspect}")
+ {:file= => file, :line= => line}.each do |m,v|
+ error.send(m, v) if v
+ end
+ raise error
end
- hash.each { |name, val|
- method = name.to_s + "="
- if self.respond_to? method
- self.send(method, val)
- else
- raise Puppet::DevError, "Invalid scope argument #{name}"
- end
- }
-
- extend_with_functions_module
-
- @tags = []
-
- # The symbol table for this scope. This is where we store variables.
- @symtable = {}
-
- # the ephemeral symbol tables
- # those should not persist long, and are used for the moment only
- # for $0..$xy capture variables of regexes
- # this is actually implemented as a stack, with each ephemeral scope
- # shadowing the previous one
- @ephemeral = [ Ephemeral.new ]
-
- # All of the defaults set for types. It's a hash of hashes,
- # with the first key being the type, then the second key being
- # the parameter.
- @defaults = Hash.new { |dhash,type|
- dhash[type] = {}
- }
-
- # The table for storing class singletons. This will only actually
- # be used by top scopes and node scopes.
- @class_scopes = {}
+ out << tmp
+ end
end
- # Store the fact that we've evaluated a class, and store a reference to
- # the scope in which it was evaluated, so that we can look it up later.
- def class_set(name, scope)
- return parent.class_set(name,scope) if parent
- @class_scopes[name] = scope
- end
+ out
+ end
- # Return the scope associated with a class. This is just here so
- # that subclasses can set their parent scopes to be the scope of
- # their parent class, and it's also used when looking up qualified
- # variables.
- def class_scope(klass)
- # They might pass in either the class or class name
- k = klass.respond_to?(:name) ? klass.name : klass
- @class_scopes[k] || (parent && parent.class_scope(k))
- end
+ # Return the tags associated with this scope. It's basically
+ # just our parents' tags, plus our type. We don't cache this value
+ # because our parent tags might change between calls.
+ def tags
+ resource.tags
+ end
- # Collect all of the defaults set at any higher scopes.
- # This is a different type of lookup because it's additive --
- # it collects all of the defaults, with defaults in closer scopes
- # overriding those in later scopes.
- def lookupdefaults(type)
- values = {}
-
- # first collect the values from the parents
- unless parent.nil?
- parent.lookupdefaults(type).each { |var,value|
- values[var] = value
- }
- end
+ # Used mainly for logging
+ def to_s
+ "Scope(#{@resource})"
+ end
- # then override them with any current values
- # this should probably be done differently
- if @defaults.include?(type)
- @defaults[type].each { |var,value|
- values[var] = value
- }
- end
+ # Undefine a variable; only used for testing.
+ def unsetvar(var)
+ table = ephemeral?(var) ? @ephemeral.last : @symtable
+ table.delete(var) if table.include?(var)
+ end
- #Puppet.debug "Got defaults for %s: %s" %
- # [type,values.inspect]
- values
+ # remove ephemeral scope up to level
+ def unset_ephemeral_var(level=:all)
+ if level == :all
+ @ephemeral = [ Ephemeral.new ]
+ else
+ (@ephemeral.size - level).times do
+ @ephemeral.pop
+ end
end
+ end
- # Look up a defined type.
- def lookuptype(name)
- find_definition(name) || find_hostclass(name)
+ # check if name exists in one of the ephemeral scope.
+ def ephemeral_include?(name)
+ @ephemeral.reverse.each do |eph|
+ return true if eph.include?(name)
end
+ false
+ end
- def lookup_qualified_var(name, usestring)
- parts = name.split(/::/)
- shortname = parts.pop
- klassname = parts.join("::")
- klass = find_hostclass(klassname)
- unless klass
- warning "Could not look up qualified variable '#{name}'; class #{klassname} could not be found"
- return usestring ? "" : :undefined
- end
- unless kscope = class_scope(klass)
- warning "Could not look up qualified variable '#{name}'; class #{klassname} has not been evaluated"
- return usestring ? "" : :undefined
- end
- kscope.lookupvar(shortname, usestring)
- end
+ # is name an ephemeral variable?
+ def ephemeral?(name)
+ name =~ /^\d+$/
+ end
- private :lookup_qualified_var
+ def ephemeral_level
+ @ephemeral.size
+ end
- # Look up a variable. The simplest value search we do. Default to returning
- # an empty string for missing values, but support returning a constant.
- def lookupvar(name, usestring = true)
- table = ephemeral?(name) ? @ephemeral.last : @symtable
- # If the variable is qualified, then find the specified scope and look the variable up there instead.
- if name =~ /::/
- return lookup_qualified_var(name, usestring)
- end
- # We can't use "if table[name]" here because the value might be false
- if ephemeral_include?(name) or table.include?(name)
- if usestring and table[name] == :undef
- return ""
- else
- return table[name]
- end
- elsif self.parent
- return parent.lookupvar(name, usestring)
- elsif usestring
- return ""
- else
- return :undefined
- end
- end
+ def new_ephemeral
+ @ephemeral.push(Ephemeral.new(@ephemeral.last))
+ end
- # Return a hash containing our variables and their values, optionally (and
- # by default) including the values defined in our parent. Local values
- # shadow parent values.
- def to_hash(recursive = true)
- target = parent.to_hash(recursive) if recursive and parent
- target ||= Hash.new
- @symtable.keys.each { |name|
- value = @symtable[name]
- if value == :undef
- target.delete(name)
- else
- target[name] = value
- end
- }
- target
- end
+ def ephemeral_from(match, file = nil, line = nil)
+ raise(ArgumentError,"Invalid regex match data") unless match.is_a?(MatchData)
- def namespaces
- @namespaces.dup
- end
+ new_ephemeral
- # Create a new scope and set these options.
- def newscope(options = {})
- compiler.newscope(self, options)
+ setvar("0", match[0], :file => file, :line => line, :ephemeral => true)
+ match.captures.each_with_index do |m,i|
+ setvar("#{i+1}", m, :file => file, :line => line, :ephemeral => true)
end
+ end
- def parent_module_name
- return nil unless @parent
- return nil unless @parent.source
- @parent.source.module_name
- end
-
- # Return the list of scopes up to the top scope, ordered with our own first.
- # This is used for looking up variables and defaults.
- def scope_path
- if parent
- [self, parent.scope_path].flatten.compact
- else
- [self]
- end
- end
-
- # Set defaults for a type. The typename should already be downcased,
- # so that the syntax is isolated. We don't do any kind of type-checking
- # here; instead we let the resource do it when the defaults are used.
- def setdefaults(type, params)
- table = @defaults[type]
-
- # if we got a single param, it'll be in its own array
- params = [params] unless params.is_a?(Array)
-
- params.each { |param|
- #Puppet.debug "Default for %s is %s => %s" %
- # [type,ary[0].inspect,ary[1].inspect]
- if table.include?(param.name)
- raise Puppet::ParseError.new("Default already defined for #{type} { #{param.name} }; cannot redefine", param.line, param.file)
- end
- table[param.name] = param
- }
- end
-
- # Set a variable in the current scope. This will override settings
- # in scopes above, but will not allow variables in the current scope
- # to be reassigned.
- def setvar(name,value, options = {})
- table = options[:ephemeral] ? @ephemeral.last : @symtable
- #Puppet.debug "Setting %s to '%s' at level %s mode append %s" %
- # [name.inspect,value,self.level, append]
- if table.include?(name)
- unless options[:append]
- error = Puppet::ParseError.new("Cannot reassign variable #{name}")
- else
- error = Puppet::ParseError.new("Cannot append, variable #{name} is defined in this scope")
- end
- error.file = options[:file] if options[:file]
- error.line = options[:line] if options[:line]
- raise error
- end
-
- unless options[:append]
- table[name] = value
- else # append case
- # lookup the value in the scope if it exists and insert the var
- table[name] = lookupvar(name)
- # concatenate if string, append if array, nothing for other types
- case value
- when Array
- table[name] += value
- when Hash
- raise ArgumentError, "Trying to append to a hash with something which is not a hash is unsupported" unless value.is_a?(Hash)
- table[name].merge!(value)
- else
- table[name] << value
- end
- end
- end
-
- # Return an interpolated string.
- def strinterp(string, file = nil, line = nil)
- # Most strings won't have variables in them.
- ss = StringScanner.new(string)
- out = ""
- while not ss.eos?
- if ss.scan(/^\$\{((\w*::)*\w+|[0-9]+)\}|^\$([0-9])|^\$((\w*::)*\w+)/)
- # If it matches the backslash, then just retun the dollar sign.
- if ss.matched == '\\$'
- out << '$'
- else # look the variable up
- # make sure $0-$9 are lookupable only if ephemeral
- var = ss[1] || ss[3] || ss[4]
- if var and var =~ /^[0-9]+$/ and not ephemeral_include?(var)
- next
- end
- out << lookupvar(var).to_s || ""
- end
- elsif ss.scan(/^\\(.)/)
- # Puppet.debug("Got escape: pos:%d; m:%s" % [ss.pos, ss.matched])
- case ss[1]
- when 'n'
- out << "\n"
- when 't'
- out << "\t"
- when 's'
- out << " "
- when '\\'
- out << '\\'
- when '$'
- out << '$'
- else
- str = "Unrecognised escape sequence '#{ss.matched}'"
- str += " in file #{file}" if file
- str += " at line #{line}" if line
- Puppet.warning str
- out << ss.matched
- end
- elsif ss.scan(/^\$/)
- out << '$'
- elsif ss.scan(/^\\\n/) # an escaped carriage return
- next
- else
- tmp = ss.scan(/[^\\$]+/)
- # Puppet.debug("Got other: pos:%d; m:%s" % [ss.pos, tmp])
- unless tmp
- error = Puppet::ParseError.new("Could not parse string #{string.inspect}")
- {:file= => file, :line= => line}.each do |m,v|
- error.send(m, v) if v
- end
- raise error
- end
- out << tmp
- end
- end
-
- out
- end
-
- # Return the tags associated with this scope. It's basically
- # just our parents' tags, plus our type. We don't cache this value
- # because our parent tags might change between calls.
- def tags
- resource.tags
- end
-
- # Used mainly for logging
- def to_s
- "Scope(#{@resource})"
- end
-
- # Undefine a variable; only used for testing.
- def unsetvar(var)
- table = ephemeral?(var) ? @ephemeral.last : @symtable
- table.delete(var) if table.include?(var)
- end
-
- # remove ephemeral scope up to level
- def unset_ephemeral_var(level=:all)
- if level == :all
- @ephemeral = [ Ephemeral.new ]
- else
- (@ephemeral.size - level).times do
- @ephemeral.pop
- end
- end
- end
+ private
- # check if name exists in one of the ephemeral scope.
- def ephemeral_include?(name)
- @ephemeral.reverse.each do |eph|
- return true if eph.include?(name)
- end
- false
- end
-
- # is name an ephemeral variable?
- def ephemeral?(name)
- name =~ /^\d+$/
- end
-
- def ephemeral_level
- @ephemeral.size
- end
-
- def new_ephemeral
- @ephemeral.push(Ephemeral.new(@ephemeral.last))
- end
-
- def ephemeral_from(match, file = nil, line = nil)
- raise(ArgumentError,"Invalid regex match data") unless match.is_a?(MatchData)
-
- new_ephemeral
-
- setvar("0", match[0], :file => file, :line => line, :ephemeral => true)
- match.captures.each_with_index do |m,i|
- setvar("#{i+1}", m, :file => file, :line => line, :ephemeral => true)
- end
- end
-
- private
-
- def extend_with_functions_module
- extend Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.root)
- extend Puppet::Parser::Functions.environment_module(compiler ? environment : nil)
- end
+ def extend_with_functions_module
+ extend Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.root)
+ extend Puppet::Parser::Functions.environment_module(compiler ? environment : nil)
+ end
end
diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb
index 6966387cf..73a4ad8aa 100644
--- a/lib/puppet/parser/templatewrapper.rb
+++ b/lib/puppet/parser/templatewrapper.rb
@@ -3,112 +3,112 @@
require 'puppet/parser/files'
class Puppet::Parser::TemplateWrapper
- attr_writer :scope
- attr_reader :file
- attr_accessor :string
- include Puppet::Util
- Puppet::Util.logmethods(self)
-
- def initialize(scope)
- @__scope__ = scope
+ attr_writer :scope
+ attr_reader :file
+ attr_accessor :string
+ include Puppet::Util
+ Puppet::Util.logmethods(self)
+
+ def initialize(scope)
+ @__scope__ = scope
+ end
+
+ def scope
+ @__scope__
+ end
+
+ # Should return true if a variable is defined, false if it is not
+ def has_variable?(name)
+ if scope.lookupvar(name.to_s, false) != :undefined
+ true
+ else
+ false
end
-
- def scope
- @__scope__
+ end
+
+ # Allow templates to access the defined classes
+ def classes
+ scope.catalog.classes
+ end
+
+ # Allow templates to access the tags defined in the current scope
+ def tags
+ scope.tags
+ end
+
+ # Allow templates to access the all the defined tags
+ def all_tags
+ scope.catalog.tags
+ end
+
+ # Ruby treats variables like methods, so we used to expose variables
+ # within scope to the ERB code via method_missing. As per RedMine #1427,
+ # though, this means that conflicts between methods in our inheritance
+ # tree (Kernel#fork) and variable names (fork => "yes/no") could arise.
+ #
+ # Worse, /new/ conflicts could pop up when a new kernel or object method
+ # was added to Ruby, causing templates to suddenly fail mysteriously when
+ # Ruby was upgraded.
+ #
+ # To ensure that legacy templates using unqualified names work we retain
+ # the missing_method definition here until we declare the syntax finally
+ # dead.
+ def method_missing(name, *args)
+ # We have to tell lookupvar to return :undefined to us when
+ # appropriate; otherwise it converts to "".
+ value = scope.lookupvar(name.to_s, false)
+ if value != :undefined
+ return value
+ else
+ # Just throw an error immediately, instead of searching for
+ # other missingmethod things or whatever.
+ raise Puppet::ParseError, "Could not find value for '#{name}'"
end
+ end
- # Should return true if a variable is defined, false if it is not
- def has_variable?(name)
- if scope.lookupvar(name.to_s, false) != :undefined
- true
- else
- false
- end
+ def file=(filename)
+ unless @file = Puppet::Parser::Files.find_template(filename, scope.compiler.environment.to_s)
+ raise Puppet::ParseError, "Could not find template '#{filename}'"
end
- # Allow templates to access the defined classes
- def classes
- scope.catalog.classes
- end
+ # We'll only ever not have a parser in testing, but, eh.
+ scope.known_resource_types.watch_file(file)
- # Allow templates to access the tags defined in the current scope
- def tags
- scope.tags
- end
+ @string = File.read(file)
+ end
- # Allow templates to access the all the defined tags
- def all_tags
- scope.catalog.tags
+ def result(string = nil)
+ if string
+ self.string = string
+ template_source = "inline template"
+ else
+ template_source = file
end
- # Ruby treats variables like methods, so we used to expose variables
- # within scope to the ERB code via method_missing. As per RedMine #1427,
- # though, this means that conflicts between methods in our inheritance
- # tree (Kernel#fork) and variable names (fork => "yes/no") could arise.
- #
- # Worse, /new/ conflicts could pop up when a new kernel or object method
- # was added to Ruby, causing templates to suddenly fail mysteriously when
- # Ruby was upgraded.
- #
- # To ensure that legacy templates using unqualified names work we retain
- # the missing_method definition here until we declare the syntax finally
- # dead.
- def method_missing(name, *args)
- # We have to tell lookupvar to return :undefined to us when
- # appropriate; otherwise it converts to "".
- value = scope.lookupvar(name.to_s, false)
- if value != :undefined
- return value
+ # Expose all the variables in our scope as instance variables of the
+ # current object, making it possible to access them without conflict
+ # to the regular methods.
+ benchmark(:debug, "Bound template variables for #{template_source}") do
+ scope.to_hash.each { |name, value|
+ if name.kind_of?(String)
+ realname = name.gsub(/[^\w]/, "_")
else
- # Just throw an error immediately, instead of searching for
- # other missingmethod things or whatever.
- raise Puppet::ParseError, "Could not find value for '#{name}'"
+ realname = name
end
+ instance_variable_set("@#{realname}", value)
+ }
end
- def file=(filename)
- unless @file = Puppet::Parser::Files.find_template(filename, scope.compiler.environment.to_s)
- raise Puppet::ParseError, "Could not find template '#{filename}'"
- end
-
- # We'll only ever not have a parser in testing, but, eh.
- scope.known_resource_types.watch_file(file)
-
- @string = File.read(file)
+ result = nil
+ benchmark(:debug, "Interpolated template #{template_source}") do
+ template = ERB.new(self.string, 0, "-")
+ result = template.result(binding)
end
- def result(string = nil)
- if string
- self.string = string
- template_source = "inline template"
- else
- template_source = file
- end
-
- # Expose all the variables in our scope as instance variables of the
- # current object, making it possible to access them without conflict
- # to the regular methods.
- benchmark(:debug, "Bound template variables for #{template_source}") do
- scope.to_hash.each { |name, value|
- if name.kind_of?(String)
- realname = name.gsub(/[^\w]/, "_")
- else
- realname = name
- end
- instance_variable_set("@#{realname}", value)
- }
- end
-
- result = nil
- benchmark(:debug, "Interpolated template #{template_source}") do
- template = ERB.new(self.string, 0, "-")
- result = template.result(binding)
- end
-
- result
- end
+ result
+ end
- def to_s
- "template[#{(file ? file : "inline")}]"
- end
+ def to_s
+ "template[#{(file ? file : "inline")}]"
+ end
end
diff --git a/lib/puppet/parser/type_loader.rb b/lib/puppet/parser/type_loader.rb
index 37fa03f20..e56ab9418 100644
--- a/lib/puppet/parser/type_loader.rb
+++ b/lib/puppet/parser/type_loader.rb
@@ -1,146 +1,146 @@
require 'puppet/node/environment'
class Puppet::Parser::TypeLoader
- include Puppet::Node::Environment::Helper
-
- class Helper < Hash
- include MonitorMixin
- def done_with(item)
- synchronize do
- delete(item)[:busy].signal if self.has_key?(item) and self[item][:loader] == Thread.current
- end
- end
- def owner_of(item)
- synchronize do
- if !self.has_key? item
- self[item] = { :loader => Thread.current, :busy => self.new_cond}
- :nobody
- elsif self[item][:loader] == Thread.current
- :this_thread
- else
- flag = self[item][:busy]
- flag.wait
- flag.signal
- :another_thread
- end
- end
- end
+ include Puppet::Node::Environment::Helper
+
+ class Helper < Hash
+ include MonitorMixin
+ def done_with(item)
+ synchronize do
+ delete(item)[:busy].signal if self.has_key?(item) and self[item][:loader] == Thread.current
+ end
end
-
- # Import our files.
- def import(file, current_file = nil)
- return if Puppet[:ignoreimport]
-
- # use a path relative to the file doing the importing
- if current_file
- dir = current_file.sub(%r{[^/]+$},'').sub(/\/$/, '')
+ def owner_of(item)
+ synchronize do
+ if !self.has_key? item
+ self[item] = { :loader => Thread.current, :busy => self.new_cond}
+ :nobody
+ elsif self[item][:loader] == Thread.current
+ :this_thread
else
- dir = "."
- end
- if dir == ""
- dir = "."
- end
-
- pat = file
- modname, files = Puppet::Parser::Files.find_manifests(pat, :cwd => dir, :environment => environment)
- if files.size == 0
- raise Puppet::ImportError.new("No file(s) found for import of '#{pat}'")
- end
-
- files.each do |file|
- unless file =~ /^#{File::SEPARATOR}/
- file = File.join(dir, file)
- end
- @imported[file] = true
- parse_file(file)
+ flag = self[item][:busy]
+ flag.wait
+ flag.signal
+ :another_thread
end
-
- modname
+ end
end
+ end
- def imported?(file)
- @imported.has_key?(file)
- end
+ # Import our files.
+ def import(file, current_file = nil)
+ return if Puppet[:ignoreimport]
- def known_resource_types
- environment.known_resource_types
+ # use a path relative to the file doing the importing
+ if current_file
+ dir = current_file.sub(%r{[^/]+$},'').sub(/\/$/, '')
+ else
+ dir = "."
end
-
- def initialize(env)
- self.environment = env
- @loaded = []
- @loading = Helper.new
-
- @imported = {}
+ if dir == ""
+ dir = "."
end
- def load_until(namespaces, name)
- return nil if name == "" # special-case main.
- name2files(namespaces, name).each do |filename|
- modname = nil
- import_if_possible(filename) do
- modname = import(filename)
- @loaded << filename
- end
- if result = yield(filename)
- Puppet.info "Automatically imported #{name} from #{filename}"
- result.module_name = modname if modname and result.respond_to?(:module_name=)
- return result
- end
- end
- nil
+ pat = file
+ modname, files = Puppet::Parser::Files.find_manifests(pat, :cwd => dir, :environment => environment)
+ if files.size == 0
+ raise Puppet::ImportError.new("No file(s) found for import of '#{pat}'")
end
- def loaded?(name)
- @loaded.include?(name)
+ files.each do |file|
+ unless file =~ /^#{File::SEPARATOR}/
+ file = File.join(dir, file)
+ end
+ @imported[file] = true
+ parse_file(file)
end
- def name2files(namespaces, name)
- return [name.sub(/^::/, '').gsub("::", File::SEPARATOR)] if name =~ /^::/
+ modname
+ end
+
+ def imported?(file)
+ @imported.has_key?(file)
+ end
+
+ def known_resource_types
+ environment.known_resource_types
+ end
+
+ def initialize(env)
+ self.environment = env
+ @loaded = []
+ @loading = Helper.new
+
+ @imported = {}
+ end
+
+ def load_until(namespaces, name)
+ return nil if name == "" # special-case main.
+ name2files(namespaces, name).each do |filename|
+ modname = nil
+ import_if_possible(filename) do
+ modname = import(filename)
+ @loaded << filename
+ end
+ if result = yield(filename)
+ Puppet.info "Automatically imported #{name} from #{filename}"
+ result.module_name = modname if modname and result.respond_to?(:module_name=)
+ return result
+ end
+ end
+ nil
+ end
- result = namespaces.inject([]) do |names_to_try, namespace|
- fullname = (namespace + "::#{name}").sub(/^::/, '')
+ def loaded?(name)
+ @loaded.include?(name)
+ end
- # Try to load the module init file if we're a qualified name
- names_to_try << fullname.split("::")[0] if fullname.include?("::")
+ def name2files(namespaces, name)
+ return [name.sub(/^::/, '').gsub("::", File::SEPARATOR)] if name =~ /^::/
- # Then the fully qualified name
- names_to_try << fullname
- end
+ result = namespaces.inject([]) do |names_to_try, namespace|
+ fullname = (namespace + "::#{name}").sub(/^::/, '')
- # Otherwise try to load the bare name on its own. This
- # is appropriate if the class we're looking for is in a
- # module that's different from our namespace.
- result << name
- result.uniq.collect { |f| f.gsub("::", File::SEPARATOR) }
- end
+ # Try to load the module init file if we're a qualified name
+ names_to_try << fullname.split("::")[0] if fullname.include?("::")
- def parse_file(file)
- Puppet.debug("importing '#{file}' in environment #{environment}")
- parser = Puppet::Parser::Parser.new(environment)
- parser.file = file
- parser.parse
+ # Then the fully qualified name
+ names_to_try << fullname
end
- private
-
- # Utility method factored out of load for handling thread-safety.
- # This isn't tested in the specs, because that's basically impossible.
- def import_if_possible(file)
- return if @loaded.include?(file)
- begin
- case @loading.owner_of(file)
- when :this_thread
- return
- when :another_thread
- return import_if_possible(file)
- when :nobody
- yield
- end
- rescue Puppet::ImportError => detail
- # We couldn't load the item
- ensure
- @loading.done_with(file)
- end
+ # Otherwise try to load the bare name on its own. This
+ # is appropriate if the class we're looking for is in a
+ # module that's different from our namespace.
+ result << name
+ result.uniq.collect { |f| f.gsub("::", File::SEPARATOR) }
+ end
+
+ def parse_file(file)
+ Puppet.debug("importing '#{file}' in environment #{environment}")
+ parser = Puppet::Parser::Parser.new(environment)
+ parser.file = file
+ parser.parse
+ end
+
+ private
+
+ # Utility method factored out of load for handling thread-safety.
+ # This isn't tested in the specs, because that's basically impossible.
+ def import_if_possible(file)
+ return if @loaded.include?(file)
+ begin
+ case @loading.owner_of(file)
+ when :this_thread
+ return
+ when :another_thread
+ return import_if_possible(file)
+ when :nobody
+ yield
+ end
+ rescue Puppet::ImportError => detail
+ # We couldn't load the item
+ ensure
+ @loading.done_with(file)
end
+ end
end
diff --git a/lib/puppet/parser/yaml_trimmer.rb b/lib/puppet/parser/yaml_trimmer.rb
index 131bafb8d..cf7870916 100644
--- a/lib/puppet/parser/yaml_trimmer.rb
+++ b/lib/puppet/parser/yaml_trimmer.rb
@@ -1,9 +1,9 @@
module Puppet::Parser::YamlTrimmer
- REMOVE = %w{@scope @source}
+ REMOVE = %w{@scope @source}
- def to_yaml_properties
- r = instance_variables - REMOVE
- r -= skip_for_yaml if respond_to?(:skip_for_yaml)
- r
- end
+ def to_yaml_properties
+ r = instance_variables - REMOVE
+ r -= skip_for_yaml if respond_to?(:skip_for_yaml)
+ r
+ end
end
diff --git a/lib/puppet/property.rb b/lib/puppet/property.rb
index c7165fe6e..282a52cf4 100644
--- a/lib/puppet/property.rb
+++ b/lib/puppet/property.rb
@@ -5,320 +5,320 @@ require 'puppet'
require 'puppet/parameter'
class Puppet::Property < Puppet::Parameter
- require 'puppet/property/ensure'
-
- # Because 'should' uses an array, we have a special method for handling
- # it. We also want to keep copies of the original values, so that
- # they can be retrieved and compared later when merging.
- attr_reader :shouldorig
-
- attr_writer :noop
-
- class << self
- attr_accessor :unmanaged
- attr_reader :name
-
- # Return array matching info, defaulting to just matching
- # the first value.
- def array_matching
- @array_matching ||= :first
- end
-
- # Set whether properties should match all values or just the first one.
- def array_matching=(value)
- value = value.intern if value.is_a?(String)
- raise ArgumentError, "Supported values for Property#array_matching are 'first' and 'all'" unless [:first, :all].include?(value)
- @array_matching = value
- end
- end
-
- # Look up a value's name, so we can find options and such.
- def self.value_name(name)
- if value = value_collection.match?(name)
- value.name
- end
- end
-
- # Retrieve an option set when a value was defined.
- def self.value_option(name, option)
- if value = value_collection.value(name)
- value.send(option)
- end
- end
-
- # Define a new valid value for a property. You must provide the value itself,
- # usually as a symbol, or a regex to match the value.
- #
- # The first argument to the method is either the value itself or a regex.
- # The second argument is an option hash; valid options are:
- # * <tt>:method</tt>: The name of the method to define. Defaults to 'set_<value>'.
- # * <tt>:required_features</tt>: A list of features this value requires.
- # * <tt>:event</tt>: The event that should be returned when this value is set.
- # * <tt>:call</tt>: When to call any associated block. The default value
- # is ``instead``, which means to call the value instead of calling the
- # provider. You can also specify ``before`` or ``after``, which will
- # call both the block and the provider, according to the order you specify
- # (the ``first`` refers to when the block is called, not the provider).
- def self.newvalue(name, options = {}, &block)
- value = value_collection.newvalue(name, options, &block)
-
- define_method(value.method, &value.block) if value.method and value.block
- value
- end
-
- # Call the provider method.
- def call_provider(value)
- provider.send(self.class.name.to_s + "=", value)
- rescue NoMethodError
- self.fail "The #{provider.class.name} provider can not handle attribute #{self.class.name}"
- end
-
- # Call the dynamically-created method associated with our value, if
- # there is one.
- def call_valuemethod(name, value)
- if method = self.class.value_option(name, :method) and self.respond_to?(method)
- begin
- event = self.send(method)
- rescue Puppet::Error
- raise
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- error = Puppet::Error.new("Could not set '#{value} on #{self.class.name}: #{detail}", @resource.line, @resource.file)
- error.set_backtrace detail.backtrace
- raise error
- end
- elsif block = self.class.value_option(name, :block)
- # FIXME It'd be better here to define a method, so that
- # the blocks could return values.
- self.instance_eval(&block)
- else
- devfail "Could not find method for value '#{name}'"
- end
- end
-
- # How should a property change be printed as a string?
- def change_to_s(current_value, newvalue)
- begin
- if current_value == :absent
- return "defined '#{name}' as '#{should_to_s(newvalue)}'"
- elsif newvalue == :absent or newvalue == [:absent]
- return "undefined '#{name}' from '#{is_to_s(current_value)}'"
- else
- return "#{name} changed '#{is_to_s(current_value)}' to '#{should_to_s(newvalue)}'"
- end
- rescue Puppet::Error, Puppet::DevError
- raise
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::DevError, "Could not convert change '#{name}' to string: #{detail}"
- end
- end
+ require 'puppet/property/ensure'
- # Figure out which event to return.
- def event_name
- value = self.should
+ # Because 'should' uses an array, we have a special method for handling
+ # it. We also want to keep copies of the original values, so that
+ # they can be retrieved and compared later when merging.
+ attr_reader :shouldorig
- event_name = self.class.value_option(value, :event) and return event_name
+ attr_writer :noop
- name == :ensure or return (name.to_s + "_changed").to_sym
+ class << self
+ attr_accessor :unmanaged
+ attr_reader :name
- return (resource.type.to_s + case value
- when :present; "_created"
- when :absent; "_removed"
- else
- "_changed"
- end).to_sym
+ # Return array matching info, defaulting to just matching
+ # the first value.
+ def array_matching
+ @array_matching ||= :first
end
- # Return a modified form of the resource event.
- def event
- resource.event :name => event_name, :desired_value => should, :property => self, :source_description => path
+ # Set whether properties should match all values or just the first one.
+ def array_matching=(value)
+ value = value.intern if value.is_a?(String)
+ raise ArgumentError, "Supported values for Property#array_matching are 'first' and 'all'" unless [:first, :all].include?(value)
+ @array_matching = value
end
+ end
- attr_reader :shadow
-
- # initialize our property
- def initialize(hash = {})
- super
-
- if ! self.metaparam? and klass = Puppet::Type.metaparamclass(self.class.name)
- setup_shadow(klass)
- end
+ # Look up a value's name, so we can find options and such.
+ def self.value_name(name)
+ if value = value_collection.match?(name)
+ value.name
end
+ end
- # Determine whether the property is in-sync or not. If @should is
- # not defined or is set to a non-true value, then we do not have
- # a valid value for it and thus consider the property to be in-sync
- # since we cannot fix it. Otherwise, we expect our should value
- # to be an array, and if @is matches any of those values, then
- # we consider it to be in-sync.
- def insync?(is)
- return true unless @should
-
- self.devfail "#{self.class.name}'s should is not array" unless @should.is_a?(Array)
-
- # an empty array is analogous to no should values
- return true if @should.empty?
-
- # Look for a matching value
- return (is == @should or is == @should.collect { |v| v.to_s }) if match_all?
-
- @should.each { |val| return true if is == val or is == val.to_s }
-
- # otherwise, return false
- false
+ # Retrieve an option set when a value was defined.
+ def self.value_option(name, option)
+ if value = value_collection.value(name)
+ value.send(option)
end
-
- # because the @should and @is vars might be in weird formats,
- # we need to set up a mechanism for pretty printing of the values
- # default to just the values, but this way individual properties can
- # override these methods
- def is_to_s(currentvalue)
- currentvalue
+ end
+
+ # Define a new valid value for a property. You must provide the value itself,
+ # usually as a symbol, or a regex to match the value.
+ #
+ # The first argument to the method is either the value itself or a regex.
+ # The second argument is an option hash; valid options are:
+ # * <tt>:method</tt>: The name of the method to define. Defaults to 'set_<value>'.
+ # * <tt>:required_features</tt>: A list of features this value requires.
+ # * <tt>:event</tt>: The event that should be returned when this value is set.
+ # * <tt>:call</tt>: When to call any associated block. The default value
+ # is ``instead``, which means to call the value instead of calling the
+ # provider. You can also specify ``before`` or ``after``, which will
+ # call both the block and the provider, according to the order you specify
+ # (the ``first`` refers to when the block is called, not the provider).
+ def self.newvalue(name, options = {}, &block)
+ value = value_collection.newvalue(name, options, &block)
+
+ define_method(value.method, &value.block) if value.method and value.block
+ value
+ end
+
+ # Call the provider method.
+ def call_provider(value)
+ provider.send(self.class.name.to_s + "=", value)
+ rescue NoMethodError
+ self.fail "The #{provider.class.name} provider can not handle attribute #{self.class.name}"
+ end
+
+ # Call the dynamically-created method associated with our value, if
+ # there is one.
+ def call_valuemethod(name, value)
+ if method = self.class.value_option(name, :method) and self.respond_to?(method)
+ begin
+ event = self.send(method)
+ rescue Puppet::Error
+ raise
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ error = Puppet::Error.new("Could not set '#{value} on #{self.class.name}: #{detail}", @resource.line, @resource.file)
+ error.set_backtrace detail.backtrace
+ raise error
+ end
+ elsif block = self.class.value_option(name, :block)
+ # FIXME It'd be better here to define a method, so that
+ # the blocks could return values.
+ self.instance_eval(&block)
+ else
+ devfail "Could not find method for value '#{name}'"
end
-
- # Send a log message.
- def log(msg)
-
- Puppet::Util::Log.create(
-
- :level => resource[:loglevel],
- :message => msg,
-
- :source => self
- )
+ end
+
+ # How should a property change be printed as a string?
+ def change_to_s(current_value, newvalue)
+ begin
+ if current_value == :absent
+ return "defined '#{name}' as '#{should_to_s(newvalue)}'"
+ elsif newvalue == :absent or newvalue == [:absent]
+ return "undefined '#{name}' from '#{is_to_s(current_value)}'"
+ else
+ return "#{name} changed '#{is_to_s(current_value)}' to '#{should_to_s(newvalue)}'"
+ end
+ rescue Puppet::Error, Puppet::DevError
+ raise
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::DevError, "Could not convert change '#{name}' to string: #{detail}"
end
+ end
- # Should we match all values, or just the first?
- def match_all?
- self.class.array_matching == :all
- end
+ # Figure out which event to return.
+ def event_name
+ value = self.should
- # Execute our shadow's munge code, too, if we have one.
- def munge(value)
- self.shadow.munge(value) if self.shadow
+ event_name = self.class.value_option(value, :event) and return event_name
- super
- end
+ name == :ensure or return (name.to_s + "_changed").to_sym
- # each property class must define the name method, and property instances
- # do not change that name
- # this implicitly means that a given object can only have one property
- # instance of a given property class
- def name
- self.class.name
- end
+ return (resource.type.to_s + case value
+ when :present; "_created"
+ when :absent; "_removed"
+ else
+ "_changed"
+ end).to_sym
+ end
- # for testing whether we should actually do anything
- def noop
- # This is only here to make testing easier.
- if @resource.respond_to?(:noop?)
- @resource.noop?
- else
- if defined?(@noop)
- @noop
- else
- Puppet[:noop]
- end
- end
- end
+ # Return a modified form of the resource event.
+ def event
+ resource.event :name => event_name, :desired_value => should, :property => self, :source_description => path
+ end
- # By default, call the method associated with the property name on our
- # provider. In other words, if the property name is 'gid', we'll call
- # 'provider.gid' to retrieve the current value.
- def retrieve
- provider.send(self.class.name)
- end
+ attr_reader :shadow
- # Set our value, using the provider, an associated block, or both.
- def set(value)
- # Set a name for looking up associated options like the event.
- name = self.class.value_name(value)
-
- call = self.class.value_option(name, :call) || :none
-
- if call == :instead
- call_valuemethod(name, value)
- elsif call == :none
- # They haven't provided a block, and our parent does not have
- # a provider, so we have no idea how to handle this.
- self.fail "#{self.class.name} cannot handle values of type #{value.inspect}" unless @resource.provider
- call_provider(value)
- else
- # LAK:NOTE 20081031 This is a change in behaviour -- you could
- # previously specify :call => [;before|:after], which would call
- # the setter *in addition to* the block. I'm convinced this
- # was never used, and it makes things unecessarily complicated.
- # If you want to specify a block and still call the setter, then
- # do so in the block.
- devfail "Cannot use obsolete :call value '#{call}' for property '#{self.class.name}'"
- end
- end
+ # initialize our property
+ def initialize(hash = {})
+ super
- # If there's a shadowing metaparam, instantiate it now.
- # This allows us to create a property or parameter with the
- # same name as a metaparameter, and the metaparam will only be
- # stored as a shadow.
- def setup_shadow(klass)
- @shadow = klass.new(:resource => self.resource)
+ if ! self.metaparam? and klass = Puppet::Type.metaparamclass(self.class.name)
+ setup_shadow(klass)
end
+ end
- # Only return the first value
- def should
- return nil unless defined?(@should)
+ # Determine whether the property is in-sync or not. If @should is
+ # not defined or is set to a non-true value, then we do not have
+ # a valid value for it and thus consider the property to be in-sync
+ # since we cannot fix it. Otherwise, we expect our should value
+ # to be an array, and if @is matches any of those values, then
+ # we consider it to be in-sync.
+ def insync?(is)
+ return true unless @should
- self.devfail "should for #{self.class.name} on #{resource.name} is not an array" unless @should.is_a?(Array)
+ self.devfail "#{self.class.name}'s should is not array" unless @should.is_a?(Array)
- if match_all?
- return @should.collect { |val| self.unmunge(val) }
- else
- return self.unmunge(@should[0])
- end
- end
+ # an empty array is analogous to no should values
+ return true if @should.empty?
- # Set the should value.
- def should=(values)
- values = [values] unless values.is_a?(Array)
+ # Look for a matching value
+ return (is == @should or is == @should.collect { |v| v.to_s }) if match_all?
- @shouldorig = values
+ @should.each { |val| return true if is == val or is == val.to_s }
- values.each { |val| validate(val) }
- @should = values.collect { |val| self.munge(val) }
- end
+ # otherwise, return false
+ false
+ end
- def should_to_s(newvalue)
- [newvalue].flatten.join(" ")
- end
+ # because the @should and @is vars might be in weird formats,
+ # we need to set up a mechanism for pretty printing of the values
+ # default to just the values, but this way individual properties can
+ # override these methods
+ def is_to_s(currentvalue)
+ currentvalue
+ end
- def sync
- devfail "Got a nil value for should" unless should
- set(should)
- end
+ # Send a log message.
+ def log(msg)
- # Verify that the passed value is valid.
- # If the developer uses a 'validate' hook, this method will get overridden.
- def unsafe_validate(value)
- super
- validate_features_per_value(value)
+ Puppet::Util::Log.create(
+
+ :level => resource[:loglevel],
+ :message => msg,
+
+ :source => self
+ )
+ end
+
+ # Should we match all values, or just the first?
+ def match_all?
+ self.class.array_matching == :all
+ end
+
+ # Execute our shadow's munge code, too, if we have one.
+ def munge(value)
+ self.shadow.munge(value) if self.shadow
+
+ super
+ end
+
+ # each property class must define the name method, and property instances
+ # do not change that name
+ # this implicitly means that a given object can only have one property
+ # instance of a given property class
+ def name
+ self.class.name
+ end
+
+ # for testing whether we should actually do anything
+ def noop
+ # This is only here to make testing easier.
+ if @resource.respond_to?(:noop?)
+ @resource.noop?
+ else
+ if defined?(@noop)
+ @noop
+ else
+ Puppet[:noop]
+ end
end
-
- # Make sure that we've got all of the required features for a given value.
- def validate_features_per_value(value)
- if features = self.class.value_option(self.class.value_name(value), :required_features)
- features = Array(features)
- needed_features = features.collect { |f| f.to_s }.join(", ")
- raise ArgumentError, "Provider must have features '#{needed_features}' to set '#{self.class.name}' to '#{value}'" unless provider.satisfies?(features)
- end
+ end
+
+ # By default, call the method associated with the property name on our
+ # provider. In other words, if the property name is 'gid', we'll call
+ # 'provider.gid' to retrieve the current value.
+ def retrieve
+ provider.send(self.class.name)
+ end
+
+ # Set our value, using the provider, an associated block, or both.
+ def set(value)
+ # Set a name for looking up associated options like the event.
+ name = self.class.value_name(value)
+
+ call = self.class.value_option(name, :call) || :none
+
+ if call == :instead
+ call_valuemethod(name, value)
+ elsif call == :none
+ # They haven't provided a block, and our parent does not have
+ # a provider, so we have no idea how to handle this.
+ self.fail "#{self.class.name} cannot handle values of type #{value.inspect}" unless @resource.provider
+ call_provider(value)
+ else
+ # LAK:NOTE 20081031 This is a change in behaviour -- you could
+ # previously specify :call => [;before|:after], which would call
+ # the setter *in addition to* the block. I'm convinced this
+ # was never used, and it makes things unecessarily complicated.
+ # If you want to specify a block and still call the setter, then
+ # do so in the block.
+ devfail "Cannot use obsolete :call value '#{call}' for property '#{self.class.name}'"
end
-
- # Just return any should value we might have.
- def value
- self.should
+ end
+
+ # If there's a shadowing metaparam, instantiate it now.
+ # This allows us to create a property or parameter with the
+ # same name as a metaparameter, and the metaparam will only be
+ # stored as a shadow.
+ def setup_shadow(klass)
+ @shadow = klass.new(:resource => self.resource)
+ end
+
+ # Only return the first value
+ def should
+ return nil unless defined?(@should)
+
+ self.devfail "should for #{self.class.name} on #{resource.name} is not an array" unless @should.is_a?(Array)
+
+ if match_all?
+ return @should.collect { |val| self.unmunge(val) }
+ else
+ return self.unmunge(@should[0])
end
-
- # Match the Parameter interface, but we really just use 'should' internally.
- # Note that the should= method does all of the validation and such.
- def value=(value)
- self.should = value
+ end
+
+ # Set the should value.
+ def should=(values)
+ values = [values] unless values.is_a?(Array)
+
+ @shouldorig = values
+
+ values.each { |val| validate(val) }
+ @should = values.collect { |val| self.munge(val) }
+ end
+
+ def should_to_s(newvalue)
+ [newvalue].flatten.join(" ")
+ end
+
+ def sync
+ devfail "Got a nil value for should" unless should
+ set(should)
+ end
+
+ # Verify that the passed value is valid.
+ # If the developer uses a 'validate' hook, this method will get overridden.
+ def unsafe_validate(value)
+ super
+ validate_features_per_value(value)
+ end
+
+ # Make sure that we've got all of the required features for a given value.
+ def validate_features_per_value(value)
+ if features = self.class.value_option(self.class.value_name(value), :required_features)
+ features = Array(features)
+ needed_features = features.collect { |f| f.to_s }.join(", ")
+ raise ArgumentError, "Provider must have features '#{needed_features}' to set '#{self.class.name}' to '#{value}'" unless provider.satisfies?(features)
end
+ end
+
+ # Just return any should value we might have.
+ def value
+ self.should
+ end
+
+ # Match the Parameter interface, but we really just use 'should' internally.
+ # Note that the should= method does all of the validation and such.
+ def value=(value)
+ self.should = value
+ end
end
diff --git a/lib/puppet/property/ensure.rb b/lib/puppet/property/ensure.rb
index d6aa99ef3..8b97ddeab 100644
--- a/lib/puppet/property/ensure.rb
+++ b/lib/puppet/property/ensure.rb
@@ -3,90 +3,90 @@ require 'puppet/property'
# This property will get automatically added to any type that responds
# to the methods 'exists?', 'create', and 'destroy'.
class Puppet::Property::Ensure < Puppet::Property
- @name = :ensure
+ @name = :ensure
- def self.defaultvalues
- newvalue(:present) do
- if @resource.provider and @resource.provider.respond_to?(:create)
- @resource.provider.create
- else
- @resource.create
- end
- nil # return nil so the event is autogenerated
- end
-
- newvalue(:absent) do
- if @resource.provider and @resource.provider.respond_to?(:destroy)
- @resource.provider.destroy
- else
- @resource.destroy
- end
- nil # return nil so the event is autogenerated
- end
+ def self.defaultvalues
+ newvalue(:present) do
+ if @resource.provider and @resource.provider.respond_to?(:create)
+ @resource.provider.create
+ else
+ @resource.create
+ end
+ nil # return nil so the event is autogenerated
+ end
- defaultto do
- if @resource.managed?
- :present
- else
- nil
- end
- end
+ newvalue(:absent) do
+ if @resource.provider and @resource.provider.respond_to?(:destroy)
+ @resource.provider.destroy
+ else
+ @resource.destroy
+ end
+ nil # return nil so the event is autogenerated
+ end
- # This doc will probably get overridden
- @doc ||= "The basic property that the resource should be in."
+ defaultto do
+ if @resource.managed?
+ :present
+ else
+ nil
+ end
end
- def self.inherited(sub)
- # Add in the two properties that everyone will have.
- sub.class_eval do
- end
+ # This doc will probably get overridden
+ @doc ||= "The basic property that the resource should be in."
+ end
+
+ def self.inherited(sub)
+ # Add in the two properties that everyone will have.
+ sub.class_eval do
end
+ end
- def change_to_s(currentvalue, newvalue)
- begin
- if currentvalue == :absent or currentvalue.nil?
- return "created"
- elsif newvalue == :absent
- return "removed"
- else
- return "#{self.name} changed '#{self.is_to_s(currentvalue)}' to '#{self.should_to_s(newvalue)}'"
- end
- rescue Puppet::Error, Puppet::DevError
- raise
- rescue => detail
- raise Puppet::DevError, "Could not convert change #{self.name} to string: #{detail}"
- end
+ def change_to_s(currentvalue, newvalue)
+ begin
+ if currentvalue == :absent or currentvalue.nil?
+ return "created"
+ elsif newvalue == :absent
+ return "removed"
+ else
+ return "#{self.name} changed '#{self.is_to_s(currentvalue)}' to '#{self.should_to_s(newvalue)}'"
+ end
+ rescue Puppet::Error, Puppet::DevError
+ raise
+ rescue => detail
+ raise Puppet::DevError, "Could not convert change #{self.name} to string: #{detail}"
end
+ end
- def retrieve
- # XXX This is a problem -- whether the object exists or not often
- # depends on the results of other properties, yet we're the first property
- # to get checked, which means that those other properties do not have
- # @is values set. This seems to be the source of quite a few bugs,
- # although they're mostly logging bugs, not functional ones.
- if prov = @resource.provider and prov.respond_to?(:exists?)
- result = prov.exists?
- elsif @resource.respond_to?(:exists?)
- result = @resource.exists?
- else
- raise Puppet::DevError, "No ability to determine if #{@resource.class.name} exists"
- end
- if result
- return :present
- else
- return :absent
- end
+ def retrieve
+ # XXX This is a problem -- whether the object exists or not often
+ # depends on the results of other properties, yet we're the first property
+ # to get checked, which means that those other properties do not have
+ # @is values set. This seems to be the source of quite a few bugs,
+ # although they're mostly logging bugs, not functional ones.
+ if prov = @resource.provider and prov.respond_to?(:exists?)
+ result = prov.exists?
+ elsif @resource.respond_to?(:exists?)
+ result = @resource.exists?
+ else
+ raise Puppet::DevError, "No ability to determine if #{@resource.class.name} exists"
+ end
+ if result
+ return :present
+ else
+ return :absent
end
+ end
- # If they're talking about the thing at all, they generally want to
- # say it should exist.
- #defaultto :present
- defaultto do
- if @resource.managed?
- :present
- else
- nil
- end
+ # If they're talking about the thing at all, they generally want to
+ # say it should exist.
+ #defaultto :present
+ defaultto do
+ if @resource.managed?
+ :present
+ else
+ nil
end
+ end
end
diff --git a/lib/puppet/property/keyvalue.rb b/lib/puppet/property/keyvalue.rb
index 2ac87acfd..0181708f9 100644
--- a/lib/puppet/property/keyvalue.rb
+++ b/lib/puppet/property/keyvalue.rb
@@ -9,80 +9,80 @@
require 'puppet/property'
module Puppet
- class Property
- class KeyValue < Property
-
- def hash_to_key_value_s(hash)
- hash.select { |k,v| true }.map { |pair| pair.join(separator) }.join(delimiter)
- end
-
- def should_to_s(should_value)
- hash_to_key_value_s(should_value)
- end
-
- def is_to_s(current_value)
- hash_to_key_value_s(current_value)
- end
-
- def membership
- :key_value_membership
- end
-
- def inclusive?
- @resource[membership] == :inclusive
- end
-
- def hashify(key_value_array)
- #turns string array into a hash
- key_value_array.inject({}) do |hash, key_value|
- tmp = key_value.split(separator)
- hash[tmp[0].intern] = tmp[1]
- hash
- end
- end
-
- def process_current_hash(current)
- return {} if current == :absent
-
- #inclusive means we are managing everything so if it isn't in should, its gone
- current.each_key { |key| current[key] = nil } if inclusive?
- current
- end
-
- def should
- return nil unless @should
-
- members = hashify(@should)
- current = process_current_hash(retrieve)
-
- #shared keys will get overwritten by members
- current.merge(members)
- end
-
- def separator
- "="
- end
-
- def delimiter
- ";"
- end
-
- def retrieve
- #ok, some 'convention' if the keyvalue property is named properties, provider should implement a properties method
- if key_hash = provider.send(name) and key_hash != :absent
- return key_hash
- else
- return :absent
- end
- end
-
- def insync?(is)
- return true unless @should
-
- return true unless is
-
- (is == self.should)
- end
+ class Property
+ class KeyValue < Property
+
+ def hash_to_key_value_s(hash)
+ hash.select { |k,v| true }.map { |pair| pair.join(separator) }.join(delimiter)
+ end
+
+ def should_to_s(should_value)
+ hash_to_key_value_s(should_value)
+ end
+
+ def is_to_s(current_value)
+ hash_to_key_value_s(current_value)
+ end
+
+ def membership
+ :key_value_membership
+ end
+
+ def inclusive?
+ @resource[membership] == :inclusive
+ end
+
+ def hashify(key_value_array)
+ #turns string array into a hash
+ key_value_array.inject({}) do |hash, key_value|
+ tmp = key_value.split(separator)
+ hash[tmp[0].intern] = tmp[1]
+ hash
end
+ end
+
+ def process_current_hash(current)
+ return {} if current == :absent
+
+ #inclusive means we are managing everything so if it isn't in should, its gone
+ current.each_key { |key| current[key] = nil } if inclusive?
+ current
+ end
+
+ def should
+ return nil unless @should
+
+ members = hashify(@should)
+ current = process_current_hash(retrieve)
+
+ #shared keys will get overwritten by members
+ current.merge(members)
+ end
+
+ def separator
+ "="
+ end
+
+ def delimiter
+ ";"
+ end
+
+ def retrieve
+ #ok, some 'convention' if the keyvalue property is named properties, provider should implement a properties method
+ if key_hash = provider.send(name) and key_hash != :absent
+ return key_hash
+ else
+ return :absent
+ end
+ end
+
+ def insync?(is)
+ return true unless @should
+
+ return true unless is
+
+ (is == self.should)
+ end
end
+ end
end
diff --git a/lib/puppet/property/list.rb b/lib/puppet/property/list.rb
index 0433a515a..dcee85db7 100644
--- a/lib/puppet/property/list.rb
+++ b/lib/puppet/property/list.rb
@@ -1,77 +1,77 @@
require 'puppet/property'
module Puppet
- class Property
- class List < Property
-
- def should_to_s(should_value)
- #just return the should value
- should_value
- end
-
- def is_to_s(currentvalue)
- if currentvalue == :absent
- return "absent"
- else
- return currentvalue.join(delimiter)
- end
- end
-
- def membership
- :membership
- end
-
- def add_should_with_current(should, current)
- should += current if current.is_a?(Array)
- should.uniq
- end
-
- def inclusive?
- @resource[membership] == :inclusive
- end
-
- #dearrayify was motivated because to simplify the implementation of the OrderedList property
- def dearrayify(array)
- array.sort.join(delimiter)
- end
-
- def should
- return nil unless @should
-
- members = @should
- #inclusive means we are managing everything so if it isn't in should, its gone
- members = add_should_with_current(members, retrieve) if ! inclusive?
-
- dearrayify(members)
- end
-
- def delimiter
- ","
- end
-
- def retrieve
- #ok, some 'convention' if the list property is named groups, provider should implement a groups method
- if tmp = provider.send(name) and tmp != :absent
- return tmp.split(delimiter)
- else
- return :absent
- end
- end
-
- def prepare_is_for_comparison(is)
- if is == :absent
- is = []
- end
- dearrayify(is)
- end
-
- def insync?(is)
- return true unless @should
-
- return true unless is
-
- (prepare_is_for_comparison(is) == self.should)
- end
+ class Property
+ class List < Property
+
+ def should_to_s(should_value)
+ #just return the should value
+ should_value
+ end
+
+ def is_to_s(currentvalue)
+ if currentvalue == :absent
+ return "absent"
+ else
+ return currentvalue.join(delimiter)
end
+ end
+
+ def membership
+ :membership
+ end
+
+ def add_should_with_current(should, current)
+ should += current if current.is_a?(Array)
+ should.uniq
+ end
+
+ def inclusive?
+ @resource[membership] == :inclusive
+ end
+
+ #dearrayify was motivated because to simplify the implementation of the OrderedList property
+ def dearrayify(array)
+ array.sort.join(delimiter)
+ end
+
+ def should
+ return nil unless @should
+
+ members = @should
+ #inclusive means we are managing everything so if it isn't in should, its gone
+ members = add_should_with_current(members, retrieve) if ! inclusive?
+
+ dearrayify(members)
+ end
+
+ def delimiter
+ ","
+ end
+
+ def retrieve
+ #ok, some 'convention' if the list property is named groups, provider should implement a groups method
+ if tmp = provider.send(name) and tmp != :absent
+ return tmp.split(delimiter)
+ else
+ return :absent
+ end
+ end
+
+ def prepare_is_for_comparison(is)
+ if is == :absent
+ is = []
+ end
+ dearrayify(is)
+ end
+
+ def insync?(is)
+ return true unless @should
+
+ return true unless is
+
+ (prepare_is_for_comparison(is) == self.should)
+ end
end
+ end
end
diff --git a/lib/puppet/property/ordered_list.rb b/lib/puppet/property/ordered_list.rb
index 816b16c48..7408b3019 100644
--- a/lib/puppet/property/ordered_list.rb
+++ b/lib/puppet/property/ordered_list.rb
@@ -1,22 +1,22 @@
require 'puppet/property/list'
module Puppet
- class Property
- class OrderedList < List
+ class Property
+ class OrderedList < List
- def add_should_with_current(should, current)
- if current.is_a?(Array)
- #tricky trick
- #Preserve all the current items in the list
- #but move them to the back of the line
- should = should + (current - should)
- end
- should
- end
-
- def dearrayify(array)
- array.join(delimiter)
- end
+ def add_should_with_current(should, current)
+ if current.is_a?(Array)
+ #tricky trick
+ #Preserve all the current items in the list
+ #but move them to the back of the line
+ should = should + (current - should)
end
+ should
+ end
+
+ def dearrayify(array)
+ array.join(delimiter)
+ end
end
+ end
end
diff --git a/lib/puppet/provider.rb b/lib/puppet/provider.rb
index 859a34658..8f993dbc1 100644
--- a/lib/puppet/provider.rb
+++ b/lib/puppet/provider.rb
@@ -1,195 +1,195 @@
# The container class for implementations.
class Puppet::Provider
- include Puppet::Util
- include Puppet::Util::Errors
- include Puppet::Util::Warnings
- extend Puppet::Util::Warnings
+ include Puppet::Util
+ include Puppet::Util::Errors
+ include Puppet::Util::Warnings
+ extend Puppet::Util::Warnings
- require 'puppet/provider/confiner'
+ require 'puppet/provider/confiner'
- extend Puppet::Provider::Confiner
+ extend Puppet::Provider::Confiner
- Puppet::Util.logmethods(self, true)
+ Puppet::Util.logmethods(self, true)
- class << self
- # Include the util module so we have access to things like 'binary'
- include Puppet::Util, Puppet::Util::Docs
- include Puppet::Util::Logging
- attr_accessor :name
+ class << self
+ # Include the util module so we have access to things like 'binary'
+ include Puppet::Util, Puppet::Util::Docs
+ include Puppet::Util::Logging
+ attr_accessor :name
- # The source parameter exists so that providers using the same
- # source can specify this, so reading doesn't attempt to read the
- # same package multiple times.
- attr_writer :source
-
- # LAK 2007-05-09: Keep the model stuff around for backward compatibility
- attr_reader :model
- attr_accessor :resource_type
- attr_writer :doc
- end
+ # The source parameter exists so that providers using the same
+ # source can specify this, so reading doesn't attempt to read the
+ # same package multiple times.
+ attr_writer :source
# LAK 2007-05-09: Keep the model stuff around for backward compatibility
attr_reader :model
- attr_accessor :resource
-
- def self.command(name)
- name = symbolize(name)
-
- if defined?(@commands) and command = @commands[name]
- # nothing
- elsif superclass.respond_to? :command and command = superclass.command(name)
- # nothing
- else
- raise Puppet::DevError, "No command #{name} defined for provider #{self.name}"
- end
-
- binary(command)
+ attr_accessor :resource_type
+ attr_writer :doc
+ end
+
+ # LAK 2007-05-09: Keep the model stuff around for backward compatibility
+ attr_reader :model
+ attr_accessor :resource
+
+ def self.command(name)
+ name = symbolize(name)
+
+ if defined?(@commands) and command = @commands[name]
+ # nothing
+ elsif superclass.respond_to? :command and command = superclass.command(name)
+ # nothing
+ else
+ raise Puppet::DevError, "No command #{name} defined for provider #{self.name}"
end
- # Define commands that are not optional.
- def self.commands(hash)
- optional_commands(hash) do |name, path|
- confine :exists => path, :for_binary => true
- end
- end
+ binary(command)
+ end
- # Is the provided feature a declared feature?
- def self.declared_feature?(name)
- defined?(@declared_features) and @declared_features.include?(name)
+ # Define commands that are not optional.
+ def self.commands(hash)
+ optional_commands(hash) do |name, path|
+ confine :exists => path, :for_binary => true
end
-
- # Does this implementation match all of the default requirements? If
- # defaults are empty, we return false.
- def self.default?
- return false if @defaults.empty?
- if @defaults.find do |fact, values|
- values = [values] unless values.is_a? Array
- if fval = Facter.value(fact).to_s and fval != ""
- fval = fval.to_s.downcase.intern
- else
- return false
- end
-
- # If any of the values match, we're a default.
- if values.find do |value| fval == value.to_s.downcase.intern end
- false
- else
- true
- end
- end
- return false
+ end
+
+ # Is the provided feature a declared feature?
+ def self.declared_feature?(name)
+ defined?(@declared_features) and @declared_features.include?(name)
+ end
+
+ # Does this implementation match all of the default requirements? If
+ # defaults are empty, we return false.
+ def self.default?
+ return false if @defaults.empty?
+ if @defaults.find do |fact, values|
+ values = [values] unless values.is_a? Array
+ if fval = Facter.value(fact).to_s and fval != ""
+ fval = fval.to_s.downcase.intern
else
- return true
+ return false
end
- end
- # Store how to determine defaults.
- def self.defaultfor(hash)
- hash.each do |d,v|
- @defaults[d] = v
+ # If any of the values match, we're a default.
+ if values.find do |value| fval == value.to_s.downcase.intern end
+ false
+ else
+ true
end
+ end
+ return false
+ else
+ return true
end
+ end
- def self.specificity
- (@defaults.length * 100) + ancestors.select { |a| a.is_a? Class }.length
+ # Store how to determine defaults.
+ def self.defaultfor(hash)
+ hash.each do |d,v|
+ @defaults[d] = v
end
-
- def self.initvars
- @defaults = {}
- @commands = {}
- end
-
- # The method for returning a list of provider instances. Note that it returns providers, preferably with values already
- # filled in, not resources.
- def self.instances
- raise Puppet::DevError, "Provider #{self.name} has not defined the 'instances' class method"
- end
-
- # Create the methods for a given command.
- def self.make_command_methods(name)
- # Now define a method for that command
- unless singleton_class.method_defined?(name)
- meta_def(name) do |*args|
- raise Puppet::Error, "Command #{name} is missing" unless command(name)
- if args.empty?
- cmd = [command(name)]
- else
- cmd = [command(name)] + args
- end
- # This might throw an ExecutionFailure, but the system above
- # will catch it, if so.
- return execute(cmd)
- end
-
- # And then define an instance method that just calls the class method.
- # We need both, so both instances and classes can easily run the commands.
- unless method_defined?(name)
- define_method(name) do |*args|
- self.class.send(name, *args)
- end
- end
+ end
+
+ def self.specificity
+ (@defaults.length * 100) + ancestors.select { |a| a.is_a? Class }.length
+ end
+
+ def self.initvars
+ @defaults = {}
+ @commands = {}
+ end
+
+ # The method for returning a list of provider instances. Note that it returns providers, preferably with values already
+ # filled in, not resources.
+ def self.instances
+ raise Puppet::DevError, "Provider #{self.name} has not defined the 'instances' class method"
+ end
+
+ # Create the methods for a given command.
+ def self.make_command_methods(name)
+ # Now define a method for that command
+ unless singleton_class.method_defined?(name)
+ meta_def(name) do |*args|
+ raise Puppet::Error, "Command #{name} is missing" unless command(name)
+ if args.empty?
+ cmd = [command(name)]
+ else
+ cmd = [command(name)] + args
end
- end
-
- # Create getter/setter methods for each property our resource type supports.
- # They all get stored in @property_hash. This method is useful
- # for those providers that use prefetch and flush.
- def self.mkmodelmethods
- warnonce "Provider.mkmodelmethods is deprecated; use Provider.mk_resource_methods"
- mk_resource_methods
- end
-
- # Create getter/setter methods for each property our resource type supports.
- # They all get stored in @property_hash. This method is useful
- # for those providers that use prefetch and flush.
- def self.mk_resource_methods
- [resource_type.validproperties, resource_type.parameters].flatten.each do |attr|
- attr = symbolize(attr)
- next if attr == :name
- define_method(attr) do
- @property_hash[attr] || :absent
- end
-
- define_method(attr.to_s + "=") do |val|
- @property_hash[attr] = val
- end
+ # This might throw an ExecutionFailure, but the system above
+ # will catch it, if so.
+ return execute(cmd)
+ end
+
+ # And then define an instance method that just calls the class method.
+ # We need both, so both instances and classes can easily run the commands.
+ unless method_defined?(name)
+ define_method(name) do |*args|
+ self.class.send(name, *args)
end
+ end
+ end
+ end
+
+ # Create getter/setter methods for each property our resource type supports.
+ # They all get stored in @property_hash. This method is useful
+ # for those providers that use prefetch and flush.
+ def self.mkmodelmethods
+ warnonce "Provider.mkmodelmethods is deprecated; use Provider.mk_resource_methods"
+ mk_resource_methods
+ end
+
+ # Create getter/setter methods for each property our resource type supports.
+ # They all get stored in @property_hash. This method is useful
+ # for those providers that use prefetch and flush.
+ def self.mk_resource_methods
+ [resource_type.validproperties, resource_type.parameters].flatten.each do |attr|
+ attr = symbolize(attr)
+ next if attr == :name
+ define_method(attr) do
+ @property_hash[attr] || :absent
+ end
+
+ define_method(attr.to_s + "=") do |val|
+ @property_hash[attr] = val
+ end
end
+ end
- self.initvars
+ self.initvars
- # Define one or more binaries we'll be using. If a block is passed, yield the name
- # and path to the block (really only used by 'commands').
- def self.optional_commands(hash)
- hash.each do |name, path|
- name = symbolize(name)
- @commands[name] = path
+ # Define one or more binaries we'll be using. If a block is passed, yield the name
+ # and path to the block (really only used by 'commands').
+ def self.optional_commands(hash)
+ hash.each do |name, path|
+ name = symbolize(name)
+ @commands[name] = path
- yield(name, path) if block_given?
+ yield(name, path) if block_given?
- # Now define the class and instance methods.
- make_command_methods(name)
- end
+ # Now define the class and instance methods.
+ make_command_methods(name)
end
-
- # Retrieve the data source. Defaults to the provider name.
- def self.source
- @source ||= self.name
+ end
+
+ # Retrieve the data source. Defaults to the provider name.
+ def self.source
+ @source ||= self.name
+ end
+
+ # Does this provider support the specified parameter?
+ def self.supports_parameter?(param)
+ if param.is_a?(Class)
+ klass = param
+ else
+ unless klass = resource_type.attrclass(param)
+ raise Puppet::DevError, "'#{param}' is not a valid parameter for #{resource_type.name}"
+ end
end
+ return true unless features = klass.required_features
- # Does this provider support the specified parameter?
- def self.supports_parameter?(param)
- if param.is_a?(Class)
- klass = param
- else
- unless klass = resource_type.attrclass(param)
- raise Puppet::DevError, "'#{param}' is not a valid parameter for #{resource_type.name}"
- end
- end
- return true unless features = klass.required_features
-
- !!satisfies?(*features)
- end
+ !!satisfies?(*features)
+ end
# def self.to_s
# unless defined?(@str)
@@ -202,80 +202,80 @@ class Puppet::Provider
# @str
# end
- dochook(:defaults) do
- if @defaults.length > 0
- return " Default for " + @defaults.collect do |f, v|
- "``#{f}`` == ``#{v}``"
- end.join(" and ") + "."
- end
+ dochook(:defaults) do
+ if @defaults.length > 0
+ return " Default for " + @defaults.collect do |f, v|
+ "``#{f}`` == ``#{v}``"
+ end.join(" and ") + "."
end
+ end
- dochook(:commands) do
- if @commands.length > 0
- return " Required binaries: " + @commands.collect do |n, c|
- "``#{c}``"
- end.join(", ") + "."
- end
+ dochook(:commands) do
+ if @commands.length > 0
+ return " Required binaries: " + @commands.collect do |n, c|
+ "``#{c}``"
+ end.join(", ") + "."
end
+ end
- dochook(:features) do
- if features.length > 0
- return " Supported features: " + features.collect do |f|
- "``#{f}``"
- end.join(", ") + "."
- end
+ dochook(:features) do
+ if features.length > 0
+ return " Supported features: " + features.collect do |f|
+ "``#{f}``"
+ end.join(", ") + "."
end
-
- # Remove the reference to the resource, so GC can clean up.
- def clear
- @resource = nil
- @model = nil
+ end
+
+ # Remove the reference to the resource, so GC can clean up.
+ def clear
+ @resource = nil
+ @model = nil
+ end
+
+ # Retrieve a named command.
+ def command(name)
+ self.class.command(name)
+ end
+
+ # Get a parameter value.
+ def get(param)
+ @property_hash[symbolize(param)] || :absent
+ end
+
+ def initialize(resource = nil)
+ if resource.is_a?(Hash)
+ # We don't use a duplicate here, because some providers (ParsedFile, at least)
+ # use the hash here for later events.
+ @property_hash = resource
+ elsif resource
+ @resource = resource
+ # LAK 2007-05-09: Keep the model stuff around for backward compatibility
+ @model = resource
+ @property_hash = {}
+ else
+ @property_hash = {}
end
-
- # Retrieve a named command.
- def command(name)
- self.class.command(name)
+ end
+
+ def name
+ if n = @property_hash[:name]
+ return n
+ elsif self.resource
+ resource.name
+ else
+ raise Puppet::DevError, "No resource and no name in property hash in #{self.class.name} instance"
end
+ end
- # Get a parameter value.
- def get(param)
- @property_hash[symbolize(param)] || :absent
+ # Set passed params as the current values.
+ def set(params)
+ params.each do |param, value|
+ @property_hash[symbolize(param)] = value
end
+ end
- def initialize(resource = nil)
- if resource.is_a?(Hash)
- # We don't use a duplicate here, because some providers (ParsedFile, at least)
- # use the hash here for later events.
- @property_hash = resource
- elsif resource
- @resource = resource
- # LAK 2007-05-09: Keep the model stuff around for backward compatibility
- @model = resource
- @property_hash = {}
- else
- @property_hash = {}
- end
- end
-
- def name
- if n = @property_hash[:name]
- return n
- elsif self.resource
- resource.name
- else
- raise Puppet::DevError, "No resource and no name in property hash in #{self.class.name} instance"
- end
- end
-
- # Set passed params as the current values.
- def set(params)
- params.each do |param, value|
- @property_hash[symbolize(param)] = value
- end
- end
-
- def to_s
- "#{@resource}(provider=#{self.class.name})"
- end
+ def to_s
+ "#{@resource}(provider=#{self.class.name})"
+ end
end
diff --git a/lib/puppet/provider/augeas/augeas.rb b/lib/puppet/provider/augeas/augeas.rb
index 4fff9e299..7dbd06240 100644
--- a/lib/puppet/provider/augeas/augeas.rb
+++ b/lib/puppet/provider/augeas/augeas.rb
@@ -21,341 +21,341 @@ require 'augeas' if Puppet.features.augeas?
require 'strscan'
Puppet::Type.type(:augeas).provide(:augeas) do
- include Puppet::Util
-
- confine :true => Puppet.features.augeas?
-
- has_features :parse_commands, :need_to_run?,:execute_changes
-
- SAVE_NOOP = "noop"
- SAVE_OVERWRITE = "overwrite"
-
- COMMANDS = {
- "set" => [ :path, :string ],
- "rm" => [ :path ],
- "clear" => [ :path ],
- "insert" => [ :string, :string, :path ],
- "get" => [ :path, :comparator, :string ],
- "match" => [ :path, :glob ],
- "size" => [:comparator, :int],
- "include" => [:string],
- "not_include" => [:string],
- "==" => [:glob],
- "!=" => [:glob]
- }
-
- COMMANDS["ins"] = COMMANDS["insert"]
- COMMANDS["remove"] = COMMANDS["rm"]
-
- attr_accessor :aug
-
- # Extracts an 2 dimensional array of commands which are in the
- # form of command path value.
- # The input can be
- # - A string with one command
- # - A string with many commands per line
- # - An array of strings.
- def parse_commands(data)
- context = resource[:context]
- # Add a trailing / if it is not there
- if (context.length > 0)
- context << "/" if context[-1, 1] != "/"
- end
-
- data = data.split($/) if data.is_a?(String)
- data = data.flatten
- args = []
- data.each do |line|
- line.strip!
- next if line.nil? || line.empty?
- argline = []
- sc = StringScanner.new(line)
- cmd = sc.scan(/\w+|==|!=/)
- formals = COMMANDS[cmd]
- fail("Unknown command #{cmd}") unless formals
- argline << cmd
- narg = 0
- formals.each do |f|
- sc.skip(/\s+/)
- narg += 1
- if f == :path
- start = sc.pos
- nbracket = 0
- inSingleTick = false
- inDoubleTick = false
- begin
- sc.skip(/([^\]\[\s\\'"]|\\.)+/)
- ch = sc.getch
- nbracket += 1 if ch == "["
- nbracket -= 1 if ch == "]"
- inSingleTick = !inSingleTick if ch == "'"
- inDoubleTick = !inDoubleTick if ch == "\""
- fail("unmatched [") if nbracket < 0
- end until ((nbracket == 0 && !inSingleTick && !inDoubleTick && (ch =~ /\s/)) || sc.eos?)
- len = sc.pos - start
- len -= 1 unless sc.eos?
- unless p = sc.string[start, len]
- fail("missing path argument #{narg} for #{cmd}")
- end
- # Rip off any ticks if they are there.
- p = p[1, (p.size - 2)] if p[0,1] == "'" || p[0,1] == "\""
- p.chomp!("/")
- if p[0,1] != '$' && p[0,1] != "/"
- argline << context + p
- else
- argline << p
- end
- elsif f == :string
- delim = sc.peek(1)
- if delim == "'" || delim == "\""
- sc.getch
- argline << sc.scan(/([^\\#{delim}]|(\\.))*/)
- sc.getch
- else
- argline << sc.scan(/[^\s]+/)
- end
- fail("missing string argument #{narg} for #{cmd}") unless argline[-1]
- elsif f == :comparator
- argline << sc.scan(/(==|!=|=~|<|<=|>|>=)/)
- unless argline[-1]
- puts sc.rest
- fail("invalid comparator for command #{cmd}")
- end
- elsif f == :int
- argline << sc.scan(/\d+/).to_i
- elsif f== :glob
- argline << sc.rest
- end
- end
- args << argline
- end
- args
+ include Puppet::Util
+
+ confine :true => Puppet.features.augeas?
+
+ has_features :parse_commands, :need_to_run?,:execute_changes
+
+ SAVE_NOOP = "noop"
+ SAVE_OVERWRITE = "overwrite"
+
+ COMMANDS = {
+ "set" => [ :path, :string ],
+ "rm" => [ :path ],
+ "clear" => [ :path ],
+ "insert" => [ :string, :string, :path ],
+ "get" => [ :path, :comparator, :string ],
+ "match" => [ :path, :glob ],
+ "size" => [:comparator, :int],
+ "include" => [:string],
+ "not_include" => [:string],
+ "==" => [:glob],
+ "!=" => [:glob]
+ }
+
+ COMMANDS["ins"] = COMMANDS["insert"]
+ COMMANDS["remove"] = COMMANDS["rm"]
+
+ attr_accessor :aug
+
+ # Extracts an 2 dimensional array of commands which are in the
+ # form of command path value.
+ # The input can be
+ # - A string with one command
+ # - A string with many commands per line
+ # - An array of strings.
+ def parse_commands(data)
+ context = resource[:context]
+ # Add a trailing / if it is not there
+ if (context.length > 0)
+ context << "/" if context[-1, 1] != "/"
end
-
- def open_augeas
- unless @aug
- flags = Augeas::NONE
- flags = Augeas::TYPE_CHECK if resource[:type_check] == :true
- flags |= Augeas::NO_MODL_AUTOLOAD if resource[:incl]
- root = resource[:root]
- load_path = resource[:load_path]
- debug("Opening augeas with root #{root}, lens path #{load_path}, flags #{flags}")
- @aug = Augeas::open(root, load_path,flags)
-
- debug("Augeas version #{get_augeas_version} is installed") if get_augeas_version >= "0.3.6"
-
- if resource[:incl]
- aug.set("/augeas/load/Xfm/lens", resource[:lens])
- aug.set("/augeas/load/Xfm/incl", resource[:incl])
- aug.load
- end
+ data = data.split($/) if data.is_a?(String)
+ data = data.flatten
+ args = []
+ data.each do |line|
+ line.strip!
+ next if line.nil? || line.empty?
+ argline = []
+ sc = StringScanner.new(line)
+ cmd = sc.scan(/\w+|==|!=/)
+ formals = COMMANDS[cmd]
+ fail("Unknown command #{cmd}") unless formals
+ argline << cmd
+ narg = 0
+ formals.each do |f|
+ sc.skip(/\s+/)
+ narg += 1
+ if f == :path
+ start = sc.pos
+ nbracket = 0
+ inSingleTick = false
+ inDoubleTick = false
+ begin
+ sc.skip(/([^\]\[\s\\'"]|\\.)+/)
+ ch = sc.getch
+ nbracket += 1 if ch == "["
+ nbracket -= 1 if ch == "]"
+ inSingleTick = !inSingleTick if ch == "'"
+ inDoubleTick = !inDoubleTick if ch == "\""
+ fail("unmatched [") if nbracket < 0
+ end until ((nbracket == 0 && !inSingleTick && !inDoubleTick && (ch =~ /\s/)) || sc.eos?)
+ len = sc.pos - start
+ len -= 1 unless sc.eos?
+ unless p = sc.string[start, len]
+ fail("missing path argument #{narg} for #{cmd}")
+ end
+ # Rip off any ticks if they are there.
+ p = p[1, (p.size - 2)] if p[0,1] == "'" || p[0,1] == "\""
+ p.chomp!("/")
+ if p[0,1] != '$' && p[0,1] != "/"
+ argline << context + p
+ else
+ argline << p
+ end
+ elsif f == :string
+ delim = sc.peek(1)
+ if delim == "'" || delim == "\""
+ sc.getch
+ argline << sc.scan(/([^\\#{delim}]|(\\.))*/)
+ sc.getch
+ else
+ argline << sc.scan(/[^\s]+/)
+ end
+ fail("missing string argument #{narg} for #{cmd}") unless argline[-1]
+ elsif f == :comparator
+ argline << sc.scan(/(==|!=|=~|<|<=|>|>=)/)
+ unless argline[-1]
+ puts sc.rest
+ fail("invalid comparator for command #{cmd}")
+ end
+ elsif f == :int
+ argline << sc.scan(/\d+/).to_i
+ elsif f== :glob
+ argline << sc.rest
end
- @aug
+ end
+ args << argline
end
-
- def close_augeas
- if @aug
- @aug.close
- debug("Closed the augeas connection")
- @aug = nil
- end
+ args
+ end
+
+
+ def open_augeas
+ unless @aug
+ flags = Augeas::NONE
+ flags = Augeas::TYPE_CHECK if resource[:type_check] == :true
+ flags |= Augeas::NO_MODL_AUTOLOAD if resource[:incl]
+ root = resource[:root]
+ load_path = resource[:load_path]
+ debug("Opening augeas with root #{root}, lens path #{load_path}, flags #{flags}")
+ @aug = Augeas::open(root, load_path,flags)
+
+ debug("Augeas version #{get_augeas_version} is installed") if get_augeas_version >= "0.3.6"
+
+ if resource[:incl]
+ aug.set("/augeas/load/Xfm/lens", resource[:lens])
+ aug.set("/augeas/load/Xfm/incl", resource[:incl])
+ aug.load
+ end
end
-
- # Used by the need_to_run? method to process get filters. Returns
- # true if there is a match, false if otherwise
- # Assumes a syntax of get /files/path [COMPARATOR] value
- def process_get(cmd_array)
- return_value = false
-
- #validate and tear apart the command
- fail ("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 4
- cmd = cmd_array.shift
- path = cmd_array.shift
- comparator = cmd_array.shift
- arg = cmd_array.join(" ")
-
- #check the value in augeas
- result = @aug.get(path) || ''
- case comparator
- when "!="
- return_value = (result != arg)
- when "=~"
- regex = Regexp.new(arg)
- return_value = (result =~ regex)
- else
- return_value = (result.send(comparator, arg))
- end
- !!return_value
+ @aug
+ end
+
+ def close_augeas
+ if @aug
+ @aug.close
+ debug("Closed the augeas connection")
+ @aug = nil
end
-
- # Used by the need_to_run? method to process match filters. Returns
- # true if there is a match, false if otherwise
- def process_match(cmd_array)
- return_value = false
-
- #validate and tear apart the command
- fail("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 3
- cmd = cmd_array.shift
- path = cmd_array.shift
-
- # Need to break apart the clause
- clause_array = parse_commands(cmd_array.shift)[0]
- verb = clause_array.shift
-
- #Get the values from augeas
- result = @aug.match(path) || []
- fail("Error trying to match path '#{path}'") if (result == -1)
-
- # Now do the work
- case verb
- when "size"
- fail("Invalid command: #{cmd_array.join(" ")}") if clause_array.length != 2
- comparator = clause_array.shift
- arg = clause_array.shift
- return_value = (result.size.send(comparator, arg))
- when "include"
- arg = clause_array.shift
- return_value = result.include?(arg)
- when "not_include"
- arg = clause_array.shift
- return_value = !result.include?(arg)
- when "=="
- begin
- arg = clause_array.shift
- new_array = eval arg
- return_value = (result == new_array)
- rescue
- fail("Invalid array in command: #{cmd_array.join(" ")}")
- end
- when "!="
- begin
- arg = clause_array.shift
- new_array = eval arg
- return_value = (result != new_array)
- rescue
- fail("Invalid array in command: #{cmd_array.join(" ")}")
- end
- end
- !!return_value
- end
-
- def get_augeas_version
- @aug.get("/augeas/version") || ""
+ end
+
+ # Used by the need_to_run? method to process get filters. Returns
+ # true if there is a match, false if otherwise
+ # Assumes a syntax of get /files/path [COMPARATOR] value
+ def process_get(cmd_array)
+ return_value = false
+
+ #validate and tear apart the command
+ fail ("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 4
+ cmd = cmd_array.shift
+ path = cmd_array.shift
+ comparator = cmd_array.shift
+ arg = cmd_array.join(" ")
+
+ #check the value in augeas
+ result = @aug.get(path) || ''
+ case comparator
+ when "!="
+ return_value = (result != arg)
+ when "=~"
+ regex = Regexp.new(arg)
+ return_value = (result =~ regex)
+ else
+ return_value = (result.send(comparator, arg))
end
-
- def set_augeas_save_mode(mode)
- @aug.set("/augeas/save", mode)
+ !!return_value
+ end
+
+ # Used by the need_to_run? method to process match filters. Returns
+ # true if there is a match, false if otherwise
+ def process_match(cmd_array)
+ return_value = false
+
+ #validate and tear apart the command
+ fail("Invalid command: #{cmd_array.join(" ")}") if cmd_array.length < 3
+ cmd = cmd_array.shift
+ path = cmd_array.shift
+
+ # Need to break apart the clause
+ clause_array = parse_commands(cmd_array.shift)[0]
+ verb = clause_array.shift
+
+ #Get the values from augeas
+ result = @aug.match(path) || []
+ fail("Error trying to match path '#{path}'") if (result == -1)
+
+ # Now do the work
+ case verb
+ when "size"
+ fail("Invalid command: #{cmd_array.join(" ")}") if clause_array.length != 2
+ comparator = clause_array.shift
+ arg = clause_array.shift
+ return_value = (result.size.send(comparator, arg))
+ when "include"
+ arg = clause_array.shift
+ return_value = result.include?(arg)
+ when "not_include"
+ arg = clause_array.shift
+ return_value = !result.include?(arg)
+ when "=="
+ begin
+ arg = clause_array.shift
+ new_array = eval arg
+ return_value = (result == new_array)
+ rescue
+ fail("Invalid array in command: #{cmd_array.join(" ")}")
+ end
+ when "!="
+ begin
+ arg = clause_array.shift
+ new_array = eval arg
+ return_value = (result != new_array)
+ rescue
+ fail("Invalid array in command: #{cmd_array.join(" ")}")
+ end
end
-
- def files_changed?
- saved_files = @aug.match("/augeas/events/saved")
- saved_files.size > 0
- end
-
- # Determines if augeas acutally needs to run.
- def need_to_run?
- force = resource[:force]
- return_value = true
+ !!return_value
+ end
+
+ def get_augeas_version
+ @aug.get("/augeas/version") || ""
+ end
+
+ def set_augeas_save_mode(mode)
+ @aug.set("/augeas/save", mode)
+ end
+
+ def files_changed?
+ saved_files = @aug.match("/augeas/events/saved")
+ saved_files.size > 0
+ end
+
+ # Determines if augeas acutally needs to run.
+ def need_to_run?
+ force = resource[:force]
+ return_value = true
+ begin
+ open_augeas
+ filter = resource[:onlyif]
+ unless filter == ""
+ cmd_array = parse_commands(filter)[0]
+ command = cmd_array[0];
begin
- open_augeas
- filter = resource[:onlyif]
- unless filter == ""
- cmd_array = parse_commands(filter)[0]
- command = cmd_array[0];
- begin
- case command
- when "get"; return_value = process_get(cmd_array)
- when "match"; return_value = process_match(cmd_array)
- end
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => e
- fail("Error sending command '#{command}' with params #{cmd_array[1..-1].inspect}/#{e.message}")
- end
- end
-
- unless force
- # If we have a verison of augeas which is at least 0.3.6 then we
- # can make the changes now, see if changes were made, and
- # actually do the save.
- if return_value and get_augeas_version >= "0.3.6"
- debug("Will attempt to save and only run if files changed")
- set_augeas_save_mode(SAVE_NOOP)
- do_execute_changes
- save_result = @aug.save
- saved_files = @aug.match("/augeas/events/saved")
- if save_result and not files_changed?
- debug("Skipping because no files were changed")
- return_value = false
- else
- debug("Files changed, should execute")
- end
- end
- end
- ensure
- close_augeas
+ case command
+ when "get"; return_value = process_get(cmd_array)
+ when "match"; return_value = process_match(cmd_array)
+ end
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => e
+ fail("Error sending command '#{command}' with params #{cmd_array[1..-1].inspect}/#{e.message}")
+ end
+ end
+
+ unless force
+ # If we have a verison of augeas which is at least 0.3.6 then we
+ # can make the changes now, see if changes were made, and
+ # actually do the save.
+ if return_value and get_augeas_version >= "0.3.6"
+ debug("Will attempt to save and only run if files changed")
+ set_augeas_save_mode(SAVE_NOOP)
+ do_execute_changes
+ save_result = @aug.save
+ saved_files = @aug.match("/augeas/events/saved")
+ if save_result and not files_changed?
+ debug("Skipping because no files were changed")
+ return_value = false
+ else
+ debug("Files changed, should execute")
+ end
end
- return_value
+ end
+ ensure
+ close_augeas
end
+ return_value
+ end
- def execute_changes
- # Re-connect to augeas, and re-execute the changes
- begin
- open_augeas
- set_augeas_save_mode(SAVE_OVERWRITE) if get_augeas_version >= "0.3.6"
-
- do_execute_changes
+ def execute_changes
+ # Re-connect to augeas, and re-execute the changes
+ begin
+ open_augeas
+ set_augeas_save_mode(SAVE_OVERWRITE) if get_augeas_version >= "0.3.6"
- success = @aug.save
- fail("Save failed with return code #{success}") if success != true
- ensure
- close_augeas
- end
+ do_execute_changes
- :executed
+ success = @aug.save
+ fail("Save failed with return code #{success}") if success != true
+ ensure
+ close_augeas
end
- # Actually execute the augeas changes.
- def do_execute_changes
- commands = parse_commands(resource[:changes])
- commands.each do |cmd_array|
- fail("invalid command #{cmd_array.join[" "]}") if cmd_array.length < 2
- command = cmd_array[0]
- cmd_array.shift
- begin
- case command
- when "set"
- debug("sending command '#{command}' with params #{cmd_array.inspect}")
- rv = aug.set(cmd_array[0], cmd_array[1])
- fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
- when "rm", "remove"
- debug("sending command '#{command}' with params #{cmd_array.inspect}")
- rv = aug.rm(cmd_array[0])
- fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
- when "clear"
- debug("sending command '#{command}' with params #{cmd_array.inspect}")
- rv = aug.clear(cmd_array[0])
- fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
- when "insert", "ins"
- label = cmd_array[0]
- where = cmd_array[1]
- path = cmd_array[2]
- case where
- when "before"; before = true
- when "after"; before = false
- else fail("Invalid value '#{where}' for where param")
- end
- debug("sending command '#{command}' with params #{[label, where, path].inspect}")
- rv = aug.insert(path, label, before)
- fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
- else fail("Command '#{command}' is not supported")
- end
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => e
- fail("Error sending command '#{command}' with params #{cmd_array.inspect}/#{e.message}")
+ :executed
+ end
+
+ # Actually execute the augeas changes.
+ def do_execute_changes
+ commands = parse_commands(resource[:changes])
+ commands.each do |cmd_array|
+ fail("invalid command #{cmd_array.join[" "]}") if cmd_array.length < 2
+ command = cmd_array[0]
+ cmd_array.shift
+ begin
+ case command
+ when "set"
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ rv = aug.set(cmd_array[0], cmd_array[1])
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+ when "rm", "remove"
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ rv = aug.rm(cmd_array[0])
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
+ when "clear"
+ debug("sending command '#{command}' with params #{cmd_array.inspect}")
+ rv = aug.clear(cmd_array[0])
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv)
+ when "insert", "ins"
+ label = cmd_array[0]
+ where = cmd_array[1]
+ path = cmd_array[2]
+ case where
+ when "before"; before = true
+ when "after"; before = false
+ else fail("Invalid value '#{where}' for where param")
end
+ debug("sending command '#{command}' with params #{[label, where, path].inspect}")
+ rv = aug.insert(path, label, before)
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1)
+ else fail("Command '#{command}' is not supported")
end
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => e
+ fail("Error sending command '#{command}' with params #{cmd_array.inspect}/#{e.message}")
+ end
end
+ end
end
diff --git a/lib/puppet/provider/computer/computer.rb b/lib/puppet/provider/computer/computer.rb
index 73f2d2b89..a6be6bdfe 100644
--- a/lib/puppet/provider/computer/computer.rb
+++ b/lib/puppet/provider/computer/computer.rb
@@ -1,22 +1,22 @@
require 'puppet/provider/nameservice/directoryservice'
Puppet::Type.type(:computer).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do
- desc "Computer object management using DirectoryService on OS X.
- Note that these are distinctly different kinds of objects to 'hosts',
- as they require a MAC address and can have all sorts of policy attached to
- them.
+ desc "Computer object management using DirectoryService on OS X.
+ Note that these are distinctly different kinds of objects to 'hosts',
+ as they require a MAC address and can have all sorts of policy attached to
+ them.
- This provider only manages Computer objects in the local directory service
- domain, not in remote directories.
+ This provider only manages Computer objects in the local directory service
+ domain, not in remote directories.
- If you wish to manage /etc/hosts on Mac OS X, then simply use the host
- type as per other platforms.
+ If you wish to manage /etc/hosts on Mac OS X, then simply use the host
+ type as per other platforms.
- "
+ "
- confine :operatingsystem => :darwin
- defaultfor :operatingsystem => :darwin
+ confine :operatingsystem => :darwin
+ defaultfor :operatingsystem => :darwin
- # hurray for abstraction. The nameservice directoryservice provider can
- # handle everything we need. super.
+ # hurray for abstraction. The nameservice directoryservice provider can
+ # handle everything we need. super.
end
diff --git a/lib/puppet/provider/confine.rb b/lib/puppet/provider/confine.rb
index e75bc5c78..6825def7e 100644
--- a/lib/puppet/provider/confine.rb
+++ b/lib/puppet/provider/confine.rb
@@ -3,78 +3,78 @@
require 'puppet/util'
class Puppet::Provider::Confine
- include Puppet::Util
+ include Puppet::Util
- @tests = {}
+ @tests = {}
- class << self
- attr_accessor :name
- end
+ class << self
+ attr_accessor :name
+ end
- def self.inherited(klass)
- name = klass.to_s.split("::").pop.downcase.to_sym
- raise "Test #{name} is already defined" if @tests.include?(name)
+ def self.inherited(klass)
+ name = klass.to_s.split("::").pop.downcase.to_sym
+ raise "Test #{name} is already defined" if @tests.include?(name)
- klass.name = name
+ klass.name = name
- @tests[name] = klass
- end
+ @tests[name] = klass
+ end
- def self.test(name)
- unless @tests[name]
- begin
- require "puppet/provider/confine/#{name}"
- rescue LoadError => detail
- unless detail.to_s =~ /No such file/i
- warn "Could not load confine test '#{name}': #{detail}"
- end
- # Could not find file
- end
+ def self.test(name)
+ unless @tests[name]
+ begin
+ require "puppet/provider/confine/#{name}"
+ rescue LoadError => detail
+ unless detail.to_s =~ /No such file/i
+ warn "Could not load confine test '#{name}': #{detail}"
end
- @tests[name]
- end
-
- attr_reader :values
-
- # Mark that this confine is used for testing binary existence.
- attr_accessor :for_binary
- def for_binary?
- for_binary
+ # Could not find file
+ end
end
-
- # Used for logging.
- attr_accessor :label
-
- def initialize(values)
- values = [values] unless values.is_a?(Array)
- @values = values
+ @tests[name]
+ end
+
+ attr_reader :values
+
+ # Mark that this confine is used for testing binary existence.
+ attr_accessor :for_binary
+ def for_binary?
+ for_binary
+ end
+
+ # Used for logging.
+ attr_accessor :label
+
+ def initialize(values)
+ values = [values] unless values.is_a?(Array)
+ @values = values
+ end
+
+ # Provide a hook for the message when there's a failure.
+ def message(value)
+ ""
+ end
+
+ # Collect the results of all of them.
+ def result
+ values.collect { |value| pass?(value) }
+ end
+
+ # Test whether our confine matches.
+ def valid?
+ values.each do |value|
+ unless pass?(value)
+ Puppet.debug(label + ": " + message(value))
+ return false
+ end
end
- # Provide a hook for the message when there's a failure.
- def message(value)
- ""
- end
+ return true
+ ensure
+ reset
+ end
- # Collect the results of all of them.
- def result
- values.collect { |value| pass?(value) }
- end
-
- # Test whether our confine matches.
- def valid?
- values.each do |value|
- unless pass?(value)
- Puppet.debug(label + ": " + message(value))
- return false
- end
- end
-
- return true
- ensure
- reset
- end
-
- # Provide a hook for subclasses.
- def reset
- end
+ # Provide a hook for subclasses.
+ def reset
+ end
end
diff --git a/lib/puppet/provider/confine/exists.rb b/lib/puppet/provider/confine/exists.rb
index 27c404acb..085118b2a 100644
--- a/lib/puppet/provider/confine/exists.rb
+++ b/lib/puppet/provider/confine/exists.rb
@@ -1,22 +1,22 @@
require 'puppet/provider/confine'
class Puppet::Provider::Confine::Exists < Puppet::Provider::Confine
- def self.summarize(confines)
- confines.inject([]) { |total, confine| total + confine.summary }
- end
+ def self.summarize(confines)
+ confines.inject([]) { |total, confine| total + confine.summary }
+ end
- def pass?(value)
- if for_binary?
- return false unless value = binary(value)
- end
- value and FileTest.exist?(value)
+ def pass?(value)
+ if for_binary?
+ return false unless value = binary(value)
end
+ value and FileTest.exist?(value)
+ end
- def message(value)
- "file #{value} does not exist"
- end
+ def message(value)
+ "file #{value} does not exist"
+ end
- def summary
- result.zip(values).inject([]) { |array, args| val, f = args; array << f unless val; array }
- end
+ def summary
+ result.zip(values).inject([]) { |array, args| val, f = args; array << f unless val; array }
+ end
end
diff --git a/lib/puppet/provider/confine/false.rb b/lib/puppet/provider/confine/false.rb
index b5b2b51c8..1c11dd40f 100644
--- a/lib/puppet/provider/confine/false.rb
+++ b/lib/puppet/provider/confine/false.rb
@@ -1,19 +1,19 @@
require 'puppet/provider/confine'
class Puppet::Provider::Confine::False < Puppet::Provider::Confine
- def self.summarize(confines)
- confines.inject(0) { |count, confine| count + confine.summary }
- end
+ def self.summarize(confines)
+ confines.inject(0) { |count, confine| count + confine.summary }
+ end
- def pass?(value)
- ! value
- end
+ def pass?(value)
+ ! value
+ end
- def message(value)
- "true value when expecting false"
- end
+ def message(value)
+ "true value when expecting false"
+ end
- def summary
- result.find_all { |v| v == false }.length
- end
+ def summary
+ result.find_all { |v| v == false }.length
+ end
end
diff --git a/lib/puppet/provider/confine/feature.rb b/lib/puppet/provider/confine/feature.rb
index 8cd5daaec..b223b8b11 100644
--- a/lib/puppet/provider/confine/feature.rb
+++ b/lib/puppet/provider/confine/feature.rb
@@ -1,17 +1,17 @@
require 'puppet/provider/confine'
class Puppet::Provider::Confine::Feature < Puppet::Provider::Confine
- def self.summarize(confines)
- confines.collect { |c| c.values }.flatten.uniq.find_all { |value| ! confines[0].pass?(value) }
- end
+ def self.summarize(confines)
+ confines.collect { |c| c.values }.flatten.uniq.find_all { |value| ! confines[0].pass?(value) }
+ end
- # Is the named feature available?
- def pass?(value)
- Puppet.features.send(value.to_s + "?")
- end
+ # Is the named feature available?
+ def pass?(value)
+ Puppet.features.send(value.to_s + "?")
+ end
- def message(value)
- "feature #{value} is missing"
- end
+ def message(value)
+ "feature #{value} is missing"
+ end
end
diff --git a/lib/puppet/provider/confine/true.rb b/lib/puppet/provider/confine/true.rb
index 86b3b144f..559f2675f 100644
--- a/lib/puppet/provider/confine/true.rb
+++ b/lib/puppet/provider/confine/true.rb
@@ -1,20 +1,20 @@
require 'puppet/provider/confine'
class Puppet::Provider::Confine::True < Puppet::Provider::Confine
- def self.summarize(confines)
- confines.inject(0) { |count, confine| count + confine.summary }
- end
+ def self.summarize(confines)
+ confines.inject(0) { |count, confine| count + confine.summary }
+ end
- def pass?(value)
- # Double negate, so we only get true or false.
- ! ! value
- end
+ def pass?(value)
+ # Double negate, so we only get true or false.
+ ! ! value
+ end
- def message(value)
- "false value when expecting true"
- end
+ def message(value)
+ "false value when expecting true"
+ end
- def summary
- result.find_all { |v| v == true }.length
- end
+ def summary
+ result.find_all { |v| v == true }.length
+ end
end
diff --git a/lib/puppet/provider/confine/variable.rb b/lib/puppet/provider/confine/variable.rb
index 84f7e4044..af8e5d314 100644
--- a/lib/puppet/provider/confine/variable.rb
+++ b/lib/puppet/provider/confine/variable.rb
@@ -5,55 +5,55 @@ require 'puppet/provider/confine'
# is set explicitly by the ConfineCollection class -- from this class,
# it's not obvious how the name would ever get set.
class Puppet::Provider::Confine::Variable < Puppet::Provider::Confine
- # Provide a hash summary of failing confines -- the key of the hash
- # is the name of the confine, and the value is the missing yet required values.
- # Only returns failed values, not all required values.
- def self.summarize(confines)
- result = Hash.new { |hash, key| hash[key] = [] }
- confines.inject(result) { |total, confine| total[confine.name] += confine.values unless confine.valid?; total }
- end
-
- # This is set by ConfineCollection.
- attr_accessor :name
-
- # Retrieve the value from facter
- def facter_value
- @facter_value ||= ::Facter.value(name).to_s.downcase
- end
-
- def initialize(values)
- super
- @values = @values.collect { |v| v.to_s.downcase }
- end
-
- def message(value)
- "facter value '#{test_value}' for '#{self.name}' not in required list '#{values.join(",")}'"
- end
-
- # Compare the passed-in value to the retrieved value.
- def pass?(value)
- test_value.downcase.to_s == value.to_s.downcase
- end
-
- def reset
- # Reset the cache. We want to cache it during a given
- # run, but not across runs.
- @facter_value = nil
- end
-
- def valid?
- @values.include?(test_value.to_s.downcase)
- ensure
- reset
- end
-
- private
-
- def setting?
- Puppet.settings.valid?(name)
- end
-
- def test_value
- setting? ? Puppet.settings[name] : facter_value
- end
+ # Provide a hash summary of failing confines -- the key of the hash
+ # is the name of the confine, and the value is the missing yet required values.
+ # Only returns failed values, not all required values.
+ def self.summarize(confines)
+ result = Hash.new { |hash, key| hash[key] = [] }
+ confines.inject(result) { |total, confine| total[confine.name] += confine.values unless confine.valid?; total }
+ end
+
+ # This is set by ConfineCollection.
+ attr_accessor :name
+
+ # Retrieve the value from facter
+ def facter_value
+ @facter_value ||= ::Facter.value(name).to_s.downcase
+ end
+
+ def initialize(values)
+ super
+ @values = @values.collect { |v| v.to_s.downcase }
+ end
+
+ def message(value)
+ "facter value '#{test_value}' for '#{self.name}' not in required list '#{values.join(",")}'"
+ end
+
+ # Compare the passed-in value to the retrieved value.
+ def pass?(value)
+ test_value.downcase.to_s == value.to_s.downcase
+ end
+
+ def reset
+ # Reset the cache. We want to cache it during a given
+ # run, but not across runs.
+ @facter_value = nil
+ end
+
+ def valid?
+ @values.include?(test_value.to_s.downcase)
+ ensure
+ reset
+ end
+
+ private
+
+ def setting?
+ Puppet.settings.valid?(name)
+ end
+
+ def test_value
+ setting? ? Puppet.settings[name] : facter_value
+ end
end
diff --git a/lib/puppet/provider/confine_collection.rb b/lib/puppet/provider/confine_collection.rb
index 0dbdc7790..46fd3baaf 100644
--- a/lib/puppet/provider/confine_collection.rb
+++ b/lib/puppet/provider/confine_collection.rb
@@ -3,48 +3,48 @@
require 'puppet/provider/confine'
class Puppet::Provider::ConfineCollection
- def confine(hash)
- if hash.include?(:for_binary)
- for_binary = true
- hash.delete(:for_binary)
- else
- for_binary = false
- end
- hash.each do |test, values|
- if klass = Puppet::Provider::Confine.test(test)
- @confines << klass.new(values)
- @confines[-1].for_binary = true if for_binary
- else
- confine = Puppet::Provider::Confine.test(:variable).new(values)
- confine.name = test
- @confines << confine
- end
- @confines[-1].label = self.label
- end
+ def confine(hash)
+ if hash.include?(:for_binary)
+ for_binary = true
+ hash.delete(:for_binary)
+ else
+ for_binary = false
end
-
- attr_reader :label
- def initialize(label)
- @label = label
- @confines = []
+ hash.each do |test, values|
+ if klass = Puppet::Provider::Confine.test(test)
+ @confines << klass.new(values)
+ @confines[-1].for_binary = true if for_binary
+ else
+ confine = Puppet::Provider::Confine.test(:variable).new(values)
+ confine.name = test
+ @confines << confine
+ end
+ @confines[-1].label = self.label
end
+ end
- # Return a hash of the whole confine set, used for the Provider
- # reference.
- def summary
- confines = Hash.new { |hash, key| hash[key] = [] }
- @confines.each { |confine| confines[confine.class] << confine }
- result = {}
- confines.each do |klass, list|
- value = klass.summarize(list)
- next if (value.respond_to?(:length) and value.length == 0) or (value == 0)
- result[klass.name] = value
+ attr_reader :label
+ def initialize(label)
+ @label = label
+ @confines = []
+ end
- end
- result
- end
+ # Return a hash of the whole confine set, used for the Provider
+ # reference.
+ def summary
+ confines = Hash.new { |hash, key| hash[key] = [] }
+ @confines.each { |confine| confines[confine.class] << confine }
+ result = {}
+ confines.each do |klass, list|
+ value = klass.summarize(list)
+ next if (value.respond_to?(:length) and value.length == 0) or (value == 0)
+ result[klass.name] = value
- def valid?
- ! @confines.detect { |c| ! c.valid? }
end
+ result
+ end
+
+ def valid?
+ ! @confines.detect { |c| ! c.valid? }
+ end
end
diff --git a/lib/puppet/provider/confiner.rb b/lib/puppet/provider/confiner.rb
index d776b689d..6e1fb23ab 100644
--- a/lib/puppet/provider/confiner.rb
+++ b/lib/puppet/provider/confiner.rb
@@ -1,16 +1,16 @@
require 'puppet/provider/confine_collection'
module Puppet::Provider::Confiner
- def confine(hash)
- confine_collection.confine(hash)
- end
+ def confine(hash)
+ confine_collection.confine(hash)
+ end
- def confine_collection
- @confine_collection ||= Puppet::Provider::ConfineCollection.new(self.to_s)
- end
+ def confine_collection
+ @confine_collection ||= Puppet::Provider::ConfineCollection.new(self.to_s)
+ end
- # Check whether this implementation is suitable for our platform.
- def suitable?(short = true)
- return(short ? confine_collection.valid? : confine_collection.summary)
- end
+ # Check whether this implementation is suitable for our platform.
+ def suitable?(short = true)
+ return(short ? confine_collection.valid? : confine_collection.summary)
+ end
end
diff --git a/lib/puppet/provider/cron/crontab.rb b/lib/puppet/provider/cron/crontab.rb
index 7dd41c642..8a347b331 100755
--- a/lib/puppet/provider/cron/crontab.rb
+++ b/lib/puppet/provider/cron/crontab.rb
@@ -1,206 +1,206 @@
require 'puppet/provider/parsedfile'
tab = case Facter.value(:operatingsystem)
- when "Solaris"
- :suntab
- when "AIX"
- :aixtab
- else
- :crontab
- end
+ when "Solaris"
+ :suntab
+ when "AIX"
+ :aixtab
+ else
+ :crontab
+ end
- Puppet::Type.type(:cron).provide(
- :crontab,
- :parent => Puppet::Provider::ParsedFile,
- :default_target => ENV["USER"] || "root",
+ Puppet::Type.type(:cron).provide(
+ :crontab,
+ :parent => Puppet::Provider::ParsedFile,
+ :default_target => ENV["USER"] || "root",
- :filetype => tab
+ :filetype => tab
) do
- commands :crontab => "crontab"
+ commands :crontab => "crontab"
- text_line :comment, :match => %r{^#}, :post_parse => proc { |record|
- record[:name] = $1 if record[:line] =~ /Puppet Name: (.+)\s*$/
- }
+ text_line :comment, :match => %r{^#}, :post_parse => proc { |record|
+ record[:name] = $1 if record[:line] =~ /Puppet Name: (.+)\s*$/
+ }
- text_line :blank, :match => %r{^\s*$}
+ text_line :blank, :match => %r{^\s*$}
- text_line :environment, :match => %r{^\w+=}
+ text_line :environment, :match => %r{^\w+=}
- record_line :freebsd_special, :fields => %w{special command},
- :match => %r{^@(\w+)\s+(.+)$}, :pre_gen => proc { |record|
- record[:special] = "@" + record[:special]
- }
+ record_line :freebsd_special, :fields => %w{special command},
+ :match => %r{^@(\w+)\s+(.+)$}, :pre_gen => proc { |record|
+ record[:special] = "@" + record[:special]
+ }
- crontab = record_line :crontab, :fields => %w{minute hour monthday month weekday command},
- :match => %r{^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$},
- :optional => %w{minute hour weekday month monthday}, :absent => "*"
+ crontab = record_line :crontab, :fields => %w{minute hour monthday month weekday command},
+ :match => %r{^\s*(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$},
+ :optional => %w{minute hour weekday month monthday}, :absent => "*"
- class << crontab
- def numeric_fields
- fields - [:command]
- end
- # Do some post-processing of the parsed record. Basically just
- # split the numeric fields on ','.
- def post_parse(record)
- numeric_fields.each do |field|
- if val = record[field] and val != :absent
- record[field] = record[field].split(",")
- end
- end
+ class << crontab
+ def numeric_fields
+ fields - [:command]
+ end
+ # Do some post-processing of the parsed record. Basically just
+ # split the numeric fields on ','.
+ def post_parse(record)
+ numeric_fields.each do |field|
+ if val = record[field] and val != :absent
+ record[field] = record[field].split(",")
end
+ end
+ end
- # Join the fields back up based on ','.
- def pre_gen(record)
- numeric_fields.each do |field|
- if vals = record[field] and vals.is_a?(Array)
- record[field] = vals.join(",")
- end
- end
+ # Join the fields back up based on ','.
+ def pre_gen(record)
+ numeric_fields.each do |field|
+ if vals = record[field] and vals.is_a?(Array)
+ record[field] = vals.join(",")
end
+ end
+ end
- # Add name and environments as necessary.
- def to_line(record)
- str = ""
- str = "# Puppet Name: #{record[:name]}\n" if record[:name]
- if record[:environment] and record[:environment] != :absent and record[:environment] != [:absent]
- record[:environment].each do |env|
- str += env + "\n"
- end
- end
-
- if record[:special]
- str += "@#{record[:special]} #{record[:command]}"
- else
- str += join(record)
- end
- str
+ # Add name and environments as necessary.
+ def to_line(record)
+ str = ""
+ str = "# Puppet Name: #{record[:name]}\n" if record[:name]
+ if record[:environment] and record[:environment] != :absent and record[:environment] != [:absent]
+ record[:environment].each do |env|
+ str += env + "\n"
end
+ end
+
+ if record[:special]
+ str += "@#{record[:special]} #{record[:command]}"
+ else
+ str += join(record)
+ end
+ str
end
+ end
- # Return the header placed at the top of each generated file, warning
- # users that modifying this file manually is probably a bad idea.
- def self.header
+ # Return the header placed at the top of each generated file, warning
+ # users that modifying this file manually is probably a bad idea.
+ def self.header
%{# HEADER: This file was autogenerated at #{Time.now} by puppet.
# HEADER: While it can still be managed manually, it is definitely not recommended.
# HEADER: Note particularly that the comments starting with 'Puppet Name' should
# HEADER: not be deleted, as doing so could cause duplicate cron jobs.\n}
- end
-
- # See if we can match the record against an existing cron job.
- def self.match(record, resources)
- resources.each do |name, resource|
- # Match the command first, since it's the most important one.
- next unless record[:target] == resource.value(:target)
- next unless record[:command] == resource.value(:command)
-
- # Then check the @special stuff
- if record[:special]
- next unless resource.value(:special) == record[:special]
- end
-
- # Then the normal fields.
- matched = true
- record_type(record[:record_type]).fields.each do |field|
- next if field == :command
- next if field == :special
- if record[field] and ! resource.value(field)
- #Puppet.info "Cron is missing %s: %s and %s" %
- # [field, record[field].inspect, resource.value(field).inspect]
- matched = false
- break
- end
-
- if ! record[field] and resource.value(field)
- #Puppet.info "Hash is missing %s: %s and %s" %
- # [field, resource.value(field).inspect, record[field].inspect]
- matched = false
- break
- end
-
- # Yay differing definitions of absent.
- next if (record[field] == :absent and resource.value(field) == "*")
-
- # Everything should be in the form of arrays, not the normal text.
- next if (record[field] == resource.value(field))
- #Puppet.info "Did not match %s: %s vs %s" %
- # [field, resource.value(field).inspect, record[field].inspect]
- matched = false
- break
- end
- return resource if matched
+ end
+
+ # See if we can match the record against an existing cron job.
+ def self.match(record, resources)
+ resources.each do |name, resource|
+ # Match the command first, since it's the most important one.
+ next unless record[:target] == resource.value(:target)
+ next unless record[:command] == resource.value(:command)
+
+ # Then check the @special stuff
+ if record[:special]
+ next unless resource.value(:special) == record[:special]
+ end
+
+ # Then the normal fields.
+ matched = true
+ record_type(record[:record_type]).fields.each do |field|
+ next if field == :command
+ next if field == :special
+ if record[field] and ! resource.value(field)
+ #Puppet.info "Cron is missing %s: %s and %s" %
+ # [field, record[field].inspect, resource.value(field).inspect]
+ matched = false
+ break
end
- false
- end
+ if ! record[field] and resource.value(field)
+ #Puppet.info "Hash is missing %s: %s and %s" %
+ # [field, resource.value(field).inspect, record[field].inspect]
+ matched = false
+ break
+ end
- # Collapse name and env records.
- def self.prefetch_hook(records)
- name = nil
- envs = nil
- result = records.each { |record|
- case record[:record_type]
- when :comment
- if record[:name]
- name = record[:name]
- record[:skip] = true
-
- # Start collecting env values
- envs = []
- end
- when :environment
- # If we're collecting env values (meaning we're in a named cronjob),
- # store the line and skip the record.
- if envs
- envs << record[:line]
- record[:skip] = true
- end
- when :blank
- # nothing
- else
- if name
- record[:name] = name
- name = nil
- end
- if envs.nil? or envs.empty?
- record[:environment] = :absent
- else
- # Collect all of the environment lines, and mark the records to be skipped,
- # since their data is included in our crontab record.
- record[:environment] = envs
-
- # And turn off env collection again
- envs = nil
- end
- end
- }.reject { |record| record[:skip] }
- result
+ # Yay differing definitions of absent.
+ next if (record[field] == :absent and resource.value(field) == "*")
+
+ # Everything should be in the form of arrays, not the normal text.
+ next if (record[field] == resource.value(field))
+ #Puppet.info "Did not match %s: %s vs %s" %
+ # [field, resource.value(field).inspect, record[field].inspect]
+ matched = false
+ break
+ end
+ return resource if matched
end
- def self.to_file(records)
- text = super
- # Apparently Freebsd will "helpfully" add a new TZ line to every
- # single cron line, but not in all cases (e.g., it doesn't do it
- # on my machine). This is my attempt to fix it so the TZ lines don't
- # multiply.
- if text =~ /(^TZ=.+\n)/
- tz = $1
- text.sub!(tz, '')
- text = tz + text
+ false
+ end
+
+ # Collapse name and env records.
+ def self.prefetch_hook(records)
+ name = nil
+ envs = nil
+ result = records.each { |record|
+ case record[:record_type]
+ when :comment
+ if record[:name]
+ name = record[:name]
+ record[:skip] = true
+
+ # Start collecting env values
+ envs = []
+ end
+ when :environment
+ # If we're collecting env values (meaning we're in a named cronjob),
+ # store the line and skip the record.
+ if envs
+ envs << record[:line]
+ record[:skip] = true
end
- text
+ when :blank
+ # nothing
+ else
+ if name
+ record[:name] = name
+ name = nil
+ end
+ if envs.nil? or envs.empty?
+ record[:environment] = :absent
+ else
+ # Collect all of the environment lines, and mark the records to be skipped,
+ # since their data is included in our crontab record.
+ record[:environment] = envs
+
+ # And turn off env collection again
+ envs = nil
+ end
+ end
+ }.reject { |record| record[:skip] }
+ result
+ end
+
+ def self.to_file(records)
+ text = super
+ # Apparently Freebsd will "helpfully" add a new TZ line to every
+ # single cron line, but not in all cases (e.g., it doesn't do it
+ # on my machine). This is my attempt to fix it so the TZ lines don't
+ # multiply.
+ if text =~ /(^TZ=.+\n)/
+ tz = $1
+ text.sub!(tz, '')
+ text = tz + text
end
+ text
+ end
- def user=(user)
- @property_hash[:user] = user
- @property_hash[:target] = user
- end
+ def user=(user)
+ @property_hash[:user] = user
+ @property_hash[:target] = user
+ end
- def user
- @property_hash[:user] || @property_hash[:target]
- end
+ def user
+ @property_hash[:user] || @property_hash[:target]
+ end
end
diff --git a/lib/puppet/provider/file/posix.rb b/lib/puppet/provider/file/posix.rb
index d715d8802..6cbf98e9a 100644
--- a/lib/puppet/provider/file/posix.rb
+++ b/lib/puppet/provider/file/posix.rb
@@ -1,99 +1,99 @@
Puppet::Type.type(:file).provide :posix do
- desc "Uses POSIX functionality to manage file's users and rights."
+ desc "Uses POSIX functionality to manage file's users and rights."
- confine :feature => :posix
+ confine :feature => :posix
- include Puppet::Util::POSIX
- include Puppet::Util::Warnings
+ include Puppet::Util::POSIX
+ include Puppet::Util::Warnings
- require 'etc'
+ require 'etc'
- def id2name(id)
- return id.to_s if id.is_a?(Symbol)
- return nil if id > Puppet[:maximum_uid].to_i
+ def id2name(id)
+ return id.to_s if id.is_a?(Symbol)
+ return nil if id > Puppet[:maximum_uid].to_i
- begin
- user = Etc.getpwuid(id)
- rescue TypeError
- return nil
- rescue ArgumentError
- return nil
- end
-
- if user.uid == ""
- return nil
- else
- return user.name
- end
+ begin
+ user = Etc.getpwuid(id)
+ rescue TypeError
+ return nil
+ rescue ArgumentError
+ return nil
end
- def insync?(current, should)
- return true unless should
-
- should.each do |value|
- if value =~ /^\d+$/
- uid = Integer(value)
- elsif value.is_a?(String)
- fail "Could not find user #{value}" unless uid = uid(value)
- else
- uid = value
- end
+ if user.uid == ""
+ return nil
+ else
+ return user.name
+ end
+ end
- return true if uid == current
- end
+ def insync?(current, should)
+ return true unless should
- unless Puppet.features.root?
- warnonce "Cannot manage ownership unless running as root"
- return true
- end
+ should.each do |value|
+ if value =~ /^\d+$/
+ uid = Integer(value)
+ elsif value.is_a?(String)
+ fail "Could not find user #{value}" unless uid = uid(value)
+ else
+ uid = value
+ end
- false
+ return true if uid == current
end
- # Determine if the user is valid, and if so, return the UID
- def validuser?(value)
- Integer(value) rescue uid(value) || false
+ unless Puppet.features.root?
+ warnonce "Cannot manage ownership unless running as root"
+ return true
end
- def retrieve(resource)
- unless stat = resource.stat(false)
- return :absent
- end
+ false
+ end
+
+ # Determine if the user is valid, and if so, return the UID
+ def validuser?(value)
+ Integer(value) rescue uid(value) || false
+ end
- currentvalue = stat.uid
+ def retrieve(resource)
+ unless stat = resource.stat(false)
+ return :absent
+ end
- # On OS X, files that are owned by -2 get returned as really
- # large UIDs instead of negative ones. This isn't a Ruby bug,
- # it's an OS X bug, since it shows up in perl, too.
- if currentvalue > Puppet[:maximum_uid].to_i
- self.warning "Apparently using negative UID (#{currentvalue}) on a platform that does not consistently handle them"
- currentvalue = :silly
- end
+ currentvalue = stat.uid
- currentvalue
+ # On OS X, files that are owned by -2 get returned as really
+ # large UIDs instead of negative ones. This isn't a Ruby bug,
+ # it's an OS X bug, since it shows up in perl, too.
+ if currentvalue > Puppet[:maximum_uid].to_i
+ self.warning "Apparently using negative UID (#{currentvalue}) on a platform that does not consistently handle them"
+ currentvalue = :silly
end
- def sync(path, links, should)
- # Set our method appropriately, depending on links.
- if links == :manage
- method = :lchown
- else
- method = :chown
- end
+ currentvalue
+ end
- uid = nil
- should.each do |user|
- break if uid = validuser?(user)
- end
+ def sync(path, links, should)
+ # Set our method appropriately, depending on links.
+ if links == :manage
+ method = :lchown
+ else
+ method = :chown
+ end
- raise Puppet::Error, "Could not find user(s) #{should.join(",")}" unless uid
+ uid = nil
+ should.each do |user|
+ break if uid = validuser?(user)
+ end
- begin
- File.send(method, uid, nil, path)
- rescue => detail
- raise Puppet::Error, "Failed to set owner to '#{uid}': #{detail}"
- end
+ raise Puppet::Error, "Could not find user(s) #{should.join(",")}" unless uid
- :file_changed
+ begin
+ File.send(method, uid, nil, path)
+ rescue => detail
+ raise Puppet::Error, "Failed to set owner to '#{uid}': #{detail}"
end
+
+ :file_changed
+ end
end
diff --git a/lib/puppet/provider/file/win32.rb b/lib/puppet/provider/file/win32.rb
index 93274ce0a..8ead69a89 100644
--- a/lib/puppet/provider/file/win32.rb
+++ b/lib/puppet/provider/file/win32.rb
@@ -1,74 +1,74 @@
Puppet::Type.type(:file).provide :microsoft_windows do
- desc "Uses Microsoft Windows functionality to manage file's users and rights."
+ desc "Uses Microsoft Windows functionality to manage file's users and rights."
- confine :feature => :microsoft_windows
+ confine :feature => :microsoft_windows
- include Puppet::Util::Warnings
+ include Puppet::Util::Warnings
- require 'sys/admin' if Puppet.features.microsoft_windows?
+ require 'sys/admin' if Puppet.features.microsoft_windows?
- def id2name(id)
- return id.to_s if id.is_a?(Symbol)
- return nil if id > Puppet[:maximum_uid].to_i
- # should translate ID numbers to usernames
- id
- end
-
- def insync?(current, should)
- return true unless should
+ def id2name(id)
+ return id.to_s if id.is_a?(Symbol)
+ return nil if id > Puppet[:maximum_uid].to_i
+ # should translate ID numbers to usernames
+ id
+ end
- should.each do |value|
- if value =~ /^\d+$/
- uid = Integer(value)
- elsif value.is_a?(String)
- fail "Could not find user #{value}" unless uid = uid(value)
- else
- uid = value
- end
+ def insync?(current, should)
+ return true unless should
- return true if uid == current
- end
+ should.each do |value|
+ if value =~ /^\d+$/
+ uid = Integer(value)
+ elsif value.is_a?(String)
+ fail "Could not find user #{value}" unless uid = uid(value)
+ else
+ uid = value
+ end
- unless Puppet.features.root?
- warnonce "Cannot manage ownership unless running as root"
- return true
- end
-
- false
+ return true if uid == current
end
- # Determine if the user is valid, and if so, return the UID
- def validuser?(value)
- info "Is '#{value}' a valid user?"
- return 0
- begin
- number = Integer(value)
- return number
- rescue ArgumentError
- number = nil
- end
- (number = uid(value)) && number
+ unless Puppet.features.root?
+ warnonce "Cannot manage ownership unless running as root"
+ return true
end
- def retrieve(resource)
- unless stat = resource.stat(false)
- return :absent
- end
-
- currentvalue = stat.uid
+ false
+ end
- # On OS X, files that are owned by -2 get returned as really
- # large UIDs instead of negative ones. This isn't a Ruby bug,
- # it's an OS X bug, since it shows up in perl, too.
- if currentvalue > Puppet[:maximum_uid].to_i
- self.warning "Apparently using negative UID (#{currentvalue}) on a platform that does not consistently handle them"
- currentvalue = :silly
- end
+ # Determine if the user is valid, and if so, return the UID
+ def validuser?(value)
+ info "Is '#{value}' a valid user?"
+ return 0
+ begin
+ number = Integer(value)
+ return number
+ rescue ArgumentError
+ number = nil
+ end
+ (number = uid(value)) && number
+ end
- currentvalue
+ def retrieve(resource)
+ unless stat = resource.stat(false)
+ return :absent
end
- def sync(path, links, should)
- info("should set '%s'%%owner to '%s'" % [path, should])
+ currentvalue = stat.uid
+
+ # On OS X, files that are owned by -2 get returned as really
+ # large UIDs instead of negative ones. This isn't a Ruby bug,
+ # it's an OS X bug, since it shows up in perl, too.
+ if currentvalue > Puppet[:maximum_uid].to_i
+ self.warning "Apparently using negative UID (#{currentvalue}) on a platform that does not consistently handle them"
+ currentvalue = :silly
end
+
+ currentvalue
+ end
+
+ def sync(path, links, should)
+ info("should set '%s'%%owner to '%s'" % [path, should])
+ end
end
diff --git a/lib/puppet/provider/group/directoryservice.rb b/lib/puppet/provider/group/directoryservice.rb
index d02273476..97fee883d 100644
--- a/lib/puppet/provider/group/directoryservice.rb
+++ b/lib/puppet/provider/group/directoryservice.rb
@@ -15,12 +15,12 @@
require 'puppet/provider/nameservice/directoryservice'
Puppet::Type.type(:group).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do
- desc "Group management using DirectoryService on OS X.
+ desc "Group management using DirectoryService on OS X.
- "
+ "
- commands :dscl => "/usr/bin/dscl"
- confine :operatingsystem => :darwin
- defaultfor :operatingsystem => :darwin
- has_feature :manages_members
+ commands :dscl => "/usr/bin/dscl"
+ confine :operatingsystem => :darwin
+ defaultfor :operatingsystem => :darwin
+ has_feature :manages_members
end
diff --git a/lib/puppet/provider/group/groupadd.rb b/lib/puppet/provider/group/groupadd.rb
index 496db3ceb..e661ddd7f 100644
--- a/lib/puppet/provider/group/groupadd.rb
+++ b/lib/puppet/provider/group/groupadd.rb
@@ -1,29 +1,29 @@
require 'puppet/provider/nameservice/objectadd'
Puppet::Type.type(:group).provide :groupadd, :parent => Puppet::Provider::NameService::ObjectAdd do
- desc "Group management via ``groupadd`` and its ilk.
+ desc "Group management via ``groupadd`` and its ilk.
- The default for most platforms
+ The default for most platforms
- "
+ "
- commands :add => "groupadd", :delete => "groupdel", :modify => "groupmod"
+ commands :add => "groupadd", :delete => "groupdel", :modify => "groupmod"
- verify :gid, "GID must be an integer" do |value|
- value.is_a? Integer
- end
+ verify :gid, "GID must be an integer" do |value|
+ value.is_a? Integer
+ end
- def addcmd
- cmd = [command(:add)]
- if gid = @resource.should(:gid)
- unless gid == :absent
- cmd << flag(:gid) << gid
- end
- end
- cmd << "-o" if @resource.allowdupe?
- cmd << @resource[:name]
-
- cmd
+ def addcmd
+ cmd = [command(:add)]
+ if gid = @resource.should(:gid)
+ unless gid == :absent
+ cmd << flag(:gid) << gid
+ end
end
+ cmd << "-o" if @resource.allowdupe?
+ cmd << @resource[:name]
+
+ cmd
+ end
end
diff --git a/lib/puppet/provider/group/ldap.rb b/lib/puppet/provider/group/ldap.rb
index d0eca0d50..2737feea6 100644
--- a/lib/puppet/provider/group/ldap.rb
+++ b/lib/puppet/provider/group/ldap.rb
@@ -1,47 +1,47 @@
require 'puppet/provider/ldap'
Puppet::Type.type(:group).provide :ldap, :parent => Puppet::Provider::Ldap do
- desc "Group management via ``ldap``.
-
- This provider requires that you have valid values for all of the
- ldap-related settings, including ``ldapbase``. You will also almost
- definitely need settings for ``ldapuser`` and ``ldappassword``, so that
- your clients can write to ldap.
-
- Note that this provider will automatically generate a GID for you if you do
- not specify one, but it is a potentially expensive operation, as it
- iterates across all existing groups to pick the appropriate next one.
-
- "
-
- confine :true => Puppet.features.ldap?, :false => (Puppet[:ldapuser] == "")
-
- # We're mapping 'members' here because we want to make it
- # easy for the ldap user provider to manage groups. This
- # way it can just use the 'update' method in the group manager,
- # whereas otherwise it would need to replicate that code.
- manages(:posixGroup).at("ou=Groups").and.maps :name => :cn, :gid => :gidNumber, :members => :memberUid
-
- # Find the next gid after the current largest gid.
- provider = self
- manager.generates(:gidNumber).with do
- largest = 500
- if existing = provider.manager.search
- existing.each do |hash|
- next unless value = hash[:gid]
- num = value[0].to_i
- largest = num if num > largest
- end
- end
- largest + 1
+ desc "Group management via ``ldap``.
+
+ This provider requires that you have valid values for all of the
+ ldap-related settings, including ``ldapbase``. You will also almost
+ definitely need settings for ``ldapuser`` and ``ldappassword``, so that
+ your clients can write to ldap.
+
+ Note that this provider will automatically generate a GID for you if you do
+ not specify one, but it is a potentially expensive operation, as it
+ iterates across all existing groups to pick the appropriate next one.
+
+ "
+
+ confine :true => Puppet.features.ldap?, :false => (Puppet[:ldapuser] == "")
+
+ # We're mapping 'members' here because we want to make it
+ # easy for the ldap user provider to manage groups. This
+ # way it can just use the 'update' method in the group manager,
+ # whereas otherwise it would need to replicate that code.
+ manages(:posixGroup).at("ou=Groups").and.maps :name => :cn, :gid => :gidNumber, :members => :memberUid
+
+ # Find the next gid after the current largest gid.
+ provider = self
+ manager.generates(:gidNumber).with do
+ largest = 500
+ if existing = provider.manager.search
+ existing.each do |hash|
+ next unless value = hash[:gid]
+ num = value[0].to_i
+ largest = num if num > largest
+ end
end
+ largest + 1
+ end
- # Convert a group name to an id.
- def self.name2id(group)
- return nil unless result = manager.search("cn=#{group}") and result.length > 0
+ # Convert a group name to an id.
+ def self.name2id(group)
+ return nil unless result = manager.search("cn=#{group}") and result.length > 0
- # Only use the first result.
- group = result[0]
- gid = group[:gid][0]
- end
+ # Only use the first result.
+ group = result[0]
+ gid = group[:gid][0]
+ end
end
diff --git a/lib/puppet/provider/group/pw.rb b/lib/puppet/provider/group/pw.rb
index 0f549f2ec..e3dd714ee 100644
--- a/lib/puppet/provider/group/pw.rb
+++ b/lib/puppet/provider/group/pw.rb
@@ -1,34 +1,34 @@
require 'puppet/provider/nameservice/pw'
Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService::PW do
- desc "Group management via ``pw``.
+ desc "Group management via ``pw``.
- Only works on FreeBSD.
+ Only works on FreeBSD.
- "
+ "
- commands :pw => "/usr/sbin/pw"
- defaultfor :operatingsystem => :freebsd
+ commands :pw => "/usr/sbin/pw"
+ defaultfor :operatingsystem => :freebsd
- verify :gid, "GID must be an integer" do |value|
- value.is_a? Integer
- end
+ verify :gid, "GID must be an integer" do |value|
+ value.is_a? Integer
+ end
- def addcmd
- cmd = [command(:pw), "groupadd", @resource[:name]]
- if gid = @resource.should(:gid)
- unless gid == :absent
- cmd << flag(:gid) << gid
- end
- end
-
- # Apparently, contrary to the man page, groupadd does
- # not accept -o.
- #if @parent[:allowdupe] == :true
- # cmd << "-o"
- #end
-
- cmd
+ def addcmd
+ cmd = [command(:pw), "groupadd", @resource[:name]]
+ if gid = @resource.should(:gid)
+ unless gid == :absent
+ cmd << flag(:gid) << gid
+ end
end
+
+ # Apparently, contrary to the man page, groupadd does
+ # not accept -o.
+ #if @parent[:allowdupe] == :true
+ # cmd << "-o"
+ #end
+
+ cmd
+ end
end
diff --git a/lib/puppet/provider/host/parsed.rb b/lib/puppet/provider/host/parsed.rb
index be2f735cd..4f15eff3f 100644
--- a/lib/puppet/provider/host/parsed.rb
+++ b/lib/puppet/provider/host/parsed.rb
@@ -4,70 +4,70 @@ hosts = nil
case Facter.value(:operatingsystem)
when "Solaris"; hosts = "/etc/inet/hosts"
else
- hosts = "/etc/hosts"
+ hosts = "/etc/hosts"
end
- Puppet::Type.type(:host).provide(
- :parsed,
- :parent => Puppet::Provider::ParsedFile,
- :default_target => hosts,
+ Puppet::Type.type(:host).provide(
+ :parsed,
+ :parent => Puppet::Provider::ParsedFile,
+ :default_target => hosts,
- :filetype => :flat
+ :filetype => :flat
) do
- confine :exists => hosts
+ confine :exists => hosts
- text_line :comment, :match => /^#/
- text_line :blank, :match => /^\s*$/
+ text_line :comment, :match => /^#/
+ text_line :blank, :match => /^\s*$/
- record_line :parsed, :fields => %w{ip name host_aliases},
- :optional => %w{host_aliases},
- :rts => true do |line|
- hash = {}
- if line.sub!(/^(\S+)\s+(\S+)\s*/, '')
- hash[:ip] = $1
- hash[:name] = $2
+ record_line :parsed, :fields => %w{ip name host_aliases},
+ :optional => %w{host_aliases},
+ :rts => true do |line|
+ hash = {}
+ if line.sub!(/^(\S+)\s+(\S+)\s*/, '')
+ hash[:ip] = $1
+ hash[:name] = $2
- if line.empty?
- hash[:host_aliases] = []
- else
- line.sub!(/\s*/, '')
- line.sub!(/^([^#]+)\s*/) do |value|
- aliases = $1
- unless aliases =~ /^\s*$/
- hash[:host_aliases] = aliases.split(/\s+/)
- end
+ if line.empty?
+ hash[:host_aliases] = []
+ else
+ line.sub!(/\s*/, '')
+ line.sub!(/^([^#]+)\s*/) do |value|
+ aliases = $1
+ unless aliases =~ /^\s*$/
+ hash[:host_aliases] = aliases.split(/\s+/)
+ end
- ""
- end
- end
- else
- raise Puppet::Error, "Could not match '#{line}'"
+ ""
end
-
- hash[:host_aliases] = [] if hash[:host_aliases] == ""
-
- return hash
+ end
+ else
+ raise Puppet::Error, "Could not match '#{line}'"
end
- # Convert the current object into a host-style string.
- def self.to_line(hash)
- return super unless hash[:record_type] == :parsed
- [:ip, :name].each do |n|
- raise ArgumentError, "#{n} is a required attribute for hosts" unless hash[n] and hash[n] != :absent
- end
+ hash[:host_aliases] = [] if hash[:host_aliases] == ""
- str = "#{hash[:ip]}\t#{hash[:name]}"
+ return hash
+ end
- if hash.include? :host_aliases and !hash[:host_aliases].empty?
- if hash[:host_aliases].is_a? Array
- str += "\t#{hash[:host_aliases].join("\t")}"
- else
- raise ArgumentError, "Host aliases must be specified as an array"
- end
- end
+ # Convert the current object into a host-style string.
+ def self.to_line(hash)
+ return super unless hash[:record_type] == :parsed
+ [:ip, :name].each do |n|
+ raise ArgumentError, "#{n} is a required attribute for hosts" unless hash[n] and hash[n] != :absent
+ end
+
+ str = "#{hash[:ip]}\t#{hash[:name]}"
- str
+ if hash.include? :host_aliases and !hash[:host_aliases].empty?
+ if hash[:host_aliases].is_a? Array
+ str += "\t#{hash[:host_aliases].join("\t")}"
+ else
+ raise ArgumentError, "Host aliases must be specified as an array"
+ end
end
+
+ str
+ end
end
diff --git a/lib/puppet/provider/ldap.rb b/lib/puppet/provider/ldap.rb
index cc5c67fd2..b7d6baa9e 100644
--- a/lib/puppet/provider/ldap.rb
+++ b/lib/puppet/provider/ldap.rb
@@ -2,132 +2,132 @@ require 'puppet/provider'
# The base class for LDAP providers.
class Puppet::Provider::Ldap < Puppet::Provider
- require 'puppet/util/ldap/manager'
-
- class << self
- attr_reader :manager
+ require 'puppet/util/ldap/manager'
+
+ class << self
+ attr_reader :manager
+ end
+
+ # Look up all instances at our location. Yay.
+ def self.instances
+ return [] unless list = manager.search
+
+ list.collect { |entry| new(entry) }
+ end
+
+ # Specify the ldap manager for this provider, which is
+ # used to figure out how we actually interact with ldap.
+ def self.manages(*args)
+ @manager = Puppet::Util::Ldap::Manager.new
+ @manager.manages(*args)
+
+ # Set up our getter/setter methods.
+ mk_resource_methods
+ @manager
+ end
+
+ # Query all of our resources from ldap.
+ def self.prefetch(resources)
+ resources.each do |name, resource|
+ if result = manager.find(name)
+ result[:ensure] = :present
+ resource.provider = new(result)
+ else
+ resource.provider = new(:ensure => :absent)
+ end
end
-
- # Look up all instances at our location. Yay.
- def self.instances
- return [] unless list = manager.search
-
- list.collect { |entry| new(entry) }
+ end
+
+ def manager
+ self.class.manager
+ end
+
+ def create
+ @property_hash[:ensure] = :present
+ self.class.resource_type.validproperties.each do |property|
+ if val = resource.should(property)
+ @property_hash[property] = val
+ end
end
-
- # Specify the ldap manager for this provider, which is
- # used to figure out how we actually interact with ldap.
- def self.manages(*args)
- @manager = Puppet::Util::Ldap::Manager.new
- @manager.manages(*args)
-
- # Set up our getter/setter methods.
- mk_resource_methods
- @manager
+ end
+
+ def delete
+ @property_hash[:ensure] = :absent
+ end
+
+ def exists?
+ @property_hash[:ensure] != :absent
+ end
+
+ # Apply our changes to ldap, yo.
+ def flush
+ # Just call the manager's update() method.
+ @property_hash.delete(:groups)
+ @ldap_properties.delete(:groups)
+ manager.update(name, ldap_properties, properties)
+ @property_hash.clear
+ @ldap_properties.clear
+ end
+
+ def initialize(*args)
+ raise(Puppet::DevError, "No LDAP Configuration defined for #{self.class}") unless self.class.manager
+ raise(Puppet::DevError, "Invalid LDAP Configuration defined for #{self.class}") unless self.class.manager.valid?
+ super
+
+ @property_hash = @property_hash.inject({}) do |result, ary|
+ param, values = ary
+
+ # Skip any attributes we don't manage.
+ next result unless self.class.resource_type.valid_parameter?(param)
+
+ paramclass = self.class.resource_type.attrclass(param)
+
+ unless values.is_a?(Array)
+ result[param] = values
+ next result
+ end
+
+ # Only use the first value if the attribute class doesn't manage
+ # arrays of values.
+ if paramclass.superclass == Puppet::Parameter or paramclass.array_matching == :first
+ result[param] = values[0]
+ else
+ result[param] = values
+ end
+ result
end
- # Query all of our resources from ldap.
- def self.prefetch(resources)
- resources.each do |name, resource|
- if result = manager.find(name)
- result[:ensure] = :present
- resource.provider = new(result)
- else
- resource.provider = new(:ensure => :absent)
- end
- end
+ # Make a duplicate, so that we have a copy for comparison
+ # at the end.
+ @ldap_properties = @property_hash.dup
+ end
+
+ # Return the current state of ldap.
+ def ldap_properties
+ @ldap_properties.dup
+ end
+
+ # Return (and look up if necessary) the desired state.
+ def properties
+ if @property_hash.empty?
+ @property_hash = query || {:ensure => :absent}
+ @property_hash[:ensure] = :absent if @property_hash.empty?
end
-
- def manager
- self.class.manager
+ @property_hash.dup
+ end
+
+ # Collect the current attributes from ldap. Returns
+ # the results, but also stores the attributes locally,
+ # so we have something to compare against when we update.
+ # LAK:NOTE This is normally not used, because we rely on prefetching.
+ def query
+ # Use the module function.
+ unless attributes = manager.find(name)
+ @ldap_properties = {}
+ return nil
end
- def create
- @property_hash[:ensure] = :present
- self.class.resource_type.validproperties.each do |property|
- if val = resource.should(property)
- @property_hash[property] = val
- end
- end
- end
-
- def delete
- @property_hash[:ensure] = :absent
- end
-
- def exists?
- @property_hash[:ensure] != :absent
- end
-
- # Apply our changes to ldap, yo.
- def flush
- # Just call the manager's update() method.
- @property_hash.delete(:groups)
- @ldap_properties.delete(:groups)
- manager.update(name, ldap_properties, properties)
- @property_hash.clear
- @ldap_properties.clear
- end
-
- def initialize(*args)
- raise(Puppet::DevError, "No LDAP Configuration defined for #{self.class}") unless self.class.manager
- raise(Puppet::DevError, "Invalid LDAP Configuration defined for #{self.class}") unless self.class.manager.valid?
- super
-
- @property_hash = @property_hash.inject({}) do |result, ary|
- param, values = ary
-
- # Skip any attributes we don't manage.
- next result unless self.class.resource_type.valid_parameter?(param)
-
- paramclass = self.class.resource_type.attrclass(param)
-
- unless values.is_a?(Array)
- result[param] = values
- next result
- end
-
- # Only use the first value if the attribute class doesn't manage
- # arrays of values.
- if paramclass.superclass == Puppet::Parameter or paramclass.array_matching == :first
- result[param] = values[0]
- else
- result[param] = values
- end
- result
- end
-
- # Make a duplicate, so that we have a copy for comparison
- # at the end.
- @ldap_properties = @property_hash.dup
- end
-
- # Return the current state of ldap.
- def ldap_properties
- @ldap_properties.dup
- end
-
- # Return (and look up if necessary) the desired state.
- def properties
- if @property_hash.empty?
- @property_hash = query || {:ensure => :absent}
- @property_hash[:ensure] = :absent if @property_hash.empty?
- end
- @property_hash.dup
- end
-
- # Collect the current attributes from ldap. Returns
- # the results, but also stores the attributes locally,
- # so we have something to compare against when we update.
- # LAK:NOTE This is normally not used, because we rely on prefetching.
- def query
- # Use the module function.
- unless attributes = manager.find(name)
- @ldap_properties = {}
- return nil
- end
-
- @ldap_properties = attributes
- @ldap_properties.dup
- end
+ @ldap_properties = attributes
+ @ldap_properties.dup
+ end
end
diff --git a/lib/puppet/provider/macauthorization/macauthorization.rb b/lib/puppet/provider/macauthorization/macauthorization.rb
index 4c55d7280..fdf9fd18c 100644
--- a/lib/puppet/provider/macauthorization/macauthorization.rb
+++ b/lib/puppet/provider/macauthorization/macauthorization.rb
@@ -5,309 +5,309 @@ require 'tempfile'
Puppet::Type.type(:macauthorization).provide :macauthorization, :parent => Puppet::Provider do
- desc "Manage Mac OS X authorization database rules and rights.
+ desc "Manage Mac OS X authorization database rules and rights.
- "
+ "
- commands :security => "/usr/bin/security"
- commands :sw_vers => "/usr/bin/sw_vers"
+ commands :security => "/usr/bin/security"
+ commands :sw_vers => "/usr/bin/sw_vers"
- confine :operatingsystem => :darwin
+ confine :operatingsystem => :darwin
- # This should be confined based on macosx_productversion once
- # http://projects.reductivelabs.com/issues/show/1796
- # is resolved.
- if FileTest.exists?("/usr/bin/sw_vers")
- product_version = sw_vers "-productVersion"
+ # This should be confined based on macosx_productversion once
+ # http://projects.reductivelabs.com/issues/show/1796
+ # is resolved.
+ if FileTest.exists?("/usr/bin/sw_vers")
+ product_version = sw_vers "-productVersion"
- confine :true => if /^10.5/.match(product_version) or /^10.6/.match(product_version)
- true
- end
+ confine :true => if /^10.5/.match(product_version) or /^10.6/.match(product_version)
+ true
end
+ end
- defaultfor :operatingsystem => :darwin
-
- AuthDB = "/etc/authorization"
-
- @rights = {}
- @rules = {}
- @parsed_auth_db = {}
- @comment = "" # Not implemented yet. Is there any real need to?
-
- # This map exists due to the use of hyphens and reserved words in
- # the authorization schema.
- PuppetToNativeAttributeMap = { :allow_root => "allow-root",
- :authenticate_user => "authenticate-user",
- :auth_class => "class",
- :k_of_n => "k-of-n",
- :session_owner => "session-owner", }
-
- class << self
- attr_accessor :parsed_auth_db
- attr_accessor :rights
- attr_accessor :rules
- attr_accessor :comments # Not implemented yet.
-
- def prefetch(resources)
- self.populate_rules_rights
- end
-
- def instances
- if self.parsed_auth_db == {}
- self.prefetch(nil)
- end
- self.parsed_auth_db.collect do |k,v|
- new(:name => k)
- end
- end
-
- def populate_rules_rights
- auth_plist = Plist::parse_xml(AuthDB)
- raise Puppet::Error.new("Cannot parse: #{AuthDB}") if not auth_plist
- self.rights = auth_plist["rights"].dup
- self.rules = auth_plist["rules"].dup
- self.parsed_auth_db = self.rights.dup
- self.parsed_auth_db.merge!(self.rules.dup)
- end
+ defaultfor :operatingsystem => :darwin
- end
+ AuthDB = "/etc/authorization"
- # standard required provider instance methods
+ @rights = {}
+ @rules = {}
+ @parsed_auth_db = {}
+ @comment = "" # Not implemented yet. Is there any real need to?
- def initialize(resource)
- if self.class.parsed_auth_db == {}
- self.class.prefetch(resource)
- end
- super
- end
+ # This map exists due to the use of hyphens and reserved words in
+ # the authorization schema.
+ PuppetToNativeAttributeMap = { :allow_root => "allow-root",
+ :authenticate_user => "authenticate-user",
+ :auth_class => "class",
+ :k_of_n => "k-of-n",
+ :session_owner => "session-owner", }
+ class << self
+ attr_accessor :parsed_auth_db
+ attr_accessor :rights
+ attr_accessor :rules
+ attr_accessor :comments # Not implemented yet.
- def create
- # we just fill the @property_hash in here and let the flush method
- # deal with it rather than repeating code.
- new_values = {}
- validprops = Puppet::Type.type(resource.class.name).validproperties
- validprops.each do |prop|
- next if prop == :ensure
- if value = resource.should(prop) and value != ""
- new_values[prop] = value
- end
- end
- @property_hash = new_values.dup
+ def prefetch(resources)
+ self.populate_rules_rights
end
- def destroy
- # We explicitly delete here rather than in the flush method.
- case resource[:auth_type]
- when :right
- destroy_right
- when :rule
- destroy_rule
- else
- raise Puppet::Error.new("Must specify auth_type when destroying.")
- end
+ def instances
+ if self.parsed_auth_db == {}
+ self.prefetch(nil)
+ end
+ self.parsed_auth_db.collect do |k,v|
+ new(:name => k)
+ end
end
- def exists?
- !!self.class.parsed_auth_db.has_key?(resource[:name])
+ def populate_rules_rights
+ auth_plist = Plist::parse_xml(AuthDB)
+ raise Puppet::Error.new("Cannot parse: #{AuthDB}") if not auth_plist
+ self.rights = auth_plist["rights"].dup
+ self.rules = auth_plist["rules"].dup
+ self.parsed_auth_db = self.rights.dup
+ self.parsed_auth_db.merge!(self.rules.dup)
end
+ end
- def flush
- # deletion happens in the destroy methods
- if resource[:ensure] != :absent
- case resource[:auth_type]
- when :right
- flush_right
- when :rule
- flush_rule
- else
- raise Puppet::Error.new("flush requested for unknown type.")
- end
- @property_hash.clear
- end
+ # standard required provider instance methods
+
+ def initialize(resource)
+ if self.class.parsed_auth_db == {}
+ self.class.prefetch(resource)
+ end
+ super
+ end
+
+
+ def create
+ # we just fill the @property_hash in here and let the flush method
+ # deal with it rather than repeating code.
+ new_values = {}
+ validprops = Puppet::Type.type(resource.class.name).validproperties
+ validprops.each do |prop|
+ next if prop == :ensure
+ if value = resource.should(prop) and value != ""
+ new_values[prop] = value
+ end
end
+ @property_hash = new_values.dup
+ end
+
+ def destroy
+ # We explicitly delete here rather than in the flush method.
+ case resource[:auth_type]
+ when :right
+ destroy_right
+ when :rule
+ destroy_rule
+ else
+ raise Puppet::Error.new("Must specify auth_type when destroying.")
+ end
+ end
+
+ def exists?
+ !!self.class.parsed_auth_db.has_key?(resource[:name])
+ end
+
+
+ def flush
+ # deletion happens in the destroy methods
+ if resource[:ensure] != :absent
+ case resource[:auth_type]
+ when :right
+ flush_right
+ when :rule
+ flush_rule
+ else
+ raise Puppet::Error.new("flush requested for unknown type.")
+ end
+ @property_hash.clear
+ end
+ end
- # utility methods below
+ # utility methods below
- def destroy_right
- security "authorizationdb", :remove, resource[:name]
- end
+ def destroy_right
+ security "authorizationdb", :remove, resource[:name]
+ end
- def destroy_rule
- authdb = Plist::parse_xml(AuthDB)
- authdb_rules = authdb["rules"].dup
- if authdb_rules[resource[:name]]
- begin
- authdb["rules"].delete(resource[:name])
- Plist::Emit.save_plist(authdb, AuthDB)
- rescue Errno::EACCES => e
- raise Puppet::Error.new("Error saving #{AuthDB}: #{e}")
- end
- end
+ def destroy_rule
+ authdb = Plist::parse_xml(AuthDB)
+ authdb_rules = authdb["rules"].dup
+ if authdb_rules[resource[:name]]
+ begin
+ authdb["rules"].delete(resource[:name])
+ Plist::Emit.save_plist(authdb, AuthDB)
+ rescue Errno::EACCES => e
+ raise Puppet::Error.new("Error saving #{AuthDB}: #{e}")
+ end
end
-
- def flush_right
- # first we re-read the right just to make sure we're in sync for
- # values that weren't specified in the manifest. As we're supplying
- # the whole plist when specifying the right it seems safest to be
- # paranoid given the low cost of quering the db once more.
- cmds = []
- cmds << :security << "authorizationdb" << "read" << resource[:name]
- output = execute(cmds, :combine => false)
- current_values = Plist::parse_xml(output)
- current_values ||= {}
- specified_values = convert_plist_to_native_attributes(@property_hash)
-
- # take the current values, merge the specified values to obtain a
- # complete description of the new values.
- new_values = current_values.merge(specified_values)
- set_right(resource[:name], new_values)
+ end
+
+ def flush_right
+ # first we re-read the right just to make sure we're in sync for
+ # values that weren't specified in the manifest. As we're supplying
+ # the whole plist when specifying the right it seems safest to be
+ # paranoid given the low cost of quering the db once more.
+ cmds = []
+ cmds << :security << "authorizationdb" << "read" << resource[:name]
+ output = execute(cmds, :combine => false)
+ current_values = Plist::parse_xml(output)
+ current_values ||= {}
+ specified_values = convert_plist_to_native_attributes(@property_hash)
+
+ # take the current values, merge the specified values to obtain a
+ # complete description of the new values.
+ new_values = current_values.merge(specified_values)
+ set_right(resource[:name], new_values)
+ end
+
+ def flush_rule
+ authdb = Plist::parse_xml(AuthDB)
+ authdb_rules = authdb["rules"].dup
+ current_values = {}
+ current_values = authdb_rules[resource[:name]] if authdb_rules[resource[:name]]
+ specified_values = convert_plist_to_native_attributes(@property_hash)
+ new_values = current_values.merge(specified_values)
+ set_rule(resource[:name], new_values)
+ end
+
+ def set_right(name, values)
+ # Both creates and modifies rights as it simply overwrites them.
+ # The security binary only allows for writes using stdin, so we
+ # dump the values to a tempfile.
+ values = convert_plist_to_native_attributes(values)
+ tmp = Tempfile.new('puppet_macauthorization')
+ begin
+ Plist::Emit.save_plist(values, tmp.path)
+ cmds = []
+ cmds << :security << "authorizationdb" << "write" << name
+
+ output = execute(
+ cmds, :combine => false,
+
+ :stdinfile => tmp.path.to_s)
+ rescue Errno::EACCES => e
+ raise Puppet::Error.new("Cannot save right to #{tmp.path}: #{e}")
+ ensure
+ tmp.close
+ tmp.unlink
end
-
- def flush_rule
- authdb = Plist::parse_xml(AuthDB)
- authdb_rules = authdb["rules"].dup
- current_values = {}
- current_values = authdb_rules[resource[:name]] if authdb_rules[resource[:name]]
- specified_values = convert_plist_to_native_attributes(@property_hash)
- new_values = current_values.merge(specified_values)
- set_rule(resource[:name], new_values)
+ end
+
+ def set_rule(name, values)
+ # Both creates and modifies rules as it overwrites the entry in the
+ # rules dictionary. Unfortunately the security binary doesn't
+ # support modifying rules at all so we have to twiddle the whole
+ # plist... :( See Apple Bug #6386000
+ values = convert_plist_to_native_attributes(values)
+ authdb = Plist::parse_xml(AuthDB)
+ authdb["rules"][name] = values
+
+ begin
+ Plist::Emit.save_plist(authdb, AuthDB)
+ rescue
+ raise Puppet::Error.new("Error writing to: #{AuthDB}")
end
-
- def set_right(name, values)
- # Both creates and modifies rights as it simply overwrites them.
- # The security binary only allows for writes using stdin, so we
- # dump the values to a tempfile.
- values = convert_plist_to_native_attributes(values)
- tmp = Tempfile.new('puppet_macauthorization')
- begin
- Plist::Emit.save_plist(values, tmp.path)
- cmds = []
- cmds << :security << "authorizationdb" << "write" << name
-
- output = execute(
- cmds, :combine => false,
-
- :stdinfile => tmp.path.to_s)
- rescue Errno::EACCES => e
- raise Puppet::Error.new("Cannot save right to #{tmp.path}: #{e}")
- ensure
- tmp.close
- tmp.unlink
- end
+ end
+
+ def convert_plist_to_native_attributes(propertylist)
+ # This mainly converts the keys from the puppet attributes to the
+ # 'native' ones, but also enforces that the keys are all Strings
+ # rather than Symbols so that any merges of the resultant Hash are
+ # sane. The exception is booleans, where we coerce to a proper bool
+ # if they come in as a symbol.
+ newplist = {}
+ propertylist.each_pair do |key, value|
+ next if key == :ensure # not part of the auth db schema.
+ next if key == :auth_type # not part of the auth db schema.
+ case value
+ when true, :true
+ value = true
+ when false, :false
+ value = false
+ end
+ new_key = key
+ if PuppetToNativeAttributeMap.has_key?(key)
+ new_key = PuppetToNativeAttributeMap[key].to_s
+ elsif not key.is_a?(String)
+ new_key = key.to_s
+ end
+ newplist[new_key] = value
end
+ newplist
+ end
- def set_rule(name, values)
- # Both creates and modifies rules as it overwrites the entry in the
- # rules dictionary. Unfortunately the security binary doesn't
- # support modifying rules at all so we have to twiddle the whole
- # plist... :( See Apple Bug #6386000
- values = convert_plist_to_native_attributes(values)
- authdb = Plist::parse_xml(AuthDB)
- authdb["rules"][name] = values
-
- begin
- Plist::Emit.save_plist(authdb, AuthDB)
- rescue
- raise Puppet::Error.new("Error writing to: #{AuthDB}")
- end
- end
+ def retrieve_value(resource_name, attribute)
+ # We set boolean values to symbols when retrieving values
+ raise Puppet::Error.new("Cannot find #{resource_name} in auth db") if not self.class.parsed_auth_db.has_key?(resource_name)
- def convert_plist_to_native_attributes(propertylist)
- # This mainly converts the keys from the puppet attributes to the
- # 'native' ones, but also enforces that the keys are all Strings
- # rather than Symbols so that any merges of the resultant Hash are
- # sane. The exception is booleans, where we coerce to a proper bool
- # if they come in as a symbol.
- newplist = {}
- propertylist.each_pair do |key, value|
- next if key == :ensure # not part of the auth db schema.
- next if key == :auth_type # not part of the auth db schema.
- case value
- when true, :true
- value = true
- when false, :false
- value = false
- end
- new_key = key
- if PuppetToNativeAttributeMap.has_key?(key)
- new_key = PuppetToNativeAttributeMap[key].to_s
- elsif not key.is_a?(String)
- new_key = key.to_s
- end
- newplist[new_key] = value
- end
- newplist
+ if PuppetToNativeAttributeMap.has_key?(attribute)
+ native_attribute = PuppetToNativeAttributeMap[attribute]
+ else
+ native_attribute = attribute.to_s
end
- def retrieve_value(resource_name, attribute)
- # We set boolean values to symbols when retrieving values
- raise Puppet::Error.new("Cannot find #{resource_name} in auth db") if not self.class.parsed_auth_db.has_key?(resource_name)
-
- if PuppetToNativeAttributeMap.has_key?(attribute)
- native_attribute = PuppetToNativeAttributeMap[attribute]
- else
- native_attribute = attribute.to_s
- end
-
- if self.class.parsed_auth_db[resource_name].has_key?(native_attribute)
- value = self.class.parsed_auth_db[resource_name][native_attribute]
- case value
- when true, :true
- value = :true
- when false, :false
- value = :false
- end
-
- @property_hash[attribute] = value
- return value
- else
- @property_hash.delete(attribute)
- return "" # so ralsh doesn't display it.
- end
+ if self.class.parsed_auth_db[resource_name].has_key?(native_attribute)
+ value = self.class.parsed_auth_db[resource_name][native_attribute]
+ case value
+ when true, :true
+ value = :true
+ when false, :false
+ value = :false
+ end
+
+ @property_hash[attribute] = value
+ return value
+ else
+ @property_hash.delete(attribute)
+ return "" # so ralsh doesn't display it.
end
+ end
- # property methods below
- #
- # We define them all dynamically apart from auth_type which is a special
- # case due to not being in the actual authorization db schema.
+ # property methods below
+ #
+ # We define them all dynamically apart from auth_type which is a special
+ # case due to not being in the actual authorization db schema.
- properties = [ :allow_root, :authenticate_user, :auth_class, :comment,
- :group, :k_of_n, :mechanisms, :rule, :session_owner,
- :shared, :timeout, :tries ]
+ properties = [ :allow_root, :authenticate_user, :auth_class, :comment,
+ :group, :k_of_n, :mechanisms, :rule, :session_owner,
+ :shared, :timeout, :tries ]
- properties.each do |field|
- define_method(field.to_s) do
- retrieve_value(resource[:name], field)
- end
-
- define_method(field.to_s + "=") do |value|
- @property_hash[field] = value
- end
+ properties.each do |field|
+ define_method(field.to_s) do
+ retrieve_value(resource[:name], field)
end
- def auth_type
- if resource.should(:auth_type) != nil
- return resource.should(:auth_type)
- elsif self.exists?
- # this is here just for ralsh, so it can work out what type it is.
- if self.class.rights.has_key?(resource[:name])
- return :right
- elsif self.class.rules.has_key?(resource[:name])
- return :rule
- else
- raise Puppet::Error.new("#{resource[:name]} is unknown type.")
- end
- else
- raise Puppet::Error.new("auth_type required for new resources.")
- end
+ define_method(field.to_s + "=") do |value|
+ @property_hash[field] = value
end
-
- def auth_type=(value)
- @property_hash[:auth_type] = value
+ end
+
+ def auth_type
+ if resource.should(:auth_type) != nil
+ return resource.should(:auth_type)
+ elsif self.exists?
+ # this is here just for ralsh, so it can work out what type it is.
+ if self.class.rights.has_key?(resource[:name])
+ return :right
+ elsif self.class.rules.has_key?(resource[:name])
+ return :rule
+ else
+ raise Puppet::Error.new("#{resource[:name]} is unknown type.")
+ end
+ else
+ raise Puppet::Error.new("auth_type required for new resources.")
end
+ end
+
+ def auth_type=(value)
+ @property_hash[:auth_type] = value
+ end
end
diff --git a/lib/puppet/provider/mailalias/aliases.rb b/lib/puppet/provider/mailalias/aliases.rb
index 388fd631c..35c2f98fe 100755
--- a/lib/puppet/provider/mailalias/aliases.rb
+++ b/lib/puppet/provider/mailalias/aliases.rb
@@ -1,44 +1,44 @@
require 'puppet/provider/parsedfile'
- Puppet::Type.type(:mailalias).provide(
- :aliases,
- :parent => Puppet::Provider::ParsedFile,
- :default_target => "/etc/aliases",
+ Puppet::Type.type(:mailalias).provide(
+ :aliases,
+ :parent => Puppet::Provider::ParsedFile,
+ :default_target => "/etc/aliases",
- :filetype => :flat
+ :filetype => :flat
) do
- text_line :comment, :match => /^#/
- text_line :blank, :match => /^\s*$/
+ text_line :comment, :match => /^#/
+ text_line :blank, :match => /^\s*$/
- record_line :aliases, :fields => %w{name recipient}, :separator => /\s*:\s*/, :block_eval => :instance do
- def post_parse(record)
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- # It's not sufficient to assign to an existing hash.
- recipient = record[:recipient].split(/\s*,\s*/).collect { |d| d.gsub(/^['"]|['"]$/, '') }
- record[:recipient] = recipient
- record
- end
+ record_line :aliases, :fields => %w{name recipient}, :separator => /\s*:\s*/, :block_eval => :instance do
+ def post_parse(record)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ # It's not sufficient to assign to an existing hash.
+ recipient = record[:recipient].split(/\s*,\s*/).collect { |d| d.gsub(/^['"]|['"]$/, '') }
+ record[:recipient] = recipient
+ record
+ end
- def process(line)
- ret = {}
- records = line.split(':',2)
- ret[:name] = records[0].strip
- ret[:recipient] = records[1].strip
- ret
- end
+ def process(line)
+ ret = {}
+ records = line.split(':',2)
+ ret[:name] = records[0].strip
+ ret[:recipient] = records[1].strip
+ ret
+ end
- def to_line(record)
- dest = record[:recipient].collect do |d|
- # Quote aliases that have non-alpha chars
- if d =~ /[^-\w@.]/
- '"%s"' % d
- else
- d
- end
- end.join(",")
- "#{record[:name]}: #{dest}"
+ def to_line(record)
+ dest = record[:recipient].collect do |d|
+ # Quote aliases that have non-alpha chars
+ if d =~ /[^-\w@.]/
+ '"%s"' % d
+ else
+ d
end
+ end.join(",")
+ "#{record[:name]}: #{dest}"
end
+ end
end
diff --git a/lib/puppet/provider/maillist/mailman.rb b/lib/puppet/provider/maillist/mailman.rb
index cfb788b31..4fdc20a69 100755
--- a/lib/puppet/provider/maillist/mailman.rb
+++ b/lib/puppet/provider/maillist/mailman.rb
@@ -1,110 +1,110 @@
require 'puppet/provider/parsedfile'
Puppet::Type.type(:maillist).provide(:mailman) do
- if [ "CentOS", "RedHat", "Fedora" ].any? { |os| Facter.value(:operatingsystem) == os }
- commands :list_lists => "/usr/lib/mailman/bin/list_lists", :rmlist => "/usr/lib/mailman/bin/rmlist", :newlist => "/usr/lib/mailman/bin/newlist"
- commands :mailman => "/usr/lib/mailman/mail/mailman"
- else
- # This probably won't work for non-Debian installs, but this path is sure not to be in the PATH.
- commands :list_lists => "list_lists", :rmlist => "rmlist", :newlist => "newlist"
- commands :mailman => "/var/lib/mailman/mail/mailman"
- end
+ if [ "CentOS", "RedHat", "Fedora" ].any? { |os| Facter.value(:operatingsystem) == os }
+ commands :list_lists => "/usr/lib/mailman/bin/list_lists", :rmlist => "/usr/lib/mailman/bin/rmlist", :newlist => "/usr/lib/mailman/bin/newlist"
+ commands :mailman => "/usr/lib/mailman/mail/mailman"
+ else
+ # This probably won't work for non-Debian installs, but this path is sure not to be in the PATH.
+ commands :list_lists => "list_lists", :rmlist => "rmlist", :newlist => "newlist"
+ commands :mailman => "/var/lib/mailman/mail/mailman"
+ end
- mk_resource_methods
+ mk_resource_methods
- # Return a list of existing mailman instances.
- def self.instances
- list_lists.split("\n").reject { |line| line.include?("matching mailing lists") }.collect do |line|
- name, description = line.sub(/^\s+/, '').sub(/\s+$/, '').split(/\s+-\s+/)
- description = :absent if description.include?("no description available")
- new(:ensure => :present, :name => name, :description => description)
- end
+ # Return a list of existing mailman instances.
+ def self.instances
+ list_lists.split("\n").reject { |line| line.include?("matching mailing lists") }.collect do |line|
+ name, description = line.sub(/^\s+/, '').sub(/\s+$/, '').split(/\s+-\s+/)
+ description = :absent if description.include?("no description available")
+ new(:ensure => :present, :name => name, :description => description)
end
+ end
- # Prefetch our list list, yo.
- def self.prefetch(lists)
- instances.each do |prov|
- if list = lists[prov.name] || lists[prov.name.downcase]
- list.provider = prov
- end
- end
+ # Prefetch our list list, yo.
+ def self.prefetch(lists)
+ instances.each do |prov|
+ if list = lists[prov.name] || lists[prov.name.downcase]
+ list.provider = prov
+ end
end
+ end
- def aliases
- mailman = self.class.command(:mailman)
- name = self.name.downcase
- aliases = {name => "| #{mailman} post #{name}"}
- %w{admin bounces confirm join leave owner request subscribe unsubscribe}.each do |address|
- aliases["#{name}-#{address}"] = "| #{mailman} #{address} #{name}"
- end
- aliases
+ def aliases
+ mailman = self.class.command(:mailman)
+ name = self.name.downcase
+ aliases = {name => "| #{mailman} post #{name}"}
+ %w{admin bounces confirm join leave owner request subscribe unsubscribe}.each do |address|
+ aliases["#{name}-#{address}"] = "| #{mailman} #{address} #{name}"
end
+ aliases
+ end
- # Create the list.
- def create
- args = []
- if val = @resource[:mailserver]
- args << "--emailhost" << val
- end
- if val = @resource[:webserver]
- args << "--urlhost" << val
- end
-
- args << self.name
- if val = @resource[:admin]
- args << val
- else
- raise ArgumentError, "Mailman lists require an administrator email address"
- end
- if val = @resource[:password]
- args << val
- else
- raise ArgumentError, "Mailman lists require an administrator password"
- end
- newlist(*args)
+ # Create the list.
+ def create
+ args = []
+ if val = @resource[:mailserver]
+ args << "--emailhost" << val
end
-
- # Delete the list.
- def destroy(purge = false)
- args = []
- args << "--archives" if purge
- args << self.name
- rmlist(*args)
+ if val = @resource[:webserver]
+ args << "--urlhost" << val
end
- # Does our list exist already?
- def exists?
- properties[:ensure] != :absent
+ args << self.name
+ if val = @resource[:admin]
+ args << val
+ else
+ raise ArgumentError, "Mailman lists require an administrator email address"
end
-
- # Clear out the cached values.
- def flush
- @property_hash.clear
+ if val = @resource[:password]
+ args << val
+ else
+ raise ArgumentError, "Mailman lists require an administrator password"
end
+ newlist(*args)
+ end
- # Look up the current status.
- def properties
- if @property_hash.empty?
- @property_hash = query || {:ensure => :absent}
- @property_hash[:ensure] = :absent if @property_hash.empty?
- end
- @property_hash.dup
- end
+ # Delete the list.
+ def destroy(purge = false)
+ args = []
+ args << "--archives" if purge
+ args << self.name
+ rmlist(*args)
+ end
+
+ # Does our list exist already?
+ def exists?
+ properties[:ensure] != :absent
+ end
- # Remove the list and its archives.
- def purge
- destroy(true)
+ # Clear out the cached values.
+ def flush
+ @property_hash.clear
+ end
+
+ # Look up the current status.
+ def properties
+ if @property_hash.empty?
+ @property_hash = query || {:ensure => :absent}
+ @property_hash[:ensure] = :absent if @property_hash.empty?
end
+ @property_hash.dup
+ end
+
+ # Remove the list and its archives.
+ def purge
+ destroy(true)
+ end
- # Pull the current state of the list from the full list. We're
- # getting some double entendre here....
- def query
- self.class.instances.each do |list|
- if list.name == self.name or list.name.downcase == self.name
- return list.properties
- end
- end
- nil
+ # Pull the current state of the list from the full list. We're
+ # getting some double entendre here....
+ def query
+ self.class.instances.each do |list|
+ if list.name == self.name or list.name.downcase == self.name
+ return list.properties
+ end
end
+ nil
+ end
end
diff --git a/lib/puppet/provider/mcx/mcxcontent.rb b/lib/puppet/provider/mcx/mcxcontent.rb
index ba9ca31dd..cb5adc698 100644
--- a/lib/puppet/provider/mcx/mcxcontent.rb
+++ b/lib/puppet/provider/mcx/mcxcontent.rb
@@ -21,185 +21,185 @@ require 'tempfile'
Puppet::Type.type(:mcx).provide :mcxcontent, :parent => Puppet::Provider do
- desc "MCX Settings management using DirectoryService on OS X.
+ desc "MCX Settings management using DirectoryService on OS X.
- This provider manages the entire MCXSettings attribute available
- to some directory services nodes. This management is 'all or nothing'
- in that discrete application domain key value pairs are not managed
- by this provider.
+ This provider manages the entire MCXSettings attribute available
+ to some directory services nodes. This management is 'all or nothing'
+ in that discrete application domain key value pairs are not managed
+ by this provider.
- It is recommended to use WorkGroup Manager to configure Users, Groups,
- Computers, or ComputerLists, then use 'ralsh mcx' to generate a puppet
- manifest from the resulting configuration.
+ It is recommended to use WorkGroup Manager to configure Users, Groups,
+ Computers, or ComputerLists, then use 'ralsh mcx' to generate a puppet
+ manifest from the resulting configuration.
- Original Author: Jeff McCune (mccune.jeff@gmail.com)
+ Original Author: Jeff McCune (mccune.jeff@gmail.com)
"
- # This provides a mapping of puppet types to DirectoryService
- # type strings.
- TypeMap = {
- :user => "Users",
- :group => "Groups",
- :computer => "Computers",
- :computerlist => "ComputerLists",
- }
-
- class MCXContentProviderException < Exception
-
- end
-
- commands :dscl => "/usr/bin/dscl"
- confine :operatingsystem => :darwin
- defaultfor :operatingsystem => :darwin
-
- # self.instances is all important.
- # This is the only class method, it returns
- # an array of instances of this class.
- def self.instances
- mcx_list = []
- for ds_type in TypeMap.keys
- ds_path = "/Local/Default/#{TypeMap[ds_type]}"
- output = dscl 'localhost', '-list', ds_path
- member_list = output.split
- for ds_name in member_list
- content = mcxexport(ds_type, ds_name)
- if content.empty?
- Puppet.debug "/#{TypeMap[ds_type]}/#{ds_name} has no MCX data."
- else
- # This node has MCX data.
-
- rsrc = self.new(
- :name => "/#{TypeMap[ds_type]}/#{ds_name}",
- :ds_type => ds_type,
- :ds_name => ds_name,
-
- :content => content)
- mcx_list << rsrc
- end
- end
+ # This provides a mapping of puppet types to DirectoryService
+ # type strings.
+ TypeMap = {
+ :user => "Users",
+ :group => "Groups",
+ :computer => "Computers",
+ :computerlist => "ComputerLists",
+ }
+
+ class MCXContentProviderException < Exception
+
+ end
+
+ commands :dscl => "/usr/bin/dscl"
+ confine :operatingsystem => :darwin
+ defaultfor :operatingsystem => :darwin
+
+ # self.instances is all important.
+ # This is the only class method, it returns
+ # an array of instances of this class.
+ def self.instances
+ mcx_list = []
+ for ds_type in TypeMap.keys
+ ds_path = "/Local/Default/#{TypeMap[ds_type]}"
+ output = dscl 'localhost', '-list', ds_path
+ member_list = output.split
+ for ds_name in member_list
+ content = mcxexport(ds_type, ds_name)
+ if content.empty?
+ Puppet.debug "/#{TypeMap[ds_type]}/#{ds_name} has no MCX data."
+ else
+ # This node has MCX data.
+
+ rsrc = self.new(
+ :name => "/#{TypeMap[ds_type]}/#{ds_name}",
+ :ds_type => ds_type,
+ :ds_name => ds_name,
+
+ :content => content)
+ mcx_list << rsrc
end
- mcx_list
+ end
end
-
- private
-
- # mcxexport is used by instances, and therefore
- # a class method.
- def self.mcxexport(ds_type, ds_name)
- ds_t = TypeMap[ds_type]
- ds_n = ds_name.to_s
- ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
- dscl 'localhost', '-mcxexport', ds_path
+ mcx_list
+ end
+
+ private
+
+ # mcxexport is used by instances, and therefore
+ # a class method.
+ def self.mcxexport(ds_type, ds_name)
+ ds_t = TypeMap[ds_type]
+ ds_n = ds_name.to_s
+ ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
+ dscl 'localhost', '-mcxexport', ds_path
+ end
+
+ def mcximport(ds_type, ds_name, val)
+ ds_t = TypeMap[ds_type]
+ ds_n = ds_name.to_s
+ ds_path = "/Local/Default/#{ds_t}/#{ds_name}"
+
+ tmp = Tempfile.new('puppet_mcx')
+ begin
+ tmp << val
+ tmp.flush
+ dscl 'localhost', '-mcximport', ds_path, tmp.path
+ ensure
+ tmp.close
+ tmp.unlink
end
-
- def mcximport(ds_type, ds_name, val)
- ds_t = TypeMap[ds_type]
- ds_n = ds_name.to_s
- ds_path = "/Local/Default/#{ds_t}/#{ds_name}"
-
- tmp = Tempfile.new('puppet_mcx')
- begin
- tmp << val
- tmp.flush
- dscl 'localhost', '-mcximport', ds_path, tmp.path
- ensure
- tmp.close
- tmp.unlink
- end
+ end
+
+ # Given the resource name string, parse ds_type out.
+ def parse_type(name)
+ tmp = name.split('/')[1]
+ if ! tmp.is_a? String
+ raise MCXContentProviderException,
+ "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter."
end
-
- # Given the resource name string, parse ds_type out.
- def parse_type(name)
- tmp = name.split('/')[1]
- if ! tmp.is_a? String
- raise MCXContentProviderException,
- "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter."
- end
- # De-pluralize and downcase.
- tmp = tmp.chop.downcase.to_sym
- if not TypeMap.keys.member? tmp
- raise MCXContentProviderException,
- "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter."
- end
- tmp
+ # De-pluralize and downcase.
+ tmp = tmp.chop.downcase.to_sym
+ if not TypeMap.keys.member? tmp
+ raise MCXContentProviderException,
+ "Coult not parse ds_type from resource name '#{name}'. Specify with ds_type parameter."
end
-
- # Given the resource name string, parse ds_name out.
- def parse_name(name)
- ds_name = name.split('/')[2]
- if ! ds_name.is_a? String
- raise MCXContentProviderException,
- "Could not parse ds_name from resource name '#{name}'. Specify with ds_name parameter."
- end
- ds_name
+ tmp
+ end
+
+ # Given the resource name string, parse ds_name out.
+ def parse_name(name)
+ ds_name = name.split('/')[2]
+ if ! ds_name.is_a? String
+ raise MCXContentProviderException,
+ "Could not parse ds_name from resource name '#{name}'. Specify with ds_name parameter."
end
+ ds_name
+ end
+
+ # Gather ds_type and ds_name from resource or
+ # parse it out of the name.
+ # This is a private instance method, not a class method.
+ def get_dsparams
+ ds_type = resource[:ds_type]
+ ds_type ||= parse_type(resource[:name])
+ raise MCXContentProviderException unless TypeMap.keys.include? ds_type.to_sym
+
+ ds_name = resource[:ds_name]
+ ds_name ||= parse_name(resource[:name])
+
+ rval = {
+ :ds_type => ds_type.to_sym,
+ :ds_name => ds_name,
+ }
- # Gather ds_type and ds_name from resource or
- # parse it out of the name.
- # This is a private instance method, not a class method.
- def get_dsparams
- ds_type = resource[:ds_type]
- ds_type ||= parse_type(resource[:name])
- raise MCXContentProviderException unless TypeMap.keys.include? ds_type.to_sym
-
- ds_name = resource[:ds_name]
- ds_name ||= parse_name(resource[:name])
-
- rval = {
- :ds_type => ds_type.to_sym,
- :ds_name => ds_name,
- }
-
- return rval
+ return rval
- end
+ end
- public
+ public
- def create
- self.content=(resource[:content])
- end
+ def create
+ self.content=(resource[:content])
+ end
- def destroy
- ds_parms = get_dsparams
- ds_t = TypeMap[ds_parms[:ds_type]]
- ds_n = ds_parms[:ds_name].to_s
- ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
+ def destroy
+ ds_parms = get_dsparams
+ ds_t = TypeMap[ds_parms[:ds_type]]
+ ds_n = ds_parms[:ds_name].to_s
+ ds_path = "/Local/Default/#{ds_t}/#{ds_n}"
- dscl 'localhost', '-mcxdelete', ds_path
- end
+ dscl 'localhost', '-mcxdelete', ds_path
+ end
- def exists?
- # JJM Just re-use the content method and see if it's empty.
- begin
- mcx = content
- rescue Puppet::ExecutionFailure => e
- return false
- end
- has_mcx = ! mcx.empty?
+ def exists?
+ # JJM Just re-use the content method and see if it's empty.
+ begin
+ mcx = content
+ rescue Puppet::ExecutionFailure => e
+ return false
end
+ has_mcx = ! mcx.empty?
+ end
- def content
- ds_parms = get_dsparams
+ def content
+ ds_parms = get_dsparams
- mcx = self.class.mcxexport(
- ds_parms[:ds_type],
+ mcx = self.class.mcxexport(
+ ds_parms[:ds_type],
- ds_parms[:ds_name])
- mcx
- end
+ ds_parms[:ds_name])
+ mcx
+ end
- def content=(value)
- # dscl localhost -mcximport
- ds_parms = get_dsparams
+ def content=(value)
+ # dscl localhost -mcximport
+ ds_parms = get_dsparams
- mcx = mcximport(
- ds_parms[:ds_type],
- ds_parms[:ds_name],
+ mcx = mcximport(
+ ds_parms[:ds_type],
+ ds_parms[:ds_name],
- resource[:content])
- mcx
- end
+ resource[:content])
+ mcx
+ end
end
diff --git a/lib/puppet/provider/mount.rb b/lib/puppet/provider/mount.rb
index 2136339a3..393ae56c9 100644
--- a/lib/puppet/provider/mount.rb
+++ b/lib/puppet/provider/mount.rb
@@ -6,46 +6,46 @@ require 'puppet'
# A module just to store the mount/unmount methods. Individual providers
# still need to add the mount commands manually.
module Puppet::Provider::Mount
- # This only works when the mount point is synced to the fstab.
- def mount
- # Manually pass the mount options in, since some OSes *cough*OS X*cough* don't
- # read from /etc/fstab but still want to use this type.
- args = []
- args << "-o" << self.options if self.options and self.options != :absent
- args << resource[:name]
+ # This only works when the mount point is synced to the fstab.
+ def mount
+ # Manually pass the mount options in, since some OSes *cough*OS X*cough* don't
+ # read from /etc/fstab but still want to use this type.
+ args = []
+ args << "-o" << self.options if self.options and self.options != :absent
+ args << resource[:name]
- flush if respond_to?(:flush)
- mountcmd(*args)
- end
+ flush if respond_to?(:flush)
+ mountcmd(*args)
+ end
- def remount
- info "Remounting"
- if resource[:remounts] == :true
- mountcmd "-o", "remount", resource[:name]
- else
- unmount
- mount
- end
+ def remount
+ info "Remounting"
+ if resource[:remounts] == :true
+ mountcmd "-o", "remount", resource[:name]
+ else
+ unmount
+ mount
end
+ end
- # This only works when the mount point is synced to the fstab.
- def unmount
- umount resource[:name]
- end
+ # This only works when the mount point is synced to the fstab.
+ def unmount
+ umount resource[:name]
+ end
- # Is the mount currently mounted?
- def mounted?
- platform = Facter.value("operatingsystem")
- name = resource[:name]
- mounts = mountcmd.split("\n").find do |line|
- case platform
- when "Darwin"
- line =~ / on #{name} / or line =~ %r{ on /private/var/automount#{name}}
- when "Solaris"
- line =~ /^#{name} on /
- else
- line =~ / on #{name} /
- end
- end
+ # Is the mount currently mounted?
+ def mounted?
+ platform = Facter.value("operatingsystem")
+ name = resource[:name]
+ mounts = mountcmd.split("\n").find do |line|
+ case platform
+ when "Darwin"
+ line =~ / on #{name} / or line =~ %r{ on /private/var/automount#{name}}
+ when "Solaris"
+ line =~ /^#{name} on /
+ else
+ line =~ / on #{name} /
+ end
end
+ end
end
diff --git a/lib/puppet/provider/mount/parsed.rb b/lib/puppet/provider/mount/parsed.rb
index 1100ad62c..82d1628bd 100755
--- a/lib/puppet/provider/mount/parsed.rb
+++ b/lib/puppet/provider/mount/parsed.rb
@@ -5,43 +5,43 @@ fstab = nil
case Facter.value(:operatingsystem)
when "Solaris"; fstab = "/etc/vfstab"
else
- fstab = "/etc/fstab"
+ fstab = "/etc/fstab"
end
- Puppet::Type.type(:mount).provide(
- :parsed,
- :parent => Puppet::Provider::ParsedFile,
- :default_target => fstab,
+ Puppet::Type.type(:mount).provide(
+ :parsed,
+ :parent => Puppet::Provider::ParsedFile,
+ :default_target => fstab,
- :filetype => :flat
+ :filetype => :flat
) do
- include Puppet::Provider::Mount
- #confine :exists => fstab
+ include Puppet::Provider::Mount
+ #confine :exists => fstab
- commands :mountcmd => "mount", :umount => "umount"
+ commands :mountcmd => "mount", :umount => "umount"
- @platform = Facter["operatingsystem"].value
- case @platform
- when "Solaris"
- @fields = [:device, :blockdevice, :name, :fstype, :pass, :atboot, :options]
- else
- @fields = [:device, :name, :fstype, :options, :dump, :pass]
- @fielddefaults = [ nil ] * 4 + [ "0", "2" ]
- end
+ @platform = Facter["operatingsystem"].value
+ case @platform
+ when "Solaris"
+ @fields = [:device, :blockdevice, :name, :fstype, :pass, :atboot, :options]
+ else
+ @fields = [:device, :name, :fstype, :options, :dump, :pass]
+ @fielddefaults = [ nil ] * 4 + [ "0", "2" ]
+ end
- text_line :comment, :match => /^\s*#/
- text_line :blank, :match => /^\s*$/
+ text_line :comment, :match => /^\s*#/
+ text_line :blank, :match => /^\s*$/
- optional_fields = @fields - [:device, :name, :blockdevice]
- mandatory_fields = @fields - optional_fields
+ optional_fields = @fields - [:device, :name, :blockdevice]
+ mandatory_fields = @fields - optional_fields
- # fstab will ignore lines that have fewer than the mandatory number of columns,
- # so we should, too.
- field_pattern = '(\s*(?>\S+))'
- text_line :incomplete, :match => /^(?!#{field_pattern}{#{mandatory_fields.length}})/
+ # fstab will ignore lines that have fewer than the mandatory number of columns,
+ # so we should, too.
+ field_pattern = '(\s*(?>\S+))'
+ text_line :incomplete, :match => /^(?!#{field_pattern}{#{mandatory_fields.length}})/
- record_line self.name, :fields => @fields, :separator => /\s+/, :joiner => "\t", :optional => optional_fields
+ record_line self.name, :fields => @fields, :separator => /\s+/, :joiner => "\t", :optional => optional_fields
end
diff --git a/lib/puppet/provider/naginator.rb b/lib/puppet/provider/naginator.rb
index 1006a4c0d..5c610fb31 100644
--- a/lib/puppet/provider/naginator.rb
+++ b/lib/puppet/provider/naginator.rb
@@ -7,52 +7,52 @@ require 'puppet/external/nagios'
# The base class for all Naginator providers.
class Puppet::Provider::Naginator < Puppet::Provider::ParsedFile
- NAME_STRING = "## --PUPPET_NAME-- (called '_naginator_name' in the manifest)"
- # Retrieve the associated class from Nagios::Base.
- def self.nagios_type
- unless @nagios_type
- name = resource_type.name.to_s.sub(/^nagios_/, '')
- unless @nagios_type = Nagios::Base.type(name.to_sym)
- raise Puppet::DevError, "Could not find nagios type '#{name}'"
- end
-
- # And add our 'ensure' settings, since they aren't a part of
- # Naginator by default
- @nagios_type.send(:attr_accessor, :ensure, :target, :on_disk)
- end
- @nagios_type
+ NAME_STRING = "## --PUPPET_NAME-- (called '_naginator_name' in the manifest)"
+ # Retrieve the associated class from Nagios::Base.
+ def self.nagios_type
+ unless @nagios_type
+ name = resource_type.name.to_s.sub(/^nagios_/, '')
+ unless @nagios_type = Nagios::Base.type(name.to_sym)
+ raise Puppet::DevError, "Could not find nagios type '#{name}'"
+ end
+
+ # And add our 'ensure' settings, since they aren't a part of
+ # Naginator by default
+ @nagios_type.send(:attr_accessor, :ensure, :target, :on_disk)
end
-
- def self.parse(text)
- Nagios::Parser.new.parse(text.gsub(NAME_STRING, "_naginator_name"))
- rescue => detail
- raise Puppet::Error, "Could not parse configuration for #{resource_type.name}: #{detail}"
- end
-
- def self.to_file(records)
- header + records.collect { |record| record.to_s }.join("\n").gsub("_naginator_name", NAME_STRING)
- end
-
- def self.skip_record?(record)
- false
- end
-
- def self.valid_attr?(klass, attr_name)
- nagios_type.parameters.include?(attr_name)
- end
-
- def initialize(resource = nil)
- if resource.is_a?(Nagios::Base)
- # We don't use a duplicate here, because some providers (ParsedFile, at least)
- # use the hash here for later events.
- @property_hash = resource
- elsif resource
- @resource = resource if resource
- # LAK 2007-05-09: Keep the model stuff around for backward compatibility
- @model = resource
- @property_hash = self.class.nagios_type.new
- else
- @property_hash = self.class.nagios_type.new
- end
+ @nagios_type
+ end
+
+ def self.parse(text)
+ Nagios::Parser.new.parse(text.gsub(NAME_STRING, "_naginator_name"))
+ rescue => detail
+ raise Puppet::Error, "Could not parse configuration for #{resource_type.name}: #{detail}"
+ end
+
+ def self.to_file(records)
+ header + records.collect { |record| record.to_s }.join("\n").gsub("_naginator_name", NAME_STRING)
+ end
+
+ def self.skip_record?(record)
+ false
+ end
+
+ def self.valid_attr?(klass, attr_name)
+ nagios_type.parameters.include?(attr_name)
+ end
+
+ def initialize(resource = nil)
+ if resource.is_a?(Nagios::Base)
+ # We don't use a duplicate here, because some providers (ParsedFile, at least)
+ # use the hash here for later events.
+ @property_hash = resource
+ elsif resource
+ @resource = resource if resource
+ # LAK 2007-05-09: Keep the model stuff around for backward compatibility
+ @model = resource
+ @property_hash = self.class.nagios_type.new
+ else
+ @property_hash = self.class.nagios_type.new
end
+ end
end
diff --git a/lib/puppet/provider/nameservice.rb b/lib/puppet/provider/nameservice.rb
index 6564a4154..7339b646e 100644
--- a/lib/puppet/provider/nameservice.rb
+++ b/lib/puppet/provider/nameservice.rb
@@ -4,270 +4,270 @@ require 'puppet'
# their backend, but they're pretty similar on the front-end. This class
# provides a way for them all to be as similar as possible.
class Puppet::Provider::NameService < Puppet::Provider
- class << self
- def autogen_default(param)
- defined?(@autogen_defaults) ? @autogen_defaults[symbolize(param)] : nil
- end
-
- def autogen_defaults(hash)
- @autogen_defaults ||= {}
- hash.each do |param, value|
- @autogen_defaults[symbolize(param)] = value
- end
- end
+ class << self
+ def autogen_default(param)
+ defined?(@autogen_defaults) ? @autogen_defaults[symbolize(param)] : nil
+ end
- def initvars
- @checks = {}
- super
- end
+ def autogen_defaults(hash)
+ @autogen_defaults ||= {}
+ hash.each do |param, value|
+ @autogen_defaults[symbolize(param)] = value
+ end
+ end
- def instances
- objects = []
- listbyname do |name|
- objects << new(:name => name, :ensure => :present)
- end
+ def initvars
+ @checks = {}
+ super
+ end
- objects
- end
+ def instances
+ objects = []
+ listbyname do |name|
+ objects << new(:name => name, :ensure => :present)
+ end
- def option(name, option)
- name = name.intern if name.is_a? String
- (defined?(@options) and @options.include? name and @options[name].include? option) ? @options[name][option] : nil
- end
+ objects
+ end
- def options(name, hash)
- raise Puppet::DevError, "#{name} is not a valid attribute for #{resource_type.name}" unless resource_type.valid_parameter?(name)
- @options ||= {}
- @options[name] ||= {}
+ def option(name, option)
+ name = name.intern if name.is_a? String
+ (defined?(@options) and @options.include? name and @options[name].include? option) ? @options[name][option] : nil
+ end
- # Set options individually, so we can call the options method
- # multiple times.
- hash.each do |param, value|
- @options[name][param] = value
- end
- end
+ def options(name, hash)
+ raise Puppet::DevError, "#{name} is not a valid attribute for #{resource_type.name}" unless resource_type.valid_parameter?(name)
+ @options ||= {}
+ @options[name] ||= {}
- # List everything out by name. Abstracted a bit so that it works
- # for both users and groups.
- def listbyname
- names = []
- Etc.send("set#{section()}ent")
- begin
- while ent = Etc.send("get#{section()}ent")
- names << ent.name
- yield ent.name if block_given?
- end
- ensure
- Etc.send("end#{section()}ent")
- end
-
- names
- end
+ # Set options individually, so we can call the options method
+ # multiple times.
+ hash.each do |param, value|
+ @options[name][param] = value
+ end
+ end
- def resource_type=(resource_type)
- super
- @resource_type.validproperties.each do |prop|
- next if prop == :ensure
- define_method(prop) { get(prop) || :absent} unless public_method_defined?(prop)
- define_method(prop.to_s + "=") { |*vals| set(prop, *vals) } unless public_method_defined?(prop.to_s + "=")
- end
+ # List everything out by name. Abstracted a bit so that it works
+ # for both users and groups.
+ def listbyname
+ names = []
+ Etc.send("set#{section()}ent")
+ begin
+ while ent = Etc.send("get#{section()}ent")
+ names << ent.name
+ yield ent.name if block_given?
end
+ ensure
+ Etc.send("end#{section()}ent")
+ end
- # This is annoying, but there really aren't that many options,
- # and this *is* built into Ruby.
- def section
- unless defined?(@resource_type)
- raise Puppet::DevError,
- "Cannot determine Etc section without a resource type"
-
- end
-
- if @resource_type.name == :group
- "gr"
- else
- "pw"
- end
- end
+ names
+ end
- def validate(name, value)
- name = name.intern if name.is_a? String
- if @checks.include? name
- block = @checks[name][:block]
- raise ArgumentError, "Invalid value #{value}: #{@checks[name][:error]}" unless block.call(value)
- end
- end
+ def resource_type=(resource_type)
+ super
+ @resource_type.validproperties.each do |prop|
+ next if prop == :ensure
+ define_method(prop) { get(prop) || :absent} unless public_method_defined?(prop)
+ define_method(prop.to_s + "=") { |*vals| set(prop, *vals) } unless public_method_defined?(prop.to_s + "=")
+ end
+ end
- def verify(name, error, &block)
- name = name.intern if name.is_a? String
- @checks[name] = {:error => error, :block => block}
- end
+ # This is annoying, but there really aren't that many options,
+ # and this *is* built into Ruby.
+ def section
+ unless defined?(@resource_type)
+ raise Puppet::DevError,
+ "Cannot determine Etc section without a resource type"
- private
+ end
- def op(property)
- @ops[property.name] || ("-#{property.name}")
- end
+ if @resource_type.name == :group
+ "gr"
+ else
+ "pw"
+ end
end
- # Autogenerate a value. Mostly used for uid/gid, but also used heavily
- # with DirectoryServices, because DirectoryServices is stupid.
- def autogen(field)
- field = symbolize(field)
- id_generators = {:user => :uid, :group => :gid}
- if id_generators[@resource.class.name] == field
- return autogen_id(field)
- else
- if value = self.class.autogen_default(field)
- return value
- elsif respond_to?("autogen_#{field}")
- return send("autogen_#{field}")
- else
- return nil
- end
- end
+ def validate(name, value)
+ name = name.intern if name.is_a? String
+ if @checks.include? name
+ block = @checks[name][:block]
+ raise ArgumentError, "Invalid value #{value}: #{@checks[name][:error]}" unless block.call(value)
+ end
end
- # Autogenerate either a uid or a gid. This is hard-coded: we can only
- # generate one field type per class.
- def autogen_id(field)
- highest = 0
-
- group = method = nil
- case @resource.class.name
- when :user; group = :passwd; method = :uid
- when :group; group = :group; method = :gid
- else
- raise Puppet::DevError, "Invalid resource name #{resource}"
- end
+ def verify(name, error, &block)
+ name = name.intern if name.is_a? String
+ @checks[name] = {:error => error, :block => block}
+ end
- # Make sure we don't use the same value multiple times
- if defined?(@@prevauto)
- @@prevauto += 1
- else
- Etc.send(group) { |obj|
- if obj.gid > highest
- highest = obj.send(method) unless obj.send(method) > 65000
- end
- }
-
- @@prevauto = highest + 1
- end
+ private
- @@prevauto
+ def op(property)
+ @ops[property.name] || ("-#{property.name}")
+ end
+ end
+
+ # Autogenerate a value. Mostly used for uid/gid, but also used heavily
+ # with DirectoryServices, because DirectoryServices is stupid.
+ def autogen(field)
+ field = symbolize(field)
+ id_generators = {:user => :uid, :group => :gid}
+ if id_generators[@resource.class.name] == field
+ return autogen_id(field)
+ else
+ if value = self.class.autogen_default(field)
+ return value
+ elsif respond_to?("autogen_#{field}")
+ return send("autogen_#{field}")
+ else
+ return nil
+ end
+ end
+ end
+
+ # Autogenerate either a uid or a gid. This is hard-coded: we can only
+ # generate one field type per class.
+ def autogen_id(field)
+ highest = 0
+
+ group = method = nil
+ case @resource.class.name
+ when :user; group = :passwd; method = :uid
+ when :group; group = :group; method = :gid
+ else
+ raise Puppet::DevError, "Invalid resource name #{resource}"
end
- def create
- if exists?
- info "already exists"
- # The object already exists
- return nil
+ # Make sure we don't use the same value multiple times
+ if defined?(@@prevauto)
+ @@prevauto += 1
+ else
+ Etc.send(group) { |obj|
+ if obj.gid > highest
+ highest = obj.send(method) unless obj.send(method) > 65000
end
+ }
- begin
- execute(self.addcmd)
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not create #{@resource.class.name} #{@resource.name}: #{detail}"
- end
+ @@prevauto = highest + 1
end
- def delete
- unless exists?
- info "already absent"
- # the object already doesn't exist
- return nil
- end
+ @@prevauto
+ end
- begin
- execute(self.deletecmd)
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not delete #{@resource.class.name} #{@resource.name}: #{detail}"
- end
+ def create
+ if exists?
+ info "already exists"
+ # The object already exists
+ return nil
end
- def ensure
- if exists?
- :present
- else
- :absent
- end
+ begin
+ execute(self.addcmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not create #{@resource.class.name} #{@resource.name}: #{detail}"
end
+ end
- # Does our object exist?
- def exists?
- !!getinfo(true)
+ def delete
+ unless exists?
+ info "already absent"
+ # the object already doesn't exist
+ return nil
end
- # Retrieve a specific value by name.
- def get(param)
- (hash = getinfo(false)) ? hash[param] : nil
+ begin
+ execute(self.deletecmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not delete #{@resource.class.name} #{@resource.name}: #{detail}"
end
+ end
- # Retrieve what we can about our object
- def getinfo(refresh)
- if @objectinfo.nil? or refresh == true
- @etcmethod ||= ("get" + self.class.section.to_s + "nam").intern
- begin
- @objectinfo = Etc.send(@etcmethod, @resource[:name])
- rescue ArgumentError => detail
- @objectinfo = nil
- end
- end
-
- # Now convert our Etc struct into a hash.
- @objectinfo ? info2hash(@objectinfo) : nil
+ def ensure
+ if exists?
+ :present
+ else
+ :absent
+ end
+ end
+
+ # Does our object exist?
+ def exists?
+ !!getinfo(true)
+ end
+
+ # Retrieve a specific value by name.
+ def get(param)
+ (hash = getinfo(false)) ? hash[param] : nil
+ end
+
+ # Retrieve what we can about our object
+ def getinfo(refresh)
+ if @objectinfo.nil? or refresh == true
+ @etcmethod ||= ("get" + self.class.section.to_s + "nam").intern
+ begin
+ @objectinfo = Etc.send(@etcmethod, @resource[:name])
+ rescue ArgumentError => detail
+ @objectinfo = nil
+ end
end
- # The list of all groups the user is a member of. Different
- # user mgmt systems will need to override this method.
- def groups
- groups = []
-
- # Reset our group list
- Etc.setgrent
+ # Now convert our Etc struct into a hash.
+ @objectinfo ? info2hash(@objectinfo) : nil
+ end
- user = @resource[:name]
+ # The list of all groups the user is a member of. Different
+ # user mgmt systems will need to override this method.
+ def groups
+ groups = []
- # Now iterate across all of the groups, adding each one our
- # user is a member of
- while group = Etc.getgrent
- members = group.mem
+ # Reset our group list
+ Etc.setgrent
- groups << group.name if members.include? user
- end
+ user = @resource[:name]
- # We have to close the file, so each listing is a separate
- # reading of the file.
- Etc.endgrent
+ # Now iterate across all of the groups, adding each one our
+ # user is a member of
+ while group = Etc.getgrent
+ members = group.mem
- groups.join(",")
+ groups << group.name if members.include? user
end
- # Convert the Etc struct into a hash.
- def info2hash(info)
- hash = {}
- self.class.resource_type.validproperties.each do |param|
- method = posixmethod(param)
- hash[param] = info.send(posixmethod(param)) if info.respond_to? method
- end
+ # We have to close the file, so each listing is a separate
+ # reading of the file.
+ Etc.endgrent
- hash
+ groups.join(",")
+ end
+
+ # Convert the Etc struct into a hash.
+ def info2hash(info)
+ hash = {}
+ self.class.resource_type.validproperties.each do |param|
+ method = posixmethod(param)
+ hash[param] = info.send(posixmethod(param)) if info.respond_to? method
end
- def initialize(resource)
- super
+ hash
+ end
- @objectinfo = nil
- end
+ def initialize(resource)
+ super
- def set(param, value)
- self.class.validate(param, value)
- cmd = modifycmd(param, value)
- raise Puppet::DevError, "Nameservice command must be an array" unless cmd.is_a?(Array)
- begin
- execute(cmd)
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
- end
+ @objectinfo = nil
+ end
+
+ def set(param, value)
+ self.class.validate(param, value)
+ cmd = modifycmd(param, value)
+ raise Puppet::DevError, "Nameservice command must be an array" unless cmd.is_a?(Array)
+ begin
+ execute(cmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}"
end
+ end
end
diff --git a/lib/puppet/provider/nameservice/directoryservice.rb b/lib/puppet/provider/nameservice/directoryservice.rb
index 060ed4c31..76fc466ac 100644
--- a/lib/puppet/provider/nameservice/directoryservice.rb
+++ b/lib/puppet/provider/nameservice/directoryservice.rb
@@ -20,497 +20,497 @@ require 'cgi'
class Puppet::Provider::NameService
class DirectoryService < Puppet::Provider::NameService
- # JJM: Dive into the singleton_class
- class << self
- # JJM: This allows us to pass information when calling
- # Puppet::Type.type
- # e.g. Puppet::Type.type(:user).provide :directoryservice, :ds_path => "Users"
- # This is referenced in the get_ds_path class method
- attr_writer :ds_path
- attr_writer :macosx_version_major
+ # JJM: Dive into the singleton_class
+ class << self
+ # JJM: This allows us to pass information when calling
+ # Puppet::Type.type
+ # e.g. Puppet::Type.type(:user).provide :directoryservice, :ds_path => "Users"
+ # This is referenced in the get_ds_path class method
+ attr_writer :ds_path
+ attr_writer :macosx_version_major
+ end
+
+ initvars
+
+ commands :dscl => "/usr/bin/dscl"
+ commands :dseditgroup => "/usr/sbin/dseditgroup"
+ commands :sw_vers => "/usr/bin/sw_vers"
+ confine :operatingsystem => :darwin
+ defaultfor :operatingsystem => :darwin
+
+
+ # JJM 2007-07-25: This map is used to map NameService attributes to their
+ # corresponding DirectoryService attribute names.
+ # See: http://images.apple.com/server/docs/Open_Directory_v10.4.pdf
+ # JJM: Note, this is de-coupled from the Puppet::Type, and must
+ # be actively maintained. There may also be collisions with different
+ # types (Users, Groups, Mounts, Hosts, etc...)
+ @@ds_to_ns_attribute_map = {
+ 'RecordName' => :name,
+ 'PrimaryGroupID' => :gid,
+ 'NFSHomeDirectory' => :home,
+ 'UserShell' => :shell,
+ 'UniqueID' => :uid,
+ 'RealName' => :comment,
+ 'Password' => :password,
+ 'GeneratedUID' => :guid,
+ 'IPAddress' => :ip_address,
+ 'ENetAddress' => :en_address,
+ 'GroupMembership' => :members,
+ }
+ # JJM The same table as above, inverted.
+ @@ns_to_ds_attribute_map = {
+ :name => 'RecordName',
+ :gid => 'PrimaryGroupID',
+ :home => 'NFSHomeDirectory',
+ :shell => 'UserShell',
+ :uid => 'UniqueID',
+ :comment => 'RealName',
+ :password => 'Password',
+ :guid => 'GeneratedUID',
+ :en_address => 'ENetAddress',
+ :ip_address => 'IPAddress',
+ :members => 'GroupMembership',
+ }
+
+ @@password_hash_dir = "/var/db/shadow/hash"
+
+ def self.instances
+ # JJM Class method that provides an array of instance objects of this
+ # type.
+ # JJM: Properties are dependent on the Puppet::Type we're managine.
+ type_property_array = [:name] + @resource_type.validproperties
+
+ # Create a new instance of this Puppet::Type for each object present
+ # on the system.
+ list_all_present.collect do |name_string|
+ self.new(single_report(name_string, *type_property_array))
end
-
- initvars
-
- commands :dscl => "/usr/bin/dscl"
- commands :dseditgroup => "/usr/sbin/dseditgroup"
- commands :sw_vers => "/usr/bin/sw_vers"
- confine :operatingsystem => :darwin
- defaultfor :operatingsystem => :darwin
-
-
- # JJM 2007-07-25: This map is used to map NameService attributes to their
- # corresponding DirectoryService attribute names.
- # See: http://images.apple.com/server/docs/Open_Directory_v10.4.pdf
- # JJM: Note, this is de-coupled from the Puppet::Type, and must
- # be actively maintained. There may also be collisions with different
- # types (Users, Groups, Mounts, Hosts, etc...)
- @@ds_to_ns_attribute_map = {
- 'RecordName' => :name,
- 'PrimaryGroupID' => :gid,
- 'NFSHomeDirectory' => :home,
- 'UserShell' => :shell,
- 'UniqueID' => :uid,
- 'RealName' => :comment,
- 'Password' => :password,
- 'GeneratedUID' => :guid,
- 'IPAddress' => :ip_address,
- 'ENetAddress' => :en_address,
- 'GroupMembership' => :members,
- }
- # JJM The same table as above, inverted.
- @@ns_to_ds_attribute_map = {
- :name => 'RecordName',
- :gid => 'PrimaryGroupID',
- :home => 'NFSHomeDirectory',
- :shell => 'UserShell',
- :uid => 'UniqueID',
- :comment => 'RealName',
- :password => 'Password',
- :guid => 'GeneratedUID',
- :en_address => 'ENetAddress',
- :ip_address => 'IPAddress',
- :members => 'GroupMembership',
- }
-
- @@password_hash_dir = "/var/db/shadow/hash"
-
- def self.instances
- # JJM Class method that provides an array of instance objects of this
- # type.
- # JJM: Properties are dependent on the Puppet::Type we're managine.
- type_property_array = [:name] + @resource_type.validproperties
-
- # Create a new instance of this Puppet::Type for each object present
- # on the system.
- list_all_present.collect do |name_string|
- self.new(single_report(name_string, *type_property_array))
- end
+ end
+
+ def self.get_ds_path
+ # JJM: 2007-07-24 This method dynamically returns the DS path we're concerned with.
+ # For example, if we're working with an user type, this will be /Users
+ # with a group type, this will be /Groups.
+ # @ds_path is an attribute of the class itself.
+ return @ds_path if defined?(@ds_path)
+ # JJM: "Users" or "Groups" etc ... (Based on the Puppet::Type)
+ # Remember this is a class method, so self.class is Class
+ # Also, @resource_type seems to be the reference to the
+ # Puppet::Type this class object is providing for.
+ @resource_type.name.to_s.capitalize + "s"
+ end
+
+ def self.get_macosx_version_major
+ return @macosx_version_major if defined?(@macosx_version_major)
+ begin
+ # Make sure we've loaded all of the facts
+ Facter.loadfacts
+
+ if Facter.value(:macosx_productversion_major)
+ product_version_major = Facter.value(:macosx_productversion_major)
+ else
+ # TODO: remove this code chunk once we require Facter 1.5.5 or higher.
+ Puppet.warning("DEPRECATION WARNING: Future versions of the directoryservice provider will require Facter 1.5.5 or newer.")
+ product_version = Facter.value(:macosx_productversion)
+ fail("Could not determine OS X version from Facter") if product_version.nil?
+ product_version_major = product_version.scan(/(\d+)\.(\d+)./).join(".")
+ end
+ fail("#{product_version_major} is not supported by the directoryservice provider") if %w{10.0 10.1 10.2 10.3}.include?(product_version_major)
+ @macosx_version_major = product_version_major
+ return @macosx_version_major
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not determine OS X version: #{detail}")
end
+ end
- def self.get_ds_path
- # JJM: 2007-07-24 This method dynamically returns the DS path we're concerned with.
- # For example, if we're working with an user type, this will be /Users
- # with a group type, this will be /Groups.
- # @ds_path is an attribute of the class itself.
- return @ds_path if defined?(@ds_path)
- # JJM: "Users" or "Groups" etc ... (Based on the Puppet::Type)
- # Remember this is a class method, so self.class is Class
- # Also, @resource_type seems to be the reference to the
- # Puppet::Type this class object is providing for.
- @resource_type.name.to_s.capitalize + "s"
- end
- def self.get_macosx_version_major
- return @macosx_version_major if defined?(@macosx_version_major)
- begin
- # Make sure we've loaded all of the facts
- Facter.loadfacts
-
- if Facter.value(:macosx_productversion_major)
- product_version_major = Facter.value(:macosx_productversion_major)
- else
- # TODO: remove this code chunk once we require Facter 1.5.5 or higher.
- Puppet.warning("DEPRECATION WARNING: Future versions of the directoryservice provider will require Facter 1.5.5 or newer.")
- product_version = Facter.value(:macosx_productversion)
- fail("Could not determine OS X version from Facter") if product_version.nil?
- product_version_major = product_version.scan(/(\d+)\.(\d+)./).join(".")
- end
- fail("#{product_version_major} is not supported by the directoryservice provider") if %w{10.0 10.1 10.2 10.3}.include?(product_version_major)
- @macosx_version_major = product_version_major
- return @macosx_version_major
- rescue Puppet::ExecutionFailure => detail
- fail("Could not determine OS X version: #{detail}")
- end
+ def self.list_all_present
+ # JJM: List all objects of this Puppet::Type already present on the system.
+ begin
+ dscl_output = execute(get_exec_preamble("-list"))
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not get #{@resource_type.name} list from DirectoryService")
end
-
-
- def self.list_all_present
- # JJM: List all objects of this Puppet::Type already present on the system.
- begin
- dscl_output = execute(get_exec_preamble("-list"))
- rescue Puppet::ExecutionFailure => detail
- fail("Could not get #{@resource_type.name} list from DirectoryService")
- end
- dscl_output.split("\n")
+ dscl_output.split("\n")
+ end
+
+ def self.parse_dscl_url_data(dscl_output)
+ # we need to construct a Hash from the dscl -url output to match
+ # that returned by the dscl -plist output for 10.5+ clients.
+ #
+ # Nasty assumptions:
+ # a) no values *end* in a colon ':', only keys
+ # b) if a line ends in a colon and the next line does start with
+ # a space, then the second line is a value of the first.
+ # c) (implied by (b)) keys don't start with spaces.
+
+ dscl_plist = {}
+ dscl_output.split("\n").inject([]) do |array, line|
+ if line =~ /^\s+/ # it's a value
+ array[-1] << line # add the value to the previous key
+ else
+ array << line
+ end
+ array
+ end.compact
+
+ dscl_output.each do |line|
+ # This should be a 'normal' entry. key and value on one line.
+ # We split on ': ' to deal with keys/values with a colon in them.
+ split_array = line.split(/:\s+/)
+ key = split_array.first
+ value = CGI::unescape(split_array.last.strip.chomp)
+ # We need to treat GroupMembership separately as it is currently
+ # the only attribute we care about multiple values for, and
+ # the values can never contain spaces (shortnames)
+ # We also make every value an array to be consistent with the
+ # output of dscl -plist under 10.5
+ if key == "GroupMembership"
+ dscl_plist[key] = value.split(/\s/)
+ else
+ dscl_plist[key] = [value]
+ end
end
-
- def self.parse_dscl_url_data(dscl_output)
- # we need to construct a Hash from the dscl -url output to match
- # that returned by the dscl -plist output for 10.5+ clients.
- #
- # Nasty assumptions:
- # a) no values *end* in a colon ':', only keys
- # b) if a line ends in a colon and the next line does start with
- # a space, then the second line is a value of the first.
- # c) (implied by (b)) keys don't start with spaces.
-
- dscl_plist = {}
- dscl_output.split("\n").inject([]) do |array, line|
- if line =~ /^\s+/ # it's a value
- array[-1] << line # add the value to the previous key
- else
- array << line
- end
- array
- end.compact
-
- dscl_output.each do |line|
- # This should be a 'normal' entry. key and value on one line.
- # We split on ': ' to deal with keys/values with a colon in them.
- split_array = line.split(/:\s+/)
- key = split_array.first
- value = CGI::unescape(split_array.last.strip.chomp)
- # We need to treat GroupMembership separately as it is currently
- # the only attribute we care about multiple values for, and
- # the values can never contain spaces (shortnames)
- # We also make every value an array to be consistent with the
- # output of dscl -plist under 10.5
- if key == "GroupMembership"
- dscl_plist[key] = value.split(/\s/)
- else
- dscl_plist[key] = [value]
- end
- end
- dscl_plist
+ dscl_plist
+ end
+
+ def self.parse_dscl_plist_data(dscl_output)
+ Plist.parse_xml(dscl_output)
+ end
+
+ def self.generate_attribute_hash(input_hash, *type_properties)
+ attribute_hash = {}
+ input_hash.keys.each do |key|
+ ds_attribute = key.sub("dsAttrTypeStandard:", "")
+ next unless (@@ds_to_ns_attribute_map.keys.include?(ds_attribute) and type_properties.include? @@ds_to_ns_attribute_map[ds_attribute])
+ ds_value = input_hash[key]
+ case @@ds_to_ns_attribute_map[ds_attribute]
+ when :members
+ ds_value = ds_value # only members uses arrays so far
+ when :gid, :uid
+ # OS X stores objects like uid/gid as strings.
+ # Try casting to an integer for these cases to be
+ # consistent with the other providers and the group type
+ # validation
+ begin
+ ds_value = Integer(ds_value[0])
+ rescue ArgumentError
+ ds_value = ds_value[0]
+ end
+ else ds_value = ds_value[0]
+ end
+ attribute_hash[@@ds_to_ns_attribute_map[ds_attribute]] = ds_value
end
- def self.parse_dscl_plist_data(dscl_output)
- Plist.parse_xml(dscl_output)
+ # NBK: need to read the existing password here as it's not actually
+ # stored in the user record. It is stored at a path that involves the
+ # UUID of the user record for non-Mobile local acccounts.
+ # Mobile Accounts are out of scope for this provider for now
+ attribute_hash[:password] = self.get_password(attribute_hash[:guid]) if @resource_type.validproperties.include?(:password) and Puppet.features.root?
+ attribute_hash
+ end
+
+ def self.single_report(resource_name, *type_properties)
+ # JJM 2007-07-24:
+ # Given a the name of an object and a list of properties of that
+ # object, return all property values in a hash.
+ #
+ # This class method returns nil if the object doesn't exist
+ # Otherwise, it returns a hash of the object properties.
+
+ all_present_str_array = list_all_present
+
+ # NBK: shortcut the process if the resource is missing
+ return nil unless all_present_str_array.include? resource_name
+
+ dscl_vector = get_exec_preamble("-read", resource_name)
+ begin
+ dscl_output = execute(dscl_vector)
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not get report. command execution failed.")
end
- def self.generate_attribute_hash(input_hash, *type_properties)
- attribute_hash = {}
- input_hash.keys.each do |key|
- ds_attribute = key.sub("dsAttrTypeStandard:", "")
- next unless (@@ds_to_ns_attribute_map.keys.include?(ds_attribute) and type_properties.include? @@ds_to_ns_attribute_map[ds_attribute])
- ds_value = input_hash[key]
- case @@ds_to_ns_attribute_map[ds_attribute]
- when :members
- ds_value = ds_value # only members uses arrays so far
- when :gid, :uid
- # OS X stores objects like uid/gid as strings.
- # Try casting to an integer for these cases to be
- # consistent with the other providers and the group type
- # validation
- begin
- ds_value = Integer(ds_value[0])
- rescue ArgumentError
- ds_value = ds_value[0]
- end
- else ds_value = ds_value[0]
- end
- attribute_hash[@@ds_to_ns_attribute_map[ds_attribute]] = ds_value
- end
-
- # NBK: need to read the existing password here as it's not actually
- # stored in the user record. It is stored at a path that involves the
- # UUID of the user record for non-Mobile local acccounts.
- # Mobile Accounts are out of scope for this provider for now
- attribute_hash[:password] = self.get_password(attribute_hash[:guid]) if @resource_type.validproperties.include?(:password) and Puppet.features.root?
- attribute_hash
+ # Two code paths is ugly, but until we can drop 10.4 support we don't
+ # have a lot of choice. Ultimately this should all be done using Ruby
+ # to access the DirectoryService APIs directly, but that's simply not
+ # feasible for a while yet.
+ case self.get_macosx_version_major
+ when "10.4"
+ dscl_plist = self.parse_dscl_url_data(dscl_output)
+ when "10.5", "10.6"
+ dscl_plist = self.parse_dscl_plist_data(dscl_output)
end
- def self.single_report(resource_name, *type_properties)
- # JJM 2007-07-24:
- # Given a the name of an object and a list of properties of that
- # object, return all property values in a hash.
- #
- # This class method returns nil if the object doesn't exist
- # Otherwise, it returns a hash of the object properties.
-
- all_present_str_array = list_all_present
-
- # NBK: shortcut the process if the resource is missing
- return nil unless all_present_str_array.include? resource_name
-
- dscl_vector = get_exec_preamble("-read", resource_name)
- begin
- dscl_output = execute(dscl_vector)
- rescue Puppet::ExecutionFailure => detail
- fail("Could not get report. command execution failed.")
- end
-
- # Two code paths is ugly, but until we can drop 10.4 support we don't
- # have a lot of choice. Ultimately this should all be done using Ruby
- # to access the DirectoryService APIs directly, but that's simply not
- # feasible for a while yet.
- case self.get_macosx_version_major
- when "10.4"
- dscl_plist = self.parse_dscl_url_data(dscl_output)
- when "10.5", "10.6"
- dscl_plist = self.parse_dscl_plist_data(dscl_output)
- end
-
- self.generate_attribute_hash(dscl_plist, *type_properties)
+ self.generate_attribute_hash(dscl_plist, *type_properties)
+ end
+
+ def self.get_exec_preamble(ds_action, resource_name = nil)
+ # JJM 2007-07-24
+ # DSCL commands are often repetitive and contain the same positional
+ # arguments over and over. See http://developer.apple.com/documentation/Porting/Conceptual/PortingUnix/additionalfeatures/chapter_10_section_9.html
+ # for an example of what I mean.
+ # This method spits out proper DSCL commands for us.
+ # We EXPECT name to be @resource[:name] when called from an instance object.
+
+ # 10.4 doesn't support the -plist option for dscl, and 10.5 has a
+ # different format for the -url output with objects with spaces in
+ # their values. *sigh*. Use -url for 10.4 in the hope this can be
+ # deprecated one day, and use -plist for 10.5 and higher.
+ case self.get_macosx_version_major
+ when "10.4"
+ command_vector = [ command(:dscl), "-url", "." ]
+ when "10.5", "10.6"
+ command_vector = [ command(:dscl), "-plist", "." ]
+ end
+ # JJM: The actual action to perform. See "man dscl"
+ # Common actiosn: -create, -delete, -merge, -append, -passwd
+ command_vector << ds_action
+ # JJM: get_ds_path will spit back "Users" or "Groups",
+ # etc... Depending on the Puppet::Type of our self.
+ if resource_name
+ command_vector << "/#{get_ds_path}/#{resource_name}"
+ else
+ command_vector << "/#{get_ds_path}"
+ end
+ # JJM: This returns most of the preamble of the command.
+ # e.g. 'dscl / -create /Users/mccune'
+ command_vector
+ end
+
+ def self.set_password(resource_name, guid, password_hash)
+ password_hash_file = "#{@@password_hash_dir}/#{guid}"
+ begin
+ File.open(password_hash_file, 'w') { |f| f.write(password_hash)}
+ rescue Errno::EACCES => detail
+ fail("Could not write to password hash file: #{detail}")
end
- def self.get_exec_preamble(ds_action, resource_name = nil)
- # JJM 2007-07-24
- # DSCL commands are often repetitive and contain the same positional
- # arguments over and over. See http://developer.apple.com/documentation/Porting/Conceptual/PortingUnix/additionalfeatures/chapter_10_section_9.html
- # for an example of what I mean.
- # This method spits out proper DSCL commands for us.
- # We EXPECT name to be @resource[:name] when called from an instance object.
-
- # 10.4 doesn't support the -plist option for dscl, and 10.5 has a
- # different format for the -url output with objects with spaces in
- # their values. *sigh*. Use -url for 10.4 in the hope this can be
- # deprecated one day, and use -plist for 10.5 and higher.
- case self.get_macosx_version_major
- when "10.4"
- command_vector = [ command(:dscl), "-url", "." ]
- when "10.5", "10.6"
- command_vector = [ command(:dscl), "-plist", "." ]
- end
- # JJM: The actual action to perform. See "man dscl"
- # Common actiosn: -create, -delete, -merge, -append, -passwd
- command_vector << ds_action
- # JJM: get_ds_path will spit back "Users" or "Groups",
- # etc... Depending on the Puppet::Type of our self.
- if resource_name
- command_vector << "/#{get_ds_path}/#{resource_name}"
+ # NBK: For shadow hashes, the user AuthenticationAuthority must contain a value of
+ # ";ShadowHash;". The LKDC in 10.5 makes this more interesting though as it
+ # will dynamically generate ;Kerberosv5;;username@LKDC:SHA1 attributes if
+ # missing. Thus we make sure we only set ;ShadowHash; if it is missing, and
+ # we can do this with the merge command. This allows people to continue to
+ # use other custom AuthenticationAuthority attributes without stomping on them.
+ #
+ # There is a potential problem here in that we're only doing this when setting
+ # the password, and the attribute could get modified at other times while the
+ # hash doesn't change and so this doesn't get called at all... but
+ # without switching all the other attributes to merge instead of create I can't
+ # see a simple enough solution for this that doesn't modify the user record
+ # every single time. This should be a rather rare edge case. (famous last words)
+
+ dscl_vector = self.get_exec_preamble("-merge", resource_name)
+ dscl_vector << "AuthenticationAuthority" << ";ShadowHash;"
+ begin
+ dscl_output = execute(dscl_vector)
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not set AuthenticationAuthority.")
+ end
+ end
+
+ def self.get_password(guid)
+ password_hash = nil
+ password_hash_file = "#{@@password_hash_dir}/#{guid}"
+ if File.exists?(password_hash_file) and File.file?(password_hash_file)
+ fail("Could not read password hash file at #{password_hash_file}") if not File.readable?(password_hash_file)
+ f = File.new(password_hash_file)
+ password_hash = f.read
+ f.close
+ end
+ password_hash
+ end
+
+ def ensure=(ensure_value)
+ super
+ # We need to loop over all valid properties for the type we're
+ # managing and call the method which sets that property value
+ # dscl can't create everything at once unfortunately.
+ if ensure_value == :present
+ @resource.class.validproperties.each do |name|
+ next if name == :ensure
+ # LAK: We use property.sync here rather than directly calling
+ # the settor method because the properties might do some kind
+ # of conversion. In particular, the user gid property might
+ # have a string and need to convert it to a number
+ if @resource.should(name)
+ @resource.property(name).sync
+ elsif value = autogen(name)
+ self.send(name.to_s + "=", value)
else
- command_vector << "/#{get_ds_path}"
+ next
end
- # JJM: This returns most of the preamble of the command.
- # e.g. 'dscl / -create /Users/mccune'
- command_vector
+ end
end
-
- def self.set_password(resource_name, guid, password_hash)
- password_hash_file = "#{@@password_hash_dir}/#{guid}"
- begin
- File.open(password_hash_file, 'w') { |f| f.write(password_hash)}
- rescue Errno::EACCES => detail
- fail("Could not write to password hash file: #{detail}")
- end
-
- # NBK: For shadow hashes, the user AuthenticationAuthority must contain a value of
- # ";ShadowHash;". The LKDC in 10.5 makes this more interesting though as it
- # will dynamically generate ;Kerberosv5;;username@LKDC:SHA1 attributes if
- # missing. Thus we make sure we only set ;ShadowHash; if it is missing, and
- # we can do this with the merge command. This allows people to continue to
- # use other custom AuthenticationAuthority attributes without stomping on them.
- #
- # There is a potential problem here in that we're only doing this when setting
- # the password, and the attribute could get modified at other times while the
- # hash doesn't change and so this doesn't get called at all... but
- # without switching all the other attributes to merge instead of create I can't
- # see a simple enough solution for this that doesn't modify the user record
- # every single time. This should be a rather rare edge case. (famous last words)
-
- dscl_vector = self.get_exec_preamble("-merge", resource_name)
- dscl_vector << "AuthenticationAuthority" << ";ShadowHash;"
- begin
- dscl_output = execute(dscl_vector)
- rescue Puppet::ExecutionFailure => detail
- fail("Could not set AuthenticationAuthority.")
- end
+ end
+
+ def password=(passphrase)
+ exec_arg_vector = self.class.get_exec_preamble("-read", @resource.name)
+ exec_arg_vector << @@ns_to_ds_attribute_map[:guid]
+ begin
+ guid_output = execute(exec_arg_vector)
+ guid_plist = Plist.parse_xml(guid_output)
+ # Although GeneratedUID like all DirectoryService values can be multi-valued
+ # according to the schema, in practice user accounts cannot have multiple UUIDs
+ # otherwise Bad Things Happen, so we just deal with the first value.
+ guid = guid_plist["dsAttrTypeStandard:#{@@ns_to_ds_attribute_map[:guid]}"][0]
+ self.class.set_password(@resource.name, guid, passphrase)
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}")
end
-
- def self.get_password(guid)
- password_hash = nil
- password_hash_file = "#{@@password_hash_dir}/#{guid}"
- if File.exists?(password_hash_file) and File.file?(password_hash_file)
- fail("Could not read password hash file at #{password_hash_file}") if not File.readable?(password_hash_file)
- f = File.new(password_hash_file)
- password_hash = f.read
- f.close
- end
- password_hash
+ end
+
+ # NBK: we override @parent.set as we need to execute a series of commands
+ # to deal with array values, rather than the single command nameservice.rb
+ # expects to be returned by modifycmd. Thus we don't bother defining modifycmd.
+
+ def set(param, value)
+ self.class.validate(param, value)
+ current_members = @property_value_cache_hash[:members]
+ if param == :members
+ # If we are meant to be authoritative for the group membership
+ # then remove all existing members who haven't been specified
+ # in the manifest.
+ remove_unwanted_members(current_members, value) if @resource[:auth_membership] and not current_members.nil?
+
+ # if they're not a member, make them one.
+ add_members(current_members, value)
+ else
+ exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
+ # JJM: The following line just maps the NS name to the DS name
+ # e.g. { :uid => 'UniqueID' }
+ exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(param)]
+ # JJM: The following line sends the actual value to set the property to
+ exec_arg_vector << value.to_s
+ begin
+ execute(exec_arg_vector)
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}")
+ end
+ end
+ end
+
+ # NBK: we override @parent.create as we need to execute a series of commands
+ # to create objects with dscl, rather than the single command nameservice.rb
+ # expects to be returned by addcmd. Thus we don't bother defining addcmd.
+ def create
+ if exists?
+ info "already exists"
+ return nil
end
- def ensure=(ensure_value)
- super
- # We need to loop over all valid properties for the type we're
- # managing and call the method which sets that property value
- # dscl can't create everything at once unfortunately.
- if ensure_value == :present
- @resource.class.validproperties.each do |name|
- next if name == :ensure
- # LAK: We use property.sync here rather than directly calling
- # the settor method because the properties might do some kind
- # of conversion. In particular, the user gid property might
- # have a string and need to convert it to a number
- if @resource.should(name)
- @resource.property(name).sync
- elsif value = autogen(name)
- self.send(name.to_s + "=", value)
- else
- next
- end
- end
- end
+ # NBK: First we create the object with a known guid so we can set the contents
+ # of the password hash if required
+ # Shelling out sucks, but for a single use case it doesn't seem worth
+ # requiring people install a UUID library that doesn't come with the system.
+ # This should be revisited if Puppet starts managing UUIDs for other platform
+ # user records.
+ guid = %x{/usr/bin/uuidgen}.chomp
+
+ exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
+ exec_arg_vector << @@ns_to_ds_attribute_map[:guid] << guid
+ begin
+ execute(exec_arg_vector)
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not set GeneratedUID for #{@resource.class.name} #{@resource.name}: #{detail}")
end
- def password=(passphrase)
- exec_arg_vector = self.class.get_exec_preamble("-read", @resource.name)
- exec_arg_vector << @@ns_to_ds_attribute_map[:guid]
- begin
- guid_output = execute(exec_arg_vector)
- guid_plist = Plist.parse_xml(guid_output)
- # Although GeneratedUID like all DirectoryService values can be multi-valued
- # according to the schema, in practice user accounts cannot have multiple UUIDs
- # otherwise Bad Things Happen, so we just deal with the first value.
- guid = guid_plist["dsAttrTypeStandard:#{@@ns_to_ds_attribute_map[:guid]}"][0]
- self.class.set_password(@resource.name, guid, passphrase)
- rescue Puppet::ExecutionFailure => detail
- fail("Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}")
- end
+ if value = @resource.should(:password) and value != ""
+ self.class.set_password(@resource[:name], guid, value)
end
- # NBK: we override @parent.set as we need to execute a series of commands
- # to deal with array values, rather than the single command nameservice.rb
- # expects to be returned by modifycmd. Thus we don't bother defining modifycmd.
-
- def set(param, value)
- self.class.validate(param, value)
- current_members = @property_value_cache_hash[:members]
- if param == :members
- # If we are meant to be authoritative for the group membership
- # then remove all existing members who haven't been specified
- # in the manifest.
- remove_unwanted_members(current_members, value) if @resource[:auth_membership] and not current_members.nil?
-
- # if they're not a member, make them one.
- add_members(current_members, value)
+ # Now we create all the standard properties
+ Puppet::Type.type(@resource.class.name).validproperties.each do |property|
+ next if property == :ensure
+ if value = @resource.should(property) and value != ""
+ if property == :members
+ add_members(nil, value)
else
- exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
- # JJM: The following line just maps the NS name to the DS name
- # e.g. { :uid => 'UniqueID' }
- exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(param)]
- # JJM: The following line sends the actual value to set the property to
- exec_arg_vector << value.to_s
- begin
- execute(exec_arg_vector)
- rescue Puppet::ExecutionFailure => detail
- fail("Could not set #{param} on #{@resource.class.name}[#{@resource.name}]: #{detail}")
- end
+ exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
+ exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(property)]
+ next if property == :password # skip setting the password here
+ exec_arg_vector << value.to_s
+ begin
+ execute(exec_arg_vector)
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not create #{@resource.class.name} #{@resource.name}: #{detail}")
+ end
end
+ end
end
+ end
- # NBK: we override @parent.create as we need to execute a series of commands
- # to create objects with dscl, rather than the single command nameservice.rb
- # expects to be returned by addcmd. Thus we don't bother defining addcmd.
- def create
- if exists?
- info "already exists"
- return nil
- end
-
- # NBK: First we create the object with a known guid so we can set the contents
- # of the password hash if required
- # Shelling out sucks, but for a single use case it doesn't seem worth
- # requiring people install a UUID library that doesn't come with the system.
- # This should be revisited if Puppet starts managing UUIDs for other platform
- # user records.
- guid = %x{/usr/bin/uuidgen}.chomp
-
- exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
- exec_arg_vector << @@ns_to_ds_attribute_map[:guid] << guid
+ def remove_unwanted_members(current_members, new_members)
+ current_members.each do |member|
+ if not new_members.include?(member)
+ cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-d", member, @resource[:name]]
begin
- execute(exec_arg_vector)
+ execute(cmd)
rescue Puppet::ExecutionFailure => detail
- fail("Could not set GeneratedUID for #{@resource.class.name} #{@resource.name}: #{detail}")
- end
-
- if value = @resource.should(:password) and value != ""
- self.class.set_password(@resource[:name], guid, value)
- end
-
- # Now we create all the standard properties
- Puppet::Type.type(@resource.class.name).validproperties.each do |property|
- next if property == :ensure
- if value = @resource.should(property) and value != ""
- if property == :members
- add_members(nil, value)
- else
- exec_arg_vector = self.class.get_exec_preamble("-create", @resource[:name])
- exec_arg_vector << @@ns_to_ds_attribute_map[symbolize(property)]
- next if property == :password # skip setting the password here
- exec_arg_vector << value.to_s
- begin
- execute(exec_arg_vector)
- rescue Puppet::ExecutionFailure => detail
- fail("Could not create #{@resource.class.name} #{@resource.name}: #{detail}")
- end
- end
- end
+ fail("Could not remove #{member} from group: #{@resource.name}, #{detail}")
end
+ end
end
+ end
- def remove_unwanted_members(current_members, new_members)
- current_members.each do |member|
- if not new_members.include?(member)
- cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-d", member, @resource[:name]]
- begin
- execute(cmd)
- rescue Puppet::ExecutionFailure => detail
- fail("Could not remove #{member} from group: #{@resource.name}, #{detail}")
- end
- end
- end
- end
-
- def add_members(current_members, new_members)
- new_members.each do |new_member|
- if current_members.nil? or not current_members.include?(new_member)
- cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-a", new_member, @resource[:name]]
- begin
- execute(cmd)
- rescue Puppet::ExecutionFailure => detail
- fail("Could not add #{new_member} to group: #{@resource.name}, #{detail}")
- end
- end
+ def add_members(current_members, new_members)
+ new_members.each do |new_member|
+ if current_members.nil? or not current_members.include?(new_member)
+ cmd = [:dseditgroup, "-o", "edit", "-n", ".", "-a", new_member, @resource[:name]]
+ begin
+ execute(cmd)
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not add #{new_member} to group: #{@resource.name}, #{detail}")
end
+ end
end
-
- def deletecmd
- # JJM: Like addcmd, only called when deleting the object itself
- # Note, this isn't used to delete properties of the object,
- # at least that's how I understand it...
- self.class.get_exec_preamble("-delete", @resource[:name])
- end
-
- def getinfo(refresh = false)
- # JJM 2007-07-24:
- # Override the getinfo method, which is also defined in nameservice.rb
- # This method returns and sets @infohash
- # I'm not re-factoring the name "getinfo" because this method will be
- # most likely called by nameservice.rb, which I didn't write.
- if refresh or (! defined?(@property_value_cache_hash) or ! @property_value_cache_hash)
- # JJM 2007-07-24: OK, there's a bit of magic that's about to
- # happen... Let's see how strong my grip has become... =)
- #
- # self is a provider instance of some Puppet::Type, like
- # Puppet::Type::User::ProviderDirectoryservice for the case of the
- # user type and this provider.
- #
- # self.class looks like "user provider directoryservice", if that
- # helps you ...
- #
- # self.class.resource_type is a reference to the Puppet::Type class,
- # probably Puppet::Type::User or Puppet::Type::Group, etc...
- #
- # self.class.resource_type.validproperties is a class method,
- # returning an Array of the valid properties of that specific
- # Puppet::Type.
- #
- # So... something like [:comment, :home, :password, :shell, :uid,
- # :groups, :ensure, :gid]
- #
- # Ultimately, we add :name to the list, delete :ensure from the
- # list, then report on the remaining list. Pretty whacky, ehh?
- type_properties = [:name] + self.class.resource_type.validproperties
- type_properties.delete(:ensure) if type_properties.include? :ensure
- type_properties << :guid # append GeneratedUID so we just get the report here
- @property_value_cache_hash = self.class.single_report(@resource[:name], *type_properties)
- [:uid, :gid].each do |param|
- @property_value_cache_hash[param] = @property_value_cache_hash[param].to_i if @property_value_cache_hash and @property_value_cache_hash.include?(param)
- end
- end
- @property_value_cache_hash
+ end
+
+ def deletecmd
+ # JJM: Like addcmd, only called when deleting the object itself
+ # Note, this isn't used to delete properties of the object,
+ # at least that's how I understand it...
+ self.class.get_exec_preamble("-delete", @resource[:name])
+ end
+
+ def getinfo(refresh = false)
+ # JJM 2007-07-24:
+ # Override the getinfo method, which is also defined in nameservice.rb
+ # This method returns and sets @infohash
+ # I'm not re-factoring the name "getinfo" because this method will be
+ # most likely called by nameservice.rb, which I didn't write.
+ if refresh or (! defined?(@property_value_cache_hash) or ! @property_value_cache_hash)
+ # JJM 2007-07-24: OK, there's a bit of magic that's about to
+ # happen... Let's see how strong my grip has become... =)
+ #
+ # self is a provider instance of some Puppet::Type, like
+ # Puppet::Type::User::ProviderDirectoryservice for the case of the
+ # user type and this provider.
+ #
+ # self.class looks like "user provider directoryservice", if that
+ # helps you ...
+ #
+ # self.class.resource_type is a reference to the Puppet::Type class,
+ # probably Puppet::Type::User or Puppet::Type::Group, etc...
+ #
+ # self.class.resource_type.validproperties is a class method,
+ # returning an Array of the valid properties of that specific
+ # Puppet::Type.
+ #
+ # So... something like [:comment, :home, :password, :shell, :uid,
+ # :groups, :ensure, :gid]
+ #
+ # Ultimately, we add :name to the list, delete :ensure from the
+ # list, then report on the remaining list. Pretty whacky, ehh?
+ type_properties = [:name] + self.class.resource_type.validproperties
+ type_properties.delete(:ensure) if type_properties.include? :ensure
+ type_properties << :guid # append GeneratedUID so we just get the report here
+ @property_value_cache_hash = self.class.single_report(@resource[:name], *type_properties)
+ [:uid, :gid].each do |param|
+ @property_value_cache_hash[param] = @property_value_cache_hash[param].to_i if @property_value_cache_hash and @property_value_cache_hash.include?(param)
+ end
end
+ @property_value_cache_hash
+ end
end
end
diff --git a/lib/puppet/provider/nameservice/objectadd.rb b/lib/puppet/provider/nameservice/objectadd.rb
index 25528be85..80c142982 100644
--- a/lib/puppet/provider/nameservice/objectadd.rb
+++ b/lib/puppet/provider/nameservice/objectadd.rb
@@ -2,31 +2,31 @@ require 'puppet/provider/nameservice'
class Puppet::Provider::NameService
class ObjectAdd < Puppet::Provider::NameService
- def deletecmd
- [command(:delete), @resource[:name]]
- end
-
- # Determine the flag to pass to our command.
- def flag(name)
- name = name.intern if name.is_a? String
- self.class.option(name, :flag) || "-" + name.to_s[0,1]
- end
+ def deletecmd
+ [command(:delete), @resource[:name]]
+ end
- def modifycmd(param, value)
- cmd = [command(:modify), flag(param), value]
- if @resource.allowdupe? && ((param == :uid) || (param == :gid and self.class.name == :groupadd))
- cmd << "-o"
- end
- cmd << @resource[:name]
+ # Determine the flag to pass to our command.
+ def flag(name)
+ name = name.intern if name.is_a? String
+ self.class.option(name, :flag) || "-" + name.to_s[0,1]
+ end
- cmd
+ def modifycmd(param, value)
+ cmd = [command(:modify), flag(param), value]
+ if @resource.allowdupe? && ((param == :uid) || (param == :gid and self.class.name == :groupadd))
+ cmd << "-o"
end
+ cmd << @resource[:name]
- def posixmethod(name)
- name = name.intern if name.is_a? String
- method = self.class.option(name, :method) || name
+ cmd
+ end
- method
- end
+ def posixmethod(name)
+ name = name.intern if name.is_a? String
+ method = self.class.option(name, :method) || name
+
+ method
+ end
end
end
diff --git a/lib/puppet/provider/nameservice/pw.rb b/lib/puppet/provider/nameservice/pw.rb
index 702d705c6..74f1a9fbb 100644
--- a/lib/puppet/provider/nameservice/pw.rb
+++ b/lib/puppet/provider/nameservice/pw.rb
@@ -2,20 +2,20 @@ require 'puppet/provider/nameservice/objectadd'
class Puppet::Provider::NameService
class PW < ObjectAdd
- def deletecmd
- [command(:pw), "#{@resource.class.name.to_s}del", @resource[:name]]
- end
+ def deletecmd
+ [command(:pw), "#{@resource.class.name.to_s}del", @resource[:name]]
+ end
- def modifycmd(param, value)
- cmd = [
- command(:pw),
- "#{@resource.class.name.to_s}mod",
- @resource[:name],
- flag(param),
- value
- ]
- cmd
- end
+ def modifycmd(param, value)
+ cmd = [
+ command(:pw),
+ "#{@resource.class.name.to_s}mod",
+ @resource[:name],
+ flag(param),
+ value
+ ]
+ cmd
+ end
end
end
diff --git a/lib/puppet/provider/package.rb b/lib/puppet/provider/package.rb
index 0ce6cca0a..2f5f67547 100644
--- a/lib/puppet/provider/package.rb
+++ b/lib/puppet/provider/package.rb
@@ -2,26 +2,26 @@
# Copyright (c) 2007. All rights reserved.
class Puppet::Provider::Package < Puppet::Provider
- # Prefetch our package list, yo.
- def self.prefetch(packages)
- instances.each do |prov|
- if pkg = packages[prov.name]
- pkg.provider = prov
- end
- end
+ # Prefetch our package list, yo.
+ def self.prefetch(packages)
+ instances.each do |prov|
+ if pkg = packages[prov.name]
+ pkg.provider = prov
+ end
end
+ end
- # Clear out the cached values.
- def flush
- @property_hash.clear
- end
+ # Clear out the cached values.
+ def flush
+ @property_hash.clear
+ end
- # Look up the current status.
- def properties
- if @property_hash.empty?
- @property_hash = query || {:ensure => :absent}
- @property_hash[:ensure] = :absent if @property_hash.empty?
- end
- @property_hash.dup
+ # Look up the current status.
+ def properties
+ if @property_hash.empty?
+ @property_hash = query || {:ensure => :absent}
+ @property_hash[:ensure] = :absent if @property_hash.empty?
end
+ @property_hash.dup
+ end
end
diff --git a/lib/puppet/provider/package/aix.rb b/lib/puppet/provider/package/aix.rb
index dce4ccb42..134a84526 100644
--- a/lib/puppet/provider/package/aix.rb
+++ b/lib/puppet/provider/package/aix.rb
@@ -2,127 +2,127 @@ require 'puppet/provider/package'
require 'puppet/util/package'
Puppet::Type.type(:package).provide :aix, :parent => Puppet::Provider::Package do
- desc "Installation from AIX Software directory"
+ desc "Installation from AIX Software directory"
- # The commands we are using on an AIX box are installed standard
- # (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
- commands :lslpp => "/usr/bin/lslpp",
- :installp => "/usr/sbin/installp"
+ # The commands we are using on an AIX box are installed standard
+ # (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
+ commands :lslpp => "/usr/bin/lslpp",
+ :installp => "/usr/sbin/installp"
- # AIX supports versionable packages with and without a NIM server
- has_feature :versionable
+ # AIX supports versionable packages with and without a NIM server
+ has_feature :versionable
- confine :operatingsystem => [ :aix ]
- defaultfor :operatingsystem => :aix
+ confine :operatingsystem => [ :aix ]
+ defaultfor :operatingsystem => :aix
- attr_accessor :latest_info
+ attr_accessor :latest_info
- def self.srclistcmd(source)
- [ command(:installp), "-L", "-d", source ]
- end
-
- def self.prefetch(packages)
- raise Puppet::Error, "The aix provider can only be used by root" if Process.euid != 0
+ def self.srclistcmd(source)
+ [ command(:installp), "-L", "-d", source ]
+ end
- return unless packages.detect { |name, package| package.should(:ensure) == :latest }
+ def self.prefetch(packages)
+ raise Puppet::Error, "The aix provider can only be used by root" if Process.euid != 0
- sources = packages.collect { |name, package| package[:source] }.uniq
+ return unless packages.detect { |name, package| package.should(:ensure) == :latest }
- updates = {}
- sources.each do |source|
- execute(self.srclistcmd(source)).each do |line|
- if line =~ /^[^#][^:]*:([^:]*):([^:]*)/
- current = {}
- current[:name] = $1
- current[:version] = $2
- current[:source] = source
+ sources = packages.collect { |name, package| package[:source] }.uniq
- if updates.key?(current[:name])
- previous = updates[current[:name]]
+ updates = {}
+ sources.each do |source|
+ execute(self.srclistcmd(source)).each do |line|
+ if line =~ /^[^#][^:]*:([^:]*):([^:]*)/
+ current = {}
+ current[:name] = $1
+ current[:version] = $2
+ current[:source] = source
- updates[ current[:name] ] = current unless Puppet::Util::Package.versioncmp(previous[:version], current[:version]) == 1
+ if updates.key?(current[:name])
+ previous = updates[current[:name]]
- else
- updates[current[:name]] = current
- end
- end
- end
- end
+ updates[ current[:name] ] = current unless Puppet::Util::Package.versioncmp(previous[:version], current[:version]) == 1
- packages.each do |name, package|
- if info = updates[package[:name]]
- package.provider.latest_info = info[0]
- end
+ else
+ updates[current[:name]] = current
+ end
end
+ end
end
- def uninstall
- # Automatically process dependencies when installing/uninstalling
- # with the -g option to installp.
- installp "-gu", @resource[:name]
+ packages.each do |name, package|
+ if info = updates[package[:name]]
+ package.provider.latest_info = info[0]
+ end
end
+ end
- def install(useversion = true)
- unless source = @resource[:source]
- self.fail "A directory is required which will be used to find packages"
- end
+ def uninstall
+ # Automatically process dependencies when installing/uninstalling
+ # with the -g option to installp.
+ installp "-gu", @resource[:name]
+ end
- pkg = @resource[:name]
+ def install(useversion = true)
+ unless source = @resource[:source]
+ self.fail "A directory is required which will be used to find packages"
+ end
- pkg << " #{@resource.should(:ensure)}" if (! @resource.should(:ensure).is_a? Symbol) and useversion
+ pkg = @resource[:name]
- installp "-acgwXY", "-d", source, pkg
- end
+ pkg << " #{@resource.should(:ensure)}" if (! @resource.should(:ensure).is_a? Symbol) and useversion
- def self.pkglist(hash = {})
- cmd = [command(:lslpp), "-qLc"]
+ installp "-acgwXY", "-d", source, pkg
+ end
- if name = hash[:pkgname]
- cmd << name
- end
+ def self.pkglist(hash = {})
+ cmd = [command(:lslpp), "-qLc"]
- begin
- list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*)/).collect { |n,e|
- { :name => n, :ensure => e, :provider => self.name }
- }
- rescue Puppet::ExecutionFailure => detail
- if hash[:pkgname]
- return nil
- else
- raise Puppet::Error, "Could not list installed Packages: #{detail}"
- end
- end
+ if name = hash[:pkgname]
+ cmd << name
+ end
- if hash[:pkgname]
- return list.shift
- else
- return list
- end
+ begin
+ list = execute(cmd).scan(/^[^#][^:]*:([^:]*):([^:]*)/).collect { |n,e|
+ { :name => n, :ensure => e, :provider => self.name }
+ }
+ rescue Puppet::ExecutionFailure => detail
+ if hash[:pkgname]
+ return nil
+ else
+ raise Puppet::Error, "Could not list installed Packages: #{detail}"
+ end
end
- def self.instances
- pkglist.collect do |hash|
- new(hash)
- end
+ if hash[:pkgname]
+ return list.shift
+ else
+ return list
+ end
+ end
+
+ def self.instances
+ pkglist.collect do |hash|
+ new(hash)
end
+ end
- def latest
- upd = latest_info
+ def latest
+ upd = latest_info
- unless upd.nil?
- return "#{upd[:version]}"
- else
- raise Puppet::DevError, "Tried to get latest on a missing package" if properties[:ensure] == :absent
+ unless upd.nil?
+ return "#{upd[:version]}"
+ else
+ raise Puppet::DevError, "Tried to get latest on a missing package" if properties[:ensure] == :absent
- return properties[:ensure]
- end
+ return properties[:ensure]
end
+ end
- def query
- self.class.pkglist(:pkgname => @resource[:name])
- end
+ def query
+ self.class.pkglist(:pkgname => @resource[:name])
+ end
- def update
- self.install(false)
- end
+ def update
+ self.install(false)
+ end
end
diff --git a/lib/puppet/provider/package/appdmg.rb b/lib/puppet/provider/package/appdmg.rb
index 11858114d..a49700ef1 100644
--- a/lib/puppet/provider/package/appdmg.rb
+++ b/lib/puppet/provider/package/appdmg.rb
@@ -14,97 +14,97 @@
require 'puppet/provider/package'
Puppet::Type.type(:package).provide(:appdmg, :parent => Puppet::Provider::Package) do
- desc "Package management which copies application bundles to a target."
+ desc "Package management which copies application bundles to a target."
- confine :operatingsystem => :darwin
+ confine :operatingsystem => :darwin
- commands :hdiutil => "/usr/bin/hdiutil"
- commands :curl => "/usr/bin/curl"
- commands :ditto => "/usr/bin/ditto"
+ commands :hdiutil => "/usr/bin/hdiutil"
+ commands :curl => "/usr/bin/curl"
+ commands :ditto => "/usr/bin/ditto"
- # JJM We store a cookie for each installed .app.dmg in /var/db
- def self.instances_by_name
- Dir.entries("/var/db").find_all { |f|
- f =~ /^\.puppet_appdmg_installed_/
- }.collect do |f|
- name = f.sub(/^\.puppet_appdmg_installed_/, '')
- yield name if block_given?
- name
- end
+ # JJM We store a cookie for each installed .app.dmg in /var/db
+ def self.instances_by_name
+ Dir.entries("/var/db").find_all { |f|
+ f =~ /^\.puppet_appdmg_installed_/
+ }.collect do |f|
+ name = f.sub(/^\.puppet_appdmg_installed_/, '')
+ yield name if block_given?
+ name
end
+ end
- def self.instances
- instances_by_name.collect do |name|
- new(:name => name, :provider => :appdmg, :ensure => :installed)
- end
+ def self.instances
+ instances_by_name.collect do |name|
+ new(:name => name, :provider => :appdmg, :ensure => :installed)
end
+ end
- def self.installapp(source, name, orig_source)
- appname = File.basename(source);
- ditto "--rsrc", source, "/Applications/#{appname}"
- File.open("/var/db/.puppet_appdmg_installed_#{name}", "w") do |t|
- t.print "name: '#{name}'\n"
- t.print "source: '#{orig_source}'\n"
- end
+ def self.installapp(source, name, orig_source)
+ appname = File.basename(source);
+ ditto "--rsrc", source, "/Applications/#{appname}"
+ File.open("/var/db/.puppet_appdmg_installed_#{name}", "w") do |t|
+ t.print "name: '#{name}'\n"
+ t.print "source: '#{orig_source}'\n"
end
+ end
- def self.installpkgdmg(source, name)
- unless source =~ /\.dmg$/i
- self.fail "Mac OS X PKG DMG's must specificy a source string ending in .dmg"
- end
- require 'open-uri'
- require 'facter/util/plist'
+ def self.installpkgdmg(source, name)
+ unless source =~ /\.dmg$/i
+ self.fail "Mac OS X PKG DMG's must specificy a source string ending in .dmg"
+ end
+ require 'open-uri'
+ require 'facter/util/plist'
+ cached_source = source
+ if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source
+ cached_source = "/tmp/#{name}"
+ begin
+ curl "-o", cached_source, "-C", "-", "-k", "-s", "--url", source
+ Puppet.debug "Success: curl transfered [#{name}]"
+ rescue Puppet::ExecutionFailure
+ Puppet.debug "curl did not transfer [#{name}]. Falling back to slower open-uri transfer methods."
cached_source = source
- if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source
- cached_source = "/tmp/#{name}"
- begin
- curl "-o", cached_source, "-C", "-", "-k", "-s", "--url", source
- Puppet.debug "Success: curl transfered [#{name}]"
- rescue Puppet::ExecutionFailure
- Puppet.debug "curl did not transfer [#{name}]. Falling back to slower open-uri transfer methods."
- cached_source = source
- end
- end
+ end
+ end
- begin
- open(cached_source) do |dmg|
- xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-mountrandom", "/tmp", dmg.path
- ptable = Plist::parse_xml xml_str
- # JJM Filter out all mount-paths into a single array, discard the rest.
- mounts = ptable['system-entities'].collect { |entity|
- entity['mount-point']
- }.select { |mountloc|; mountloc }
- begin
- mounts.each do |fspath|
- Dir.entries(fspath).select { |f|
- f =~ /\.app$/i
- }.each do |pkg|
- installapp("#{fspath}/#{pkg}", name, source)
- end
- end
- ensure
- hdiutil "eject", mounts[0]
- end
+ begin
+ open(cached_source) do |dmg|
+ xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-mountrandom", "/tmp", dmg.path
+ ptable = Plist::parse_xml xml_str
+ # JJM Filter out all mount-paths into a single array, discard the rest.
+ mounts = ptable['system-entities'].collect { |entity|
+ entity['mount-point']
+ }.select { |mountloc|; mountloc }
+ begin
+ mounts.each do |fspath|
+ Dir.entries(fspath).select { |f|
+ f =~ /\.app$/i
+ }.each do |pkg|
+ installapp("#{fspath}/#{pkg}", name, source)
+ end
end
- ensure
- # JJM Remove the file if open-uri didn't already do so.
- File.unlink(cached_source) if File.exist?(cached_source)
- end
+ ensure
+ hdiutil "eject", mounts[0]
+ end
+ end
+ ensure
+ # JJM Remove the file if open-uri didn't already do so.
+ File.unlink(cached_source) if File.exist?(cached_source)
end
+ end
- def query
- FileTest.exists?("/var/db/.puppet_appdmg_installed_#{@resource[:name]}") ? {:name => @resource[:name], :ensure => :present} : nil
- end
+ def query
+ FileTest.exists?("/var/db/.puppet_appdmg_installed_#{@resource[:name]}") ? {:name => @resource[:name], :ensure => :present} : nil
+ end
- def install
- source = nil
- unless source = @resource[:source]
- self.fail "Mac OS X PKG DMG's must specify a package source."
- end
- unless name = @resource[:name]
- self.fail "Mac OS X PKG DMG's must specify a package name."
- end
- self.class.installpkgdmg(source,name)
+ def install
+ source = nil
+ unless source = @resource[:source]
+ self.fail "Mac OS X PKG DMG's must specify a package source."
+ end
+ unless name = @resource[:name]
+ self.fail "Mac OS X PKG DMG's must specify a package name."
end
+ self.class.installpkgdmg(source,name)
+ end
end
diff --git a/lib/puppet/provider/package/apple.rb b/lib/puppet/provider/package/apple.rb
index 613e14e5e..0946de47f 100755
--- a/lib/puppet/provider/package/apple.rb
+++ b/lib/puppet/provider/package/apple.rb
@@ -2,50 +2,50 @@ require 'puppet/provider/package'
# OS X Packaging sucks. We can install packages, but that's about it.
Puppet::Type.type(:package).provide :apple, :parent => Puppet::Provider::Package do
- desc "Package management based on OS X's builtin packaging system. This is
- essentially the simplest and least functional package system in existence --
- it only supports installation; no deletion or upgrades. The provider will
- automatically add the ``.pkg`` extension, so leave that off when specifying
- the package name."
+ desc "Package management based on OS X's builtin packaging system. This is
+ essentially the simplest and least functional package system in existence --
+ it only supports installation; no deletion or upgrades. The provider will
+ automatically add the ``.pkg`` extension, so leave that off when specifying
+ the package name."
- confine :operatingsystem => :darwin
- commands :installer => "/usr/sbin/installer"
+ confine :operatingsystem => :darwin
+ commands :installer => "/usr/sbin/installer"
- def self.instances
- instance_by_name.collect do |name|
+ def self.instances
+ instance_by_name.collect do |name|
- self.new(
+ self.new(
- :name => name,
- :provider => :apple,
+ :name => name,
+ :provider => :apple,
- :ensure => :installed
- )
- end
+ :ensure => :installed
+ )
end
-
- def self.instance_by_name
- Dir.entries("/Library/Receipts").find_all { |f|
- f =~ /\.pkg$/
- }.collect { |f|
- name = f.sub(/\.pkg/, '')
- yield name if block_given?
-
- name
- }
- end
-
- def query
- FileTest.exists?("/Library/Receipts/#{@resource[:name]}.pkg") ? {:name => @resource[:name], :ensure => :present} : nil
+ end
+
+ def self.instance_by_name
+ Dir.entries("/Library/Receipts").find_all { |f|
+ f =~ /\.pkg$/
+ }.collect { |f|
+ name = f.sub(/\.pkg/, '')
+ yield name if block_given?
+
+ name
+ }
+ end
+
+ def query
+ FileTest.exists?("/Library/Receipts/#{@resource[:name]}.pkg") ? {:name => @resource[:name], :ensure => :present} : nil
+ end
+
+ def install
+ source = nil
+ unless source = @resource[:source]
+ self.fail "Mac OS X packages must specify a package source"
end
- def install
- source = nil
- unless source = @resource[:source]
- self.fail "Mac OS X packages must specify a package source"
- end
-
- installer "-pkg", source, "-target", "/"
- end
+ installer "-pkg", source, "-target", "/"
+ end
end
diff --git a/lib/puppet/provider/package/apt.rb b/lib/puppet/provider/package/apt.rb
index deab23428..d055e7552 100755
--- a/lib/puppet/provider/package/apt.rb
+++ b/lib/puppet/provider/package/apt.rb
@@ -1,108 +1,108 @@
Puppet::Type.type(:package).provide :apt, :parent => :dpkg, :source => :dpkg do
- # Provide sorting functionality
- include Puppet::Util::Package
+ # Provide sorting functionality
+ include Puppet::Util::Package
- desc "Package management via ``apt-get``."
+ desc "Package management via ``apt-get``."
- has_feature :versionable
+ has_feature :versionable
- commands :aptget => "/usr/bin/apt-get"
- commands :aptcache => "/usr/bin/apt-cache"
- commands :preseed => "/usr/bin/debconf-set-selections"
+ commands :aptget => "/usr/bin/apt-get"
+ commands :aptcache => "/usr/bin/apt-cache"
+ commands :preseed => "/usr/bin/debconf-set-selections"
- defaultfor :operatingsystem => [:debian, :ubuntu]
+ defaultfor :operatingsystem => [:debian, :ubuntu]
- ENV['DEBIAN_FRONTEND'] = "noninteractive"
+ ENV['DEBIAN_FRONTEND'] = "noninteractive"
- # A derivative of DPKG; this is how most people actually manage
- # Debian boxes, and the only thing that differs is that it can
- # install packages from remote sites.
+ # A derivative of DPKG; this is how most people actually manage
+ # Debian boxes, and the only thing that differs is that it can
+ # install packages from remote sites.
- def checkforcdrom
- unless defined?(@@checkedforcdrom)
- if FileTest.exists? "/etc/apt/sources.list"
- @@checkedforcdrom = !!(File.read("/etc/apt/sources.list") =~ /^[^#]*cdrom:/)
- else
- # This is basically a pathalogical case, but we'll just
- # ignore it
- @@checkedforcdrom = false
- end
- end
+ def checkforcdrom
+ unless defined?(@@checkedforcdrom)
+ if FileTest.exists? "/etc/apt/sources.list"
+ @@checkedforcdrom = !!(File.read("/etc/apt/sources.list") =~ /^[^#]*cdrom:/)
+ else
+ # This is basically a pathalogical case, but we'll just
+ # ignore it
+ @@checkedforcdrom = false
+ end
+ end
- if @@checkedforcdrom and @resource[:allowcdrom] != :true
- raise Puppet::Error,
- "/etc/apt/sources.list contains a cdrom source; not installing. Use 'allowcdrom' to override this failure."
- end
+ if @@checkedforcdrom and @resource[:allowcdrom] != :true
+ raise Puppet::Error,
+ "/etc/apt/sources.list contains a cdrom source; not installing. Use 'allowcdrom' to override this failure."
+ end
+ end
+
+ # Install a package using 'apt-get'. This function needs to support
+ # installing a specific version.
+ def install
+ self.run_preseed if @resource[:responsefile]
+ should = @resource[:ensure]
+
+ checkforcdrom
+ cmd = %w{-q -y}
+
+ keep = ""
+ if config = @resource[:configfiles]
+ if config == :keep
+ cmd << "-o" << 'DPkg::Options::=--force-confold'
+ else
+ cmd << "-o" << 'DPkg::Options::=--force-confnew'
+ end
end
- # Install a package using 'apt-get'. This function needs to support
- # installing a specific version.
- def install
- self.run_preseed if @resource[:responsefile]
- should = @resource[:ensure]
-
- checkforcdrom
- cmd = %w{-q -y}
-
- keep = ""
- if config = @resource[:configfiles]
- if config == :keep
- cmd << "-o" << 'DPkg::Options::=--force-confold'
- else
- cmd << "-o" << 'DPkg::Options::=--force-confnew'
- end
- end
-
- str = @resource[:name]
- case should
- when true, false, Symbol
- # pass
- else
- # Add the package version and --force-yes option
- str += "=#{should}"
- cmd << "--force-yes"
- end
-
- cmd << :install << str
-
- aptget(*cmd)
+ str = @resource[:name]
+ case should
+ when true, false, Symbol
+ # pass
+ else
+ # Add the package version and --force-yes option
+ str += "=#{should}"
+ cmd << "--force-yes"
end
- # What's the latest package version available?
- def latest
- output = aptcache :policy, @resource[:name]
+ cmd << :install << str
- if output =~ /Candidate:\s+(\S+)\s/
- return $1
- else
- self.err "Could not find latest version"
- return nil
- end
- end
+ aptget(*cmd)
+ end
- #
- # preseeds answers to dpkg-set-selection from the "responsefile"
- #
- def run_preseed
- if response = @resource[:responsefile] and FileTest.exist?(response)
- self.info("Preseeding #{response} to debconf-set-selections")
-
- preseed response
- else
- self.info "No responsefile specified or non existant, not preseeding anything"
- end
- end
+ # What's the latest package version available?
+ def latest
+ output = aptcache :policy, @resource[:name]
- def uninstall
- self.run_preseed if @resource[:responsefile]
- aptget "-y", "-q", :remove, @resource[:name]
+ if output =~ /Candidate:\s+(\S+)\s/
+ return $1
+ else
+ self.err "Could not find latest version"
+ return nil
end
-
- def purge
- self.run_preseed if @resource[:responsefile]
- aptget '-y', '-q', :remove, '--purge', @resource[:name]
- # workaround a "bug" in apt, that already removed packages are not purged
- super
+ end
+
+ #
+ # preseeds answers to dpkg-set-selection from the "responsefile"
+ #
+ def run_preseed
+ if response = @resource[:responsefile] and FileTest.exist?(response)
+ self.info("Preseeding #{response} to debconf-set-selections")
+
+ preseed response
+ else
+ self.info "No responsefile specified or non existant, not preseeding anything"
end
+ end
+
+ def uninstall
+ self.run_preseed if @resource[:responsefile]
+ aptget "-y", "-q", :remove, @resource[:name]
+ end
+
+ def purge
+ self.run_preseed if @resource[:responsefile]
+ aptget '-y', '-q', :remove, '--purge', @resource[:name]
+ # workaround a "bug" in apt, that already removed packages are not purged
+ super
+ end
end
diff --git a/lib/puppet/provider/package/aptitude.rb b/lib/puppet/provider/package/aptitude.rb
index 5529535de..557e657a4 100755
--- a/lib/puppet/provider/package/aptitude.rb
+++ b/lib/puppet/provider/package/aptitude.rb
@@ -1,29 +1,29 @@
Puppet::Type.type(:package).provide :aptitude, :parent => :apt, :source => :dpkg do
- desc "Package management via ``aptitude``."
+ desc "Package management via ``aptitude``."
- has_feature :versionable
+ has_feature :versionable
- commands :aptitude => "/usr/bin/aptitude"
- commands :aptcache => "/usr/bin/apt-cache"
+ commands :aptitude => "/usr/bin/aptitude"
+ commands :aptcache => "/usr/bin/apt-cache"
- ENV['DEBIAN_FRONTEND'] = "noninteractive"
+ ENV['DEBIAN_FRONTEND'] = "noninteractive"
- def aptget(*args)
- args.flatten!
- # Apparently aptitude hasn't always supported a -q flag.
- args.delete("-q") if args.include?("-q")
- output = aptitude(*args)
+ def aptget(*args)
+ args.flatten!
+ # Apparently aptitude hasn't always supported a -q flag.
+ args.delete("-q") if args.include?("-q")
+ output = aptitude(*args)
- # Yay, stupid aptitude doesn't throw an error when the package is missing.
- if args.include?(:install) and output =~ /Couldn't find any package/
- raise Puppet::Error.new(
- "Could not find package #{self.name}"
- )
- end
+ # Yay, stupid aptitude doesn't throw an error when the package is missing.
+ if args.include?(:install) and output =~ /Couldn't find any package/
+ raise Puppet::Error.new(
+ "Could not find package #{self.name}"
+ )
end
+ end
- def purge
- aptitude '-y', 'purge', @resource[:name]
- end
+ def purge
+ aptitude '-y', 'purge', @resource[:name]
+ end
end
diff --git a/lib/puppet/provider/package/aptrpm.rb b/lib/puppet/provider/package/aptrpm.rb
index 42f7e706c..d7842089f 100644
--- a/lib/puppet/provider/package/aptrpm.rb
+++ b/lib/puppet/provider/package/aptrpm.rb
@@ -1,84 +1,84 @@
Puppet::Type.type(:package).provide :aptrpm, :parent => :rpm, :source => :rpm do
- # Provide sorting functionality
- include Puppet::Util::Package
-
- desc "Package management via ``apt-get`` ported to ``rpm``."
-
- has_feature :versionable
-
- commands :aptget => "apt-get"
- commands :aptcache => "apt-cache"
- commands :rpm => "rpm"
-
- if command('rpm')
- confine :true => begin
- rpm('-ql', 'rpm')
- rescue Puppet::ExecutionFailure
- false
- else
- true
- end
+ # Provide sorting functionality
+ include Puppet::Util::Package
+
+ desc "Package management via ``apt-get`` ported to ``rpm``."
+
+ has_feature :versionable
+
+ commands :aptget => "apt-get"
+ commands :aptcache => "apt-cache"
+ commands :rpm => "rpm"
+
+ if command('rpm')
+ confine :true => begin
+ rpm('-ql', 'rpm')
+ rescue Puppet::ExecutionFailure
+ false
+ else
+ true
+ end
+ end
+
+ # Install a package using 'apt-get'. This function needs to support
+ # installing a specific version.
+ def install
+ should = @resource.should(:ensure)
+
+ str = @resource[:name]
+ case should
+ when true, false, Symbol
+ # pass
+ else
+ # Add the package version
+ str += "=#{should}"
end
+ cmd = %w{-q -y}
- # Install a package using 'apt-get'. This function needs to support
- # installing a specific version.
- def install
- should = @resource.should(:ensure)
+ cmd << 'install' << str
- str = @resource[:name]
- case should
- when true, false, Symbol
- # pass
- else
- # Add the package version
- str += "=#{should}"
- end
- cmd = %w{-q -y}
+ aptget(*cmd)
+ end
- cmd << 'install' << str
+ # What's the latest package version available?
+ def latest
+ output = aptcache :showpkg, @resource[:name]
- aptget(*cmd)
- end
-
- # What's the latest package version available?
- def latest
- output = aptcache :showpkg, @resource[:name]
-
- if output =~ /Versions:\s*\n((\n|.)+)^$/
- versions = $1
- available_versions = versions.split(/\n/).collect { |version|
- if version =~ /^([^\(]+)\(/
- $1
- else
- self.warning "Could not match version '#{version}'"
- nil
- end
- }.reject { |vers| vers.nil? }.sort { |a,b|
- versioncmp(a,b)
- }
-
- if available_versions.length == 0
- self.debug "No latest version"
- print output if Puppet[:debug]
- end
-
- # Get the latest and greatest version number
- return available_versions.pop
+ if output =~ /Versions:\s*\n((\n|.)+)^$/
+ versions = $1
+ available_versions = versions.split(/\n/).collect { |version|
+ if version =~ /^([^\(]+)\(/
+ $1
else
- self.err "Could not match string"
+ self.warning "Could not match version '#{version}'"
+ nil
end
+ }.reject { |vers| vers.nil? }.sort { |a,b|
+ versioncmp(a,b)
+ }
+
+ if available_versions.length == 0
+ self.debug "No latest version"
+ print output if Puppet[:debug]
+ end
+
+ # Get the latest and greatest version number
+ return available_versions.pop
+ else
+ self.err "Could not match string"
end
+ end
- def update
- self.install
- end
+ def update
+ self.install
+ end
- def uninstall
- aptget "-y", "-q", 'remove', @resource[:name]
- end
+ def uninstall
+ aptget "-y", "-q", 'remove', @resource[:name]
+ end
- def purge
- aptget '-y', '-q', 'remove', '--purge', @resource[:name]
- end
+ def purge
+ aptget '-y', '-q', 'remove', '--purge', @resource[:name]
+ end
end
diff --git a/lib/puppet/provider/package/blastwave.rb b/lib/puppet/provider/package/blastwave.rb
index d1cfe6f2b..9f1f1ec19 100755
--- a/lib/puppet/provider/package/blastwave.rb
+++ b/lib/puppet/provider/package/blastwave.rb
@@ -1,112 +1,112 @@
# Packaging using Blastwave's pkg-get program.
Puppet::Type.type(:package).provide :blastwave, :parent => :sun, :source => :sun do
- desc "Package management using Blastwave.org's ``pkg-get`` command on Solaris."
- pkgget = "pkg-get"
- pkgget = "/opt/csw/bin/pkg-get" if FileTest.executable?("/opt/csw/bin/pkg-get")
+ desc "Package management using Blastwave.org's ``pkg-get`` command on Solaris."
+ pkgget = "pkg-get"
+ pkgget = "/opt/csw/bin/pkg-get" if FileTest.executable?("/opt/csw/bin/pkg-get")
- confine :operatingsystem => :solaris
+ confine :operatingsystem => :solaris
- commands :pkgget => pkgget
+ commands :pkgget => pkgget
- def pkgget_with_cat(*args)
- Puppet::Util::Execution::withenv(:PAGER => "/usr/bin/cat") { pkgget(*args) }
- end
-
- def self.extended(mod)
- unless command(:pkgget) != "pkg-get"
- raise Puppet::Error,
- "The pkg-get command is missing; blastwave packaging unavailable"
- end
+ def pkgget_with_cat(*args)
+ Puppet::Util::Execution::withenv(:PAGER => "/usr/bin/cat") { pkgget(*args) }
+ end
- unless FileTest.exists?("/var/pkg-get/admin")
- Puppet.notice "It is highly recommended you create '/var/pkg-get/admin'."
- Puppet.notice "See /var/pkg-get/admin-fullauto"
- end
+ def self.extended(mod)
+ unless command(:pkgget) != "pkg-get"
+ raise Puppet::Error,
+ "The pkg-get command is missing; blastwave packaging unavailable"
end
- def self.instances(hash = {})
- blastlist(hash).collect do |bhash|
- bhash.delete(:avail)
- new(bhash)
- end
+ unless FileTest.exists?("/var/pkg-get/admin")
+ Puppet.notice "It is highly recommended you create '/var/pkg-get/admin'."
+ Puppet.notice "See /var/pkg-get/admin-fullauto"
end
+ end
- # Turn our blastwave listing into a bunch of hashes.
- def self.blastlist(hash)
- command = ["-c"]
-
- command << hash[:justme] if hash[:justme]
-
- output = Puppet::Util::Execution::withenv(:PAGER => "/usr/bin/cat") { pkgget command }
+ def self.instances(hash = {})
+ blastlist(hash).collect do |bhash|
+ bhash.delete(:avail)
+ new(bhash)
+ end
+ end
- list = output.split("\n").collect do |line|
- next if line =~ /^#/
- next if line =~ /^WARNING/
- next if line =~ /localrev\s+remoterev/
+ # Turn our blastwave listing into a bunch of hashes.
+ def self.blastlist(hash)
+ command = ["-c"]
- blastsplit(line)
- end.reject { |h| h.nil? }
+ command << hash[:justme] if hash[:justme]
- if hash[:justme]
- return list[0]
- else
- list.reject! { |h|
- h[:ensure] == :absent
- }
- return list
- end
+ output = Puppet::Util::Execution::withenv(:PAGER => "/usr/bin/cat") { pkgget command }
- end
+ list = output.split("\n").collect do |line|
+ next if line =~ /^#/
+ next if line =~ /^WARNING/
+ next if line =~ /localrev\s+remoterev/
- # Split the different lines into hashes.
- def self.blastsplit(line)
- if line =~ /\s*(\S+)\s+((\[Not installed\])|(\S+))\s+(\S+)/
- hash = {}
- hash[:name] = $1
- hash[:ensure] = if $2 == "[Not installed]"
- :absent
- else
- $2
- end
- hash[:avail] = $5
-
- hash[:avail] = hash[:ensure] if hash[:avail] == "SAME"
-
- # Use the name method, so it works with subclasses.
- hash[:provider] = self.name
-
- return hash
- else
- Puppet.warning "Cannot match #{line}"
- return nil
- end
- end
+ blastsplit(line)
+ end.reject { |h| h.nil? }
- def install
- pkgget_with_cat "-f", :install, @resource[:name]
+ if hash[:justme]
+ return list[0]
+ else
+ list.reject! { |h|
+ h[:ensure] == :absent
+ }
+ return list
end
- # Retrieve the version from the current package file.
- def latest
- hash = self.class.blastlist(:justme => @resource[:name])
- hash[:avail]
+ end
+
+ # Split the different lines into hashes.
+ def self.blastsplit(line)
+ if line =~ /\s*(\S+)\s+((\[Not installed\])|(\S+))\s+(\S+)/
+ hash = {}
+ hash[:name] = $1
+ hash[:ensure] = if $2 == "[Not installed]"
+ :absent
+ else
+ $2
+ end
+ hash[:avail] = $5
+
+ hash[:avail] = hash[:ensure] if hash[:avail] == "SAME"
+
+ # Use the name method, so it works with subclasses.
+ hash[:provider] = self.name
+
+ return hash
+ else
+ Puppet.warning "Cannot match #{line}"
+ return nil
end
-
- def query
- if hash = self.class.blastlist(:justme => @resource[:name])
- hash
- else
- {:ensure => :absent}
- end
+ end
+
+ def install
+ pkgget_with_cat "-f", :install, @resource[:name]
+ end
+
+ # Retrieve the version from the current package file.
+ def latest
+ hash = self.class.blastlist(:justme => @resource[:name])
+ hash[:avail]
+ end
+
+ def query
+ if hash = self.class.blastlist(:justme => @resource[:name])
+ hash
+ else
+ {:ensure => :absent}
end
+ end
- # Remove the old package, and install the new one
- def update
- pkgget_with_cat "-f", :upgrade, @resource[:name]
- end
+ # Remove the old package, and install the new one
+ def update
+ pkgget_with_cat "-f", :upgrade, @resource[:name]
+ end
- def uninstall
- pkgget_with_cat "-f", :remove, @resource[:name]
- end
+ def uninstall
+ pkgget_with_cat "-f", :remove, @resource[:name]
+ end
end
diff --git a/lib/puppet/provider/package/darwinport.rb b/lib/puppet/provider/package/darwinport.rb
index c746cc3b3..c5f9ba28f 100755
--- a/lib/puppet/provider/package/darwinport.rb
+++ b/lib/puppet/provider/package/darwinport.rb
@@ -1,86 +1,86 @@
require 'puppet/provider/package'
Puppet::Type.type(:package).provide :darwinport, :parent => Puppet::Provider::Package do
- desc "Package management using DarwinPorts on OS X."
-
- confine :operatingsystem => :darwin
- commands :port => "/opt/local/bin/port"
-
- def self.eachpkgashash
- # list out all of the packages
- open("| #{command(:port)} list installed") { |process|
- regex = %r{(\S+)\s+@(\S+)\s+(\S+)}
- fields = [:name, :ensure, :location]
- hash = {}
-
- # now turn each returned line into a package object
- process.each { |line|
- hash.clear
-
- if match = regex.match(line)
- fields.zip(match.captures) { |field,value|
- hash[field] = value
- }
-
- hash.delete :location
- hash[:provider] = self.name
- yield hash.dup
- else
- raise Puppet::DevError,
- "Failed to match dpkg line #{line}"
- end
- }
- }
- end
-
- def self.instances
- packages = []
-
- eachpkgashash do |hash|
- packages << new(hash)
+ desc "Package management using DarwinPorts on OS X."
+
+ confine :operatingsystem => :darwin
+ commands :port => "/opt/local/bin/port"
+
+ def self.eachpkgashash
+ # list out all of the packages
+ open("| #{command(:port)} list installed") { |process|
+ regex = %r{(\S+)\s+@(\S+)\s+(\S+)}
+ fields = [:name, :ensure, :location]
+ hash = {}
+
+ # now turn each returned line into a package object
+ process.each { |line|
+ hash.clear
+
+ if match = regex.match(line)
+ fields.zip(match.captures) { |field,value|
+ hash[field] = value
+ }
+
+ hash.delete :location
+ hash[:provider] = self.name
+ yield hash.dup
+ else
+ raise Puppet::DevError,
+ "Failed to match dpkg line #{line}"
end
+ }
+ }
+ end
- packages
- end
+ def self.instances
+ packages = []
- def install
- should = @resource.should(:ensure)
-
- # Seems like you can always say 'upgrade'
- output = port "upgrade", @resource[:name]
- if output =~ /^Error: No port/
- raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
- end
+ eachpkgashash do |hash|
+ packages << new(hash)
end
- def query
- version = nil
- self.class.eachpkgashash do |hash|
- return hash if hash[:name] == @resource[:name]
- end
+ packages
+ end
- nil
+ def install
+ should = @resource.should(:ensure)
+
+ # Seems like you can always say 'upgrade'
+ output = port "upgrade", @resource[:name]
+ if output =~ /^Error: No port/
+ raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
end
+ end
- def latest
- info = port :search, "^#{@resource[:name]}$"
+ def query
+ version = nil
+ self.class.eachpkgashash do |hash|
+ return hash if hash[:name] == @resource[:name]
+ end
- if $CHILD_STATUS != 0 or info =~ /^Error/
- return nil
- end
+ nil
+ end
- ary = info.split(/\s+/)
- version = ary[2].sub(/^@/, '')
+ def latest
+ info = port :search, "^#{@resource[:name]}$"
- version
+ if $CHILD_STATUS != 0 or info =~ /^Error/
+ return nil
end
- def uninstall
- port :uninstall, @resource[:name]
- end
+ ary = info.split(/\s+/)
+ version = ary[2].sub(/^@/, '')
- def update
- install
- end
+ version
+ end
+
+ def uninstall
+ port :uninstall, @resource[:name]
+ end
+
+ def update
+ install
+ end
end
diff --git a/lib/puppet/provider/package/dpkg.rb b/lib/puppet/provider/package/dpkg.rb
index 06d3f58f8..bee63bfba 100755
--- a/lib/puppet/provider/package/dpkg.rb
+++ b/lib/puppet/provider/package/dpkg.rb
@@ -1,156 +1,156 @@
require 'puppet/provider/package'
Puppet::Type.type(:package).provide :dpkg, :parent => Puppet::Provider::Package do
- desc "Package management via ``dpkg``. Because this only uses ``dpkg``
- and not ``apt``, you must specify the source of any packages you want
- to manage."
-
- has_feature :holdable
-
- commands :dpkg => "/usr/bin/dpkg"
- commands :dpkg_deb => "/usr/bin/dpkg-deb"
- commands :dpkgquery => "/usr/bin/dpkg-query"
-
- def self.instances
- packages = []
-
- # list out all of the packages
- cmd = "#{command(:dpkgquery)} -W --showformat '${Status} ${Package} ${Version}\\n'"
- Puppet.debug "Executing '#{cmd}'"
- execpipe(cmd) do |process|
- # our regex for matching dpkg output
- regex = %r{^(\S+) +(\S+) +(\S+) (\S+) (\S*)$}
- fields = [:desired, :error, :status, :name, :ensure]
- hash = {}
-
- # now turn each returned line into a package object
- process.each { |line|
- if hash = parse_line(line)
- packages << new(hash)
- end
- }
+ desc "Package management via ``dpkg``. Because this only uses ``dpkg``
+ and not ``apt``, you must specify the source of any packages you want
+ to manage."
+
+ has_feature :holdable
+
+ commands :dpkg => "/usr/bin/dpkg"
+ commands :dpkg_deb => "/usr/bin/dpkg-deb"
+ commands :dpkgquery => "/usr/bin/dpkg-query"
+
+ def self.instances
+ packages = []
+
+ # list out all of the packages
+ cmd = "#{command(:dpkgquery)} -W --showformat '${Status} ${Package} ${Version}\\n'"
+ Puppet.debug "Executing '#{cmd}'"
+ execpipe(cmd) do |process|
+ # our regex for matching dpkg output
+ regex = %r{^(\S+) +(\S+) +(\S+) (\S+) (\S*)$}
+ fields = [:desired, :error, :status, :name, :ensure]
+ hash = {}
+
+ # now turn each returned line into a package object
+ process.each { |line|
+ if hash = parse_line(line)
+ packages << new(hash)
end
-
- packages
+ }
end
- self::REGEX = %r{^(\S+) +(\S+) +(\S+) (\S+) (\S*)$}
- self::FIELDS = [:desired, :error, :status, :name, :ensure]
+ packages
+ end
- def self.parse_line(line)
- if match = self::REGEX.match(line)
- hash = {}
+ self::REGEX = %r{^(\S+) +(\S+) +(\S+) (\S+) (\S*)$}
+ self::FIELDS = [:desired, :error, :status, :name, :ensure]
- self::FIELDS.zip(match.captures) { |field,value|
- hash[field] = value
- }
+ def self.parse_line(line)
+ if match = self::REGEX.match(line)
+ hash = {}
- hash[:provider] = self.name
+ self::FIELDS.zip(match.captures) { |field,value|
+ hash[field] = value
+ }
- if hash[:status] == 'not-installed'
- hash[:ensure] = :purged
- elsif ['config-files', 'half-installed', 'unpacked', 'half-configured'].include?(hash[:status])
- hash[:ensure] = :absent
- end
- hash[:ensure] = :held if hash[:desired] == 'hold'
- else
- Puppet.warning "Failed to match dpkg-query line #{line.inspect}"
- return nil
- end
+ hash[:provider] = self.name
- hash
+ if hash[:status] == 'not-installed'
+ hash[:ensure] = :purged
+ elsif ['config-files', 'half-installed', 'unpacked', 'half-configured'].include?(hash[:status])
+ hash[:ensure] = :absent
+ end
+ hash[:ensure] = :held if hash[:desired] == 'hold'
+ else
+ Puppet.warning "Failed to match dpkg-query line #{line.inspect}"
+ return nil
end
- def install
- unless file = @resource[:source]
- raise ArgumentError, "You cannot install dpkg packages without a source"
- end
+ hash
+ end
- args = []
+ def install
+ unless file = @resource[:source]
+ raise ArgumentError, "You cannot install dpkg packages without a source"
+ end
- # We always unhold when installing to remove any prior hold.
- self.unhold
+ args = []
- if @resource[:configfiles] == :keep
- args << '--force-confold'
- else
- args << '--force-confnew'
- end
- args << '-i' << file
+ # We always unhold when installing to remove any prior hold.
+ self.unhold
- dpkg(*args)
+ if @resource[:configfiles] == :keep
+ args << '--force-confold'
+ else
+ args << '--force-confnew'
end
+ args << '-i' << file
- def update
- self.install
- end
+ dpkg(*args)
+ end
- # Return the version from the package.
- def latest
- output = dpkg_deb "--show", @resource[:source]
- matches = /^(\S+)\t(\S+)$/.match(output).captures
- warning "source doesn't contain named package, but #{matches[0]}" unless matches[0].match( Regexp.escape(@resource[:name]) )
- matches[1]
- end
+ def update
+ self.install
+ end
- def query
- packages = []
+ # Return the version from the package.
+ def latest
+ output = dpkg_deb "--show", @resource[:source]
+ matches = /^(\S+)\t(\S+)$/.match(output).captures
+ warning "source doesn't contain named package, but #{matches[0]}" unless matches[0].match( Regexp.escape(@resource[:name]) )
+ matches[1]
+ end
- fields = [:desired, :error, :status, :name, :ensure]
+ def query
+ packages = []
- hash = {}
+ fields = [:desired, :error, :status, :name, :ensure]
- # list out our specific package
- begin
+ hash = {}
- output = dpkgquery(
- "-W", "--showformat",
-
- '${Status} ${Package} ${Version}\\n', @resource[:name]
- )
- rescue Puppet::ExecutionFailure
- # dpkg-query exits 1 if the package is not found.
- return {:ensure => :purged, :status => 'missing', :name => @resource[:name], :error => 'ok'}
+ # list out our specific package
+ begin
- end
-
- hash = self.class.parse_line(output) || {:ensure => :absent, :status => 'missing', :name => @resource[:name], :error => 'ok'}
-
- if hash[:error] != "ok"
- raise Puppet::Error.new(
- "Package #{hash[:name]}, version #{hash[:ensure]} is in error state: #{hash[:error]}"
- )
- end
+ output = dpkgquery(
+ "-W", "--showformat",
+
+ '${Status} ${Package} ${Version}\\n', @resource[:name]
+ )
+ rescue Puppet::ExecutionFailure
+ # dpkg-query exits 1 if the package is not found.
+ return {:ensure => :purged, :status => 'missing', :name => @resource[:name], :error => 'ok'}
- hash
end
- def uninstall
- dpkg "-r", @resource[:name]
- end
+ hash = self.class.parse_line(output) || {:ensure => :absent, :status => 'missing', :name => @resource[:name], :error => 'ok'}
- def purge
- dpkg "--purge", @resource[:name]
+ if hash[:error] != "ok"
+ raise Puppet::Error.new(
+ "Package #{hash[:name]}, version #{hash[:ensure]} is in error state: #{hash[:error]}"
+ )
end
- def hold
- self.install
- begin
- Tempfile.open('puppet_dpkg_set_selection') { |tmpfile|
- tmpfile.write("#{@resource[:name]} hold\n")
- tmpfile.flush
- execute([:dpkg, "--set-selections"], :stdinfile => tmpfile.path.to_s)
- }
- end
+ hash
+ end
+
+ def uninstall
+ dpkg "-r", @resource[:name]
+ end
+
+ def purge
+ dpkg "--purge", @resource[:name]
+ end
+
+ def hold
+ self.install
+ begin
+ Tempfile.open('puppet_dpkg_set_selection') { |tmpfile|
+ tmpfile.write("#{@resource[:name]} hold\n")
+ tmpfile.flush
+ execute([:dpkg, "--set-selections"], :stdinfile => tmpfile.path.to_s)
+ }
end
-
- def unhold
- begin
- Tempfile.open('puppet_dpkg_set_selection') { |tmpfile|
- tmpfile.write("#{@resource[:name]} install\n")
- tmpfile.flush
- execute([:dpkg, "--set-selections"], :stdinfile => tmpfile.path.to_s)
- }
- end
+ end
+
+ def unhold
+ begin
+ Tempfile.open('puppet_dpkg_set_selection') { |tmpfile|
+ tmpfile.write("#{@resource[:name]} install\n")
+ tmpfile.flush
+ execute([:dpkg, "--set-selections"], :stdinfile => tmpfile.path.to_s)
+ }
end
+ end
end
diff --git a/lib/puppet/provider/package/fink.rb b/lib/puppet/provider/package/fink.rb
index a7310b00a..5cf47860e 100755
--- a/lib/puppet/provider/package/fink.rb
+++ b/lib/puppet/provider/package/fink.rb
@@ -1,82 +1,82 @@
Puppet::Type.type(:package).provide :fink, :parent => :dpkg, :source => :dpkg do
- # Provide sorting functionality
- include Puppet::Util::Package
-
- desc "Package management via ``fink``."
-
- commands :fink => "/sw/bin/fink"
- commands :aptget => "/sw/bin/apt-get"
- commands :aptcache => "/sw/bin/apt-cache"
- commands :dpkgquery => "/sw/bin/dpkg-query"
+ # Provide sorting functionality
+ include Puppet::Util::Package
+
+ desc "Package management via ``fink``."
+
+ commands :fink => "/sw/bin/fink"
+ commands :aptget => "/sw/bin/apt-get"
+ commands :aptcache => "/sw/bin/apt-cache"
+ commands :dpkgquery => "/sw/bin/dpkg-query"
+
+ has_feature :versionable
+
+ # A derivative of DPKG; this is how most people actually manage
+ # Debian boxes, and the only thing that differs is that it can
+ # install packages from remote sites.
+
+ def finkcmd(*args)
+ fink(*args)
+ end
+
+ # Install a package using 'apt-get'. This function needs to support
+ # installing a specific version.
+ def install
+ self.run_preseed if @resource[:responsefile]
+ should = @resource.should(:ensure)
+
+ str = @resource[:name]
+ case should
+ when true, false, Symbol
+ # pass
+ else
+ # Add the package version
+ str += "=#{should}"
+ end
+ cmd = %w{-b -q -y}
- has_feature :versionable
+ keep = ""
- # A derivative of DPKG; this is how most people actually manage
- # Debian boxes, and the only thing that differs is that it can
- # install packages from remote sites.
+ cmd << :install << str
- def finkcmd(*args)
- fink(*args)
- end
+ finkcmd(cmd)
+ end
- # Install a package using 'apt-get'. This function needs to support
- # installing a specific version.
- def install
- self.run_preseed if @resource[:responsefile]
- should = @resource.should(:ensure)
+ # What's the latest package version available?
+ def latest
+ output = aptcache :policy, @resource[:name]
- str = @resource[:name]
- case should
- when true, false, Symbol
- # pass
+ if output =~ /Candidate:\s+(\S+)\s/
+ return $1
else
- # Add the package version
- str += "=#{should}"
+ self.err "Could not find latest version"
+ return nil
+ end
end
- cmd = %w{-b -q -y}
-
- keep = ""
- cmd << :install << str
+ #
+ # preseeds answers to dpkg-set-selection from the "responsefile"
+ #
+ def run_preseed
+ if response = @resource[:responsefile] and FileTest.exists?(response)
+ self.info("Preseeding #{response} to debconf-set-selections")
- finkcmd(cmd)
+ preseed response
+ else
+ self.info "No responsefile specified or non existant, not preseeding anything"
end
+ end
- # What's the latest package version available?
- def latest
- output = aptcache :policy, @resource[:name]
-
- if output =~ /Candidate:\s+(\S+)\s/
- return $1
- else
- self.err "Could not find latest version"
- return nil
- end
- end
-
- #
- # preseeds answers to dpkg-set-selection from the "responsefile"
- #
- def run_preseed
- if response = @resource[:responsefile] and FileTest.exists?(response)
- self.info("Preseeding #{response} to debconf-set-selections")
-
- preseed response
- else
- self.info "No responsefile specified or non existant, not preseeding anything"
- end
- end
-
- def update
- self.install
- end
+ def update
+ self.install
+ end
- def uninstall
- finkcmd "-y", "-q", :remove, @model[:name]
- end
+ def uninstall
+ finkcmd "-y", "-q", :remove, @model[:name]
+ end
- def purge
- aptget '-y', '-q', 'remove', '--purge', @resource[:name]
- end
+ def purge
+ aptget '-y', '-q', 'remove', '--purge', @resource[:name]
+ end
end
diff --git a/lib/puppet/provider/package/freebsd.rb b/lib/puppet/provider/package/freebsd.rb
index 95d15c735..2f012a4ed 100755
--- a/lib/puppet/provider/package/freebsd.rb
+++ b/lib/puppet/provider/package/freebsd.rb
@@ -1,50 +1,50 @@
Puppet::Type.type(:package).provide :freebsd, :parent => :openbsd do
- desc "The specific form of package management on FreeBSD. This is an
- extremely quirky packaging system, in that it freely mixes between
- ports and packages. Apparently all of the tools are written in Ruby,
- so there are plans to rewrite this support to directly use those
- libraries."
+ desc "The specific form of package management on FreeBSD. This is an
+ extremely quirky packaging system, in that it freely mixes between
+ ports and packages. Apparently all of the tools are written in Ruby,
+ so there are plans to rewrite this support to directly use those
+ libraries."
- commands :pkginfo => "/usr/sbin/pkg_info",
- :pkgadd => "/usr/sbin/pkg_add",
- :pkgdelete => "/usr/sbin/pkg_delete"
+ commands :pkginfo => "/usr/sbin/pkg_info",
+ :pkgadd => "/usr/sbin/pkg_add",
+ :pkgdelete => "/usr/sbin/pkg_delete"
- confine :operatingsystem => :freebsd
+ confine :operatingsystem => :freebsd
- def self.listcmd
- command(:pkginfo)
- end
+ def self.listcmd
+ command(:pkginfo)
+ end
- def install
- should = @resource.should(:ensure)
-
- if @resource[:source] =~ /\/$/
- if @resource[:source] =~ /^(ftp|https?):/
- withenv :PACKAGESITE => @resource[:source] do
- pkgadd "-r", @resource[:name]
- end
- else
- withenv :PKG_PATH => @resource[:source] do
- pkgadd @resource[:name]
- end
- end
- else
- Puppet.warning "source is defined but does not have trailing slash, ignoring #{@resource[:source]}" if @resource[:source]
- pkgadd "-r", @resource[:name]
- end
- end
+ def install
+ should = @resource.should(:ensure)
- def query
- self.class.instances.each do |provider|
- if provider.name == @resource.name
- return provider.properties
- end
+ if @resource[:source] =~ /\/$/
+ if @resource[:source] =~ /^(ftp|https?):/
+ withenv :PACKAGESITE => @resource[:source] do
+ pkgadd "-r", @resource[:name]
end
- nil
+ else
+ withenv :PKG_PATH => @resource[:source] do
+ pkgadd @resource[:name]
+ end
+ end
+ else
+ Puppet.warning "source is defined but does not have trailing slash, ignoring #{@resource[:source]}" if @resource[:source]
+ pkgadd "-r", @resource[:name]
end
+ end
- def uninstall
- pkgdelete "#{@resource[:name]}-#{@resource.should(:ensure)}"
+ def query
+ self.class.instances.each do |provider|
+ if provider.name == @resource.name
+ return provider.properties
+ end
end
+ nil
+ end
+
+ def uninstall
+ pkgdelete "#{@resource[:name]}-#{@resource.should(:ensure)}"
+ end
end
diff --git a/lib/puppet/provider/package/gem.rb b/lib/puppet/provider/package/gem.rb
index 90b436fa6..8d70b756f 100755
--- a/lib/puppet/provider/package/gem.rb
+++ b/lib/puppet/provider/package/gem.rb
@@ -3,122 +3,122 @@ require 'uri'
# Ruby gems support.
Puppet::Type.type(:package).provide :gem, :parent => Puppet::Provider::Package do
- desc "Ruby Gem support. If a URL is passed via ``source``, then that URL is used as the
- remote gem repository; if a source is present but is not a valid URL, it will be
- interpreted as the path to a local gem file. If source is not present at all,
- the gem will be installed from the default gem repositories."
+ desc "Ruby Gem support. If a URL is passed via ``source``, then that URL is used as the
+ remote gem repository; if a source is present but is not a valid URL, it will be
+ interpreted as the path to a local gem file. If source is not present at all,
+ the gem will be installed from the default gem repositories."
- has_feature :versionable
+ has_feature :versionable
- commands :gemcmd => "gem"
+ commands :gemcmd => "gem"
- def self.gemlist(hash)
- command = [command(:gemcmd), "list"]
+ def self.gemlist(hash)
+ command = [command(:gemcmd), "list"]
- if hash[:local]
- command << "--local"
- else
- command << "--remote"
- end
-
- if name = hash[:justme]
- command << name
- end
-
- begin
- list = execute(command).split("\n").collect do |set|
- if gemhash = gemsplit(set)
- gemhash[:provider] = :gem
- gemhash
- else
- nil
- end
- end.compact
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not list gems: #{detail}"
- end
+ if hash[:local]
+ command << "--local"
+ else
+ command << "--remote"
+ end
- if hash[:justme]
- return list.shift
- else
- return list
- end
+ if name = hash[:justme]
+ command << name
end
- def self.gemsplit(desc)
- case desc
- when /^\*\*\*/, /^\s*$/, /^\s+/; return nil
- when /^(\S+)\s+\((.+)\)/
- name = $1
- version = $2.split(/,\s*/)[0]
- return {
- :name => name,
- :ensure => version
- }
+ begin
+ list = execute(command).split("\n").collect do |set|
+ if gemhash = gemsplit(set)
+ gemhash[:provider] = :gem
+ gemhash
else
- Puppet.warning "Could not match #{desc}"
- nil
+ nil
end
+ end.compact
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not list gems: #{detail}"
end
- def self.instances(justme = false)
- gemlist(:local => true).collect do |hash|
- new(hash)
- end
+ if hash[:justme]
+ return list.shift
+ else
+ return list
end
+ end
+
+ def self.gemsplit(desc)
+ case desc
+ when /^\*\*\*/, /^\s*$/, /^\s+/; return nil
+ when /^(\S+)\s+\((.+)\)/
+ name = $1
+ version = $2.split(/,\s*/)[0]
+ return {
+ :name => name,
+ :ensure => version
+ }
+ else
+ Puppet.warning "Could not match #{desc}"
+ nil
+ end
+ end
- def install(useversion = true)
- command = [command(:gemcmd), "install"]
- command << "-v" << resource[:ensure] if (! resource[:ensure].is_a? Symbol) and useversion
- # Always include dependencies
- command << "--include-dependencies"
-
- if source = resource[:source]
- begin
- uri = URI.parse(source)
- rescue => detail
- fail "Invalid source '#{uri}': #{detail}"
- end
-
- case uri.scheme
- when nil
- # no URI scheme => interpret the source as a local file
- command << source
- when /file/i
- command << uri.path
- when 'puppet'
- # we don't support puppet:// URLs (yet)
- raise Puppet::Error.new("puppet:// URLs are not supported as gem sources")
- else
- # interpret it as a gem repository
- command << "--source" << "#{source}" << resource[:name]
- end
- else
- command << resource[:name]
- end
-
- output = execute(command)
- # Apparently some stupid gem versions don't exit non-0 on failure
- self.fail "Could not install: #{output.chomp}" if output.include?("ERROR")
+ def self.instances(justme = false)
+ gemlist(:local => true).collect do |hash|
+ new(hash)
+ end
+ end
+
+ def install(useversion = true)
+ command = [command(:gemcmd), "install"]
+ command << "-v" << resource[:ensure] if (! resource[:ensure].is_a? Symbol) and useversion
+ # Always include dependencies
+ command << "--include-dependencies"
+
+ if source = resource[:source]
+ begin
+ uri = URI.parse(source)
+ rescue => detail
+ fail "Invalid source '#{uri}': #{detail}"
+ end
+
+ case uri.scheme
+ when nil
+ # no URI scheme => interpret the source as a local file
+ command << source
+ when /file/i
+ command << uri.path
+ when 'puppet'
+ # we don't support puppet:// URLs (yet)
+ raise Puppet::Error.new("puppet:// URLs are not supported as gem sources")
+ else
+ # interpret it as a gem repository
+ command << "--source" << "#{source}" << resource[:name]
+ end
+ else
+ command << resource[:name]
end
- def latest
- # This always gets the latest version available.
- hash = self.class.gemlist(:justme => resource[:name])
+ output = execute(command)
+ # Apparently some stupid gem versions don't exit non-0 on failure
+ self.fail "Could not install: #{output.chomp}" if output.include?("ERROR")
+ end
- hash[:ensure]
- end
+ def latest
+ # This always gets the latest version available.
+ hash = self.class.gemlist(:justme => resource[:name])
- def query
- self.class.gemlist(:justme => resource[:name], :local => true)
- end
+ hash[:ensure]
+ end
- def uninstall
- gemcmd "uninstall", "-x", "-a", resource[:name]
- end
+ def query
+ self.class.gemlist(:justme => resource[:name], :local => true)
+ end
- def update
- self.install(false)
- end
+ def uninstall
+ gemcmd "uninstall", "-x", "-a", resource[:name]
+ end
+
+ def update
+ self.install(false)
+ end
end
diff --git a/lib/puppet/provider/package/hpux.rb b/lib/puppet/provider/package/hpux.rb
index 4d5394643..8396edf6d 100644
--- a/lib/puppet/provider/package/hpux.rb
+++ b/lib/puppet/provider/package/hpux.rb
@@ -4,41 +4,41 @@ require 'puppet/provider/package'
Puppet::Type.type(:package).provide :hpux, :parent => Puppet::Provider::Package do
- desc "HP-UX's packaging system."
-
- commands :swinstall => "/usr/sbin/swinstall",
- :swlist => "/usr/sbin/swlist",
- :swremove => "/usr/sbin/swremove"
-
- confine :operatingsystem => "hp-ux"
-
- defaultfor :operatingsystem => "hp-ux"
-
- def self.instances
- # TODO: This is very hard on HP-UX!
- []
- end
-
- # source and name are required
- def install
- raise ArgumentError, "source must be provided to install HP-UX packages" unless resource[:source]
- args = standard_args + ["-s", resource[:source], resource[:name]]
- swinstall(*args)
- end
-
- def query
- swlist resource[:name]
- {:ensure => :present}
- rescue
- {:ensure => :absent}
- end
-
- def uninstall
- args = standard_args + [resource[:name]]
- swremove(*args)
- end
-
- def standard_args
- ["-x", "mount_all_filesystems=false"]
- end
+ desc "HP-UX's packaging system."
+
+ commands :swinstall => "/usr/sbin/swinstall",
+ :swlist => "/usr/sbin/swlist",
+ :swremove => "/usr/sbin/swremove"
+
+ confine :operatingsystem => "hp-ux"
+
+ defaultfor :operatingsystem => "hp-ux"
+
+ def self.instances
+ # TODO: This is very hard on HP-UX!
+ []
+ end
+
+ # source and name are required
+ def install
+ raise ArgumentError, "source must be provided to install HP-UX packages" unless resource[:source]
+ args = standard_args + ["-s", resource[:source], resource[:name]]
+ swinstall(*args)
+ end
+
+ def query
+ swlist resource[:name]
+ {:ensure => :present}
+ rescue
+ {:ensure => :absent}
+ end
+
+ def uninstall
+ args = standard_args + [resource[:name]]
+ swremove(*args)
+ end
+
+ def standard_args
+ ["-x", "mount_all_filesystems=false"]
+ end
end
diff --git a/lib/puppet/provider/package/nim.rb b/lib/puppet/provider/package/nim.rb
index 33d4bf11d..8f52016db 100644
--- a/lib/puppet/provider/package/nim.rb
+++ b/lib/puppet/provider/package/nim.rb
@@ -2,34 +2,34 @@ require 'puppet/provider/package'
require 'puppet/util/package'
Puppet::Type.type(:package).provide :nim, :parent => :aix, :source => :aix do
- desc "Installation from NIM LPP source"
+ desc "Installation from NIM LPP source"
- # The commands we are using on an AIX box are installed standard
- # (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
- commands :nimclient => "/usr/sbin/nimclient"
+ # The commands we are using on an AIX box are installed standard
+ # (except nimclient) nimclient needs the bos.sysmgt.nim.client fileset.
+ commands :nimclient => "/usr/sbin/nimclient"
- # If NIM has not been configured, /etc/niminfo will not be present.
- # However, we have no way of knowing if the NIM server is not configured
- # properly.
- confine :exists => "/etc/niminfo"
+ # If NIM has not been configured, /etc/niminfo will not be present.
+ # However, we have no way of knowing if the NIM server is not configured
+ # properly.
+ confine :exists => "/etc/niminfo"
- has_feature :versionable
+ has_feature :versionable
- attr_accessor :latest_info
+ attr_accessor :latest_info
- def self.srclistcmd(source)
- [ command(:nimclient), "-o", "showres", "-a", "installp_flags=L", "-a", "resource=#{source}" ]
- end
+ def self.srclistcmd(source)
+ [ command(:nimclient), "-o", "showres", "-a", "installp_flags=L", "-a", "resource=#{source}" ]
+ end
- def install(useversion = true)
- unless source = @resource[:source]
- self.fail "An LPP source location is required in 'source'"
- end
+ def install(useversion = true)
+ unless source = @resource[:source]
+ self.fail "An LPP source location is required in 'source'"
+ end
- pkg = @resource[:name]
+ pkg = @resource[:name]
- pkg << " " << @resource.should(:ensure) if (! @resource.should(:ensure).is_a? Symbol) and useversion
+ pkg << " " << @resource.should(:ensure) if (! @resource.should(:ensure).is_a? Symbol) and useversion
- nimclient "-o", "cust", "-a", "installp_flags=acgwXY", "-a", "lpp_source=#{source}", "-a", "filesets='#{pkg}'"
- end
+ nimclient "-o", "cust", "-a", "installp_flags=acgwXY", "-a", "lpp_source=#{source}", "-a", "filesets='#{pkg}'"
+ end
end
diff --git a/lib/puppet/provider/package/openbsd.rb b/lib/puppet/provider/package/openbsd.rb
index f6005efa7..ca477e56a 100755
--- a/lib/puppet/provider/package/openbsd.rb
+++ b/lib/puppet/provider/package/openbsd.rb
@@ -2,119 +2,119 @@ require 'puppet/provider/package'
# Packaging on OpenBSD. Doesn't work anywhere else that I know of.
Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Package do
- include Puppet::Util::Execution
- desc "OpenBSD's form of ``pkg_add`` support."
-
- commands :pkginfo => "pkg_info", :pkgadd => "pkg_add", :pkgdelete => "pkg_delete"
-
- defaultfor :operatingsystem => :openbsd
- confine :operatingsystem => :openbsd
-
- has_feature :versionable
-
- def self.instances
- packages = []
-
- begin
- execpipe(listcmd) do |process|
- # our regex for matching pkg_info output
- regex = /^(.*)-(\d[^-]*)[-]?(\D*)(.*)$/
- fields = [:name, :ensure, :flavor ]
- hash = {}
-
- # now turn each returned line into a package object
- process.each { |line|
- if match = regex.match(line.split[0])
- fields.zip(match.captures) { |field,value|
- hash[field] = value
- }
- yup = nil
- name = hash[:name]
-
- hash[:provider] = self.name
-
- packages << new(hash)
- hash = {}
- else
- # Print a warning on lines we can't match, but move
- # on, since it should be non-fatal
- warning("Failed to match line #{line}")
- end
- }
- end
-
- return packages
- rescue Puppet::ExecutionFailure
- return nil
- end
- end
+ include Puppet::Util::Execution
+ desc "OpenBSD's form of ``pkg_add`` support."
- def self.listcmd
- [command(:pkginfo), " -a"]
- end
+ commands :pkginfo => "pkg_info", :pkgadd => "pkg_add", :pkgdelete => "pkg_delete"
- def install
- should = @resource.should(:ensure)
+ defaultfor :operatingsystem => :openbsd
+ confine :operatingsystem => :openbsd
- unless @resource[:source]
- raise Puppet::Error,
- "You must specify a package source for BSD packages"
- end
+ has_feature :versionable
- old_ensure = @resource[:ensure]
+ def self.instances
+ packages = []
- if @resource[:source] =~ /\/$/
- withenv :PKG_PATH => @resource[:source] do
- @resource[:ensure] = old_ensure if (@resource[:ensure] = get_version) == nil
- full_name = [ @resource[:name], @resource[:ensure], @resource[:flavor] ]
- pkgadd full_name.join('-').chomp('-')
- end
- else
- pkgadd @resource[:source]
- end
+ begin
+ execpipe(listcmd) do |process|
+ # our regex for matching pkg_info output
+ regex = /^(.*)-(\d[^-]*)[-]?(\D*)(.*)$/
+ fields = [:name, :ensure, :flavor ]
+ hash = {}
+ # now turn each returned line into a package object
+ process.each { |line|
+ if match = regex.match(line.split[0])
+ fields.zip(match.captures) { |field,value|
+ hash[field] = value
+ }
+ yup = nil
+ name = hash[:name]
+
+ hash[:provider] = self.name
+
+ packages << new(hash)
+ hash = {}
+ else
+ # Print a warning on lines we can't match, but move
+ # on, since it should be non-fatal
+ warning("Failed to match line #{line}")
+ end
+ }
+ end
+
+ return packages
+ rescue Puppet::ExecutionFailure
+ return nil
end
+ end
- def get_version
- execpipe([command(:pkginfo), " -I ", @resource[:name]]) do |process|
- # our regex for matching pkg_info output
- regex = /^(.*)-(\d[^-]*)[-]?(\D*)(.*)$/
- fields = [ :name, :version, :flavor ]
- master_version = 0
-
- process.each do |line|
- if match = regex.match(line.split[0])
- # now we return the first version, unless ensure is latest
- version = match.captures[1]
- return version unless @resource[:ensure] == "latest"
-
- master_version = version unless master_version > version
- end
- end
-
- return master_version unless master_version == 0
- raise Puppet::Error, "#{version} is not available for this package"
- end
- rescue Puppet::ExecutionFailure
- return nil
+ def self.listcmd
+ [command(:pkginfo), " -a"]
+ end
+
+ def install
+ should = @resource.should(:ensure)
+
+ unless @resource[:source]
+ raise Puppet::Error,
+ "You must specify a package source for BSD packages"
end
- def query
- hash = {}
- info = pkginfo @resource[:name]
+ old_ensure = @resource[:ensure]
+
+ if @resource[:source] =~ /\/$/
+ withenv :PKG_PATH => @resource[:source] do
+ @resource[:ensure] = old_ensure if (@resource[:ensure] = get_version) == nil
+ full_name = [ @resource[:name], @resource[:ensure], @resource[:flavor] ]
+ pkgadd full_name.join('-').chomp('-')
+ end
+ else
+ pkgadd @resource[:source]
+ end
+
+ end
- # Search for the version info
- if info =~ /Information for (inst:)?#{@resource[:name]}-(\S+)/
- hash[:ensure] = $2
- else
- return nil
+ def get_version
+ execpipe([command(:pkginfo), " -I ", @resource[:name]]) do |process|
+ # our regex for matching pkg_info output
+ regex = /^(.*)-(\d[^-]*)[-]?(\D*)(.*)$/
+ fields = [ :name, :version, :flavor ]
+ master_version = 0
+
+ process.each do |line|
+ if match = regex.match(line.split[0])
+ # now we return the first version, unless ensure is latest
+ version = match.captures[1]
+ return version unless @resource[:ensure] == "latest"
+
+ master_version = version unless master_version > version
+ end
end
- hash
+ return master_version unless master_version == 0
+ raise Puppet::Error, "#{version} is not available for this package"
+ end
+ rescue Puppet::ExecutionFailure
+ return nil
+ end
+
+ def query
+ hash = {}
+ info = pkginfo @resource[:name]
+
+ # Search for the version info
+ if info =~ /Information for (inst:)?#{@resource[:name]}-(\S+)/
+ hash[:ensure] = $2
+ else
+ return nil
end
- def uninstall
- pkgdelete @resource[:name]
- end
+ hash
+ end
+
+ def uninstall
+ pkgdelete @resource[:name]
+ end
end
diff --git a/lib/puppet/provider/package/pkg.rb b/lib/puppet/provider/package/pkg.rb
index 35a712100..9a3733c95 100644
--- a/lib/puppet/provider/package/pkg.rb
+++ b/lib/puppet/provider/package/pkg.rb
@@ -1,108 +1,108 @@
require 'puppet/provider/package'
Puppet::Type.type(:package).provide :pkg, :parent => Puppet::Provider::Package do
- desc "OpenSolaris image packaging system. See pkg(5) for more information"
+ desc "OpenSolaris image packaging system. See pkg(5) for more information"
- commands :pkg => "/usr/bin/pkg"
+ commands :pkg => "/usr/bin/pkg"
- confine :operatingsystem => :solaris
+ confine :operatingsystem => :solaris
- #defaultfor [:operatingsystem => :solaris, :kernelrelease => "5.11"]
+ #defaultfor [:operatingsystem => :solaris, :kernelrelease => "5.11"]
- def self.instances
- packages = []
+ def self.instances
+ packages = []
- cmd = "#{command(:pkg)} list -H"
- execpipe(cmd) do |process|
- hash = {}
+ cmd = "#{command(:pkg)} list -H"
+ execpipe(cmd) do |process|
+ hash = {}
- # now turn each returned line into a package object
- process.each { |line|
- if hash = parse_line(line)
- packages << new(hash)
- end
- }
+ # now turn each returned line into a package object
+ process.each { |line|
+ if hash = parse_line(line)
+ packages << new(hash)
end
-
- packages
+ }
end
- self::REGEX = %r{^(\S+)\s+(\S+)\s+(\S+)\s+}
- self::FIELDS = [:name, :version, :status]
+ packages
+ end
- def self.parse_line(line)
- hash = {}
- if match = self::REGEX.match(line)
+ self::REGEX = %r{^(\S+)\s+(\S+)\s+(\S+)\s+}
+ self::FIELDS = [:name, :version, :status]
- self::FIELDS.zip(match.captures) { |field,value|
- hash[field] = value
- }
+ def self.parse_line(line)
+ hash = {}
+ if match = self::REGEX.match(line)
- hash[:provider] = self.name
- hash[:error] = "ok"
+ self::FIELDS.zip(match.captures) { |field,value|
+ hash[field] = value
+ }
- if hash[:status] == "installed"
- hash[:ensure] = :present
- else
- hash[:ensure] = :absent
- end
- else
- Puppet.warning "Failed to match 'pkg list' line #{line.inspect}"
- return nil
- end
+ hash[:provider] = self.name
+ hash[:error] = "ok"
- hash
+ if hash[:status] == "installed"
+ hash[:ensure] = :present
+ else
+ hash[:ensure] = :absent
+ end
+ else
+ Puppet.warning "Failed to match 'pkg list' line #{line.inspect}"
+ return nil
end
- # return the version of the package
- # TODO deal with multiple publishers
- def latest
- version = nil
- pkg(:list, "-Ha", @resource[:name]).split("\n").each do |line|
- v = line.split[2]
- case v
- when "known"
- return v
- when "installed"
- version = v
- else
- Puppet.warn "unknown package state for #{@resource[:name]}: #{v}"
- end
- end
- version
+ hash
+ end
+
+ # return the version of the package
+ # TODO deal with multiple publishers
+ def latest
+ version = nil
+ pkg(:list, "-Ha", @resource[:name]).split("\n").each do |line|
+ v = line.split[2]
+ case v
+ when "known"
+ return v
+ when "installed"
+ version = v
+ else
+ Puppet.warn "unknown package state for #{@resource[:name]}: #{v}"
+ end
end
-
- # install the package
- def install
- pkg :install, @resource[:name]
+ version
+ end
+
+ # install the package
+ def install
+ pkg :install, @resource[:name]
+ end
+
+ # uninstall the package
+ def uninstall
+ pkg :uninstall, '-r', @resource[:name]
+ end
+
+ # update the package to the latest version available
+ def update
+ self.install
+ end
+
+ # list a specific package
+ def query
+ begin
+ output = pkg(:list, "-H", @resource[:name])
+ rescue Puppet::ExecutionFailure
+ # pkg returns 1 if the package is not found.
+ return {:ensure => :absent, :status => 'missing',
+ :name => @resource[:name], :error => 'ok'}
end
- # uninstall the package
- def uninstall
- pkg :uninstall, '-r', @resource[:name]
- end
+ hash = self.class.parse_line(output) ||
+ {:ensure => :absent, :status => 'missing', :name => @resource[:name], :error => 'ok'}
- # update the package to the latest version available
- def update
- self.install
- end
+ raise Puppet::Error.new( "Package #{hash[:name]}, version #{hash[:version]} is in error state: #{hash[:error]}") if hash[:error] != "ok"
- # list a specific package
- def query
- begin
- output = pkg(:list, "-H", @resource[:name])
- rescue Puppet::ExecutionFailure
- # pkg returns 1 if the package is not found.
- return {:ensure => :absent, :status => 'missing',
- :name => @resource[:name], :error => 'ok'}
- end
-
- hash = self.class.parse_line(output) ||
- {:ensure => :absent, :status => 'missing', :name => @resource[:name], :error => 'ok'}
-
- raise Puppet::Error.new( "Package #{hash[:name]}, version #{hash[:version]} is in error state: #{hash[:error]}") if hash[:error] != "ok"
-
- hash
- end
+ hash
+ end
end
diff --git a/lib/puppet/provider/package/pkgdmg.rb b/lib/puppet/provider/package/pkgdmg.rb
index b533f1002..4506fbf9d 100644
--- a/lib/puppet/provider/package/pkgdmg.rb
+++ b/lib/puppet/provider/package/pkgdmg.rb
@@ -29,116 +29,116 @@ require 'puppet/provider/package'
require 'facter/util/plist'
Puppet::Type.type(:package).provide :pkgdmg, :parent => Puppet::Provider::Package do
- desc "Package management based on Apple's Installer.app and DiskUtility.app. This package works by checking the contents of a DMG image for Apple pkg or mpkg files. Any number of pkg or mpkg files may exist in the root directory of the DMG file system. Sub directories are not checked for packages. See `the wiki docs </trac/puppet/wiki/DmgPackages>` for more detail."
+ desc "Package management based on Apple's Installer.app and DiskUtility.app. This package works by checking the contents of a DMG image for Apple pkg or mpkg files. Any number of pkg or mpkg files may exist in the root directory of the DMG file system. Sub directories are not checked for packages. See `the wiki docs </trac/puppet/wiki/DmgPackages>` for more detail."
- confine :operatingsystem => :darwin
- defaultfor :operatingsystem => :darwin
- commands :installer => "/usr/sbin/installer"
- commands :hdiutil => "/usr/bin/hdiutil"
- commands :curl => "/usr/bin/curl"
+ confine :operatingsystem => :darwin
+ defaultfor :operatingsystem => :darwin
+ commands :installer => "/usr/sbin/installer"
+ commands :hdiutil => "/usr/bin/hdiutil"
+ commands :curl => "/usr/bin/curl"
- # JJM We store a cookie for each installed .pkg.dmg in /var/db
- def self.instance_by_name
- Dir.entries("/var/db").find_all { |f|
- f =~ /^\.puppet_pkgdmg_installed_/
- }.collect do |f|
- name = f.sub(/^\.puppet_pkgdmg_installed_/, '')
- yield name if block_given?
- name
- end
+ # JJM We store a cookie for each installed .pkg.dmg in /var/db
+ def self.instance_by_name
+ Dir.entries("/var/db").find_all { |f|
+ f =~ /^\.puppet_pkgdmg_installed_/
+ }.collect do |f|
+ name = f.sub(/^\.puppet_pkgdmg_installed_/, '')
+ yield name if block_given?
+ name
end
+ end
- def self.instances
- instance_by_name.collect do |name|
+ def self.instances
+ instance_by_name.collect do |name|
- new(
+ new(
- :name => name,
- :provider => :pkgdmg,
+ :name => name,
+ :provider => :pkgdmg,
- :ensure => :installed
- )
- end
+ :ensure => :installed
+ )
end
+ end
- def self.installpkg(source, name, orig_source)
- installer "-pkg", source, "-target", "/"
- # Non-zero exit status will throw an exception.
- File.open("/var/db/.puppet_pkgdmg_installed_#{name}", "w") do |t|
- t.print "name: '#{name}'\n"
- t.print "source: '#{orig_source}'\n"
- end
+ def self.installpkg(source, name, orig_source)
+ installer "-pkg", source, "-target", "/"
+ # Non-zero exit status will throw an exception.
+ File.open("/var/db/.puppet_pkgdmg_installed_#{name}", "w") do |t|
+ t.print "name: '#{name}'\n"
+ t.print "source: '#{orig_source}'\n"
end
+ end
- def self.installpkgdmg(source, name)
- unless source =~ /\.dmg$/i || source =~ /\.pkg$/i
- raise Puppet::Error.new("Mac OS X PKG DMG's must specificy a source string ending in .dmg or flat .pkg file")
- end
- require 'open-uri'
+ def self.installpkgdmg(source, name)
+ unless source =~ /\.dmg$/i || source =~ /\.pkg$/i
+ raise Puppet::Error.new("Mac OS X PKG DMG's must specificy a source string ending in .dmg or flat .pkg file")
+ end
+ require 'open-uri'
+ cached_source = source
+ if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source
+ cached_source = "/tmp/#{name}"
+ begin
+ curl "-o", cached_source, "-C", "-", "-k", "-s", "--url", source
+ Puppet.debug "Success: curl transfered [#{name}]"
+ rescue Puppet::ExecutionFailure
+ Puppet.debug "curl did not transfer [#{name}]. Falling back to slower open-uri transfer methods."
cached_source = source
- if %r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ cached_source
- cached_source = "/tmp/#{name}"
- begin
- curl "-o", cached_source, "-C", "-", "-k", "-s", "--url", source
- Puppet.debug "Success: curl transfered [#{name}]"
- rescue Puppet::ExecutionFailure
- Puppet.debug "curl did not transfer [#{name}]. Falling back to slower open-uri transfer methods."
- cached_source = source
- end
- end
+ end
+ end
- begin
- if source =~ /\.dmg$/i
- File.open(cached_source) do |dmg|
- xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-noidme", "-mountrandom", "/tmp", dmg.path
- hdiutil_info = Plist::parse_xml(xml_str)
- raise Puppet::Error.new("No disk entities returned by mount at #{dmg.path}") unless hdiutil_info.has_key?("system-entities")
- mounts = hdiutil_info["system-entities"].collect { |entity|
- entity["mount-point"]
- }.compact
- begin
- mounts.each do |mountpoint|
- Dir.entries(mountpoint).select { |f|
- f =~ /\.m{0,1}pkg$/i
- }.each do |pkg|
- installpkg("#{mountpoint}/#{pkg}", name, source)
- end
- end
- ensure
- mounts.each do |mountpoint|
- hdiutil "eject", mountpoint
- end
- end
- end
- elsif source =~ /\.pkg$/i
- installpkg(cached_source, name, source)
- else
- raise Puppet::Error.new("Mac OS X PKG DMG's must specificy a source string ending in .dmg or flat .pkg file")
+ begin
+ if source =~ /\.dmg$/i
+ File.open(cached_source) do |dmg|
+ xml_str = hdiutil "mount", "-plist", "-nobrowse", "-readonly", "-noidme", "-mountrandom", "/tmp", dmg.path
+ hdiutil_info = Plist::parse_xml(xml_str)
+ raise Puppet::Error.new("No disk entities returned by mount at #{dmg.path}") unless hdiutil_info.has_key?("system-entities")
+ mounts = hdiutil_info["system-entities"].collect { |entity|
+ entity["mount-point"]
+ }.compact
+ begin
+ mounts.each do |mountpoint|
+ Dir.entries(mountpoint).select { |f|
+ f =~ /\.m{0,1}pkg$/i
+ }.each do |pkg|
+ installpkg("#{mountpoint}/#{pkg}", name, source)
+ end
+ end
+ ensure
+ mounts.each do |mountpoint|
+ hdiutil "eject", mountpoint
end
- ensure
- # JJM Remove the file if open-uri didn't already do so.
- File.unlink(cached_source) if File.exist?(cached_source)
+ end
end
+ elsif source =~ /\.pkg$/i
+ installpkg(cached_source, name, source)
+ else
+ raise Puppet::Error.new("Mac OS X PKG DMG's must specificy a source string ending in .dmg or flat .pkg file")
+ end
+ ensure
+ # JJM Remove the file if open-uri didn't already do so.
+ File.unlink(cached_source) if File.exist?(cached_source)
end
+ end
- def query
- if FileTest.exists?("/var/db/.puppet_pkgdmg_installed_#{@resource[:name]}")
- Puppet.debug "/var/db/.puppet_pkgdmg_installed_#{@resource[:name]} found"
- return {:name => @resource[:name], :ensure => :present}
- else
- return nil
- end
+ def query
+ if FileTest.exists?("/var/db/.puppet_pkgdmg_installed_#{@resource[:name]}")
+ Puppet.debug "/var/db/.puppet_pkgdmg_installed_#{@resource[:name]} found"
+ return {:name => @resource[:name], :ensure => :present}
+ else
+ return nil
end
+ end
- def install
- source = nil
- unless source = @resource[:source]
- raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package source.")
- end
- unless name = @resource[:name]
- raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package name.")
- end
- self.class.installpkgdmg(source,name)
+ def install
+ source = nil
+ unless source = @resource[:source]
+ raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package source.")
+ end
+ unless name = @resource[:name]
+ raise Puppet::Error.new("Mac OS X PKG DMG's must specify a package name.")
end
+ self.class.installpkgdmg(source,name)
+ end
end
diff --git a/lib/puppet/provider/package/portage.rb b/lib/puppet/provider/package/portage.rb
index 82d16699c..30f0e4a25 100644
--- a/lib/puppet/provider/package/portage.rb
+++ b/lib/puppet/provider/package/portage.rb
@@ -2,121 +2,121 @@ require 'puppet/provider/package'
require 'fileutils'
Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Package do
- desc "Provides packaging support for Gentoo's portage system."
+ desc "Provides packaging support for Gentoo's portage system."
- has_feature :versionable
+ has_feature :versionable
- commands :emerge => "/usr/bin/emerge", :eix => "/usr/bin/eix", :update_eix => "/usr/bin/eix-update"
+ commands :emerge => "/usr/bin/emerge", :eix => "/usr/bin/eix", :update_eix => "/usr/bin/eix-update"
- confine :operatingsystem => :gentoo
+ confine :operatingsystem => :gentoo
- defaultfor :operatingsystem => :gentoo
+ defaultfor :operatingsystem => :gentoo
- def self.instances
- result_format = /^(\S+)\s+(\S+)\s+\[(\S+)\]\s+\[(\S+)\]\s+(\S+)\s+(.*)$/
- result_fields = [:category, :name, :ensure, :version_available, :vendor, :description]
+ def self.instances
+ result_format = /^(\S+)\s+(\S+)\s+\[(\S+)\]\s+\[(\S+)\]\s+(\S+)\s+(.*)$/
+ result_fields = [:category, :name, :ensure, :version_available, :vendor, :description]
- version_format = "{last}<version>{}"
- search_format = "<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>\n"
+ version_format = "{last}<version>{}"
+ search_format = "<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>\n"
- begin
- update_eix if !FileUtils.uptodate?("/var/cache/eix", %w{/usr/bin/eix /usr/portage/metadata/timestamp})
+ begin
+ update_eix if !FileUtils.uptodate?("/var/cache/eix", %w{/usr/bin/eix /usr/portage/metadata/timestamp})
- search_output = nil
- Puppet::Util::Execution.withenv :LASTVERSION => version_format do
- search_output = eix "--nocolor", "--pure-packages", "--stable", "--installed", "--format", search_format
- end
+ search_output = nil
+ Puppet::Util::Execution.withenv :LASTVERSION => version_format do
+ search_output = eix "--nocolor", "--pure-packages", "--stable", "--installed", "--format", search_format
+ end
- packages = []
- search_output.each do |search_result|
- match = result_format.match(search_result)
+ packages = []
+ search_output.each do |search_result|
+ match = result_format.match(search_result)
- if match
- package = {}
- result_fields.zip(match.captures) do |field, value|
- package[field] = value unless !value or value.empty?
- end
- package[:provider] = :portage
- packages << new(package)
- end
- end
-
- return packages
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new(detail)
+ if match
+ package = {}
+ result_fields.zip(match.captures) do |field, value|
+ package[field] = value unless !value or value.empty?
+ end
+ package[:provider] = :portage
+ packages << new(package)
end
- end
-
- def install
- should = @resource.should(:ensure)
- name = package_name
- unless should == :present or should == :latest
- # We must install a specific version
- name = "=#{name}-#{should}"
- end
- emerge name
- end
+ end
- # The common package name format.
- def package_name
- @resource[:category] ? "#{@resource[:category]}/#{@resource[:name]}" : @resource[:name]
+ return packages
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error.new(detail)
end
-
- def uninstall
- emerge "--unmerge", package_name
- end
-
- def update
- self.install
+ end
+
+ def install
+ should = @resource.should(:ensure)
+ name = package_name
+ unless should == :present or should == :latest
+ # We must install a specific version
+ name = "=#{name}-#{should}"
end
-
- def query
- result_format = /^(\S+)\s+(\S+)\s+\[(\S*)\]\s+\[(\S+)\]\s+(\S+)\s+(.*)$/
- result_fields = [:category, :name, :ensure, :version_available, :vendor, :description]
-
- version_format = "{last}<version>{}"
- search_format = "<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>\n"
-
- search_field = package_name.count('/') > 0 ? "--category-name" : "--name"
- search_value = package_name
-
- begin
- update_eix if !FileUtils.uptodate?("/var/cache/eix", %w{/usr/bin/eix /usr/portage/metadata/timestamp})
-
- search_output = nil
- Puppet::Util::Execution.withenv :LASTVERSION => version_format do
- search_output = eix "--nocolor", "--pure-packages", "--stable", "--format", search_format, "--exact", search_field, search_value
- end
-
- packages = []
- search_output.each do |search_result|
- match = result_format.match(search_result)
-
- if match
- package = {}
- result_fields.zip(match.captures) do |field, value|
- package[field] = value unless !value or value.empty?
- end
- package[:ensure] = package[:ensure] ? package[:ensure] : :absent
- packages << package
- end
- end
-
- case packages.size
- when 0
- not_found_value = "#{@resource[:category] ? @resource[:category] : "<unspecified category>"}/#{@resource[:name]}"
- raise Puppet::Error.new("No package found with the specified name [#{not_found_value}]")
- when 1
- return packages[0]
- else
- raise Puppet::Error.new("More than one package with the specified name [#{search_value}], please use the category parameter to disambiguate")
- end
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new(detail)
+ emerge name
+ end
+
+ # The common package name format.
+ def package_name
+ @resource[:category] ? "#{@resource[:category]}/#{@resource[:name]}" : @resource[:name]
+ end
+
+ def uninstall
+ emerge "--unmerge", package_name
+ end
+
+ def update
+ self.install
+ end
+
+ def query
+ result_format = /^(\S+)\s+(\S+)\s+\[(\S*)\]\s+\[(\S+)\]\s+(\S+)\s+(.*)$/
+ result_fields = [:category, :name, :ensure, :version_available, :vendor, :description]
+
+ version_format = "{last}<version>{}"
+ search_format = "<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>\n"
+
+ search_field = package_name.count('/') > 0 ? "--category-name" : "--name"
+ search_value = package_name
+
+ begin
+ update_eix if !FileUtils.uptodate?("/var/cache/eix", %w{/usr/bin/eix /usr/portage/metadata/timestamp})
+
+ search_output = nil
+ Puppet::Util::Execution.withenv :LASTVERSION => version_format do
+ search_output = eix "--nocolor", "--pure-packages", "--stable", "--format", search_format, "--exact", search_field, search_value
+ end
+
+ packages = []
+ search_output.each do |search_result|
+ match = result_format.match(search_result)
+
+ if match
+ package = {}
+ result_fields.zip(match.captures) do |field, value|
+ package[field] = value unless !value or value.empty?
+ end
+ package[:ensure] = package[:ensure] ? package[:ensure] : :absent
+ packages << package
end
+ end
+
+ case packages.size
+ when 0
+ not_found_value = "#{@resource[:category] ? @resource[:category] : "<unspecified category>"}/#{@resource[:name]}"
+ raise Puppet::Error.new("No package found with the specified name [#{not_found_value}]")
+ when 1
+ return packages[0]
+ else
+ raise Puppet::Error.new("More than one package with the specified name [#{search_value}], please use the category parameter to disambiguate")
+ end
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error.new(detail)
end
+ end
- def latest
- self.query[:version_available]
- end
+ def latest
+ self.query[:version_available]
+ end
end
diff --git a/lib/puppet/provider/package/ports.rb b/lib/puppet/provider/package/ports.rb
index 1b8f0fb8c..c8020928e 100755
--- a/lib/puppet/provider/package/ports.rb
+++ b/lib/puppet/provider/package/ports.rb
@@ -1,95 +1,95 @@
Puppet::Type.type(:package).provide :ports, :parent => :freebsd, :source => :freebsd do
- desc "Support for FreeBSD's ports. Again, this still mixes packages and ports."
+ desc "Support for FreeBSD's ports. Again, this still mixes packages and ports."
- commands :portupgrade => "/usr/local/sbin/portupgrade",
- :portversion => "/usr/local/sbin/portversion",
- :portuninstall => "/usr/local/sbin/pkg_deinstall",
- :portinfo => "/usr/sbin/pkg_info"
+ commands :portupgrade => "/usr/local/sbin/portupgrade",
+ :portversion => "/usr/local/sbin/portversion",
+ :portuninstall => "/usr/local/sbin/pkg_deinstall",
+ :portinfo => "/usr/sbin/pkg_info"
- defaultfor :operatingsystem => :freebsd
+ defaultfor :operatingsystem => :freebsd
- # I hate ports
- %w{INTERACTIVE UNAME}.each do |var|
- ENV.delete(var) if ENV.include?(var)
- end
+ # I hate ports
+ %w{INTERACTIVE UNAME}.each do |var|
+ ENV.delete(var) if ENV.include?(var)
+ end
- def install
- # -N: install if the package is missing, otherwise upgrade
- # -M: yes, we're a batch, so don't ask any questions
- cmd = %w{-N -M BATCH=yes} << @resource[:name]
+ def install
+ # -N: install if the package is missing, otherwise upgrade
+ # -M: yes, we're a batch, so don't ask any questions
+ cmd = %w{-N -M BATCH=yes} << @resource[:name]
- output = portupgrade(*cmd)
- if output =~ /\*\* No such /
- raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
- end
+ output = portupgrade(*cmd)
+ if output =~ /\*\* No such /
+ raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
end
+ end
- # If there are multiple packages, we only use the last one
- def latest
- cmd = ["-v", @resource[:name]]
+ # If there are multiple packages, we only use the last one
+ def latest
+ cmd = ["-v", @resource[:name]]
- begin
- output = portversion(*cmd)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new(output)
- end
- line = output.split("\n").pop
+ begin
+ output = portversion(*cmd)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new(output)
+ end
+ line = output.split("\n").pop
- unless line =~ /^(\S+)\s+(\S)\s+(.+)$/
- # There's no "latest" version, so just return a placeholder
- return :latest
- end
+ unless line =~ /^(\S+)\s+(\S)\s+(.+)$/
+ # There's no "latest" version, so just return a placeholder
+ return :latest
+ end
- pkgstuff = $1
- match = $2
- info = $3
+ pkgstuff = $1
+ match = $2
+ info = $3
- unless pkgstuff =~ /^(\S+)-([^-\s]+)$/
- raise Puppet::Error,
- "Could not match package info '#{pkgstuff}'"
- end
+ unless pkgstuff =~ /^(\S+)-([^-\s]+)$/
+ raise Puppet::Error,
+ "Could not match package info '#{pkgstuff}'"
+ end
- name, version = $1, $2
+ name, version = $1, $2
- if match == "=" or match == ">"
- # we're up to date or more recent
- return version
- end
+ if match == "=" or match == ">"
+ # we're up to date or more recent
+ return version
+ end
- # Else, we need to be updated; we need to pull out the new version
+ # Else, we need to be updated; we need to pull out the new version
- unless info =~ /\((\w+) has (.+)\)/
- raise Puppet::Error,
- "Could not match version info '#{info}'"
- end
+ unless info =~ /\((\w+) has (.+)\)/
+ raise Puppet::Error,
+ "Could not match version info '#{info}'"
+ end
- source, newversion = $1, $2
+ source, newversion = $1, $2
- debug "Newer version in #{source}"
- newversion
- end
+ debug "Newer version in #{source}"
+ newversion
+ end
- def query
- # support portorigin_glob such as "mail/postfix"
- name = self.name
- if name =~ /\//
- name = self.name.split(/\//).slice(1)
- end
- self.class.instances.each do |instance|
- if instance.name == name
- return instance.properties
- end
- end
-
- nil
+ def query
+ # support portorigin_glob such as "mail/postfix"
+ name = self.name
+ if name =~ /\//
+ name = self.name.split(/\//).slice(1)
end
-
- def uninstall
- portuninstall @resource[:name]
+ self.class.instances.each do |instance|
+ if instance.name == name
+ return instance.properties
+ end
end
- def update
- install
- end
+ nil
+ end
+
+ def uninstall
+ portuninstall @resource[:name]
+ end
+
+ def update
+ install
+ end
end
diff --git a/lib/puppet/provider/package/portupgrade.rb b/lib/puppet/provider/package/portupgrade.rb
index 08cb52f47..45e35bbca 100644
--- a/lib/puppet/provider/package/portupgrade.rb
+++ b/lib/puppet/provider/package/portupgrade.rb
@@ -3,248 +3,248 @@
require 'puppet/provider/package'
Puppet::Type.type(:package).provide :portupgrade, :parent => Puppet::Provider::Package do
- include Puppet::Util::Execution
+ include Puppet::Util::Execution
- desc "Support for FreeBSD's ports using the portupgrade ports management software.
- Use the port's full origin as the resource name. eg (ports-mgmt/portupgrade)
- for the portupgrade port."
+ desc "Support for FreeBSD's ports using the portupgrade ports management software.
+ Use the port's full origin as the resource name. eg (ports-mgmt/portupgrade)
+ for the portupgrade port."
- ## has_features is usually autodetected based on defs below.
- # has_features :installable, :uninstallable, :upgradeable
+ ## has_features is usually autodetected based on defs below.
+ # has_features :installable, :uninstallable, :upgradeable
- commands :portupgrade => "/usr/local/sbin/portupgrade",
- :portinstall => "/usr/local/sbin/portinstall",
- :portversion => "/usr/local/sbin/portversion",
- :portuninstall => "/usr/local/sbin/pkg_deinstall",
- :portinfo => "/usr/sbin/pkg_info"
+ commands :portupgrade => "/usr/local/sbin/portupgrade",
+ :portinstall => "/usr/local/sbin/portinstall",
+ :portversion => "/usr/local/sbin/portversion",
+ :portuninstall => "/usr/local/sbin/pkg_deinstall",
+ :portinfo => "/usr/sbin/pkg_info"
- ## Activate this only once approved by someone important.
- # defaultfor :operatingsystem => :freebsd
+ ## Activate this only once approved by someone important.
+ # defaultfor :operatingsystem => :freebsd
- # Remove unwanted environment variables.
- %w{INTERACTIVE UNAME}.each do |var|
- if ENV.include?(var)
- ENV.delete(var)
- end
- end
-
- ######## instances sub command (builds the installed packages list)
-
- def self.instances
- Puppet.debug "portupgrade.rb Building packages list from installed ports"
-
- # regex to match output from pkg_info
- regex = %r{^(\S+)-([^-\s]+):(\S+)$}
- # Corresponding field names
- fields = [:portname, :ensure, :portorigin]
- # define Temporary hash used, packages array of hashes
- hash = Hash.new
- packages = []
-
- # exec command
- cmdline = ["-aoQ"]
- begin
- output = portinfo(*cmdline)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new(output)
- return nil
- end
+ # Remove unwanted environment variables.
+ %w{INTERACTIVE UNAME}.each do |var|
+ if ENV.include?(var)
+ ENV.delete(var)
+ end
+ end
+
+ ######## instances sub command (builds the installed packages list)
+
+ def self.instances
+ Puppet.debug "portupgrade.rb Building packages list from installed ports"
+
+ # regex to match output from pkg_info
+ regex = %r{^(\S+)-([^-\s]+):(\S+)$}
+ # Corresponding field names
+ fields = [:portname, :ensure, :portorigin]
+ # define Temporary hash used, packages array of hashes
+ hash = Hash.new
+ packages = []
+
+ # exec command
+ cmdline = ["-aoQ"]
+ begin
+ output = portinfo(*cmdline)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new(output)
+ return nil
+ end
- # split output and match it and populate temp hash
- output.split("\n").each { |data|
- # reset hash to nil for each line
- hash.clear
- if match = regex.match(data)
- # Output matched regex
- fields.zip(match.captures) { |field, value|
- hash[field] = value
- }
-
- # populate the actual :name field from the :portorigin
- # Set :provider to this object name
- hash[:name] = hash[:portorigin]
- hash[:provider] = self.name
-
- # Add to the full packages listing
- packages << new(hash)
-
- else
- # unrecognised output from pkg_info
- Puppet.debug "portupgrade.Instances() - unable to match output: #{data}"
- end
- }
-
- # return the packages array of hashes
- return packages
+ # split output and match it and populate temp hash
+ output.split("\n").each { |data|
+ # reset hash to nil for each line
+ hash.clear
+ if match = regex.match(data)
+ # Output matched regex
+ fields.zip(match.captures) { |field, value|
+ hash[field] = value
+ }
+
+ # populate the actual :name field from the :portorigin
+ # Set :provider to this object name
+ hash[:name] = hash[:portorigin]
+ hash[:provider] = self.name
+
+ # Add to the full packages listing
+ packages << new(hash)
+
+ else
+ # unrecognised output from pkg_info
+ Puppet.debug "portupgrade.Instances() - unable to match output: #{data}"
+ end
+ }
- end
+ # return the packages array of hashes
+ return packages
- ######## Installation sub command
+ end
- def install
- Puppet.debug "portupgrade.install() - Installation call on #{@resource[:name]}"
- # -M: yes, we're a batch, so don't ask any questions
- cmdline = ["-M BATCH=yes", @resource[:name]]
+ ######## Installation sub command
- # FIXME: it's possible that portinstall prompts for data so locks up.
- begin
- output = portinstall(*cmdline)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new(output)
- end
+ def install
+ Puppet.debug "portupgrade.install() - Installation call on #{@resource[:name]}"
+ # -M: yes, we're a batch, so don't ask any questions
+ cmdline = ["-M BATCH=yes", @resource[:name]]
- if output =~ /\*\* No such /
- raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
- end
+ # FIXME: it's possible that portinstall prompts for data so locks up.
+ begin
+ output = portinstall(*cmdline)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new(output)
+ end
- # No return code required, so do nil to be clean
- return nil
+ if output =~ /\*\* No such /
+ raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
end
- ######## Latest subcommand (returns the latest version available, or current version if installed is latest)
+ # No return code required, so do nil to be clean
+ return nil
+ end
- def latest
- Puppet.debug "portupgrade.latest() - Latest check called on #{@resource[:name]}"
- # search for latest version available, or return current version.
- # cmdline = "portversion -v <portorigin>", returns "<portname> <code> <stuff>"
- # or "** No matching package found: <portname>"
- cmdline = ["-v", @resource[:name]]
+ ######## Latest subcommand (returns the latest version available, or current version if installed is latest)
- begin
- output = portversion(*cmdline)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new(output)
- end
+ def latest
+ Puppet.debug "portupgrade.latest() - Latest check called on #{@resource[:name]}"
+ # search for latest version available, or return current version.
+ # cmdline = "portversion -v <portorigin>", returns "<portname> <code> <stuff>"
+ # or "** No matching package found: <portname>"
+ cmdline = ["-v", @resource[:name]]
- # Check: output format.
- if output =~ /^\S+-([^-\s]+)\s+(\S)\s+(.*)/
- # $1 = installed version, $2 = comparison, $3 other data
- # latest installed
- installedversion = $1
- comparison = $2
- otherdata = $3
-
- # Only return a new version number when it's clear that there is a new version
- # all others return the current version so no unexpected 'upgrades' occur.
- case comparison
- when "=", ">"
- Puppet.debug "portupgrade.latest() - Installed package is latest (#{installedversion})"
- return installedversion
- when "<"
- # "portpkg-1.7_5 < needs updating (port has 1.14)"
- # "portpkg-1.7_5 < needs updating (port has 1.14) (=> 'newport/pkg')
- if otherdata =~ /\(port has (\S+)\)/
- newversion = $1
- Puppet.debug "portupgrade.latest() - Installed version needs updating to (#{newversion})"
- return newversion
- else
- Puppet.debug "portupgrade.latest() - Unable to determine new version from (#{otherdata})"
- return installedversion
- end
- when "?", "!", "#"
- Puppet.debug "portupgrade.latest() - Comparison Error reported from portversion (#{output})"
- return installedversion
- else
- Puppet.debug "portupgrade.latest() - Unknown code from portversion output (#{output})"
- return installedversion
- end
+ begin
+ output = portversion(*cmdline)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new(output)
+ end
+ # Check: output format.
+ if output =~ /^\S+-([^-\s]+)\s+(\S)\s+(.*)/
+ # $1 = installed version, $2 = comparison, $3 other data
+ # latest installed
+ installedversion = $1
+ comparison = $2
+ otherdata = $3
+
+ # Only return a new version number when it's clear that there is a new version
+ # all others return the current version so no unexpected 'upgrades' occur.
+ case comparison
+ when "=", ">"
+ Puppet.debug "portupgrade.latest() - Installed package is latest (#{installedversion})"
+ return installedversion
+ when "<"
+ # "portpkg-1.7_5 < needs updating (port has 1.14)"
+ # "portpkg-1.7_5 < needs updating (port has 1.14) (=> 'newport/pkg')
+ if otherdata =~ /\(port has (\S+)\)/
+ newversion = $1
+ Puppet.debug "portupgrade.latest() - Installed version needs updating to (#{newversion})"
+ return newversion
else
- # error: output not parsed correctly, error out with nil.
- # Seriously - this section should never be called in a perfect world.
- # as verification that the port is installed has already happened in query.
- if output =~ /^\*\* No matching package /
- raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
- else
- # Any other error (dump output to log)
- raise Puppet::ExecutionFailure, "Unexpected output from portversion: #{output}"
- end
-
- # Just in case we still are running, return nil
- return nil
+ Puppet.debug "portupgrade.latest() - Unable to determine new version from (#{otherdata})"
+ return installedversion
end
+ when "?", "!", "#"
+ Puppet.debug "portupgrade.latest() - Comparison Error reported from portversion (#{output})"
+ return installedversion
+ else
+ Puppet.debug "portupgrade.latest() - Unknown code from portversion output (#{output})"
+ return installedversion
+ end
- # At this point normal operation has finished and we shouldn't have been called.
- # Error out and let the admin deal with it.
- raise Puppet::Error, "portversion.latest() - fatal error with portversion: #{output}"
- return nil
+ else
+ # error: output not parsed correctly, error out with nil.
+ # Seriously - this section should never be called in a perfect world.
+ # as verification that the port is installed has already happened in query.
+ if output =~ /^\*\* No matching package /
+ raise Puppet::ExecutionFailure, "Could not find package #{@resource[:name]}"
+ else
+ # Any other error (dump output to log)
+ raise Puppet::ExecutionFailure, "Unexpected output from portversion: #{output}"
+ end
+ # Just in case we still are running, return nil
+ return nil
end
- ###### Query subcommand - return a hash of details if exists, or nil if it doesn't.
- # Used to make sure the package is installed
+ # At this point normal operation has finished and we shouldn't have been called.
+ # Error out and let the admin deal with it.
+ raise Puppet::Error, "portversion.latest() - fatal error with portversion: #{output}"
+ return nil
- def query
- Puppet.debug "portupgrade.query() - Called on #{@resource[:name]}"
+ end
- cmdline = ["-qO", @resource[:name]]
- begin
- output = portinfo(*cmdline)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new(output)
- end
+ ###### Query subcommand - return a hash of details if exists, or nil if it doesn't.
+ # Used to make sure the package is installed
- # Check: if output isn't in the right format, return nil
- if output =~ /^(\S+)-([^-\s]+)/
- # Fill in the details
- hash = Hash.new
- hash[:portorigin] = self.name
- hash[:portname] = $1
- hash[:ensure] = $2
-
- # If more details are required, then we can do another pkg_info query here
- # and parse out that output and add to the hash
-
- # return the hash to the caller
- return hash
- else
- Puppet.debug "portupgrade.query() - package (#{@resource[:name]}) not installed"
- return nil
- end
+ def query
+ Puppet.debug "portupgrade.query() - Called on #{@resource[:name]}"
+ cmdline = ["-qO", @resource[:name]]
+ begin
+ output = portinfo(*cmdline)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new(output)
end
- ####### Uninstall command
+ # Check: if output isn't in the right format, return nil
+ if output =~ /^(\S+)-([^-\s]+)/
+ # Fill in the details
+ hash = Hash.new
+ hash[:portorigin] = self.name
+ hash[:portname] = $1
+ hash[:ensure] = $2
+
+ # If more details are required, then we can do another pkg_info query here
+ # and parse out that output and add to the hash
+
+ # return the hash to the caller
+ return hash
+ else
+ Puppet.debug "portupgrade.query() - package (#{@resource[:name]}) not installed"
+ return nil
+ end
- def uninstall
- Puppet.debug "portupgrade.uninstall() - called on #{@resource[:name]}"
- # Get full package name from port origin to uninstall with
- cmdline = ["-qO", @resource[:name]]
- begin
- output = portinfo(*cmdline)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new(output)
- end
+ end
- if output =~ /^(\S+)/
- # output matches, so uninstall it
- portuninstall $1
- end
+ ####### Uninstall command
+ def uninstall
+ Puppet.debug "portupgrade.uninstall() - called on #{@resource[:name]}"
+ # Get full package name from port origin to uninstall with
+ cmdline = ["-qO", @resource[:name]]
+ begin
+ output = portinfo(*cmdline)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new(output)
end
- ######## Update/upgrade command
+ if output =~ /^(\S+)/
+ # output matches, so uninstall it
+ portuninstall $1
+ end
- def update
- Puppet.debug "portupgrade.update() - called on (#{@resource[:name]})"
+ end
- cmdline = ["-qO", @resource[:name]]
- begin
- output = portinfo(*cmdline)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new(output)
- end
+ ######## Update/upgrade command
- if output =~ /^(\S+)/
- # output matches, so upgrade the software
- cmdline = ["-M BATCH=yes", $1]
- begin
- output = portupgrade(*cmdline)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new(output)
- end
- end
+ def update
+ Puppet.debug "portupgrade.update() - called on (#{@resource[:name]})"
+
+ cmdline = ["-qO", @resource[:name]]
+ begin
+ output = portinfo(*cmdline)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new(output)
+ end
+
+ if output =~ /^(\S+)/
+ # output matches, so upgrade the software
+ cmdline = ["-M BATCH=yes", $1]
+ begin
+ output = portupgrade(*cmdline)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new(output)
+ end
end
+ end
## EOF
end
diff --git a/lib/puppet/provider/package/rpm.rb b/lib/puppet/provider/package/rpm.rb
index cabdd1b1f..d33a4f2f3 100755
--- a/lib/puppet/provider/package/rpm.rb
+++ b/lib/puppet/provider/package/rpm.rb
@@ -1,132 +1,132 @@
require 'puppet/provider/package'
# RPM packaging. Should work anywhere that has rpm installed.
Puppet::Type.type(:package).provide :rpm, :source => :rpm, :parent => Puppet::Provider::Package do
- desc "RPM packaging support; should work anywhere with a working ``rpm``
- binary."
-
- has_feature :versionable
-
- # The query format by which we identify installed packages
- NEVRAFORMAT = "%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH}"
- NEVRA_FIELDS = [:name, :epoch, :version, :release, :arch]
-
- commands :rpm => "rpm"
-
- if command('rpm')
- confine :true => begin
- rpm('--version')
- rescue Puppet::ExecutionFailure
- false
- else
- true
- end
+ desc "RPM packaging support; should work anywhere with a working ``rpm``
+ binary."
+
+ has_feature :versionable
+
+ # The query format by which we identify installed packages
+ NEVRAFORMAT = "%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH}"
+ NEVRA_FIELDS = [:name, :epoch, :version, :release, :arch]
+
+ commands :rpm => "rpm"
+
+ if command('rpm')
+ confine :true => begin
+ rpm('--version')
+ rescue Puppet::ExecutionFailure
+ false
+ else
+ true
+ end
+ end
+
+ def self.instances
+ packages = []
+
+ # rpm < 4.1 don't support --nosignature
+ output = rpm "--version"
+ sig = "--nosignature"
+ if output =~ /RPM version (([123].*)|(4\.0.*))/
+ sig = ""
end
- def self.instances
- packages = []
-
- # rpm < 4.1 don't support --nosignature
- output = rpm "--version"
- sig = "--nosignature"
- if output =~ /RPM version (([123].*)|(4\.0.*))/
- sig = ""
- end
-
- # list out all of the packages
- begin
- execpipe("#{command(:rpm)} -qa #{sig} --nodigest --qf '#{NEVRAFORMAT}\n'") { |process|
- # now turn each returned line into a package object
- process.each { |line|
- hash = nevra_to_hash(line)
- packages << new(hash)
- }
- }
- rescue Puppet::ExecutionFailure
- raise Puppet::Error, "Failed to list packages"
- end
-
- packages
+ # list out all of the packages
+ begin
+ execpipe("#{command(:rpm)} -qa #{sig} --nodigest --qf '#{NEVRAFORMAT}\n'") { |process|
+ # now turn each returned line into a package object
+ process.each { |line|
+ hash = nevra_to_hash(line)
+ packages << new(hash)
+ }
+ }
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error, "Failed to list packages"
end
- # Find the fully versioned package name and the version alone. Returns
- # a hash with entries :instance => fully versioned package name, and
- # :ensure => version-release
- def query
- #NOTE: Prior to a fix for issue 1243, this method potentially returned a cached value
- #IF YOU CALL THIS METHOD, IT WILL CALL RPM
- #Use get(:property) to check if cached values are available
- cmd = ["-q", @resource[:name], "--nosignature", "--nodigest", "--qf", "#{NEVRAFORMAT}\n"]
-
- begin
- output = rpm(*cmd)
- rescue Puppet::ExecutionFailure
- return nil
- end
-
- # FIXME: We could actually be getting back multiple packages
- # for multilib
- @property_hash.update(self.class.nevra_to_hash(output))
-
- @property_hash.dup
+ packages
+ end
+
+ # Find the fully versioned package name and the version alone. Returns
+ # a hash with entries :instance => fully versioned package name, and
+ # :ensure => version-release
+ def query
+ #NOTE: Prior to a fix for issue 1243, this method potentially returned a cached value
+ #IF YOU CALL THIS METHOD, IT WILL CALL RPM
+ #Use get(:property) to check if cached values are available
+ cmd = ["-q", @resource[:name], "--nosignature", "--nodigest", "--qf", "#{NEVRAFORMAT}\n"]
+
+ begin
+ output = rpm(*cmd)
+ rescue Puppet::ExecutionFailure
+ return nil
end
- # Here we just retrieve the version from the file specified in the source.
- def latest
- unless source = @resource[:source]
- @resource.fail "RPMs must specify a package source"
- end
+ # FIXME: We could actually be getting back multiple packages
+ # for multilib
+ @property_hash.update(self.class.nevra_to_hash(output))
- cmd = [command(:rpm), "-q", "--qf", "#{NEVRAFORMAT}\n", "-p", "#{@resource[:source]}"]
- h = self.class.nevra_to_hash(execfail(cmd, Puppet::Error))
- h[:ensure]
- end
+ @property_hash.dup
+ end
- def install
- source = nil
- unless source = @resource[:source]
- @resource.fail "RPMs must specify a package source"
- end
- # RPM gets pissy if you try to install an already
- # installed package
- if @resource.should(:ensure) == @property_hash[:ensure] or
- @resource.should(:ensure) == :latest && @property_hash[:ensure] == latest
- return
- end
-
- flag = "-i"
- flag = "-U" if @property_hash[:ensure] and @property_hash[:ensure] != :absent
-
- rpm flag, "--oldpackage", source
+ # Here we just retrieve the version from the file specified in the source.
+ def latest
+ unless source = @resource[:source]
+ @resource.fail "RPMs must specify a package source"
end
- def uninstall
- query unless get(:arch)
- nvr = "#{get(:name)}-#{get(:version)}-#{get(:release)}"
- arch = ".#{get(:arch)}"
- # If they specified an arch in the manifest, erase that Otherwise,
- # erase the arch we got back from the query. If multiple arches are
- # installed and only the package name is specified (without the
- # arch), this will uninstall all of them on successive runs of the
- # client, one after the other
- if @resource[:name][-arch.size, arch.size] == arch
- nvr += arch
- else
- nvr += ".#{get(:arch)}"
- end
- rpm "-e", nvr
- end
+ cmd = [command(:rpm), "-q", "--qf", "#{NEVRAFORMAT}\n", "-p", "#{@resource[:source]}"]
+ h = self.class.nevra_to_hash(execfail(cmd, Puppet::Error))
+ h[:ensure]
+ end
- def update
- self.install
+ def install
+ source = nil
+ unless source = @resource[:source]
+ @resource.fail "RPMs must specify a package source"
+ end
+ # RPM gets pissy if you try to install an already
+ # installed package
+ if @resource.should(:ensure) == @property_hash[:ensure] or
+ @resource.should(:ensure) == :latest && @property_hash[:ensure] == latest
+ return
end
- def self.nevra_to_hash(line)
- line.chomp!
- hash = {}
- NEVRA_FIELDS.zip(line.split) { |f, v| hash[f] = v }
- hash[:provider] = self.name
- hash[:ensure] = "#{hash[:version]}-#{hash[:release]}"
- hash
+ flag = "-i"
+ flag = "-U" if @property_hash[:ensure] and @property_hash[:ensure] != :absent
+
+ rpm flag, "--oldpackage", source
+ end
+
+ def uninstall
+ query unless get(:arch)
+ nvr = "#{get(:name)}-#{get(:version)}-#{get(:release)}"
+ arch = ".#{get(:arch)}"
+ # If they specified an arch in the manifest, erase that Otherwise,
+ # erase the arch we got back from the query. If multiple arches are
+ # installed and only the package name is specified (without the
+ # arch), this will uninstall all of them on successive runs of the
+ # client, one after the other
+ if @resource[:name][-arch.size, arch.size] == arch
+ nvr += arch
+ else
+ nvr += ".#{get(:arch)}"
end
+ rpm "-e", nvr
+ end
+
+ def update
+ self.install
+ end
+
+ def self.nevra_to_hash(line)
+ line.chomp!
+ hash = {}
+ NEVRA_FIELDS.zip(line.split) { |f, v| hash[f] = v }
+ hash[:provider] = self.name
+ hash[:ensure] = "#{hash[:version]}-#{hash[:release]}"
+ hash
+ end
end
diff --git a/lib/puppet/provider/package/rug.rb b/lib/puppet/provider/package/rug.rb
index 227edc7c2..7028cc9e5 100644
--- a/lib/puppet/provider/package/rug.rb
+++ b/lib/puppet/provider/package/rug.rb
@@ -1,52 +1,52 @@
Puppet::Type.type(:package).provide :rug, :parent => :rpm do
- desc "Support for suse ``rug`` package manager."
-
- has_feature :versionable
-
- commands :rug => "/usr/bin/rug"
- commands :rpm => "rpm"
- defaultfor :operatingsystem => [:suse, :sles]
- confine :operatingsystem => [:suse, :sles]
-
- # Install a package using 'rug'.
- def install
- should = @resource.should(:ensure)
- self.debug "Ensuring => #{should}"
- wanted = @resource[:name]
-
- # XXX: We don't actually deal with epochs here.
- case should
- when true, false, Symbol
- # pass
- else
- # Add the package version
- wanted += "-#{should}"
- end
- output = rug "--quiet", :install, "-y", wanted
-
- unless self.query
- raise Puppet::ExecutionFailure.new(
- "Could not find package #{self.name}"
- )
- end
+ desc "Support for suse ``rug`` package manager."
+
+ has_feature :versionable
+
+ commands :rug => "/usr/bin/rug"
+ commands :rpm => "rpm"
+ defaultfor :operatingsystem => [:suse, :sles]
+ confine :operatingsystem => [:suse, :sles]
+
+ # Install a package using 'rug'.
+ def install
+ should = @resource.should(:ensure)
+ self.debug "Ensuring => #{should}"
+ wanted = @resource[:name]
+
+ # XXX: We don't actually deal with epochs here.
+ case should
+ when true, false, Symbol
+ # pass
+ else
+ # Add the package version
+ wanted += "-#{should}"
end
+ output = rug "--quiet", :install, "-y", wanted
- # What's the latest package version available?
- def latest
- #rug can only get a list of *all* available packages?
- output = rug "list-updates"
-
- if output =~ /#{Regexp.escape @resource[:name]}\s*\|\s*([^\s\|]+)/
- return $1
- else
- # rug didn't find updates, pretend the current
- # version is the latest
- return @property_hash[:ensure]
- end
+ unless self.query
+ raise Puppet::ExecutionFailure.new(
+ "Could not find package #{self.name}"
+ )
end
-
- def update
- # rug install can be used for update, too
- self.install
+ end
+
+ # What's the latest package version available?
+ def latest
+ #rug can only get a list of *all* available packages?
+ output = rug "list-updates"
+
+ if output =~ /#{Regexp.escape @resource[:name]}\s*\|\s*([^\s\|]+)/
+ return $1
+ else
+ # rug didn't find updates, pretend the current
+ # version is the latest
+ return @property_hash[:ensure]
end
+ end
+
+ def update
+ # rug install can be used for update, too
+ self.install
+ end
end
diff --git a/lib/puppet/provider/package/sun.rb b/lib/puppet/provider/package/sun.rb
index c98636e11..05bbe9726 100755
--- a/lib/puppet/provider/package/sun.rb
+++ b/lib/puppet/provider/package/sun.rb
@@ -3,153 +3,153 @@
require 'puppet/provider/package'
Puppet::Type.type(:package).provide :sun, :parent => Puppet::Provider::Package do
- desc "Sun's packaging system. Requires that you specify the source for
- the packages you're managing."
- commands :pkginfo => "/usr/bin/pkginfo",
- :pkgadd => "/usr/sbin/pkgadd",
- :pkgrm => "/usr/sbin/pkgrm"
-
- confine :operatingsystem => :solaris
-
- defaultfor :operatingsystem => :solaris
-
- def self.instances
- packages = []
- hash = {}
- names = {
- "PKGINST" => :name,
- "NAME" => nil,
- "CATEGORY" => :category,
- "ARCH" => :platform,
- "VERSION" => :ensure,
- "BASEDIR" => :root,
- "HOTLINE" => nil,
- "EMAIL" => nil,
- "VENDOR" => :vendor,
- "DESC" => :description,
- "PSTAMP" => nil,
- "INSTDATE" => nil,
- "STATUS" => nil,
- "FILES" => nil
- }
-
- cmd = "#{command(:pkginfo)} -l"
-
- # list out all of the packages
- execpipe(cmd) { |process|
- # we're using the long listing, so each line is a separate
- # piece of information
- process.each { |line|
- case line
- when /^$/
- hash[:provider] = :sun
-
- packages << new(hash)
- hash = {}
- when /\s*(\w+):\s+(.+)/
- name = $1
- value = $2
- if names.include?(name)
- hash[names[name]] = value unless names[name].nil?
- end
- when /\s+\d+.+/
- # nothing; we're ignoring the FILES info
- end
- }
- }
- packages
- end
-
- # Get info on a package, optionally specifying a device.
- def info2hash(device = nil)
- names = {
- "PKGINST" => :name,
- "NAME" => nil,
- "CATEGORY" => :category,
- "ARCH" => :platform,
- "VERSION" => :ensure,
- "BASEDIR" => :root,
- "HOTLINE" => nil,
- "EMAIL" => nil,
- "VSTOCK" => nil,
- "VENDOR" => :vendor,
- "DESC" => :description,
- "PSTAMP" => nil,
- "INSTDATE" => nil,
- "STATUS" => nil,
- "FILES" => nil
- }
-
- hash = {}
- cmd = "#{command(:pkginfo)} -l"
- cmd += " -d #{device}" if device
- cmd += " #{@resource[:name]}"
-
- begin
- # list out all of the packages
- execpipe(cmd) { |process|
- # we're using the long listing, so each line is a separate
- # piece of information
- process.readlines.each { |line|
- case line
- when /^$/ # ignore
- when /\s*([A-Z]+):\s+(.+)/
- name = $1
- value = $2
- if names.include?(name)
- hash[names[name]] = value unless names[name].nil?
- end
- when /\s+\d+.+/
- # nothing; we're ignoring the FILES info
- end
- }
- }
- return hash
- rescue Puppet::ExecutionFailure => detail
- return {:ensure => :absent} if detail.message =~ /information for "#{Regexp.escape(@resource[:name])}" was not found/
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Unable to get information about package #{@resource[:name]} because of: #{detail}"
+ desc "Sun's packaging system. Requires that you specify the source for
+ the packages you're managing."
+ commands :pkginfo => "/usr/bin/pkginfo",
+ :pkgadd => "/usr/sbin/pkgadd",
+ :pkgrm => "/usr/sbin/pkgrm"
+
+ confine :operatingsystem => :solaris
+
+ defaultfor :operatingsystem => :solaris
+
+ def self.instances
+ packages = []
+ hash = {}
+ names = {
+ "PKGINST" => :name,
+ "NAME" => nil,
+ "CATEGORY" => :category,
+ "ARCH" => :platform,
+ "VERSION" => :ensure,
+ "BASEDIR" => :root,
+ "HOTLINE" => nil,
+ "EMAIL" => nil,
+ "VENDOR" => :vendor,
+ "DESC" => :description,
+ "PSTAMP" => nil,
+ "INSTDATE" => nil,
+ "STATUS" => nil,
+ "FILES" => nil
+ }
+
+ cmd = "#{command(:pkginfo)} -l"
+
+ # list out all of the packages
+ execpipe(cmd) { |process|
+ # we're using the long listing, so each line is a separate
+ # piece of information
+ process.each { |line|
+ case line
+ when /^$/
+ hash[:provider] = :sun
+
+ packages << new(hash)
+ hash = {}
+ when /\s*(\w+):\s+(.+)/
+ name = $1
+ value = $2
+ if names.include?(name)
+ hash[names[name]] = value unless names[name].nil?
+ end
+ when /\s+\d+.+/
+ # nothing; we're ignoring the FILES info
end
+ }
+ }
+ packages
+ end
+
+ # Get info on a package, optionally specifying a device.
+ def info2hash(device = nil)
+ names = {
+ "PKGINST" => :name,
+ "NAME" => nil,
+ "CATEGORY" => :category,
+ "ARCH" => :platform,
+ "VERSION" => :ensure,
+ "BASEDIR" => :root,
+ "HOTLINE" => nil,
+ "EMAIL" => nil,
+ "VSTOCK" => nil,
+ "VENDOR" => :vendor,
+ "DESC" => :description,
+ "PSTAMP" => nil,
+ "INSTDATE" => nil,
+ "STATUS" => nil,
+ "FILES" => nil
+ }
+
+ hash = {}
+ cmd = "#{command(:pkginfo)} -l"
+ cmd += " -d #{device}" if device
+ cmd += " #{@resource[:name]}"
+
+ begin
+ # list out all of the packages
+ execpipe(cmd) { |process|
+ # we're using the long listing, so each line is a separate
+ # piece of information
+ process.readlines.each { |line|
+ case line
+ when /^$/ # ignore
+ when /\s*([A-Z]+):\s+(.+)/
+ name = $1
+ value = $2
+ if names.include?(name)
+ hash[names[name]] = value unless names[name].nil?
+ end
+ when /\s+\d+.+/
+ # nothing; we're ignoring the FILES info
+ end
+ }
+ }
+ return hash
+ rescue Puppet::ExecutionFailure => detail
+ return {:ensure => :absent} if detail.message =~ /information for "#{Regexp.escape(@resource[:name])}" was not found/
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Unable to get information about package #{@resource[:name]} because of: #{detail}"
end
+ end
- def install
- raise Puppet::Error, "Sun packages must specify a package source" unless @resource[:source]
- cmd = []
+ def install
+ raise Puppet::Error, "Sun packages must specify a package source" unless @resource[:source]
+ cmd = []
- cmd << "-a" << @resource[:adminfile] if @resource[:adminfile]
+ cmd << "-a" << @resource[:adminfile] if @resource[:adminfile]
- cmd << "-r" << @resource[:responsefile] if @resource[:responsefile]
+ cmd << "-r" << @resource[:responsefile] if @resource[:responsefile]
- cmd << "-d" << @resource[:source]
- cmd << "-n" << @resource[:name]
+ cmd << "-d" << @resource[:source]
+ cmd << "-n" << @resource[:name]
- pkgadd cmd
- end
+ pkgadd cmd
+ end
- # Retrieve the version from the current package file.
- def latest
- hash = info2hash(@resource[:source])
- hash[:ensure]
- end
+ # Retrieve the version from the current package file.
+ def latest
+ hash = info2hash(@resource[:source])
+ hash[:ensure]
+ end
- def query
- info2hash()
- end
+ def query
+ info2hash()
+ end
- def uninstall
- command = ["-n"]
+ def uninstall
+ command = ["-n"]
- command << "-a" << @resource[:adminfile] if @resource[:adminfile]
+ command << "-a" << @resource[:adminfile] if @resource[:adminfile]
- command << @resource[:name]
- pkgrm command
- end
+ command << @resource[:name]
+ pkgrm command
+ end
- # Remove the old package, and install the new one. This will probably
- # often fail.
- def update
- self.uninstall if (@property_hash[:ensure] || info2hash()[:ensure]) != :absent
- self.install
- end
+ # Remove the old package, and install the new one. This will probably
+ # often fail.
+ def update
+ self.uninstall if (@property_hash[:ensure] || info2hash()[:ensure]) != :absent
+ self.install
+ end
end
diff --git a/lib/puppet/provider/package/sunfreeware.rb b/lib/puppet/provider/package/sunfreeware.rb
index d7bcd0982..53f03ed6e 100755
--- a/lib/puppet/provider/package/sunfreeware.rb
+++ b/lib/puppet/provider/package/sunfreeware.rb
@@ -1,11 +1,11 @@
# At this point, it's an exact copy of the Blastwave stuff.
Puppet::Type.type(:package).provide :sunfreeware, :parent => :blastwave, :source => :sun do
- desc "Package management using sunfreeware.com's ``pkg-get`` command on Solaris.
- At this point, support is exactly the same as ``blastwave`` support and
- has not actually been tested."
- commands :pkgget => "pkg-get"
+ desc "Package management using sunfreeware.com's ``pkg-get`` command on Solaris.
+ At this point, support is exactly the same as ``blastwave`` support and
+ has not actually been tested."
+ commands :pkgget => "pkg-get"
- confine :operatingsystem => :solaris
+ confine :operatingsystem => :solaris
end
diff --git a/lib/puppet/provider/package/up2date.rb b/lib/puppet/provider/package/up2date.rb
index 8780e7fd4..5ff32bedc 100644
--- a/lib/puppet/provider/package/up2date.rb
+++ b/lib/puppet/provider/package/up2date.rb
@@ -1,42 +1,42 @@
Puppet::Type.type(:package).provide :up2date, :parent => :rpm, :source => :rpm do
- desc "Support for Red Hat's proprietary ``up2date`` package update
- mechanism."
+ desc "Support for Red Hat's proprietary ``up2date`` package update
+ mechanism."
- commands :up2date => "/usr/sbin/up2date-nox"
+ commands :up2date => "/usr/sbin/up2date-nox"
- defaultfor :operatingsystem => [:redhat, :oel, :ovm],
- :lsbdistrelease => ["2.1", "3", "4"]
+ defaultfor :operatingsystem => [:redhat, :oel, :ovm],
+ :lsbdistrelease => ["2.1", "3", "4"]
- confine :operatingsystem => [:redhat, :oel, :ovm]
+ confine :operatingsystem => [:redhat, :oel, :ovm]
- # Install a package using 'up2date'.
- def install
- up2date "-u", @resource[:name]
+ # Install a package using 'up2date'.
+ def install
+ up2date "-u", @resource[:name]
- unless self.query
- raise Puppet::ExecutionFailure.new(
- "Could not find package #{self.name}"
- )
- end
+ unless self.query
+ raise Puppet::ExecutionFailure.new(
+ "Could not find package #{self.name}"
+ )
end
-
- # What's the latest package version available?
- def latest
- #up2date can only get a list of *all* available packages?
- output = up2date "--showall"
-
- if output =~ /^#{Regexp.escape @resource[:name]}-(\d+.*)\.\w+/
- return $1
- else
- # up2date didn't find updates, pretend the current
- # version is the latest
- return @property_hash[:ensure]
- end
+ end
+
+ # What's the latest package version available?
+ def latest
+ #up2date can only get a list of *all* available packages?
+ output = up2date "--showall"
+
+ if output =~ /^#{Regexp.escape @resource[:name]}-(\d+.*)\.\w+/
+ return $1
+ else
+ # up2date didn't find updates, pretend the current
+ # version is the latest
+ return @property_hash[:ensure]
end
+ end
- def update
- # Install in up2date can be used for update, too
- self.install
- end
+ def update
+ # Install in up2date can be used for update, too
+ self.install
+ end
end
diff --git a/lib/puppet/provider/package/urpmi.rb b/lib/puppet/provider/package/urpmi.rb
index a7732c4a2..88a17ccb4 100644
--- a/lib/puppet/provider/package/urpmi.rb
+++ b/lib/puppet/provider/package/urpmi.rb
@@ -1,60 +1,60 @@
Puppet::Type.type(:package).provide :urpmi, :parent => :rpm, :source => :rpm do
- desc "Support via ``urpmi``."
- commands :urpmi => "urpmi", :urpmq => "urpmq", :rpm => "rpm"
-
- if command('rpm')
- confine :true => begin
- rpm('-ql', 'rpm')
- rescue Puppet::ExecutionFailure
- false
- else
- true
- end
+ desc "Support via ``urpmi``."
+ commands :urpmi => "urpmi", :urpmq => "urpmq", :rpm => "rpm"
+
+ if command('rpm')
+ confine :true => begin
+ rpm('-ql', 'rpm')
+ rescue Puppet::ExecutionFailure
+ false
+ else
+ true
+ end
+ end
+
+ defaultfor :operatingsystem => [:mandriva, :mandrake]
+
+ has_feature :versionable
+
+ def install
+ should = @resource.should(:ensure)
+ self.debug "Ensuring => #{should}"
+ wanted = @resource[:name]
+
+ # XXX: We don't actually deal with epochs here.
+ case should
+ when true, false, Symbol
+ # pass
+ else
+ # Add the package version
+ wanted += "-#{should}"
end
- defaultfor :operatingsystem => [:mandriva, :mandrake]
+ output = urpmi "--auto", wanted
- has_feature :versionable
-
- def install
- should = @resource.should(:ensure)
- self.debug "Ensuring => #{should}"
- wanted = @resource[:name]
-
- # XXX: We don't actually deal with epochs here.
- case should
- when true, false, Symbol
- # pass
- else
- # Add the package version
- wanted += "-#{should}"
- end
-
- output = urpmi "--auto", wanted
-
- unless self.query
- raise Puppet::Error.new(
- "Could not find package #{self.name}"
- )
- end
+ unless self.query
+ raise Puppet::Error.new(
+ "Could not find package #{self.name}"
+ )
end
-
- # What's the latest package version available?
- def latest
- output = urpmq "-S", @resource[:name]
-
- if output =~ /^#{Regexp.escape @resource[:name]}\s+:\s+.*\(\s+(\S+)\s+\)/
- return $1
- else
- # urpmi didn't find updates, pretend the current
- # version is the latest
- return @resource[:ensure]
- end
+ end
+
+ # What's the latest package version available?
+ def latest
+ output = urpmq "-S", @resource[:name]
+
+ if output =~ /^#{Regexp.escape @resource[:name]}\s+:\s+.*\(\s+(\S+)\s+\)/
+ return $1
+ else
+ # urpmi didn't find updates, pretend the current
+ # version is the latest
+ return @resource[:ensure]
end
+ end
- def update
- # Install in urpmi can be used for update, too
- self.install
- end
+ def update
+ # Install in urpmi can be used for update, too
+ self.install
+ end
end
diff --git a/lib/puppet/provider/package/yum.rb b/lib/puppet/provider/package/yum.rb
index 17981f03c..07f68ddb1 100755
--- a/lib/puppet/provider/package/yum.rb
+++ b/lib/puppet/provider/package/yum.rb
@@ -1,100 +1,100 @@
Puppet::Type.type(:package).provide :yum, :parent => :rpm, :source => :rpm do
- desc "Support via ``yum``."
-
- has_feature :versionable
-
- commands :yum => "yum", :rpm => "rpm", :python => "python"
-
- YUMHELPER = File::join(File::dirname(__FILE__), "yumhelper.py")
-
- attr_accessor :latest_info
-
- if command('rpm')
- confine :true => begin
- rpm('--version')
- rescue Puppet::ExecutionFailure
- false
- else
- true
- end
- end
-
- defaultfor :operatingsystem => [:fedora, :centos, :redhat]
-
- def self.prefetch(packages)
- raise Puppet::Error, "The yum provider can only be used as root" if Process.euid != 0
- super
- return unless packages.detect { |name, package| package.should(:ensure) == :latest }
-
- # collect our 'latest' info
- updates = {}
- python(YUMHELPER).each_line do |l|
- l.chomp!
- next if l.empty?
- if l[0,4] == "_pkg"
- hash = nevra_to_hash(l[5..-1])
- [hash[:name], "#{hash[:name]}.#{hash[:arch]}"].each do |n|
- updates[n] ||= []
- updates[n] << hash
- end
- end
- end
-
- # Add our 'latest' info to the providers.
- packages.each do |name, package|
- if info = updates[package[:name]]
- package.provider.latest_info = info[0]
- end
+ desc "Support via ``yum``."
+
+ has_feature :versionable
+
+ commands :yum => "yum", :rpm => "rpm", :python => "python"
+
+ YUMHELPER = File::join(File::dirname(__FILE__), "yumhelper.py")
+
+ attr_accessor :latest_info
+
+ if command('rpm')
+ confine :true => begin
+ rpm('--version')
+ rescue Puppet::ExecutionFailure
+ false
+ else
+ true
+ end
+ end
+
+ defaultfor :operatingsystem => [:fedora, :centos, :redhat]
+
+ def self.prefetch(packages)
+ raise Puppet::Error, "The yum provider can only be used as root" if Process.euid != 0
+ super
+ return unless packages.detect { |name, package| package.should(:ensure) == :latest }
+
+ # collect our 'latest' info
+ updates = {}
+ python(YUMHELPER).each_line do |l|
+ l.chomp!
+ next if l.empty?
+ if l[0,4] == "_pkg"
+ hash = nevra_to_hash(l[5..-1])
+ [hash[:name], "#{hash[:name]}.#{hash[:arch]}"].each do |n|
+ updates[n] ||= []
+ updates[n] << hash
end
+ end
end
- def install
- should = @resource.should(:ensure)
- self.debug "Ensuring => #{should}"
- wanted = @resource[:name]
-
- # XXX: We don't actually deal with epochs here.
- case should
- when true, false, Symbol
- # pass
- should = nil
- else
- # Add the package version
- wanted += "-#{should}"
- end
-
- output = yum "-d", "0", "-e", "0", "-y", :install, wanted
-
- is = self.query
- raise Puppet::Error, "Could not find package #{self.name}" unless is
-
- # FIXME: Should we raise an exception even if should == :latest
- # and yum updated us to a version other than @param_hash[:ensure] ?
- raise Puppet::Error, "Failed to update to version #{should}, got version #{is[:ensure]} instead" if should && should != is[:ensure]
+ # Add our 'latest' info to the providers.
+ packages.each do |name, package|
+ if info = updates[package[:name]]
+ package.provider.latest_info = info[0]
+ end
end
-
- # What's the latest package version available?
- def latest
- upd = latest_info
- unless upd.nil?
- # FIXME: there could be more than one update for a package
- # because of multiarch
- return "#{upd[:version]}-#{upd[:release]}"
- else
- # Yum didn't find updates, pretend the current
- # version is the latest
- raise Puppet::DevError, "Tried to get latest on a missing package" if properties[:ensure] == :absent
- return properties[:ensure]
- end
+ end
+
+ def install
+ should = @resource.should(:ensure)
+ self.debug "Ensuring => #{should}"
+ wanted = @resource[:name]
+
+ # XXX: We don't actually deal with epochs here.
+ case should
+ when true, false, Symbol
+ # pass
+ should = nil
+ else
+ # Add the package version
+ wanted += "-#{should}"
end
- def update
- # Install in yum can be used for update, too
- self.install
+ output = yum "-d", "0", "-e", "0", "-y", :install, wanted
+
+ is = self.query
+ raise Puppet::Error, "Could not find package #{self.name}" unless is
+
+ # FIXME: Should we raise an exception even if should == :latest
+ # and yum updated us to a version other than @param_hash[:ensure] ?
+ raise Puppet::Error, "Failed to update to version #{should}, got version #{is[:ensure]} instead" if should && should != is[:ensure]
+ end
+
+ # What's the latest package version available?
+ def latest
+ upd = latest_info
+ unless upd.nil?
+ # FIXME: there could be more than one update for a package
+ # because of multiarch
+ return "#{upd[:version]}-#{upd[:release]}"
+ else
+ # Yum didn't find updates, pretend the current
+ # version is the latest
+ raise Puppet::DevError, "Tried to get latest on a missing package" if properties[:ensure] == :absent
+ return properties[:ensure]
end
+ end
- def purge
- yum "-y", :erase, @resource[:name]
- end
+ def update
+ # Install in yum can be used for update, too
+ self.install
+ end
+
+ def purge
+ yum "-y", :erase, @resource[:name]
+ end
end
diff --git a/lib/puppet/provider/package/zypper.rb b/lib/puppet/provider/package/zypper.rb
index 9f7386b20..d56c72549 100644
--- a/lib/puppet/provider/package/zypper.rb
+++ b/lib/puppet/provider/package/zypper.rb
@@ -1,52 +1,52 @@
Puppet::Type.type(:package).provide :zypper, :parent => :rpm do
- desc "Support for SuSE ``zypper`` package manager. Found in SLES10sp2+ and SLES11"
-
- has_feature :versionable
-
- commands :zypper => "/usr/bin/zypper"
- commands :rpm => "rpm"
-
- confine :operatingsystem => [:suse, :sles, :sled, :opensuse]
-
- # Install a package using 'zypper'.
- def install
- should = @resource.should(:ensure)
- self.debug "Ensuring => #{should}"
- wanted = @resource[:name]
-
- # XXX: We don't actually deal with epochs here.
- case should
- when true, false, Symbol
- # pass
- else
- # Add the package version
- wanted = "#{wanted}-#{should}"
- end
- output = zypper "--quiet", :install, "-l", "-y", wanted
-
- unless self.query
- raise Puppet::ExecutionFailure.new(
- "Could not find package #{self.name}"
- )
- end
- end
+ desc "Support for SuSE ``zypper`` package manager. Found in SLES10sp2+ and SLES11"
+
+ has_feature :versionable
+
+ commands :zypper => "/usr/bin/zypper"
+ commands :rpm => "rpm"
+
+ confine :operatingsystem => [:suse, :sles, :sled, :opensuse]
- # What's the latest package version available?
- def latest
- #zypper can only get a list of *all* available packages?
- output = zypper "list-updates"
-
- if output =~ /#{Regexp.escape @resource[:name]}\s*\|\s*([^\s\|]+)/
- return $1
- else
- # zypper didn't find updates, pretend the current
- # version is the latest
- return @property_hash[:ensure]
- end
+ # Install a package using 'zypper'.
+ def install
+ should = @resource.should(:ensure)
+ self.debug "Ensuring => #{should}"
+ wanted = @resource[:name]
+
+ # XXX: We don't actually deal with epochs here.
+ case should
+ when true, false, Symbol
+ # pass
+ else
+ # Add the package version
+ wanted = "#{wanted}-#{should}"
end
+ output = zypper "--quiet", :install, "-l", "-y", wanted
- def update
- # zypper install can be used for update, too
- self.install
+ unless self.query
+ raise Puppet::ExecutionFailure.new(
+ "Could not find package #{self.name}"
+ )
+ end
+ end
+
+ # What's the latest package version available?
+ def latest
+ #zypper can only get a list of *all* available packages?
+ output = zypper "list-updates"
+
+ if output =~ /#{Regexp.escape @resource[:name]}\s*\|\s*([^\s\|]+)/
+ return $1
+ else
+ # zypper didn't find updates, pretend the current
+ # version is the latest
+ return @property_hash[:ensure]
end
+ end
+
+ def update
+ # zypper install can be used for update, too
+ self.install
+ end
end
diff --git a/lib/puppet/provider/parsedfile.rb b/lib/puppet/provider/parsedfile.rb
index 811607abb..ffd36e59f 100755
--- a/lib/puppet/provider/parsedfile.rb
+++ b/lib/puppet/provider/parsedfile.rb
@@ -11,124 +11,124 @@ require 'puppet/util/fileparsing'
# Once the provider prefetches the data, it's the resource's job to copy
# that data over to the @is variables.
class Puppet::Provider::ParsedFile < Puppet::Provider
- extend Puppet::Util::FileParsing
+ extend Puppet::Util::FileParsing
- class << self
- attr_accessor :default_target, :target
- end
-
- attr_accessor :property_hash
+ class << self
+ attr_accessor :default_target, :target
+ end
- def self.clean(hash)
- newhash = hash.dup
- [:record_type, :on_disk].each do |p|
- newhash.delete(p) if newhash.include?(p)
- end
+ attr_accessor :property_hash
- newhash
+ def self.clean(hash)
+ newhash = hash.dup
+ [:record_type, :on_disk].each do |p|
+ newhash.delete(p) if newhash.include?(p)
end
- def self.clear
- @target_objects.clear
- @records.clear
- end
+ newhash
+ end
- def self.filetype
- @filetype ||= Puppet::Util::FileType.filetype(:flat)
- end
+ def self.clear
+ @target_objects.clear
+ @records.clear
+ end
- def self.filetype=(type)
- if type.is_a?(Class)
- @filetype = type
- elsif klass = Puppet::Util::FileType.filetype(type)
- @filetype = klass
- else
- raise ArgumentError, "Invalid filetype #{type}"
- end
+ def self.filetype
+ @filetype ||= Puppet::Util::FileType.filetype(:flat)
+ end
+
+ def self.filetype=(type)
+ if type.is_a?(Class)
+ @filetype = type
+ elsif klass = Puppet::Util::FileType.filetype(type)
+ @filetype = klass
+ else
+ raise ArgumentError, "Invalid filetype #{type}"
end
+ end
- # Flush all of the targets for which there are modified records. The only
- # reason we pass a record here is so that we can add it to the stack if
- # necessary -- it's passed from the instance calling 'flush'.
- def self.flush(record)
- # Make sure this record is on the list to be flushed.
- unless record[:on_disk]
- record[:on_disk] = true
- @records << record
-
- # If we've just added the record, then make sure our
- # target will get flushed.
- modified(record[:target] || default_target)
- end
+ # Flush all of the targets for which there are modified records. The only
+ # reason we pass a record here is so that we can add it to the stack if
+ # necessary -- it's passed from the instance calling 'flush'.
+ def self.flush(record)
+ # Make sure this record is on the list to be flushed.
+ unless record[:on_disk]
+ record[:on_disk] = true
+ @records << record
- return unless defined?(@modified) and ! @modified.empty?
+ # If we've just added the record, then make sure our
+ # target will get flushed.
+ modified(record[:target] || default_target)
+ end
- flushed = []
- @modified.sort { |a,b| a.to_s <=> b.to_s }.uniq.each do |target|
- Puppet.debug "Flushing #{@resource_type.name} provider target #{target}"
- flush_target(target)
- flushed << target
- end
+ return unless defined?(@modified) and ! @modified.empty?
- @modified.reject! { |t| flushed.include?(t) }
+ flushed = []
+ @modified.sort { |a,b| a.to_s <=> b.to_s }.uniq.each do |target|
+ Puppet.debug "Flushing #{@resource_type.name} provider target #{target}"
+ flush_target(target)
+ flushed << target
end
- # Make sure our file is backed up, but only back it up once per transaction.
- # We cheat and rely on the fact that @records is created on each prefetch.
- def self.backup_target(target)
- return nil unless target_object(target).respond_to?(:backup)
+ @modified.reject! { |t| flushed.include?(t) }
+ end
- @backup_stats ||= {}
- return nil if @backup_stats[target] == @records.object_id
+ # Make sure our file is backed up, but only back it up once per transaction.
+ # We cheat and rely on the fact that @records is created on each prefetch.
+ def self.backup_target(target)
+ return nil unless target_object(target).respond_to?(:backup)
- target_object(target).backup
- @backup_stats[target] = @records.object_id
- end
+ @backup_stats ||= {}
+ return nil if @backup_stats[target] == @records.object_id
- # Flush all of the records relating to a specific target.
- def self.flush_target(target)
- backup_target(target)
+ target_object(target).backup
+ @backup_stats[target] = @records.object_id
+ end
- records = target_records(target).reject { |r|
- r[:ensure] == :absent
- }
- target_object(target).write(to_file(records))
- end
+ # Flush all of the records relating to a specific target.
+ def self.flush_target(target)
+ backup_target(target)
- # Return the header placed at the top of each generated file, warning
- # users that modifying this file manually is probably a bad idea.
- def self.header
+ records = target_records(target).reject { |r|
+ r[:ensure] == :absent
+ }
+ target_object(target).write(to_file(records))
+ end
+
+ # Return the header placed at the top of each generated file, warning
+ # users that modifying this file manually is probably a bad idea.
+ def self.header
%{# HEADER: This file was autogenerated at #{Time.now}
# HEADER: by puppet. While it can still be managed manually, it
# HEADER: is definitely not recommended.\n}
- end
-
- # Add another type var.
- def self.initvars
- @records = []
- @target_objects = {}
-
- @target = nil
-
- # Default to flat files
- @filetype ||= Puppet::Util::FileType.filetype(:flat)
- super
- end
-
- # Return a list of all of the records we can find.
- def self.instances
- targets.collect do |target|
- prefetch_target(target)
- end.flatten.reject { |r| skip_record?(r) }.collect do |record|
- new(record)
- end
- end
-
- # Override the default method with a lot more functionality.
- def self.mk_resource_methods
- [resource_type.validproperties, resource_type.parameters].flatten.each do |attr|
- attr = symbolize(attr)
- define_method(attr) do
+ end
+
+ # Add another type var.
+ def self.initvars
+ @records = []
+ @target_objects = {}
+
+ @target = nil
+
+ # Default to flat files
+ @filetype ||= Puppet::Util::FileType.filetype(:flat)
+ super
+ end
+
+ # Return a list of all of the records we can find.
+ def self.instances
+ targets.collect do |target|
+ prefetch_target(target)
+ end.flatten.reject { |r| skip_record?(r) }.collect do |record|
+ new(record)
+ end
+ end
+
+ # Override the default method with a lot more functionality.
+ def self.mk_resource_methods
+ [resource_type.validproperties, resource_type.parameters].flatten.each do |attr|
+ attr = symbolize(attr)
+ define_method(attr) do
# if @property_hash.empty?
# # Note that this swaps the provider out from under us.
# prefetch
@@ -138,235 +138,235 @@ class Puppet::Provider::ParsedFile < Puppet::Provider
# return @resource.provider.send(attr)
# end
# end
- # If it's not a valid field for this record type (which can happen
- # when different platforms support different fields), then just
- # return the should value, so the resource shuts up.
- if @property_hash[attr] or self.class.valid_attr?(self.class.name, attr)
- @property_hash[attr] || :absent
- else
- if defined?(@resource)
- @resource.should(attr)
- else
- nil
- end
- end
- end
-
- define_method(attr.to_s + "=") do |val|
- mark_target_modified
- @property_hash[attr] = val
- end
- end
- end
-
- # Always make the resource methods.
- def self.resource_type=(resource)
- super
- mk_resource_methods
- end
-
- # Mark a target as modified so we know to flush it. This only gets
- # used within the attr= methods.
- def self.modified(target)
- @modified ||= []
- @modified << target unless @modified.include?(target)
- end
-
- # Retrieve all of the data from disk. There are three ways to know
- # which files to retrieve: We might have a list of file objects already
- # set up, there might be instances of our associated resource and they
- # will have a path parameter set, and we will have a default path
- # set. We need to turn those three locations into a list of files,
- # prefetch each one, and make sure they're associated with each appropriate
- # resource instance.
- def self.prefetch(resources = nil)
- # Reset the record list.
- @records = prefetch_all_targets(resources)
-
- match_providers_with_resources(resources)
- end
-
- def self.match_providers_with_resources(resources)
- return unless resources
- matchers = resources.dup
- @records.each do |record|
- # Skip things like comments and blank lines
- next if skip_record?(record)
-
- if name = record[:name] and resource = resources[name]
- resource.provider = new(record)
- elsif respond_to?(:match)
- if resource = match(record, matchers)
- # Remove this resource from circulation so we don't unnecessarily try to match
- matchers.delete(resource.title)
- record[:name] = resource[:name]
- resource.provider = new(record)
- end
- end
- end
- end
-
- def self.prefetch_all_targets(resources)
- records = []
- targets(resources).each do |target|
- records += prefetch_target(target)
+ # If it's not a valid field for this record type (which can happen
+ # when different platforms support different fields), then just
+ # return the should value, so the resource shuts up.
+ if @property_hash[attr] or self.class.valid_attr?(self.class.name, attr)
+ @property_hash[attr] || :absent
+ else
+ if defined?(@resource)
+ @resource.should(attr)
+ else
+ nil
+ end
end
- records
- end
+ end
- # Prefetch an individual target.
- def self.prefetch_target(target)
- target_records = retrieve(target).each do |r|
- r[:on_disk] = true
- r[:target] = target
- r[:ensure] = :present
+ define_method(attr.to_s + "=") do |val|
+ mark_target_modified
+ @property_hash[attr] = val
+ end
+ end
+ end
+
+ # Always make the resource methods.
+ def self.resource_type=(resource)
+ super
+ mk_resource_methods
+ end
+
+ # Mark a target as modified so we know to flush it. This only gets
+ # used within the attr= methods.
+ def self.modified(target)
+ @modified ||= []
+ @modified << target unless @modified.include?(target)
+ end
+
+ # Retrieve all of the data from disk. There are three ways to know
+ # which files to retrieve: We might have a list of file objects already
+ # set up, there might be instances of our associated resource and they
+ # will have a path parameter set, and we will have a default path
+ # set. We need to turn those three locations into a list of files,
+ # prefetch each one, and make sure they're associated with each appropriate
+ # resource instance.
+ def self.prefetch(resources = nil)
+ # Reset the record list.
+ @records = prefetch_all_targets(resources)
+
+ match_providers_with_resources(resources)
+ end
+
+ def self.match_providers_with_resources(resources)
+ return unless resources
+ matchers = resources.dup
+ @records.each do |record|
+ # Skip things like comments and blank lines
+ next if skip_record?(record)
+
+ if name = record[:name] and resource = resources[name]
+ resource.provider = new(record)
+ elsif respond_to?(:match)
+ if resource = match(record, matchers)
+ # Remove this resource from circulation so we don't unnecessarily try to match
+ matchers.delete(resource.title)
+ record[:name] = resource[:name]
+ resource.provider = new(record)
end
-
- target_records = prefetch_hook(target_records) if respond_to?(:prefetch_hook)
-
- raise Puppet::DevError, "Prefetching #{target} for provider #{self.name} returned nil" unless target_records
-
- target_records
- end
-
- # Is there an existing record with this name?
- def self.record?(name)
- return nil unless @records
- @records.find { |r| r[:name] == name }
- end
-
- # Retrieve the text for the file. Returns nil in the unlikely
- # event that it doesn't exist.
- def self.retrieve(path)
- # XXX We need to be doing something special here in case of failure.
- text = target_object(path).read
- if text.nil? or text == ""
- # there is no file
- return []
- else
- # Set the target, for logging.
- old = @target
- begin
- @target = path
- return self.parse(text)
- rescue Puppet::Error => detail
- detail.file = @target
- raise detail
- ensure
- @target = old
- end
+ end
+ end
+ end
+
+ def self.prefetch_all_targets(resources)
+ records = []
+ targets(resources).each do |target|
+ records += prefetch_target(target)
+ end
+ records
+ end
+
+ # Prefetch an individual target.
+ def self.prefetch_target(target)
+ target_records = retrieve(target).each do |r|
+ r[:on_disk] = true
+ r[:target] = target
+ r[:ensure] = :present
+ end
+
+ target_records = prefetch_hook(target_records) if respond_to?(:prefetch_hook)
+
+ raise Puppet::DevError, "Prefetching #{target} for provider #{self.name} returned nil" unless target_records
+
+ target_records
+ end
+
+ # Is there an existing record with this name?
+ def self.record?(name)
+ return nil unless @records
+ @records.find { |r| r[:name] == name }
+ end
+
+ # Retrieve the text for the file. Returns nil in the unlikely
+ # event that it doesn't exist.
+ def self.retrieve(path)
+ # XXX We need to be doing something special here in case of failure.
+ text = target_object(path).read
+ if text.nil? or text == ""
+ # there is no file
+ return []
+ else
+ # Set the target, for logging.
+ old = @target
+ begin
+ @target = path
+ return self.parse(text)
+ rescue Puppet::Error => detail
+ detail.file = @target
+ raise detail
+ ensure
+ @target = old
+ end
+ end
+ end
+
+ # Should we skip the record? Basically, we skip text records.
+ # This is only here so subclasses can override it.
+ def self.skip_record?(record)
+ record_type(record[:record_type]).text?
+ end
+
+ # Initialize the object if necessary.
+ def self.target_object(target)
+ @target_objects[target] ||= filetype.new(target)
+
+ @target_objects[target]
+ end
+
+ # Find all of the records for a given target
+ def self.target_records(target)
+ @records.find_all { |r| r[:target] == target }
+ end
+
+ # Find a list of all of the targets that we should be reading. This is
+ # used to figure out what targets we need to prefetch.
+ def self.targets(resources = nil)
+ targets = []
+ # First get the default target
+ raise Puppet::DevError, "Parsed Providers must define a default target" unless self.default_target
+ targets << self.default_target
+
+ # Then get each of the file objects
+ targets += @target_objects.keys
+
+ # Lastly, check the file from any resource instances
+ if resources
+ resources.each do |name, resource|
+ if value = resource.should(:target)
+ targets << value
end
+ end
end
- # Should we skip the record? Basically, we skip text records.
- # This is only here so subclasses can override it.
- def self.skip_record?(record)
- record_type(record[:record_type]).text?
- end
+ targets.uniq.compact
+ end
- # Initialize the object if necessary.
- def self.target_object(target)
- @target_objects[target] ||= filetype.new(target)
+ def self.to_file(records)
+ text = super
+ header + text
+ end
- @target_objects[target]
+ def create
+ @resource.class.validproperties.each do |property|
+ if value = @resource.should(property)
+ @property_hash[property] = value
+ end
end
+ mark_target_modified
+ (@resource.class.name.to_s + "_created").intern
+ end
- # Find all of the records for a given target
- def self.target_records(target)
- @records.find_all { |r| r[:target] == target }
- end
+ def destroy
+ # We use the method here so it marks the target as modified.
+ self.ensure = :absent
+ (@resource.class.name.to_s + "_deleted").intern
+ end
- # Find a list of all of the targets that we should be reading. This is
- # used to figure out what targets we need to prefetch.
- def self.targets(resources = nil)
- targets = []
- # First get the default target
- raise Puppet::DevError, "Parsed Providers must define a default target" unless self.default_target
- targets << self.default_target
-
- # Then get each of the file objects
- targets += @target_objects.keys
-
- # Lastly, check the file from any resource instances
- if resources
- resources.each do |name, resource|
- if value = resource.should(:target)
- targets << value
- end
- end
- end
+ def exists?
+ !(@property_hash[:ensure] == :absent or @property_hash[:ensure].nil?)
+ end
- targets.uniq.compact
- end
+ # Write our data to disk.
+ def flush
+ # Make sure we've got a target and name set.
- def self.to_file(records)
- text = super
- header + text
+ # If the target isn't set, then this is our first modification, so
+ # mark it for flushing.
+ unless @property_hash[:target]
+ @property_hash[:target] = @resource.should(:target) || self.class.default_target
+ self.class.modified(@property_hash[:target])
end
+ @property_hash[:name] ||= @resource.name
- def create
- @resource.class.validproperties.each do |property|
- if value = @resource.should(property)
- @property_hash[property] = value
- end
- end
- mark_target_modified
- (@resource.class.name.to_s + "_created").intern
- end
-
- def destroy
- # We use the method here so it marks the target as modified.
- self.ensure = :absent
- (@resource.class.name.to_s + "_deleted").intern
- end
-
- def exists?
- !(@property_hash[:ensure] == :absent or @property_hash[:ensure].nil?)
- end
-
- # Write our data to disk.
- def flush
- # Make sure we've got a target and name set.
+ self.class.flush(@property_hash)
- # If the target isn't set, then this is our first modification, so
- # mark it for flushing.
- unless @property_hash[:target]
- @property_hash[:target] = @resource.should(:target) || self.class.default_target
- self.class.modified(@property_hash[:target])
- end
- @property_hash[:name] ||= @resource.name
-
- self.class.flush(@property_hash)
-
- #@property_hash = {}
- end
+ #@property_hash = {}
+ end
- def initialize(record)
- super
+ def initialize(record)
+ super
- # The 'record' could be a resource or a record, depending on how the provider
- # is initialized. If we got an empty property hash (probably because the resource
- # is just being initialized), then we want to set up some defualts.
- @property_hash = self.class.record?(resource[:name]) || {:record_type => self.class.name, :ensure => :absent} if @property_hash.empty?
- end
+ # The 'record' could be a resource or a record, depending on how the provider
+ # is initialized. If we got an empty property hash (probably because the resource
+ # is just being initialized), then we want to set up some defualts.
+ @property_hash = self.class.record?(resource[:name]) || {:record_type => self.class.name, :ensure => :absent} if @property_hash.empty?
+ end
- # Retrieve the current state from disk.
- def prefetch
- raise Puppet::DevError, "Somehow got told to prefetch with no resource set" unless @resource
- self.class.prefetch(@resource[:name] => @resource)
- end
+ # Retrieve the current state from disk.
+ def prefetch
+ raise Puppet::DevError, "Somehow got told to prefetch with no resource set" unless @resource
+ self.class.prefetch(@resource[:name] => @resource)
+ end
- def record_type
- @property_hash[:record_type]
- end
+ def record_type
+ @property_hash[:record_type]
+ end
- private
+ private
- # Mark both the resource and provider target as modified.
- def mark_target_modified
- if defined?(@resource) and restarget = @resource.should(:target) and restarget != @property_hash[:target]
- self.class.modified(restarget)
- end
- self.class.modified(@property_hash[:target]) if @property_hash[:target] != :absent and @property_hash[:target]
+ # Mark both the resource and provider target as modified.
+ def mark_target_modified
+ if defined?(@resource) and restarget = @resource.should(:target) and restarget != @property_hash[:target]
+ self.class.modified(restarget)
end
+ self.class.modified(@property_hash[:target]) if @property_hash[:target] != :absent and @property_hash[:target]
+ end
end
diff --git a/lib/puppet/provider/selboolean/getsetsebool.rb b/lib/puppet/provider/selboolean/getsetsebool.rb
index 259d9471e..cacc41386 100644
--- a/lib/puppet/provider/selboolean/getsetsebool.rb
+++ b/lib/puppet/provider/selboolean/getsetsebool.rb
@@ -1,47 +1,47 @@
Puppet::Type.type(:selboolean).provide(:getsetsebool) do
- desc "Manage SELinux booleans using the getsebool and setsebool binaries."
+ desc "Manage SELinux booleans using the getsebool and setsebool binaries."
- commands :getsebool => "/usr/sbin/getsebool"
- commands :setsebool => "/usr/sbin/setsebool"
+ commands :getsebool => "/usr/sbin/getsebool"
+ commands :setsebool => "/usr/sbin/setsebool"
- def value
- self.debug "Retrieving value of selboolean #{@resource[:name]}"
+ def value
+ self.debug "Retrieving value of selboolean #{@resource[:name]}"
- status = getsebool(@resource[:name])
+ status = getsebool(@resource[:name])
- if status =~ / off$/
- return :off
- elsif status =~ / on$/ then
- return :on
- else
- status.chomp!
- raise Puppet::Error, "Invalid response '#{status}' returned from getsebool"
- end
+ if status =~ / off$/
+ return :off
+ elsif status =~ / on$/ then
+ return :on
+ else
+ status.chomp!
+ raise Puppet::Error, "Invalid response '#{status}' returned from getsebool"
end
+ end
- def value=(new)
- persist = ""
- if @resource[:persistent] == :true
- self.debug "Enabling persistence"
- persist = "-P"
- end
- execoutput("#{command(:setsebool)} #{persist} #{@resource[:name]} #{new}")
- :file_changed
+ def value=(new)
+ persist = ""
+ if @resource[:persistent] == :true
+ self.debug "Enabling persistence"
+ persist = "-P"
end
+ execoutput("#{command(:setsebool)} #{persist} #{@resource[:name]} #{new}")
+ :file_changed
+ end
- # Required workaround, since SELinux policy prevents setsebool
- # from writing to any files, even tmp, preventing the standard
- # 'setsebool("...")' construct from working.
+ # Required workaround, since SELinux policy prevents setsebool
+ # from writing to any files, even tmp, preventing the standard
+ # 'setsebool("...")' construct from working.
- def execoutput (cmd)
- output = ''
- begin
- execpipe(cmd) do |out|
- output = out.readlines.join('').chomp!
- end
- rescue Puppet::ExecutionFailure
- raise Puppet::ExecutionFailure, output.split("\n")[0]
- end
- output
+ def execoutput (cmd)
+ output = ''
+ begin
+ execpipe(cmd) do |out|
+ output = out.readlines.join('').chomp!
+ end
+ rescue Puppet::ExecutionFailure
+ raise Puppet::ExecutionFailure, output.split("\n")[0]
end
+ output
+ end
end
diff --git a/lib/puppet/provider/selmodule/semodule.rb b/lib/puppet/provider/selmodule/semodule.rb
index d6bf09a6a..64197156f 100644
--- a/lib/puppet/provider/selmodule/semodule.rb
+++ b/lib/puppet/provider/selmodule/semodule.rb
@@ -1,135 +1,135 @@
Puppet::Type.type(:selmodule).provide(:semodule) do
- desc "Manage SELinux policy modules using the semodule binary."
+ desc "Manage SELinux policy modules using the semodule binary."
- commands :semodule => "/usr/sbin/semodule"
+ commands :semodule => "/usr/sbin/semodule"
- def create
- begin
- execoutput("#{command(:semodule)} --install #{selmod_name_to_filename}")
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not load policy module: #{detail}";
- end
- :true
- end
-
- def destroy
- execoutput("#{command(:semodule)} --remove #{@resource[:name]}")
+ def create
+ begin
+ execoutput("#{command(:semodule)} --install #{selmod_name_to_filename}")
rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not remove policy module: #{detail}";
+ raise Puppet::Error, "Could not load policy module: #{detail}";
end
-
- def exists?
- self.debug "Checking for module #{@resource[:name]}"
- execpipe("#{command(:semodule)} --list") do |out|
- out.each do |line|
- if line =~ /#{@resource[:name]}\b/
- return :true
- end
- end
+ :true
+ end
+
+ def destroy
+ execoutput("#{command(:semodule)} --remove #{@resource[:name]}")
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not remove policy module: #{detail}";
+ end
+
+ def exists?
+ self.debug "Checking for module #{@resource[:name]}"
+ execpipe("#{command(:semodule)} --list") do |out|
+ out.each do |line|
+ if line =~ /#{@resource[:name]}\b/
+ return :true
end
- nil
+ end
end
+ nil
+ end
- def syncversion
- self.debug "Checking syncversion on #{@resource[:name]}"
+ def syncversion
+ self.debug "Checking syncversion on #{@resource[:name]}"
- loadver = selmodversion_loaded
+ loadver = selmodversion_loaded
- if(loadver) then
- filever = selmodversion_file
- if (filever == loadver)
- return :true
- end
- end
- :false
+ if(loadver) then
+ filever = selmodversion_file
+ if (filever == loadver)
+ return :true
+ end
end
-
- def syncversion= (dosync)
- execoutput("#{command(:semodule)} --upgrade #{selmod_name_to_filename}")
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not upgrade policy module: #{detail}";
+ :false
+ end
+
+ def syncversion= (dosync)
+ execoutput("#{command(:semodule)} --upgrade #{selmod_name_to_filename}")
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not upgrade policy module: #{detail}";
+ end
+
+ # Helper functions
+
+ def execoutput (cmd)
+ output = ''
+ begin
+ execpipe(cmd) do |out|
+ output = out.readlines.join('').chomp!
+ end
+ rescue Puppet::ExecutionFailure
+ raise Puppet::ExecutionFailure, output.split("\n")[0]
end
-
- # Helper functions
-
- def execoutput (cmd)
- output = ''
- begin
- execpipe(cmd) do |out|
- output = out.readlines.join('').chomp!
- end
- rescue Puppet::ExecutionFailure
- raise Puppet::ExecutionFailure, output.split("\n")[0]
- end
- output
+ output
+ end
+
+ def selmod_name_to_filename
+ if @resource[:selmodulepath]
+ return @resource[:selmodulepath]
+ else
+ return "#{@resource[:selmoduledir]}/#{@resource[:name]}.pp"
end
+ end
- def selmod_name_to_filename
- if @resource[:selmodulepath]
- return @resource[:selmodulepath]
- else
- return "#{@resource[:selmoduledir]}/#{@resource[:name]}.pp"
- end
- end
+ def selmod_readnext (handle)
+ len = handle.read(4).unpack('L')[0]
+ handle.read(len)
+ end
- def selmod_readnext (handle)
- len = handle.read(4).unpack('L')[0]
- handle.read(len)
- end
-
- def selmodversion_file
- magic = 0xF97CFF8F
+ def selmodversion_file
+ magic = 0xF97CFF8F
- filename = selmod_name_to_filename
- mod = File.new(filename, "r")
+ filename = selmod_name_to_filename
+ mod = File.new(filename, "r")
- (hdr, ver, numsec) = mod.read(12).unpack('LLL')
+ (hdr, ver, numsec) = mod.read(12).unpack('LLL')
- raise Puppet::Error, "Found #{hdr} instead of magic #{magic} in #{filename}" if hdr != magic
+ raise Puppet::Error, "Found #{hdr} instead of magic #{magic} in #{filename}" if hdr != magic
- raise Puppet::Error, "Unknown policy file version #{ver} in #{filename}" if ver != 1
+ raise Puppet::Error, "Unknown policy file version #{ver} in #{filename}" if ver != 1
- # Read through (and throw away) the file section offsets, and also
- # the magic header for the first section.
+ # Read through (and throw away) the file section offsets, and also
+ # the magic header for the first section.
- mod.read((numsec + 1) * 4)
+ mod.read((numsec + 1) * 4)
- ## Section 1 should be "SE Linux Module"
+ ## Section 1 should be "SE Linux Module"
- selmod_readnext(mod)
- selmod_readnext(mod)
+ selmod_readnext(mod)
+ selmod_readnext(mod)
- # Skip past the section headers
- mod.read(14)
+ # Skip past the section headers
+ mod.read(14)
- # Module name
- selmod_readnext(mod)
+ # Module name
+ selmod_readnext(mod)
- # At last! the version
+ # At last! the version
- v = selmod_readnext(mod)
+ v = selmod_readnext(mod)
- self.debug "file version #{v}"
- v
- end
+ self.debug "file version #{v}"
+ v
+ end
- def selmodversion_loaded
- lines = ()
- begin
- execpipe("#{command(:semodule)} --list") do |output|
- lines = output.readlines
- lines.each do |line|
- line.chomp!
- bits = line.split
- if bits[0] == @resource[:name]
- self.debug "load version #{bits[1]}"
- return bits[1]
- end
- end
- end
- rescue Puppet::ExecutionFailure
- raise Puppet::ExecutionFailure, "Could not list policy modules: #{lines.join(' ').chomp!}"
+ def selmodversion_loaded
+ lines = ()
+ begin
+ execpipe("#{command(:semodule)} --list") do |output|
+ lines = output.readlines
+ lines.each do |line|
+ line.chomp!
+ bits = line.split
+ if bits[0] == @resource[:name]
+ self.debug "load version #{bits[1]}"
+ return bits[1]
+ end
end
- nil
+ end
+ rescue Puppet::ExecutionFailure
+ raise Puppet::ExecutionFailure, "Could not list policy modules: #{lines.join(' ').chomp!}"
end
+ nil
+ end
end
diff --git a/lib/puppet/provider/service/base.rb b/lib/puppet/provider/service/base.rb
index 50e8790d1..70d764187 100755
--- a/lib/puppet/provider/service/base.rb
+++ b/lib/puppet/provider/service/base.rb
@@ -1,144 +1,144 @@
Puppet::Type.type(:service).provide :base do
- desc "The simplest form of service support.
-
- You have to specify enough about your service for this to work; the
- minimum you can specify is a binary for starting the process, and this
- same binary will be searched for in the process table to stop the
- service. It is preferable to specify start, stop, and status commands,
- akin to how you would do so using ``init``.
-
- "
-
- commands :kill => "kill"
-
- def self.instances
- []
- end
-
- # Get the process ID for a running process. Requires the 'pattern'
- # parameter.
- def getpid
- @resource.fail "Either stop/status commands or a pattern must be specified" unless @resource[:pattern]
- ps = Facter["ps"].value
- @resource.fail "You must upgrade Facter to a version that includes 'ps'" unless ps and ps != ""
- regex = Regexp.new(@resource[:pattern])
- self.debug "Executing '#{ps}'"
- IO.popen(ps) { |table|
- table.each { |line|
- if regex.match(line)
- ary = line.sub(/^\s+/, '').split(/\s+/)
- return ary[1]
- end
- }
- }
-
- nil
- end
-
- # How to restart the process.
- def restart
- if @resource[:restart] or restartcmd
- ucommand(:restart)
- else
- self.stop
- self.start
- end
- end
-
- # There is no default command, which causes other methods to be used
- def restartcmd
- end
-
- # Check if the process is running. Prefer the 'status' parameter,
- # then 'statuscmd' method, then look in the process table. We give
- # the object the option to not return a status command, which might
- # happen if, for instance, it has an init script (and thus responds to
- # 'statuscmd') but does not have 'hasstatus' enabled.
- def status
- if @resource[:status] or statuscmd
- # Don't fail when the exit status is not 0.
- ucommand(:status, false)
-
- # Expicitly calling exitstatus to facilitate testing
- if $CHILD_STATUS.exitstatus == 0
- return :running
- else
- return :stopped
- end
- elsif pid = self.getpid
- self.debug "PID is #{pid}"
- return :running
- else
- return :stopped
+ desc "The simplest form of service support.
+
+ You have to specify enough about your service for this to work; the
+ minimum you can specify is a binary for starting the process, and this
+ same binary will be searched for in the process table to stop the
+ service. It is preferable to specify start, stop, and status commands,
+ akin to how you would do so using ``init``.
+
+ "
+
+ commands :kill => "kill"
+
+ def self.instances
+ []
+ end
+
+ # Get the process ID for a running process. Requires the 'pattern'
+ # parameter.
+ def getpid
+ @resource.fail "Either stop/status commands or a pattern must be specified" unless @resource[:pattern]
+ ps = Facter["ps"].value
+ @resource.fail "You must upgrade Facter to a version that includes 'ps'" unless ps and ps != ""
+ regex = Regexp.new(@resource[:pattern])
+ self.debug "Executing '#{ps}'"
+ IO.popen(ps) { |table|
+ table.each { |line|
+ if regex.match(line)
+ ary = line.sub(/^\s+/, '').split(/\s+/)
+ return ary[1]
end
+ }
+ }
+
+ nil
+ end
+
+ # How to restart the process.
+ def restart
+ if @resource[:restart] or restartcmd
+ ucommand(:restart)
+ else
+ self.stop
+ self.start
end
-
- # There is no default command, which causes other methods to be used
- def statuscmd
+ end
+
+ # There is no default command, which causes other methods to be used
+ def restartcmd
+ end
+
+ # Check if the process is running. Prefer the 'status' parameter,
+ # then 'statuscmd' method, then look in the process table. We give
+ # the object the option to not return a status command, which might
+ # happen if, for instance, it has an init script (and thus responds to
+ # 'statuscmd') but does not have 'hasstatus' enabled.
+ def status
+ if @resource[:status] or statuscmd
+ # Don't fail when the exit status is not 0.
+ ucommand(:status, false)
+
+ # Expicitly calling exitstatus to facilitate testing
+ if $CHILD_STATUS.exitstatus == 0
+ return :running
+ else
+ return :stopped
+ end
+ elsif pid = self.getpid
+ self.debug "PID is #{pid}"
+ return :running
+ else
+ return :stopped
end
-
- # Run the 'start' parameter command, or the specified 'startcmd'.
- def start
- ucommand(:start)
+ end
+
+ # There is no default command, which causes other methods to be used
+ def statuscmd
+ end
+
+ # Run the 'start' parameter command, or the specified 'startcmd'.
+ def start
+ ucommand(:start)
+ end
+
+ # The command used to start. Generated if the 'binary' argument
+ # is passed.
+ def startcmd
+ if @resource[:binary]
+ return @resource[:binary]
+ else
+ raise Puppet::Error,
+ "Services must specify a start command or a binary"
end
-
- # The command used to start. Generated if the 'binary' argument
- # is passed.
- def startcmd
- if @resource[:binary]
- return @resource[:binary]
- else
- raise Puppet::Error,
- "Services must specify a start command or a binary"
- end
+ end
+
+ # Stop the service. If a 'stop' parameter is specified, it
+ # takes precedence; otherwise checks if the object responds to
+ # a 'stopcmd' method, and if so runs that; otherwise, looks
+ # for the process in the process table.
+ # This method will generally not be overridden by submodules.
+ def stop
+ if @resource[:stop] or stopcmd
+ ucommand(:stop)
+ else
+ pid = getpid
+ unless pid
+ self.info "#{self.name} is not running"
+ return false
+ end
+ begin
+ output = kill pid
+ rescue Puppet::ExecutionFailure => detail
+ @resource.fail "Could not kill #{self.name}, PID #{pid}: #{output}"
+ end
+ return true
end
-
- # Stop the service. If a 'stop' parameter is specified, it
- # takes precedence; otherwise checks if the object responds to
- # a 'stopcmd' method, and if so runs that; otherwise, looks
- # for the process in the process table.
- # This method will generally not be overridden by submodules.
- def stop
- if @resource[:stop] or stopcmd
- ucommand(:stop)
- else
- pid = getpid
- unless pid
- self.info "#{self.name} is not running"
- return false
- end
- begin
- output = kill pid
- rescue Puppet::ExecutionFailure => detail
- @resource.fail "Could not kill #{self.name}, PID #{pid}: #{output}"
- end
- return true
- end
+ end
+
+ # There is no default command, which causes other methods to be used
+ def stopcmd
+ end
+
+ # A simple wrapper so execution failures are a bit more informative.
+ def texecute(type, command, fof = true)
+ begin
+ # #565: Services generally produce no output, so squelch them.
+ execute(command, :failonfail => fof, :squelch => true)
+ rescue Puppet::ExecutionFailure => detail
+ @resource.fail "Could not #{type} #{@resource.ref}: #{detail}"
end
-
- # There is no default command, which causes other methods to be used
- def stopcmd
- end
-
- # A simple wrapper so execution failures are a bit more informative.
- def texecute(type, command, fof = true)
- begin
- # #565: Services generally produce no output, so squelch them.
- execute(command, :failonfail => fof, :squelch => true)
- rescue Puppet::ExecutionFailure => detail
- @resource.fail "Could not #{type} #{@resource.ref}: #{detail}"
- end
- nil
- end
-
- # Use either a specified command or the default for our provider.
- def ucommand(type, fof = true)
- if c = @resource[type]
- cmd = [c]
- else
- cmd = [send("#{type}cmd")].flatten
- end
- texecute(type, cmd, fof)
+ nil
+ end
+
+ # Use either a specified command or the default for our provider.
+ def ucommand(type, fof = true)
+ if c = @resource[type]
+ cmd = [c]
+ else
+ cmd = [send("#{type}cmd")].flatten
end
+ texecute(type, cmd, fof)
+ end
end
diff --git a/lib/puppet/provider/service/bsd.rb b/lib/puppet/provider/service/bsd.rb
index 15e4385a1..2e00c33f1 100644
--- a/lib/puppet/provider/service/bsd.rb
+++ b/lib/puppet/provider/service/bsd.rb
@@ -1,48 +1,48 @@
# Manage FreeBSD services.
Puppet::Type.type(:service).provide :bsd, :parent => :init do
- desc "FreeBSD's (and probably NetBSD?) form of ``init``-style service management.
+ desc "FreeBSD's (and probably NetBSD?) form of ``init``-style service management.
- Uses ``rc.conf.d`` for service enabling and disabling.
+ Uses ``rc.conf.d`` for service enabling and disabling.
"
- confine :operatingsystem => [:freebsd, :netbsd, :openbsd]
-
- @@rcconf_dir = '/etc/rc.conf.d'
-
- def self.defpath
- superclass.defpath
- end
-
- # remove service file from rc.conf.d to disable it
- def disable
- rcfile = File.join(@@rcconf_dir, @model[:name])
- File.delete(rcfile) if File.exists?(rcfile)
- end
-
- # if the service file exists in rc.conf.d then it's already enabled
- def enabled?
- rcfile = File.join(@@rcconf_dir, @model[:name])
- return :true if File.exists?(rcfile)
-
- :false
- end
-
- # enable service by creating a service file under rc.conf.d with the
- # proper contents
- def enable
- Dir.mkdir(@@rcconf_dir) if not File.exists?(@@rcconf_dir)
- rcfile = File.join(@@rcconf_dir, @model[:name])
- open(rcfile, 'w') { |f| f << "%s_enable=\"YES\"\n" % @model[:name] }
- end
-
- # Override stop/start commands to use one<cmd>'s and the avoid race condition
- # where provider trys to stop/start the service before it is enabled
- def startcmd
- [self.initscript, :onestart]
- end
-
- def stopcmd
- [self.initscript, :onestop]
- end
+ confine :operatingsystem => [:freebsd, :netbsd, :openbsd]
+
+ @@rcconf_dir = '/etc/rc.conf.d'
+
+ def self.defpath
+ superclass.defpath
+ end
+
+ # remove service file from rc.conf.d to disable it
+ def disable
+ rcfile = File.join(@@rcconf_dir, @model[:name])
+ File.delete(rcfile) if File.exists?(rcfile)
+ end
+
+ # if the service file exists in rc.conf.d then it's already enabled
+ def enabled?
+ rcfile = File.join(@@rcconf_dir, @model[:name])
+ return :true if File.exists?(rcfile)
+
+ :false
+ end
+
+ # enable service by creating a service file under rc.conf.d with the
+ # proper contents
+ def enable
+ Dir.mkdir(@@rcconf_dir) if not File.exists?(@@rcconf_dir)
+ rcfile = File.join(@@rcconf_dir, @model[:name])
+ open(rcfile, 'w') { |f| f << "%s_enable=\"YES\"\n" % @model[:name] }
+ end
+
+ # Override stop/start commands to use one<cmd>'s and the avoid race condition
+ # where provider trys to stop/start the service before it is enabled
+ def startcmd
+ [self.initscript, :onestart]
+ end
+
+ def stopcmd
+ [self.initscript, :onestop]
+ end
end
diff --git a/lib/puppet/provider/service/daemontools.rb b/lib/puppet/provider/service/daemontools.rb
index 7a584a1f9..65abf7728 100644
--- a/lib/puppet/provider/service/daemontools.rb
+++ b/lib/puppet/provider/service/daemontools.rb
@@ -2,193 +2,193 @@
#
# author Brice Figureau <brice-puppet@daysofwonder.com>
Puppet::Type.type(:service).provide :daemontools, :parent => :base do
- desc "Daemontools service management.
+ desc "Daemontools service management.
- This provider manages daemons running supervised by D.J.Bernstein daemontools.
- It tries to detect the service directory, with by order of preference:
+ This provider manages daemons running supervised by D.J.Bernstein daemontools.
+ It tries to detect the service directory, with by order of preference:
- * /service
- * /etc/service
- * /var/lib/svscan
+ * /service
+ * /etc/service
+ * /var/lib/svscan
- The daemon directory should be placed in a directory that can be
- by default in:
+ The daemon directory should be placed in a directory that can be
+ by default in:
- * /var/lib/service
- * /etc
+ * /var/lib/service
+ * /etc
- or this can be overriden in the service resource parameters::
+ or this can be overriden in the service resource parameters::
- service {
- \"myservice\":
- provider => \"daemontools\", path => \"/path/to/daemons\";
- }
+ service {
+ \"myservice\":
+ provider => \"daemontools\", path => \"/path/to/daemons\";
+ }
- This provider supports out of the box:
+ This provider supports out of the box:
- * start/stop (mapped to enable/disable)
- * enable/disable
- * restart
- * status
+ * start/stop (mapped to enable/disable)
+ * enable/disable
+ * restart
+ * status
- If a service has ensure => \"running\", it will link /path/to/daemon to
- /path/to/service, which will automatically enable the service.
+ If a service has ensure => \"running\", it will link /path/to/daemon to
+ /path/to/service, which will automatically enable the service.
- If a service has ensure => \"stopped\", it will only down the service, not
- remove the /path/to/service link.
+ If a service has ensure => \"stopped\", it will only down the service, not
+ remove the /path/to/service link.
- "
+ "
- commands :svc => "/usr/bin/svc", :svstat => "/usr/bin/svstat"
+ commands :svc => "/usr/bin/svc", :svstat => "/usr/bin/svstat"
- class << self
- attr_writer :defpath
+ class << self
+ attr_writer :defpath
- # Determine the daemon path.
- def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
- unless @defpath
- ["/var/lib/service", "/etc"].each do |path|
- if FileTest.exist?(path)
- @defpath = path
- break
- end
- end
- raise "Could not find the daemon directory (tested [/var/lib/service,/etc])" unless @defpath
- end
- @defpath
+ # Determine the daemon path.
+ def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
+ unless @defpath
+ ["/var/lib/service", "/etc"].each do |path|
+ if FileTest.exist?(path)
+ @defpath = path
+ break
+ end
end
+ raise "Could not find the daemon directory (tested [/var/lib/service,/etc])" unless @defpath
+ end
+ @defpath
end
+ end
- attr_writer :servicedir
+ attr_writer :servicedir
- # returns all providers for all existing services in @defpath
- # ie enabled or not
- def self.instances
- path = self.defpath
- unless FileTest.directory?(path)
- Puppet.notice "Service path #{path} does not exist"
- next
- end
-
- # reject entries that aren't either a directory
- # or don't contain a run file
- Dir.entries(path).reject { |e|
- fullpath = File.join(path, e)
- e =~ /^\./ or ! FileTest.directory?(fullpath) or ! FileTest.exist?(File.join(fullpath,"run"))
- }.collect do |name|
- new(:name => name, :path => path)
- end
+ # returns all providers for all existing services in @defpath
+ # ie enabled or not
+ def self.instances
+ path = self.defpath
+ unless FileTest.directory?(path)
+ Puppet.notice "Service path #{path} does not exist"
+ next
end
- # returns the daemon dir on this node
- def self.daemondir
- self.defpath
+ # reject entries that aren't either a directory
+ # or don't contain a run file
+ Dir.entries(path).reject { |e|
+ fullpath = File.join(path, e)
+ e =~ /^\./ or ! FileTest.directory?(fullpath) or ! FileTest.exist?(File.join(fullpath,"run"))
+ }.collect do |name|
+ new(:name => name, :path => path)
end
-
- # find the service dir on this node
- def servicedir
- unless @servicedir
- ["/service", "/etc/service","/var/lib/svscan"].each do |path|
- if FileTest.exist?(path)
- @servicedir = path
- break
- end
- end
- raise "Could not find service directory" unless @servicedir
+ end
+
+ # returns the daemon dir on this node
+ def self.daemondir
+ self.defpath
+ end
+
+ # find the service dir on this node
+ def servicedir
+ unless @servicedir
+ ["/service", "/etc/service","/var/lib/svscan"].each do |path|
+ if FileTest.exist?(path)
+ @servicedir = path
+ break
end
- @servicedir
+ end
+ raise "Could not find service directory" unless @servicedir
end
-
- # returns the full path of this service when enabled
- # (ie in the service directory)
- def service
- File.join(self.servicedir, resource[:name])
+ @servicedir
+ end
+
+ # returns the full path of this service when enabled
+ # (ie in the service directory)
+ def service
+ File.join(self.servicedir, resource[:name])
+ end
+
+ # returns the full path to the current daemon directory
+ # note that this path can be overriden in the resource
+ # definition
+ def daemon
+ File.join(resource[:path], resource[:name])
+ end
+
+ def status
+ begin
+ output = svstat self.service
+ if output =~ /:\s+up \(/
+ return :running
+ end
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}" )
end
-
- # returns the full path to the current daemon directory
- # note that this path can be overriden in the resource
- # definition
- def daemon
- File.join(resource[:path], resource[:name])
+ :stopped
+ end
+
+ def setupservice
+ if resource[:manifest]
+ Puppet.notice "Configuring #{resource[:name]}"
+ command = [ resource[:manifest], resource[:name] ]
+ #texecute("setupservice", command)
+ rv = system("#{command}")
+ end
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}" )
+ end
+
+ def enabled?
+ case self.status
+ when :running
+ # obviously if the daemon is running then it is enabled
+ return :true
+ else
+ # the service is enabled if it is linked
+ return FileTest.symlink?(self.service) ? :true : :false
end
-
- def status
- begin
- output = svstat self.service
- if output =~ /:\s+up \(/
- return :running
- end
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}" )
+ end
+
+ def enable
+ if ! FileTest.directory?(self.daemon)
+ Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
+ self.setupservice
+ end
+ if self.daemon
+ if ! FileTest.symlink?(self.service)
+ Puppet.notice "Enabling #{self.service}: linking #{self.daemon} -> #{self.service}"
+ File.symlink(self.daemon, self.service)
end
- :stopped
- end
-
- def setupservice
- if resource[:manifest]
- Puppet.notice "Configuring #{resource[:name]}"
- command = [ resource[:manifest], resource[:name] ]
- #texecute("setupservice", command)
- rv = system("#{command}")
- end
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}" )
- end
-
- def enabled?
- case self.status
- when :running
- # obviously if the daemon is running then it is enabled
- return :true
- else
- # the service is enabled if it is linked
- return FileTest.symlink?(self.service) ? :true : :false
+ end
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error.new( "No daemon directory found for #{self.service}")
+ end
+
+ def disable
+ begin
+ if ! FileTest.directory?(self.daemon)
+ Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
+ self.setupservice
+ end
+ if self.daemon
+ if FileTest.symlink?(self.service)
+ Puppet.notice "Disabling #{self.service}: removing link #{self.daemon} -> #{self.service}"
+ File.unlink(self.service)
end
- end
-
- def enable
- if ! FileTest.directory?(self.daemon)
- Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
- self.setupservice
- end
- if self.daemon
- if ! FileTest.symlink?(self.service)
- Puppet.notice "Enabling #{self.service}: linking #{self.daemon} -> #{self.service}"
- File.symlink(self.daemon, self.service)
- end
- end
+ end
rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new( "No daemon directory found for #{self.service}")
- end
-
- def disable
- begin
- if ! FileTest.directory?(self.daemon)
- Puppet.notice "No daemon dir, calling setupservice for #{resource[:name]}"
- self.setupservice
- end
- if self.daemon
- if FileTest.symlink?(self.service)
- Puppet.notice "Disabling #{self.service}: removing link #{self.daemon} -> #{self.service}"
- File.unlink(self.service)
- end
- end
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new( "No daemon directory found for #{self.service}")
- end
- self.stop
+ raise Puppet::Error.new( "No daemon directory found for #{self.service}")
end
+ self.stop
+ end
- def restart
- svc "-t", self.service
- end
+ def restart
+ svc "-t", self.service
+ end
- def start
- enable unless enabled? == :true
- svc "-u", self.service
- end
+ def start
+ enable unless enabled? == :true
+ svc "-u", self.service
+ end
- def stop
- svc "-d", self.service
- end
+ def stop
+ svc "-d", self.service
+ end
end
diff --git a/lib/puppet/provider/service/debian.rb b/lib/puppet/provider/service/debian.rb
index 746ed1ce3..4379f1b59 100755
--- a/lib/puppet/provider/service/debian.rb
+++ b/lib/puppet/provider/service/debian.rb
@@ -1,48 +1,48 @@
# Manage debian services. Start/stop is the same as InitSvc, but enable/disable
# is special.
Puppet::Type.type(:service).provide :debian, :parent => :init do
- desc "Debian's form of ``init``-style management.
-
- The only difference is that this supports service enabling and disabling
- via ``update-rc.d`` and determines enabled status via ``invoke-rc.d``.
-
- "
-
- commands :update_rc => "/usr/sbin/update-rc.d"
- # note this isn't being used as a command until
- # http://projects.reductivelabs.com/issues/2538
- # is resolved.
- commands :invoke_rc => "/usr/sbin/invoke-rc.d"
-
- defaultfor :operatingsystem => [:debian, :ubuntu]
-
- def self.defpath
- superclass.defpath
+ desc "Debian's form of ``init``-style management.
+
+ The only difference is that this supports service enabling and disabling
+ via ``update-rc.d`` and determines enabled status via ``invoke-rc.d``.
+
+ "
+
+ commands :update_rc => "/usr/sbin/update-rc.d"
+ # note this isn't being used as a command until
+ # http://projects.reductivelabs.com/issues/2538
+ # is resolved.
+ commands :invoke_rc => "/usr/sbin/invoke-rc.d"
+
+ defaultfor :operatingsystem => [:debian, :ubuntu]
+
+ def self.defpath
+ superclass.defpath
+ end
+
+ # Remove the symlinks
+ def disable
+ update_rc "-f", @resource[:name], "remove"
+ update_rc @resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", "."
+ end
+
+ def enabled?
+ # TODO: Replace system call when Puppet::Util.execute gives us a way
+ # to determine exit status. http://projects.reductivelabs.com/issues/2538
+ system("/usr/sbin/invoke-rc.d", "--quiet", "--query", @resource[:name], "start")
+
+ # 104 is the exit status when you query start an enabled service.
+ # 106 is the exit status when the policy layer supplies a fallback action
+ # See x-man-page://invoke-rc.d
+ if [104, 106].include?($CHILD_STATUS.exitstatus)
+ return :true
+ else
+ return :false
end
+ end
- # Remove the symlinks
- def disable
- update_rc "-f", @resource[:name], "remove"
- update_rc @resource[:name], "stop", "00", "1", "2", "3", "4", "5", "6", "."
- end
-
- def enabled?
- # TODO: Replace system call when Puppet::Util.execute gives us a way
- # to determine exit status. http://projects.reductivelabs.com/issues/2538
- system("/usr/sbin/invoke-rc.d", "--quiet", "--query", @resource[:name], "start")
-
- # 104 is the exit status when you query start an enabled service.
- # 106 is the exit status when the policy layer supplies a fallback action
- # See x-man-page://invoke-rc.d
- if [104, 106].include?($CHILD_STATUS.exitstatus)
- return :true
- else
- return :false
- end
- end
-
- def enable
- update_rc "-f", @resource[:name], "remove"
- update_rc @resource[:name], "defaults"
- end
+ def enable
+ update_rc "-f", @resource[:name], "remove"
+ update_rc @resource[:name], "defaults"
+ end
end
diff --git a/lib/puppet/provider/service/freebsd.rb b/lib/puppet/provider/service/freebsd.rb
index f491d70a2..10970e4da 100644
--- a/lib/puppet/provider/service/freebsd.rb
+++ b/lib/puppet/provider/service/freebsd.rb
@@ -1,136 +1,136 @@
Puppet::Type.type(:service).provide :freebsd, :parent => :init do
- desc "Provider for FreeBSD. Makes use of rcvar argument of init scripts and parses/edits rc files."
-
- confine :operatingsystem => [:freebsd]
- defaultfor :operatingsystem => [:freebsd]
-
- @@rcconf = '/etc/rc.conf'
- @@rcconf_local = '/etc/rc.conf.local'
- @@rcconf_dir = '/etc/rc.conf.d'
-
- def self.defpath
- superclass.defpath
- end
-
- # Executing an init script with the 'rcvar' argument returns
- # the service name, rcvar name and whether it's enabled/disabled
- def rcvar
- rcvar = execute([self.initscript, :rcvar], :failonfail => true, :squelch => false)
- rcvar = rcvar.split("\n")
- end
-
- # Extract service name
- def service_name
- name = self.rcvar[0]
- self.error("No service name found in rcvar") if name.nil?
- name = name.gsub!(/# (.*)/, '\1')
- self.error("Service name is empty") if name.nil?
- self.debug("Service name is #{name}")
- name
- end
-
- # Extract rcvar name
- def rcvar_name
- name = self.rcvar[1]
- self.error("No rcvar name found in rcvar") if name.nil?
- name = name.gsub!(/(.*)_enable=(.*)/, '\1')
- self.error("rcvar name is empty") if name.nil?
- self.debug("rcvar name is #{name}")
- name
- end
-
- # Extract rcvar value
- def rcvar_value
- value = self.rcvar[1]
- self.error("No rcvar value found in rcvar") if value.nil?
- value = value.gsub!(/(.*)_enable=\"?(.*)\"?/, '\2')
- self.error("rcvar value is empty") if value.nil?
- self.debug("rcvar value is #{value}")
- value
- end
-
- # Edit rc files and set the service to yes/no
- def rc_edit(yesno)
- service = self.service_name
- rcvar = self.rcvar_name
- self.debug("Editing rc files: setting #{rcvar} to #{yesno} for #{service}")
- self.rc_add(service, rcvar, yesno) if not self.rc_replace(service, rcvar, yesno)
- end
-
- # Try to find an existing setting in the rc files
- # and replace the value
- def rc_replace(service, rcvar, yesno)
- success = false
- # Replace in all files, not just in the first found with a match
- [@@rcconf, @@rcconf_local, @@rcconf_dir + "/#{service}"].each do |filename|
- if File.exists?(filename)
- s = File.read(filename)
- if s.gsub!(/(#{rcvar}_enable)=\"?(YES|NO)\"?/, "\\1=\"#{yesno}\"")
- File.open(filename, File::WRONLY) { |f| f << s }
- self.debug("Replaced in #{filename}")
- success = true
- end
- end
- end
- success
- end
-
- # Add a new setting to the rc files
- def rc_add(service, rcvar, yesno)
- append = "\n\# Added by Puppet\n#{rcvar}_enable=\"#{yesno}\""
- # First, try the one-file-per-service style
- if File.exists?(@@rcconf_dir)
- File.open(@@rcconf_dir + "/#{service}", File::WRONLY | File::APPEND | File::CREAT, 0644) {
- |f| f << append
- self.debug("Appended to #{f.path}")
- }
- else
- # Else, check the local rc file first, but don't create it
- if File.exists?(@@rcconf_local)
- File.open(@@rcconf_local, File::WRONLY | File::APPEND) {
- |f| f << append
- self.debug("Appended to #{f.path}")
- }
- else
- # At last use the standard rc.conf file
- File.open(@@rcconf, File::WRONLY | File::APPEND | File::CREAT, 0644) {
- |f| f << append
- self.debug("Appended to #{f.path}")
- }
- end
- end
- end
-
- def enabled?
- if /YES$/ =~ self.rcvar_value
- self.debug("Is enabled")
- return :true
+ desc "Provider for FreeBSD. Makes use of rcvar argument of init scripts and parses/edits rc files."
+
+ confine :operatingsystem => [:freebsd]
+ defaultfor :operatingsystem => [:freebsd]
+
+ @@rcconf = '/etc/rc.conf'
+ @@rcconf_local = '/etc/rc.conf.local'
+ @@rcconf_dir = '/etc/rc.conf.d'
+
+ def self.defpath
+ superclass.defpath
+ end
+
+ # Executing an init script with the 'rcvar' argument returns
+ # the service name, rcvar name and whether it's enabled/disabled
+ def rcvar
+ rcvar = execute([self.initscript, :rcvar], :failonfail => true, :squelch => false)
+ rcvar = rcvar.split("\n")
+ end
+
+ # Extract service name
+ def service_name
+ name = self.rcvar[0]
+ self.error("No service name found in rcvar") if name.nil?
+ name = name.gsub!(/# (.*)/, '\1')
+ self.error("Service name is empty") if name.nil?
+ self.debug("Service name is #{name}")
+ name
+ end
+
+ # Extract rcvar name
+ def rcvar_name
+ name = self.rcvar[1]
+ self.error("No rcvar name found in rcvar") if name.nil?
+ name = name.gsub!(/(.*)_enable=(.*)/, '\1')
+ self.error("rcvar name is empty") if name.nil?
+ self.debug("rcvar name is #{name}")
+ name
+ end
+
+ # Extract rcvar value
+ def rcvar_value
+ value = self.rcvar[1]
+ self.error("No rcvar value found in rcvar") if value.nil?
+ value = value.gsub!(/(.*)_enable=\"?(.*)\"?/, '\2')
+ self.error("rcvar value is empty") if value.nil?
+ self.debug("rcvar value is #{value}")
+ value
+ end
+
+ # Edit rc files and set the service to yes/no
+ def rc_edit(yesno)
+ service = self.service_name
+ rcvar = self.rcvar_name
+ self.debug("Editing rc files: setting #{rcvar} to #{yesno} for #{service}")
+ self.rc_add(service, rcvar, yesno) if not self.rc_replace(service, rcvar, yesno)
+ end
+
+ # Try to find an existing setting in the rc files
+ # and replace the value
+ def rc_replace(service, rcvar, yesno)
+ success = false
+ # Replace in all files, not just in the first found with a match
+ [@@rcconf, @@rcconf_local, @@rcconf_dir + "/#{service}"].each do |filename|
+ if File.exists?(filename)
+ s = File.read(filename)
+ if s.gsub!(/(#{rcvar}_enable)=\"?(YES|NO)\"?/, "\\1=\"#{yesno}\"")
+ File.open(filename, File::WRONLY) { |f| f << s }
+ self.debug("Replaced in #{filename}")
+ success = true
end
- self.debug("Is disabled")
- :false
+ end
end
-
- def enable
- self.debug("Enabling")
- self.rc_edit("YES")
- end
-
- def disable
- self.debug("Disabling")
- self.rc_edit("NO")
- end
-
- def startcmd
- [self.initscript, :onestart]
- end
-
- def stopcmd
- [self.initscript, :onestop]
+ success
+ end
+
+ # Add a new setting to the rc files
+ def rc_add(service, rcvar, yesno)
+ append = "\n\# Added by Puppet\n#{rcvar}_enable=\"#{yesno}\""
+ # First, try the one-file-per-service style
+ if File.exists?(@@rcconf_dir)
+ File.open(@@rcconf_dir + "/#{service}", File::WRONLY | File::APPEND | File::CREAT, 0644) {
+ |f| f << append
+ self.debug("Appended to #{f.path}")
+ }
+ else
+ # Else, check the local rc file first, but don't create it
+ if File.exists?(@@rcconf_local)
+ File.open(@@rcconf_local, File::WRONLY | File::APPEND) {
+ |f| f << append
+ self.debug("Appended to #{f.path}")
+ }
+ else
+ # At last use the standard rc.conf file
+ File.open(@@rcconf, File::WRONLY | File::APPEND | File::CREAT, 0644) {
+ |f| f << append
+ self.debug("Appended to #{f.path}")
+ }
+ end
end
+ end
- def statuscmd
- [self.initscript, :onestatus]
+ def enabled?
+ if /YES$/ =~ self.rcvar_value
+ self.debug("Is enabled")
+ return :true
end
+ self.debug("Is disabled")
+ :false
+ end
+
+ def enable
+ self.debug("Enabling")
+ self.rc_edit("YES")
+ end
+
+ def disable
+ self.debug("Disabling")
+ self.rc_edit("NO")
+ end
+
+ def startcmd
+ [self.initscript, :onestart]
+ end
+
+ def stopcmd
+ [self.initscript, :onestop]
+ end
+
+ def statuscmd
+ [self.initscript, :onestatus]
+ end
end
diff --git a/lib/puppet/provider/service/gentoo.rb b/lib/puppet/provider/service/gentoo.rb
index 109524bc0..08250a06a 100644
--- a/lib/puppet/provider/service/gentoo.rb
+++ b/lib/puppet/provider/service/gentoo.rb
@@ -1,52 +1,52 @@
# Manage gentoo services. Start/stop is the same as InitSvc, but enable/disable
# is special.
Puppet::Type.type(:service).provide :gentoo, :parent => :init do
- desc "Gentoo's form of ``init``-style service management.
+ desc "Gentoo's form of ``init``-style service management.
- Uses ``rc-update`` for service enabling and disabling.
+ Uses ``rc-update`` for service enabling and disabling.
- "
+ "
- commands :update => "/sbin/rc-update"
+ commands :update => "/sbin/rc-update"
- confine :operatingsystem => :gentoo
+ confine :operatingsystem => :gentoo
- defaultfor :operatingsystem => :gentoo
+ defaultfor :operatingsystem => :gentoo
- def self.defpath
- superclass.defpath
- end
+ def self.defpath
+ superclass.defpath
+ end
+
+ def disable
+ output = update :del, @resource[:name], :default
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error, "Could not disable #{self.name}: #{output}"
+ end
- def disable
- output = update :del, @resource[:name], :default
+ def enabled?
+ begin
+ output = update :show
rescue Puppet::ExecutionFailure
- raise Puppet::Error, "Could not disable #{self.name}: #{output}"
+ return :false
end
- def enabled?
- begin
- output = update :show
- rescue Puppet::ExecutionFailure
- return :false
- end
-
- line = output.split(/\n/).find { |l| l.include?(@resource[:name]) }
+ line = output.split(/\n/).find { |l| l.include?(@resource[:name]) }
- return :false unless line
+ return :false unless line
- # If it's enabled then it will print output showing service | runlevel
- if output =~ /^\s*#{@resource[:name]}\s*\|\s*(boot|default)/
- return :true
- else
- return :false
- end
+ # If it's enabled then it will print output showing service | runlevel
+ if output =~ /^\s*#{@resource[:name]}\s*\|\s*(boot|default)/
+ return :true
+ else
+ return :false
end
+ end
- def enable
- output = update :add, @resource[:name], :default
- rescue Puppet::ExecutionFailure
- raise Puppet::Error, "Could not enable #{self.name}: #{output}"
- end
+ def enable
+ output = update :add, @resource[:name], :default
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error, "Could not enable #{self.name}: #{output}"
+ end
end
# $Id $
diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb
index 17d3bad36..6abff12db 100755
--- a/lib/puppet/provider/service/init.rb
+++ b/lib/puppet/provider/service/init.rb
@@ -1,141 +1,141 @@
# The standard init-based service type. Many other service types are
# customizations of this module.
Puppet::Type.type(:service).provide :init, :parent => :base do
- desc "Standard init service management.
+ desc "Standard init service management.
- This provider assumes that the init script has no ``status`` command,
- because so few scripts do, so you need to either provide a status
- command or specify via ``hasstatus`` that one already exists in the
- init script.
+ This provider assumes that the init script has no ``status`` command,
+ because so few scripts do, so you need to either provide a status
+ command or specify via ``hasstatus`` that one already exists in the
+ init script.
"
- class << self
- attr_accessor :defpath
+ class << self
+ attr_accessor :defpath
+ end
+
+ case Facter["operatingsystem"].value
+ when "FreeBSD"
+ @defpath = ["/etc/rc.d", "/usr/local/etc/rc.d"]
+ when "HP-UX"
+ @defpath = "/sbin/init.d"
+ else
+ @defpath = "/etc/init.d"
+ end
+
+ # We can't confine this here, because the init path can be overridden.
+ #confine :exists => @defpath
+
+ # List all services of this type.
+ def self.instances
+ get_services(self.defpath)
+ end
+
+ def self.get_services(defpath, exclude=[])
+ defpath = [defpath] unless defpath.is_a? Array
+ instances = []
+ defpath.each do |path|
+ unless FileTest.directory?(path)
+ Puppet.debug "Service path #{path} does not exist"
+ next
+ end
+
+ check = [:ensure]
+
+ check << :enable if public_method_defined? :enabled?
+
+ Dir.entries(path).each do |name|
+ fullpath = File.join(path, name)
+ next if name =~ /^\./
+ next if exclude.include? name
+ next if not FileTest.executable?(fullpath)
+ instances << new(:name => name, :path => path, :hasstatus => true)
+ end
end
-
- case Facter["operatingsystem"].value
- when "FreeBSD"
- @defpath = ["/etc/rc.d", "/usr/local/etc/rc.d"]
- when "HP-UX"
- @defpath = "/sbin/init.d"
+ instances
+ end
+
+ # Mark that our init script supports 'status' commands.
+ def hasstatus=(value)
+ case value
+ when true, "true"; @parameters[:hasstatus] = true
+ when false, "false"; @parameters[:hasstatus] = false
else
- @defpath = "/etc/init.d"
- end
-
- # We can't confine this here, because the init path can be overridden.
- #confine :exists => @defpath
-
- # List all services of this type.
- def self.instances
- get_services(self.defpath)
- end
-
- def self.get_services(defpath, exclude=[])
- defpath = [defpath] unless defpath.is_a? Array
- instances = []
- defpath.each do |path|
- unless FileTest.directory?(path)
- Puppet.debug "Service path #{path} does not exist"
- next
- end
-
- check = [:ensure]
-
- check << :enable if public_method_defined? :enabled?
-
- Dir.entries(path).each do |name|
- fullpath = File.join(path, name)
- next if name =~ /^\./
- next if exclude.include? name
- next if not FileTest.executable?(fullpath)
- instances << new(:name => name, :path => path, :hasstatus => true)
- end
- end
- instances
+ raise Puppet::Error, "Invalid 'hasstatus' value #{value.inspect}"
end
-
- # Mark that our init script supports 'status' commands.
- def hasstatus=(value)
- case value
- when true, "true"; @parameters[:hasstatus] = true
- when false, "false"; @parameters[:hasstatus] = false
+ end
+
+ # Where is our init script?
+ def initscript
+ @initscript ||= self.search(@resource[:name])
+ end
+
+ def paths
+ @paths ||= @resource[:path].find_all do |path|
+ if File.directory?(path)
+ true
+ else
+ if File.exist?(path) and ! File.directory?(path)
+ self.debug "Search path #{path} is not a directory"
else
- raise Puppet::Error, "Invalid 'hasstatus' value #{value.inspect}"
+ self.debug "Search path #{path} does not exist"
end
+ false
+ end
end
-
- # Where is our init script?
- def initscript
- @initscript ||= self.search(@resource[:name])
- end
-
- def paths
- @paths ||= @resource[:path].find_all do |path|
- if File.directory?(path)
- true
- else
- if File.exist?(path) and ! File.directory?(path)
- self.debug "Search path #{path} is not a directory"
- else
- self.debug "Search path #{path} does not exist"
- end
- false
- end
- end
- end
-
- def search(name)
- paths.each { |path|
- fqname = File.join(path,name)
- begin
- stat = File.stat(fqname)
- rescue
- # should probably rescue specific errors...
- self.debug("Could not find #{name} in #{path}")
- next
- end
-
- # if we've gotten this far, we found a valid script
- return fqname
- }
-
- paths.each { |path|
- fqname_sh = File.join(path,"#{name}.sh")
- begin
- stat = File.stat(fqname_sh)
- rescue
- # should probably rescue specific errors...
- self.debug("Could not find #{name}.sh in #{path}")
- next
- end
-
- # if we've gotten this far, we found a valid script
- return fqname_sh
- }
- raise Puppet::Error, "Could not find init script for '#{name}'"
- end
-
- # The start command is just the init scriptwith 'start'.
- def startcmd
- [initscript, :start]
- end
-
- # The stop command is just the init script with 'stop'.
- def stopcmd
- [initscript, :stop]
- end
-
- def restartcmd
- (@resource[:hasrestart] == :true) && [initscript, :restart]
- end
-
- # If it was specified that the init script has a 'status' command, then
- # we just return that; otherwise, we return false, which causes it to
- # fallback to other mechanisms.
- def statuscmd
- (@resource[:hasstatus] == :true) && [initscript, :status]
- end
+ end
+
+ def search(name)
+ paths.each { |path|
+ fqname = File.join(path,name)
+ begin
+ stat = File.stat(fqname)
+ rescue
+ # should probably rescue specific errors...
+ self.debug("Could not find #{name} in #{path}")
+ next
+ end
+
+ # if we've gotten this far, we found a valid script
+ return fqname
+ }
+
+ paths.each { |path|
+ fqname_sh = File.join(path,"#{name}.sh")
+ begin
+ stat = File.stat(fqname_sh)
+ rescue
+ # should probably rescue specific errors...
+ self.debug("Could not find #{name}.sh in #{path}")
+ next
+ end
+
+ # if we've gotten this far, we found a valid script
+ return fqname_sh
+ }
+ raise Puppet::Error, "Could not find init script for '#{name}'"
+ end
+
+ # The start command is just the init scriptwith 'start'.
+ def startcmd
+ [initscript, :start]
+ end
+
+ # The stop command is just the init script with 'stop'.
+ def stopcmd
+ [initscript, :stop]
+ end
+
+ def restartcmd
+ (@resource[:hasrestart] == :true) && [initscript, :restart]
+ end
+
+ # If it was specified that the init script has a 'status' command, then
+ # we just return that; otherwise, we return false, which causes it to
+ # fallback to other mechanisms.
+ def statuscmd
+ (@resource[:hasstatus] == :true) && [initscript, :status]
+ end
end
diff --git a/lib/puppet/provider/service/launchd.rb b/lib/puppet/provider/service/launchd.rb
index 9be961b09..970359539 100644
--- a/lib/puppet/provider/service/launchd.rb
+++ b/lib/puppet/provider/service/launchd.rb
@@ -1,256 +1,256 @@
require 'facter/util/plist'
Puppet::Type.type(:service).provide :launchd, :parent => :base do
- desc "launchd service management framework.
-
- This provider manages launchd jobs, the default service framework for
- Mac OS X, that has also been open sourced by Apple for possible use on
- other platforms.
-
- See:
- * http://developer.apple.com/macosx/launchd.html
- * http://launchd.macosforge.org/
-
- This provider reads plists out of the following directories:
- * /System/Library/LaunchDaemons
- * /System/Library/LaunchAgents
- * /Library/LaunchDaemons
- * /Library/LaunchAgents
-
- and builds up a list of services based upon each plists \"Label\" entry.
-
- This provider supports:
- * ensure => running/stopped,
- * enable => true/false
- * status
- * restart
-
- Here is how the Puppet states correspond to launchd states:
- * stopped => job unloaded
- * started => job loaded
- * enabled => 'Disable' removed from job plist file
- * disabled => 'Disable' added to job plist file
-
- Note that this allows you to do something launchctl can't do, which is to
- be in a state of \"stopped/enabled\ or \"running/disabled\".
-
- "
-
- commands :launchctl => "/bin/launchctl"
- commands :sw_vers => "/usr/bin/sw_vers"
-
- defaultfor :operatingsystem => :darwin
- confine :operatingsystem => :darwin
-
- has_feature :enableable
-
- Launchd_Paths = ["/Library/LaunchAgents",
- "/Library/LaunchDaemons",
- "/System/Library/LaunchAgents",
- "/System/Library/LaunchDaemons",]
-
- Launchd_Overrides = "/var/db/launchd.db/com.apple.launchd/overrides.plist"
-
-
- # returns a label => path map for either all jobs, or just a single
- # job if the label is specified
- def self.jobsearch(label=nil)
- label_to_path_map = {}
- Launchd_Paths.each do |path|
- if FileTest.exists?(path)
- Dir.entries(path).each do |f|
- next if f =~ /^\..*$/
- next if FileTest.directory?(f)
- fullpath = File.join(path, f)
- job = Plist::parse_xml(fullpath)
- if job and job.has_key?("Label")
- if job["Label"] == label
- return { label => fullpath }
- else
- label_to_path_map[job["Label"]] = fullpath
- end
- end
- end
+ desc "launchd service management framework.
+
+ This provider manages launchd jobs, the default service framework for
+ Mac OS X, that has also been open sourced by Apple for possible use on
+ other platforms.
+
+ See:
+ * http://developer.apple.com/macosx/launchd.html
+ * http://launchd.macosforge.org/
+
+ This provider reads plists out of the following directories:
+ * /System/Library/LaunchDaemons
+ * /System/Library/LaunchAgents
+ * /Library/LaunchDaemons
+ * /Library/LaunchAgents
+
+ and builds up a list of services based upon each plists \"Label\" entry.
+
+ This provider supports:
+ * ensure => running/stopped,
+ * enable => true/false
+ * status
+ * restart
+
+ Here is how the Puppet states correspond to launchd states:
+ * stopped => job unloaded
+ * started => job loaded
+ * enabled => 'Disable' removed from job plist file
+ * disabled => 'Disable' added to job plist file
+
+ Note that this allows you to do something launchctl can't do, which is to
+ be in a state of \"stopped/enabled\ or \"running/disabled\".
+
+ "
+
+ commands :launchctl => "/bin/launchctl"
+ commands :sw_vers => "/usr/bin/sw_vers"
+
+ defaultfor :operatingsystem => :darwin
+ confine :operatingsystem => :darwin
+
+ has_feature :enableable
+
+ Launchd_Paths = ["/Library/LaunchAgents",
+ "/Library/LaunchDaemons",
+ "/System/Library/LaunchAgents",
+ "/System/Library/LaunchDaemons",]
+
+ Launchd_Overrides = "/var/db/launchd.db/com.apple.launchd/overrides.plist"
+
+
+ # returns a label => path map for either all jobs, or just a single
+ # job if the label is specified
+ def self.jobsearch(label=nil)
+ label_to_path_map = {}
+ Launchd_Paths.each do |path|
+ if FileTest.exists?(path)
+ Dir.entries(path).each do |f|
+ next if f =~ /^\..*$/
+ next if FileTest.directory?(f)
+ fullpath = File.join(path, f)
+ job = Plist::parse_xml(fullpath)
+ if job and job.has_key?("Label")
+ if job["Label"] == label
+ return { label => fullpath }
+ else
+ label_to_path_map[job["Label"]] = fullpath
end
+ end
end
-
- # if we didn't find the job above and we should have, error.
- raise Puppet::Error.new("Unable to find launchd plist for job: #{label}") if label
- # if returning all jobs
- label_to_path_map
- end
-
-
- def self.instances
- jobs = self.jobsearch
- jobs.keys.collect do |job|
- new(:name => job, :provider => :launchd, :path => jobs[job])
- end
+ end
end
+ # if we didn't find the job above and we should have, error.
+ raise Puppet::Error.new("Unable to find launchd plist for job: #{label}") if label
+ # if returning all jobs
+ label_to_path_map
+ end
- def self.get_macosx_version_major
- return @macosx_version_major if defined?(@macosx_version_major)
- begin
- # Make sure we've loaded all of the facts
- Facter.loadfacts
- if Facter.value(:macosx_productversion_major)
- product_version_major = Facter.value(:macosx_productversion_major)
- else
- # TODO: remove this code chunk once we require Facter 1.5.5 or higher.
- Puppet.warning("DEPRECATION WARNING: Future versions of the launchd provider will require Facter 1.5.5 or newer.")
- product_version = Facter.value(:macosx_productversion)
- fail("Could not determine OS X version from Facter") if product_version.nil?
- product_version_major = product_version.scan(/(\d+)\.(\d+)./).join(".")
- end
- fail("#{product_version_major} is not supported by the launchd provider") if %w{10.0 10.1 10.2 10.3}.include?(product_version_major)
- @macosx_version_major = product_version_major
- return @macosx_version_major
- rescue Puppet::ExecutionFailure => detail
- fail("Could not determine OS X version: #{detail}")
- end
+ def self.instances
+ jobs = self.jobsearch
+ jobs.keys.collect do |job|
+ new(:name => job, :provider => :launchd, :path => jobs[job])
end
-
-
- # finds the path for a given label and returns the path and parsed plist
- # as an array of [path, plist]. Note plist is really a Hash here.
- def plist_from_label(label)
- job = self.class.jobsearch(label)
- job_path = job[label]
- job_plist = Plist::parse_xml(job_path)
- raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}") if not job_plist
- [job_path, job_plist]
+ end
+
+
+ def self.get_macosx_version_major
+ return @macosx_version_major if defined?(@macosx_version_major)
+ begin
+ # Make sure we've loaded all of the facts
+ Facter.loadfacts
+
+ if Facter.value(:macosx_productversion_major)
+ product_version_major = Facter.value(:macosx_productversion_major)
+ else
+ # TODO: remove this code chunk once we require Facter 1.5.5 or higher.
+ Puppet.warning("DEPRECATION WARNING: Future versions of the launchd provider will require Facter 1.5.5 or newer.")
+ product_version = Facter.value(:macosx_productversion)
+ fail("Could not determine OS X version from Facter") if product_version.nil?
+ product_version_major = product_version.scan(/(\d+)\.(\d+)./).join(".")
+ end
+ fail("#{product_version_major} is not supported by the launchd provider") if %w{10.0 10.1 10.2 10.3}.include?(product_version_major)
+ @macosx_version_major = product_version_major
+ return @macosx_version_major
+ rescue Puppet::ExecutionFailure => detail
+ fail("Could not determine OS X version: #{detail}")
end
-
-
- def status
- # launchctl list <jobname> exits zero if the job is loaded
- # and non-zero if it isn't. Simple way to check... but is only
- # available on OS X 10.5 unfortunately, so we grab the whole list
- # and check if our resource is included. The output formats differ
- # between 10.4 and 10.5, thus the necessity for splitting
- begin
- output = launchctl :list
- raise Puppet::Error.new("launchctl list failed to return any data.") if output.nil?
- output.split("\n").each do |j|
- return :running if j.split(/\s/).last == resource[:name]
- end
- return :stopped
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new("Unable to determine status of #{resource[:name]}")
- end
+ end
+
+
+ # finds the path for a given label and returns the path and parsed plist
+ # as an array of [path, plist]. Note plist is really a Hash here.
+ def plist_from_label(label)
+ job = self.class.jobsearch(label)
+ job_path = job[label]
+ job_plist = Plist::parse_xml(job_path)
+ raise Puppet::Error.new("Unable to parse launchd plist at path: #{job_path}") if not job_plist
+ [job_path, job_plist]
+ end
+
+
+ def status
+ # launchctl list <jobname> exits zero if the job is loaded
+ # and non-zero if it isn't. Simple way to check... but is only
+ # available on OS X 10.5 unfortunately, so we grab the whole list
+ # and check if our resource is included. The output formats differ
+ # between 10.4 and 10.5, thus the necessity for splitting
+ begin
+ output = launchctl :list
+ raise Puppet::Error.new("launchctl list failed to return any data.") if output.nil?
+ output.split("\n").each do |j|
+ return :running if j.split(/\s/).last == resource[:name]
+ end
+ return :stopped
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new("Unable to determine status of #{resource[:name]}")
end
-
-
- # start the service. To get to a state of running/enabled, we need to
- # conditionally enable at load, then disable by modifying the plist file
- # directly.
- def start
- job_path, job_plist = plist_from_label(resource[:name])
- did_enable_job = false
- cmds = []
- cmds << :launchctl << :load
- if self.enabled? == :false # launchctl won't load disabled jobs
- cmds << "-w"
- did_enable_job = true
- end
- cmds << job_path
- begin
- execute(cmds)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new("Unable to start service: #{resource[:name]} at path: #{job_path}")
- end
- # As load -w clears the Disabled flag, we need to add it in after
- self.disable if did_enable_job and resource[:enable] == :false
+ end
+
+
+ # start the service. To get to a state of running/enabled, we need to
+ # conditionally enable at load, then disable by modifying the plist file
+ # directly.
+ def start
+ job_path, job_plist = plist_from_label(resource[:name])
+ did_enable_job = false
+ cmds = []
+ cmds << :launchctl << :load
+ if self.enabled? == :false # launchctl won't load disabled jobs
+ cmds << "-w"
+ did_enable_job = true
end
-
-
- def stop
- job_path, job_plist = plist_from_label(resource[:name])
- did_disable_job = false
- cmds = []
- cmds << :launchctl << :unload
- if self.enabled? == :true # keepalive jobs can't be stopped without disabling
- cmds << "-w"
- did_disable_job = true
- end
- cmds << job_path
- begin
- execute(cmds)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error.new("Unable to stop service: #{resource[:name]} at path: #{job_path}")
- end
- # As unload -w sets the Disabled flag, we need to add it in after
- self.enable if did_disable_job and resource[:enable] == :true
+ cmds << job_path
+ begin
+ execute(cmds)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new("Unable to start service: #{resource[:name]} at path: #{job_path}")
end
-
-
- # launchd jobs are enabled by default. They are only disabled if the key
- # "Disabled" is set to true, but it can also be set to false to enable it.
- # In 10.6, the Disabled key in the job plist is consulted, but only if there
- # is no entry in the global overrides plist.
- # We need to draw a distinction between undefined, true and false for both
- # locations where the Disabled flag can be defined.
- def enabled?
- job_plist_disabled = nil
- overrides_disabled = nil
-
- job_path, job_plist = plist_from_label(resource[:name])
- job_plist_disabled = job_plist["Disabled"] if job_plist.has_key?("Disabled")
-
- if self.class.get_macosx_version_major == "10.6":
- overrides = Plist::parse_xml(Launchd_Overrides)
-
- unless overrides.nil?
- if overrides.has_key?(resource[:name])
- overrides_disabled = overrides[resource[:name]]["Disabled"] if overrides[resource[:name]].has_key?("Disabled")
- end
- end
- end
-
- if overrides_disabled.nil?
- if job_plist_disabled.nil? or job_plist_disabled == false
- return :true
- end
- elsif overrides_disabled == false
- return :true
- end
- :false
+ # As load -w clears the Disabled flag, we need to add it in after
+ self.disable if did_enable_job and resource[:enable] == :false
+ end
+
+
+ def stop
+ job_path, job_plist = plist_from_label(resource[:name])
+ did_disable_job = false
+ cmds = []
+ cmds << :launchctl << :unload
+ if self.enabled? == :true # keepalive jobs can't be stopped without disabling
+ cmds << "-w"
+ did_disable_job = true
end
-
-
- # enable and disable are a bit hacky. We write out the plist with the appropriate value
- # rather than dealing with launchctl as it is unable to change the Disabled flag
- # without actually loading/unloading the job.
- # In 10.6 we need to write out a disabled key to the global overrides plist, in earlier
- # versions this is stored in the job plist itself.
- def enable
- if self.class.get_macosx_version_major == "10.6"
- overrides = Plist::parse_xml(Launchd_Overrides)
- overrides[resource[:name]] = { "Disabled" => false }
- Plist::Emit.save_plist(overrides, Launchd_Overrides)
- else
- job_path, job_plist = plist_from_label(resource[:name])
- if self.enabled? == :false
- job_plist.delete("Disabled")
- Plist::Emit.save_plist(job_plist, job_path)
- end
+ cmds << job_path
+ begin
+ execute(cmds)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error.new("Unable to stop service: #{resource[:name]} at path: #{job_path}")
+ end
+ # As unload -w sets the Disabled flag, we need to add it in after
+ self.enable if did_disable_job and resource[:enable] == :true
+ end
+
+
+ # launchd jobs are enabled by default. They are only disabled if the key
+ # "Disabled" is set to true, but it can also be set to false to enable it.
+ # In 10.6, the Disabled key in the job plist is consulted, but only if there
+ # is no entry in the global overrides plist.
+ # We need to draw a distinction between undefined, true and false for both
+ # locations where the Disabled flag can be defined.
+ def enabled?
+ job_plist_disabled = nil
+ overrides_disabled = nil
+
+ job_path, job_plist = plist_from_label(resource[:name])
+ job_plist_disabled = job_plist["Disabled"] if job_plist.has_key?("Disabled")
+
+ if self.class.get_macosx_version_major == "10.6":
+ overrides = Plist::parse_xml(Launchd_Overrides)
+
+ unless overrides.nil?
+ if overrides.has_key?(resource[:name])
+ overrides_disabled = overrides[resource[:name]]["Disabled"] if overrides[resource[:name]].has_key?("Disabled")
end
+ end
end
-
- def disable
- if self.class.get_macosx_version_major == "10.6"
- overrides = Plist::parse_xml(Launchd_Overrides)
- overrides[resource[:name]] = { "Disabled" => true }
- Plist::Emit.save_plist(overrides, Launchd_Overrides)
- else
- job_path, job_plist = plist_from_label(resource[:name])
- job_plist["Disabled"] = true
- Plist::Emit.save_plist(job_plist, job_path)
- end
+ if overrides_disabled.nil?
+ if job_plist_disabled.nil? or job_plist_disabled == false
+ return :true
+ end
+ elsif overrides_disabled == false
+ return :true
+ end
+ :false
+ end
+
+
+ # enable and disable are a bit hacky. We write out the plist with the appropriate value
+ # rather than dealing with launchctl as it is unable to change the Disabled flag
+ # without actually loading/unloading the job.
+ # In 10.6 we need to write out a disabled key to the global overrides plist, in earlier
+ # versions this is stored in the job plist itself.
+ def enable
+ if self.class.get_macosx_version_major == "10.6"
+ overrides = Plist::parse_xml(Launchd_Overrides)
+ overrides[resource[:name]] = { "Disabled" => false }
+ Plist::Emit.save_plist(overrides, Launchd_Overrides)
+ else
+ job_path, job_plist = plist_from_label(resource[:name])
+ if self.enabled? == :false
+ job_plist.delete("Disabled")
+ Plist::Emit.save_plist(job_plist, job_path)
+ end
+ end
+ end
+
+
+ def disable
+ if self.class.get_macosx_version_major == "10.6"
+ overrides = Plist::parse_xml(Launchd_Overrides)
+ overrides[resource[:name]] = { "Disabled" => true }
+ Plist::Emit.save_plist(overrides, Launchd_Overrides)
+ else
+ job_path, job_plist = plist_from_label(resource[:name])
+ job_plist["Disabled"] = true
+ Plist::Emit.save_plist(job_plist, job_path)
end
+ end
end
diff --git a/lib/puppet/provider/service/redhat.rb b/lib/puppet/provider/service/redhat.rb
index 3a25db3ac..3ca67d66f 100755
--- a/lib/puppet/provider/service/redhat.rb
+++ b/lib/puppet/provider/service/redhat.rb
@@ -1,76 +1,76 @@
# Manage Red Hat services. Start/stop uses /sbin/service and enable/disable uses chkconfig
Puppet::Type.type(:service).provide :redhat, :parent => :init, :source => :init do
- desc "Red Hat's (and probably many others) form of ``init``-style service management:
+ desc "Red Hat's (and probably many others) form of ``init``-style service management:
- Uses ``chkconfig`` for service enabling and disabling.
+ Uses ``chkconfig`` for service enabling and disabling.
- "
+ "
- commands :chkconfig => "/sbin/chkconfig", :service => "/sbin/service"
+ commands :chkconfig => "/sbin/chkconfig", :service => "/sbin/service"
- defaultfor :operatingsystem => [:redhat, :fedora, :suse, :centos, :sles, :oel, :ovm]
+ defaultfor :operatingsystem => [:redhat, :fedora, :suse, :centos, :sles, :oel, :ovm]
- def self.instances
- # this exclude list is all from /sbin/service (5.x), but I did not exclude kudzu
- self.get_services(['/etc/init.d'], ['functions', 'halt', 'killall', 'single', 'linuxconf'])
- end
-
- def self.defpath
- superclass.defpath
- end
-
- # Remove the symlinks
- def disable
- output = chkconfig(@resource[:name], :off)
- rescue Puppet::ExecutionFailure
- raise Puppet::Error, "Could not disable #{self.name}: #{output}"
- end
-
- def enabled?
- begin
- output = chkconfig(@resource[:name])
- rescue Puppet::ExecutionFailure
- return :false
- end
-
- # If it's disabled on SuSE, then it will print output showing "off"
- # at the end
- if output =~ /.* off$/
- return :false
- end
+ def self.instances
+ # this exclude list is all from /sbin/service (5.x), but I did not exclude kudzu
+ self.get_services(['/etc/init.d'], ['functions', 'halt', 'killall', 'single', 'linuxconf'])
+ end
- :true
- end
-
- # Don't support them specifying runlevels; always use the runlevels
- # in the init scripts.
- def enable
- output = chkconfig(@resource[:name], :on)
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not enable #{self.name}: #{detail}"
- end
-
- def initscript
- raise Puppet::Error, "Do not directly call the init script for '#{@resource[:name]}'; use 'service' instead"
- end
+ def self.defpath
+ superclass.defpath
+ end
- # use hasstatus=>true when its set for the provider.
- def statuscmd
- ((@resource.provider.get(:hasstatus) == true) || (@resource[:hasstatus] == :true)) && [command(:service), @resource[:name], "status"]
- end
+ # Remove the symlinks
+ def disable
+ output = chkconfig(@resource[:name], :off)
+ rescue Puppet::ExecutionFailure
+ raise Puppet::Error, "Could not disable #{self.name}: #{output}"
+ end
- def restartcmd
- (@resource[:hasrestart] == :true) && [command(:service), @resource[:name], "restart"]
+ def enabled?
+ begin
+ output = chkconfig(@resource[:name])
+ rescue Puppet::ExecutionFailure
+ return :false
end
- def startcmd
- [command(:service), @resource[:name], "start"]
+ # If it's disabled on SuSE, then it will print output showing "off"
+ # at the end
+ if output =~ /.* off$/
+ return :false
end
- def stopcmd
- [command(:service), @resource[:name], "stop"]
- end
+ :true
+ end
+
+ # Don't support them specifying runlevels; always use the runlevels
+ # in the init scripts.
+ def enable
+ output = chkconfig(@resource[:name], :on)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not enable #{self.name}: #{detail}"
+ end
+
+ def initscript
+ raise Puppet::Error, "Do not directly call the init script for '#{@resource[:name]}'; use 'service' instead"
+ end
+
+ # use hasstatus=>true when its set for the provider.
+ def statuscmd
+ ((@resource.provider.get(:hasstatus) == true) || (@resource[:hasstatus] == :true)) && [command(:service), @resource[:name], "status"]
+ end
+
+ def restartcmd
+ (@resource[:hasrestart] == :true) && [command(:service), @resource[:name], "restart"]
+ end
+
+ def startcmd
+ [command(:service), @resource[:name], "start"]
+ end
+
+ def stopcmd
+ [command(:service), @resource[:name], "stop"]
+ end
end
diff --git a/lib/puppet/provider/service/runit.rb b/lib/puppet/provider/service/runit.rb
index c2603c9d8..0315b9597 100644
--- a/lib/puppet/provider/service/runit.rb
+++ b/lib/puppet/provider/service/runit.rb
@@ -2,102 +2,102 @@
#
# author Brice Figureau <brice-puppet@daysofwonder.com>
Puppet::Type.type(:service).provide :runit, :parent => :daemontools do
- desc "Runit service management.
+ desc "Runit service management.
- This provider manages daemons running supervised by Runit.
- It tries to detect the service directory, with by order of preference:
+ This provider manages daemons running supervised by Runit.
+ It tries to detect the service directory, with by order of preference:
- * /service
- * /var/service
- * /etc/service
+ * /service
+ * /var/service
+ * /etc/service
- The daemon directory should be placed in a directory that can be
- by default in:
+ The daemon directory should be placed in a directory that can be
+ by default in:
- * /etc/sv
+ * /etc/sv
- or this can be overriden in the service resource parameters::
+ or this can be overriden in the service resource parameters::
- service {
- \"myservice\":
- provider => \"runit\", path => \"/path/to/daemons\";
- }
+ service {
+ \"myservice\":
+ provider => \"runit\", path => \"/path/to/daemons\";
+ }
- This provider supports out of the box:
+ This provider supports out of the box:
- * start/stop
- * enable/disable
- * restart
- * status
+ * start/stop
+ * enable/disable
+ * restart
+ * status
"
- commands :sv => "/usr/bin/sv"
-
- class << self
- # this is necessary to autodetect a valid resource
- # default path, since there is no standard for such directory.
- def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
- unless @defpath
- ["/etc/sv", "/var/lib/service"].each do |path|
- if FileTest.exist?(path)
- @defpath = path
- break
- end
- end
- raise "Could not find the daemon directory (tested [/var/lib/service,/etc])" unless @defpath
- end
- @defpath
+ commands :sv => "/usr/bin/sv"
+
+ class << self
+ # this is necessary to autodetect a valid resource
+ # default path, since there is no standard for such directory.
+ def defpath(dummy_argument=:work_arround_for_ruby_GC_bug)
+ unless @defpath
+ ["/etc/sv", "/var/lib/service"].each do |path|
+ if FileTest.exist?(path)
+ @defpath = path
+ break
+ end
end
+ raise "Could not find the daemon directory (tested [/var/lib/service,/etc])" unless @defpath
+ end
+ @defpath
end
-
- # find the service dir on this node
- def servicedir
- unless @servicedir
- ["/service", "/etc/service","/var/service"].each do |path|
- if FileTest.exist?(path)
- @servicedir = path
- break
- end
- end
- raise "Could not find service directory" unless @servicedir
- end
- @servicedir
- end
-
- def status
- begin
- output = sv "status", self.daemon
- return :running if output =~ /^run: /
- rescue Puppet::ExecutionFailure => detail
- unless detail.message =~ /(warning: |runsv not running$)/
- raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}" )
- end
+ end
+
+ # find the service dir on this node
+ def servicedir
+ unless @servicedir
+ ["/service", "/etc/service","/var/service"].each do |path|
+ if FileTest.exist?(path)
+ @servicedir = path
+ break
end
- :stopped
- end
-
- def stop
- sv "stop", self.service
+ end
+ raise "Could not find service directory" unless @servicedir
end
-
- def start
- enable unless enabled? == :true
- sv "start", self.service
- end
-
- def restart
- sv "restart", self.service
- end
-
- # disable by removing the symlink so that runit
- # doesn't restart our service behind our back
- # note that runit doesn't need to perform a stop
- # before a disable
- def disable
- # unlink the daemon symlink to disable it
- File.unlink(self.service) if FileTest.symlink?(self.service)
+ @servicedir
+ end
+
+ def status
+ begin
+ output = sv "status", self.daemon
+ return :running if output =~ /^run: /
+ rescue Puppet::ExecutionFailure => detail
+ unless detail.message =~ /(warning: |runsv not running$)/
+ raise Puppet::Error.new( "Could not get status for service #{resource.ref}: #{detail}" )
+ end
end
+ :stopped
+ end
+
+ def stop
+ sv "stop", self.service
+ end
+
+ def start
+ enable unless enabled? == :true
+ sv "start", self.service
+ end
+
+ def restart
+ sv "restart", self.service
+ end
+
+ # disable by removing the symlink so that runit
+ # doesn't restart our service behind our back
+ # note that runit doesn't need to perform a stop
+ # before a disable
+ def disable
+ # unlink the daemon symlink to disable it
+ File.unlink(self.service) if FileTest.symlink?(self.service)
+ end
end
diff --git a/lib/puppet/provider/service/smf.rb b/lib/puppet/provider/service/smf.rb
index ca7af9449..3efb2eb37 100755
--- a/lib/puppet/provider/service/smf.rb
+++ b/lib/puppet/provider/service/smf.rb
@@ -1,103 +1,103 @@
# Solaris 10 SMF-style services.
Puppet::Type.type(:service).provide :smf, :parent => :base do
- desc "Support for Sun's new Service Management Framework.
+ desc "Support for Sun's new Service Management Framework.
- Starting a service is effectively equivalent to enabling it, so there is
- only support for starting and stopping services, which also enables and
- disables them, respectively.
+ Starting a service is effectively equivalent to enabling it, so there is
+ only support for starting and stopping services, which also enables and
+ disables them, respectively.
- By specifying manifest => \"/path/to/service.xml\", the SMF manifest will
- be imported if it does not exist.
+ By specifying manifest => \"/path/to/service.xml\", the SMF manifest will
+ be imported if it does not exist.
- "
+ "
- defaultfor :operatingsystem => :solaris
+ defaultfor :operatingsystem => :solaris
- confine :operatingsystem => :solaris
+ confine :operatingsystem => :solaris
- commands :adm => "/usr/sbin/svcadm", :svcs => "/usr/bin/svcs"
- commands :svccfg => "/usr/sbin/svccfg"
+ commands :adm => "/usr/sbin/svcadm", :svcs => "/usr/bin/svcs"
+ commands :svccfg => "/usr/sbin/svccfg"
- def setupservice
- if resource[:manifest]
- [command(:svcs), "-l", @resource[:name]]
- if $CHILD_STATUS.exitstatus == 1
- Puppet.notice "Importing #{@resource[:manifest]} for #{@resource[:name]}"
- svccfg :import, resource[:manifest]
- end
- end
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}" )
- end
-
- def enable
- self.start
- end
-
- def enabled?
- case self.status
- when :running
- return :true
- else
- return :false
+ def setupservice
+ if resource[:manifest]
+ [command(:svcs), "-l", @resource[:name]]
+ if $CHILD_STATUS.exitstatus == 1
+ Puppet.notice "Importing #{@resource[:manifest]} for #{@resource[:name]}"
+ svccfg :import, resource[:manifest]
end
+ end
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error.new( "Cannot config #{self.service} to enable it: #{detail}" )
+ end
+
+ def enable
+ self.start
+ end
+
+ def enabled?
+ case self.status
+ when :running
+ return :true
+ else
+ return :false
end
-
- def disable
- self.stop
+ end
+
+ def disable
+ self.stop
+ end
+
+ def restartcmd
+ [command(:adm), :restart, @resource[:name]]
+ end
+
+ def startcmd
+ self.setupservice
+ case self.status
+ when :stopped
+ [command(:adm), :enable, @resource[:name]]
+ when :maintenance
+ [command(:adm), :clear, @resource[:name]]
end
+ end
- def restartcmd
- [command(:adm), :restart, @resource[:name]]
+ def status
+ if @resource[:status]
+ super
+ return
end
- def startcmd
- self.setupservice
- case self.status
- when :stopped
- [command(:adm), :enable, @resource[:name]]
- when :maintenance
- [command(:adm), :clear, @resource[:name]]
- end
+ begin
+ # get the current state and the next state, and if the next
+ # state is set (i.e. not "-") use it for state comparison
+ states = svcs("-H", "-o", "state,nstate", @resource[:name]).chomp.split
+ state = states[1] == "-" ? states[0] : states[1]
+ rescue Puppet::ExecutionFailure
+ info "Could not get status on service #{self.name}"
+ return :stopped
end
- def status
- if @resource[:status]
- super
- return
- end
-
- begin
- # get the current state and the next state, and if the next
- # state is set (i.e. not "-") use it for state comparison
- states = svcs("-H", "-o", "state,nstate", @resource[:name]).chomp.split
- state = states[1] == "-" ? states[0] : states[1]
- rescue Puppet::ExecutionFailure
- info "Could not get status on service #{self.name}"
- return :stopped
- end
-
- case state
- when "online"
- #self.warning "matched running #{line.inspect}"
- return :running
- when "offline", "disabled", "uninitialized"
- #self.warning "matched stopped #{line.inspect}"
- return :stopped
- when "maintenance"
- return :maintenance
- when "legacy_run"
- raise Puppet::Error,
- "Cannot manage legacy services through SMF"
- else
- raise Puppet::Error,
- "Unmanageable state '#{state}' on service #{self.name}"
- end
-
+ case state
+ when "online"
+ #self.warning "matched running #{line.inspect}"
+ return :running
+ when "offline", "disabled", "uninitialized"
+ #self.warning "matched stopped #{line.inspect}"
+ return :stopped
+ when "maintenance"
+ return :maintenance
+ when "legacy_run"
+ raise Puppet::Error,
+ "Cannot manage legacy services through SMF"
+ else
+ raise Puppet::Error,
+ "Unmanageable state '#{state}' on service #{self.name}"
end
- def stopcmd
- [command(:adm), :disable, @resource[:name]]
- end
+ end
+
+ def stopcmd
+ [command(:adm), :disable, @resource[:name]]
+ end
end
diff --git a/lib/puppet/provider/service/src.rb b/lib/puppet/provider/service/src.rb
index aed88d531..2bd643c0b 100755
--- a/lib/puppet/provider/service/src.rb
+++ b/lib/puppet/provider/service/src.rb
@@ -1,87 +1,87 @@
# AIX System Resource controller (SRC)
Puppet::Type.type(:service).provide :src, :parent => :base do
- desc "Support for AIX's System Resource controller.
-
- Services are started/stopped based on the stopsrc and startsrc
- commands, and some services can be refreshed with refresh command.
-
- * Enabling and disableing services is not supported, as it requires
- modifications to /etc/inittab.
-
- * Starting and stopping groups of subsystems is not yet supported
- "
-
- defaultfor :operatingsystem => :aix
- confine :operatingsystem => :aix
-
- commands :stopsrc => "/usr/bin/stopsrc"
- commands :startsrc => "/usr/bin/startsrc"
- commands :refresh => "/usr/bin/refresh"
- commands :lssrc => "/usr/bin/lssrc"
-
- has_feature :refreshable
-
- def startcmd
- [command(:startsrc), "-s", @resource[:name]]
- end
-
- def stopcmd
- [command(:stopsrc), "-s", @resource[:name]]
- end
-
- def restart
- execute([command(:lssrc), "-Ss", @resource[:name]]).each do |line|
- args = line.split(":")
-
- next unless args[0] == @resource[:name]
-
- # Subsystems with the -K flag can get refreshed (HUPed)
- # While subsystems with -S (signals) must be stopped/started
- method = args[11]
- do_refresh = case method
- when "-K" then :true
- when "-S" then :false
- else self.fail("Unknown service communication method #{method}")
- end
-
- begin
- if do_refresh == :true
- execute([command(:refresh), "-s", @resource[:name]])
- else
- self.stop
- self.start
- end
- return :true
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new("Unable to restart service #{@resource[:name]}, error was: #{detail}" )
- end
- end
- self.fail("No such service found")
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}" )
- end
-
- def status
- execute([command(:lssrc), "-s", @resource[:name]]).each do |line|
- args = line.split
-
- # This is the header line
- next unless args[0] == @resource[:name]
-
- # PID is the 3rd field, but inoperative subsystems
- # skip this so split doesn't work right
- state = case args[-1]
- when "active" then :running
- when "inoperative" then :stopped
- end
- Puppet.debug("Service #{@resource[:name]} is #{args[-1]}")
- return state
- end
- self.fail("No such service found")
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}" )
- end
+ desc "Support for AIX's System Resource controller.
+
+ Services are started/stopped based on the stopsrc and startsrc
+ commands, and some services can be refreshed with refresh command.
+
+ * Enabling and disableing services is not supported, as it requires
+ modifications to /etc/inittab.
+
+ * Starting and stopping groups of subsystems is not yet supported
+ "
+
+ defaultfor :operatingsystem => :aix
+ confine :operatingsystem => :aix
+
+ commands :stopsrc => "/usr/bin/stopsrc"
+ commands :startsrc => "/usr/bin/startsrc"
+ commands :refresh => "/usr/bin/refresh"
+ commands :lssrc => "/usr/bin/lssrc"
+
+ has_feature :refreshable
+
+ def startcmd
+ [command(:startsrc), "-s", @resource[:name]]
+ end
+
+ def stopcmd
+ [command(:stopsrc), "-s", @resource[:name]]
+ end
+
+ def restart
+ execute([command(:lssrc), "-Ss", @resource[:name]]).each do |line|
+ args = line.split(":")
+
+ next unless args[0] == @resource[:name]
+
+ # Subsystems with the -K flag can get refreshed (HUPed)
+ # While subsystems with -S (signals) must be stopped/started
+ method = args[11]
+ do_refresh = case method
+ when "-K" then :true
+ when "-S" then :false
+ else self.fail("Unknown service communication method #{method}")
+ end
+
+ begin
+ if do_refresh == :true
+ execute([command(:refresh), "-s", @resource[:name]])
+ else
+ self.stop
+ self.start
+ end
+ return :true
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error.new("Unable to restart service #{@resource[:name]}, error was: #{detail}" )
+ end
+ end
+ self.fail("No such service found")
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}" )
+ end
+
+ def status
+ execute([command(:lssrc), "-s", @resource[:name]]).each do |line|
+ args = line.split
+
+ # This is the header line
+ next unless args[0] == @resource[:name]
+
+ # PID is the 3rd field, but inoperative subsystems
+ # skip this so split doesn't work right
+ state = case args[-1]
+ when "active" then :running
+ when "inoperative" then :stopped
+ end
+ Puppet.debug("Service #{@resource[:name]} is #{args[-1]}")
+ return state
+ end
+ self.fail("No such service found")
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error.new("Cannot get status of #{@resource[:name]}, error was: #{detail}" )
+ end
end
diff --git a/lib/puppet/provider/ssh_authorized_key/parsed.rb b/lib/puppet/provider/ssh_authorized_key/parsed.rb
index a9738e761..82f6b8881 100644
--- a/lib/puppet/provider/ssh_authorized_key/parsed.rb
+++ b/lib/puppet/provider/ssh_authorized_key/parsed.rb
@@ -1,89 +1,89 @@
require 'puppet/provider/parsedfile'
- Puppet::Type.type(:ssh_authorized_key).provide(
- :parsed,
- :parent => Puppet::Provider::ParsedFile,
- :filetype => :flat,
+ Puppet::Type.type(:ssh_authorized_key).provide(
+ :parsed,
+ :parent => Puppet::Provider::ParsedFile,
+ :filetype => :flat,
- :default_target => ''
+ :default_target => ''
) do
- desc "Parse and generate authorized_keys files for SSH."
+ desc "Parse and generate authorized_keys files for SSH."
- text_line :comment, :match => /^#/
- text_line :blank, :match => /^\s+/
+ text_line :comment, :match => /^#/
+ text_line :blank, :match => /^\s+/
- record_line :parsed,
- :fields => %w{options type key name},
- :optional => %w{options},
- :rts => /^\s+/,
- :match => /^(?:(.+) )?(ssh-dss|ssh-rsa) ([^ ]+) ?(.*)$/,
- :post_parse => proc { |h|
- h[:name] = "" if h[:name] == :absent
- h[:options] ||= [:absent]
- h[:options] = Puppet::Type::Ssh_authorized_key::ProviderParsed.parse_options(h[:options]) if h[:options].is_a? String
- },
- :pre_gen => proc { |h|
- h[:options] = [] if h[:options].include?(:absent)
- h[:options] = h[:options].join(',')
- }
+ record_line :parsed,
+ :fields => %w{options type key name},
+ :optional => %w{options},
+ :rts => /^\s+/,
+ :match => /^(?:(.+) )?(ssh-dss|ssh-rsa) ([^ ]+) ?(.*)$/,
+ :post_parse => proc { |h|
+ h[:name] = "" if h[:name] == :absent
+ h[:options] ||= [:absent]
+ h[:options] = Puppet::Type::Ssh_authorized_key::ProviderParsed.parse_options(h[:options]) if h[:options].is_a? String
+ },
+ :pre_gen => proc { |h|
+ h[:options] = [] if h[:options].include?(:absent)
+ h[:options] = h[:options].join(',')
+ }
- record_line :key_v1,
- :fields => %w{options bits exponent modulus name},
- :optional => %w{options},
- :rts => /^\s+/,
- :match => /^(?:(.+) )?(\d+) (\d+) (\d+)(?: (.+))?$/
+ record_line :key_v1,
+ :fields => %w{options bits exponent modulus name},
+ :optional => %w{options},
+ :rts => /^\s+/,
+ :match => /^(?:(.+) )?(\d+) (\d+) (\d+)(?: (.+))?$/
- def dir_perm
- 0700
- end
+ def dir_perm
+ 0700
+ end
- def file_perm
- 0600
- end
+ def file_perm
+ 0600
+ end
- def target
- @resource.should(:target) || File.expand_path("~#{@resource.should(:user)}/.ssh/authorized_keys")
- rescue
- raise Puppet::Error, "Target not defined and/or specified user does not exist yet"
- end
+ def target
+ @resource.should(:target) || File.expand_path("~#{@resource.should(:user)}/.ssh/authorized_keys")
+ rescue
+ raise Puppet::Error, "Target not defined and/or specified user does not exist yet"
+ end
- def user
- uid = File.stat(target).uid
- Etc.getpwuid(uid).name
- end
+ def user
+ uid = File.stat(target).uid
+ Etc.getpwuid(uid).name
+ end
- def flush
- raise Puppet::Error, "Cannot write SSH authorized keys without user" unless @resource.should(:user)
- raise Puppet::Error, "User '#{@resource.should(:user)}' does not exist" unless uid = Puppet::Util.uid(@resource.should(:user))
- unless File.exist?(dir = File.dirname(target))
- Puppet.debug "Creating #{dir}"
- Dir.mkdir(dir, dir_perm)
- File.chown(uid, nil, dir)
- end
- Puppet::Util::SUIDManager.asuser(@resource.should(:user)) { super }
- File.chown(uid, nil, target)
- File.chmod(file_perm, target)
+ def flush
+ raise Puppet::Error, "Cannot write SSH authorized keys without user" unless @resource.should(:user)
+ raise Puppet::Error, "User '#{@resource.should(:user)}' does not exist" unless uid = Puppet::Util.uid(@resource.should(:user))
+ unless File.exist?(dir = File.dirname(target))
+ Puppet.debug "Creating #{dir}"
+ Dir.mkdir(dir, dir_perm)
+ File.chown(uid, nil, dir)
end
+ Puppet::Util::SUIDManager.asuser(@resource.should(:user)) { super }
+ File.chown(uid, nil, target)
+ File.chmod(file_perm, target)
+ end
- # parse sshv2 option strings, wich is a comma separated list of
- # either key="values" elements or bare-word elements
- def self.parse_options(options)
- result = []
- scanner = StringScanner.new(options)
- while !scanner.eos?
- scanner.skip(/[ \t]*/)
- # scan a long option
- if out = scanner.scan(/[-a-z0-9A-Z_]+=\".*?\"/) or out = scanner.scan(/[-a-z0-9A-Z_]+/)
- result << out
- else
- # found an unscannable token, let's abort
- break
- end
- # eat a comma
- scanner.skip(/[ \t]*,[ \t]*/)
- end
- result
+ # parse sshv2 option strings, wich is a comma separated list of
+ # either key="values" elements or bare-word elements
+ def self.parse_options(options)
+ result = []
+ scanner = StringScanner.new(options)
+ while !scanner.eos?
+ scanner.skip(/[ \t]*/)
+ # scan a long option
+ if out = scanner.scan(/[-a-z0-9A-Z_]+=\".*?\"/) or out = scanner.scan(/[-a-z0-9A-Z_]+/)
+ result << out
+ else
+ # found an unscannable token, let's abort
+ break
+ end
+ # eat a comma
+ scanner.skip(/[ \t]*,[ \t]*/)
end
+ result
+ end
end
diff --git a/lib/puppet/provider/sshkey/parsed.rb b/lib/puppet/provider/sshkey/parsed.rb
index 4fefc4067..dcc55b403 100755
--- a/lib/puppet/provider/sshkey/parsed.rb
+++ b/lib/puppet/provider/sshkey/parsed.rb
@@ -4,35 +4,35 @@ known = nil
case Facter.value(:operatingsystem)
when "Darwin"; known = "/etc/ssh_known_hosts"
else
- known = "/etc/ssh/ssh_known_hosts"
+ known = "/etc/ssh/ssh_known_hosts"
end
- Puppet::Type.type(:sshkey).provide(
- :parsed,
- :parent => Puppet::Provider::ParsedFile,
- :default_target => known,
+ Puppet::Type.type(:sshkey).provide(
+ :parsed,
+ :parent => Puppet::Provider::ParsedFile,
+ :default_target => known,
- :filetype => :flat
+ :filetype => :flat
) do
- desc "Parse and generate host-wide known hosts files for SSH."
+ desc "Parse and generate host-wide known hosts files for SSH."
- text_line :comment, :match => /^#/
- text_line :blank, :match => /^\s+/
+ text_line :comment, :match => /^#/
+ text_line :blank, :match => /^\s+/
- record_line :parsed, :fields => %w{name type key},
- :post_parse => proc { |hash|
- names = hash[:name].split(",", -1)
- hash[:name] = names.shift
- hash[:host_aliases] = names
- },
- :pre_gen => proc { |hash|
- if hash[:host_aliases]
- names = [hash[:name], hash[:host_aliases]].flatten
+ record_line :parsed, :fields => %w{name type key},
+ :post_parse => proc { |hash|
+ names = hash[:name].split(",", -1)
+ hash[:name] = names.shift
+ hash[:host_aliases] = names
+ },
+ :pre_gen => proc { |hash|
+ if hash[:host_aliases]
+ names = [hash[:name], hash[:host_aliases]].flatten
- hash[:name] = [hash[:name], hash[:host_aliases]].flatten.join(",")
- hash.delete(:host_aliases)
- end
- }
+ hash[:name] = [hash[:name], hash[:host_aliases]].flatten.join(",")
+ hash.delete(:host_aliases)
+ end
+ }
end
diff --git a/lib/puppet/provider/user/directoryservice.rb b/lib/puppet/provider/user/directoryservice.rb
index 46d017e4b..4b62a6ae7 100644
--- a/lib/puppet/provider/user/directoryservice.rb
+++ b/lib/puppet/provider/user/directoryservice.rb
@@ -15,86 +15,86 @@
require 'puppet/provider/nameservice/directoryservice'
Puppet::Type.type(:user).provide :directoryservice, :parent => Puppet::Provider::NameService::DirectoryService do
- desc "User management using DirectoryService on OS X."
+ desc "User management using DirectoryService on OS X."
- commands :dscl => "/usr/bin/dscl"
- confine :operatingsystem => :darwin
- defaultfor :operatingsystem => :darwin
+ commands :dscl => "/usr/bin/dscl"
+ confine :operatingsystem => :darwin
+ defaultfor :operatingsystem => :darwin
- # JJM: DirectoryService can manage passwords.
- # This needs to be a special option to dscl though (-passwd)
- has_feature :manages_passwords
+ # JJM: DirectoryService can manage passwords.
+ # This needs to be a special option to dscl though (-passwd)
+ has_feature :manages_passwords
- # JJM: comment matches up with the /etc/passwd concept of an user
- options :comment, :key => "realname"
- options :password, :key => "passwd"
+ # JJM: comment matches up with the /etc/passwd concept of an user
+ options :comment, :key => "realname"
+ options :password, :key => "passwd"
- autogen_defaults :home => "/var/empty", :shell => "/usr/bin/false"
+ autogen_defaults :home => "/var/empty", :shell => "/usr/bin/false"
- verify :gid, "GID must be an integer" do |value|
- value.is_a? Integer
- end
+ verify :gid, "GID must be an integer" do |value|
+ value.is_a? Integer
+ end
- verify :uid, "UID must be an integer" do |value|
- value.is_a? Integer
- end
+ verify :uid, "UID must be an integer" do |value|
+ value.is_a? Integer
+ end
- def autogen_comment
- @resource[:name].capitalize
- end
+ def autogen_comment
+ @resource[:name].capitalize
+ end
- # The list of all groups the user is a member of.
- # JJM: FIXME: Override this method...
- def groups
- groups = []
- groups.join(",")
- end
+ # The list of all groups the user is a member of.
+ # JJM: FIXME: Override this method...
+ def groups
+ groups = []
+ groups.join(",")
+ end
- # This is really lame. We have to iterate over each
- # of the groups and add us to them.
- def groups=(groups)
- # case groups
- # when Fixnum
- # groups = [groups.to_s]
- # when String
- # groups = groups.split(/\s*,\s*/)
- # else
- # raise Puppet::DevError, "got invalid groups value #{groups.class} of type #{groups}"
- # end
- # # Get just the groups we need to modify
- # diff = groups - (@is || [])
- #
- # data = {}
- # open("| #{command(:nireport)} / /groups name users") do |file|
- # file.each do |line|
- # name, members = line.split(/\s+/)
- #
- # if members.nil? or members =~ /NoValue/
- # data[name] = []
- # else
- # # Add each diff group's current members
- # data[name] = members.split(/,/)
- # end
- # end
- # end
- #
- # user = @resource[:name]
- # data.each do |name, members|
- # if members.include? user and groups.include? name
- # # I'm in the group and should be
- # next
- # elsif members.include? user
- # # I'm in the group and shouldn't be
- # setuserlist(name, members - [user])
- # elsif groups.include? name
- # # I'm not in the group and should be
- # setuserlist(name, members + [user])
- # else
- # # I'm not in the group and shouldn't be
- # next
- # end
- # end
- end
+ # This is really lame. We have to iterate over each
+ # of the groups and add us to them.
+ def groups=(groups)
+ # case groups
+ # when Fixnum
+ # groups = [groups.to_s]
+ # when String
+ # groups = groups.split(/\s*,\s*/)
+ # else
+ # raise Puppet::DevError, "got invalid groups value #{groups.class} of type #{groups}"
+ # end
+ # # Get just the groups we need to modify
+ # diff = groups - (@is || [])
+ #
+ # data = {}
+ # open("| #{command(:nireport)} / /groups name users") do |file|
+ # file.each do |line|
+ # name, members = line.split(/\s+/)
+ #
+ # if members.nil? or members =~ /NoValue/
+ # data[name] = []
+ # else
+ # # Add each diff group's current members
+ # data[name] = members.split(/,/)
+ # end
+ # end
+ # end
+ #
+ # user = @resource[:name]
+ # data.each do |name, members|
+ # if members.include? user and groups.include? name
+ # # I'm in the group and should be
+ # next
+ # elsif members.include? user
+ # # I'm in the group and shouldn't be
+ # setuserlist(name, members - [user])
+ # elsif groups.include? name
+ # # I'm not in the group and should be
+ # setuserlist(name, members + [user])
+ # else
+ # # I'm not in the group and shouldn't be
+ # next
+ # end
+ # end
+ end
end
diff --git a/lib/puppet/provider/user/hpux.rb b/lib/puppet/provider/user/hpux.rb
index db8dd194e..50506c4cd 100644
--- a/lib/puppet/provider/user/hpux.rb
+++ b/lib/puppet/provider/user/hpux.rb
@@ -1,30 +1,30 @@
Puppet::Type.type(:user).provide :hpuxuseradd, :parent => :useradd do
- desc "User management for hp-ux! Undocumented switch to special usermod because HP-UX regular usermod is TOO STUPID to change stuff while the user is logged in."
+ desc "User management for hp-ux! Undocumented switch to special usermod because HP-UX regular usermod is TOO STUPID to change stuff while the user is logged in."
- defaultfor :operatingsystem => "hp-ux"
- confine :operatingsystem => "hp-ux"
+ defaultfor :operatingsystem => "hp-ux"
+ confine :operatingsystem => "hp-ux"
- commands :modify => "/usr/sam/lbin/usermod.sam", :delete => "/usr/sam/lbin/userdel.sam", :add => "/usr/sbin/useradd"
- options :comment, :method => :gecos
- options :groups, :flag => "-G"
- options :home, :flag => "-d", :method => :dir
+ commands :modify => "/usr/sam/lbin/usermod.sam", :delete => "/usr/sam/lbin/userdel.sam", :add => "/usr/sbin/useradd"
+ options :comment, :method => :gecos
+ options :groups, :flag => "-G"
+ options :home, :flag => "-d", :method => :dir
- verify :gid, "GID must be an integer" do |value|
- value.is_a? Integer
- end
+ verify :gid, "GID must be an integer" do |value|
+ value.is_a? Integer
+ end
- verify :groups, "Groups must be comma-separated" do |value|
- value !~ /\s/
- end
+ verify :groups, "Groups must be comma-separated" do |value|
+ value !~ /\s/
+ end
- has_features :manages_homedir, :allows_duplicates
+ has_features :manages_homedir, :allows_duplicates
- def deletecmd
- super.insert(1,"-F")
- end
+ def deletecmd
+ super.insert(1,"-F")
+ end
- def modifycmd(param,value)
- super.insert(1,"-F")
- end
+ def modifycmd(param,value)
+ super.insert(1,"-F")
+ end
end
diff --git a/lib/puppet/provider/user/ldap.rb b/lib/puppet/provider/user/ldap.rb
index 406ed0f93..df082c569 100644
--- a/lib/puppet/provider/user/ldap.rb
+++ b/lib/puppet/provider/user/ldap.rb
@@ -1,129 +1,129 @@
require 'puppet/provider/ldap'
Puppet::Type.type(:user).provide :ldap, :parent => Puppet::Provider::Ldap do
- desc "User management via ``ldap``. This provider requires that you
- have valid values for all of the ldap-related settings,
- including ``ldapbase``. You will also almost definitely need settings
- for ``ldapuser`` and ``ldappassword``, so that your clients can write
- to ldap.
-
- Note that this provider will automatically generate a UID for you if
- you do not specify one, but it is a potentially expensive operation,
- as it iterates across all existing users to pick the appropriate next
- one."
-
- confine :feature => :ldap, :false => (Puppet[:ldapuser] == "")
-
- has_feature :manages_passwords
-
- manages(:posixAccount, :person).at("ou=People").named_by(:uid).and.maps :name => :uid,
- :password => :userPassword,
- :comment => :cn,
- :uid => :uidNumber,
- :gid => :gidNumber,
- :home => :homeDirectory,
- :shell => :loginShell
-
- # Use the last field of a space-separated array as
- # the sn. LDAP requires a surname, for some stupid reason.
- manager.generates(:sn).from(:cn).with do |cn|
- x = 1
- cn[0].split(/\s+/)[-1]
+ desc "User management via ``ldap``. This provider requires that you
+ have valid values for all of the ldap-related settings,
+ including ``ldapbase``. You will also almost definitely need settings
+ for ``ldapuser`` and ``ldappassword``, so that your clients can write
+ to ldap.
+
+ Note that this provider will automatically generate a UID for you if
+ you do not specify one, but it is a potentially expensive operation,
+ as it iterates across all existing users to pick the appropriate next
+ one."
+
+ confine :feature => :ldap, :false => (Puppet[:ldapuser] == "")
+
+ has_feature :manages_passwords
+
+ manages(:posixAccount, :person).at("ou=People").named_by(:uid).and.maps :name => :uid,
+ :password => :userPassword,
+ :comment => :cn,
+ :uid => :uidNumber,
+ :gid => :gidNumber,
+ :home => :homeDirectory,
+ :shell => :loginShell
+
+ # Use the last field of a space-separated array as
+ # the sn. LDAP requires a surname, for some stupid reason.
+ manager.generates(:sn).from(:cn).with do |cn|
+ x = 1
+ cn[0].split(/\s+/)[-1]
+ end
+
+ # Find the next uid after the current largest uid.
+ provider = self
+ manager.generates(:uidNumber).with do
+ largest = 500
+ if existing = provider.manager.search
+ existing.each do |hash|
+ next unless value = hash[:uid]
+ num = value[0].to_i
+ largest = num if num > largest
+ end
end
-
- # Find the next uid after the current largest uid.
- provider = self
- manager.generates(:uidNumber).with do
- largest = 500
- if existing = provider.manager.search
- existing.each do |hash|
- next unless value = hash[:uid]
- num = value[0].to_i
- largest = num if num > largest
- end
- end
- largest + 1
+ largest + 1
+ end
+
+ # Convert our gid to a group name, if necessary.
+ def gid=(value)
+ value = group2id(value) unless [Fixnum, Bignum].include?(value.class)
+
+ @property_hash[:gid] = value
+ end
+
+ # Find all groups this user is a member of in ldap.
+ def groups
+ # We want to cache the current result, so we know if we
+ # have to remove old values.
+ unless @property_hash[:groups]
+ unless result = group_manager.search("memberUid=#{name}")
+ return @property_hash[:groups] = :absent
+ end
+
+ return @property_hash[:groups] = result.collect { |r| r[:name] }.sort.join(",")
end
+ @property_hash[:groups]
+ end
- # Convert our gid to a group name, if necessary.
- def gid=(value)
- value = group2id(value) unless [Fixnum, Bignum].include?(value.class)
+ # Manage the list of groups this user is a member of.
+ def groups=(values)
+ should = values.split(",")
- @property_hash[:gid] = value
+ if groups == :absent
+ is = []
+ else
+ is = groups.split(",")
end
- # Find all groups this user is a member of in ldap.
- def groups
- # We want to cache the current result, so we know if we
- # have to remove old values.
- unless @property_hash[:groups]
- unless result = group_manager.search("memberUid=#{name}")
- return @property_hash[:groups] = :absent
- end
-
- return @property_hash[:groups] = result.collect { |r| r[:name] }.sort.join(",")
- end
- @property_hash[:groups]
- end
+ modes = {}
+ [is, should].flatten.uniq.each do |group|
+ # Skip it when they're in both
+ next if is.include?(group) and should.include?(group)
- # Manage the list of groups this user is a member of.
- def groups=(values)
- should = values.split(",")
+ # We're adding a group.
+ modes[group] = :add and next unless is.include?(group)
- if groups == :absent
- is = []
- else
- is = groups.split(",")
- end
+ # We're removing a group.
+ modes[group] = :remove and next unless should.include?(group)
+ end
- modes = {}
- [is, should].flatten.uniq.each do |group|
- # Skip it when they're in both
- next if is.include?(group) and should.include?(group)
+ modes.each do |group, form|
+ self.fail "Could not find ldap group #{group}" unless ldap_group = group_manager.find(group)
- # We're adding a group.
- modes[group] = :add and next unless is.include?(group)
+ current = ldap_group[:members]
- # We're removing a group.
- modes[group] = :remove and next unless should.include?(group)
+ if form == :add
+ if current.is_a?(Array) and ! current.empty?
+ new = current + [name]
+ else
+ new = [name]
end
+ else
+ new = current - [name]
+ new = :absent if new.empty?
+ end
- modes.each do |group, form|
- self.fail "Could not find ldap group #{group}" unless ldap_group = group_manager.find(group)
-
- current = ldap_group[:members]
-
- if form == :add
- if current.is_a?(Array) and ! current.empty?
- new = current + [name]
- else
- new = [name]
- end
- else
- new = current - [name]
- new = :absent if new.empty?
- end
-
- group_manager.update(group, {:ensure => :present, :members => current}, {:ensure => :present, :members => new})
- end
+ group_manager.update(group, {:ensure => :present, :members => current}, {:ensure => :present, :members => new})
end
+ end
- # Convert a gropu name to an id.
- def group2id(group)
- Puppet::Type.type(:group).provider(:ldap).name2id(group)
- end
+ # Convert a gropu name to an id.
+ def group2id(group)
+ Puppet::Type.type(:group).provider(:ldap).name2id(group)
+ end
- private
+ private
- def group_manager
- Puppet::Type.type(:group).provider(:ldap).manager
- end
+ def group_manager
+ Puppet::Type.type(:group).provider(:ldap).manager
+ end
- def group_properties(values)
- if values.empty? or values == :absent
- {:ensure => :present}
- else
- {:ensure => :present, :members => values}
- end
+ def group_properties(values)
+ if values.empty? or values == :absent
+ {:ensure => :present}
+ else
+ {:ensure => :present, :members => values}
end
+ end
end
diff --git a/lib/puppet/provider/user/pw.rb b/lib/puppet/provider/user/pw.rb
index 7d3eda281..345d924bf 100644
--- a/lib/puppet/provider/user/pw.rb
+++ b/lib/puppet/provider/user/pw.rb
@@ -1,41 +1,41 @@
require 'puppet/provider/nameservice/pw'
Puppet::Type.type(:user).provide :pw, :parent => Puppet::Provider::NameService::PW do
- desc "User management via ``pw`` on FreeBSD."
-
- commands :pw => "pw"
- has_features :manages_homedir, :allows_duplicates
-
- defaultfor :operatingsystem => :freebsd
-
- options :home, :flag => "-d", :method => :dir
- options :comment, :method => :gecos
- options :groups, :flag => "-G"
-
- verify :gid, "GID must be an integer" do |value|
- value.is_a? Integer
+ desc "User management via ``pw`` on FreeBSD."
+
+ commands :pw => "pw"
+ has_features :manages_homedir, :allows_duplicates
+
+ defaultfor :operatingsystem => :freebsd
+
+ options :home, :flag => "-d", :method => :dir
+ options :comment, :method => :gecos
+ options :groups, :flag => "-G"
+
+ verify :gid, "GID must be an integer" do |value|
+ value.is_a? Integer
+ end
+
+ verify :groups, "Groups must be comma-separated" do |value|
+ value !~ /\s/
+ end
+
+ def addcmd
+ cmd = [command(:pw), "useradd", @resource[:name]]
+ @resource.class.validproperties.each do |property|
+ next if property == :ensure
+ # the value needs to be quoted, mostly because -c might
+ # have spaces in it
+ if value = @resource.should(property) and value != ""
+ cmd << flag(property) << value
+ end
end
- verify :groups, "Groups must be comma-separated" do |value|
- value !~ /\s/
- end
-
- def addcmd
- cmd = [command(:pw), "useradd", @resource[:name]]
- @resource.class.validproperties.each do |property|
- next if property == :ensure
- # the value needs to be quoted, mostly because -c might
- # have spaces in it
- if value = @resource.should(property) and value != ""
- cmd << flag(property) << value
- end
- end
+ cmd << "-o" if @resource.allowdupe?
- cmd << "-o" if @resource.allowdupe?
+ cmd << "-m" if @resource.managehome?
- cmd << "-m" if @resource.managehome?
-
- cmd
- end
+ cmd
+ end
end
diff --git a/lib/puppet/provider/user/user_role_add.rb b/lib/puppet/provider/user/user_role_add.rb
index 7c7c9e315..ea1b01b3b 100644
--- a/lib/puppet/provider/user/user_role_add.rb
+++ b/lib/puppet/provider/user/user_role_add.rb
@@ -2,177 +2,177 @@ require 'puppet/util/user_attr'
Puppet::Type.type(:user).provide :user_role_add, :parent => :useradd, :source => :useradd do
- desc "User management inherits ``useradd`` and adds logic to manage roles on Solaris using roleadd."
-
- defaultfor :operatingsystem => :solaris
-
- commands :add => "useradd", :delete => "userdel", :modify => "usermod", :role_add => "roleadd", :role_delete => "roledel", :role_modify => "rolemod"
- options :home, :flag => "-d", :method => :dir
- options :comment, :method => :gecos
- options :groups, :flag => "-G"
- options :roles, :flag => "-R"
- options :auths, :flag => "-A"
- options :profiles, :flag => "-P"
-
- verify :gid, "GID must be an integer" do |value|
- value.is_a? Integer
- end
-
- verify :groups, "Groups must be comma-separated" do |value|
- value !~ /\s/
- end
-
- has_features :manages_homedir, :allows_duplicates, :manages_solaris_rbac, :manages_passwords
-
- #must override this to hand the keyvalue pairs
- def add_properties
- cmd = []
- Puppet::Type.type(:user).validproperties.each do |property|
- #skip the password because we can't create it with the solaris useradd
- next if [:ensure, :password].include?(property)
- # 1680 Now you can set the hashed passwords on solaris:lib/puppet/provider/user/user_role_add.rb
- # the value needs to be quoted, mostly because -c might
- # have spaces in it
- if value = @resource.should(property) and value != ""
- if property == :keys
- cmd += build_keys_cmd(value)
- else
- cmd << flag(property) << value
- end
- end
- end
- cmd
- end
-
- def user_attributes
- @user_attributes ||= UserAttr.get_attributes_by_name(@resource[:name])
- end
-
- def flush
- @user_attributes = nil
- end
-
- def command(cmd)
- cmd = ("role_#{cmd}").intern if is_role? or (!exists? and @resource[:ensure] == :role)
- super(cmd)
- end
-
- def is_role?
- user_attributes and user_attributes[:type] == "role"
- end
-
- def run(cmd, msg)
- execute(cmd)
- rescue Puppet::ExecutionFailure => detail
- raise Puppet::Error, "Could not #{msg} #{@resource.class.name} #{@resource.name}: #{detail}"
- end
-
- def transition(type)
- cmd = [command(:modify)]
- cmd << "-K" << "type=#{type}"
- cmd += add_properties
- cmd << @resource[:name]
- end
-
- def create
- if is_role?
- run(transition("normal"), "transition role to")
+ desc "User management inherits ``useradd`` and adds logic to manage roles on Solaris using roleadd."
+
+ defaultfor :operatingsystem => :solaris
+
+ commands :add => "useradd", :delete => "userdel", :modify => "usermod", :role_add => "roleadd", :role_delete => "roledel", :role_modify => "rolemod"
+ options :home, :flag => "-d", :method => :dir
+ options :comment, :method => :gecos
+ options :groups, :flag => "-G"
+ options :roles, :flag => "-R"
+ options :auths, :flag => "-A"
+ options :profiles, :flag => "-P"
+
+ verify :gid, "GID must be an integer" do |value|
+ value.is_a? Integer
+ end
+
+ verify :groups, "Groups must be comma-separated" do |value|
+ value !~ /\s/
+ end
+
+ has_features :manages_homedir, :allows_duplicates, :manages_solaris_rbac, :manages_passwords
+
+ #must override this to hand the keyvalue pairs
+ def add_properties
+ cmd = []
+ Puppet::Type.type(:user).validproperties.each do |property|
+ #skip the password because we can't create it with the solaris useradd
+ next if [:ensure, :password].include?(property)
+ # 1680 Now you can set the hashed passwords on solaris:lib/puppet/provider/user/user_role_add.rb
+ # the value needs to be quoted, mostly because -c might
+ # have spaces in it
+ if value = @resource.should(property) and value != ""
+ if property == :keys
+ cmd += build_keys_cmd(value)
else
- run(addcmd, "create")
+ cmd << flag(property) << value
end
- # added to handle case when password is specified
- self.password = @resource[:password] if @resource[:password]
- end
-
- def destroy
- run(deletecmd, "delete "+ (is_role? ? "role" : "user"))
- end
-
- def create_role
- if exists? and !is_role?
- run(transition("role"), "transition user to")
- else
- run(addcmd, "create role")
- end
- end
-
- def roles
- user_attributes[:roles] if user_attributes
- end
-
- def auths
- user_attributes[:auths] if user_attributes
- end
-
- def profiles
- user_attributes[:profiles] if user_attributes
- end
-
- def project
- user_attributes[:project] if user_attributes
- end
-
- def managed_attributes
- [:name, :type, :roles, :auths, :profiles, :project]
- end
-
- def remove_managed_attributes
- managed = managed_attributes
- user_attributes.select { |k,v| !managed.include?(k) }.inject({}) { |hash, array| hash[array[0]] = array[1]; hash }
- end
-
- def keys
- if user_attributes
- #we have to get rid of all the keys we are managing another way
- remove_managed_attributes
- end
- end
-
- def build_keys_cmd(keys_hash)
- cmd = []
- keys_hash.each do |k,v|
- cmd << "-K" << "#{k}=#{v}"
- end
- cmd
- end
-
- def keys=(keys_hash)
- run([command(:modify)] + build_keys_cmd(keys_hash) << @resource[:name], "modify attribute key pairs")
- end
-
- #Read in /etc/shadow, find the line for this user (skipping comments, because who knows) and return the hashed pw (the second entry)
- #No abstraction, all esoteric knowledge of file formats, yay
- def password
- #got perl?
- if ary = File.readlines("/etc/shadow").reject { |r| r =~ /^[^\w]/}.collect { |l| l.split(':')[0..1] }.find { |user, passwd| user == @resource[:name] }
- pass = ary[1]
- end
- pass
- end
-
- #Read in /etc/shadow, find the line for our used and rewrite it with the new pw
- #Smooth like 80 grit
- def password=(cryptopw)
- begin
- File.open("/etc/shadow", "r") do |shadow|
- File.open("/etc/shadow_tmp", "w", 0600) do |shadow_tmp|
- while line = shadow.gets
- line_arr = line.split(':')
- if line_arr[0] == @resource[:name]
- line_arr[1] = cryptopw
- line = line_arr.join(':')
- end
- shadow_tmp.print line
- end
- end
+ end
+ end
+ cmd
+ end
+
+ def user_attributes
+ @user_attributes ||= UserAttr.get_attributes_by_name(@resource[:name])
+ end
+
+ def flush
+ @user_attributes = nil
+ end
+
+ def command(cmd)
+ cmd = ("role_#{cmd}").intern if is_role? or (!exists? and @resource[:ensure] == :role)
+ super(cmd)
+ end
+
+ def is_role?
+ user_attributes and user_attributes[:type] == "role"
+ end
+
+ def run(cmd, msg)
+ execute(cmd)
+ rescue Puppet::ExecutionFailure => detail
+ raise Puppet::Error, "Could not #{msg} #{@resource.class.name} #{@resource.name}: #{detail}"
+ end
+
+ def transition(type)
+ cmd = [command(:modify)]
+ cmd << "-K" << "type=#{type}"
+ cmd += add_properties
+ cmd << @resource[:name]
+ end
+
+ def create
+ if is_role?
+ run(transition("normal"), "transition role to")
+ else
+ run(addcmd, "create")
+ end
+ # added to handle case when password is specified
+ self.password = @resource[:password] if @resource[:password]
+ end
+
+ def destroy
+ run(deletecmd, "delete "+ (is_role? ? "role" : "user"))
+ end
+
+ def create_role
+ if exists? and !is_role?
+ run(transition("role"), "transition user to")
+ else
+ run(addcmd, "create role")
+ end
+ end
+
+ def roles
+ user_attributes[:roles] if user_attributes
+ end
+
+ def auths
+ user_attributes[:auths] if user_attributes
+ end
+
+ def profiles
+ user_attributes[:profiles] if user_attributes
+ end
+
+ def project
+ user_attributes[:project] if user_attributes
+ end
+
+ def managed_attributes
+ [:name, :type, :roles, :auths, :profiles, :project]
+ end
+
+ def remove_managed_attributes
+ managed = managed_attributes
+ user_attributes.select { |k,v| !managed.include?(k) }.inject({}) { |hash, array| hash[array[0]] = array[1]; hash }
+ end
+
+ def keys
+ if user_attributes
+ #we have to get rid of all the keys we are managing another way
+ remove_managed_attributes
+ end
+ end
+
+ def build_keys_cmd(keys_hash)
+ cmd = []
+ keys_hash.each do |k,v|
+ cmd << "-K" << "#{k}=#{v}"
+ end
+ cmd
+ end
+
+ def keys=(keys_hash)
+ run([command(:modify)] + build_keys_cmd(keys_hash) << @resource[:name], "modify attribute key pairs")
+ end
+
+ #Read in /etc/shadow, find the line for this user (skipping comments, because who knows) and return the hashed pw (the second entry)
+ #No abstraction, all esoteric knowledge of file formats, yay
+ def password
+ #got perl?
+ if ary = File.readlines("/etc/shadow").reject { |r| r =~ /^[^\w]/}.collect { |l| l.split(':')[0..1] }.find { |user, passwd| user == @resource[:name] }
+ pass = ary[1]
+ end
+ pass
+ end
+
+ #Read in /etc/shadow, find the line for our used and rewrite it with the new pw
+ #Smooth like 80 grit
+ def password=(cryptopw)
+ begin
+ File.open("/etc/shadow", "r") do |shadow|
+ File.open("/etc/shadow_tmp", "w", 0600) do |shadow_tmp|
+ while line = shadow.gets
+ line_arr = line.split(':')
+ if line_arr[0] == @resource[:name]
+ line_arr[1] = cryptopw
+ line = line_arr.join(':')
end
- File.rename("/etc/shadow_tmp", "/etc/shadow")
- rescue => detail
- fail "Could not write temporary shadow file: #{detail}"
- ensure
- # Make sure this *always* gets deleted
- File.unlink("/etc/shadow_tmp") if File.exist?("/etc/shadow_tmp")
+ shadow_tmp.print line
+ end
end
- end
+ end
+ File.rename("/etc/shadow_tmp", "/etc/shadow")
+ rescue => detail
+ fail "Could not write temporary shadow file: #{detail}"
+ ensure
+ # Make sure this *always* gets deleted
+ File.unlink("/etc/shadow_tmp") if File.exist?("/etc/shadow_tmp")
+ end
+ end
end
diff --git a/lib/puppet/provider/user/useradd.rb b/lib/puppet/provider/user/useradd.rb
index 7645969ff..ec87694d7 100644
--- a/lib/puppet/provider/user/useradd.rb
+++ b/lib/puppet/provider/user/useradd.rb
@@ -1,69 +1,69 @@
require 'puppet/provider/nameservice/objectadd'
Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameService::ObjectAdd do
- desc "User management via ``useradd`` and its ilk. Note that you will need to install the ``Shadow Password`` Ruby library often known as ruby-libshadow to manage user passwords."
+ desc "User management via ``useradd`` and its ilk. Note that you will need to install the ``Shadow Password`` Ruby library often known as ruby-libshadow to manage user passwords."
- commands :add => "useradd", :delete => "userdel", :modify => "usermod"
+ commands :add => "useradd", :delete => "userdel", :modify => "usermod"
- options :home, :flag => "-d", :method => :dir
- options :comment, :method => :gecos
- options :groups, :flag => "-G"
+ options :home, :flag => "-d", :method => :dir
+ options :comment, :method => :gecos
+ options :groups, :flag => "-G"
- verify :gid, "GID must be an integer" do |value|
- value.is_a? Integer
- end
+ verify :gid, "GID must be an integer" do |value|
+ value.is_a? Integer
+ end
- verify :groups, "Groups must be comma-separated" do |value|
- value !~ /\s/
- end
+ verify :groups, "Groups must be comma-separated" do |value|
+ value !~ /\s/
+ end
- has_features :manages_homedir, :allows_duplicates
+ has_features :manages_homedir, :allows_duplicates
- has_feature :manages_passwords if Puppet.features.libshadow?
+ has_feature :manages_passwords if Puppet.features.libshadow?
- def check_allow_dup
- @resource.allowdupe? ? ["-o"] : []
- end
+ def check_allow_dup
+ @resource.allowdupe? ? ["-o"] : []
+ end
- def check_manage_home
- cmd = []
- if @resource.managehome?
- cmd << "-m"
- elsif %w{Fedora RedHat CentOS OEL OVS}.include?(Facter.value("operatingsystem"))
- cmd << "-M"
- end
- cmd
+ def check_manage_home
+ cmd = []
+ if @resource.managehome?
+ cmd << "-m"
+ elsif %w{Fedora RedHat CentOS OEL OVS}.include?(Facter.value("operatingsystem"))
+ cmd << "-M"
end
+ cmd
+ end
- def add_properties
- cmd = []
- Puppet::Type.type(:user).validproperties.each do |property|
- next if property == :ensure
- # the value needs to be quoted, mostly because -c might
- # have spaces in it
- if value = @resource.should(property) and value != ""
- cmd << flag(property) << value
- end
- end
- cmd
+ def add_properties
+ cmd = []
+ Puppet::Type.type(:user).validproperties.each do |property|
+ next if property == :ensure
+ # the value needs to be quoted, mostly because -c might
+ # have spaces in it
+ if value = @resource.should(property) and value != ""
+ cmd << flag(property) << value
+ end
end
+ cmd
+ end
- def addcmd
- cmd = [command(:add)]
- cmd += add_properties
- cmd += check_allow_dup
- cmd += check_manage_home
- cmd << @resource[:name]
- end
+ def addcmd
+ cmd = [command(:add)]
+ cmd += add_properties
+ cmd += check_allow_dup
+ cmd += check_manage_home
+ cmd << @resource[:name]
+ end
- # Retrieve the password using the Shadow Password library
- def password
- if Puppet.features.libshadow?
- if ent = Shadow::Passwd.getspnam(@resource.name)
- return ent.sp_pwdp
- end
- end
- :absent
+ # Retrieve the password using the Shadow Password library
+ def password
+ if Puppet.features.libshadow?
+ if ent = Shadow::Passwd.getspnam(@resource.name)
+ return ent.sp_pwdp
+ end
end
+ :absent
+ end
end
diff --git a/lib/puppet/provider/zfs/solaris.rb b/lib/puppet/provider/zfs/solaris.rb
index 418c902bd..85d054f86 100644
--- a/lib/puppet/provider/zfs/solaris.rb
+++ b/lib/puppet/provider/zfs/solaris.rb
@@ -1,45 +1,45 @@
Puppet::Type.type(:zfs).provide(:solaris) do
- desc "Provider for Solaris zfs."
-
- commands :zfs => "/usr/sbin/zfs"
- defaultfor :operatingsystem => :solaris
-
- def add_properties
- properties = []
- Puppet::Type.type(:zfs).validproperties.each do |property|
- next if property == :ensure
- if value = @resource[property] and value != ""
- properties << "-o" << "#{property}=#{value}"
- end
- end
- properties
+ desc "Provider for Solaris zfs."
+
+ commands :zfs => "/usr/sbin/zfs"
+ defaultfor :operatingsystem => :solaris
+
+ def add_properties
+ properties = []
+ Puppet::Type.type(:zfs).validproperties.each do |property|
+ next if property == :ensure
+ if value = @resource[property] and value != ""
+ properties << "-o" << "#{property}=#{value}"
+ end
end
-
- def create
- zfs *([:create] + add_properties + [@resource[:name]])
- end
-
- def destroy
- zfs(:destroy, @resource[:name])
+ properties
+ end
+
+ def create
+ zfs *([:create] + add_properties + [@resource[:name]])
+ end
+
+ def destroy
+ zfs(:destroy, @resource[:name])
+ end
+
+ def exists?
+ if zfs(:list).split("\n").detect { |line| line.split("\s")[0] == @resource[:name] }
+ true
+ else
+ false
end
+ end
- def exists?
- if zfs(:list).split("\n").detect { |line| line.split("\s")[0] == @resource[:name] }
- true
- else
- false
- end
+ [:mountpoint, :compression, :copies, :quota, :reservation, :sharenfs, :snapdir].each do |field|
+ define_method(field) do
+ zfs(:get, "-H", "-o", "value", field, @resource[:name]).strip
end
- [:mountpoint, :compression, :copies, :quota, :reservation, :sharenfs, :snapdir].each do |field|
- define_method(field) do
- zfs(:get, "-H", "-o", "value", field, @resource[:name]).strip
- end
-
- define_method(field.to_s + "=") do |should|
- zfs(:set, "#{field}=#{should}", @resource[:name])
- end
+ define_method(field.to_s + "=") do |should|
+ zfs(:set, "#{field}=#{should}", @resource[:name])
end
+ end
end
diff --git a/lib/puppet/provider/zone/solaris.rb b/lib/puppet/provider/zone/solaris.rb
index 33b1bc122..c11444993 100644
--- a/lib/puppet/provider/zone/solaris.rb
+++ b/lib/puppet/provider/zone/solaris.rb
@@ -1,257 +1,257 @@
Puppet::Type.type(:zone).provide(:solaris) do
- desc "Provider for Solaris Zones."
+ desc "Provider for Solaris Zones."
- commands :adm => "/usr/sbin/zoneadm", :cfg => "/usr/sbin/zonecfg"
- defaultfor :operatingsystem => :solaris
+ commands :adm => "/usr/sbin/zoneadm", :cfg => "/usr/sbin/zonecfg"
+ defaultfor :operatingsystem => :solaris
- mk_resource_methods
+ mk_resource_methods
- # Convert the output of a list into a hash
- def self.line2hash(line)
- fields = [:id, :name, :ensure, :path]
+ # Convert the output of a list into a hash
+ def self.line2hash(line)
+ fields = [:id, :name, :ensure, :path]
- properties = {}
- line.split(":").each_with_index { |value, index|
- next unless fields[index]
- properties[fields[index]] = value
- }
+ properties = {}
+ line.split(":").each_with_index { |value, index|
+ next unless fields[index]
+ properties[fields[index]] = value
+ }
- # Configured but not installed zones do not have IDs
- properties.delete(:id) if properties[:id] == "-"
+ # Configured but not installed zones do not have IDs
+ properties.delete(:id) if properties[:id] == "-"
- properties[:ensure] = symbolize(properties[:ensure])
+ properties[:ensure] = symbolize(properties[:ensure])
- properties
- end
+ properties
+ end
- def self.instances
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = adm(:list, "-cp").split("\n").collect do |line|
- new(line2hash(line))
- end
+ def self.instances
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = adm(:list, "-cp").split("\n").collect do |line|
+ new(line2hash(line))
end
-
- # Perform all of our configuration steps.
- def configure
- # If the thing is entirely absent, then we need to create the config.
- # Is there someway to get this on one line?
- str = "create -b #{@resource[:create_args]}\nset zonepath=#{@resource[:path]}\n"
-
- # Then perform all of our configuration steps. It's annoying
- # that we need this much internal info on the resource.
- @resource.send(:properties).each do |property|
- str += property.configtext + "\n" if property.is_a? ZoneConfigProperty and ! property.insync?(properties[property.name])
- end
-
- str += "commit\n"
- setconfig(str)
+ end
+
+ # Perform all of our configuration steps.
+ def configure
+ # If the thing is entirely absent, then we need to create the config.
+ # Is there someway to get this on one line?
+ str = "create -b #{@resource[:create_args]}\nset zonepath=#{@resource[:path]}\n"
+
+ # Then perform all of our configuration steps. It's annoying
+ # that we need this much internal info on the resource.
+ @resource.send(:properties).each do |property|
+ str += property.configtext + "\n" if property.is_a? ZoneConfigProperty and ! property.insync?(properties[property.name])
end
- def destroy
- zonecfg :delete, "-F"
+ str += "commit\n"
+ setconfig(str)
+ end
+
+ def destroy
+ zonecfg :delete, "-F"
+ end
+
+ def exists?
+ properties[:ensure] != :absent
+ end
+
+ # Clear out the cached values.
+ def flush
+ @property_hash.clear
+ end
+
+ def install(dummy_argument=:work_arround_for_ruby_GC_bug)
+ if @resource[:clone] # TODO: add support for "-s snapshot"
+ zoneadm :clone, @resource[:clone]
+ elsif @resource[:install_args]
+ zoneadm :install, @resource[:install_args].split(" ")
+ else
+ zoneadm :install
end
+ end
+
+ # Look up the current status.
+ def properties
+ if @property_hash.empty?
+ @property_hash = status || {}
+ if @property_hash.empty?
+ @property_hash[:ensure] = :absent
+ else
+ @resource.class.validproperties.each do |name|
+ @property_hash[name] ||= :absent
+ end
+ end
- def exists?
- properties[:ensure] != :absent
end
-
- # Clear out the cached values.
- def flush
- @property_hash.clear
+ @property_hash.dup
+ end
+
+ # We need a way to test whether a zone is in process. Our 'ensure'
+ # property models the static states, but we need to handle the temporary ones.
+ def processing?
+ if hash = status
+ case hash[:ensure]
+ when "incomplete", "ready", "shutting_down"
+ true
+ else
+ false
+ end
+ else
+ false
end
-
- def install(dummy_argument=:work_arround_for_ruby_GC_bug)
- if @resource[:clone] # TODO: add support for "-s snapshot"
- zoneadm :clone, @resource[:clone]
- elsif @resource[:install_args]
- zoneadm :install, @resource[:install_args].split(" ")
+ end
+
+ # Collect the configuration of the zone.
+ def getconfig
+ output = zonecfg :info
+
+ name = nil
+ current = nil
+ hash = {}
+ output.split("\n").each do |line|
+ case line
+ when /^(\S+):\s*$/
+ name = $1
+ current = nil # reset it
+ when /^(\S+):\s*(.+)$/
+ hash[$1.intern] = $2
+ when /^\s+(\S+):\s*(.+)$/
+ if name
+ hash[name] = [] unless hash.include? name
+
+ unless current
+ current = {}
+ hash[name] << current
+ end
+ current[$1.intern] = $2
else
- zoneadm :install
+ err "Ignoring '#{line}'"
end
+ else
+ debug "Ignoring zone output '#{line}'"
+ end
end
- # Look up the current status.
- def properties
- if @property_hash.empty?
- @property_hash = status || {}
- if @property_hash.empty?
- @property_hash[:ensure] = :absent
- else
- @resource.class.validproperties.each do |name|
- @property_hash[name] ||= :absent
- end
- end
+ hash
+ end
- end
- @property_hash.dup
+ # Execute a configuration string. Can't be private because it's called
+ # by the properties.
+ def setconfig(str)
+ command = "#{command(:cfg)} -z #{@resource[:name]} -f -"
+ debug "Executing '#{command}' in zone #{@resource[:name]} with '#{str}'"
+ IO.popen(command, "w") do |pipe|
+ pipe.puts str
end
- # We need a way to test whether a zone is in process. Our 'ensure'
- # property models the static states, but we need to handle the temporary ones.
- def processing?
- if hash = status
- case hash[:ensure]
- when "incomplete", "ready", "shutting_down"
- true
- else
- false
- end
- else
- false
- end
+ unless $CHILD_STATUS == 0
+ raise ArgumentError, "Failed to apply configuration"
end
+ end
- # Collect the configuration of the zone.
- def getconfig
- output = zonecfg :info
-
- name = nil
- current = nil
- hash = {}
- output.split("\n").each do |line|
- case line
- when /^(\S+):\s*$/
- name = $1
- current = nil # reset it
- when /^(\S+):\s*(.+)$/
- hash[$1.intern] = $2
- when /^\s+(\S+):\s*(.+)$/
- if name
- hash[name] = [] unless hash.include? name
-
- unless current
- current = {}
- hash[name] << current
- end
- current[$1.intern] = $2
- else
- err "Ignoring '#{line}'"
- end
- else
- debug "Ignoring zone output '#{line}'"
- end
- end
+ def start
+ # Check the sysidcfg stuff
+ if cfg = @resource[:sysidcfg]
+ zoneetc = File.join(@resource[:path], "root", "etc")
+ sysidcfg = File.join(zoneetc, "sysidcfg")
- hash
- end
+ # if the zone root isn't present "ready" the zone
+ # which makes zoneadmd mount the zone root
+ zoneadm :ready unless File.directory?(zoneetc)
- # Execute a configuration string. Can't be private because it's called
- # by the properties.
- def setconfig(str)
- command = "#{command(:cfg)} -z #{@resource[:name]} -f -"
- debug "Executing '#{command}' in zone #{@resource[:name]} with '#{str}'"
- IO.popen(command, "w") do |pipe|
- pipe.puts str
- end
-
- unless $CHILD_STATUS == 0
- raise ArgumentError, "Failed to apply configuration"
+ unless File.exists?(sysidcfg)
+ begin
+ File.open(sysidcfg, "w", 0600) do |f|
+ f.puts cfg
+ end
+ rescue => detail
+ puts detail.stacktrace if Puppet[:debug]
+ raise Puppet::Error, "Could not create sysidcfg: #{detail}"
end
+ end
end
- def start
- # Check the sysidcfg stuff
- if cfg = @resource[:sysidcfg]
- zoneetc = File.join(@resource[:path], "root", "etc")
- sysidcfg = File.join(zoneetc, "sysidcfg")
-
- # if the zone root isn't present "ready" the zone
- # which makes zoneadmd mount the zone root
- zoneadm :ready unless File.directory?(zoneetc)
-
- unless File.exists?(sysidcfg)
- begin
- File.open(sysidcfg, "w", 0600) do |f|
- f.puts cfg
- end
- rescue => detail
- puts detail.stacktrace if Puppet[:debug]
- raise Puppet::Error, "Could not create sysidcfg: #{detail}"
- end
- end
- end
+ zoneadm :boot
+ end
- zoneadm :boot
+ # Return a hash of the current status of this zone.
+ def status
+ begin
+ output = adm "-z", @resource[:name], :list, "-p"
+ rescue Puppet::ExecutionFailure
+ return nil
end
- # Return a hash of the current status of this zone.
- def status
- begin
- output = adm "-z", @resource[:name], :list, "-p"
- rescue Puppet::ExecutionFailure
- return nil
- end
-
- main = self.class.line2hash(output.chomp)
+ main = self.class.line2hash(output.chomp)
- # Now add in the configuration information
- config_status.each do |name, value|
- main[name] = value
- end
-
- main
+ # Now add in the configuration information
+ config_status.each do |name, value|
+ main[name] = value
end
- def ready
- zoneadm :ready
- end
+ main
+ end
- def stop
- zoneadm :halt
- end
+ def ready
+ zoneadm :ready
+ end
- def unconfigure
- zonecfg :delete, "-F"
- end
+ def stop
+ zoneadm :halt
+ end
- def uninstall
- zoneadm :uninstall, "-F"
- end
+ def unconfigure
+ zonecfg :delete, "-F"
+ end
- private
+ def uninstall
+ zoneadm :uninstall, "-F"
+ end
- # Turn the results of getconfig into status information.
- def config_status
- config = getconfig
- result = {}
+ private
- result[:autoboot] = config[:autoboot] ? config[:autoboot].intern : :absent
- result[:pool] = config[:pool]
- result[:shares] = config[:shares]
- if dir = config["inherit-pkg-dir"]
- result[:inherit] = dir.collect { |dirs| dirs[:dir] }
- end
- result[:iptype] = config[:"ip-type"]
- if net = config["net"]
- result[:ip] = net.collect do |params|
- if params[:defrouter]
- "#{params[:physical]}:#{params[:address]}:#{params[:defrouter]}"
- elsif params[:address]
- "#{params[:physical]}:#{params[:address]}"
- else
- params[:physical]
- end
- end
- end
+ # Turn the results of getconfig into status information.
+ def config_status
+ config = getconfig
+ result = {}
- result
+ result[:autoboot] = config[:autoboot] ? config[:autoboot].intern : :absent
+ result[:pool] = config[:pool]
+ result[:shares] = config[:shares]
+ if dir = config["inherit-pkg-dir"]
+ result[:inherit] = dir.collect { |dirs| dirs[:dir] }
end
-
- def zoneadm(*cmd)
- adm("-z", @resource[:name], *cmd)
- rescue Puppet::ExecutionFailure => detail
- self.fail "Could not #{cmd[0]} zone: #{detail}"
+ result[:iptype] = config[:"ip-type"]
+ if net = config["net"]
+ result[:ip] = net.collect do |params|
+ if params[:defrouter]
+ "#{params[:physical]}:#{params[:address]}:#{params[:defrouter]}"
+ elsif params[:address]
+ "#{params[:physical]}:#{params[:address]}"
+ else
+ params[:physical]
+ end
+ end
end
- def zonecfg(*cmd)
- # You apparently can't get the configuration of the global zone
- return "" if self.name == "global"
+ result
+ end
- begin
- cfg("-z", self.name, *cmd)
- rescue Puppet::ExecutionFailure => detail
- self.fail "Could not #{cmd[0]} zone: #{detail}"
- end
+ def zoneadm(*cmd)
+ adm("-z", @resource[:name], *cmd)
+ rescue Puppet::ExecutionFailure => detail
+ self.fail "Could not #{cmd[0]} zone: #{detail}"
+ end
+
+ def zonecfg(*cmd)
+ # You apparently can't get the configuration of the global zone
+ return "" if self.name == "global"
+
+ begin
+ cfg("-z", self.name, *cmd)
+ rescue Puppet::ExecutionFailure => detail
+ self.fail "Could not #{cmd[0]} zone: #{detail}"
end
+ end
end
diff --git a/lib/puppet/provider/zpool/solaris.rb b/lib/puppet/provider/zpool/solaris.rb
index bfd37085a..e597c2ae1 100644
--- a/lib/puppet/provider/zpool/solaris.rb
+++ b/lib/puppet/provider/zpool/solaris.rb
@@ -1,114 +1,114 @@
Puppet::Type.type(:zpool).provide(:solaris) do
- desc "Provider for Solaris zpool."
-
- commands :zpool => "/usr/sbin/zpool"
- defaultfor :operatingsystem => :solaris
-
- def process_zpool_data(pool_array)
- if pool_array == []
- return Hash.new(:absent)
- end
- #get the name and get rid of it
- pool = Hash.new
- pool[:pool] = pool_array[0]
- pool_array.shift
-
- tmp = []
-
- #order matters here :(
- pool_array.reverse.each do |value|
- sym = nil
- case value
- when "spares"; sym = :spare
- when "logs"; sym = :log
- when "mirror", "raidz1", "raidz2"
- sym = value == "mirror" ? :mirror : :raidz
- pool[:raid_parity] = "raidz2" if value == "raidz2"
- else
- tmp << value
- sym = :disk if value == pool_array.first
- end
-
- if sym
- pool[sym] = pool[sym] ? pool[sym].unshift(tmp.reverse.join(' ')) : [tmp.reverse.join(' ')]
- tmp.clear
- end
- end
-
- pool
- end
+ desc "Provider for Solaris zpool."
- def get_pool_data
- #this is all voodoo dependent on the output from zpool
- zpool_data = %x{ zpool status #{@resource[:pool]}}.split("\n").select { |line| line.index("\t") == 0 }.collect { |l| l.strip.split("\s")[0] }
- zpool_data.shift
- zpool_data
- end
+ commands :zpool => "/usr/sbin/zpool"
+ defaultfor :operatingsystem => :solaris
- def current_pool
- @current_pool = process_zpool_data(get_pool_data) unless (defined?(@current_pool) and @current_pool)
- @current_pool
+ def process_zpool_data(pool_array)
+ if pool_array == []
+ return Hash.new(:absent)
end
-
- def flush
- @current_pool= nil
+ #get the name and get rid of it
+ pool = Hash.new
+ pool[:pool] = pool_array[0]
+ pool_array.shift
+
+ tmp = []
+
+ #order matters here :(
+ pool_array.reverse.each do |value|
+ sym = nil
+ case value
+ when "spares"; sym = :spare
+ when "logs"; sym = :log
+ when "mirror", "raidz1", "raidz2"
+ sym = value == "mirror" ? :mirror : :raidz
+ pool[:raid_parity] = "raidz2" if value == "raidz2"
+ else
+ tmp << value
+ sym = :disk if value == pool_array.first
+ end
+
+ if sym
+ pool[sym] = pool[sym] ? pool[sym].unshift(tmp.reverse.join(' ')) : [tmp.reverse.join(' ')]
+ tmp.clear
+ end
end
- #Adds log and spare
- def build_named(name)
- if prop = @resource[name.intern]
- [name] + prop.collect { |p| p.split(' ') }.flatten
- else
- []
- end
+ pool
+ end
+
+ def get_pool_data
+ #this is all voodoo dependent on the output from zpool
+ zpool_data = %x{ zpool status #{@resource[:pool]}}.split("\n").select { |line| line.index("\t") == 0 }.collect { |l| l.strip.split("\s")[0] }
+ zpool_data.shift
+ zpool_data
+ end
+
+ def current_pool
+ @current_pool = process_zpool_data(get_pool_data) unless (defined?(@current_pool) and @current_pool)
+ @current_pool
+ end
+
+ def flush
+ @current_pool= nil
+ end
+
+ #Adds log and spare
+ def build_named(name)
+ if prop = @resource[name.intern]
+ [name] + prop.collect { |p| p.split(' ') }.flatten
+ else
+ []
end
-
- #query for parity and set the right string
- def raidzarity
- @resource[:raid_parity] ? @resource[:raid_parity] : "raidz1"
+ end
+
+ #query for parity and set the right string
+ def raidzarity
+ @resource[:raid_parity] ? @resource[:raid_parity] : "raidz1"
+ end
+
+ #handle mirror or raid
+ def handle_multi_arrays(prefix, array)
+ array.collect{ |a| [prefix] + a.split(' ') }.flatten
+ end
+
+ #builds up the vdevs for create command
+ def build_vdevs
+ if disk = @resource[:disk]
+ disk.collect { |d| d.split(' ') }.flatten
+ elsif mirror = @resource[:mirror]
+ handle_multi_arrays("mirror", mirror)
+ elsif raidz = @resource[:raidz]
+ handle_multi_arrays(raidzarity, raidz)
end
+ end
- #handle mirror or raid
- def handle_multi_arrays(prefix, array)
- array.collect{ |a| [prefix] + a.split(' ') }.flatten
- end
+ def create
+ zpool(*([:create, @resource[:pool]] + build_vdevs + build_named("spare") + build_named("log")))
+ end
- #builds up the vdevs for create command
- def build_vdevs
- if disk = @resource[:disk]
- disk.collect { |d| d.split(' ') }.flatten
- elsif mirror = @resource[:mirror]
- handle_multi_arrays("mirror", mirror)
- elsif raidz = @resource[:raidz]
- handle_multi_arrays(raidzarity, raidz)
- end
- end
-
- def create
- zpool(*([:create, @resource[:pool]] + build_vdevs + build_named("spare") + build_named("log")))
- end
+ def delete
+ zpool :destroy, @resource[:pool]
+ end
- def delete
- zpool :destroy, @resource[:pool]
+ def exists?
+ if current_pool[:pool] == :absent
+ false
+ else
+ true
end
+ end
- def exists?
- if current_pool[:pool] == :absent
- false
- else
- true
- end
+ [:disk, :mirror, :raidz, :log, :spare].each do |field|
+ define_method(field) do
+ current_pool[field]
end
- [:disk, :mirror, :raidz, :log, :spare].each do |field|
- define_method(field) do
- current_pool[field]
- end
-
- define_method(field.to_s + "=") do |should|
- Puppet.warning "NO CHANGES BEING MADE: zpool #{field} does not match, should be '#{should}' currently is '#{current_pool[field]}'"
- end
+ define_method(field.to_s + "=") do |should|
+ Puppet.warning "NO CHANGES BEING MADE: zpool #{field} does not match, should be '#{should}' currently is '#{current_pool[field]}'"
end
+ end
end
diff --git a/lib/puppet/rails.rb b/lib/puppet/rails.rb
index f1d97bf4f..414b1bc18 100644
--- a/lib/puppet/rails.rb
+++ b/lib/puppet/rails.rb
@@ -4,132 +4,132 @@ require 'facter'
require 'puppet'
module Puppet::Rails
- TIME_DEBUG = true
-
- def self.connect
- # This global init does not work for testing, because we remove
- # the state dir on every test.
- return if ActiveRecord::Base.connected?
-
- Puppet.settings.use(:main, :rails, :master)
-
- ActiveRecord::Base.logger = Logger.new(Puppet[:railslog])
- begin
- loglevel = Logger.const_get(Puppet[:rails_loglevel].upcase)
- ActiveRecord::Base.logger.level = loglevel
- rescue => detail
- Puppet.warning "'#{Puppet[:rails_loglevel]}' is not a valid Rails log level; using debug"
- ActiveRecord::Base.logger.level = Logger::DEBUG
- end
-
- if (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR <= 1)
- ActiveRecord::Base.allow_concurrency = true
- end
-
- ActiveRecord::Base.verify_active_connections!
-
- begin
- args = database_arguments
- Puppet.info "Connecting to #{args[:adapter]} database: #{args[:database]}"
- ActiveRecord::Base.establish_connection(args)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not connect to database: #{detail}"
- end
+ TIME_DEBUG = true
+
+ def self.connect
+ # This global init does not work for testing, because we remove
+ # the state dir on every test.
+ return if ActiveRecord::Base.connected?
+
+ Puppet.settings.use(:main, :rails, :master)
+
+ ActiveRecord::Base.logger = Logger.new(Puppet[:railslog])
+ begin
+ loglevel = Logger.const_get(Puppet[:rails_loglevel].upcase)
+ ActiveRecord::Base.logger.level = loglevel
+ rescue => detail
+ Puppet.warning "'#{Puppet[:rails_loglevel]}' is not a valid Rails log level; using debug"
+ ActiveRecord::Base.logger.level = Logger::DEBUG
end
- # The arguments for initializing the database connection.
- def self.database_arguments
- adapter = Puppet[:dbadapter]
-
- args = {:adapter => adapter, :log_level => Puppet[:rails_loglevel]}
-
- case adapter
- when "sqlite3"
- args[:database] = Puppet[:dblocation]
- when "mysql", "postgresql"
- args[:host] = Puppet[:dbserver] unless Puppet[:dbserver].to_s.empty?
- args[:port] = Puppet[:dbport] unless Puppet[:dbport].to_s.empty?
- args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty?
- args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty?
- args[:database] = Puppet[:dbname]
- args[:reconnect]= true
-
- socket = Puppet[:dbsocket]
- args[:socket] = socket unless socket.to_s.empty?
-
- connections = Puppet[:dbconnections].to_i
- args[:pool] = connections if connections > 0
- when "oracle_enhanced":
- args[:database] = Puppet[:dbname] unless Puppet[:dbname].to_s.empty?
- args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty?
- args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty?
-
- connections = Puppet[:dbconnections].to_i
- args[:pool] = connections if connections > 0
- else
- raise ArgumentError, "Invalid db adapter #{adapter}"
- end
- args
+ if (::ActiveRecord::VERSION::MAJOR == 2 and ::ActiveRecord::VERSION::MINOR <= 1)
+ ActiveRecord::Base.allow_concurrency = true
end
- # Set up our database connection. It'd be nice to have a "use" system
- # that could make callbacks.
- def self.init
- raise Puppet::DevError, "No activerecord, cannot init Puppet::Rails" unless Puppet.features.rails?
+ ActiveRecord::Base.verify_active_connections!
- connect
+ begin
+ args = database_arguments
+ Puppet.info "Connecting to #{args[:adapter]} database: #{args[:database]}"
+ ActiveRecord::Base.establish_connection(args)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Could not connect to database: #{detail}"
+ end
+ end
+
+ # The arguments for initializing the database connection.
+ def self.database_arguments
+ adapter = Puppet[:dbadapter]
+
+ args = {:adapter => adapter, :log_level => Puppet[:rails_loglevel]}
+
+ case adapter
+ when "sqlite3"
+ args[:database] = Puppet[:dblocation]
+ when "mysql", "postgresql"
+ args[:host] = Puppet[:dbserver] unless Puppet[:dbserver].to_s.empty?
+ args[:port] = Puppet[:dbport] unless Puppet[:dbport].to_s.empty?
+ args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty?
+ args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty?
+ args[:database] = Puppet[:dbname]
+ args[:reconnect]= true
+
+ socket = Puppet[:dbsocket]
+ args[:socket] = socket unless socket.to_s.empty?
+
+ connections = Puppet[:dbconnections].to_i
+ args[:pool] = connections if connections > 0
+ when "oracle_enhanced":
+ args[:database] = Puppet[:dbname] unless Puppet[:dbname].to_s.empty?
+ args[:username] = Puppet[:dbuser] unless Puppet[:dbuser].to_s.empty?
+ args[:password] = Puppet[:dbpassword] unless Puppet[:dbpassword].to_s.empty?
+
+ connections = Puppet[:dbconnections].to_i
+ args[:pool] = connections if connections > 0
+ else
+ raise ArgumentError, "Invalid db adapter #{adapter}"
+ end
+ args
+ end
+
+ # Set up our database connection. It'd be nice to have a "use" system
+ # that could make callbacks.
+ def self.init
+ raise Puppet::DevError, "No activerecord, cannot init Puppet::Rails" unless Puppet.features.rails?
- unless ActiveRecord::Base.connection.tables.include?("resources")
- require 'puppet/rails/database/schema'
- Puppet::Rails::Schema.init
- end
+ connect
- migrate if Puppet[:dbmigrate]
+ unless ActiveRecord::Base.connection.tables.include?("resources")
+ require 'puppet/rails/database/schema'
+ Puppet::Rails::Schema.init
end
- # Migrate to the latest db schema.
- def self.migrate
- dbdir = nil
- $LOAD_PATH.each { |d|
- tmp = File.join(d, "puppet/rails/database")
- if FileTest.directory?(tmp)
- dbdir = tmp
- break
- end
- }
-
- raise Puppet::Error, "Could not find Puppet::Rails database dir" unless dbdir
-
- raise Puppet::Error, "Database has problems, can't migrate." unless ActiveRecord::Base.connection.tables.include?("resources")
-
- Puppet.notice "Migrating"
-
- begin
- ActiveRecord::Migrator.migrate(dbdir)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not migrate database: #{detail}"
- end
+ migrate if Puppet[:dbmigrate]
+ end
+
+ # Migrate to the latest db schema.
+ def self.migrate
+ dbdir = nil
+ $LOAD_PATH.each { |d|
+ tmp = File.join(d, "puppet/rails/database")
+ if FileTest.directory?(tmp)
+ dbdir = tmp
+ break
+ end
+ }
+
+ raise Puppet::Error, "Could not find Puppet::Rails database dir" unless dbdir
+
+ raise Puppet::Error, "Database has problems, can't migrate." unless ActiveRecord::Base.connection.tables.include?("resources")
+
+ Puppet.notice "Migrating"
+
+ begin
+ ActiveRecord::Migrator.migrate(dbdir)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Could not migrate database: #{detail}"
end
+ end
- # Tear down the database. Mostly only used during testing.
- def self.teardown
- raise Puppet::DevError, "No activerecord, cannot init Puppet::Rails" unless Puppet.features.rails?
+ # Tear down the database. Mostly only used during testing.
+ def self.teardown
+ raise Puppet::DevError, "No activerecord, cannot init Puppet::Rails" unless Puppet.features.rails?
- Puppet.settings.use(:master, :rails)
+ Puppet.settings.use(:master, :rails)
- begin
- ActiveRecord::Base.establish_connection(database_arguments)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not connect to database: #{detail}"
- end
+ begin
+ ActiveRecord::Base.establish_connection(database_arguments)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Could not connect to database: #{detail}"
+ end
- ActiveRecord::Base.connection.tables.each do |t|
- ActiveRecord::Base.connection.drop_table t
- end
+ ActiveRecord::Base.connection.tables.each do |t|
+ ActiveRecord::Base.connection.drop_table t
end
+ end
end
require 'puppet/rails/host' if Puppet.features.rails?
diff --git a/lib/puppet/rails/benchmark.rb b/lib/puppet/rails/benchmark.rb
index 35e6fdcef..375674e19 100644
--- a/lib/puppet/rails/benchmark.rb
+++ b/lib/puppet/rails/benchmark.rb
@@ -1,63 +1,63 @@
require 'benchmark'
module Puppet::Rails::Benchmark
- $benchmarks = {:accumulated => {}}
+ $benchmarks = {:accumulated => {}}
- def time_debug?
- Puppet::Rails::TIME_DEBUG
- end
+ def time_debug?
+ Puppet::Rails::TIME_DEBUG
+ end
- def railsmark(message)
- result = nil
- seconds = Benchmark.realtime { result = yield }
- Puppet.debug(message + " in %0.2f seconds" % seconds)
+ def railsmark(message)
+ result = nil
+ seconds = Benchmark.realtime { result = yield }
+ Puppet.debug(message + " in %0.2f seconds" % seconds)
- $benchmarks[message] = seconds if time_debug?
- result
- end
+ $benchmarks[message] = seconds if time_debug?
+ result
+ end
- def debug_benchmark(message)
- return yield unless Puppet::Rails::TIME_DEBUG
+ def debug_benchmark(message)
+ return yield unless Puppet::Rails::TIME_DEBUG
- railsmark(message) { yield }
- end
+ railsmark(message) { yield }
+ end
- # Collect partial benchmarks to be logged when they're
- # all done.
- # These are always low-level debugging so we only
- # print them if time_debug is enabled.
- def accumulate_benchmark(message, label)
- return yield unless time_debug?
+ # Collect partial benchmarks to be logged when they're
+ # all done.
+ # These are always low-level debugging so we only
+ # print them if time_debug is enabled.
+ def accumulate_benchmark(message, label)
+ return yield unless time_debug?
- $benchmarks[:accumulated][message] ||= Hash.new(0)
- $benchmarks[:accumulated][message][label] += Benchmark.realtime { yield }
- end
+ $benchmarks[:accumulated][message] ||= Hash.new(0)
+ $benchmarks[:accumulated][message][label] += Benchmark.realtime { yield }
+ end
- # Log the accumulated marks.
- def log_accumulated_marks(message)
- return unless time_debug?
+ # Log the accumulated marks.
+ def log_accumulated_marks(message)
+ return unless time_debug?
- return if $benchmarks[:accumulated].empty? or $benchmarks[:accumulated][message].nil? or $benchmarks[:accumulated][message].empty?
+ return if $benchmarks[:accumulated].empty? or $benchmarks[:accumulated][message].nil? or $benchmarks[:accumulated][message].empty?
- $benchmarks[:accumulated][message].each do |label, value|
- Puppet.debug(message + ("(#{label})") + (" in %0.2f seconds" % value))
- end
+ $benchmarks[:accumulated][message].each do |label, value|
+ Puppet.debug(message + ("(#{label})") + (" in %0.2f seconds" % value))
end
+ end
- def write_benchmarks
- return unless time_debug?
+ def write_benchmarks
+ return unless time_debug?
- branch = %x{git branch}.split("\n").find { |l| l =~ /^\*/ }.sub("* ", '')
+ branch = %x{git branch}.split("\n").find { |l| l =~ /^\*/ }.sub("* ", '')
- file = "/tmp/time_debugging.yaml"
+ file = "/tmp/time_debugging.yaml"
- require 'yaml'
+ require 'yaml'
- if FileTest.exist?(file)
- data = YAML.load_file(file)
- else
- data = {}
- end
- data[branch] = $benchmarks
- Puppet::Util.secure_open(file, "w") { |f| f.print YAML.dump(data) }
+ if FileTest.exist?(file)
+ data = YAML.load_file(file)
+ else
+ data = {}
end
+ data[branch] = $benchmarks
+ Puppet::Util.secure_open(file, "w") { |f| f.print YAML.dump(data) }
+ end
end
diff --git a/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb b/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb
index 65432a6b7..22dffb854 100644
--- a/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb
+++ b/lib/puppet/rails/database/001_add_created_at_to_all_tables.rb
@@ -1,13 +1,13 @@
class AddCreatedAtToAllTables < ActiveRecord::Migration
- def self.up
- ActiveRecord::Base.connection.tables.each do |t|
- add_column t.to_s, :created_at, :datetime unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at")
- end
+ def self.up
+ ActiveRecord::Base.connection.tables.each do |t|
+ add_column t.to_s, :created_at, :datetime unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at")
end
+ end
- def self.down
- ActiveRecord::Base.connection.tables.each do |t|
- remove_column t.to_s, :created_at unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at")
- end
+ def self.down
+ ActiveRecord::Base.connection.tables.each do |t|
+ remove_column t.to_s, :created_at unless ActiveRecord::Base.connection.columns(t).collect {|c| c.name}.include?("created_at")
end
+ end
end
diff --git a/lib/puppet/rails/database/002_remove_duplicated_index_on_all_tables.rb b/lib/puppet/rails/database/002_remove_duplicated_index_on_all_tables.rb
index c1e60db14..021889df7 100644
--- a/lib/puppet/rails/database/002_remove_duplicated_index_on_all_tables.rb
+++ b/lib/puppet/rails/database/002_remove_duplicated_index_on_all_tables.rb
@@ -1,13 +1,13 @@
class RemoveDuplicatedIndexOnAllTables < ActiveRecord::Migration
- def self.up
- ActiveRecord::Base.connection.tables.each do |t|
- remove_index t.to_s, :id if ActiveRecord::Base.connection.indexes(t).collect {|c| c.columns}.include?("id")
- end
+ def self.up
+ ActiveRecord::Base.connection.tables.each do |t|
+ remove_index t.to_s, :id if ActiveRecord::Base.connection.indexes(t).collect {|c| c.columns}.include?("id")
end
+ end
- def self.down
- ActiveRecord::Base.connection.tables.each do |t|
- add_index t.to_s, :id, :integer => true unless ActiveRecord::Base.connection.indexes(t).collect {|c| c.columns}.include?("id")
- end
+ def self.down
+ ActiveRecord::Base.connection.tables.each do |t|
+ add_index t.to_s, :id, :integer => true unless ActiveRecord::Base.connection.indexes(t).collect {|c| c.columns}.include?("id")
end
+ end
end
diff --git a/lib/puppet/rails/database/003_add_environment_to_host.rb b/lib/puppet/rails/database/003_add_environment_to_host.rb
index 95f036d11..5c06bb8c0 100644
--- a/lib/puppet/rails/database/003_add_environment_to_host.rb
+++ b/lib/puppet/rails/database/003_add_environment_to_host.rb
@@ -1,9 +1,9 @@
class AddEnvironmentToHost < ActiveRecord::Migration
- def self.up
- add_column :hosts, :environment, :string unless ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment")
- end
+ def self.up
+ add_column :hosts, :environment, :string unless ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment")
+ end
- def self.down
- remove_column :hosts, :environment if ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment")
- end
+ def self.down
+ remove_column :hosts, :environment if ActiveRecord::Base.connection.columns(:hosts).collect {|c| c.name}.include?("environment")
+ end
end
diff --git a/lib/puppet/rails/database/schema.rb b/lib/puppet/rails/database/schema.rb
index 8cb7350eb..8b389d773 100644
--- a/lib/puppet/rails/database/schema.rb
+++ b/lib/puppet/rails/database/schema.rb
@@ -1,114 +1,114 @@
class Puppet::Rails::Schema
- def self.init
- oldout = nil
- Puppet::Util.benchmark(Puppet, :notice, "Initialized database") do
- # We want to rewrite stdout, so we don't get migration messages.
- oldout = $stdout
- $stdout = File.open("/dev/null", "w")
- ActiveRecord::Schema.define do
- create_table :resources do |t|
- t.column :title, :text, :null => false
- t.column :restype, :string, :null => false
- t.column :host_id, :integer
- t.column :source_file_id, :integer
- t.column :exported, :boolean
- t.column :line, :integer
- t.column :updated_at, :datetime
- t.column :created_at, :datetime
- end
- add_index :resources, :host_id, :integer => true
- add_index :resources, :source_file_id, :integer => true
+ def self.init
+ oldout = nil
+ Puppet::Util.benchmark(Puppet, :notice, "Initialized database") do
+ # We want to rewrite stdout, so we don't get migration messages.
+ oldout = $stdout
+ $stdout = File.open("/dev/null", "w")
+ ActiveRecord::Schema.define do
+ create_table :resources do |t|
+ t.column :title, :text, :null => false
+ t.column :restype, :string, :null => false
+ t.column :host_id, :integer
+ t.column :source_file_id, :integer
+ t.column :exported, :boolean
+ t.column :line, :integer
+ t.column :updated_at, :datetime
+ t.column :created_at, :datetime
+ end
+ add_index :resources, :host_id, :integer => true
+ add_index :resources, :source_file_id, :integer => true
- # Thanks, mysql! MySQL requires a length on indexes in text fields.
- # So, we provide them for mysql and handle everything else specially.
- # Oracle doesn't index on CLOB fields, so we skip it
- if Puppet[:dbadapter] == "mysql"
- execute "CREATE INDEX typentitle ON resources (restype,title(50));"
- elsif Puppet[:dbadapter] != "oracle_enhanced"
- add_index :resources, [:title, :restype]
- end
+ # Thanks, mysql! MySQL requires a length on indexes in text fields.
+ # So, we provide them for mysql and handle everything else specially.
+ # Oracle doesn't index on CLOB fields, so we skip it
+ if Puppet[:dbadapter] == "mysql"
+ execute "CREATE INDEX typentitle ON resources (restype,title(50));"
+ elsif Puppet[:dbadapter] != "oracle_enhanced"
+ add_index :resources, [:title, :restype]
+ end
- create_table :source_files do |t|
- t.column :filename, :string
- t.column :path, :string
- t.column :updated_at, :datetime
- t.column :created_at, :datetime
- end
- add_index :source_files, :filename
+ create_table :source_files do |t|
+ t.column :filename, :string
+ t.column :path, :string
+ t.column :updated_at, :datetime
+ t.column :created_at, :datetime
+ end
+ add_index :source_files, :filename
- create_table :resource_tags do |t|
- t.column :resource_id, :integer
- t.column :puppet_tag_id, :integer
- t.column :updated_at, :datetime
- t.column :created_at, :datetime
- end
- add_index :resource_tags, :resource_id, :integer => true
- add_index :resource_tags, :puppet_tag_id, :integer => true
+ create_table :resource_tags do |t|
+ t.column :resource_id, :integer
+ t.column :puppet_tag_id, :integer
+ t.column :updated_at, :datetime
+ t.column :created_at, :datetime
+ end
+ add_index :resource_tags, :resource_id, :integer => true
+ add_index :resource_tags, :puppet_tag_id, :integer => true
- create_table :puppet_tags do |t|
- t.column :name, :string
- t.column :updated_at, :datetime
- t.column :created_at, :datetime
- end
+ create_table :puppet_tags do |t|
+ t.column :name, :string
+ t.column :updated_at, :datetime
+ t.column :created_at, :datetime
+ end
- # Oracle automatically creates a primary key index
- add_index :puppet_tags, :id, :integer => true if Puppet[:dbadapter] != "oracle_enhanced"
+ # Oracle automatically creates a primary key index
+ add_index :puppet_tags, :id, :integer => true if Puppet[:dbadapter] != "oracle_enhanced"
- create_table :hosts do |t|
- t.column :name, :string, :null => false
- t.column :ip, :string
- t.column :environment, :text
- t.column :last_compile, :datetime
- t.column :last_freshcheck, :datetime
- t.column :last_report, :datetime
- #Use updated_at to automatically add timestamp on save.
- t.column :updated_at, :datetime
- t.column :source_file_id, :integer
- t.column :created_at, :datetime
- end
- add_index :hosts, :source_file_id, :integer => true
- add_index :hosts, :name
+ create_table :hosts do |t|
+ t.column :name, :string, :null => false
+ t.column :ip, :string
+ t.column :environment, :text
+ t.column :last_compile, :datetime
+ t.column :last_freshcheck, :datetime
+ t.column :last_report, :datetime
+ #Use updated_at to automatically add timestamp on save.
+ t.column :updated_at, :datetime
+ t.column :source_file_id, :integer
+ t.column :created_at, :datetime
+ end
+ add_index :hosts, :source_file_id, :integer => true
+ add_index :hosts, :name
- create_table :fact_names do |t|
- t.column :name, :string, :null => false
- t.column :updated_at, :datetime
- t.column :created_at, :datetime
- end
- add_index :fact_names, :name
+ create_table :fact_names do |t|
+ t.column :name, :string, :null => false
+ t.column :updated_at, :datetime
+ t.column :created_at, :datetime
+ end
+ add_index :fact_names, :name
- create_table :fact_values do |t|
- t.column :value, :text, :null => false
- t.column :fact_name_id, :integer, :null => false
- t.column :host_id, :integer, :null => false
- t.column :updated_at, :datetime
- t.column :created_at, :datetime
- end
- add_index :fact_values, :fact_name_id, :integer => true
- add_index :fact_values, :host_id, :integer => true
+ create_table :fact_values do |t|
+ t.column :value, :text, :null => false
+ t.column :fact_name_id, :integer, :null => false
+ t.column :host_id, :integer, :null => false
+ t.column :updated_at, :datetime
+ t.column :created_at, :datetime
+ end
+ add_index :fact_values, :fact_name_id, :integer => true
+ add_index :fact_values, :host_id, :integer => true
- create_table :param_values do |t|
- t.column :value, :text, :null => false
- t.column :param_name_id, :integer, :null => false
- t.column :line, :integer
- t.column :resource_id, :integer
- t.column :updated_at, :datetime
- t.column :created_at, :datetime
- end
- add_index :param_values, :param_name_id, :integer => true
- add_index :param_values, :resource_id, :integer => true
+ create_table :param_values do |t|
+ t.column :value, :text, :null => false
+ t.column :param_name_id, :integer, :null => false
+ t.column :line, :integer
+ t.column :resource_id, :integer
+ t.column :updated_at, :datetime
+ t.column :created_at, :datetime
+ end
+ add_index :param_values, :param_name_id, :integer => true
+ add_index :param_values, :resource_id, :integer => true
- create_table :param_names do |t|
- t.column :name, :string, :null => false
- t.column :updated_at, :datetime
- t.column :created_at, :datetime
- end
- add_index :param_names, :name
- end
+ create_table :param_names do |t|
+ t.column :name, :string, :null => false
+ t.column :updated_at, :datetime
+ t.column :created_at, :datetime
end
- ensure
- $stdout.close
- $stdout = oldout if oldout
- oldout = nil
+ add_index :param_names, :name
+ end
end
+ ensure
+ $stdout.close
+ $stdout = oldout if oldout
+ oldout = nil
+ end
end
diff --git a/lib/puppet/rails/fact_name.rb b/lib/puppet/rails/fact_name.rb
index e6e7c5d03..fb40ec48f 100644
--- a/lib/puppet/rails/fact_name.rb
+++ b/lib/puppet/rails/fact_name.rb
@@ -1,7 +1,7 @@
require 'puppet/rails/fact_value'
class Puppet::Rails::FactName < ActiveRecord::Base
- has_many :fact_values, :dependent => :destroy
+ has_many :fact_values, :dependent => :destroy
end
# $Id: fact_name.rb 1952 2006-12-19 05:47:57Z luke $
diff --git a/lib/puppet/rails/fact_value.rb b/lib/puppet/rails/fact_value.rb
index a451cbb88..45a88b2dc 100644
--- a/lib/puppet/rails/fact_value.rb
+++ b/lib/puppet/rails/fact_value.rb
@@ -1,10 +1,10 @@
class Puppet::Rails::FactValue < ActiveRecord::Base
- belongs_to :fact_name
- belongs_to :host
+ belongs_to :fact_name
+ belongs_to :host
- def to_label
- "#{self.fact_name.name}"
- end
+ def to_label
+ "#{self.fact_name.name}"
+ end
end
# $Id: fact_value.rb 1952 2006-12-19 05:47:57Z luke $
diff --git a/lib/puppet/rails/host.rb b/lib/puppet/rails/host.rb
index 510790235..6c008bccf 100644
--- a/lib/puppet/rails/host.rb
+++ b/lib/puppet/rails/host.rb
@@ -5,318 +5,318 @@ require 'puppet/rails/benchmark'
require 'puppet/util/rails/collection_merger'
class Puppet::Rails::Host < ActiveRecord::Base
- include Puppet::Rails::Benchmark
- extend Puppet::Rails::Benchmark
- include Puppet::Util
- include Puppet::Util::CollectionMerger
-
- has_many :fact_values, :dependent => :destroy, :class_name => "Puppet::Rails::FactValue"
- has_many :fact_names, :through => :fact_values, :class_name => "Puppet::Rails::FactName"
- belongs_to :source_file
- has_many :resources, :dependent => :destroy, :class_name => "Puppet::Rails::Resource"
-
- # If the host already exists, get rid of its objects
- def self.clean(host)
- if obj = self.find_by_name(host)
- obj.rails_objects.clear
- return obj
- else
- return nil
- end
+ include Puppet::Rails::Benchmark
+ extend Puppet::Rails::Benchmark
+ include Puppet::Util
+ include Puppet::Util::CollectionMerger
+
+ has_many :fact_values, :dependent => :destroy, :class_name => "Puppet::Rails::FactValue"
+ has_many :fact_names, :through => :fact_values, :class_name => "Puppet::Rails::FactName"
+ belongs_to :source_file
+ has_many :resources, :dependent => :destroy, :class_name => "Puppet::Rails::Resource"
+
+ # If the host already exists, get rid of its objects
+ def self.clean(host)
+ if obj = self.find_by_name(host)
+ obj.rails_objects.clear
+ return obj
+ else
+ return nil
end
+ end
- def self.from_puppet(node)
- host = find_by_name(node.name) || new(:name => node.name)
-
- {"ipaddress" => "ip", "environment" => "environment"}.each do |myparam, itsparam|
- if value = node.send(myparam)
- host.send(itsparam + "=", value)
- end
- end
+ def self.from_puppet(node)
+ host = find_by_name(node.name) || new(:name => node.name)
- host
+ {"ipaddress" => "ip", "environment" => "environment"}.each do |myparam, itsparam|
+ if value = node.send(myparam)
+ host.send(itsparam + "=", value)
+ end
end
- # Store our host in the database.
- def self.store(node, resources)
- args = {}
-
- host = nil
- railsmark "Stored node" do
- transaction do
- #unless host = find_by_name(name)
-
- debug_benchmark("Searched for host")do
- unless host = find_by_name(node.name)
- host = new(:name => node.name)
- end
- end
- if ip = node.parameters["ipaddress"]
- host.ip = ip
- end
-
- if env = node.environment
- host.environment = env
- end
-
- # Store the facts into the database.
- host.merge_facts(node.parameters)
+ host
+ end
- debug_benchmark("Handled resources") {
- host.merge_resources(resources)
- }
+ # Store our host in the database.
+ def self.store(node, resources)
+ args = {}
- host.last_compile = Time.now
-
- debug_benchmark("Saved host") {
- host.save
- }
- end
+ host = nil
+ railsmark "Stored node" do
+ transaction do
+ #unless host = find_by_name(name)
+ debug_benchmark("Searched for host")do
+ unless host = find_by_name(node.name)
+ host = new(:name => node.name)
+ end
+ end
+ if ip = node.parameters["ipaddress"]
+ host.ip = ip
end
- # This only runs if time debugging is enabled.
- write_benchmarks
+ if env = node.environment
+ host.environment = env
+ end
- host
- end
+ # Store the facts into the database.
+ host.merge_facts(node.parameters)
- # Return the value of a fact.
- def fact(name)
+ debug_benchmark("Handled resources") {
+ host.merge_resources(resources)
+ }
- if fv = self.fact_values.find(
- :all, :include => :fact_name,
+ host.last_compile = Time.now
- :conditions => "fact_names.name = '#{name}'")
- return fv
- else
- return nil
- end
- end
+ debug_benchmark("Saved host") {
+ host.save
+ }
+ end
- # returns a hash of fact_names.name => [ fact_values ] for this host.
- # Note that 'fact_values' is actually a list of the value instances, not
- # just actual values.
- def get_facts_hash
- fact_values = self.fact_values.find(:all, :include => :fact_name)
- return fact_values.inject({}) do | hash, value |
- hash[value.fact_name.name] ||= []
- hash[value.fact_name.name] << value
- hash
- end
end
+ # This only runs if time debugging is enabled.
+ write_benchmarks
- # This is *very* similar to the merge_parameters method
- # of Puppet::Rails::Resource.
- def merge_facts(facts)
- db_facts = {}
+ host
+ end
- deletions = []
- self.fact_values.find(:all, :include => :fact_name).each do |value|
- deletions << value['id'] and next unless facts.include?(value['name'])
- # Now store them for later testing.
- db_facts[value['name']] ||= []
- db_facts[value['name']] << value
- end
+ # Return the value of a fact.
+ def fact(name)
- # Now get rid of any parameters whose value list is different.
- # This might be extra work in cases where an array has added or lost
- # a single value, but in the most common case (a single value has changed)
- # this makes sense.
- db_facts.each do |name, value_hashes|
- values = value_hashes.collect { |v| v['value'] }
+ if fv = self.fact_values.find(
+ :all, :include => :fact_name,
- unless values == facts[name]
- value_hashes.each { |v| deletions << v['id'] }
- end
- end
+ :conditions => "fact_names.name = '#{name}'")
+ return fv
+ else
+ return nil
+ end
+ end
+
+ # returns a hash of fact_names.name => [ fact_values ] for this host.
+ # Note that 'fact_values' is actually a list of the value instances, not
+ # just actual values.
+ def get_facts_hash
+ fact_values = self.fact_values.find(:all, :include => :fact_name)
+ return fact_values.inject({}) do | hash, value |
+ hash[value.fact_name.name] ||= []
+ hash[value.fact_name.name] << value
+ hash
+ end
+ end
- # Perform our deletions.
- Puppet::Rails::FactValue.delete(deletions) unless deletions.empty?
- # Lastly, add any new parameters.
- facts.each do |name, value|
- next if db_facts.include?(name)
- values = value.is_a?(Array) ? value : [value]
+ # This is *very* similar to the merge_parameters method
+ # of Puppet::Rails::Resource.
+ def merge_facts(facts)
+ db_facts = {}
- values.each do |v|
- fact_values.build(:value => v, :fact_name => Puppet::Rails::FactName.find_or_create_by_name(name))
- end
- end
+ deletions = []
+ self.fact_values.find(:all, :include => :fact_name).each do |value|
+ deletions << value['id'] and next unless facts.include?(value['name'])
+ # Now store them for later testing.
+ db_facts[value['name']] ||= []
+ db_facts[value['name']] << value
end
- # Set our resources.
- def merge_resources(list)
- # keep only exported resources in thin_storeconfig mode
- list = list.select { |r| r.exported? } if Puppet.settings[:thin_storeconfigs]
-
- resources_by_id = nil
- debug_benchmark("Searched for resources") {
- resources_by_id = find_resources
- }
-
- debug_benchmark("Searched for resource params and tags") {
- find_resources_parameters_tags(resources_by_id)
- } if id
+ # Now get rid of any parameters whose value list is different.
+ # This might be extra work in cases where an array has added or lost
+ # a single value, but in the most common case (a single value has changed)
+ # this makes sense.
+ db_facts.each do |name, value_hashes|
+ values = value_hashes.collect { |v| v['value'] }
- debug_benchmark("Performed resource comparison") {
- compare_to_catalog(resources_by_id, list)
- }
+ unless values == facts[name]
+ value_hashes.each { |v| deletions << v['id'] }
+ end
end
- def find_resources
- condition = { :exported => true } if Puppet.settings[:thin_storeconfigs]
+ # Perform our deletions.
+ Puppet::Rails::FactValue.delete(deletions) unless deletions.empty?
- resources.find(:all, :include => :source_file, :conditions => condition || {}).inject({}) do | hash, resource |
- hash[resource.id] = resource
- hash
- end
- end
+ # Lastly, add any new parameters.
+ facts.each do |name, value|
+ next if db_facts.include?(name)
+ values = value.is_a?(Array) ? value : [value]
- def find_resources_parameters_tags(resources)
- find_resources_parameters(resources)
- find_resources_tags(resources)
+ values.each do |v|
+ fact_values.build(:value => v, :fact_name => Puppet::Rails::FactName.find_or_create_by_name(name))
+ end
end
+ end
- def compare_to_catalog(existing, list)
- compiled = list.inject({}) do |hash, resource|
- hash[resource.ref] = resource
- hash
- end
+ # Set our resources.
+ def merge_resources(list)
+ # keep only exported resources in thin_storeconfig mode
+ list = list.select { |r| r.exported? } if Puppet.settings[:thin_storeconfigs]
- resources = nil
- debug_benchmark("Resource removal") {
- resources = remove_unneeded_resources(compiled, existing)
- }
+ resources_by_id = nil
+ debug_benchmark("Searched for resources") {
+ resources_by_id = find_resources
+ }
- # Now for all resources in the catalog but not in the db, we're pretty easy.
- additions = nil
- debug_benchmark("Resource merger") {
- additions = perform_resource_merger(compiled, resources)
- }
+ debug_benchmark("Searched for resource params and tags") {
+ find_resources_parameters_tags(resources_by_id)
+ } if id
- debug_benchmark("Resource addition") {
- additions.each do |resource|
- build_rails_resource_from_parser_resource(resource)
- end
+ debug_benchmark("Performed resource comparison") {
+ compare_to_catalog(resources_by_id, list)
+ }
+ end
- log_accumulated_marks "Added resources"
- }
- end
+ def find_resources
+ condition = { :exported => true } if Puppet.settings[:thin_storeconfigs]
- def add_new_resources(additions)
- additions.each do |resource|
- Puppet::Rails::Resource.from_parser_resource(self, resource)
- end
+ resources.find(:all, :include => :source_file, :conditions => condition || {}).inject({}) do | hash, resource |
+ hash[resource.id] = resource
+ hash
end
+ end
- # Turn a parser resource into a Rails resource.
- def build_rails_resource_from_parser_resource(resource)
- db_resource = nil
- accumulate_benchmark("Added resources", :initialization) {
- args = Puppet::Rails::Resource.rails_resource_initial_args(resource)
+ def find_resources_parameters_tags(resources)
+ find_resources_parameters(resources)
+ find_resources_tags(resources)
+ end
- db_resource = self.resources.build(args)
+ def compare_to_catalog(existing, list)
+ compiled = list.inject({}) do |hash, resource|
+ hash[resource.ref] = resource
+ hash
+ end
- # Our file= method does the name to id conversion.
- db_resource.file = resource.file
- }
+ resources = nil
+ debug_benchmark("Resource removal") {
+ resources = remove_unneeded_resources(compiled, existing)
+ }
+
+ # Now for all resources in the catalog but not in the db, we're pretty easy.
+ additions = nil
+ debug_benchmark("Resource merger") {
+ additions = perform_resource_merger(compiled, resources)
+ }
+
+ debug_benchmark("Resource addition") {
+ additions.each do |resource|
+ build_rails_resource_from_parser_resource(resource)
+ end
+
+ log_accumulated_marks "Added resources"
+ }
+ end
+
+ def add_new_resources(additions)
+ additions.each do |resource|
+ Puppet::Rails::Resource.from_parser_resource(self, resource)
+ end
+ end
+ # Turn a parser resource into a Rails resource.
+ def build_rails_resource_from_parser_resource(resource)
+ db_resource = nil
+ accumulate_benchmark("Added resources", :initialization) {
+ args = Puppet::Rails::Resource.rails_resource_initial_args(resource)
- accumulate_benchmark("Added resources", :parameters) {
- resource.each do |param, value|
- Puppet::Rails::ParamValue.from_parser_param(param, value).each do |value_hash|
- db_resource.param_values.build(value_hash)
- end
- end
- }
+ db_resource = self.resources.build(args)
- accumulate_benchmark("Added resources", :tags) {
- resource.tags.each { |tag| db_resource.add_resource_tag(tag) }
- }
+ # Our file= method does the name to id conversion.
+ db_resource.file = resource.file
+ }
- db_resource.save
- db_resource
- end
+ accumulate_benchmark("Added resources", :parameters) {
+ resource.each do |param, value|
+ Puppet::Rails::ParamValue.from_parser_param(param, value).each do |value_hash|
+ db_resource.param_values.build(value_hash)
+ end
+ end
+ }
+ accumulate_benchmark("Added resources", :tags) {
+ resource.tags.each { |tag| db_resource.add_resource_tag(tag) }
+ }
- def perform_resource_merger(compiled, resources)
- return compiled.values if resources.empty?
+ db_resource.save
- # Now for all resources in the catalog but not in the db, we're pretty easy.
- additions = []
- compiled.each do |ref, resource|
- if db_resource = resources[ref]
- db_resource.merge_parser_resource(resource)
- else
- additions << resource
- end
- end
- log_accumulated_marks "Resource merger"
+ db_resource
+ end
- additions
- end
- def remove_unneeded_resources(compiled, existing)
- deletions = []
- resources = {}
- existing.each do |id, resource|
- # it seems that it can happen (see bug #2010) some resources are duplicated in the
- # database (ie logically corrupted database), in which case we remove the extraneous
- # entries.
- if resources.include?(resource.ref)
- deletions << id
- next
- end
-
- # If the resource is in the db but not in the catalog, mark it
- # for removal.
- unless compiled.include?(resource.ref)
- deletions << id
- next
- end
-
- resources[resource.ref] = resource
- end
- # We need to use 'destroy' here, not 'delete', so that all
- # dependent objects get removed, too.
- Puppet::Rails::Resource.destroy(deletions) unless deletions.empty?
+ def perform_resource_merger(compiled, resources)
+ return compiled.values if resources.empty?
- resources
+ # Now for all resources in the catalog but not in the db, we're pretty easy.
+ additions = []
+ compiled.each do |ref, resource|
+ if db_resource = resources[ref]
+ db_resource.merge_parser_resource(resource)
+ else
+ additions << resource
+ end
end
-
- def find_resources_parameters(resources)
- params = Puppet::Rails::ParamValue.find_all_params_from_host(self)
-
- # assign each loaded parameters/tags to the resource it belongs to
- params.each do |param|
- resources[param['resource_id']].add_param_to_list(param) if resources.include?(param['resource_id'])
- end
+ log_accumulated_marks "Resource merger"
+
+ additions
+ end
+
+ def remove_unneeded_resources(compiled, existing)
+ deletions = []
+ resources = {}
+ existing.each do |id, resource|
+ # it seems that it can happen (see bug #2010) some resources are duplicated in the
+ # database (ie logically corrupted database), in which case we remove the extraneous
+ # entries.
+ if resources.include?(resource.ref)
+ deletions << id
+ next
+ end
+
+ # If the resource is in the db but not in the catalog, mark it
+ # for removal.
+ unless compiled.include?(resource.ref)
+ deletions << id
+ next
+ end
+
+ resources[resource.ref] = resource
end
+ # We need to use 'destroy' here, not 'delete', so that all
+ # dependent objects get removed, too.
+ Puppet::Rails::Resource.destroy(deletions) unless deletions.empty?
- def find_resources_tags(resources)
- tags = Puppet::Rails::ResourceTag.find_all_tags_from_host(self)
+ resources
+ end
- tags.each do |tag|
- resources[tag['resource_id']].add_tag_to_list(tag) if resources.include?(tag['resource_id'])
- end
- end
+ def find_resources_parameters(resources)
+ params = Puppet::Rails::ParamValue.find_all_params_from_host(self)
- def update_connect_time
- self.last_connect = Time.now
- save
+ # assign each loaded parameters/tags to the resource it belongs to
+ params.each do |param|
+ resources[param['resource_id']].add_param_to_list(param) if resources.include?(param['resource_id'])
end
+ end
- def to_puppet
- node = Puppet::Node.new(self.name)
- {"ip" => "ipaddress", "environment" => "environment"}.each do |myparam, itsparam|
- if value = send(myparam)
- node.send(itsparam + "=", value)
- end
- end
+ def find_resources_tags(resources)
+ tags = Puppet::Rails::ResourceTag.find_all_tags_from_host(self)
- node
+ tags.each do |tag|
+ resources[tag['resource_id']].add_tag_to_list(tag) if resources.include?(tag['resource_id'])
+ end
+ end
+
+ def update_connect_time
+ self.last_connect = Time.now
+ save
+ end
+
+ def to_puppet
+ node = Puppet::Node.new(self.name)
+ {"ip" => "ipaddress", "environment" => "environment"}.each do |myparam, itsparam|
+ if value = send(myparam)
+ node.send(itsparam + "=", value)
+ end
end
+
+ node
+ end
end
diff --git a/lib/puppet/rails/param_name.rb b/lib/puppet/rails/param_name.rb
index 69e2fb6e2..91cf45628 100644
--- a/lib/puppet/rails/param_name.rb
+++ b/lib/puppet/rails/param_name.rb
@@ -3,23 +3,23 @@ require 'puppet/rails/param_value'
require 'puppet/util/rails/cache_accumulator'
class Puppet::Rails::ParamName < ActiveRecord::Base
- include Puppet::Util::CollectionMerger
- has_many :param_values, :dependent => :destroy
+ include Puppet::Util::CollectionMerger
+ has_many :param_values, :dependent => :destroy
- include Puppet::Util::CacheAccumulator
- accumulates :name
+ include Puppet::Util::CacheAccumulator
+ accumulates :name
- def to_resourceparam(resource, source)
- hash = {}
- hash[:name] = self.name.to_sym
- hash[:source] = source
- hash[:value] = resource.param_values.find(:all, :conditions => [ "param_name_id = ?", self.id]).collect { |v| v.value }
- if hash[:value].length == 1
- hash[:value] = hash[:value].shift
- elsif hash[:value].empty?
- hash[:value] = nil
- end
- Puppet::Parser::Resource::Param.new hash
+ def to_resourceparam(resource, source)
+ hash = {}
+ hash[:name] = self.name.to_sym
+ hash[:source] = source
+ hash[:value] = resource.param_values.find(:all, :conditions => [ "param_name_id = ?", self.id]).collect { |v| v.value }
+ if hash[:value].length == 1
+ hash[:value] = hash[:value].shift
+ elsif hash[:value].empty?
+ hash[:value] = nil
end
+ Puppet::Parser::Resource::Param.new hash
+ end
end
diff --git a/lib/puppet/rails/param_value.rb b/lib/puppet/rails/param_value.rb
index e4b5a668f..d7c88f844 100644
--- a/lib/puppet/rails/param_value.rb
+++ b/lib/puppet/rails/param_value.rb
@@ -1,74 +1,74 @@
require 'puppet/util/rails/reference_serializer'
class Puppet::Rails::ParamValue < ActiveRecord::Base
- include Puppet::Util::ReferenceSerializer
- extend Puppet::Util::ReferenceSerializer
+ include Puppet::Util::ReferenceSerializer
+ extend Puppet::Util::ReferenceSerializer
- belongs_to :param_name
- belongs_to :resource
+ belongs_to :param_name
+ belongs_to :resource
- # Store a new parameter in a Rails db.
- def self.from_parser_param(param, values)
- values = munge_parser_values(values)
+ # Store a new parameter in a Rails db.
+ def self.from_parser_param(param, values)
+ values = munge_parser_values(values)
- param_name = Puppet::Rails::ParamName.find_or_create_by_name(param.to_s)
- return values.collect do |v|
- {:value => v, :param_name => param_name}
- end
+ param_name = Puppet::Rails::ParamName.find_or_create_by_name(param.to_s)
+ return values.collect do |v|
+ {:value => v, :param_name => param_name}
end
+ end
- # Make sure an array (or possibly not an array) of values is correctly
- # set up for Rails. The main thing is that Resource::Reference objects
- # should stay objects, so they just get serialized.
- def self.munge_parser_values(value)
- values = value.is_a?(Array) ? value : [value]
- values.map do |v|
- if v.is_a?(Puppet::Resource)
- v
- else
- v.to_s
- end
- end
+ # Make sure an array (or possibly not an array) of values is correctly
+ # set up for Rails. The main thing is that Resource::Reference objects
+ # should stay objects, so they just get serialized.
+ def self.munge_parser_values(value)
+ values = value.is_a?(Array) ? value : [value]
+ values.map do |v|
+ if v.is_a?(Puppet::Resource)
+ v
+ else
+ v.to_s
+ end
end
+ end
- def value
- unserialize_value(self[:value])
- end
+ def value
+ unserialize_value(self[:value])
+ end
- # I could not find a cleaner way to handle making sure that resource references
- # were consistently serialized and deserialized.
- def value=(val)
- self[:value] = serialize_value(val)
- end
+ # I could not find a cleaner way to handle making sure that resource references
+ # were consistently serialized and deserialized.
+ def value=(val)
+ self[:value] = serialize_value(val)
+ end
- def to_label
- "#{self.param_name.name}"
- end
+ def to_label
+ "#{self.param_name.name}"
+ end
- # returns an array of hash containing all the parameters of a given resource
- def self.find_all_params_from_resource(db_resource)
- params = db_resource.connection.select_all("SELECT v.id, v.value, v.line, v.resource_id, v.param_name_id, n.name FROM param_values v INNER JOIN param_names n ON v.param_name_id=n.id WHERE v.resource_id=#{db_resource.id}")
- params.each do |val|
- val['value'] = unserialize_value(val['value'])
- val['line'] = val['line'] ? Integer(val['line']) : nil
- val['resource_id'] = Integer(val['resource_id'])
- end
- params
+ # returns an array of hash containing all the parameters of a given resource
+ def self.find_all_params_from_resource(db_resource)
+ params = db_resource.connection.select_all("SELECT v.id, v.value, v.line, v.resource_id, v.param_name_id, n.name FROM param_values v INNER JOIN param_names n ON v.param_name_id=n.id WHERE v.resource_id=#{db_resource.id}")
+ params.each do |val|
+ val['value'] = unserialize_value(val['value'])
+ val['line'] = val['line'] ? Integer(val['line']) : nil
+ val['resource_id'] = Integer(val['resource_id'])
end
+ params
+ end
- # returns an array of hash containing all the parameters of a given host
- def self.find_all_params_from_host(db_host)
- params = db_host.connection.select_all("SELECT v.id, v.value, v.line, v.resource_id, v.param_name_id, n.name FROM param_values v INNER JOIN resources r ON v.resource_id=r.id INNER JOIN param_names n ON v.param_name_id=n.id WHERE r.host_id=#{db_host.id}")
- params.each do |val|
- val['value'] = unserialize_value(val['value'])
- val['line'] = val['line'] ? Integer(val['line']) : nil
- val['resource_id'] = Integer(val['resource_id'])
- end
- params
+ # returns an array of hash containing all the parameters of a given host
+ def self.find_all_params_from_host(db_host)
+ params = db_host.connection.select_all("SELECT v.id, v.value, v.line, v.resource_id, v.param_name_id, n.name FROM param_values v INNER JOIN resources r ON v.resource_id=r.id INNER JOIN param_names n ON v.param_name_id=n.id WHERE r.host_id=#{db_host.id}")
+ params.each do |val|
+ val['value'] = unserialize_value(val['value'])
+ val['line'] = val['line'] ? Integer(val['line']) : nil
+ val['resource_id'] = Integer(val['resource_id'])
end
+ params
+ end
- def to_s
- "#{self.name} => #{self.value}"
- end
+ def to_s
+ "#{self.name} => #{self.value}"
+ end
end
diff --git a/lib/puppet/rails/puppet_tag.rb b/lib/puppet/rails/puppet_tag.rb
index 2cc2c135f..fadbfa6f6 100644
--- a/lib/puppet/rails/puppet_tag.rb
+++ b/lib/puppet/rails/puppet_tag.rb
@@ -2,9 +2,9 @@ require 'puppet/rails/resource_tag'
require 'puppet/util/rails/cache_accumulator'
class Puppet::Rails::PuppetTag < ActiveRecord::Base
- has_many :resource_tags, :dependent => :destroy
- has_many :resources, :through => :resource_tags
+ has_many :resource_tags, :dependent => :destroy
+ has_many :resources, :through => :resource_tags
- include Puppet::Util::CacheAccumulator
- accumulates :name
+ include Puppet::Util::CacheAccumulator
+ accumulates :name
end
diff --git a/lib/puppet/rails/resource.rb b/lib/puppet/rails/resource.rb
index f485909a3..a5cdd0c13 100644
--- a/lib/puppet/rails/resource.rb
+++ b/lib/puppet/rails/resource.rb
@@ -6,226 +6,226 @@ require 'puppet/rails/benchmark'
require 'puppet/util/rails/collection_merger'
class Puppet::Rails::Resource < ActiveRecord::Base
- include Puppet::Util::CollectionMerger
- include Puppet::Util::ReferenceSerializer
- include Puppet::Rails::Benchmark
+ include Puppet::Util::CollectionMerger
+ include Puppet::Util::ReferenceSerializer
+ include Puppet::Rails::Benchmark
+
+ has_many :param_values, :dependent => :destroy, :class_name => "Puppet::Rails::ParamValue"
+ has_many :param_names, :through => :param_values, :class_name => "Puppet::Rails::ParamName"
- has_many :param_values, :dependent => :destroy, :class_name => "Puppet::Rails::ParamValue"
- has_many :param_names, :through => :param_values, :class_name => "Puppet::Rails::ParamName"
+ has_many :resource_tags, :dependent => :destroy, :class_name => "Puppet::Rails::ResourceTag"
+ has_many :puppet_tags, :through => :resource_tags, :class_name => "Puppet::Rails::PuppetTag"
- has_many :resource_tags, :dependent => :destroy, :class_name => "Puppet::Rails::ResourceTag"
- has_many :puppet_tags, :through => :resource_tags, :class_name => "Puppet::Rails::PuppetTag"
+ belongs_to :source_file
+ belongs_to :host
- belongs_to :source_file
- belongs_to :host
+ @tags = {}
+ def self.tags
+ @tags
+ end
- @tags = {}
- def self.tags
- @tags
+ # Determine the basic details on the resource.
+ def self.rails_resource_initial_args(resource)
+ result = [:type, :title, :line].inject({}) do |hash, param|
+ # 'type' isn't a valid column name, so we have to use another name.
+ to = (param == :type) ? :restype : param
+ if value = resource.send(param)
+ hash[to] = value
+ end
+ hash
end
- # Determine the basic details on the resource.
- def self.rails_resource_initial_args(resource)
- result = [:type, :title, :line].inject({}) do |hash, param|
- # 'type' isn't a valid column name, so we have to use another name.
- to = (param == :type) ? :restype : param
- if value = resource.send(param)
- hash[to] = value
- end
- hash
- end
-
- # We always want a value here, regardless of what the resource has,
- # so we break it out separately.
- result[:exported] = resource.exported || false
-
- result
- end
+ # We always want a value here, regardless of what the resource has,
+ # so we break it out separately.
+ result[:exported] = resource.exported || false
- def add_resource_tag(tag)
- pt = Puppet::Rails::PuppetTag.accumulate_by_name(tag)
- resource_tags.build(:puppet_tag => pt)
- end
+ result
+ end
- def file
- (f = self.source_file) ? f.filename : nil
- end
+ def add_resource_tag(tag)
+ pt = Puppet::Rails::PuppetTag.accumulate_by_name(tag)
+ resource_tags.build(:puppet_tag => pt)
+ end
- def file=(file)
- self.source_file = Puppet::Rails::SourceFile.find_or_create_by_filename(file)
- end
+ def file
+ (f = self.source_file) ? f.filename : nil
+ end
- def title
- unserialize_value(self[:title])
- end
+ def file=(file)
+ self.source_file = Puppet::Rails::SourceFile.find_or_create_by_filename(file)
+ end
- def params_list
- @params_list ||= []
- end
+ def title
+ unserialize_value(self[:title])
+ end
- def params_list=(params)
- @params_list = params
- end
+ def params_list
+ @params_list ||= []
+ end
- def add_param_to_list(param)
- params_list << param
- end
+ def params_list=(params)
+ @params_list = params
+ end
- def tags_list
- @tags_list ||= []
- end
+ def add_param_to_list(param)
+ params_list << param
+ end
- def tags_list=(tags)
- @tags_list = tags
- end
+ def tags_list
+ @tags_list ||= []
+ end
- def add_tag_to_list(tag)
- tags_list << tag
- end
+ def tags_list=(tags)
+ @tags_list = tags
+ end
- def [](param)
- super || parameter(param)
- end
+ def add_tag_to_list(tag)
+ tags_list << tag
+ end
- # Make sure this resource is equivalent to the provided Parser resource.
- def merge_parser_resource(resource)
- accumulate_benchmark("Individual resource merger", :attributes) { merge_attributes(resource) }
- accumulate_benchmark("Individual resource merger", :parameters) { merge_parameters(resource) }
- accumulate_benchmark("Individual resource merger", :tags) { merge_tags(resource) }
- save
- end
+ def [](param)
+ super || parameter(param)
+ end
- def merge_attributes(resource)
- args = self.class.rails_resource_initial_args(resource)
- args.each do |param, value|
- self[param] = value unless resource[param] == value
- end
+ # Make sure this resource is equivalent to the provided Parser resource.
+ def merge_parser_resource(resource)
+ accumulate_benchmark("Individual resource merger", :attributes) { merge_attributes(resource) }
+ accumulate_benchmark("Individual resource merger", :parameters) { merge_parameters(resource) }
+ accumulate_benchmark("Individual resource merger", :tags) { merge_tags(resource) }
+ save
+ end
- # Handle file specially
- self.file = resource.file if (resource.file and (!resource.file or self.file != resource.file))
+ def merge_attributes(resource)
+ args = self.class.rails_resource_initial_args(resource)
+ args.each do |param, value|
+ self[param] = value unless resource[param] == value
end
- def merge_parameters(resource)
- catalog_params = {}
- resource.each do |param, value|
- catalog_params[param.to_s] = value
- end
-
- db_params = {}
-
- deletions = []
- params_list.each do |value|
- # First remove any parameters our catalog resource doesn't have at all.
- deletions << value['id'] and next unless catalog_params.include?(value['name'])
-
- # Now store them for later testing.
- db_params[value['name']] ||= []
- db_params[value['name']] << value
- end
-
- # Now get rid of any parameters whose value list is different.
- # This might be extra work in cases where an array has added or lost
- # a single value, but in the most common case (a single value has changed)
- # this makes sense.
- db_params.each do |name, value_hashes|
- values = value_hashes.collect { |v| v['value'] }
-
- value_hashes.each { |v| deletions << v['id'] } unless value_compare(catalog_params[name], values)
- end
-
- # Perform our deletions.
- Puppet::Rails::ParamValue.delete(deletions) unless deletions.empty?
-
- # Lastly, add any new parameters.
- catalog_params.each do |name, value|
- next if db_params.include?(name) && ! db_params[name].find{ |val| deletions.include?( val["id"] ) }
- values = value.is_a?(Array) ? value : [value]
-
- values.each do |v|
- param_values.build(:value => serialize_value(v), :line => resource.line, :param_name => Puppet::Rails::ParamName.accumulate_by_name(name))
- end
- end
- end
+ # Handle file specially
+ self.file = resource.file if (resource.file and (!resource.file or self.file != resource.file))
+ end
- # Make sure the tag list is correct.
- def merge_tags(resource)
- in_db = []
- deletions = []
- resource_tags = resource.tags
- tags_list.each do |tag|
- deletions << tag['id'] and next unless resource_tags.include?(tag['name'])
- in_db << tag['name']
- end
- Puppet::Rails::ResourceTag.delete(deletions) unless deletions.empty?
-
- (resource_tags - in_db).each do |tag|
- add_resource_tag(tag)
- end
+ def merge_parameters(resource)
+ catalog_params = {}
+ resource.each do |param, value|
+ catalog_params[param.to_s] = value
end
- def value_compare(v,db_value)
- v = [v] unless v.is_a?(Array)
+ db_params = {}
- v == db_value
- end
+ deletions = []
+ params_list.each do |value|
+ # First remove any parameters our catalog resource doesn't have at all.
+ deletions << value['id'] and next unless catalog_params.include?(value['name'])
+
+ # Now store them for later testing.
+ db_params[value['name']] ||= []
+ db_params[value['name']] << value
+ end
+
+ # Now get rid of any parameters whose value list is different.
+ # This might be extra work in cases where an array has added or lost
+ # a single value, but in the most common case (a single value has changed)
+ # this makes sense.
+ db_params.each do |name, value_hashes|
+ values = value_hashes.collect { |v| v['value'] }
- def name
- ref
+ value_hashes.each { |v| deletions << v['id'] } unless value_compare(catalog_params[name], values)
end
- def parameter(param)
- if pn = param_names.find_by_name(param)
- return (pv = param_values.find(:first, :conditions => [ 'param_name_id = ?', pn])) ? pv.value : nil
- end
- end
+ # Perform our deletions.
+ Puppet::Rails::ParamValue.delete(deletions) unless deletions.empty?
+
+ # Lastly, add any new parameters.
+ catalog_params.each do |name, value|
+ next if db_params.include?(name) && ! db_params[name].find{ |val| deletions.include?( val["id"] ) }
+ values = value.is_a?(Array) ? value : [value]
+
+ values.each do |v|
+ param_values.build(:value => serialize_value(v), :line => resource.line, :param_name => Puppet::Rails::ParamName.accumulate_by_name(name))
+ end
+ end
+ end
- def ref(dummy_argument=:work_arround_for_ruby_GC_bug)
- "#{self[:restype].split("::").collect { |s| s.capitalize }.join("::")}[#{self.title}]"
- end
+ # Make sure the tag list is correct.
+ def merge_tags(resource)
+ in_db = []
+ deletions = []
+ resource_tags = resource.tags
+ tags_list.each do |tag|
+ deletions << tag['id'] and next unless resource_tags.include?(tag['name'])
+ in_db << tag['name']
+ end
+ Puppet::Rails::ResourceTag.delete(deletions) unless deletions.empty?
- # Returns a hash of parameter names and values, no ActiveRecord instances.
- def to_hash
- Puppet::Rails::ParamValue.find_all_params_from_resource(self).inject({}) do |hash, value|
- hash[value['name']] ||= []
- hash[value['name']] << value.value
- hash
- end
+ (resource_tags - in_db).each do |tag|
+ add_resource_tag(tag)
+ end
+ end
+
+ def value_compare(v,db_value)
+ v = [v] unless v.is_a?(Array)
+
+ v == db_value
+ end
+
+ def name
+ ref
+ end
+
+ def parameter(param)
+ if pn = param_names.find_by_name(param)
+ return (pv = param_values.find(:first, :conditions => [ 'param_name_id = ?', pn])) ? pv.value : nil
+ end
+ end
+
+ def ref(dummy_argument=:work_arround_for_ruby_GC_bug)
+ "#{self[:restype].split("::").collect { |s| s.capitalize }.join("::")}[#{self.title}]"
+ end
+
+ # Returns a hash of parameter names and values, no ActiveRecord instances.
+ def to_hash
+ Puppet::Rails::ParamValue.find_all_params_from_resource(self).inject({}) do |hash, value|
+ hash[value['name']] ||= []
+ hash[value['name']] << value.value
+ hash
end
+ end
+
+ # Convert our object to a resource. Do not retain whether the object
+ # is exported, though, since that would cause it to get stripped
+ # from the configuration.
+ def to_resource(scope)
+ hash = self.attributes
+ hash["type"] = hash["restype"]
+ hash.delete("restype")
- # Convert our object to a resource. Do not retain whether the object
- # is exported, though, since that would cause it to get stripped
- # from the configuration.
- def to_resource(scope)
- hash = self.attributes
- hash["type"] = hash["restype"]
- hash.delete("restype")
-
- # FIXME At some point, we're going to want to retain this information
- # for logging and auditing.
- hash.delete("host_id")
- hash.delete("updated_at")
- hash.delete("source_file_id")
- hash.delete("created_at")
- hash.delete("id")
- hash.each do |p, v|
- hash.delete(p) if v.nil?
- end
- hash[:scope] = scope
- hash[:source] = scope.source
- hash[:params] = []
- names = []
- self.param_names.each do |pname|
- # We can get the same name multiple times because of how the
- # db layout works.
- next if names.include?(pname.name)
- names << pname.name
- hash[:params] << pname.to_resourceparam(self, scope.source)
- end
- obj = Puppet::Parser::Resource.new(hash)
-
- # Store the ID, so we can check if we're re-collecting the same resource.
- obj.rails_id = self.id
-
- obj
+ # FIXME At some point, we're going to want to retain this information
+ # for logging and auditing.
+ hash.delete("host_id")
+ hash.delete("updated_at")
+ hash.delete("source_file_id")
+ hash.delete("created_at")
+ hash.delete("id")
+ hash.each do |p, v|
+ hash.delete(p) if v.nil?
end
+ hash[:scope] = scope
+ hash[:source] = scope.source
+ hash[:params] = []
+ names = []
+ self.param_names.each do |pname|
+ # We can get the same name multiple times because of how the
+ # db layout works.
+ next if names.include?(pname.name)
+ names << pname.name
+ hash[:params] << pname.to_resourceparam(self, scope.source)
+ end
+ obj = Puppet::Parser::Resource.new(hash)
+
+ # Store the ID, so we can check if we're re-collecting the same resource.
+ obj.rails_id = self.id
+
+ obj
+ end
end
diff --git a/lib/puppet/rails/resource_tag.rb b/lib/puppet/rails/resource_tag.rb
index 0bbac11d3..1c1aa4595 100644
--- a/lib/puppet/rails/resource_tag.rb
+++ b/lib/puppet/rails/resource_tag.rb
@@ -1,26 +1,26 @@
class Puppet::Rails::ResourceTag < ActiveRecord::Base
- belongs_to :puppet_tag
- belongs_to :resource
+ belongs_to :puppet_tag
+ belongs_to :resource
- def to_label
- "#{self.puppet_tag.name}"
- end
+ def to_label
+ "#{self.puppet_tag.name}"
+ end
- # returns an array of hash containing tags of resource
- def self.find_all_tags_from_resource(db_resource)
- tags = db_resource.connection.select_all("SELECT t.id, t.resource_id, p.name FROM resource_tags t INNER JOIN puppet_tags p ON t.puppet_tag_id=p.id WHERE t.resource_id=#{db_resource.id}")
- tags.each do |val|
- val['resource_id'] = Integer(val['resource_id'])
- end
- tags
+ # returns an array of hash containing tags of resource
+ def self.find_all_tags_from_resource(db_resource)
+ tags = db_resource.connection.select_all("SELECT t.id, t.resource_id, p.name FROM resource_tags t INNER JOIN puppet_tags p ON t.puppet_tag_id=p.id WHERE t.resource_id=#{db_resource.id}")
+ tags.each do |val|
+ val['resource_id'] = Integer(val['resource_id'])
end
+ tags
+ end
- # returns an array of hash containing tags of a host
- def self.find_all_tags_from_host(db_host)
- tags = db_host.connection.select_all("SELECT t.id, t.resource_id, p.name FROM resource_tags t INNER JOIN resources r ON t.resource_id=r.id INNER JOIN puppet_tags p ON t.puppet_tag_id=p.id WHERE r.host_id=#{db_host.id}")
- tags.each do |val|
- val['resource_id'] = Integer(val['resource_id'])
- end
- tags
+ # returns an array of hash containing tags of a host
+ def self.find_all_tags_from_host(db_host)
+ tags = db_host.connection.select_all("SELECT t.id, t.resource_id, p.name FROM resource_tags t INNER JOIN resources r ON t.resource_id=r.id INNER JOIN puppet_tags p ON t.puppet_tag_id=p.id WHERE r.host_id=#{db_host.id}")
+ tags.each do |val|
+ val['resource_id'] = Integer(val['resource_id'])
end
+ tags
+ end
end
diff --git a/lib/puppet/rails/source_file.rb b/lib/puppet/rails/source_file.rb
index 6a691893a..02557ffca 100644
--- a/lib/puppet/rails/source_file.rb
+++ b/lib/puppet/rails/source_file.rb
@@ -1,8 +1,8 @@
class Puppet::Rails::SourceFile < ActiveRecord::Base
- has_one :host
- has_one :resource
+ has_one :host
+ has_one :resource
- def to_label
- "#{self.filename}"
- end
+ def to_label
+ "#{self.filename}"
+ end
end
diff --git a/lib/puppet/reference/configuration.rb b/lib/puppet/reference/configuration.rb
index 2f60ecc65..bfa2cb802 100644
--- a/lib/puppet/reference/configuration.rb
+++ b/lib/puppet/reference/configuration.rb
@@ -1,44 +1,44 @@
config = Puppet::Util::Reference.newreference(:configuration, :depth => 1, :doc => "A reference for all configuration parameters") do
- docs = {}
- Puppet.settings.each do |name, object|
- docs[name] = object
+ docs = {}
+ Puppet.settings.each do |name, object|
+ docs[name] = object
+ end
+
+ str = ""
+ docs.sort { |a, b|
+ a[0].to_s <=> b[0].to_s
+ }.each do |name, object|
+ # Make each name an anchor
+ header = name.to_s
+ str += h(header, 3)
+
+ # Print the doc string itself
+ begin
+ str += object.desc.gsub(/\n/, " ")
+ rescue => detail
+ puts detail.backtrace
+ puts detail
+ end
+ str += "\n\n"
+
+ # Now print the data about the item.
+ str += ""
+ val = object.default
+ if name.to_s == "vardir"
+ val = "/var/lib/puppet"
+ elsif name.to_s == "confdir"
+ val = "/etc/puppet"
end
- str = ""
- docs.sort { |a, b|
- a[0].to_s <=> b[0].to_s
- }.each do |name, object|
- # Make each name an anchor
- header = name.to_s
- str += h(header, 3)
-
- # Print the doc string itself
- begin
- str += object.desc.gsub(/\n/, " ")
- rescue => detail
- puts detail.backtrace
- puts detail
- end
- str += "\n\n"
-
- # Now print the data about the item.
- str += ""
- val = object.default
- if name.to_s == "vardir"
- val = "/var/lib/puppet"
- elsif name.to_s == "confdir"
- val = "/etc/puppet"
- end
-
- # Leave out the section information; it was apparently confusing people.
- #str += "- **Section**: #{object.section}\n"
- unless val == ""
- str += "- **Default**: #{val}\n"
- end
- str += "\n"
+ # Leave out the section information; it was apparently confusing people.
+ #str += "- **Section**: #{object.section}\n"
+ unless val == ""
+ str += "- **Default**: #{val}\n"
end
+ str += "\n"
+ end
- return str
+ return str
end
config.header = "
@@ -57,14 +57,14 @@ These parameters can be supplied to the executables either as command-line
options or in the configuration file. For instance, the command-line
invocation below would set the configuration directory to ``/private/puppet``::
- $ puppet agent --confdir=/private/puppet
+ $ puppet agent --confdir=/private/puppet
Note that boolean options are turned on and off with a slightly different
syntax on the command line::
- $ puppet agent --storeconfigs
+ $ puppet agent --storeconfigs
- $ puppet agent --no-storeconfigs
+ $ puppet agent --no-storeconfigs
The invocations above will enable and disable, respectively, the storage of
the client configuration.
@@ -89,9 +89,9 @@ File Format
The file follows INI-style formatting. Here is an example of a very simple
``puppet.conf`` file::
- [main]
- confdir = /private/puppet
- storeconfigs = true
+ [main]
+ confdir = /private/puppet
+ storeconfigs = true
Note that boolean parameters must be explicitly specified as `true` or
`false` as seen above.
@@ -99,8 +99,8 @@ Note that boolean parameters must be explicitly specified as `true` or
If you need to change file parameters (e.g., reset the mode or owner), do
so within curly braces on the same line::
- [main]
- myfile = /tmp/whatever {owner = root, mode = 644}
+ [main]
+ myfile = /tmp/whatever {owner = root, mode = 644}
If you're starting out with a fresh configuration, you may wish to let
the executable generate a template configuration file for you by invoking
@@ -108,7 +108,7 @@ the executable in question with the `--genconfig` command. The executable
will print a template configuration to standard output, which can be
redirected to a file like so::
- $ puppet agent --genconfig > /etc/puppet/puppet.conf
+ $ puppet agent --genconfig > /etc/puppet/puppet.conf
Note that this invocation will replace the contents of any pre-existing
`puppet.conf` file, so make a backup of your present config if it contains
@@ -119,12 +119,12 @@ argument, which will generate a manifest that can be used to manage all of
Puppet's directories and files and prints it to standard output. This can
likewise be redirected to a file::
- $ puppet agent --genmanifest > /etc/puppet/manifests/site.pp
+ $ puppet agent --genmanifest > /etc/puppet/manifests/site.pp
Puppet can also create user and group accounts for itself (one `puppet` group
and one `puppet` user) if it is invoked as `root` with the `--mkusers` argument::
- $ puppet agent --mkusers
+ $ puppet agent --mkusers
Signals
-------
diff --git a/lib/puppet/reference/function.rb b/lib/puppet/reference/function.rb
index 0dc2f7967..1333e0d26 100644
--- a/lib/puppet/reference/function.rb
+++ b/lib/puppet/reference/function.rb
@@ -1,5 +1,5 @@
function = Puppet::Util::Reference.newreference :function, :doc => "All functions available in the parser" do
- Puppet::Parser::Functions.functiondocs
+ Puppet::Parser::Functions.functiondocs
end
function.header = "
There are two types of functions in Puppet: Statements and rvalues.
diff --git a/lib/puppet/reference/indirection.rb b/lib/puppet/reference/indirection.rb
index 13c014ed4..549299b36 100644
--- a/lib/puppet/reference/indirection.rb
+++ b/lib/puppet/reference/indirection.rb
@@ -4,24 +4,24 @@ require 'puppet/file_serving/content'
require 'puppet/file_serving/metadata'
reference = Puppet::Util::Reference.newreference :indirection, :doc => "Indirection types and their terminus classes" do
- text = ""
- Puppet::Indirector::Indirection.instances.sort { |a,b| a.to_s <=> b.to_s }.each do |indirection|
- ind = Puppet::Indirector::Indirection.instance(indirection)
- name = indirection.to_s.capitalize
- text += indirection.to_s + "\n" + ("-" * name.length) + "\n\n"
+ text = ""
+ Puppet::Indirector::Indirection.instances.sort { |a,b| a.to_s <=> b.to_s }.each do |indirection|
+ ind = Puppet::Indirector::Indirection.instance(indirection)
+ name = indirection.to_s.capitalize
+ text += indirection.to_s + "\n" + ("-" * name.length) + "\n\n"
- text += ind.doc + "\n\n"
+ text += ind.doc + "\n\n"
- Puppet::Indirector::Terminus.terminus_classes(ind.name).sort { |a,b| a.to_s <=> b.to_s }.each do |terminus|
- text += terminus.to_s + "\n" + ("+" * terminus.to_s.length) + "\n\n"
+ Puppet::Indirector::Terminus.terminus_classes(ind.name).sort { |a,b| a.to_s <=> b.to_s }.each do |terminus|
+ text += terminus.to_s + "\n" + ("+" * terminus.to_s.length) + "\n\n"
- term_class = Puppet::Indirector::Terminus.terminus_class(ind.name, terminus)
+ term_class = Puppet::Indirector::Terminus.terminus_class(ind.name, terminus)
- text += Puppet::Util::Docs.scrub(term_class.doc) + "\n\n"
- end
+ text += Puppet::Util::Docs.scrub(term_class.doc) + "\n\n"
end
+ end
- text
+ text
end
reference.header = "This is the list of all indirections, their associated terminus classes, and how you select between them.
diff --git a/lib/puppet/reference/metaparameter.rb b/lib/puppet/reference/metaparameter.rb
index 9368de186..6a319f1c2 100644
--- a/lib/puppet/reference/metaparameter.rb
+++ b/lib/puppet/reference/metaparameter.rb
@@ -1,48 +1,48 @@
metaparameter = Puppet::Util::Reference.newreference :metaparameter, :doc => "All Puppet metaparameters and all their details" do
- types = {}
- Puppet::Type.loadall
+ types = {}
+ Puppet::Type.loadall
- Puppet::Type.eachtype { |type|
- next if type.name == :puppet
- next if type.name == :component
- types[type.name] = type
- }
+ Puppet::Type.eachtype { |type|
+ next if type.name == :puppet
+ next if type.name == :component
+ types[type.name] = type
+ }
- str = %{
- Metaparameters
- --------------
- Metaparameters are parameters that work with any resource type; they are part of the
- Puppet framework itself rather than being part of the implementation of any
- given instance. Thus, any defined metaparameter can be used with any instance
- in your manifest, including defined components.
+ str = %{
+ Metaparameters
+ --------------
+ Metaparameters are parameters that work with any resource type; they are part of the
+ Puppet framework itself rather than being part of the implementation of any
+ given instance. Thus, any defined metaparameter can be used with any instance
+ in your manifest, including defined components.
- Available Metaparameters
- ++++++++++++++++++++++++
- }
- begin
- params = []
- Puppet::Type.eachmetaparam { |param|
- params << param
- }
+ Available Metaparameters
+ ++++++++++++++++++++++++
+ }
+ begin
+ params = []
+ Puppet::Type.eachmetaparam { |param|
+ params << param
+ }
- params.sort { |a,b|
- a.to_s <=> b.to_s
- }.each { |param|
- str += paramwrap(param.to_s, scrub(Puppet::Type.metaparamdoc(param)), :level => 4)
- #puts "<dt>#{param}</dt>"
- #puts tab(1) + Puppet::Type.metaparamdoc(param).scrub.indent($tab)gsub(/\n\s*/,' ')
- #puts "<dd>"
- #puts indent(scrub(Puppet::Type.metaparamdoc(param)), $tab)
- #puts scrub(Puppet::Type.metaparamdoc(param))
- #puts "</dd>"
+ params.sort { |a,b|
+ a.to_s <=> b.to_s
+ }.each { |param|
+ str += paramwrap(param.to_s, scrub(Puppet::Type.metaparamdoc(param)), :level => 4)
+ #puts "<dt>#{param}</dt>"
+ #puts tab(1) + Puppet::Type.metaparamdoc(param).scrub.indent($tab)gsub(/\n\s*/,' ')
+ #puts "<dd>"
+ #puts indent(scrub(Puppet::Type.metaparamdoc(param)), $tab)
+ #puts scrub(Puppet::Type.metaparamdoc(param))
+ #puts "</dd>"
- #puts ""
- }
- rescue => detail
- puts detail.backtrace
- puts "incorrect metaparams: #{detail}"
- exit(1)
- end
+ #puts ""
+ }
+ rescue => detail
+ puts detail.backtrace
+ puts "incorrect metaparams: #{detail}"
+ exit(1)
+ end
- str
+ str
end
diff --git a/lib/puppet/reference/network.rb b/lib/puppet/reference/network.rb
index 14b26dd70..a3bff656b 100644
--- a/lib/puppet/reference/network.rb
+++ b/lib/puppet/reference/network.rb
@@ -1,23 +1,23 @@
network = Puppet::Util::Reference.newreference :network, :depth => 2, :doc => "Available network handlers and clients" do
- ret = ""
- Puppet::Network::Handler.subclasses.sort { |a,b| a.to_s <=> b.to_s }.each do |name|
- handler = Puppet::Network::Handler.handler(name)
+ ret = ""
+ Puppet::Network::Handler.subclasses.sort { |a,b| a.to_s <=> b.to_s }.each do |name|
+ handler = Puppet::Network::Handler.handler(name)
- next if ! handler.doc or handler.doc == ""
+ next if ! handler.doc or handler.doc == ""
- interface = handler.interface
+ interface = handler.interface
- ret += h(name, 2)
+ ret += h(name, 2)
- ret += scrub(handler.doc)
- ret += "\n\n"
- ret += option(:prefix, interface.prefix)
- ret += option(:side, handler.side.to_s.capitalize)
- ret += option(:methods, interface.methods.collect { |ary| ary[0] }.join(", ") )
- ret += "\n\n"
- end
+ ret += scrub(handler.doc)
+ ret += "\n\n"
+ ret += option(:prefix, interface.prefix)
+ ret += option(:side, handler.side.to_s.capitalize)
+ ret += option(:methods, interface.methods.collect { |ary| ary[0] }.join(", ") )
+ ret += "\n\n"
+ end
- ret
+ ret
end
network.header = "
diff --git a/lib/puppet/reference/providers.rb b/lib/puppet/reference/providers.rb
index b19549350..a0f10633b 100644
--- a/lib/puppet/reference/providers.rb
+++ b/lib/puppet/reference/providers.rb
@@ -1,114 +1,114 @@
# This doesn't get stored in trac, since it changes every time.
providers = Puppet::Util::Reference.newreference :providers, :title => "Provider Suitability Report", :depth => 1, :dynamic => true, :doc => "Which providers are valid for this machine" do
- types = []
- Puppet::Type.loadall
- Puppet::Type.eachtype do |klass|
- next unless klass.providers.length > 0
- types << klass
+ types = []
+ Puppet::Type.loadall
+ Puppet::Type.eachtype do |klass|
+ next unless klass.providers.length > 0
+ types << klass
+ end
+ types.sort! { |a,b| a.name.to_s <=> b.name.to_s }
+
+ command_line = Puppet::Util::CommandLine.new
+ types.reject! { |type| ! command_line.args.include?(type.name.to_s) } unless command_line.args.empty?
+
+ ret = "Details about this host:\n\n"
+
+ # Throw some facts in there, so we know where the report is from.
+ ["Ruby Version", "Puppet Version", "Operating System", "Operating System Release"].each do |label|
+ name = label.gsub(/\s+/, '')
+ value = Facter.value(name)
+ ret += option(label, value)
+ end
+ ret += "\n"
+
+ count = 1
+
+ # Produce output for each type.
+ types.each do |type|
+ features = type.features
+ ret += "\n" # add a trailing newline
+
+ # Now build up a table of provider suitability.
+ headers = %w{Provider Suitable?} + features.collect { |f| f.to_s }.sort
+
+ table_data = {}
+
+ functional = false
+ notes = []
+ begin
+ default = type.defaultprovider.name
+ rescue Puppet::DevError
+ default = "none"
end
- types.sort! { |a,b| a.name.to_s <=> b.name.to_s }
-
- command_line = Puppet::Util::CommandLine.new
- types.reject! { |type| ! command_line.args.include?(type.name.to_s) } unless command_line.args.empty?
-
- ret = "Details about this host:\n\n"
-
- # Throw some facts in there, so we know where the report is from.
- ["Ruby Version", "Puppet Version", "Operating System", "Operating System Release"].each do |label|
- name = label.gsub(/\s+/, '')
- value = Facter.value(name)
- ret += option(label, value)
- end
- ret += "\n"
-
- count = 1
-
- # Produce output for each type.
- types.each do |type|
- features = type.features
- ret += "\n" # add a trailing newline
-
- # Now build up a table of provider suitability.
- headers = %w{Provider Suitable?} + features.collect { |f| f.to_s }.sort
-
- table_data = {}
-
- functional = false
- notes = []
- begin
- default = type.defaultprovider.name
- rescue Puppet::DevError
- default = "none"
- end
- type.providers.sort { |a,b| a.to_s <=> b.to_s }.each do |pname|
- data = []
- table_data[pname] = data
- provider = type.provider(pname)
-
- # Add the suitability note
- if missing = provider.suitable?(false) and missing.empty?
- data << "**X**"
- suit = true
- functional = true
- else
- data << "[#{count}]_" # A pointer to the appropriate footnote
- suit = false
+ type.providers.sort { |a,b| a.to_s <=> b.to_s }.each do |pname|
+ data = []
+ table_data[pname] = data
+ provider = type.provider(pname)
+
+ # Add the suitability note
+ if missing = provider.suitable?(false) and missing.empty?
+ data << "**X**"
+ suit = true
+ functional = true
+ else
+ data << "[#{count}]_" # A pointer to the appropriate footnote
+ suit = false
+ end
+
+ # Add a footnote with the details about why this provider is unsuitable, if that's the case
+ unless suit
+ details = ".. [#{count}]\n"
+ missing.each do |test, values|
+ case test
+ when :exists
+ details += " - Missing files #{values.join(", ")}\n"
+ when :variable
+ values.each do |name, facts|
+ if Puppet.settings.valid?(name)
+ details += " - Setting #{name} (currently #{Puppet.settings.value(name).inspect}) not in list #{facts.join(", ")}\n"
+ else
+ details += " - Fact #{name} (currently #{Facter.value(name).inspect}) not in list #{facts.join(", ")}\n"
+ end
end
+ when :true
+ details += " - Got #{values} true tests that should have been false\n"
+ when :false
+ details += " - Got #{values} false tests that should have been true\n"
+ when :feature
+ details += " - Missing features #{values.collect { |f| f.to_s }.join(",")}\n"
+ end
+ end
+ notes << details
- # Add a footnote with the details about why this provider is unsuitable, if that's the case
- unless suit
- details = ".. [#{count}]\n"
- missing.each do |test, values|
- case test
- when :exists
- details += " - Missing files #{values.join(", ")}\n"
- when :variable
- values.each do |name, facts|
- if Puppet.settings.valid?(name)
- details += " - Setting #{name} (currently #{Puppet.settings.value(name).inspect}) not in list #{facts.join(", ")}\n"
- else
- details += " - Fact #{name} (currently #{Facter.value(name).inspect}) not in list #{facts.join(", ")}\n"
- end
- end
- when :true
- details += " - Got #{values} true tests that should have been false\n"
- when :false
- details += " - Got #{values} false tests that should have been true\n"
- when :feature
- details += " - Missing features #{values.collect { |f| f.to_s }.join(",")}\n"
- end
- end
- notes << details
-
- count += 1
- end
+ count += 1
+ end
- # Add a note for every feature
- features.each do |feature|
- if provider.features.include?(feature)
- data << "**X**"
- else
- data << ""
- end
- end
+ # Add a note for every feature
+ features.each do |feature|
+ if provider.features.include?(feature)
+ data << "**X**"
+ else
+ data << ""
end
+ end
+ end
- ret += h(type.name.to_s + "_", 2)
-
- ret += ".. _#{type.name}: #{"http://reductivelabs.com/trac/puppet/wiki/TypeReference##{type.name}"}\n\n"
- ret += option("Default provider", default)
- ret += doctable(headers, table_data)
+ ret += h(type.name.to_s + "_", 2)
- notes.each do |note|
- ret += note + "\n"
- end
+ ret += ".. _#{type.name}: #{"http://reductivelabs.com/trac/puppet/wiki/TypeReference##{type.name}"}\n\n"
+ ret += option("Default provider", default)
+ ret += doctable(headers, table_data)
- ret += "\n"
+ notes.each do |note|
+ ret += note + "\n"
end
ret += "\n"
+ end
+
+ ret += "\n"
- ret
+ ret
end
providers.header = "
Puppet resource types are usually backed by multiple implementations called ``providers``,
diff --git a/lib/puppet/reference/report.rb b/lib/puppet/reference/report.rb
index 2ea00b6d6..481ca2dc1 100644
--- a/lib/puppet/reference/report.rb
+++ b/lib/puppet/reference/report.rb
@@ -1,7 +1,7 @@
require 'puppet/reports'
report = Puppet::Util::Reference.newreference :report, :doc => "All available transaction reports" do
- Puppet::Reports.reportdocs
+ Puppet::Reports.reportdocs
end
report.header = "
diff --git a/lib/puppet/reference/type.rb b/lib/puppet/reference/type.rb
index c52e764d6..be8742edc 100644
--- a/lib/puppet/reference/type.rb
+++ b/lib/puppet/reference/type.rb
@@ -1,113 +1,113 @@
type = Puppet::Util::Reference.newreference :type, :doc => "All Puppet resource types and all their details" do
- types = {}
- Puppet::Type.loadall
+ types = {}
+ Puppet::Type.loadall
- Puppet::Type.eachtype { |type|
- next if type.name == :puppet
- next if type.name == :component
- types[type.name] = type
- }
+ Puppet::Type.eachtype { |type|
+ next if type.name == :puppet
+ next if type.name == :component
+ types[type.name] = type
+ }
- str = %{
+ str = %{
- Resource Types
- --------------
+ Resource Types
+ --------------
- - The *namevar* is the parameter used to uniquely identify a type instance.
- This is the parameter that gets assigned when a string is provided before
- the colon in a type declaration. In general, only developers will need to
- worry about which parameter is the ``namevar``.
+ - The *namevar* is the parameter used to uniquely identify a type instance.
+ This is the parameter that gets assigned when a string is provided before
+ the colon in a type declaration. In general, only developers will need to
+ worry about which parameter is the ``namevar``.
- In the following code::
+ In the following code::
- file { "/etc/passwd":
- owner => root,
- group => root,
- mode => 644
- }
+ file { "/etc/passwd":
+ owner => root,
+ group => root,
+ mode => 644
+ }
- ``/etc/passwd`` is considered the title of the file object (used for things like
- dependency handling), and because ``path`` is the namevar for ``file``, that
- string is assigned to the ``path`` parameter.
+ ``/etc/passwd`` is considered the title of the file object (used for things like
+ dependency handling), and because ``path`` is the namevar for ``file``, that
+ string is assigned to the ``path`` parameter.
- *Parameters* determine the specific configuration of the instance. They either
- directly modify the system (internally, these are called properties) or they affect
- how the instance behaves (e.g., adding a search path for ``exec`` instances or determining recursion on ``file`` instances).
+ directly modify the system (internally, these are called properties) or they affect
+ how the instance behaves (e.g., adding a search path for ``exec`` instances or determining recursion on ``file`` instances).
- *Providers* provide low-level functionality for a given resource type. This is
- usually in the form of calling out to external commands.
+ usually in the form of calling out to external commands.
- When required binaries are specified for providers, fully qualifed paths
- indicate that the binary must exist at that specific path and unqualified
- binaries indicate that Puppet will search for the binary using the shell
- path.
+ When required binaries are specified for providers, fully qualifed paths
+ indicate that the binary must exist at that specific path and unqualified
+ binaries indicate that Puppet will search for the binary using the shell
+ path.
- *Features* are abilities that some providers might not support. You can use the list
- of supported features to determine how a given provider can be used.
+ of supported features to determine how a given provider can be used.
- Resource types define features they can use, and providers can be tested to see
- which features they provide.
+ Resource types define features they can use, and providers can be tested to see
+ which features they provide.
- }
+ }
- types.sort { |a,b|
- a.to_s <=> b.to_s
- }.each { |name,type|
+ types.sort { |a,b|
+ a.to_s <=> b.to_s
+ }.each { |name,type|
- str += "
+ str += "
----------------
"
- str += h(name, 3)
- str += scrub(type.doc) + "\n\n"
-
- # Handle the feature docs.
- if featuredocs = type.featuredocs
- str += h("Features", 4)
- str += featuredocs
- end
-
- docs = {}
- type.validproperties.sort { |a,b|
- a.to_s <=> b.to_s
- }.reject { |sname|
- property = type.propertybyname(sname)
- property.nodoc
- }.each { |sname|
- property = type.propertybyname(sname)
-
- raise "Could not retrieve property #{sname} on type #{type.name}" unless property
-
- doc = nil
- unless doc = property.doc
- $stderr.puts "No docs for #{type}[#{sname}]"
- next
- end
- doc = doc.dup
- tmp = doc
- tmp = scrub(tmp)
-
- docs[sname] = tmp
- }
-
- str += h("Parameters", 4) + "\n"
- type.parameters.sort { |a,b|
- a.to_s <=> b.to_s
- }.each { |name,param|
- #docs[name] = indent(scrub(type.paramdoc(name)), $tab)
- docs[name] = scrub(type.paramdoc(name))
- }
-
- additional_key_attributes = type.key_attributes - [:name]
- docs.sort { |a, b|
- a[0].to_s <=> b[0].to_s
- }.each { |name, doc|
- str += paramwrap(name, doc, :namevar => additional_key_attributes.include?(name))
- }
- str += "\n"
+ str += h(name, 3)
+ str += scrub(type.doc) + "\n\n"
+
+ # Handle the feature docs.
+ if featuredocs = type.featuredocs
+ str += h("Features", 4)
+ str += featuredocs
+ end
+
+ docs = {}
+ type.validproperties.sort { |a,b|
+ a.to_s <=> b.to_s
+ }.reject { |sname|
+ property = type.propertybyname(sname)
+ property.nodoc
+ }.each { |sname|
+ property = type.propertybyname(sname)
+
+ raise "Could not retrieve property #{sname} on type #{type.name}" unless property
+
+ doc = nil
+ unless doc = property.doc
+ $stderr.puts "No docs for #{type}[#{sname}]"
+ next
+ end
+ doc = doc.dup
+ tmp = doc
+ tmp = scrub(tmp)
+
+ docs[sname] = tmp
+ }
+
+ str += h("Parameters", 4) + "\n"
+ type.parameters.sort { |a,b|
+ a.to_s <=> b.to_s
+ }.each { |name,param|
+ #docs[name] = indent(scrub(type.paramdoc(name)), $tab)
+ docs[name] = scrub(type.paramdoc(name))
+ }
+
+ additional_key_attributes = type.key_attributes - [:name]
+ docs.sort { |a, b|
+ a[0].to_s <=> b[0].to_s
+ }.each { |name, doc|
+ str += paramwrap(name, doc, :namevar => additional_key_attributes.include?(name))
}
+ str += "\n"
+ }
- str
+ str
end
diff --git a/lib/puppet/relationship.rb b/lib/puppet/relationship.rb
index b3908701c..7079fb44b 100644
--- a/lib/puppet/relationship.rb
+++ b/lib/puppet/relationship.rb
@@ -12,83 +12,83 @@ require 'puppet/util/pson'
# It used to be a subclass of GRATR::Edge, but that class has weird hash
# overrides that dramatically slow down the graphing.
class Puppet::Relationship
- extend Puppet::Util::Pson
- attr_accessor :source, :target, :callback
+ extend Puppet::Util::Pson
+ attr_accessor :source, :target, :callback
- attr_reader :event
+ attr_reader :event
- def self.from_pson(pson)
- source = pson["source"]
- target = pson["target"]
+ def self.from_pson(pson)
+ source = pson["source"]
+ target = pson["target"]
- args = {}
- if event = pson["event"]
- args[:event] = event
- end
- if callback = pson["callback"]
- args[:callback] = callback
- end
-
- new(source, target, args)
+ args = {}
+ if event = pson["event"]
+ args[:event] = event
end
-
- def event=(event)
- raise ArgumentError, "You must pass a callback for non-NONE events" if event != :NONE and ! callback
- @event = event
+ if callback = pson["callback"]
+ args[:callback] = callback
end
- def initialize(source, target, options = {})
- @source, @target = source, target
+ new(source, target, args)
+ end
- options = (options || {}).inject({}) { |h,a| h[a[0].to_sym] = a[1]; h }
- [:callback, :event].each do |option|
- if value = options[option]
- send(option.to_s + "=", value)
- end
- end
- end
+ def event=(event)
+ raise ArgumentError, "You must pass a callback for non-NONE events" if event != :NONE and ! callback
+ @event = event
+ end
- # Does the passed event match our event? This is where the meaning
- # of :NONE comes from.
- def match?(event)
- if self.event.nil? or event == :NONE or self.event == :NONE
- return false
- elsif self.event == :ALL_EVENTS or event == self.event
- return true
- else
- return false
- end
- end
+ def initialize(source, target, options = {})
+ @source, @target = source, target
- def label
- result = {}
- result[:callback] = callback if callback
- result[:event] = event if event
- result
+ options = (options || {}).inject({}) { |h,a| h[a[0].to_sym] = a[1]; h }
+ [:callback, :event].each do |option|
+ if value = options[option]
+ send(option.to_s + "=", value)
+ end
end
-
- def ref
- "#{source} => #{target}"
+ end
+
+ # Does the passed event match our event? This is where the meaning
+ # of :NONE comes from.
+ def match?(event)
+ if self.event.nil? or event == :NONE or self.event == :NONE
+ return false
+ elsif self.event == :ALL_EVENTS or event == self.event
+ return true
+ else
+ return false
end
-
- def to_pson_data_hash
- data = {
- 'source' => source.to_s,
- 'target' => target.to_s
- }
-
- ["event", "callback"].each do |attr|
- next unless value = send(attr)
- data[attr] = value
- end
- data
+ end
+
+ def label
+ result = {}
+ result[:callback] = callback if callback
+ result[:event] = event if event
+ result
+ end
+
+ def ref
+ "#{source} => #{target}"
+ end
+
+ def to_pson_data_hash
+ data = {
+ 'source' => source.to_s,
+ 'target' => target.to_s
+ }
+
+ ["event", "callback"].each do |attr|
+ next unless value = send(attr)
+ data[attr] = value
end
+ data
+ end
- def to_pson(*args)
- to_pson_data_hash.to_pson(*args)
- end
+ def to_pson(*args)
+ to_pson_data_hash.to_pson(*args)
+ end
- def to_s
- ref
- end
+ def to_s
+ ref
+ end
end
diff --git a/lib/puppet/reports.rb b/lib/puppet/reports.rb
index 2e1f1e2ce..3ebd16e30 100755
--- a/lib/puppet/reports.rb
+++ b/lib/puppet/reports.rb
@@ -2,48 +2,48 @@ require 'puppet/util/instance_loader'
# A simple mechanism for loading and returning reports.
class Puppet::Reports
- extend Puppet::Util::ClassGen
- extend Puppet::Util::InstanceLoader
+ extend Puppet::Util::ClassGen
+ extend Puppet::Util::InstanceLoader
- # Set up autoloading and retrieving of reports.
- instance_load :report, 'puppet/reports'
+ # Set up autoloading and retrieving of reports.
+ instance_load :report, 'puppet/reports'
- class << self
- attr_reader :hooks
- end
+ class << self
+ attr_reader :hooks
+ end
- # Add a new report type.
- def self.register_report(name, options = {}, &block)
- name = symbolize(name)
+ # Add a new report type.
+ def self.register_report(name, options = {}, &block)
+ name = symbolize(name)
- mod = genmodule(name, :extend => Puppet::Util::Docs, :hash => instance_hash(:report), :block => block)
+ mod = genmodule(name, :extend => Puppet::Util::Docs, :hash => instance_hash(:report), :block => block)
- mod.useyaml = true if options[:useyaml]
+ mod.useyaml = true if options[:useyaml]
- mod.send(:define_method, :report_name) do
- name
- end
+ mod.send(:define_method, :report_name) do
+ name
end
+ end
- # Collect the docs for all of our reports.
- def self.reportdocs
- docs = ""
-
- # Use this method so they all get loaded
- instance_loader(:report).loadall
- loaded_instances(:report).sort { |a,b| a.to_s <=> b.to_s }.each do |name|
- mod = self.report(name)
- docs += "#{name}\n#{"-" * name.to_s.length}\n"
+ # Collect the docs for all of our reports.
+ def self.reportdocs
+ docs = ""
- docs += Puppet::Util::Docs.scrub(mod.doc) + "\n\n"
- end
+ # Use this method so they all get loaded
+ instance_loader(:report).loadall
+ loaded_instances(:report).sort { |a,b| a.to_s <=> b.to_s }.each do |name|
+ mod = self.report(name)
+ docs += "#{name}\n#{"-" * name.to_s.length}\n"
- docs
+ docs += Puppet::Util::Docs.scrub(mod.doc) + "\n\n"
end
- # List each of the reports.
- def self.reports
- instance_loader(:report).loadall
- loaded_instances(:report)
- end
+ docs
+ end
+
+ # List each of the reports.
+ def self.reports
+ instance_loader(:report).loadall
+ loaded_instances(:report)
+ end
end
diff --git a/lib/puppet/reports/http.rb b/lib/puppet/reports/http.rb
index d74782cf8..f1a74195d 100644
--- a/lib/puppet/reports/http.rb
+++ b/lib/puppet/reports/http.rb
@@ -4,19 +4,19 @@ require 'uri'
Puppet::Reports.register_report(:http) do
- desc <<-DESC
- Send report information via HTTP to the ``reporturl``. Each host sends
- its report as a YAML dump and this sends this YAML to a client via HTTP POST.
- The YAML is the `report` parameter of the request."
- DESC
+ desc <<-DESC
+ Send report information via HTTP to the ``reporturl``. Each host sends
+ its report as a YAML dump and this sends this YAML to a client via HTTP POST.
+ The YAML is the `report` parameter of the request."
+ DESC
- def process
- url = URI.parse(Puppet[:reporturl])
- req = Net::HTTP::Post.new(url.path)
- req.body = self.to_yaml
- req.content_type = "application/x-yaml"
- Net::HTTP.new(url.host, url.port).start {|http|
- http.request(req)
- }
- end
+ def process
+ url = URI.parse(Puppet[:reporturl])
+ req = Net::HTTP::Post.new(url.path)
+ req.body = self.to_yaml
+ req.content_type = "application/x-yaml"
+ Net::HTTP.new(url.host, url.port).start {|http|
+ http.request(req)
+ }
+ end
end
diff --git a/lib/puppet/reports/log.rb b/lib/puppet/reports/log.rb
index 827572c2c..1fc6876a6 100644
--- a/lib/puppet/reports/log.rb
+++ b/lib/puppet/reports/log.rb
@@ -1,14 +1,14 @@
require 'puppet/reports'
Puppet::Reports.register_report(:log) do
- desc "Send all received logs to the local log destinations. Usually
- the log destination is syslog."
+ desc "Send all received logs to the local log destinations. Usually
+ the log destination is syslog."
- def process
- self.logs.each do |log|
- log.source = "//#{self.host}/#{log.source}"
- Puppet::Util::Log.newmessage(log)
- end
+ def process
+ self.logs.each do |log|
+ log.source = "//#{self.host}/#{log.source}"
+ Puppet::Util::Log.newmessage(log)
end
+ end
end
diff --git a/lib/puppet/reports/rrdgraph.rb b/lib/puppet/reports/rrdgraph.rb
index 2f27f63af..9fbeb60e8 100644
--- a/lib/puppet/reports/rrdgraph.rb
+++ b/lib/puppet/reports/rrdgraph.rb
@@ -1,129 +1,129 @@
Puppet::Reports.register_report(:rrdgraph) do
- desc "Graph all available data about hosts using the RRD library. You
- must have the Ruby RRDtool library installed to use this report, which
- you can get from `the RubyRRDTool RubyForge page`_. This package may also
- be available as ``ruby-rrd`` or ``rrdtool-ruby`` in your distribution's package
- management system. The library and/or package will both require the binary
- ``rrdtool`` package from your distribution to be installed.
-
- .. _the RubyRRDTool RubyForge page: http://rubyforge.org/projects/rubyrrdtool/
-
- This report will create, manage, and graph RRD database files for each
- of the metrics generated during transactions, and it will create a
- few simple html files to display the reporting host's graphs. At this
- point, it will not create a common index file to display links to
- all hosts.
-
- All RRD files and graphs get created in the ``rrddir`` directory. If
- you want to serve these publicly, you should be able to just alias that
- directory in a web server.
-
- If you really know what you're doing, you can tune the ``rrdinterval``,
- which defaults to the ``runinterval``."
-
- def hostdir
- @hostdir ||= File.join(Puppet[:rrddir], self.host)
- end
-
- def htmlfile(type, graphs, field)
- file = File.join(hostdir, "#{type}.html")
- File.open(file, "w") do |of|
- of.puts "<html><head><title>#{type.capitalize} graphs for #{host}</title></head><body>"
-
- graphs.each do |graph|
- if field == :first
- name = graph.sub(/-\w+.png/, '').capitalize
- else
- name = graph.sub(/\w+-/, '').sub(".png", '').capitalize
- end
- of.puts "<img src=#{graph}><br>"
- end
- of.puts "</body></html>"
+ desc "Graph all available data about hosts using the RRD library. You
+ must have the Ruby RRDtool library installed to use this report, which
+ you can get from `the RubyRRDTool RubyForge page`_. This package may also
+ be available as ``ruby-rrd`` or ``rrdtool-ruby`` in your distribution's package
+ management system. The library and/or package will both require the binary
+ ``rrdtool`` package from your distribution to be installed.
+
+ .. _the RubyRRDTool RubyForge page: http://rubyforge.org/projects/rubyrrdtool/
+
+ This report will create, manage, and graph RRD database files for each
+ of the metrics generated during transactions, and it will create a
+ few simple html files to display the reporting host's graphs. At this
+ point, it will not create a common index file to display links to
+ all hosts.
+
+ All RRD files and graphs get created in the ``rrddir`` directory. If
+ you want to serve these publicly, you should be able to just alias that
+ directory in a web server.
+
+ If you really know what you're doing, you can tune the ``rrdinterval``,
+ which defaults to the ``runinterval``."
+
+ def hostdir
+ @hostdir ||= File.join(Puppet[:rrddir], self.host)
+ end
+
+ def htmlfile(type, graphs, field)
+ file = File.join(hostdir, "#{type}.html")
+ File.open(file, "w") do |of|
+ of.puts "<html><head><title>#{type.capitalize} graphs for #{host}</title></head><body>"
+
+ graphs.each do |graph|
+ if field == :first
+ name = graph.sub(/-\w+.png/, '').capitalize
+ else
+ name = graph.sub(/\w+-/, '').sub(".png", '').capitalize
end
-
- file
+ of.puts "<img src=#{graph}><br>"
+ end
+ of.puts "</body></html>"
end
- def mkhtml
- images = Dir.entries(hostdir).find_all { |d| d =~ /\.png/ }
+ file
+ end
- periodorder = %w{daily weekly monthly yearly}
+ def mkhtml
+ images = Dir.entries(hostdir).find_all { |d| d =~ /\.png/ }
- periods = {}
- types = {}
- images.each do |n|
- type, period = n.sub(".png", '').split("-")
- periods[period] ||= []
- types[type] ||= []
- periods[period] << n
- types[type] << n
- end
+ periodorder = %w{daily weekly monthly yearly}
- files = []
- # Make the period html files
- periodorder.each do |period|
- unless ary = periods[period]
- raise Puppet::Error, "Could not find graphs for #{period}"
- end
- files << htmlfile(period, ary, :first)
- end
+ periods = {}
+ types = {}
+ images.each do |n|
+ type, period = n.sub(".png", '').split("-")
+ periods[period] ||= []
+ types[type] ||= []
+ periods[period] << n
+ types[type] << n
+ end
- # make the type html files
- types.sort { |a,b| a[0] <=> b[0] }.each do |type, ary|
- newary = []
- periodorder.each do |period|
- if graph = ary.find { |g| g.include?("-#{period}.png") }
- newary << graph
- else
- raise "Could not find #{type}-#{period} graph"
- end
- end
-
- files << htmlfile(type, newary, :second)
- end
+ files = []
+ # Make the period html files
+ periodorder.each do |period|
+ unless ary = periods[period]
+ raise Puppet::Error, "Could not find graphs for #{period}"
+ end
+ files << htmlfile(period, ary, :first)
+ end
- File.open(File.join(hostdir, "index.html"), "w") do |of|
- of.puts "<html><head><title>Report graphs for #{host}</title></head><body>"
- files.each do |file|
- of.puts "<a href='#{File.basename(file)}'>#{File.basename(file).sub(".html",'').capitalize}</a><br/>"
- end
- of.puts "</body></html>"
+ # make the type html files
+ types.sort { |a,b| a[0] <=> b[0] }.each do |type, ary|
+ newary = []
+ periodorder.each do |period|
+ if graph = ary.find { |g| g.include?("-#{period}.png") }
+ newary << graph
+ else
+ raise "Could not find #{type}-#{period} graph"
end
+ end
+
+ files << htmlfile(type, newary, :second)
end
- def process(time = nil)
- time ||= Time.now.to_i
+ File.open(File.join(hostdir, "index.html"), "w") do |of|
+ of.puts "<html><head><title>Report graphs for #{host}</title></head><body>"
+ files.each do |file|
+ of.puts "<a href='#{File.basename(file)}'>#{File.basename(file).sub(".html",'').capitalize}</a><br/>"
+ end
+ of.puts "</body></html>"
+ end
+ end
- unless File.directory?(hostdir) and FileTest.writable?(hostdir)
- # Some hackishness to create the dir with all of the right modes and ownership
- config = Puppet::Util::Settings.new
- config.setdefaults(:reports, :hostdir => {:default => hostdir, :owner => 'service', :mode => 0755, :group => 'service', :desc => "eh"})
+ def process(time = nil)
+ time ||= Time.now.to_i
- # This creates the dir.
- config.use(:reports)
- end
+ unless File.directory?(hostdir) and FileTest.writable?(hostdir)
+ # Some hackishness to create the dir with all of the right modes and ownership
+ config = Puppet::Util::Settings.new
+ config.setdefaults(:reports, :hostdir => {:default => hostdir, :owner => 'service', :mode => 0755, :group => 'service', :desc => "eh"})
- self.metrics.each do |name, metric|
- metric.basedir = hostdir
+ # This creates the dir.
+ config.use(:reports)
+ end
- if name == "time"
- timeclean(metric)
- end
+ self.metrics.each do |name, metric|
+ metric.basedir = hostdir
- metric.store(time)
+ if name == "time"
+ timeclean(metric)
+ end
- metric.graph
- end
+ metric.store(time)
- mkhtml unless FileTest.exists?(File.join(hostdir, "index.html"))
+ metric.graph
end
- # Unfortunately, RRD does not deal well with changing lists of values,
- # so we have to pick a list of values and stick with it. In this case,
- # that means we record the total time, the config time, and that's about
- # it. We should probably send each type's time as a separate metric.
- def timeclean(metric)
- metric.values = metric.values.find_all { |name, label, value| [:total, :config_retrieval].include?(name) }
- end
+ mkhtml unless FileTest.exists?(File.join(hostdir, "index.html"))
+ end
+
+ # Unfortunately, RRD does not deal well with changing lists of values,
+ # so we have to pick a list of values and stick with it. In this case,
+ # that means we record the total time, the config time, and that's about
+ # it. We should probably send each type's time as a separate metric.
+ def timeclean(metric)
+ metric.values = metric.values.find_all { |name, label, value| [:total, :config_retrieval].include?(name) }
+ end
end
diff --git a/lib/puppet/reports/store.rb b/lib/puppet/reports/store.rb
index 384f0eb0a..65159fc07 100644
--- a/lib/puppet/reports/store.rb
+++ b/lib/puppet/reports/store.rb
@@ -1,60 +1,60 @@
require 'puppet'
Puppet::Reports.register_report(:store) do
- desc "Store the yaml report on disk. Each host sends its report as a YAML dump
- and this just stores the file on disk, in the ``reportdir`` directory.
-
- These files collect quickly -- one every half hour -- so it is a good idea
- to perform some maintenance on them if you use this report (it's the only
- default report)."
-
- def mkclientdir(client, dir)
- config = Puppet::Util::Settings.new
-
- config.setdefaults(
- "reportclient-#{client}".to_sym,
- "client-#{client}-dir" => { :default => dir,
- :mode => 0750,
- :desc => "Client dir for #{client}",
- :owner => 'service',
- :group => 'service'
- },
+ desc "Store the yaml report on disk. Each host sends its report as a YAML dump
+ and this just stores the file on disk, in the ``reportdir`` directory.
+
+ These files collect quickly -- one every half hour -- so it is a good idea
+ to perform some maintenance on them if you use this report (it's the only
+ default report)."
+
+ def mkclientdir(client, dir)
+ config = Puppet::Util::Settings.new
+
+ config.setdefaults(
+ "reportclient-#{client}".to_sym,
+ "client-#{client}-dir" => { :default => dir,
+ :mode => 0750,
+ :desc => "Client dir for #{client}",
+ :owner => 'service',
+ :group => 'service'
+ },
- :noop => [false, "Used by settings internally."]
- )
+ :noop => [false, "Used by settings internally."]
+ )
- config.use("reportclient-#{client}".to_sym)
- end
-
- def process
- # We don't want any tracking back in the fs. Unlikely, but there
- # you go.
- client = self.host.gsub("..",".")
+ config.use("reportclient-#{client}".to_sym)
+ end
- dir = File.join(Puppet[:reportdir], client)
+ def process
+ # We don't want any tracking back in the fs. Unlikely, but there
+ # you go.
+ client = self.host.gsub("..",".")
- mkclientdir(client, dir) unless FileTest.exists?(dir)
+ dir = File.join(Puppet[:reportdir], client)
- # Now store the report.
- now = Time.now.gmtime
- name = %w{year month day hour min}.collect do |method|
- # Make sure we're at least two digits everywhere
- "%02d" % now.send(method).to_s
- end.join("") + ".yaml"
+ mkclientdir(client, dir) unless FileTest.exists?(dir)
- file = File.join(dir, name)
+ # Now store the report.
+ now = Time.now.gmtime
+ name = %w{year month day hour min}.collect do |method|
+ # Make sure we're at least two digits everywhere
+ "%02d" % now.send(method).to_s
+ end.join("") + ".yaml"
- begin
- File.open(file, "w", 0640) do |f|
- f.print to_yaml
- end
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.warning "Could not write report for #{client} at #{file}: #{detail}"
- end
+ file = File.join(dir, name)
- # Only testing cares about the return value
- file
+ begin
+ File.open(file, "w", 0640) do |f|
+ f.print to_yaml
+ end
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.warning "Could not write report for #{client} at #{file}: #{detail}"
end
+
+ # Only testing cares about the return value
+ file
+ end
end
diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb
index f77d3c9fb..652104096 100644
--- a/lib/puppet/reports/tagmail.rb
+++ b/lib/puppet/reports/tagmail.rb
@@ -5,165 +5,165 @@ require 'net/smtp'
require 'time'
Puppet::Reports.register_report(:tagmail) do
- desc "This report sends specific log messages to specific email addresses
- based on the tags in the log messages. See the
- `UsingTags tag documentation`:trac: for more information
- on tags.
-
- To use this report, you must create a ``tagmail.conf`` (in the location
- specified by ``tagmap``). This is a simple file that maps tags to
- email addresses: Any log messages in the report that match the specified
- tags will be sent to the specified email addresses.
-
- Tags must be comma-separated, and they can be negated so that messages
- only match when they do not have that tag. The tags are separated from
- the email addresses by a colon, and the email addresses should also
- be comma-separated.
-
- Lastly, there is an ``all`` tag that will always match all log messages.
-
- Here is an example tagmail.conf::
-
- all: me@domain.com
- webserver, !mailserver: httpadmins@domain.com
-
- This will send all messages to ``me@domain.com``, and all messages from
- webservers that are not also from mailservers to ``httpadmins@domain.com``.
-
- If you are using anti-spam controls, such as grey-listing, on your mail
- server you should whitelist the sending email (controlled by ``reportform`` configuration option) to ensure your email is not discarded as spam.
- "
-
-
- # Find all matching messages.
- def match(taglists)
- matching_logs = []
- taglists.each do |emails, pos, neg|
- # First find all of the messages matched by our positive tags
- messages = nil
- if pos.include?("all")
- messages = self.logs
- else
- # Find all of the messages that are tagged with any of our
- # tags.
- messages = self.logs.find_all do |log|
- pos.detect { |tag| log.tagged?(tag) }
- end
- end
-
- # Now go through and remove any messages that match our negative tags
- messages = messages.reject do |log|
- true if neg.detect do |tag| log.tagged?(tag) end
- end
-
- if messages.empty?
- Puppet.info "No messages to report to #{emails.join(",")}"
- next
- else
- matching_logs << [emails, messages.collect { |m| m.to_report }.join("\n")]
- end
+ desc "This report sends specific log messages to specific email addresses
+ based on the tags in the log messages. See the
+ `UsingTags tag documentation`:trac: for more information
+ on tags.
+
+ To use this report, you must create a ``tagmail.conf`` (in the location
+ specified by ``tagmap``). This is a simple file that maps tags to
+ email addresses: Any log messages in the report that match the specified
+ tags will be sent to the specified email addresses.
+
+ Tags must be comma-separated, and they can be negated so that messages
+ only match when they do not have that tag. The tags are separated from
+ the email addresses by a colon, and the email addresses should also
+ be comma-separated.
+
+ Lastly, there is an ``all`` tag that will always match all log messages.
+
+ Here is an example tagmail.conf::
+
+ all: me@domain.com
+ webserver, !mailserver: httpadmins@domain.com
+
+ This will send all messages to ``me@domain.com``, and all messages from
+ webservers that are not also from mailservers to ``httpadmins@domain.com``.
+
+ If you are using anti-spam controls, such as grey-listing, on your mail
+ server you should whitelist the sending email (controlled by ``reportform`` configuration option) to ensure your email is not discarded as spam.
+ "
+
+
+ # Find all matching messages.
+ def match(taglists)
+ matching_logs = []
+ taglists.each do |emails, pos, neg|
+ # First find all of the messages matched by our positive tags
+ messages = nil
+ if pos.include?("all")
+ messages = self.logs
+ else
+ # Find all of the messages that are tagged with any of our
+ # tags.
+ messages = self.logs.find_all do |log|
+ pos.detect { |tag| log.tagged?(tag) }
end
-
- matching_logs
+ end
+
+ # Now go through and remove any messages that match our negative tags
+ messages = messages.reject do |log|
+ true if neg.detect do |tag| log.tagged?(tag) end
+ end
+
+ if messages.empty?
+ Puppet.info "No messages to report to #{emails.join(",")}"
+ next
+ else
+ matching_logs << [emails, messages.collect { |m| m.to_report }.join("\n")]
+ end
end
- # Load the config file
- def parse(text)
- taglists = []
- text.split("\n").each do |line|
- taglist = emails = nil
- case line.chomp
- when /^\s*#/; next
- when /^\s*$/; next
- when /^\s*(.+)\s*:\s*(.+)\s*$/
- taglist = $1
- emails = $2.sub(/#.*$/,'')
- else
- raise ArgumentError, "Invalid tagmail config file"
- end
-
- pos = []
- neg = []
- taglist.sub(/\s+$/,'').split(/\s*,\s*/).each do |tag|
- unless tag =~ /^!?[-\w]+$/
- raise ArgumentError, "Invalid tag #{tag.inspect}"
- end
- case tag
- when /^\w+/; pos << tag
- when /^!\w+/; neg << tag.sub("!", '')
- else
- raise Puppet::Error, "Invalid tag '#{tag}'"
- end
- end
-
- # Now split the emails
- emails = emails.sub(/\s+$/,'').split(/\s*,\s*/)
- taglists << [emails, pos, neg]
+ matching_logs
+ end
+
+ # Load the config file
+ def parse(text)
+ taglists = []
+ text.split("\n").each do |line|
+ taglist = emails = nil
+ case line.chomp
+ when /^\s*#/; next
+ when /^\s*$/; next
+ when /^\s*(.+)\s*:\s*(.+)\s*$/
+ taglist = $1
+ emails = $2.sub(/#.*$/,'')
+ else
+ raise ArgumentError, "Invalid tagmail config file"
+ end
+
+ pos = []
+ neg = []
+ taglist.sub(/\s+$/,'').split(/\s*,\s*/).each do |tag|
+ unless tag =~ /^!?[-\w]+$/
+ raise ArgumentError, "Invalid tag #{tag.inspect}"
end
- taglists
- end
-
- # Process the report. This just calls the other associated messages.
- def process
- unless FileTest.exists?(Puppet[:tagmap])
- Puppet.notice "Cannot send tagmail report; no tagmap file #{Puppet[:tagmap]}"
- return
+ case tag
+ when /^\w+/; pos << tag
+ when /^!\w+/; neg << tag.sub("!", '')
+ else
+ raise Puppet::Error, "Invalid tag '#{tag}'"
end
+ end
- taglists = parse(File.read(Puppet[:tagmap]))
-
- # Now find any appropriately tagged messages.
- reports = match(taglists)
-
- send(reports)
+ # Now split the emails
+ emails = emails.sub(/\s+$/,'').split(/\s*,\s*/)
+ taglists << [emails, pos, neg]
+ end
+ taglists
+ end
+
+ # Process the report. This just calls the other associated messages.
+ def process
+ unless FileTest.exists?(Puppet[:tagmap])
+ Puppet.notice "Cannot send tagmail report; no tagmap file #{Puppet[:tagmap]}"
+ return
end
- # Send the email reports.
- def send(reports)
- pid = fork do
- if Puppet[:smtpserver] != "none"
- begin
- Net::SMTP.start(Puppet[:smtpserver]) do |smtp|
- reports.each do |emails, messages|
- smtp.open_message_stream(Puppet[:reportfrom], *emails) do |p|
- p.puts "From: #{Puppet[:reportfrom]}"
- p.puts "Subject: Puppet Report for #{self.host}"
- p.puts "To: " + emails.join(", ")
- p.puts "Date: #{Time.now.rfc2822}"
- p.puts
- p.puts messages
- end
- end
- end
- rescue => detail
- puts detail.backtrace if Puppet[:debug]
- raise Puppet::Error,
- "Could not send report emails through smtp: #{detail}"
- end
- elsif Puppet[:sendmail] != ""
- begin
- reports.each do |emails, messages|
- # We need to open a separate process for every set of email addresses
- IO.popen(Puppet[:sendmail] + " " + emails.join(" "), "w") do |p|
- p.puts "From: #{Puppet[:reportfrom]}"
- p.puts "Subject: Puppet Report for #{self.host}"
- p.puts "To: " + emails.join(", ")
-
- p.puts messages
- end
- end
- rescue => detail
- puts detail.backtrace if Puppet[:debug]
- raise Puppet::Error,
- "Could not send report emails via sendmail: #{detail}"
- end
- else
- raise Puppet::Error, "SMTP server is unset and could not find sendmail"
+ taglists = parse(File.read(Puppet[:tagmap]))
+
+ # Now find any appropriately tagged messages.
+ reports = match(taglists)
+
+ send(reports)
+ end
+
+ # Send the email reports.
+ def send(reports)
+ pid = fork do
+ if Puppet[:smtpserver] != "none"
+ begin
+ Net::SMTP.start(Puppet[:smtpserver]) do |smtp|
+ reports.each do |emails, messages|
+ smtp.open_message_stream(Puppet[:reportfrom], *emails) do |p|
+ p.puts "From: #{Puppet[:reportfrom]}"
+ p.puts "Subject: Puppet Report for #{self.host}"
+ p.puts "To: " + emails.join(", ")
+ p.puts "Date: #{Time.now.rfc2822}"
+ p.puts
+ p.puts messages
+ end
end
+ end
+ rescue => detail
+ puts detail.backtrace if Puppet[:debug]
+ raise Puppet::Error,
+ "Could not send report emails through smtp: #{detail}"
end
-
- # Don't bother waiting for the pid to return.
- Process.detach(pid)
+ elsif Puppet[:sendmail] != ""
+ begin
+ reports.each do |emails, messages|
+ # We need to open a separate process for every set of email addresses
+ IO.popen(Puppet[:sendmail] + " " + emails.join(" "), "w") do |p|
+ p.puts "From: #{Puppet[:reportfrom]}"
+ p.puts "Subject: Puppet Report for #{self.host}"
+ p.puts "To: " + emails.join(", ")
+
+ p.puts messages
+ end
+ end
+ rescue => detail
+ puts detail.backtrace if Puppet[:debug]
+ raise Puppet::Error,
+ "Could not send report emails via sendmail: #{detail}"
+ end
+ else
+ raise Puppet::Error, "SMTP server is unset and could not find sendmail"
+ end
end
+
+ # Don't bother waiting for the pid to return.
+ Process.detach(pid)
+ end
end
diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb
index cc84b7663..9894f2f9e 100644
--- a/lib/puppet/resource.rb
+++ b/lib/puppet/resource.rb
@@ -5,475 +5,475 @@ require 'puppet/util/pson'
# The simplest resource class. Eventually it will function as the
# base class for all resource-like behaviour.
class Puppet::Resource
- include Puppet::Util::Tagging
+ include Puppet::Util::Tagging
- require 'puppet/resource/type_collection_helper'
- include Puppet::Resource::TypeCollectionHelper
+ require 'puppet/resource/type_collection_helper'
+ include Puppet::Resource::TypeCollectionHelper
- extend Puppet::Util::Pson
- include Enumerable
- attr_accessor :file, :line, :catalog, :exported, :virtual, :validate_parameters, :strict
- attr_reader :namespaces
+ extend Puppet::Util::Pson
+ include Enumerable
+ attr_accessor :file, :line, :catalog, :exported, :virtual, :validate_parameters, :strict
+ attr_reader :namespaces
- require 'puppet/indirector'
- extend Puppet::Indirector
- indirects :resource, :terminus_class => :ral
+ require 'puppet/indirector'
+ extend Puppet::Indirector
+ indirects :resource, :terminus_class => :ral
- ATTRIBUTES = [:file, :line, :exported]
+ ATTRIBUTES = [:file, :line, :exported]
- def self.from_pson(pson)
- raise ArgumentError, "No resource type provided in pson data" unless type = pson['type']
- raise ArgumentError, "No resource title provided in pson data" unless title = pson['title']
+ def self.from_pson(pson)
+ raise ArgumentError, "No resource type provided in pson data" unless type = pson['type']
+ raise ArgumentError, "No resource title provided in pson data" unless title = pson['title']
- resource = new(type, title)
+ resource = new(type, title)
- if params = pson['parameters']
- params.each { |param, value| resource[param] = value }
- end
-
- if tags = pson['tags']
- tags.each { |tag| resource.tag(tag) }
- end
-
- ATTRIBUTES.each do |a|
- if value = pson[a.to_s]
- resource.send(a.to_s + "=", value)
- end
- end
-
- resource.exported ||= false
-
- resource
+ if params = pson['parameters']
+ params.each { |param, value| resource[param] = value }
end
- def to_pson_data_hash
- data = ([:type, :title, :tags] + ATTRIBUTES).inject({}) do |hash, param|
- next hash unless value = self.send(param)
- hash[param.to_s] = value
- hash
- end
-
- data["exported"] ||= false
-
- params = self.to_hash.inject({}) do |hash, ary|
- param, value = ary
-
- # Don't duplicate the title as the namevar
- next hash if param == namevar and value == title
- if value.is_a? Puppet::Resource
- hash[param] = value.to_s
- else
- hash[param] = value
- end
- hash
- end
-
- data["parameters"] = params unless params.empty?
-
- data
+ if tags = pson['tags']
+ tags.each { |tag| resource.tag(tag) }
end
- def to_pson(*args)
- to_pson_data_hash.to_pson(*args)
+ ATTRIBUTES.each do |a|
+ if value = pson[a.to_s]
+ resource.send(a.to_s + "=", value)
+ end
end
- # Proxy these methods to the parameters hash. It's likely they'll
- # be overridden at some point, but this works for now.
- %w{has_key? keys length delete empty? <<}.each do |method|
- define_method(method) do |*args|
- @parameters.send(method, *args)
- end
- end
+ resource.exported ||= false
- # Set a given parameter. Converts all passed names
- # to lower-case symbols.
- def []=(param, value)
- validate_parameter(param) if validate_parameters
- @parameters[parameter_name(param)] = value
- end
+ resource
+ end
- # Return a given parameter's value. Converts all passed names
- # to lower-case symbols.
- def [](param)
- @parameters[parameter_name(param)]
+ def to_pson_data_hash
+ data = ([:type, :title, :tags] + ATTRIBUTES).inject({}) do |hash, param|
+ next hash unless value = self.send(param)
+ hash[param.to_s] = value
+ hash
end
- def ==(other)
- return false unless other.respond_to?(:title) and self.type == other.type and self.title == other.title
+ data["exported"] ||= false
- return false unless to_hash == other.to_hash
- true
- end
-
- # Compatibility method.
- def builtin?
- builtin_type?
- end
-
- # Is this a builtin resource type?
- def builtin_type?
- resource_type.is_a?(Class)
- end
-
- # Iterate over each param/value pair, as required for Enumerable.
- def each
- @parameters.each { |p,v| yield p, v }
- end
-
- def include?(parameter)
- super || @parameters.keys.include?( parameter_name(parameter) )
- end
-
- # These two methods are extracted into a Helper
- # module, but file load order prevents me
- # from including them in the class, and I had weird
- # behaviour (i.e., sometimes it didn't work) when
- # I directly extended each resource with the helper.
- def environment
- Puppet::Node::Environment.new(@environment)
- end
-
- def environment=(env)
- if env.is_a?(String) or env.is_a?(Symbol)
- @environment = env
- else
- @environment = env.name
- end
- end
+ params = self.to_hash.inject({}) do |hash, ary|
+ param, value = ary
- %w{exported virtual strict}.each do |m|
- define_method(m+"?") do
- self.send(m)
- end
+ # Don't duplicate the title as the namevar
+ next hash if param == namevar and value == title
+ if value.is_a? Puppet::Resource
+ hash[param] = value.to_s
+ else
+ hash[param] = value
+ end
+ hash
end
- # Create our resource.
- def initialize(type, title = nil, attributes = {})
- @parameters = {}
- @namespaces = [""]
+ data["parameters"] = params unless params.empty?
- # Set things like namespaces and strictness first.
- attributes.each do |attr, value|
- next if attr == :parameters
- send(attr.to_s + "=", value)
- end
-
- # We do namespaces first, and use tmp variables, so our title
- # canonicalization works (i.e., namespaces are set and resource
- # types can be looked up)
- tmp_type, tmp_title = extract_type_and_title(type, title)
- self.type = tmp_type
- self.title = tmp_title
-
- if params = attributes[:parameters]
- extract_parameters(params)
- end
-
- resolve_type_and_title
+ data
+ end
- tag(self.type)
- tag(self.title) if valid_tag?(self.title)
+ def to_pson(*args)
+ to_pson_data_hash.to_pson(*args)
+ end
- raise ArgumentError, "Invalid resource type #{type}" if strict? and ! resource_type
+ # Proxy these methods to the parameters hash. It's likely they'll
+ # be overridden at some point, but this works for now.
+ %w{has_key? keys length delete empty? <<}.each do |method|
+ define_method(method) do |*args|
+ @parameters.send(method, *args)
end
+ end
- def ref
- to_s
- end
+ # Set a given parameter. Converts all passed names
+ # to lower-case symbols.
+ def []=(param, value)
+ validate_parameter(param) if validate_parameters
+ @parameters[parameter_name(param)] = value
+ end
- # Find our resource.
- def resolve
- return(catalog ? catalog.resource(to_s) : nil)
- end
+ # Return a given parameter's value. Converts all passed names
+ # to lower-case symbols.
+ def [](param)
+ @parameters[parameter_name(param)]
+ end
- def title=(value)
- @unresolved_title = value
- @title = nil
- end
+ def ==(other)
+ return false unless other.respond_to?(:title) and self.type == other.type and self.title == other.title
- def resource_type
- case type
- when "Class"; find_hostclass(title)
- when "Node"; find_node(title)
- else
- find_resource_type(type)
- end
- end
+ return false unless to_hash == other.to_hash
+ true
+ end
- # Produce a simple hash of our parameters.
- def to_hash
- parse_title.merge @parameters
- end
+ # Compatibility method.
+ def builtin?
+ builtin_type?
+ end
- def to_s
- "#{type}[#{title}]"
- end
+ # Is this a builtin resource type?
+ def builtin_type?
+ resource_type.is_a?(Class)
+ end
- def uniqueness_key
- self.to_hash.values_at(*key_attributes.sort_by { |k| k.to_s })
- end
+ # Iterate over each param/value pair, as required for Enumerable.
+ def each
+ @parameters.each { |p,v| yield p, v }
+ end
- def key_attributes
- return(resource_type.respond_to? :key_attributes) ? resource_type.key_attributes : [:name]
- end
+ def include?(parameter)
+ super || @parameters.keys.include?( parameter_name(parameter) )
+ end
- # Convert our resource to Puppet code.
- def to_manifest
- "%s { '%s':\n%s\n}" % [self.type.to_s.downcase, self.title,
- @parameters.collect { |p, v|
- if v.is_a? Array
- " #{p} => [\'#{v.join("','")}\']"
- else
- " #{p} => \'#{v}\'"
- end
- }.join(",\n")
- ]
- end
+ # These two methods are extracted into a Helper
+ # module, but file load order prevents me
+ # from including them in the class, and I had weird
+ # behaviour (i.e., sometimes it didn't work) when
+ # I directly extended each resource with the helper.
+ def environment
+ Puppet::Node::Environment.new(@environment)
+ end
- def to_ref
- ref
+ def environment=(env)
+ if env.is_a?(String) or env.is_a?(Symbol)
+ @environment = env
+ else
+ @environment = env.name
end
+ end
- # Convert our resource to a RAL resource instance. Creates component
- # instances for resource types that don't exist.
- def to_ral
- if typeklass = Puppet::Type.type(self.type)
- return typeklass.new(self)
+ %w{exported virtual strict}.each do |m|
+ define_method(m+"?") do
+ self.send(m)
+ end
+ end
+
+ # Create our resource.
+ def initialize(type, title = nil, attributes = {})
+ @parameters = {}
+ @namespaces = [""]
+
+ # Set things like namespaces and strictness first.
+ attributes.each do |attr, value|
+ next if attr == :parameters
+ send(attr.to_s + "=", value)
+ end
+
+ # We do namespaces first, and use tmp variables, so our title
+ # canonicalization works (i.e., namespaces are set and resource
+ # types can be looked up)
+ tmp_type, tmp_title = extract_type_and_title(type, title)
+ self.type = tmp_type
+ self.title = tmp_title
+
+ if params = attributes[:parameters]
+ extract_parameters(params)
+ end
+
+ resolve_type_and_title
+
+ tag(self.type)
+ tag(self.title) if valid_tag?(self.title)
+
+ raise ArgumentError, "Invalid resource type #{type}" if strict? and ! resource_type
+ end
+
+ def ref
+ to_s
+ end
+
+ # Find our resource.
+ def resolve
+ return(catalog ? catalog.resource(to_s) : nil)
+ end
+
+ def title=(value)
+ @unresolved_title = value
+ @title = nil
+ end
+
+ def resource_type
+ case type
+ when "Class"; find_hostclass(title)
+ when "Node"; find_node(title)
+ else
+ find_resource_type(type)
+ end
+ end
+
+ # Produce a simple hash of our parameters.
+ def to_hash
+ parse_title.merge @parameters
+ end
+
+ def to_s
+ "#{type}[#{title}]"
+ end
+
+ def uniqueness_key
+ self.to_hash.values_at(*key_attributes.sort_by { |k| k.to_s })
+ end
+
+ def key_attributes
+ return(resource_type.respond_to? :key_attributes) ? resource_type.key_attributes : [:name]
+ end
+
+ # Convert our resource to Puppet code.
+ def to_manifest
+ "%s { '%s':\n%s\n}" % [self.type.to_s.downcase, self.title,
+ @parameters.collect { |p, v|
+ if v.is_a? Array
+ " #{p} => [\'#{v.join("','")}\']"
else
- return Puppet::Type::Component.new(self)
+ " #{p} => \'#{v}\'"
end
- end
-
- # Translate our object to a backward-compatible transportable object.
- def to_trans
- if builtin_type? and type.downcase.to_s != "stage"
- result = to_transobject
- else
- result = to_transbucket
- end
-
- result.file = self.file
- result.line = self.line
-
- result
- end
-
- def to_trans_ref
- [type.to_s, title.to_s]
- end
-
- # Create an old-style TransObject instance, for builtin resource types.
- def to_transobject
- # Now convert to a transobject
- result = Puppet::TransObject.new(title, type)
- to_hash.each do |p, v|
- if v.is_a?(Puppet::Resource)
- v = v.to_trans_ref
- elsif v.is_a?(Array)
- v = v.collect { |av|
- av = av.to_trans_ref if av.is_a?(Puppet::Resource)
- av
- }
- end
-
- # If the value is an array with only one value, then
- # convert it to a single value. This is largely so that
- # the database interaction doesn't have to worry about
- # whether it returns an array or a string.
- result[p.to_s] = if v.is_a?(Array) and v.length == 1
- v[0]
- else
- v
- end
- end
-
- result.tags = self.tags
-
- result
- end
-
- def name
- # this is potential namespace conflict
- # between the notion of an "indirector name"
- # and a "resource name"
- [ type, title ].join('/')
- end
-
- def to_resource
- self
- end
-
- # We have to lazy-evaluate this.
- def title=(value)
- @title = nil
- @unresolved_title = value
- end
-
- # We have to lazy-evaluate this.
- def type=(value)
- @type = nil
- @unresolved_type = value || "Class"
- end
-
- def title
- resolve_type_and_title unless @title
- @title
- end
-
- def type
- resolve_type_and_title unless @type
- @type
- end
-
- def valid_parameter?(name)
- resource_type.valid_parameter?(name)
- end
-
- def validate_parameter(name)
- raise ArgumentError, "Invalid parameter #{name}" unless valid_parameter?(name)
- end
-
- private
-
- def find_node(name)
- known_resource_types.node(name)
- end
-
- def find_hostclass(title)
- name = title == :main ? "" : title
- known_resource_types.find_hostclass(namespaces, name)
- end
-
- def find_resource_type(type)
- # It still works fine without the type == 'class' short-cut, but it is a lot slower.
- find_builtin_resource_type(type) || find_defined_resource_type(type) unless type.to_s.downcase == 'class'
- end
-
- def find_builtin_resource_type(type)
- Puppet::Type.type(type.to_s.downcase.to_sym)
- end
-
- def find_defined_resource_type(type)
- known_resource_types.find_definition(namespaces, type.to_s.downcase)
- end
-
- # Produce a canonical method name.
- def parameter_name(param)
- param = param.to_s.downcase.to_sym
- if param == :name and n = namevar
- param = namevar
- end
- param
- end
-
- def namespaces=(ns)
- @namespaces = Array(ns)
- end
-
- # The namevar for our resource type. If the type doesn't exist,
- # always use :name.
- def namevar
- if builtin_type? and t = resource_type and t.key_attributes.length == 1
- t.key_attributes.first
- else
- :name
- end
- end
-
- # Create an old-style TransBucket instance, for non-builtin resource types.
- def to_transbucket
- bucket = Puppet::TransBucket.new([])
-
- bucket.type = self.type
- bucket.name = self.title
-
- # TransBuckets don't support parameters, which is why they're being deprecated.
- bucket
- end
-
- def extract_parameters(params)
- params.each do |param, value|
- validate_parameter(param) if strict?
- self[param] = value
- end
- end
-
- def extract_type_and_title(argtype, argtitle)
- if (argtitle || argtype) =~ /^([^\[\]]+)\[(.+)\]$/m then [ $1, $2 ]
- elsif argtitle then [ argtype, argtitle ]
- elsif argtype.is_a?(Puppet::Type) then [ argtype.class.name, argtype.title ]
- else raise ArgumentError, "No title provided and #{argtype.inspect} is not a valid resource reference"
- end
- end
-
- def munge_type_name(value)
- return :main if value == :main
- return "Class" if value == "" or value.nil? or value.to_s.downcase == "component"
-
- value.to_s.split("::").collect { |s| s.capitalize }.join("::")
- end
-
- # This is an annoyingly complicated method for resolving qualified
- # types as necessary, and putting them in type or title attributes.
- def resolve_type_and_title
- if @unresolved_type
- @type = resolve_type
- @unresolved_type = nil
- end
- if @unresolved_title
- @title = resolve_title
- @unresolved_title = nil
- end
- end
-
- def resolve_type
- case type = munge_type_name(@unresolved_type)
- when "Class", "Node";
- type
- else
- # Otherwise, some kind of builtin or defined resource type
- munge_type_name( (r = find_resource_type(type)) ? r.name : type)
- end
- end
-
- # This method only works if resolve_type was called first
- def resolve_title
- case @type
- when "Node"; return @unresolved_title
- when "Class";
- resolve_title_for_class(@unresolved_title)
- else
- @unresolved_title
- end
- end
-
- def resolve_title_for_class(title)
- if title == "" or title == :main
- return :main
- end
-
- if klass = find_hostclass(title)
- result = klass.name
- end
- munge_type_name(result || title)
- end
-
- def parse_title
- h = {}
- type = find_resource_type(@type)
- if type.respond_to? :title_patterns
- type.title_patterns.each { |regexp, symbols_and_lambdas|
- if captures = regexp.match(title.to_s)
- symbols_and_lambdas.zip(captures[1..-1]).each { |symbol_and_lambda,capture|
- sym, lam = symbol_and_lambda
- #self[sym] = lam.call(capture)
- h[sym] = lam.call(capture)
- }
- return h
- end
- }
- else
- return { :name => title.to_s }
+ }.join(",\n")
+ ]
+ end
+
+ def to_ref
+ ref
+ end
+
+ # Convert our resource to a RAL resource instance. Creates component
+ # instances for resource types that don't exist.
+ def to_ral
+ if typeklass = Puppet::Type.type(self.type)
+ return typeklass.new(self)
+ else
+ return Puppet::Type::Component.new(self)
+ end
+ end
+
+ # Translate our object to a backward-compatible transportable object.
+ def to_trans
+ if builtin_type? and type.downcase.to_s != "stage"
+ result = to_transobject
+ else
+ result = to_transbucket
+ end
+
+ result.file = self.file
+ result.line = self.line
+
+ result
+ end
+
+ def to_trans_ref
+ [type.to_s, title.to_s]
+ end
+
+ # Create an old-style TransObject instance, for builtin resource types.
+ def to_transobject
+ # Now convert to a transobject
+ result = Puppet::TransObject.new(title, type)
+ to_hash.each do |p, v|
+ if v.is_a?(Puppet::Resource)
+ v = v.to_trans_ref
+ elsif v.is_a?(Array)
+ v = v.collect { |av|
+ av = av.to_trans_ref if av.is_a?(Puppet::Resource)
+ av
+ }
+ end
+
+ # If the value is an array with only one value, then
+ # convert it to a single value. This is largely so that
+ # the database interaction doesn't have to worry about
+ # whether it returns an array or a string.
+ result[p.to_s] = if v.is_a?(Array) and v.length == 1
+ v[0]
+ else
+ v
+ end
+ end
+
+ result.tags = self.tags
+
+ result
+ end
+
+ def name
+ # this is potential namespace conflict
+ # between the notion of an "indirector name"
+ # and a "resource name"
+ [ type, title ].join('/')
+ end
+
+ def to_resource
+ self
+ end
+
+ # We have to lazy-evaluate this.
+ def title=(value)
+ @title = nil
+ @unresolved_title = value
+ end
+
+ # We have to lazy-evaluate this.
+ def type=(value)
+ @type = nil
+ @unresolved_type = value || "Class"
+ end
+
+ def title
+ resolve_type_and_title unless @title
+ @title
+ end
+
+ def type
+ resolve_type_and_title unless @type
+ @type
+ end
+
+ def valid_parameter?(name)
+ resource_type.valid_parameter?(name)
+ end
+
+ def validate_parameter(name)
+ raise ArgumentError, "Invalid parameter #{name}" unless valid_parameter?(name)
+ end
+
+ private
+
+ def find_node(name)
+ known_resource_types.node(name)
+ end
+
+ def find_hostclass(title)
+ name = title == :main ? "" : title
+ known_resource_types.find_hostclass(namespaces, name)
+ end
+
+ def find_resource_type(type)
+ # It still works fine without the type == 'class' short-cut, but it is a lot slower.
+ find_builtin_resource_type(type) || find_defined_resource_type(type) unless type.to_s.downcase == 'class'
+ end
+
+ def find_builtin_resource_type(type)
+ Puppet::Type.type(type.to_s.downcase.to_sym)
+ end
+
+ def find_defined_resource_type(type)
+ known_resource_types.find_definition(namespaces, type.to_s.downcase)
+ end
+
+ # Produce a canonical method name.
+ def parameter_name(param)
+ param = param.to_s.downcase.to_sym
+ if param == :name and n = namevar
+ param = namevar
+ end
+ param
+ end
+
+ def namespaces=(ns)
+ @namespaces = Array(ns)
+ end
+
+ # The namevar for our resource type. If the type doesn't exist,
+ # always use :name.
+ def namevar
+ if builtin_type? and t = resource_type and t.key_attributes.length == 1
+ t.key_attributes.first
+ else
+ :name
+ end
+ end
+
+ # Create an old-style TransBucket instance, for non-builtin resource types.
+ def to_transbucket
+ bucket = Puppet::TransBucket.new([])
+
+ bucket.type = self.type
+ bucket.name = self.title
+
+ # TransBuckets don't support parameters, which is why they're being deprecated.
+ bucket
+ end
+
+ def extract_parameters(params)
+ params.each do |param, value|
+ validate_parameter(param) if strict?
+ self[param] = value
+ end
+ end
+
+ def extract_type_and_title(argtype, argtitle)
+ if (argtitle || argtype) =~ /^([^\[\]]+)\[(.+)\]$/m then [ $1, $2 ]
+ elsif argtitle then [ argtype, argtitle ]
+ elsif argtype.is_a?(Puppet::Type) then [ argtype.class.name, argtype.title ]
+ else raise ArgumentError, "No title provided and #{argtype.inspect} is not a valid resource reference"
+ end
+ end
+
+ def munge_type_name(value)
+ return :main if value == :main
+ return "Class" if value == "" or value.nil? or value.to_s.downcase == "component"
+
+ value.to_s.split("::").collect { |s| s.capitalize }.join("::")
+ end
+
+ # This is an annoyingly complicated method for resolving qualified
+ # types as necessary, and putting them in type or title attributes.
+ def resolve_type_and_title
+ if @unresolved_type
+ @type = resolve_type
+ @unresolved_type = nil
+ end
+ if @unresolved_title
+ @title = resolve_title
+ @unresolved_title = nil
+ end
+ end
+
+ def resolve_type
+ case type = munge_type_name(@unresolved_type)
+ when "Class", "Node";
+ type
+ else
+ # Otherwise, some kind of builtin or defined resource type
+ munge_type_name( (r = find_resource_type(type)) ? r.name : type)
+ end
+ end
+
+ # This method only works if resolve_type was called first
+ def resolve_title
+ case @type
+ when "Node"; return @unresolved_title
+ when "Class";
+ resolve_title_for_class(@unresolved_title)
+ else
+ @unresolved_title
+ end
+ end
+
+ def resolve_title_for_class(title)
+ if title == "" or title == :main
+ return :main
+ end
+
+ if klass = find_hostclass(title)
+ result = klass.name
+ end
+ munge_type_name(result || title)
+ end
+
+ def parse_title
+ h = {}
+ type = find_resource_type(@type)
+ if type.respond_to? :title_patterns
+ type.title_patterns.each { |regexp, symbols_and_lambdas|
+ if captures = regexp.match(title.to_s)
+ symbols_and_lambdas.zip(captures[1..-1]).each { |symbol_and_lambda,capture|
+ sym, lam = symbol_and_lambda
+ #self[sym] = lam.call(capture)
+ h[sym] = lam.call(capture)
+ }
+ return h
end
+ }
+ else
+ return { :name => title.to_s }
end
+ end
end
diff --git a/lib/puppet/resource/catalog.rb b/lib/puppet/resource/catalog.rb
index 79888529f..e8c142965 100644
--- a/lib/puppet/resource/catalog.rb
+++ b/lib/puppet/resource/catalog.rb
@@ -13,579 +13,579 @@ require 'puppet/util/tagging'
# of the information in the catalog, including the resources
# and the relationships between them.
class Puppet::Resource::Catalog < Puppet::SimpleGraph
- class DuplicateResourceError < Puppet::Error; end
+ class DuplicateResourceError < Puppet::Error; end
- extend Puppet::Indirector
- indirects :catalog, :terminus_setting => :catalog_terminus
+ extend Puppet::Indirector
+ indirects :catalog, :terminus_setting => :catalog_terminus
- include Puppet::Util::Tagging
- extend Puppet::Util::Pson
- include Puppet::Util::Cacher::Expirer
+ include Puppet::Util::Tagging
+ extend Puppet::Util::Pson
+ include Puppet::Util::Cacher::Expirer
- # The host name this is a catalog for.
- attr_accessor :name
+ # The host name this is a catalog for.
+ attr_accessor :name
- # The catalog version. Used for testing whether a catalog
- # is up to date.
- attr_accessor :version
+ # The catalog version. Used for testing whether a catalog
+ # is up to date.
+ attr_accessor :version
- # How long this catalog took to retrieve. Used for reporting stats.
- attr_accessor :retrieval_duration
+ # How long this catalog took to retrieve. Used for reporting stats.
+ attr_accessor :retrieval_duration
- # Whether this is a host catalog, which behaves very differently.
- # In particular, reports are sent, graphs are made, and state is
- # stored in the state database. If this is set incorrectly, then you often
- # end up in infinite loops, because catalogs are used to make things
- # that the host catalog needs.
- attr_accessor :host_config
+ # Whether this is a host catalog, which behaves very differently.
+ # In particular, reports are sent, graphs are made, and state is
+ # stored in the state database. If this is set incorrectly, then you often
+ # end up in infinite loops, because catalogs are used to make things
+ # that the host catalog needs.
+ attr_accessor :host_config
- # Whether this catalog was retrieved from the cache, which affects
- # whether it is written back out again.
- attr_accessor :from_cache
+ # Whether this catalog was retrieved from the cache, which affects
+ # whether it is written back out again.
+ attr_accessor :from_cache
- # Some metadata to help us compile and generally respond to the current state.
- attr_accessor :client_version, :server_version
+ # Some metadata to help us compile and generally respond to the current state.
+ attr_accessor :client_version, :server_version
- # Add classes to our class list.
- def add_class(*classes)
- classes.each do |klass|
- @classes << klass
- end
-
- # Add the class names as tags, too.
- tag(*classes)
+ # Add classes to our class list.
+ def add_class(*classes)
+ classes.each do |klass|
+ @classes << klass
end
- def title_key_for_ref( ref )
- ref =~ /^(.+)\[(.*)\]/
- [$1, $2]
- end
+ # Add the class names as tags, too.
+ tag(*classes)
+ end
- # Add one or more resources to our graph and to our resource table.
- # This is actually a relatively complicated method, because it handles multiple
- # aspects of Catalog behaviour:
- # * Add the resource to the resource table
- # * Add the resource to the resource graph
- # * Add the resource to the relationship graph
- # * Add any aliases that make sense for the resource (e.g., name != title)
- def add_resource(*resources)
- resources.each do |resource|
- raise ArgumentError, "Can only add objects that respond to :ref, not instances of #{resource.class}" unless resource.respond_to?(:ref)
- end.each { |resource| fail_on_duplicate_type_and_title(resource) }.each do |resource|
- title_key = title_key_for_ref(resource.ref)
-
- @transient_resources << resource if applying?
- @resource_table[title_key] = resource
-
- # If the name and title differ, set up an alias
-
- if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.respond_to?(:isomorphic?) and resource.name != resource.title
- self.alias(resource, resource.uniqueness_key) if resource.isomorphic?
- end
+ def title_key_for_ref( ref )
+ ref =~ /^(.+)\[(.*)\]/
+ [$1, $2]
+ end
- resource.catalog = self if resource.respond_to?(:catalog=)
+ # Add one or more resources to our graph and to our resource table.
+ # This is actually a relatively complicated method, because it handles multiple
+ # aspects of Catalog behaviour:
+ # * Add the resource to the resource table
+ # * Add the resource to the resource graph
+ # * Add the resource to the relationship graph
+ # * Add any aliases that make sense for the resource (e.g., name != title)
+ def add_resource(*resources)
+ resources.each do |resource|
+ raise ArgumentError, "Can only add objects that respond to :ref, not instances of #{resource.class}" unless resource.respond_to?(:ref)
+ end.each { |resource| fail_on_duplicate_type_and_title(resource) }.each do |resource|
+ title_key = title_key_for_ref(resource.ref)
- add_vertex(resource)
+ @transient_resources << resource if applying?
+ @resource_table[title_key] = resource
- @relationship_graph.add_vertex(resource) if @relationship_graph
+ # If the name and title differ, set up an alias
- yield(resource) if block_given?
- end
- end
+ if resource.respond_to?(:name) and resource.respond_to?(:title) and resource.respond_to?(:isomorphic?) and resource.name != resource.title
+ self.alias(resource, resource.uniqueness_key) if resource.isomorphic?
+ end
- # Create an alias for a resource.
- def alias(resource, key)
- resource.ref =~ /^(.+)\[/
- class_name = $1 || resource.class.name
+ resource.catalog = self if resource.respond_to?(:catalog=)
- newref = [class_name, key]
+ add_vertex(resource)
- if key.is_a? String
- ref_string = "#{class_name}[#{key}]"
- return if ref_string == resource.ref
- end
+ @relationship_graph.add_vertex(resource) if @relationship_graph
- # LAK:NOTE It's important that we directly compare the references,
- # because sometimes an alias is created before the resource is
- # added to the catalog, so comparing inside the below if block
- # isn't sufficient.
- if existing = @resource_table[newref]
- return if existing == resource
- raise(ArgumentError, "Cannot alias #{resource.ref} to #{key.inspect}; resource #{newref.inspect} already exists")
- end
- @resource_table[newref] = resource
- @aliases[resource.ref] ||= []
- @aliases[resource.ref] << newref
+ yield(resource) if block_given?
end
+ end
- # Apply our catalog to the local host. Valid options
- # are:
- # :tags - set the tags that restrict what resources run
- # during the transaction
- # :ignoreschedules - tell the transaction to ignore schedules
- # when determining the resources to run
- def apply(options = {})
- @applying = true
-
- # Expire all of the resource data -- this ensures that all
- # data we're operating against is entirely current.
- expire
-
- Puppet::Util::Storage.load if host_config?
- transaction = Puppet::Transaction.new(self)
-
- transaction.report = options[:report] if options[:report]
- transaction.tags = options[:tags] if options[:tags]
- transaction.ignoreschedules = true if options[:ignoreschedules]
-
- transaction.add_times :config_retrieval => self.retrieval_duration || 0
-
- begin
- transaction.evaluate
- rescue Puppet::Error => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not apply complete catalog: #{detail}"
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Got an uncaught exception of type #{detail.class}: #{detail}"
- ensure
- # Don't try to store state unless we're a host config
- # too recursive.
- Puppet::Util::Storage.store if host_config?
- end
+ # Create an alias for a resource.
+ def alias(resource, key)
+ resource.ref =~ /^(.+)\[/
+ class_name = $1 || resource.class.name
- yield transaction if block_given?
+ newref = [class_name, key]
- return transaction
- ensure
- @applying = false
- cleanup
+ if key.is_a? String
+ ref_string = "#{class_name}[#{key}]"
+ return if ref_string == resource.ref
end
- # Are we in the middle of applying the catalog?
- def applying?
- @applying
+ # LAK:NOTE It's important that we directly compare the references,
+ # because sometimes an alias is created before the resource is
+ # added to the catalog, so comparing inside the below if block
+ # isn't sufficient.
+ if existing = @resource_table[newref]
+ return if existing == resource
+ raise(ArgumentError, "Cannot alias #{resource.ref} to #{key.inspect}; resource #{newref.inspect} already exists")
end
+ @resource_table[newref] = resource
+ @aliases[resource.ref] ||= []
+ @aliases[resource.ref] << newref
+ end
- def clear(remove_resources = true)
- super()
- # We have to do this so that the resources clean themselves up.
- @resource_table.values.each { |resource| resource.remove } if remove_resources
- @resource_table.clear
-
- if @relationship_graph
- @relationship_graph.clear
- @relationship_graph = nil
- end
- end
+ # Apply our catalog to the local host. Valid options
+ # are:
+ # :tags - set the tags that restrict what resources run
+ # during the transaction
+ # :ignoreschedules - tell the transaction to ignore schedules
+ # when determining the resources to run
+ def apply(options = {})
+ @applying = true
- def classes
- @classes.dup
- end
+ # Expire all of the resource data -- this ensures that all
+ # data we're operating against is entirely current.
+ expire
- # Create a new resource and register it in the catalog.
- def create_resource(type, options)
- unless klass = Puppet::Type.type(type)
- raise ArgumentError, "Unknown resource type #{type}"
- end
- return unless resource = klass.new(options)
+ Puppet::Util::Storage.load if host_config?
+ transaction = Puppet::Transaction.new(self)
+
+ transaction.report = options[:report] if options[:report]
+ transaction.tags = options[:tags] if options[:tags]
+ transaction.ignoreschedules = true if options[:ignoreschedules]
- add_resource(resource)
- resource
- end
+ transaction.add_times :config_retrieval => self.retrieval_duration || 0
- def dependent_data_expired?(ts)
- if applying?
- return super
- else
- return true
- end
+ begin
+ transaction.evaluate
+ rescue Puppet::Error => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not apply complete catalog: #{detail}"
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Got an uncaught exception of type #{detail.class}: #{detail}"
+ ensure
+ # Don't try to store state unless we're a host config
+ # too recursive.
+ Puppet::Util::Storage.store if host_config?
end
- # Turn our catalog graph into an old-style tree of TransObjects and TransBuckets.
- # LAK:NOTE(20081211): This is a pre-0.25 backward compatibility method.
- # It can be removed as soon as xmlrpc is killed.
- def extract
- top = nil
- current = nil
- buckets = {}
-
- unless main = resource(:stage, "main")
- raise Puppet::DevError, "Could not find 'main' stage; cannot generate catalog"
- end
-
- if stages = vertices.find_all { |v| v.type == "Stage" and v.title != "main" } and ! stages.empty?
- Puppet.warning "Stages are not supported by 0.24.x client; stage(s) #{stages.collect { |s| s.to_s }.join(', ') } will be ignored"
- end
-
- bucket = nil
- walk(main, :out) do |source, target|
- # The sources are always non-builtins.
- unless tmp = buckets[source.to_s]
- if tmp = buckets[source.to_s] = source.to_trans
- bucket = tmp
- else
- # This is because virtual resources return nil. If a virtual
- # container resource contains realized resources, we still need to get
- # to them. So, we keep a reference to the last valid bucket
- # we returned and use that if the container resource is virtual.
- end
- end
- bucket = tmp || bucket
- if child = target.to_trans
- raise "No bucket created for #{source}" unless bucket
- bucket.push child
-
- # It's important that we keep a reference to any TransBuckets we've created, so
- # we don't create multiple buckets for children.
- buckets[target.to_s] = child unless target.builtin?
- end
- end
-
- # Retrieve the bucket for the top-level scope and set the appropriate metadata.
- unless result = buckets[main.to_s]
- # This only happens when the catalog is entirely empty.
- result = buckets[main.to_s] = main.to_trans
- end
-
- result.classes = classes
-
- # Clear the cache to encourage the GC
- buckets.clear
- result
- end
+ yield transaction if block_given?
- # Make sure all of our resources are "finished".
- def finalize
- make_default_resources
+ return transaction
+ ensure
+ @applying = false
+ cleanup
+ end
- @resource_table.values.each { |resource| resource.finish }
+ # Are we in the middle of applying the catalog?
+ def applying?
+ @applying
+ end
- write_graph(:resources)
- end
+ def clear(remove_resources = true)
+ super()
+ # We have to do this so that the resources clean themselves up.
+ @resource_table.values.each { |resource| resource.remove } if remove_resources
+ @resource_table.clear
- def host_config?
- host_config
+ if @relationship_graph
+ @relationship_graph.clear
+ @relationship_graph = nil
end
+ end
- def initialize(name = nil)
- super()
- @name = name if name
- @classes = []
- @resource_table = {}
- @transient_resources = []
- @applying = false
- @relationship_graph = nil
-
- @host_config = true
-
- @aliases = {}
+ def classes
+ @classes.dup
+ end
- if block_given?
- yield(self)
- finalize
- end
+ # Create a new resource and register it in the catalog.
+ def create_resource(type, options)
+ unless klass = Puppet::Type.type(type)
+ raise ArgumentError, "Unknown resource type #{type}"
end
+ return unless resource = klass.new(options)
- # Make the default objects necessary for function.
- def make_default_resources
- # We have to add the resources to the catalog, or else they won't get cleaned up after
- # the transaction.
-
- # First create the default scheduling objects
- Puppet::Type.type(:schedule).mkdefaultschedules.each { |res| add_resource(res) unless resource(res.ref) }
+ add_resource(resource)
+ resource
+ end
- # And filebuckets
- if bucket = Puppet::Type.type(:filebucket).mkdefaultbucket
- add_resource(bucket) unless resource(bucket.ref)
- end
+ def dependent_data_expired?(ts)
+ if applying?
+ return super
+ else
+ return true
end
+ end
- # Create a graph of all of the relationships in our catalog.
- def relationship_graph
- unless @relationship_graph
- # It's important that we assign the graph immediately, because
- # the debug messages below use the relationships in the
- # relationship graph to determine the path to the resources
- # spitting out the messages. If this is not set,
- # then we get into an infinite loop.
- @relationship_graph = Puppet::SimpleGraph.new
-
- # First create the dependency graph
- self.vertices.each do |vertex|
- @relationship_graph.add_vertex vertex
- vertex.builddepends.each do |edge|
- @relationship_graph.add_edge(edge)
- end
- end
-
- # Lastly, add in any autorequires
- @relationship_graph.vertices.each do |vertex|
- vertex.autorequire(self).each do |edge|
- unless @relationship_graph.edge?(edge.source, edge.target) # don't let automatic relationships conflict with manual ones.
- unless @relationship_graph.edge?(edge.target, edge.source)
- vertex.debug "Autorequiring #{edge.source}"
- @relationship_graph.add_edge(edge)
- else
- vertex.debug "Skipping automatic relationship with #{(edge.source == vertex ? edge.target : edge.source)}"
- end
- end
- end
- end
- @relationship_graph.write_graph(:relationships) if host_config?
-
- # Then splice in the container information
- @relationship_graph.splice!(self, Puppet::Type::Component)
+ # Turn our catalog graph into an old-style tree of TransObjects and TransBuckets.
+ # LAK:NOTE(20081211): This is a pre-0.25 backward compatibility method.
+ # It can be removed as soon as xmlrpc is killed.
+ def extract
+ top = nil
+ current = nil
+ buckets = {}
- @relationship_graph.write_graph(:expanded_relationships) if host_config?
- end
- @relationship_graph
+ unless main = resource(:stage, "main")
+ raise Puppet::DevError, "Could not find 'main' stage; cannot generate catalog"
end
- # Remove the resource from our catalog. Notice that we also call
- # 'remove' on the resource, at least until resource classes no longer maintain
- # references to the resource instances.
- def remove_resource(*resources)
- resources.each do |resource|
- @resource_table.delete(resource.ref)
- if aliases = @aliases[resource.ref]
- aliases.each { |res_alias| @resource_table.delete(res_alias) }
- @aliases.delete(resource.ref)
- end
- remove_vertex!(resource) if vertex?(resource)
- @relationship_graph.remove_vertex!(resource) if @relationship_graph and @relationship_graph.vertex?(resource)
- resource.remove
- end
+ if stages = vertices.find_all { |v| v.type == "Stage" and v.title != "main" } and ! stages.empty?
+ Puppet.warning "Stages are not supported by 0.24.x client; stage(s) #{stages.collect { |s| s.to_s }.join(', ') } will be ignored"
end
- # Look a resource up by its reference (e.g., File[/etc/passwd]).
- def resource(type, title = nil)
- # Always create a resource reference, so that it always canonizes how we
- # are referring to them.
- if title
- res = Puppet::Resource.new(type, title)
+ bucket = nil
+ walk(main, :out) do |source, target|
+ # The sources are always non-builtins.
+ unless tmp = buckets[source.to_s]
+ if tmp = buckets[source.to_s] = source.to_trans
+ bucket = tmp
else
- # If they didn't provide a title, then we expect the first
- # argument to be of the form 'Class[name]', which our
- # Reference class canonizes for us.
- res = Puppet::Resource.new(nil, type)
- end
- title_key = [res.type, res.title.to_s]
- uniqueness_key = [res.type, res.uniqueness_key]
- @resource_table[title_key] || @resource_table[uniqueness_key]
- end
-
- def resource_refs
- resource_keys.collect{ |type, name| name.is_a?( String ) ? "#{type}[#{name}]" : nil}.compact
- end
-
- def resource_keys
- @resource_table.keys
- end
-
- def self.from_pson(data)
- result = new(data['name'])
-
- if tags = data['tags']
- result.tag(*tags)
- end
-
- if version = data['version']
- result.version = version
- end
-
- if resources = data['resources']
- resources = PSON.parse(resources) if resources.is_a?(String)
- resources.each do |res|
- resource_from_pson(result, res)
- end
- end
-
- if edges = data['edges']
- edges = PSON.parse(edges) if edges.is_a?(String)
- edges.each do |edge|
- edge_from_pson(result, edge)
- end
- end
-
- if classes = data['classes']
- result.add_class(*classes)
- end
-
- result
- end
-
- def self.edge_from_pson(result, edge)
- # If no type information was presented, we manually find
- # the class.
- edge = Puppet::Relationship.from_pson(edge) if edge.is_a?(Hash)
- unless source = result.resource(edge.source)
- raise ArgumentError, "Could not convert from pson: Could not find relationship source #{edge.source.inspect}"
- end
- edge.source = source
-
- unless target = result.resource(edge.target)
- raise ArgumentError, "Could not convert from pson: Could not find relationship target #{edge.target.inspect}"
+ # This is because virtual resources return nil. If a virtual
+ # container resource contains realized resources, we still need to get
+ # to them. So, we keep a reference to the last valid bucket
+ # we returned and use that if the container resource is virtual.
end
- edge.target = target
+ end
+ bucket = tmp || bucket
+ if child = target.to_trans
+ raise "No bucket created for #{source}" unless bucket
+ bucket.push child
- result.add_edge(edge)
+ # It's important that we keep a reference to any TransBuckets we've created, so
+ # we don't create multiple buckets for children.
+ buckets[target.to_s] = child unless target.builtin?
+ end
end
- def self.resource_from_pson(result, res)
- res = Puppet::Resource.from_pson(res) if res.is_a? Hash
- result.add_resource(res)
+ # Retrieve the bucket for the top-level scope and set the appropriate metadata.
+ unless result = buckets[main.to_s]
+ # This only happens when the catalog is entirely empty.
+ result = buckets[main.to_s] = main.to_trans
end
- PSON.register_document_type('Catalog',self)
- def to_pson_data_hash
- {
- 'document_type' => 'Catalog',
- 'data' => {
- 'tags' => tags,
- 'name' => name,
- 'version' => version,
- 'resources' => vertices.collect { |v| v.to_pson_data_hash },
- 'edges' => edges. collect { |e| e.to_pson_data_hash },
- 'classes' => classes
- },
- 'metadata' => {
- 'api_version' => 1
- }
- }
- end
+ result.classes = classes
- def to_pson(*args)
- to_pson_data_hash.to_pson(*args)
- end
+ # Clear the cache to encourage the GC
+ buckets.clear
+ result
+ end
- # Convert our catalog into a RAL catalog.
- def to_ral
- to_catalog :to_ral
- end
+ # Make sure all of our resources are "finished".
+ def finalize
+ make_default_resources
- # Convert our catalog into a catalog of Puppet::Resource instances.
- def to_resource
- to_catalog :to_resource
- end
+ @resource_table.values.each { |resource| resource.finish }
- # filter out the catalog, applying +block+ to each resource.
- # If the block result is false, the resource will
- # be kept otherwise it will be skipped
- def filter(&block)
- to_catalog :to_resource, &block
- end
+ write_graph(:resources)
+ end
- # Store the classes in the classfile.
- def write_class_file
- ::File.open(Puppet[:classfile], "w") do |f|
- f.puts classes.join("\n")
- end
- rescue => detail
- Puppet.err "Could not create class file #{Puppet[:classfile]}: #{detail}"
- end
+ def host_config?
+ host_config
+ end
- # Produce the graph files if requested.
- def write_graph(name)
- # We only want to graph the main host catalog.
- return unless host_config?
+ def initialize(name = nil)
+ super()
+ @name = name if name
+ @classes = []
+ @resource_table = {}
+ @transient_resources = []
+ @applying = false
+ @relationship_graph = nil
- super
- end
+ @host_config = true
- private
+ @aliases = {}
- def cleanup
- # Expire any cached data the resources are keeping.
- expire
+ if block_given?
+ yield(self)
+ finalize
end
+ end
- # Verify that the given resource isn't defined elsewhere.
- def fail_on_duplicate_type_and_title(resource)
- # Short-curcuit the common case,
- return unless existing_resource = @resource_table[title_key_for_ref(resource.ref)]
-
- # If we've gotten this far, it's a real conflict
- msg = "Duplicate definition: #{resource.ref} is already defined"
+ # Make the default objects necessary for function.
+ def make_default_resources
+ # We have to add the resources to the catalog, or else they won't get cleaned up after
+ # the transaction.
- msg << " in file #{existing_resource.file} at line #{existing_resource.line}" if existing_resource.file and existing_resource.line
+ # First create the default scheduling objects
+ Puppet::Type.type(:schedule).mkdefaultschedules.each { |res| add_resource(res) unless resource(res.ref) }
- msg << "; cannot redefine" if resource.line or resource.file
-
- raise DuplicateResourceError.new(msg)
+ # And filebuckets
+ if bucket = Puppet::Type.type(:filebucket).mkdefaultbucket
+ add_resource(bucket) unless resource(bucket.ref)
end
+ end
- # An abstracted method for converting one catalog into another type of catalog.
- # This pretty much just converts all of the resources from one class to another, using
- # a conversion method.
- def to_catalog(convert)
- result = self.class.new(self.name)
-
- result.version = self.version
-
- map = {}
- vertices.each do |resource|
- next if virtual_not_exported?(resource)
- next if block_given? and yield resource
-
- #This is hackity hack for 1094
- #Aliases aren't working in the ral catalog because the current instance of the resource
- #has a reference to the catalog being converted. . . So, give it a reference to the new one
- #problem solved. . .
- if resource.class == Puppet::Resource
- resource = resource.dup
- resource.catalog = result
- elsif resource.is_a?(Puppet::TransObject)
- resource = resource.dup
- resource.catalog = result
- elsif resource.is_a?(Puppet::Parser::Resource)
- resource = resource.to_resource
- resource.catalog = result
- end
+ # Create a graph of all of the relationships in our catalog.
+ def relationship_graph
+ unless @relationship_graph
+ # It's important that we assign the graph immediately, because
+ # the debug messages below use the relationships in the
+ # relationship graph to determine the path to the resources
+ # spitting out the messages. If this is not set,
+ # then we get into an infinite loop.
+ @relationship_graph = Puppet::SimpleGraph.new
- if resource.is_a?(Puppet::Resource) and convert.to_s == "to_resource"
- newres = resource
+ # First create the dependency graph
+ self.vertices.each do |vertex|
+ @relationship_graph.add_vertex vertex
+ vertex.builddepends.each do |edge|
+ @relationship_graph.add_edge(edge)
+ end
+ end
+
+ # Lastly, add in any autorequires
+ @relationship_graph.vertices.each do |vertex|
+ vertex.autorequire(self).each do |edge|
+ unless @relationship_graph.edge?(edge.source, edge.target) # don't let automatic relationships conflict with manual ones.
+ unless @relationship_graph.edge?(edge.target, edge.source)
+ vertex.debug "Autorequiring #{edge.source}"
+ @relationship_graph.add_edge(edge)
else
- newres = resource.send(convert)
+ vertex.debug "Skipping automatic relationship with #{(edge.source == vertex ? edge.target : edge.source)}"
end
-
- # We can't guarantee that resources don't munge their names
- # (like files do with trailing slashes), so we have to keep track
- # of what a resource got converted to.
- map[resource.ref] = newres
-
- result.add_resource newres
+ end
end
+ end
+ @relationship_graph.write_graph(:relationships) if host_config?
- message = convert.to_s.gsub "_", " "
- edges.each do |edge|
- # Skip edges between virtual resources.
- next if virtual_not_exported?(edge.source)
- next if block_given? and yield edge.source
-
- next if virtual_not_exported?(edge.target)
- next if block_given? and yield edge.target
+ # Then splice in the container information
+ @relationship_graph.splice!(self, Puppet::Type::Component)
- unless source = map[edge.source.ref]
- raise Puppet::DevError, "Could not find resource #{edge.source.ref} when converting #{message} resources"
- end
-
- unless target = map[edge.target.ref]
- raise Puppet::DevError, "Could not find resource #{edge.target.ref} when converting #{message} resources"
- end
+ @relationship_graph.write_graph(:expanded_relationships) if host_config?
+ end
+ @relationship_graph
+ end
- result.add_edge(source, target, edge.label)
- end
+ # Remove the resource from our catalog. Notice that we also call
+ # 'remove' on the resource, at least until resource classes no longer maintain
+ # references to the resource instances.
+ def remove_resource(*resources)
+ resources.each do |resource|
+ @resource_table.delete(resource.ref)
+ if aliases = @aliases[resource.ref]
+ aliases.each { |res_alias| @resource_table.delete(res_alias) }
+ @aliases.delete(resource.ref)
+ end
+ remove_vertex!(resource) if vertex?(resource)
+ @relationship_graph.remove_vertex!(resource) if @relationship_graph and @relationship_graph.vertex?(resource)
+ resource.remove
+ end
+ end
+
+ # Look a resource up by its reference (e.g., File[/etc/passwd]).
+ def resource(type, title = nil)
+ # Always create a resource reference, so that it always canonizes how we
+ # are referring to them.
+ if title
+ res = Puppet::Resource.new(type, title)
+ else
+ # If they didn't provide a title, then we expect the first
+ # argument to be of the form 'Class[name]', which our
+ # Reference class canonizes for us.
+ res = Puppet::Resource.new(nil, type)
+ end
+ title_key = [res.type, res.title.to_s]
+ uniqueness_key = [res.type, res.uniqueness_key]
+ @resource_table[title_key] || @resource_table[uniqueness_key]
+ end
+
+ def resource_refs
+ resource_keys.collect{ |type, name| name.is_a?( String ) ? "#{type}[#{name}]" : nil}.compact
+ end
+
+ def resource_keys
+ @resource_table.keys
+ end
+
+ def self.from_pson(data)
+ result = new(data['name'])
+
+ if tags = data['tags']
+ result.tag(*tags)
+ end
+
+ if version = data['version']
+ result.version = version
+ end
+
+ if resources = data['resources']
+ resources = PSON.parse(resources) if resources.is_a?(String)
+ resources.each do |res|
+ resource_from_pson(result, res)
+ end
+ end
+
+ if edges = data['edges']
+ edges = PSON.parse(edges) if edges.is_a?(String)
+ edges.each do |edge|
+ edge_from_pson(result, edge)
+ end
+ end
+
+ if classes = data['classes']
+ result.add_class(*classes)
+ end
+
+ result
+ end
+
+ def self.edge_from_pson(result, edge)
+ # If no type information was presented, we manually find
+ # the class.
+ edge = Puppet::Relationship.from_pson(edge) if edge.is_a?(Hash)
+ unless source = result.resource(edge.source)
+ raise ArgumentError, "Could not convert from pson: Could not find relationship source #{edge.source.inspect}"
+ end
+ edge.source = source
+
+ unless target = result.resource(edge.target)
+ raise ArgumentError, "Could not convert from pson: Could not find relationship target #{edge.target.inspect}"
+ end
+ edge.target = target
+
+ result.add_edge(edge)
+ end
+
+ def self.resource_from_pson(result, res)
+ res = Puppet::Resource.from_pson(res) if res.is_a? Hash
+ result.add_resource(res)
+ end
+
+ PSON.register_document_type('Catalog',self)
+ def to_pson_data_hash
+ {
+ 'document_type' => 'Catalog',
+ 'data' => {
+ 'tags' => tags,
+ 'name' => name,
+ 'version' => version,
+ 'resources' => vertices.collect { |v| v.to_pson_data_hash },
+ 'edges' => edges. collect { |e| e.to_pson_data_hash },
+ 'classes' => classes
+ },
+ 'metadata' => {
+ 'api_version' => 1
+ }
+ }
+ end
+
+ def to_pson(*args)
+ to_pson_data_hash.to_pson(*args)
+ end
+
+ # Convert our catalog into a RAL catalog.
+ def to_ral
+ to_catalog :to_ral
+ end
+
+ # Convert our catalog into a catalog of Puppet::Resource instances.
+ def to_resource
+ to_catalog :to_resource
+ end
+
+ # filter out the catalog, applying +block+ to each resource.
+ # If the block result is false, the resource will
+ # be kept otherwise it will be skipped
+ def filter(&block)
+ to_catalog :to_resource, &block
+ end
+
+ # Store the classes in the classfile.
+ def write_class_file
+ ::File.open(Puppet[:classfile], "w") do |f|
+ f.puts classes.join("\n")
+ end
+ rescue => detail
+ Puppet.err "Could not create class file #{Puppet[:classfile]}: #{detail}"
+ end
+
+ # Produce the graph files if requested.
+ def write_graph(name)
+ # We only want to graph the main host catalog.
+ return unless host_config?
+
+ super
+ end
+
+ private
+
+ def cleanup
+ # Expire any cached data the resources are keeping.
+ expire
+ end
+
+ # Verify that the given resource isn't defined elsewhere.
+ def fail_on_duplicate_type_and_title(resource)
+ # Short-curcuit the common case,
+ return unless existing_resource = @resource_table[title_key_for_ref(resource.ref)]
+
+ # If we've gotten this far, it's a real conflict
+ msg = "Duplicate definition: #{resource.ref} is already defined"
+
+ msg << " in file #{existing_resource.file} at line #{existing_resource.line}" if existing_resource.file and existing_resource.line
+
+ msg << "; cannot redefine" if resource.line or resource.file
+
+ raise DuplicateResourceError.new(msg)
+ end
+
+ # An abstracted method for converting one catalog into another type of catalog.
+ # This pretty much just converts all of the resources from one class to another, using
+ # a conversion method.
+ def to_catalog(convert)
+ result = self.class.new(self.name)
+
+ result.version = self.version
+
+ map = {}
+ vertices.each do |resource|
+ next if virtual_not_exported?(resource)
+ next if block_given? and yield resource
+
+ #This is hackity hack for 1094
+ #Aliases aren't working in the ral catalog because the current instance of the resource
+ #has a reference to the catalog being converted. . . So, give it a reference to the new one
+ #problem solved. . .
+ if resource.class == Puppet::Resource
+ resource = resource.dup
+ resource.catalog = result
+ elsif resource.is_a?(Puppet::TransObject)
+ resource = resource.dup
+ resource.catalog = result
+ elsif resource.is_a?(Puppet::Parser::Resource)
+ resource = resource.to_resource
+ resource.catalog = result
+ end
+
+ if resource.is_a?(Puppet::Resource) and convert.to_s == "to_resource"
+ newres = resource
+ else
+ newres = resource.send(convert)
+ end
+
+ # We can't guarantee that resources don't munge their names
+ # (like files do with trailing slashes), so we have to keep track
+ # of what a resource got converted to.
+ map[resource.ref] = newres
+
+ result.add_resource newres
+ end
+
+ message = convert.to_s.gsub "_", " "
+ edges.each do |edge|
+ # Skip edges between virtual resources.
+ next if virtual_not_exported?(edge.source)
+ next if block_given? and yield edge.source
+
+ next if virtual_not_exported?(edge.target)
+ next if block_given? and yield edge.target
+
+ unless source = map[edge.source.ref]
+ raise Puppet::DevError, "Could not find resource #{edge.source.ref} when converting #{message} resources"
+ end
+
+ unless target = map[edge.target.ref]
+ raise Puppet::DevError, "Could not find resource #{edge.target.ref} when converting #{message} resources"
+ end
- map.clear
+ result.add_edge(source, target, edge.label)
+ end
+
+ map.clear
- result.add_class(*self.classes)
- result.tag(*self.tags)
+ result.add_class(*self.classes)
+ result.tag(*self.tags)
- result
- end
+ result
+ end
- def virtual_not_exported?(resource)
- resource.respond_to?(:virtual?) and resource.virtual? and (resource.respond_to?(:exported?) and not resource.exported?)
- end
+ def virtual_not_exported?(resource)
+ resource.respond_to?(:virtual?) and resource.virtual? and (resource.respond_to?(:exported?) and not resource.exported?)
+ end
end
diff --git a/lib/puppet/resource/status.rb b/lib/puppet/resource/status.rb
index a52b927fc..2bdfbbfef 100644
--- a/lib/puppet/resource/status.rb
+++ b/lib/puppet/resource/status.rb
@@ -1,58 +1,58 @@
module Puppet
- class Resource
- class Status
- include Puppet::Util::Tagging
- include Puppet::Util::Logging
-
- ATTRIBUTES = [:resource, :node, :version, :file, :line, :current_values, :skipped_reason, :status, :evaluation_time, :change_count]
- attr_accessor *ATTRIBUTES
-
- STATES = [:skipped, :failed, :failed_to_restart, :restarted, :changed, :out_of_sync, :scheduled]
- attr_accessor *STATES
-
- attr_reader :source_description, :default_log_level, :time, :resource
-
- # Provide a boolean method for each of the states.
- STATES.each do |attr|
- define_method("#{attr}?") do
- !! send(attr)
- end
- end
-
- def <<(event)
- add_event(event)
- self
- end
-
- def add_event(event)
- @events << event
- if event.status == 'failure'
- self.failed = true
- end
- end
-
- def events
- @events
- end
-
- def initialize(resource)
- @source_description = resource.path
- @resource = resource.to_s
-
- [:file, :line, :version].each do |attr|
- send(attr.to_s + "=", resource.send(attr))
- end
-
- tag(*resource.tags)
- @time = Time.now
- @events = []
- end
-
- private
-
- def log_source
- source_description
- end
+ class Resource
+ class Status
+ include Puppet::Util::Tagging
+ include Puppet::Util::Logging
+
+ ATTRIBUTES = [:resource, :node, :version, :file, :line, :current_values, :skipped_reason, :status, :evaluation_time, :change_count]
+ attr_accessor *ATTRIBUTES
+
+ STATES = [:skipped, :failed, :failed_to_restart, :restarted, :changed, :out_of_sync, :scheduled]
+ attr_accessor *STATES
+
+ attr_reader :source_description, :default_log_level, :time, :resource
+
+ # Provide a boolean method for each of the states.
+ STATES.each do |attr|
+ define_method("#{attr}?") do
+ !! send(attr)
+ end
+ end
+
+ def <<(event)
+ add_event(event)
+ self
+ end
+
+ def add_event(event)
+ @events << event
+ if event.status == 'failure'
+ self.failed = true
end
+ end
+
+ def events
+ @events
+ end
+
+ def initialize(resource)
+ @source_description = resource.path
+ @resource = resource.to_s
+
+ [:file, :line, :version].each do |attr|
+ send(attr.to_s + "=", resource.send(attr))
+ end
+
+ tag(*resource.tags)
+ @time = Time.now
+ @events = []
+ end
+
+ private
+
+ def log_source
+ source_description
+ end
end
+ end
end
diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb
index 572a4f8c4..c2b4271e6 100644
--- a/lib/puppet/resource/type.rb
+++ b/lib/puppet/resource/type.rb
@@ -6,298 +6,298 @@ require 'puppet/parser/ast/leaf'
require 'puppet/dsl'
class Puppet::Resource::Type
- Puppet::ResourceType = self
- include Puppet::Util::InlineDocs
- include Puppet::Util::Warnings
- include Puppet::Util::Errors
+ Puppet::ResourceType = self
+ include Puppet::Util::InlineDocs
+ include Puppet::Util::Warnings
+ include Puppet::Util::Errors
- RESOURCE_SUPERTYPES = [:hostclass, :node, :definition]
+ RESOURCE_SUPERTYPES = [:hostclass, :node, :definition]
- attr_accessor :file, :line, :doc, :code, :ruby_code, :parent, :resource_type_collection, :module_name
- attr_reader :type, :namespace, :arguments, :behaves_like
+ attr_accessor :file, :line, :doc, :code, :ruby_code, :parent, :resource_type_collection, :module_name
+ attr_reader :type, :namespace, :arguments, :behaves_like
- RESOURCE_SUPERTYPES.each do |t|
- define_method("#{t}?") { self.type == t }
- end
-
- require 'puppet/indirector'
- extend Puppet::Indirector
- indirects :resource_type, :terminus_class => :parser
+ RESOURCE_SUPERTYPES.each do |t|
+ define_method("#{t}?") { self.type == t }
+ end
- def self.from_pson(data)
- name = data.delete('name') or raise ArgumentError, "Resource Type names must be specified"
- type = data.delete('type') || "definition"
+ require 'puppet/indirector'
+ extend Puppet::Indirector
+ indirects :resource_type, :terminus_class => :parser
- data = data.inject({}) { |result, ary| result[ary[0].intern] = ary[1]; result }
-
- new(type, name, data)
- end
+ def self.from_pson(data)
+ name = data.delete('name') or raise ArgumentError, "Resource Type names must be specified"
+ type = data.delete('type') || "definition"
- def to_pson_data_hash
- data = [:code, :doc, :line, :file, :parent].inject({}) do |hash, param|
- next hash unless value = self.send(param)
- hash[param.to_s] = value
- hash
- end
+ data = data.inject({}) { |result, ary| result[ary[0].intern] = ary[1]; result }
- data['arguments'] = arguments.dup
+ new(type, name, data)
+ end
- data['name'] = name
- data['type'] = type
-
- data
+ def to_pson_data_hash
+ data = [:code, :doc, :line, :file, :parent].inject({}) do |hash, param|
+ next hash unless value = self.send(param)
+ hash[param.to_s] = value
+ hash
end
- def to_pson(*args)
- to_pson_data_hash.to_pson(*args)
- end
+ data['arguments'] = arguments.dup
- # Are we a child of the passed class? Do a recursive search up our
- # parentage tree to figure it out.
- def child_of?(klass)
- return false unless parent
+ data['name'] = name
+ data['type'] = type
- return(klass == parent_type ? true : parent_type.child_of?(klass))
- end
+ data
+ end
- # Now evaluate the code associated with this class or definition.
- def evaluate_code(resource)
- scope = resource.scope
+ def to_pson(*args)
+ to_pson_data_hash.to_pson(*args)
+ end
- if tmp = evaluate_parent_type(resource)
- scope = tmp
- end
+ # Are we a child of the passed class? Do a recursive search up our
+ # parentage tree to figure it out.
+ def child_of?(klass)
+ return false unless parent
- scope = subscope(scope, resource) unless resource.title == :main
+ return(klass == parent_type ? true : parent_type.child_of?(klass))
+ end
- set_resource_parameters(resource, scope)
+ # Now evaluate the code associated with this class or definition.
+ def evaluate_code(resource)
+ scope = resource.scope
- code.safeevaluate(scope) if code
-
- evaluate_ruby_code(resource, scope) if ruby_code
+ if tmp = evaluate_parent_type(resource)
+ scope = tmp
end
- def initialize(type, name, options = {})
- @type = type.to_s.downcase.to_sym
- raise ArgumentError, "Invalid resource supertype '#{type}'" unless RESOURCE_SUPERTYPES.include?(@type)
-
- name = convert_from_ast(name) if name.is_a?(Puppet::Parser::AST::HostName)
-
- set_name_and_namespace(name)
+ scope = subscope(scope, resource) unless resource.title == :main
- [:code, :doc, :line, :file, :parent].each do |param|
- next unless value = options[param]
- send(param.to_s + "=", value)
- end
+ set_resource_parameters(resource, scope)
- set_arguments(options[:arguments])
- end
+ code.safeevaluate(scope) if code
- # This is only used for node names, and really only when the node name
- # is a regexp.
- def match(string)
- return string.to_s.downcase == name unless name_is_regex?
+ evaluate_ruby_code(resource, scope) if ruby_code
+ end
- @name =~ string
- end
+ def initialize(type, name, options = {})
+ @type = type.to_s.downcase.to_sym
+ raise ArgumentError, "Invalid resource supertype '#{type}'" unless RESOURCE_SUPERTYPES.include?(@type)
- # Add code from a new instance to our code.
- def merge(other)
- fail "#{name} is not a class; cannot add code to it" unless type == :hostclass
- fail "#{other.name} is not a class; cannot add code from it" unless other.type == :hostclass
- fail "Cannot have code outside of a class/node/define because 'freeze_main' is enabled" if name == "" and Puppet.settings[:freeze_main]
+ name = convert_from_ast(name) if name.is_a?(Puppet::Parser::AST::HostName)
- if parent and other.parent and parent != other.parent
- fail "Cannot merge classes with different parent classes (#{name} => #{parent} vs. #{other.name} => #{other.parent})"
- end
+ set_name_and_namespace(name)
- # We know they're either equal or only one is set, so keep whichever parent is specified.
- self.parent ||= other.parent
+ [:code, :doc, :line, :file, :parent].each do |param|
+ next unless value = options[param]
+ send(param.to_s + "=", value)
+ end
- if other.doc
- self.doc ||= ""
- self.doc += other.doc
- end
+ set_arguments(options[:arguments])
+ end
- # This might just be an empty, stub class.
- return unless other.code
+ # This is only used for node names, and really only when the node name
+ # is a regexp.
+ def match(string)
+ return string.to_s.downcase == name unless name_is_regex?
- unless self.code
- self.code = other.code
- return
- end
+ @name =~ string
+ end
- array_class = Puppet::Parser::AST::ASTArray
- self.code = array_class.new(:children => [self.code]) unless self.code.is_a?(array_class)
+ # Add code from a new instance to our code.
+ def merge(other)
+ fail "#{name} is not a class; cannot add code to it" unless type == :hostclass
+ fail "#{other.name} is not a class; cannot add code from it" unless other.type == :hostclass
+ fail "Cannot have code outside of a class/node/define because 'freeze_main' is enabled" if name == "" and Puppet.settings[:freeze_main]
- if other.code.is_a?(array_class)
- code.children += other.code.children
- else
- code.children << other.code
- end
+ if parent and other.parent and parent != other.parent
+ fail "Cannot merge classes with different parent classes (#{name} => #{parent} vs. #{other.name} => #{other.parent})"
end
- # Make an instance of our resource type. This is only possible
- # for those classes and nodes that don't have any arguments, and is
- # only useful for things like the 'include' function.
- def mk_plain_resource(scope)
- type == :definition and raise ArgumentError, "Cannot create resources for defined resource types"
- resource_type = type == :hostclass ? :class : :node
-
- # Make sure our parent class has been evaluated, if we have one.
- parent_type.mk_plain_resource(scope) if parent and ! scope.catalog.resource(resource_type, parent)
-
- # Do nothing if the resource already exists; this makes sure we don't
- # get multiple copies of the class resource, which helps provide the
- # singleton nature of classes.
- if resource = scope.catalog.resource(resource_type, name)
- return resource
- end
-
- resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self)
- scope.compiler.add_resource(scope, resource)
- scope.catalog.tag(*resource.tags)
- resource
- end
+ # We know they're either equal or only one is set, so keep whichever parent is specified.
+ self.parent ||= other.parent
- def name
- return @name unless @name.is_a?(Regexp)
- @name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'')
+ if other.doc
+ self.doc ||= ""
+ self.doc += other.doc
end
- def name_is_regex?
- @name.is_a?(Regexp)
- end
+ # This might just be an empty, stub class.
+ return unless other.code
- def parent_type
- return nil unless parent
+ unless self.code
+ self.code = other.code
+ return
+ end
- unless @parent_type ||= resource_type_collection.send(type, parent)
- fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type}"
- end
+ array_class = Puppet::Parser::AST::ASTArray
+ self.code = array_class.new(:children => [self.code]) unless self.code.is_a?(array_class)
- @parent_type
+ if other.code.is_a?(array_class)
+ code.children += other.code.children
+ else
+ code.children << other.code
+ end
+ end
+
+ # Make an instance of our resource type. This is only possible
+ # for those classes and nodes that don't have any arguments, and is
+ # only useful for things like the 'include' function.
+ def mk_plain_resource(scope)
+ type == :definition and raise ArgumentError, "Cannot create resources for defined resource types"
+ resource_type = type == :hostclass ? :class : :node
+
+ # Make sure our parent class has been evaluated, if we have one.
+ parent_type.mk_plain_resource(scope) if parent and ! scope.catalog.resource(resource_type, parent)
+
+ # Do nothing if the resource already exists; this makes sure we don't
+ # get multiple copies of the class resource, which helps provide the
+ # singleton nature of classes.
+ if resource = scope.catalog.resource(resource_type, name)
+ return resource
end
- # Set any arguments passed by the resource as variables in the scope.
- def set_resource_parameters(resource, scope)
- set = {}
- resource.to_hash.each do |param, value|
- param = param.to_sym
- fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless valid_parameter?(param)
+ resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self)
+ scope.compiler.add_resource(scope, resource)
+ scope.catalog.tag(*resource.tags)
+ resource
+ end
- exceptwrap { scope.setvar(param.to_s, value) }
+ def name
+ return @name unless @name.is_a?(Regexp)
+ @name.source.downcase.gsub(/[^-\w:.]/,'').sub(/^\.+/,'')
+ end
- set[param] = true
- end
+ def name_is_regex?
+ @name.is_a?(Regexp)
+ end
- # Verify that all required arguments are either present or
- # have been provided with defaults.
- arguments.each do |param, default|
- param = param.to_sym
- next if set.include?(param)
+ def parent_type
+ return nil unless parent
- # Even if 'default' is a false value, it's an AST value, so this works fine
- fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default
+ unless @parent_type ||= resource_type_collection.send(type, parent)
+ fail Puppet::ParseError, "Could not find parent resource type '#{parent}' of type #{type}"
+ end
- value = default.safeevaluate(scope)
- scope.setvar(param.to_s, value)
+ @parent_type
+ end
- # Set it in the resource, too, so the value makes it to the client.
- resource[param] = value
- end
+ # Set any arguments passed by the resource as variables in the scope.
+ def set_resource_parameters(resource, scope)
+ set = {}
+ resource.to_hash.each do |param, value|
+ param = param.to_sym
+ fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless valid_parameter?(param)
- scope.setvar("title", resource.title) unless set.include? :title
- scope.setvar("name", resource.name) unless set.include? :name
- scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name
+ exceptwrap { scope.setvar(param.to_s, value) }
- if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name)
- scope.setvar("caller_module_name", caller_name)
- end
- scope.class_set(self.name,scope) if hostclass? or node?
+ set[param] = true
end
- # Create a new subscope in which to evaluate our code.
- def subscope(scope, resource)
- scope.newscope :resource => resource, :namespace => self.namespace, :source => self
- end
+ # Verify that all required arguments are either present or
+ # have been provided with defaults.
+ arguments.each do |param, default|
+ param = param.to_sym
+ next if set.include?(param)
- # Check whether a given argument is valid.
- def valid_parameter?(param)
- param = param.to_s
+ # Even if 'default' is a false value, it's an AST value, so this works fine
+ fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default
- return true if param == "name"
- return true if Puppet::Type.metaparam?(param)
- return false unless defined?(@arguments)
- return(arguments.include?(param) ? true : false)
- end
+ value = default.safeevaluate(scope)
+ scope.setvar(param.to_s, value)
- def set_arguments(arguments)
- @arguments = {}
- return if arguments.nil?
-
- arguments.each do |arg, default|
- arg = arg.to_s
- warn_if_metaparam(arg, default)
- @arguments[arg] = default
- end
+ # Set it in the resource, too, so the value makes it to the client.
+ resource[param] = value
end
- private
-
- def convert_from_ast(name)
- value = name.value
- if value.is_a?(Puppet::Parser::AST::Regex)
- name = value.value
- else
- name = value
- end
- end
+ scope.setvar("title", resource.title) unless set.include? :title
+ scope.setvar("name", resource.name) unless set.include? :name
+ scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name
- def evaluate_parent_type(resource)
- return unless klass = parent_type and parent_resource = resource.scope.compiler.catalog.resource(:class, klass.name) || resource.scope.compiler.catalog.resource(:node, klass.name)
- parent_resource.evaluate unless parent_resource.evaluated?
- parent_scope(resource.scope, klass)
+ if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name)
+ scope.setvar("caller_module_name", caller_name)
end
-
- def evaluate_ruby_code(resource, scope)
- Puppet::DSL::ResourceAPI.new(resource, scope, ruby_code).evaluate
+ scope.class_set(self.name,scope) if hostclass? or node?
+ end
+
+ # Create a new subscope in which to evaluate our code.
+ def subscope(scope, resource)
+ scope.newscope :resource => resource, :namespace => self.namespace, :source => self
+ end
+
+ # Check whether a given argument is valid.
+ def valid_parameter?(param)
+ param = param.to_s
+
+ return true if param == "name"
+ return true if Puppet::Type.metaparam?(param)
+ return false unless defined?(@arguments)
+ return(arguments.include?(param) ? true : false)
+ end
+
+ def set_arguments(arguments)
+ @arguments = {}
+ return if arguments.nil?
+
+ arguments.each do |arg, default|
+ arg = arg.to_s
+ warn_if_metaparam(arg, default)
+ @arguments[arg] = default
end
+ end
- # Split an fq name into a namespace and name
- def namesplit(fullname)
- ary = fullname.split("::")
- n = ary.pop || ""
- ns = ary.join("::")
- return ns, n
- end
+ private
- def parent_scope(scope, klass)
- scope.class_scope(klass) || raise(Puppet::DevError, "Could not find scope for #{klass.name}")
+ def convert_from_ast(name)
+ value = name.value
+ if value.is_a?(Puppet::Parser::AST::Regex)
+ name = value.value
+ else
+ name = value
end
-
- def set_name_and_namespace(name)
- if name.is_a?(Regexp)
- @name = name
- @namespace = ""
- else
- @name = name.to_s.downcase
-
- # Note we're doing something somewhat weird here -- we're setting
- # the class's namespace to its fully qualified name. This means
- # anything inside that class starts looking in that namespace first.
- @namespace, ignored_shortname = @type == :hostclass ? [@name, ''] : namesplit(@name)
- end
+ end
+
+ def evaluate_parent_type(resource)
+ return unless klass = parent_type and parent_resource = resource.scope.compiler.catalog.resource(:class, klass.name) || resource.scope.compiler.catalog.resource(:node, klass.name)
+ parent_resource.evaluate unless parent_resource.evaluated?
+ parent_scope(resource.scope, klass)
+ end
+
+ def evaluate_ruby_code(resource, scope)
+ Puppet::DSL::ResourceAPI.new(resource, scope, ruby_code).evaluate
+ end
+
+ # Split an fq name into a namespace and name
+ def namesplit(fullname)
+ ary = fullname.split("::")
+ n = ary.pop || ""
+ ns = ary.join("::")
+ return ns, n
+ end
+
+ def parent_scope(scope, klass)
+ scope.class_scope(klass) || raise(Puppet::DevError, "Could not find scope for #{klass.name}")
+ end
+
+ def set_name_and_namespace(name)
+ if name.is_a?(Regexp)
+ @name = name
+ @namespace = ""
+ else
+ @name = name.to_s.downcase
+
+ # Note we're doing something somewhat weird here -- we're setting
+ # the class's namespace to its fully qualified name. This means
+ # anything inside that class starts looking in that namespace first.
+ @namespace, ignored_shortname = @type == :hostclass ? [@name, ''] : namesplit(@name)
end
+ end
- def warn_if_metaparam(param, default)
- return unless Puppet::Type.metaparamclass(param)
+ def warn_if_metaparam(param, default)
+ return unless Puppet::Type.metaparamclass(param)
- if default
- warnonce "#{param} is a metaparam; this value will inherit to all contained resources"
- else
- raise Puppet::ParseError, "#{param} is a metaparameter; please choose another parameter name in the #{self.name} definition"
- end
+ if default
+ warnonce "#{param} is a metaparam; this value will inherit to all contained resources"
+ else
+ raise Puppet::ParseError, "#{param} is a metaparameter; please choose another parameter name in the #{self.name} definition"
end
+ end
end
diff --git a/lib/puppet/resource/type_collection.rb b/lib/puppet/resource/type_collection.rb
index 39883ac67..58e8b9497 100644
--- a/lib/puppet/resource/type_collection.rb
+++ b/lib/puppet/resource/type_collection.rb
@@ -1,221 +1,221 @@
class Puppet::Resource::TypeCollection
- attr_reader :environment
+ attr_reader :environment
- def clear
- @hostclasses.clear
- @definitions.clear
- @nodes.clear
- end
+ def clear
+ @hostclasses.clear
+ @definitions.clear
+ @nodes.clear
+ end
- def initialize(env)
- @environment = env.is_a?(String) ? Puppet::Node::Environment.new(env) : env
- @hostclasses = {}
- @definitions = {}
- @nodes = {}
+ def initialize(env)
+ @environment = env.is_a?(String) ? Puppet::Node::Environment.new(env) : env
+ @hostclasses = {}
+ @definitions = {}
+ @nodes = {}
- # So we can keep a list and match the first-defined regex
- @node_list = []
+ # So we can keep a list and match the first-defined regex
+ @node_list = []
- @watched_files = {}
- end
+ @watched_files = {}
+ end
- def <<(thing)
- add(thing)
- self
- end
+ def <<(thing)
+ add(thing)
+ self
+ end
- def add(instance)
- if instance.type == :hostclass and other = @hostclasses[instance.name] and other.type == :hostclass
- other.merge(instance)
- return other
- end
- method = "add_#{instance.type}"
- send(method, instance)
- instance.resource_type_collection = self
- instance
+ def add(instance)
+ if instance.type == :hostclass and other = @hostclasses[instance.name] and other.type == :hostclass
+ other.merge(instance)
+ return other
end
+ method = "add_#{instance.type}"
+ send(method, instance)
+ instance.resource_type_collection = self
+ instance
+ end
- def add_hostclass(instance)
- dupe_check(instance, @hostclasses) { |dupe| "Class '#{instance.name}' is already defined#{dupe.error_context}; cannot redefine" }
- dupe_check(instance, @definitions) { |dupe| "Definition '#{instance.name}' is already defined#{dupe.error_context}; cannot be redefined as a class" }
+ def add_hostclass(instance)
+ dupe_check(instance, @hostclasses) { |dupe| "Class '#{instance.name}' is already defined#{dupe.error_context}; cannot redefine" }
+ dupe_check(instance, @definitions) { |dupe| "Definition '#{instance.name}' is already defined#{dupe.error_context}; cannot be redefined as a class" }
- @hostclasses[instance.name] = instance
- instance
- end
+ @hostclasses[instance.name] = instance
+ instance
+ end
- def hostclass(name)
- @hostclasses[munge_name(name)]
- end
-
- def add_node(instance)
- dupe_check(instance, @nodes) { |dupe| "Node '#{instance.name}' is already defined#{dupe.error_context}; cannot redefine" }
+ def hostclass(name)
+ @hostclasses[munge_name(name)]
+ end
- @node_list << instance
- @nodes[instance.name] = instance
- instance
- end
+ def add_node(instance)
+ dupe_check(instance, @nodes) { |dupe| "Node '#{instance.name}' is already defined#{dupe.error_context}; cannot redefine" }
- def loader
- require 'puppet/parser/type_loader'
- @loader ||= Puppet::Parser::TypeLoader.new(environment)
- end
+ @node_list << instance
+ @nodes[instance.name] = instance
+ instance
+ end
- def node(name)
- name = munge_name(name)
+ def loader
+ require 'puppet/parser/type_loader'
+ @loader ||= Puppet::Parser::TypeLoader.new(environment)
+ end
- if node = @nodes[name]
- return node
- end
+ def node(name)
+ name = munge_name(name)
- @node_list.each do |node|
- next unless node.name_is_regex?
- return node if node.match(name)
- end
- nil
+ if node = @nodes[name]
+ return node
end
- def node_exists?(name)
- @nodes[munge_name(name)]
+ @node_list.each do |node|
+ next unless node.name_is_regex?
+ return node if node.match(name)
end
+ nil
+ end
- def nodes?
- @nodes.length > 0
- end
+ def node_exists?(name)
+ @nodes[munge_name(name)]
+ end
- def add_definition(instance)
- dupe_check(instance, @hostclasses) { |dupe| "'#{instance.name}' is already defined#{dupe.error_context} as a class; cannot redefine as a definition" }
- dupe_check(instance, @definitions) { |dupe| "Definition '#{instance.name}' is already defined#{dupe.error_context}; cannot be redefined" }
- @definitions[instance.name] = instance
- end
+ def nodes?
+ @nodes.length > 0
+ end
+
+ def add_definition(instance)
+ dupe_check(instance, @hostclasses) { |dupe| "'#{instance.name}' is already defined#{dupe.error_context} as a class; cannot redefine as a definition" }
+ dupe_check(instance, @definitions) { |dupe| "Definition '#{instance.name}' is already defined#{dupe.error_context}; cannot be redefined" }
+ @definitions[instance.name] = instance
+ end
- def definition(name)
- @definitions[munge_name(name)]
+ def definition(name)
+ @definitions[munge_name(name)]
+ end
+
+ def find(namespaces, name, type)
+ #Array("") == [] for some reason
+ namespaces = [namespaces] unless namespaces.is_a?(Array)
+
+ if r = find_fully_qualified(name, type)
+ return r
end
- def find(namespaces, name, type)
- #Array("") == [] for some reason
- namespaces = [namespaces] unless namespaces.is_a?(Array)
+ namespaces.each do |namespace|
+ ary = namespace.split("::")
- if r = find_fully_qualified(name, type)
- return r
+ while ary.length > 0
+ tmp_namespace = ary.join("::")
+ if r = find_partially_qualified(tmp_namespace, name, type)
+ return r
end
- namespaces.each do |namespace|
- ary = namespace.split("::")
+ # Delete the second to last object, which reduces our namespace by one.
+ ary.pop
+ end
- while ary.length > 0
- tmp_namespace = ary.join("::")
- if r = find_partially_qualified(tmp_namespace, name, type)
- return r
- end
+ if result = send(type, name)
+ return result
+ end
+ end
+ nil
+ end
- # Delete the second to last object, which reduces our namespace by one.
- ary.pop
- end
+ def find_or_load(namespaces, name, type)
+ name = name.downcase
+ namespaces = [namespaces] unless namespaces.is_a?(Array)
+ namespaces = namespaces.collect { |ns| ns.downcase }
- if result = send(type, name)
- return result
- end
- end
- nil
+ # This could be done in the load_until, but the knowledge seems to
+ # belong here.
+ if r = find(namespaces, name, type)
+ return r
end
- def find_or_load(namespaces, name, type)
- name = name.downcase
- namespaces = [namespaces] unless namespaces.is_a?(Array)
- namespaces = namespaces.collect { |ns| ns.downcase }
+ loader.load_until(namespaces, name) { find(namespaces, name, type) }
+ end
- # This could be done in the load_until, but the knowledge seems to
- # belong here.
- if r = find(namespaces, name, type)
- return r
- end
+ def find_node(name)
+ find("", name, :node)
+ end
- loader.load_until(namespaces, name) { find(namespaces, name, type) }
- end
+ def find_hostclass(namespaces, name)
+ find_or_load(namespaces, name, :hostclass)
+ end
- def find_node(name)
- find("", name, :node)
- end
+ def find_definition(namespaces, name)
+ find_or_load(namespaces, name, :definition)
+ end
- def find_hostclass(namespaces, name)
- find_or_load(namespaces, name, :hostclass)
+ [:hostclasses, :nodes, :definitions].each do |m|
+ define_method(m) do
+ instance_variable_get("@#{m}").dup
end
+ end
- def find_definition(namespaces, name)
- find_or_load(namespaces, name, :definition)
+ def perform_initial_import
+ parser = Puppet::Parser::Parser.new(environment)
+ if code = Puppet.settings.uninterpolated_value(:code, environment.to_s) and code != ""
+ parser.string = code
+ else
+ file = Puppet.settings.value(:manifest, environment.to_s)
+ return unless File.exist?(file)
+ parser.file = file
end
+ parser.parse
+ rescue => detail
+ msg = "Could not parse for environment #{environment}: #{detail}"
+ error = Puppet::Error.new(msg)
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
- [:hostclasses, :nodes, :definitions].each do |m|
- define_method(m) do
- instance_variable_get("@#{m}").dup
- end
- end
+ def stale?
+ @watched_files.values.detect { |file| file.changed? }
+ end
- def perform_initial_import
- parser = Puppet::Parser::Parser.new(environment)
- if code = Puppet.settings.uninterpolated_value(:code, environment.to_s) and code != ""
- parser.string = code
- else
- file = Puppet.settings.value(:manifest, environment.to_s)
- return unless File.exist?(file)
- parser.file = file
- end
- parser.parse
- rescue => detail
- msg = "Could not parse for environment #{environment}: #{detail}"
- error = Puppet::Error.new(msg)
- error.set_backtrace(detail.backtrace)
- raise error
- end
+ def version
+ return @version if defined?(@version)
- def stale?
- @watched_files.values.detect { |file| file.changed? }
+ if environment[:config_version] == ""
+ @version = Time.now.to_i
+ return @version
end
- def version
- return @version if defined?(@version)
+ @version = Puppet::Util.execute([environment[:config_version]]).strip
- if environment[:config_version] == ""
- @version = Time.now.to_i
- return @version
- end
+ rescue Puppet::ExecutionFailure => e
+ raise Puppet::ParseError, "Unable to set config_version: #{e.message}"
+ end
- @version = Puppet::Util.execute([environment[:config_version]]).strip
+ def watch_file(file)
+ @watched_files[file] = Puppet::Util::LoadedFile.new(file)
+ end
- rescue Puppet::ExecutionFailure => e
- raise Puppet::ParseError, "Unable to set config_version: #{e.message}"
- end
+ def watching_file?(file)
+ @watched_files.include?(file)
+ end
- def watch_file(file)
- @watched_files[file] = Puppet::Util::LoadedFile.new(file)
- end
-
- def watching_file?(file)
- @watched_files.include?(file)
- end
-
- private
+ private
- def find_fully_qualified(name, type)
- return nil unless name =~ /^::/
+ def find_fully_qualified(name, type)
+ return nil unless name =~ /^::/
- name = name.sub(/^::/, '')
+ name = name.sub(/^::/, '')
- send(type, name)
- end
+ send(type, name)
+ end
- def find_partially_qualified(namespace, name, type)
- send(type, [namespace, name].join("::"))
- end
+ def find_partially_qualified(namespace, name, type)
+ send(type, [namespace, name].join("::"))
+ end
- def munge_name(name)
- name.to_s.downcase
- end
+ def munge_name(name)
+ name.to_s.downcase
+ end
- def dupe_check(instance, hash)
- return unless dupe = hash[instance.name]
- message = yield dupe
- instance.fail Puppet::ParseError, message
- end
+ def dupe_check(instance, hash)
+ return unless dupe = hash[instance.name]
+ message = yield dupe
+ instance.fail Puppet::ParseError, message
+ end
end
diff --git a/lib/puppet/resource/type_collection_helper.rb b/lib/puppet/resource/type_collection_helper.rb
index 819cfba0b..9dc3cce00 100644
--- a/lib/puppet/resource/type_collection_helper.rb
+++ b/lib/puppet/resource/type_collection_helper.rb
@@ -1,7 +1,7 @@
require 'puppet/resource/type_collection'
module Puppet::Resource::TypeCollectionHelper
- def known_resource_types
- environment.known_resource_types
- end
+ def known_resource_types
+ environment.known_resource_types
+ end
end
diff --git a/lib/puppet/run.rb b/lib/puppet/run.rb
index 658b9677f..150e644a0 100644
--- a/lib/puppet/run.rb
+++ b/lib/puppet/run.rb
@@ -5,73 +5,73 @@ require 'puppet/indirector'
# A basic class for running the agent. Used by
# puppetrun to kick off agents remotely.
class Puppet::Run
- extend Puppet::Indirector
- indirects :run, :terminus_class => :local
+ extend Puppet::Indirector
+ indirects :run, :terminus_class => :local
- attr_reader :status, :background, :options
+ attr_reader :status, :background, :options
- def agent
- Puppet::Agent.new(Puppet::Configurer)
- end
+ def agent
+ Puppet::Agent.new(Puppet::Configurer)
+ end
+
+ def background?
+ background
+ end
- def background?
- background
+ def initialize(options = {})
+ if options.include?(:background)
+ @background = options[:background]
+ options.delete(:background)
end
- def initialize(options = {})
- if options.include?(:background)
- @background = options[:background]
- options.delete(:background)
- end
+ valid_options = [:tags, :ignoreschedules]
+ options.each do |key, value|
+ raise ArgumentError, "Run does not accept #{key}" unless valid_options.include?(key)
+ end
- valid_options = [:tags, :ignoreschedules]
- options.each do |key, value|
- raise ArgumentError, "Run does not accept #{key}" unless valid_options.include?(key)
- end
+ @options = options
+ end
- @options = options
+ def log_run
+ msg = ""
+ msg += "triggered run" % if options[:tags]
+ msg += " with tags #{options[:tags].inspect}"
end
- def log_run
- msg = ""
- msg += "triggered run" % if options[:tags]
- msg += " with tags #{options[:tags].inspect}"
- end
+ msg += " ignoring schedules" if options[:ignoreschedules]
- msg += " ignoring schedules" if options[:ignoreschedules]
+ Puppet.notice msg
+ end
- Puppet.notice msg
+ def run
+ if agent.running?
+ @status = "running"
+ return self
end
- def run
- if agent.running?
- @status = "running"
- return self
- end
+ log_run
- log_run
+ if background?
+ Thread.new { agent.run(options) }
+ else
+ agent.run(options)
+ end
- if background?
- Thread.new { agent.run(options) }
- else
- agent.run(options)
- end
+ @status = "success"
- @status = "success"
+ self
+ end
- self
+ def self.from_pson( pson )
+ options = {}
+ pson.each do |key, value|
+ options[key.to_sym] = value
end
- def self.from_pson( pson )
- options = {}
- pson.each do |key, value|
- options[key.to_sym] = value
- end
+ new(options)
+ end
- new(options)
- end
-
- def to_pson
- @options.merge(:background => @background).to_pson
- end
+ def to_pson
+ @options.merge(:background => @background).to_pson
+ end
end
diff --git a/lib/puppet/simple_graph.rb b/lib/puppet/simple_graph.rb
index 172a0f7b5..945b1beb3 100644
--- a/lib/puppet/simple_graph.rb
+++ b/lib/puppet/simple_graph.rb
@@ -7,295 +7,295 @@ require 'set'
# A hopefully-faster graph class to replace the use of GRATR.
class Puppet::SimpleGraph
- # An internal class for handling a vertex's edges.
- class VertexWrapper
- attr_accessor :in, :out, :vertex
-
- # Remove all references to everything.
- def clear
- @adjacencies[:in].clear
- @adjacencies[:out].clear
- @vertex = nil
- end
-
- def initialize(vertex)
- @vertex = vertex
- @adjacencies = {:in => {}, :out => {}}
- end
-
- # Find adjacent vertices or edges.
- def adjacent(options)
- direction = options[:direction] || :out
- options[:type] ||= :vertices
-
- return send(direction.to_s + "_edges") if options[:type] == :edges
-
- @adjacencies[direction].keys.reject { |vertex| @adjacencies[direction][vertex].empty? }
- end
-
- # Add an edge to our list.
- def add_edge(direction, edge)
- opposite_adjacencies(direction, edge) << edge
- end
-
- # Return all known edges.
- def edges
- in_edges + out_edges
- end
+ # An internal class for handling a vertex's edges.
+ class VertexWrapper
+ attr_accessor :in, :out, :vertex
- # Test whether we share an edge with a given vertex.
- def has_edge?(direction, vertex)
- return(vertex_adjacencies(direction, vertex).length > 0 ? true : false)
- end
-
- # Create methods for returning the degree and edges.
- [:in, :out].each do |direction|
- # LAK:NOTE If you decide to create methods for directly
- # testing the degree, you'll have to get the values and flatten
- # the results -- you might have duplicate edges, which can give
- # a false impression of what the degree is. That's just
- # as expensive as just getting the edge list, so I've decided
- # to only add this method.
- define_method("#{direction}_edges") do
- @adjacencies[direction].values.inject([]) { |total, adjacent| total += adjacent.to_a; total }
- end
- end
-
- # The other vertex in the edge.
- def other_vertex(direction, edge)
- case direction
- when :in; edge.source
- else
- edge.target
- end
- end
-
- # Remove an edge from our list. Assumes that we've already checked
- # that the edge is valid.
- def remove_edge(direction, edge)
- opposite_adjacencies(direction, edge).delete(edge)
- end
-
- def to_s
- vertex.to_s
- end
-
- private
-
- # These methods exist so we don't need a Hash with a default proc.
-
- # Look up the adjacencies for a vertex at the other end of an
- # edge.
- def opposite_adjacencies(direction, edge)
- opposite_vertex = other_vertex(direction, edge)
- vertex_adjacencies(direction, opposite_vertex)
- end
-
- # Look up the adjacencies for a given vertex.
- def vertex_adjacencies(direction, vertex)
- @adjacencies[direction][vertex] ||= Set.new
- @adjacencies[direction][vertex]
- end
- end
-
- def initialize
- @vertices = {}
- @edges = []
- end
-
- # Clear our graph.
+ # Remove all references to everything.
def clear
- @vertices.each { |vertex, wrapper| wrapper.clear }
- @vertices.clear
- @edges.clear
+ @adjacencies[:in].clear
+ @adjacencies[:out].clear
+ @vertex = nil
end
- # Which resources a given resource depends upon.
- def dependents(resource)
- tree_from_vertex(resource).keys
+ def initialize(vertex)
+ @vertex = vertex
+ @adjacencies = {:in => {}, :out => {}}
end
- # Which resources depend upon the given resource.
- def dependencies(resource)
- # Cache the reversal graph, because it's somewhat expensive
- # to create.
- @reversal ||= reversal
- # Strangely, it's significantly faster to search a reversed
- # tree in the :out direction than to search a normal tree
- # in the :in direction.
- @reversal.tree_from_vertex(resource, :out).keys
- end
+ # Find adjacent vertices or edges.
+ def adjacent(options)
+ direction = options[:direction] || :out
+ options[:type] ||= :vertices
- # Whether our graph is directed. Always true. Used to produce dot files.
- def directed?
- true
- end
+ return send(direction.to_s + "_edges") if options[:type] == :edges
- # Determine all of the leaf nodes below a given vertex.
- def leaves(vertex, direction = :out)
- tree = tree_from_vertex(vertex, direction)
- l = tree.keys.find_all { |c| adjacent(c, :direction => direction).empty? }
+ @adjacencies[direction].keys.reject { |vertex| @adjacencies[direction][vertex].empty? }
end
- # Collect all of the edges that the passed events match. Returns
- # an array of edges.
- def matching_edges(event, base = nil)
- source = base || event.resource
-
- unless vertex?(source)
- Puppet.warning "Got an event from invalid vertex #{source.ref}"
- return []
- end
- # Get all of the edges that this vertex should forward events
- # to, which is the same thing as saying all edges directly below
- # This vertex in the graph.
- adjacent(source, :direction => :out, :type => :edges).find_all do |edge|
- edge.match?(event.name)
- end
+ # Add an edge to our list.
+ def add_edge(direction, edge)
+ opposite_adjacencies(direction, edge) << edge
end
- # Return a reversed version of this graph.
- def reversal
- result = self.class.new
- vertices.each { |vertex| result.add_vertex(vertex) }
- edges.each do |edge|
- newedge = edge.class.new(edge.target, edge.source, edge.label)
- result.add_edge(newedge)
- end
- result
+ # Return all known edges.
+ def edges
+ in_edges + out_edges
end
- # Return the size of the graph.
- def size
- @vertices.length
+ # Test whether we share an edge with a given vertex.
+ def has_edge?(direction, vertex)
+ return(vertex_adjacencies(direction, vertex).length > 0 ? true : false)
end
- # Return the graph as an array.
- def to_a
- @vertices.keys
+ # Create methods for returning the degree and edges.
+ [:in, :out].each do |direction|
+ # LAK:NOTE If you decide to create methods for directly
+ # testing the degree, you'll have to get the values and flatten
+ # the results -- you might have duplicate edges, which can give
+ # a false impression of what the degree is. That's just
+ # as expensive as just getting the edge list, so I've decided
+ # to only add this method.
+ define_method("#{direction}_edges") do
+ @adjacencies[direction].values.inject([]) { |total, adjacent| total += adjacent.to_a; total }
+ end
end
- # Provide a topological sort.
- def topsort
- degree = {}
- zeros = []
- result = []
-
- # Collect each of our vertices, with the number of in-edges each has.
- @vertices.each do |name, wrapper|
- edges = wrapper.in_edges
- zeros << wrapper if edges.length == 0
- degree[wrapper.vertex] = edges
- end
-
- # Iterate over each 0-degree vertex, decrementing the degree of
- # each of its out-edges.
- while wrapper = zeros.pop
- result << wrapper.vertex
- wrapper.out_edges.each do |edge|
- degree[edge.target].delete(edge)
- zeros << @vertices[edge.target] if degree[edge.target].length == 0
- end
- end
-
- # If we have any vertices left with non-zero in-degrees, then we've found a cycle.
- if cycles = degree.find_all { |vertex, edges| edges.length > 0 } and cycles.length > 0
- message = cycles.collect { |vertex, edges| edges.collect { |e| e.to_s }.join(", ") }.join(", ")
- raise Puppet::Error, "Found dependency cycles in the following relationships: #{message}; try using the '--graph' option and open the '.dot' files in OmniGraffle or GraphViz"
- end
-
- result
+ # The other vertex in the edge.
+ def other_vertex(direction, edge)
+ case direction
+ when :in; edge.source
+ else
+ edge.target
+ end
end
- # Add a new vertex to the graph.
- def add_vertex(vertex)
- @reversal = nil
- return false if vertex?(vertex)
- setup_vertex(vertex)
- true # don't return the VertexWrapper instance.
+ # Remove an edge from our list. Assumes that we've already checked
+ # that the edge is valid.
+ def remove_edge(direction, edge)
+ opposite_adjacencies(direction, edge).delete(edge)
end
- # Remove a vertex from the graph.
- def remove_vertex!(vertex)
- return nil unless vertex?(vertex)
- @vertices[vertex].edges.each { |edge| remove_edge!(edge) }
- @edges -= @vertices[vertex].edges
- @vertices[vertex].clear
- @vertices.delete(vertex)
+ def to_s
+ vertex.to_s
end
- # Test whether a given vertex is in the graph.
- def vertex?(vertex)
- @vertices.include?(vertex)
- end
+ private
- # Return a list of all vertices.
- def vertices
- @vertices.keys
- end
+ # These methods exist so we don't need a Hash with a default proc.
- # Add a new edge. The graph user has to create the edge instance,
- # since they have to specify what kind of edge it is.
- def add_edge(source, target = nil, label = nil)
- @reversal = nil
- if target
- edge = Puppet::Relationship.new(source, target, label)
- else
- edge = source
- end
- [edge.source, edge.target].each { |vertex| setup_vertex(vertex) unless vertex?(vertex) }
- @vertices[edge.source].add_edge :out, edge
- @vertices[edge.target].add_edge :in, edge
- @edges << edge
- true
+ # Look up the adjacencies for a vertex at the other end of an
+ # edge.
+ def opposite_adjacencies(direction, edge)
+ opposite_vertex = other_vertex(direction, edge)
+ vertex_adjacencies(direction, opposite_vertex)
end
- # Find a matching edge. Note that this only finds the first edge,
- # not all of them or whatever.
- def edge(source, target)
- @edges.each_with_index { |test_edge, index| return test_edge if test_edge.source == source and test_edge.target == target }
+ # Look up the adjacencies for a given vertex.
+ def vertex_adjacencies(direction, vertex)
+ @adjacencies[direction][vertex] ||= Set.new
+ @adjacencies[direction][vertex]
end
-
- def edge_label(source, target)
- return nil unless edge = edge(source, target)
- edge.label
+ end
+
+ def initialize
+ @vertices = {}
+ @edges = []
+ end
+
+ # Clear our graph.
+ def clear
+ @vertices.each { |vertex, wrapper| wrapper.clear }
+ @vertices.clear
+ @edges.clear
+ end
+
+ # Which resources a given resource depends upon.
+ def dependents(resource)
+ tree_from_vertex(resource).keys
+ end
+
+ # Which resources depend upon the given resource.
+ def dependencies(resource)
+ # Cache the reversal graph, because it's somewhat expensive
+ # to create.
+ @reversal ||= reversal
+ # Strangely, it's significantly faster to search a reversed
+ # tree in the :out direction than to search a normal tree
+ # in the :in direction.
+ @reversal.tree_from_vertex(resource, :out).keys
+ end
+
+ # Whether our graph is directed. Always true. Used to produce dot files.
+ def directed?
+ true
+ end
+
+ # Determine all of the leaf nodes below a given vertex.
+ def leaves(vertex, direction = :out)
+ tree = tree_from_vertex(vertex, direction)
+ l = tree.keys.find_all { |c| adjacent(c, :direction => direction).empty? }
+ end
+
+ # Collect all of the edges that the passed events match. Returns
+ # an array of edges.
+ def matching_edges(event, base = nil)
+ source = base || event.resource
+
+ unless vertex?(source)
+ Puppet.warning "Got an event from invalid vertex #{source.ref}"
+ return []
end
-
- # Is there an edge between the two vertices?
- def edge?(source, target)
- return false unless vertex?(source) and vertex?(target)
-
- @vertices[source].has_edge?(:out, target)
+ # Get all of the edges that this vertex should forward events
+ # to, which is the same thing as saying all edges directly below
+ # This vertex in the graph.
+ adjacent(source, :direction => :out, :type => :edges).find_all do |edge|
+ edge.match?(event.name)
end
-
- def edges
- @edges.dup
+ end
+
+ # Return a reversed version of this graph.
+ def reversal
+ result = self.class.new
+ vertices.each { |vertex| result.add_vertex(vertex) }
+ edges.each do |edge|
+ newedge = edge.class.new(edge.target, edge.source, edge.label)
+ result.add_edge(newedge)
end
-
- # Remove an edge from our graph.
- def remove_edge!(edge)
- @vertices[edge.source].remove_edge(:out, edge)
- @vertices[edge.target].remove_edge(:in, edge)
-
- @edges.delete(edge)
- nil
+ result
+ end
+
+ # Return the size of the graph.
+ def size
+ @vertices.length
+ end
+
+ # Return the graph as an array.
+ def to_a
+ @vertices.keys
+ end
+
+ # Provide a topological sort.
+ def topsort
+ degree = {}
+ zeros = []
+ result = []
+
+ # Collect each of our vertices, with the number of in-edges each has.
+ @vertices.each do |name, wrapper|
+ edges = wrapper.in_edges
+ zeros << wrapper if edges.length == 0
+ degree[wrapper.vertex] = edges
end
- # Find adjacent edges.
- def adjacent(vertex, options = {})
- return [] unless wrapper = @vertices[vertex]
- wrapper.adjacent(options)
+ # Iterate over each 0-degree vertex, decrementing the degree of
+ # each of its out-edges.
+ while wrapper = zeros.pop
+ result << wrapper.vertex
+ wrapper.out_edges.each do |edge|
+ degree[edge.target].delete(edge)
+ zeros << @vertices[edge.target] if degree[edge.target].length == 0
+ end
end
- private
-
- # An internal method that skips the validation, so we don't have
- # duplicate validation calls.
- def setup_vertex(vertex)
- @vertices[vertex] = VertexWrapper.new(vertex)
+ # If we have any vertices left with non-zero in-degrees, then we've found a cycle.
+ if cycles = degree.find_all { |vertex, edges| edges.length > 0 } and cycles.length > 0
+ message = cycles.collect { |vertex, edges| edges.collect { |e| e.to_s }.join(", ") }.join(", ")
+ raise Puppet::Error, "Found dependency cycles in the following relationships: #{message}; try using the '--graph' option and open the '.dot' files in OmniGraffle or GraphViz"
end
- public
+ result
+ end
+
+ # Add a new vertex to the graph.
+ def add_vertex(vertex)
+ @reversal = nil
+ return false if vertex?(vertex)
+ setup_vertex(vertex)
+ true # don't return the VertexWrapper instance.
+ end
+
+ # Remove a vertex from the graph.
+ def remove_vertex!(vertex)
+ return nil unless vertex?(vertex)
+ @vertices[vertex].edges.each { |edge| remove_edge!(edge) }
+ @edges -= @vertices[vertex].edges
+ @vertices[vertex].clear
+ @vertices.delete(vertex)
+ end
+
+ # Test whether a given vertex is in the graph.
+ def vertex?(vertex)
+ @vertices.include?(vertex)
+ end
+
+ # Return a list of all vertices.
+ def vertices
+ @vertices.keys
+ end
+
+ # Add a new edge. The graph user has to create the edge instance,
+ # since they have to specify what kind of edge it is.
+ def add_edge(source, target = nil, label = nil)
+ @reversal = nil
+ if target
+ edge = Puppet::Relationship.new(source, target, label)
+ else
+ edge = source
+ end
+ [edge.source, edge.target].each { |vertex| setup_vertex(vertex) unless vertex?(vertex) }
+ @vertices[edge.source].add_edge :out, edge
+ @vertices[edge.target].add_edge :in, edge
+ @edges << edge
+ true
+ end
+
+ # Find a matching edge. Note that this only finds the first edge,
+ # not all of them or whatever.
+ def edge(source, target)
+ @edges.each_with_index { |test_edge, index| return test_edge if test_edge.source == source and test_edge.target == target }
+ end
+
+ def edge_label(source, target)
+ return nil unless edge = edge(source, target)
+ edge.label
+ end
+
+ # Is there an edge between the two vertices?
+ def edge?(source, target)
+ return false unless vertex?(source) and vertex?(target)
+
+ @vertices[source].has_edge?(:out, target)
+ end
+
+ def edges
+ @edges.dup
+ end
+
+ # Remove an edge from our graph.
+ def remove_edge!(edge)
+ @vertices[edge.source].remove_edge(:out, edge)
+ @vertices[edge.target].remove_edge(:in, edge)
+
+ @edges.delete(edge)
+ nil
+ end
+
+ # Find adjacent edges.
+ def adjacent(vertex, options = {})
+ return [] unless wrapper = @vertices[vertex]
+ wrapper.adjacent(options)
+ end
+
+ private
+
+ # An internal method that skips the validation, so we don't have
+ # duplicate validation calls.
+ def setup_vertex(vertex)
+ @vertices[vertex] = VertexWrapper.new(vertex)
+ end
+
+ public
# # For some reason, unconnected vertices do not show up in
# # this graph.
@@ -306,144 +306,144 @@ class Puppet::SimpleGraph
# end
# end
- # Take container information from another graph and use it
- # to replace any container vertices with their respective leaves.
- # This creates direct relationships where there were previously
- # indirect relationships through the containers.
- def splice!(other, type)
- # We have to get the container list via a topological sort on the
- # configuration graph, because otherwise containers that contain
- # other containers will add those containers back into the
- # graph. We could get a similar affect by only setting relationships
- # to container leaves, but that would result in many more
- # relationships.
- stage_class = Puppet::Type.type(:stage)
- containers = other.topsort.find_all { |v| (v.is_a?(type) or v.is_a?(stage_class)) and vertex?(v) }
- containers.each do |container|
- # Get the list of children from the other graph.
- children = other.adjacent(container, :direction => :out)
-
- # Just remove the container if it's empty.
- if children.empty?
- remove_vertex!(container)
- next
- end
-
- # First create new edges for each of the :in edges
- [:in, :out].each do |dir|
- edges = adjacent(container, :direction => dir, :type => :edges)
- edges.each do |edge|
- children.each do |child|
- if dir == :in
- s = edge.source
- t = child
- else
- s = child
- t = edge.target
- end
-
- add_edge(s, t, edge.label)
- end
-
- # Now get rid of the edge, so remove_vertex! works correctly.
- remove_edge!(edge)
- end
+ # Take container information from another graph and use it
+ # to replace any container vertices with their respective leaves.
+ # This creates direct relationships where there were previously
+ # indirect relationships through the containers.
+ def splice!(other, type)
+ # We have to get the container list via a topological sort on the
+ # configuration graph, because otherwise containers that contain
+ # other containers will add those containers back into the
+ # graph. We could get a similar affect by only setting relationships
+ # to container leaves, but that would result in many more
+ # relationships.
+ stage_class = Puppet::Type.type(:stage)
+ containers = other.topsort.find_all { |v| (v.is_a?(type) or v.is_a?(stage_class)) and vertex?(v) }
+ containers.each do |container|
+ # Get the list of children from the other graph.
+ children = other.adjacent(container, :direction => :out)
+
+ # Just remove the container if it's empty.
+ if children.empty?
+ remove_vertex!(container)
+ next
+ end
+
+ # First create new edges for each of the :in edges
+ [:in, :out].each do |dir|
+ edges = adjacent(container, :direction => dir, :type => :edges)
+ edges.each do |edge|
+ children.each do |child|
+ if dir == :in
+ s = edge.source
+ t = child
+ else
+ s = child
+ t = edge.target
end
- remove_vertex!(container)
- end
- end
- # Just walk the tree and pass each edge.
- def walk(source, direction)
- # Use an iterative, breadth-first traversal of the graph. One could do
- # this recursively, but Ruby's slow function calls and even slower
- # recursion make the shorter, recursive algorithm cost-prohibitive.
- stack = [source]
- seen = Set.new
- until stack.empty?
- node = stack.shift
- next if seen.member? node
- connected = adjacent(node, :direction => direction)
- connected.each do |target|
- yield node, target
- end
- stack.concat(connected)
- seen << node
- end
- end
+ add_edge(s, t, edge.label)
+ end
- # A different way of walking a tree, and a much faster way than the
- # one that comes with GRATR.
- def tree_from_vertex(start, direction = :out)
- predecessor={}
- walk(start, direction) do |parent, child|
- predecessor[child] = parent
+ # Now get rid of the edge, so remove_vertex! works correctly.
+ remove_edge!(edge)
end
- predecessor
+ end
+ remove_vertex!(container)
end
-
- # LAK:FIXME This is just a paste of the GRATR code with slight modifications.
-
- # Return a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for an
- # undirected Graph. _params_ can contain any graph property specified in
- # rdot.rb. If an edge or vertex label is a kind of Hash then the keys
- # which match +dot+ properties will be used as well.
- def to_dot_graph (params = {})
- params['name'] ||= self.class.name.gsub(/:/,'_')
- fontsize = params['fontsize'] ? params['fontsize'] : '8'
- graph = (directed? ? DOT::DOTDigraph : DOT::DOTSubgraph).new(params)
- edge_klass = directed? ? DOT::DOTDirectedEdge : DOT::DOTEdge
- vertices.each do |v|
- name = v.to_s
- params = {'name' => '"'+name+'"',
- 'fontsize' => fontsize,
- 'label' => name}
- v_label = v.to_s
- params.merge!(v_label) if v_label and v_label.kind_of? Hash
- graph << DOT::DOTNode.new(params)
- end
- edges.each do |e|
- params = {'from' => '"'+ e.source.to_s + '"',
- 'to' => '"'+ e.target.to_s + '"',
- 'fontsize' => fontsize }
- e_label = e.to_s
- params.merge!(e_label) if e_label and e_label.kind_of? Hash
- graph << edge_klass.new(params)
- end
- graph
+ end
+
+ # Just walk the tree and pass each edge.
+ def walk(source, direction)
+ # Use an iterative, breadth-first traversal of the graph. One could do
+ # this recursively, but Ruby's slow function calls and even slower
+ # recursion make the shorter, recursive algorithm cost-prohibitive.
+ stack = [source]
+ seen = Set.new
+ until stack.empty?
+ node = stack.shift
+ next if seen.member? node
+ connected = adjacent(node, :direction => direction)
+ connected.each do |target|
+ yield node, target
+ end
+ stack.concat(connected)
+ seen << node
end
-
- # Output the dot format as a string
- def to_dot (params={}) to_dot_graph(params).to_s; end
-
- # Call +dotty+ for the graph which is written to the file 'graph.dot'
- # in the # current directory.
- def dotty (params = {}, dotfile = 'graph.dot')
- File.open(dotfile, 'w') {|f| f << to_dot(params) }
- system('dotty', dotfile)
+ end
+
+ # A different way of walking a tree, and a much faster way than the
+ # one that comes with GRATR.
+ def tree_from_vertex(start, direction = :out)
+ predecessor={}
+ walk(start, direction) do |parent, child|
+ predecessor[child] = parent
end
-
- # Use +dot+ to create a graphical representation of the graph. Returns the
- # filename of the graphics file.
- def write_to_graphic_file (fmt='png', dotfile='graph')
- src = dotfile + '.dot'
- dot = dotfile + '.' + fmt
-
- File.open(src, 'w') {|f| f << self.to_dot << "\n"}
-
- system( "dot -T#{fmt} #{src} -o #{dot}" )
- dot
+ predecessor
+ end
+
+ # LAK:FIXME This is just a paste of the GRATR code with slight modifications.
+
+ # Return a DOT::DOTDigraph for directed graphs or a DOT::DOTSubgraph for an
+ # undirected Graph. _params_ can contain any graph property specified in
+ # rdot.rb. If an edge or vertex label is a kind of Hash then the keys
+ # which match +dot+ properties will be used as well.
+ def to_dot_graph (params = {})
+ params['name'] ||= self.class.name.gsub(/:/,'_')
+ fontsize = params['fontsize'] ? params['fontsize'] : '8'
+ graph = (directed? ? DOT::DOTDigraph : DOT::DOTSubgraph).new(params)
+ edge_klass = directed? ? DOT::DOTDirectedEdge : DOT::DOTEdge
+ vertices.each do |v|
+ name = v.to_s
+ params = {'name' => '"'+name+'"',
+ 'fontsize' => fontsize,
+ 'label' => name}
+ v_label = v.to_s
+ params.merge!(v_label) if v_label and v_label.kind_of? Hash
+ graph << DOT::DOTNode.new(params)
end
-
- # Produce the graph files if requested.
- def write_graph(name)
- return unless Puppet[:graph]
-
- Puppet.settings.use(:graphing)
-
- file = File.join(Puppet[:graphdir], "#{name}.dot")
- File.open(file, "w") { |f|
- f.puts to_dot("name" => name.to_s.capitalize)
- }
+ edges.each do |e|
+ params = {'from' => '"'+ e.source.to_s + '"',
+ 'to' => '"'+ e.target.to_s + '"',
+ 'fontsize' => fontsize }
+ e_label = e.to_s
+ params.merge!(e_label) if e_label and e_label.kind_of? Hash
+ graph << edge_klass.new(params)
end
+ graph
+ end
+
+ # Output the dot format as a string
+ def to_dot (params={}) to_dot_graph(params).to_s; end
+
+ # Call +dotty+ for the graph which is written to the file 'graph.dot'
+ # in the # current directory.
+ def dotty (params = {}, dotfile = 'graph.dot')
+ File.open(dotfile, 'w') {|f| f << to_dot(params) }
+ system('dotty', dotfile)
+ end
+
+ # Use +dot+ to create a graphical representation of the graph. Returns the
+ # filename of the graphics file.
+ def write_to_graphic_file (fmt='png', dotfile='graph')
+ src = dotfile + '.dot'
+ dot = dotfile + '.' + fmt
+
+ File.open(src, 'w') {|f| f << self.to_dot << "\n"}
+
+ system( "dot -T#{fmt} #{src} -o #{dot}" )
+ dot
+ end
+
+ # Produce the graph files if requested.
+ def write_graph(name)
+ return unless Puppet[:graph]
+
+ Puppet.settings.use(:graphing)
+
+ file = File.join(Puppet[:graphdir], "#{name}.dot")
+ File.open(file, "w") { |f|
+ f.puts to_dot("name" => name.to_s.capitalize)
+ }
+ end
end
diff --git a/lib/puppet/ssl.rb b/lib/puppet/ssl.rb
index 9cb67a66c..8f71ba8a4 100644
--- a/lib/puppet/ssl.rb
+++ b/lib/puppet/ssl.rb
@@ -3,6 +3,6 @@ require 'puppet'
require 'openssl'
module Puppet::SSL # :nodoc:
- CA_NAME = "ca"
- require 'puppet/ssl/host'
+ CA_NAME = "ca"
+ require 'puppet/ssl/host'
end
diff --git a/lib/puppet/ssl/base.rb b/lib/puppet/ssl/base.rb
index 745d733dc..f9bbcac64 100644
--- a/lib/puppet/ssl/base.rb
+++ b/lib/puppet/ssl/base.rb
@@ -2,78 +2,78 @@ require 'puppet/ssl'
# The base class for wrapping SSL instances.
class Puppet::SSL::Base
- # For now, use the YAML separator.
- SEPARATOR = "\n---\n"
-
- def self.from_multiple_s(text)
- text.split(SEPARATOR).collect { |inst| from_s(inst) }
- end
-
- def self.to_multiple_s(instances)
- instances.collect { |inst| inst.to_s }.join(SEPARATOR)
- end
-
- def self.wraps(klass)
- @wrapped_class = klass
- end
-
- def self.wrapped_class
- raise(Puppet::DevError, "#{self} has not declared what class it wraps") unless defined?(@wrapped_class)
- @wrapped_class
- end
-
- attr_accessor :name, :content
-
- # Is this file for the CA?
- def ca?
- name == Puppet::SSL::Host.ca_name
- end
-
- def generate
- raise Puppet::DevError, "#{self.class} did not override 'generate'"
- end
-
- def initialize(name)
- @name = name.to_s.downcase
+ # For now, use the YAML separator.
+ SEPARATOR = "\n---\n"
+
+ def self.from_multiple_s(text)
+ text.split(SEPARATOR).collect { |inst| from_s(inst) }
+ end
+
+ def self.to_multiple_s(instances)
+ instances.collect { |inst| inst.to_s }.join(SEPARATOR)
+ end
+
+ def self.wraps(klass)
+ @wrapped_class = klass
+ end
+
+ def self.wrapped_class
+ raise(Puppet::DevError, "#{self} has not declared what class it wraps") unless defined?(@wrapped_class)
+ @wrapped_class
+ end
+
+ attr_accessor :name, :content
+
+ # Is this file for the CA?
+ def ca?
+ name == Puppet::SSL::Host.ca_name
+ end
+
+ def generate
+ raise Puppet::DevError, "#{self.class} did not override 'generate'"
+ end
+
+ def initialize(name)
+ @name = name.to_s.downcase
+ end
+
+ # Read content from disk appropriately.
+ def read(path)
+ @content = wrapped_class.new(File.read(path))
+ end
+
+ # Convert our thing to pem.
+ def to_s
+ return "" unless content
+ content.to_pem
+ end
+
+ # Provide the full text of the thing we're dealing with.
+ def to_text
+ return "" unless content
+ content.to_text
+ end
+
+ def fingerprint(md = :MD5)
+ require 'openssl/digest'
+
+ # ruby 1.8.x openssl digest constants are string
+ # but in 1.9.x they are symbols
+ mds = md.to_s.upcase
+ if OpenSSL::Digest.constants.include?(mds)
+ md = mds
+ elsif OpenSSL::Digest.constants.include?(mds.to_sym)
+ md = mds.to_sym
+ else
+ raise ArgumentError, "#{md} is not a valid digest algorithm for fingerprinting certificate #{name}"
end
- # Read content from disk appropriately.
- def read(path)
- @content = wrapped_class.new(File.read(path))
- end
+ OpenSSL::Digest.const_get(md).hexdigest(content.to_der).scan(/../).join(':').upcase
+ end
- # Convert our thing to pem.
- def to_s
- return "" unless content
- content.to_pem
- end
+ private
- # Provide the full text of the thing we're dealing with.
- def to_text
- return "" unless content
- content.to_text
- end
-
- def fingerprint(md = :MD5)
- require 'openssl/digest'
-
- # ruby 1.8.x openssl digest constants are string
- # but in 1.9.x they are symbols
- mds = md.to_s.upcase
- if OpenSSL::Digest.constants.include?(mds)
- md = mds
- elsif OpenSSL::Digest.constants.include?(mds.to_sym)
- md = mds.to_sym
- else
- raise ArgumentError, "#{md} is not a valid digest algorithm for fingerprinting certificate #{name}"
- end
-
- OpenSSL::Digest.const_get(md).hexdigest(content.to_der).scan(/../).join(':').upcase
- end
-
- private
-
- def wrapped_class
- self.class.wrapped_class
- end
+ def wrapped_class
+ self.class.wrapped_class
+ end
end
diff --git a/lib/puppet/ssl/certificate.rb b/lib/puppet/ssl/certificate.rb
index 07dd0c8e6..a0e600291 100644
--- a/lib/puppet/ssl/certificate.rb
+++ b/lib/puppet/ssl/certificate.rb
@@ -6,29 +6,29 @@ require 'puppet/ssl/base'
# retrieve them from the CA (or not, as is often
# the case).
class Puppet::SSL::Certificate < Puppet::SSL::Base
- # This is defined from the base class
- wraps OpenSSL::X509::Certificate
+ # This is defined from the base class
+ wraps OpenSSL::X509::Certificate
- extend Puppet::Indirector
- indirects :certificate, :terminus_class => :file
+ extend Puppet::Indirector
+ indirects :certificate, :terminus_class => :file
- # Convert a string into an instance.
- def self.from_s(string)
- instance = wrapped_class.new(string)
- name = instance.subject.to_s.sub(/\/CN=/i, '').downcase
- result = new(name)
- result.content = instance
- result
- end
+ # Convert a string into an instance.
+ def self.from_s(string)
+ instance = wrapped_class.new(string)
+ name = instance.subject.to_s.sub(/\/CN=/i, '').downcase
+ result = new(name)
+ result.content = instance
+ result
+ end
- # Because of how the format handler class is included, this
- # can't be in the base class.
- def self.supported_formats
- [:s]
- end
+ # Because of how the format handler class is included, this
+ # can't be in the base class.
+ def self.supported_formats
+ [:s]
+ end
- def expiration
- return nil unless content
- content.not_after
- end
+ def expiration
+ return nil unless content
+ content.not_after
+ end
end
diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb
index 26febb3d3..efe562d4c 100644
--- a/lib/puppet/ssl/certificate_authority.rb
+++ b/lib/puppet/ssl/certificate_authority.rb
@@ -11,274 +11,274 @@ require 'puppet/util/cacher'
# it can also be seen as a general interface into all of the
# SSL stuff.
class Puppet::SSL::CertificateAuthority
- require 'puppet/ssl/certificate_factory'
- require 'puppet/ssl/inventory'
- require 'puppet/ssl/certificate_revocation_list'
+ require 'puppet/ssl/certificate_factory'
+ require 'puppet/ssl/inventory'
+ require 'puppet/ssl/certificate_revocation_list'
- require 'puppet/ssl/certificate_authority/interface'
+ require 'puppet/ssl/certificate_authority/interface'
- class CertificateVerificationError < RuntimeError
- attr_accessor :error_code
+ class CertificateVerificationError < RuntimeError
+ attr_accessor :error_code
- def initialize(code)
- @error_code = code
- end
+ def initialize(code)
+ @error_code = code
end
+ end
- class << self
- include Puppet::Util::Cacher
+ class << self
+ include Puppet::Util::Cacher
- cached_attr(:singleton_instance) { new }
- end
+ cached_attr(:singleton_instance) { new }
+ end
- def self.ca?
- return false unless Puppet[:ca]
- return false unless Puppet.run_mode.master?
- true
- end
+ def self.ca?
+ return false unless Puppet[:ca]
+ return false unless Puppet.run_mode.master?
+ true
+ end
- # If this process can function as a CA, then return a singleton
- # instance.
- def self.instance
- return nil unless ca?
+ # If this process can function as a CA, then return a singleton
+ # instance.
+ def self.instance
+ return nil unless ca?
- singleton_instance
- end
+ singleton_instance
+ end
- attr_reader :name, :host
+ attr_reader :name, :host
- # Create and run an applicator. I wanted to build an interface where you could do
- # something like 'ca.apply(:generate).to(:all) but I don't think it's really possible.
- def apply(method, options)
- raise ArgumentError, "You must specify the hosts to apply to; valid values are an array or the symbol :all" unless options[:to]
- applier = Interface.new(method, options)
+ # Create and run an applicator. I wanted to build an interface where you could do
+ # something like 'ca.apply(:generate).to(:all) but I don't think it's really possible.
+ def apply(method, options)
+ raise ArgumentError, "You must specify the hosts to apply to; valid values are an array or the symbol :all" unless options[:to]
+ applier = Interface.new(method, options)
- applier.apply(self)
- end
+ applier.apply(self)
+ end
- # If autosign is configured, then autosign all CSRs that match our configuration.
- def autosign
- return unless auto = autosign?
+ # If autosign is configured, then autosign all CSRs that match our configuration.
+ def autosign
+ return unless auto = autosign?
- store = nil
- store = autosign_store(auto) if auto != true
+ store = nil
+ store = autosign_store(auto) if auto != true
- Puppet::SSL::CertificateRequest.search("*").each do |csr|
- sign(csr.name) if auto == true or store.allowed?(csr.name, "127.1.1.1")
- end
+ Puppet::SSL::CertificateRequest.search("*").each do |csr|
+ sign(csr.name) if auto == true or store.allowed?(csr.name, "127.1.1.1")
+ end
+ end
+
+ # Do we autosign? This returns true, false, or a filename.
+ def autosign?
+ auto = Puppet[:autosign]
+ return false if ['false', false].include?(auto)
+ return true if ['true', true].include?(auto)
+
+ raise ArgumentError, "The autosign configuration '#{auto}' must be a fully qualified file" unless auto =~ /^\//
+ FileTest.exist?(auto) && auto
+ end
+
+ # Create an AuthStore for autosigning.
+ def autosign_store(file)
+ auth = Puppet::Network::AuthStore.new
+ File.readlines(file).each do |line|
+ next if line =~ /^\s*#/
+ next if line =~ /^\s*$/
+ auth.allow(line.chomp)
end
- # Do we autosign? This returns true, false, or a filename.
- def autosign?
- auto = Puppet[:autosign]
- return false if ['false', false].include?(auto)
- return true if ['true', true].include?(auto)
-
- raise ArgumentError, "The autosign configuration '#{auto}' must be a fully qualified file" unless auto =~ /^\//
- FileTest.exist?(auto) && auto
+ auth
+ end
+
+ # Retrieve (or create, if necessary) the certificate revocation list.
+ def crl
+ unless defined?(@crl)
+ unless @crl = Puppet::SSL::CertificateRevocationList.find(Puppet::SSL::CA_NAME)
+ @crl = Puppet::SSL::CertificateRevocationList.new(Puppet::SSL::CA_NAME)
+ @crl.generate(host.certificate.content, host.key.content)
+ @crl.save
+ end
end
+ @crl
+ end
- # Create an AuthStore for autosigning.
- def autosign_store(file)
- auth = Puppet::Network::AuthStore.new
- File.readlines(file).each do |line|
- next if line =~ /^\s*#/
- next if line =~ /^\s*$/
- auth.allow(line.chomp)
- end
+ # Delegate this to our Host class.
+ def destroy(name)
+ Puppet::SSL::Host.destroy(name)
+ end
- auth
- end
+ # Generate a new certificate.
+ def generate(name)
+ raise ArgumentError, "A Certificate already exists for #{name}" if Puppet::SSL::Certificate.find(name)
+ host = Puppet::SSL::Host.new(name)
- # Retrieve (or create, if necessary) the certificate revocation list.
- def crl
- unless defined?(@crl)
- unless @crl = Puppet::SSL::CertificateRevocationList.find(Puppet::SSL::CA_NAME)
- @crl = Puppet::SSL::CertificateRevocationList.new(Puppet::SSL::CA_NAME)
- @crl.generate(host.certificate.content, host.key.content)
- @crl.save
- end
- end
- @crl
- end
+ host.generate_certificate_request
- # Delegate this to our Host class.
- def destroy(name)
- Puppet::SSL::Host.destroy(name)
- end
+ sign(name)
+ end
- # Generate a new certificate.
- def generate(name)
- raise ArgumentError, "A Certificate already exists for #{name}" if Puppet::SSL::Certificate.find(name)
- host = Puppet::SSL::Host.new(name)
+ # Generate our CA certificate.
+ def generate_ca_certificate
+ generate_password unless password?
- host.generate_certificate_request
+ host.generate_key unless host.key
- sign(name)
- end
+ # Create a new cert request. We do this
+ # specially, because we don't want to actually
+ # save the request anywhere.
+ request = Puppet::SSL::CertificateRequest.new(host.name)
+ request.generate(host.key)
- # Generate our CA certificate.
- def generate_ca_certificate
- generate_password unless password?
+ # Create a self-signed certificate.
+ @certificate = sign(host.name, :ca, request)
- host.generate_key unless host.key
+ # And make sure we initialize our CRL.
+ crl
+ end
- # Create a new cert request. We do this
- # specially, because we don't want to actually
- # save the request anywhere.
- request = Puppet::SSL::CertificateRequest.new(host.name)
- request.generate(host.key)
+ def initialize
+ Puppet.settings.use :main, :ssl, :ca
- # Create a self-signed certificate.
- @certificate = sign(host.name, :ca, request)
+ @name = Puppet[:certname]
- # And make sure we initialize our CRL.
- crl
- end
+ @host = Puppet::SSL::Host.new(Puppet::SSL::Host.ca_name)
- def initialize
- Puppet.settings.use :main, :ssl, :ca
+ setup
+ end
- @name = Puppet[:certname]
+ # Retrieve (or create, if necessary) our inventory manager.
+ def inventory
+ @inventory ||= Puppet::SSL::Inventory.new
+ end
- @host = Puppet::SSL::Host.new(Puppet::SSL::Host.ca_name)
+ # Generate a new password for the CA.
+ def generate_password
+ pass = ""
+ 20.times { pass += (rand(74) + 48).chr }
- setup
+ begin
+ Puppet.settings.write(:capass) { |f| f.print pass }
+ rescue Errno::EACCES => detail
+ raise Puppet::Error, "Could not write CA password: #{detail}"
end
- # Retrieve (or create, if necessary) our inventory manager.
- def inventory
- @inventory ||= Puppet::SSL::Inventory.new
- end
+ @password = pass
- # Generate a new password for the CA.
- def generate_password
- pass = ""
- 20.times { pass += (rand(74) + 48).chr }
+ pass
+ end
- begin
- Puppet.settings.write(:capass) { |f| f.print pass }
- rescue Errno::EACCES => detail
- raise Puppet::Error, "Could not write CA password: #{detail}"
- end
+ # List all signed certificates.
+ def list
+ Puppet::SSL::Certificate.search("*").collect { |c| c.name }
+ end
- @password = pass
+ # Read the next serial from the serial file, and increment the
+ # file so this one is considered used.
+ def next_serial
+ serial = nil
- pass
- end
+ # This is slightly odd. If the file doesn't exist, our readwritelock creates
+ # it, but with a mode we can't actually read in some cases. So, use
+ # a default before the lock.
+ serial = 0x1 unless FileTest.exist?(Puppet[:serial])
- # List all signed certificates.
- def list
- Puppet::SSL::Certificate.search("*").collect { |c| c.name }
- end
+ Puppet.settings.readwritelock(:serial) { |f|
+ serial ||= File.read(Puppet.settings[:serial]).chomp.hex if FileTest.exist?(Puppet[:serial])
- # Read the next serial from the serial file, and increment the
- # file so this one is considered used.
- def next_serial
- serial = nil
+ # We store the next valid serial, not the one we just used.
+ f << "%04X" % (serial + 1)
+ }
- # This is slightly odd. If the file doesn't exist, our readwritelock creates
- # it, but with a mode we can't actually read in some cases. So, use
- # a default before the lock.
- serial = 0x1 unless FileTest.exist?(Puppet[:serial])
+ serial
+ end
- Puppet.settings.readwritelock(:serial) { |f|
- serial ||= File.read(Puppet.settings[:serial]).chomp.hex if FileTest.exist?(Puppet[:serial])
+ # Does the password file exist?
+ def password?
+ FileTest.exist? Puppet[:capass]
+ end
- # We store the next valid serial, not the one we just used.
- f << "%04X" % (serial + 1)
- }
+ # Print a given host's certificate as text.
+ def print(name)
+ (cert = Puppet::SSL::Certificate.find(name)) ? cert.to_text : nil
+ end
- serial
- end
+ # Revoke a given certificate.
+ def revoke(name)
+ raise ArgumentError, "Cannot revoke certificates when the CRL is disabled" unless crl
- # Does the password file exist?
- def password?
- FileTest.exist? Puppet[:capass]
+ if cert = Puppet::SSL::Certificate.find(name)
+ serial = cert.content.serial
+ elsif ! serial = inventory.serial(name)
+ raise ArgumentError, "Could not find a serial number for #{name}"
end
-
- # Print a given host's certificate as text.
- def print(name)
- (cert = Puppet::SSL::Certificate.find(name)) ? cert.to_text : nil
+ crl.revoke(serial, host.key.content)
+ end
+
+ # This initializes our CA so it actually works. This should be a private
+ # method, except that you can't any-instance stub private methods, which is
+ # *awesome*. This method only really exists to provide a stub-point during
+ # testing.
+ def setup
+ generate_ca_certificate unless @host.certificate
+ end
+
+ # Sign a given certificate request.
+ def sign(hostname, cert_type = :server, self_signing_csr = nil)
+ # This is a self-signed certificate
+ if self_signing_csr
+ csr = self_signing_csr
+ issuer = csr.content
+ else
+ unless csr = Puppet::SSL::CertificateRequest.find(hostname)
+ raise ArgumentError, "Could not find certificate request for #{hostname}"
+ end
+ issuer = host.certificate.content
end
- # Revoke a given certificate.
- def revoke(name)
- raise ArgumentError, "Cannot revoke certificates when the CRL is disabled" unless crl
+ cert = Puppet::SSL::Certificate.new(hostname)
+ cert.content = Puppet::SSL::CertificateFactory.new(cert_type, csr.content, issuer, next_serial).result
+ cert.content.sign(host.key.content, OpenSSL::Digest::SHA1.new)
- if cert = Puppet::SSL::Certificate.find(name)
- serial = cert.content.serial
- elsif ! serial = inventory.serial(name)
- raise ArgumentError, "Could not find a serial number for #{name}"
- end
- crl.revoke(serial, host.key.content)
- end
+ Puppet.notice "Signed certificate request for #{hostname}"
- # This initializes our CA so it actually works. This should be a private
- # method, except that you can't any-instance stub private methods, which is
- # *awesome*. This method only really exists to provide a stub-point during
- # testing.
- def setup
- generate_ca_certificate unless @host.certificate
- end
+ # Add the cert to the inventory before we save it, since
+ # otherwise we could end up with it being duplicated, if
+ # this is the first time we build the inventory file.
+ inventory.add(cert)
- # Sign a given certificate request.
- def sign(hostname, cert_type = :server, self_signing_csr = nil)
- # This is a self-signed certificate
- if self_signing_csr
- csr = self_signing_csr
- issuer = csr.content
- else
- unless csr = Puppet::SSL::CertificateRequest.find(hostname)
- raise ArgumentError, "Could not find certificate request for #{hostname}"
- end
- issuer = host.certificate.content
- end
-
- cert = Puppet::SSL::Certificate.new(hostname)
- cert.content = Puppet::SSL::CertificateFactory.new(cert_type, csr.content, issuer, next_serial).result
- cert.content.sign(host.key.content, OpenSSL::Digest::SHA1.new)
-
- Puppet.notice "Signed certificate request for #{hostname}"
-
- # Add the cert to the inventory before we save it, since
- # otherwise we could end up with it being duplicated, if
- # this is the first time we build the inventory file.
- inventory.add(cert)
-
- # Save the now-signed cert. This should get routed correctly depending
- # on the certificate type.
- cert.save
-
- # And remove the CSR if this wasn't self signed.
- Puppet::SSL::CertificateRequest.destroy(csr.name) unless self_signing_csr
-
- cert
- end
+ # Save the now-signed cert. This should get routed correctly depending
+ # on the certificate type.
+ cert.save
- # Verify a given host's certificate.
- def verify(name)
- unless cert = Puppet::SSL::Certificate.find(name)
- raise ArgumentError, "Could not find a certificate for #{name}"
- end
- store = OpenSSL::X509::Store.new
- store.add_file Puppet[:cacert]
- store.add_crl crl.content if self.crl
- store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
- store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
-
- raise CertificateVerificationError.new(store.error), store.error_string unless store.verify(cert.content)
- end
+ # And remove the CSR if this wasn't self signed.
+ Puppet::SSL::CertificateRequest.destroy(csr.name) unless self_signing_csr
- def fingerprint(name, md = :MD5)
- unless cert = Puppet::SSL::Certificate.find(name) || Puppet::SSL::CertificateRequest.find(name)
- raise ArgumentError, "Could not find a certificate or csr for #{name}"
- end
- cert.fingerprint(md)
- end
+ cert
+ end
- # List the waiting certificate requests.
- def waiting?
- Puppet::SSL::CertificateRequest.search("*").collect { |r| r.name }
+ # Verify a given host's certificate.
+ def verify(name)
+ unless cert = Puppet::SSL::Certificate.find(name)
+ raise ArgumentError, "Could not find a certificate for #{name}"
end
+ store = OpenSSL::X509::Store.new
+ store.add_file Puppet[:cacert]
+ store.add_crl crl.content if self.crl
+ store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
+ store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
+
+ raise CertificateVerificationError.new(store.error), store.error_string unless store.verify(cert.content)
+ end
+
+ def fingerprint(name, md = :MD5)
+ unless cert = Puppet::SSL::Certificate.find(name) || Puppet::SSL::CertificateRequest.find(name)
+ raise ArgumentError, "Could not find a certificate or csr for #{name}"
+ end
+ cert.fingerprint(md)
+ end
+
+ # List the waiting certificate requests.
+ def waiting?
+ Puppet::SSL::CertificateRequest.search("*").collect { |r| r.name }
+ end
end
diff --git a/lib/puppet/ssl/certificate_authority/interface.rb b/lib/puppet/ssl/certificate_authority/interface.rb
index e5ede3c6c..f73eff5f3 100644
--- a/lib/puppet/ssl/certificate_authority/interface.rb
+++ b/lib/puppet/ssl/certificate_authority/interface.rb
@@ -2,133 +2,133 @@
# on the CA. It's only used by the 'puppetca' executable, and its
# job is to provide a CLI-like interface to the CA class.
module Puppet
- module SSL
- class CertificateAuthority
- class Interface
- INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify, :fingerprint]
-
- class InterfaceError < ArgumentError; end
-
- attr_reader :method, :subjects, :digest
-
- # Actually perform the work.
- def apply(ca)
- unless subjects or method == :list
- raise ArgumentError, "You must provide hosts or :all when using #{method}"
- end
-
- begin
- return send(method, ca) if respond_to?(method)
-
- (subjects == :all ? ca.list : subjects).each do |host|
- ca.send(method, host)
- end
- rescue InterfaceError
- raise
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not call #{method}: #{detail}"
- end
- end
-
- def generate(ca)
- raise InterfaceError, "It makes no sense to generate all hosts; you must specify a list" if subjects == :all
-
- subjects.each do |host|
- ca.generate(host)
- end
- end
-
- def initialize(method, options)
- self.method = method
- self.subjects = options[:to]
- @digest = options[:digest] || :MD5
- end
-
- # List the hosts.
- def list(ca)
- unless subjects
- puts ca.waiting?.join("\n")
- return nil
- end
-
- signed = ca.list
- requests = ca.waiting?
-
- if subjects == :all
- hosts = [signed, requests].flatten
- elsif subjects == :signed
- hosts = signed.flatten
- else
- hosts = subjects
- end
-
- hosts.uniq.sort.each do |host|
- invalid = false
- begin
- ca.verify(host) unless requests.include?(host)
- rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => details
- invalid = details.to_s
- end
- if not invalid and signed.include?(host)
- puts "+ #{host} (#{ca.fingerprint(host, @digest)})"
- elsif invalid
- puts "- #{host} (#{ca.fingerprint(host, @digest)}) (#{invalid})"
- else
- puts "#{host} (#{ca.fingerprint(host, @digest)})"
- end
- end
- end
-
- # Set the method to apply.
- def method=(method)
- raise ArgumentError, "Invalid method #{method} to apply" unless INTERFACE_METHODS.include?(method)
- @method = method
- end
-
- # Print certificate information.
- def print(ca)
- (subjects == :all ? ca.list : subjects).each do |host|
- if value = ca.print(host)
- puts value
- else
- Puppet.err "Could not find certificate for #{host}"
- end
- end
- end
-
- # Print certificate information.
- def fingerprint(ca)
- (subjects == :all ? ca.list + ca.waiting?: subjects).each do |host|
- if value = ca.fingerprint(host, @digest)
- puts "#{host} #{value}"
- else
- Puppet.err "Could not find certificate for #{host}"
- end
- end
- end
-
- # Sign a given certificate.
- def sign(ca)
- list = subjects == :all ? ca.waiting? : subjects
- raise InterfaceError, "No waiting certificate requests to sign" if list.empty?
- list.each do |host|
- ca.sign(host)
- end
- end
-
- # Set the list of hosts we're operating on. Also supports keywords.
- def subjects=(value)
- unless value == :all or value == :signed or value.is_a?(Array)
- raise ArgumentError, "Subjects must be an array or :all; not #{value}"
- end
-
- value = nil if value.is_a?(Array) and value.empty?
-
- @subjects = value
- end
+ module SSL
+ class CertificateAuthority
+ class Interface
+ INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify, :fingerprint]
+
+ class InterfaceError < ArgumentError; end
+
+ attr_reader :method, :subjects, :digest
+
+ # Actually perform the work.
+ def apply(ca)
+ unless subjects or method == :list
+ raise ArgumentError, "You must provide hosts or :all when using #{method}"
+ end
+
+ begin
+ return send(method, ca) if respond_to?(method)
+
+ (subjects == :all ? ca.list : subjects).each do |host|
+ ca.send(method, host)
+ end
+ rescue InterfaceError
+ raise
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not call #{method}: #{detail}"
+ end
+ end
+
+ def generate(ca)
+ raise InterfaceError, "It makes no sense to generate all hosts; you must specify a list" if subjects == :all
+
+ subjects.each do |host|
+ ca.generate(host)
+ end
+ end
+
+ def initialize(method, options)
+ self.method = method
+ self.subjects = options[:to]
+ @digest = options[:digest] || :MD5
+ end
+
+ # List the hosts.
+ def list(ca)
+ unless subjects
+ puts ca.waiting?.join("\n")
+ return nil
+ end
+
+ signed = ca.list
+ requests = ca.waiting?
+
+ if subjects == :all
+ hosts = [signed, requests].flatten
+ elsif subjects == :signed
+ hosts = signed.flatten
+ else
+ hosts = subjects
+ end
+
+ hosts.uniq.sort.each do |host|
+ invalid = false
+ begin
+ ca.verify(host) unless requests.include?(host)
+ rescue Puppet::SSL::CertificateAuthority::CertificateVerificationError => details
+ invalid = details.to_s
+ end
+ if not invalid and signed.include?(host)
+ puts "+ #{host} (#{ca.fingerprint(host, @digest)})"
+ elsif invalid
+ puts "- #{host} (#{ca.fingerprint(host, @digest)}) (#{invalid})"
+ else
+ puts "#{host} (#{ca.fingerprint(host, @digest)})"
end
+ end
+ end
+
+ # Set the method to apply.
+ def method=(method)
+ raise ArgumentError, "Invalid method #{method} to apply" unless INTERFACE_METHODS.include?(method)
+ @method = method
+ end
+
+ # Print certificate information.
+ def print(ca)
+ (subjects == :all ? ca.list : subjects).each do |host|
+ if value = ca.print(host)
+ puts value
+ else
+ Puppet.err "Could not find certificate for #{host}"
+ end
+ end
+ end
+
+ # Print certificate information.
+ def fingerprint(ca)
+ (subjects == :all ? ca.list + ca.waiting?: subjects).each do |host|
+ if value = ca.fingerprint(host, @digest)
+ puts "#{host} #{value}"
+ else
+ Puppet.err "Could not find certificate for #{host}"
+ end
+ end
+ end
+
+ # Sign a given certificate.
+ def sign(ca)
+ list = subjects == :all ? ca.waiting? : subjects
+ raise InterfaceError, "No waiting certificate requests to sign" if list.empty?
+ list.each do |host|
+ ca.sign(host)
+ end
+ end
+
+ # Set the list of hosts we're operating on. Also supports keywords.
+ def subjects=(value)
+ unless value == :all or value == :signed or value.is_a?(Array)
+ raise ArgumentError, "Subjects must be an array or :all; not #{value}"
+ end
+
+ value = nil if value.is_a?(Array) and value.empty?
+
+ @subjects = value
end
+ end
end
+ end
end
diff --git a/lib/puppet/ssl/certificate_factory.rb b/lib/puppet/ssl/certificate_factory.rb
index 9a5507dea..73290e9cf 100644
--- a/lib/puppet/ssl/certificate_factory.rb
+++ b/lib/puppet/ssl/certificate_factory.rb
@@ -3,143 +3,143 @@ require 'puppet/ssl'
# The tedious class that does all the manipulations to the
# certificate to correctly sign it. Yay.
class Puppet::SSL::CertificateFactory
- # How we convert from various units to the required seconds.
- UNITMAP = {
- "y" => 365 * 24 * 60 * 60,
- "d" => 24 * 60 * 60,
- "h" => 60 * 60,
- "s" => 1
- }
+ # How we convert from various units to the required seconds.
+ UNITMAP = {
+ "y" => 365 * 24 * 60 * 60,
+ "d" => 24 * 60 * 60,
+ "h" => 60 * 60,
+ "s" => 1
+ }
- attr_reader :name, :cert_type, :csr, :issuer, :serial
+ attr_reader :name, :cert_type, :csr, :issuer, :serial
- def initialize(cert_type, csr, issuer, serial)
- @cert_type, @csr, @issuer, @serial = cert_type, csr, issuer, serial
+ def initialize(cert_type, csr, issuer, serial)
+ @cert_type, @csr, @issuer, @serial = cert_type, csr, issuer, serial
- @name = @csr.subject
- end
-
- # Actually generate our certificate.
- def result
- @cert = OpenSSL::X509::Certificate.new
-
- @cert.version = 2 # X509v3
- @cert.subject = @csr.subject
- @cert.issuer = @issuer.subject
- @cert.public_key = @csr.public_key
- @cert.serial = @serial
-
- build_extensions
-
- set_ttl
-
- @cert
- end
-
- private
-
- # This is pretty ugly, but I'm not really sure it's even possible to do
- # it any other way.
- def build_extensions
- @ef = OpenSSL::X509::ExtensionFactory.new
-
- @ef.subject_certificate = @cert
+ @name = @csr.subject
+ end
- if @issuer.is_a?(OpenSSL::X509::Request) # It's a self-signed cert
- @ef.issuer_certificate = @cert
- else
- @ef.issuer_certificate = @issuer
- end
+ # Actually generate our certificate.
+ def result
+ @cert = OpenSSL::X509::Certificate.new
- @subject_alt_name = []
- @key_usage = nil
- @ext_key_usage = nil
- @extensions = []
+ @cert.version = 2 # X509v3
+ @cert.subject = @csr.subject
+ @cert.issuer = @issuer.subject
+ @cert.public_key = @csr.public_key
+ @cert.serial = @serial
- method = "add_#{@cert_type.to_s}_extensions"
+ build_extensions
- begin
- send(method)
- rescue NoMethodError
- raise ArgumentError, "#{@cert_type} is an invalid certificate type"
- end
+ set_ttl
- @extensions << @ef.create_extension("nsComment", "Puppet Ruby/OpenSSL Generated Certificate")
- @extensions << @ef.create_extension("basicConstraints", @basic_constraint, true)
- @extensions << @ef.create_extension("subjectKeyIdentifier", "hash")
- @extensions << @ef.create_extension("keyUsage", @key_usage.join(",")) if @key_usage
- @extensions << @ef.create_extension("extendedKeyUsage", @ext_key_usage.join(",")) if @ext_key_usage
- @extensions << @ef.create_extension("subjectAltName", @subject_alt_name.join(",")) if ! @subject_alt_name.empty?
+ @cert
+ end
- @cert.extensions = @extensions
+ private
- # for some reason this _must_ be the last extension added
- @extensions << @ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if @cert_type == :ca
- end
-
- # TTL for new certificates in seconds. If config param :ca_ttl is set,
- # use that, otherwise use :ca_days for backwards compatibility
- def ttl
- ttl = Puppet.settings[:ca_ttl]
-
- return ttl unless ttl.is_a?(String)
-
- raise ArgumentError, "Invalid ca_ttl #{ttl}" unless ttl =~ /^(\d+)(y|d|h|s)$/
-
- $1.to_i * UNITMAP[$2]
- end
+ # This is pretty ugly, but I'm not really sure it's even possible to do
+ # it any other way.
+ def build_extensions
+ @ef = OpenSSL::X509::ExtensionFactory.new
- def set_ttl
- # Make the certificate valid as of yesterday, because
- # so many people's clocks are out of sync.
- from = Time.now - (60*60*24)
- @cert.not_before = from
- @cert.not_after = from + ttl
- end
+ @ef.subject_certificate = @cert
- # Woot! We're a CA.
- def add_ca_extensions
- @basic_constraint = "CA:TRUE"
- @key_usage = %w{cRLSign keyCertSign}
+ if @issuer.is_a?(OpenSSL::X509::Request) # It's a self-signed cert
+ @ef.issuer_certificate = @cert
+ else
+ @ef.issuer_certificate = @issuer
end
- # We're a terminal CA, probably not self-signed.
- def add_terminalsubca_extensions
- @basic_constraint = "CA:TRUE,pathlen:0"
- @key_usage = %w{cRLSign keyCertSign}
- end
+ @subject_alt_name = []
+ @key_usage = nil
+ @ext_key_usage = nil
+ @extensions = []
- # We're a normal server.
- def add_server_extensions
- @basic_constraint = "CA:FALSE"
- dnsnames = Puppet[:certdnsnames]
- name = @name.to_s.sub(%r{/CN=},'')
- if dnsnames != ""
- dnsnames.split(':').each { |d| @subject_alt_name << 'DNS:' + d }
- @subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
- elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
- @subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
- @subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
- @subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
- end
- @key_usage = %w{digitalSignature keyEncipherment}
- @ext_key_usage = %w{serverAuth clientAuth emailProtection}
- end
+ method = "add_#{@cert_type.to_s}_extensions"
- # Um, no idea.
- def add_ocsp_extensions
- @basic_constraint = "CA:FALSE"
- @key_usage = %w{nonRepudiation digitalSignature}
- @ext_key_usage = %w{serverAuth OCSPSigning}
+ begin
+ send(method)
+ rescue NoMethodError
+ raise ArgumentError, "#{@cert_type} is an invalid certificate type"
end
- # Normal client.
- def add_client_extensions
- @basic_constraint = "CA:FALSE"
- @key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
- @ext_key_usage = %w{clientAuth emailProtection}
-
- @extensions << @ef.create_extension("nsCertType", "client,email")
+ @extensions << @ef.create_extension("nsComment", "Puppet Ruby/OpenSSL Generated Certificate")
+ @extensions << @ef.create_extension("basicConstraints", @basic_constraint, true)
+ @extensions << @ef.create_extension("subjectKeyIdentifier", "hash")
+ @extensions << @ef.create_extension("keyUsage", @key_usage.join(",")) if @key_usage
+ @extensions << @ef.create_extension("extendedKeyUsage", @ext_key_usage.join(",")) if @ext_key_usage
+ @extensions << @ef.create_extension("subjectAltName", @subject_alt_name.join(",")) if ! @subject_alt_name.empty?
+
+ @cert.extensions = @extensions
+
+ # for some reason this _must_ be the last extension added
+ @extensions << @ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if @cert_type == :ca
+ end
+
+ # TTL for new certificates in seconds. If config param :ca_ttl is set,
+ # use that, otherwise use :ca_days for backwards compatibility
+ def ttl
+ ttl = Puppet.settings[:ca_ttl]
+
+ return ttl unless ttl.is_a?(String)
+
+ raise ArgumentError, "Invalid ca_ttl #{ttl}" unless ttl =~ /^(\d+)(y|d|h|s)$/
+
+ $1.to_i * UNITMAP[$2]
+ end
+
+ def set_ttl
+ # Make the certificate valid as of yesterday, because
+ # so many people's clocks are out of sync.
+ from = Time.now - (60*60*24)
+ @cert.not_before = from
+ @cert.not_after = from + ttl
+ end
+
+ # Woot! We're a CA.
+ def add_ca_extensions
+ @basic_constraint = "CA:TRUE"
+ @key_usage = %w{cRLSign keyCertSign}
+ end
+
+ # We're a terminal CA, probably not self-signed.
+ def add_terminalsubca_extensions
+ @basic_constraint = "CA:TRUE,pathlen:0"
+ @key_usage = %w{cRLSign keyCertSign}
+ end
+
+ # We're a normal server.
+ def add_server_extensions
+ @basic_constraint = "CA:FALSE"
+ dnsnames = Puppet[:certdnsnames]
+ name = @name.to_s.sub(%r{/CN=},'')
+ if dnsnames != ""
+ dnsnames.split(':').each { |d| @subject_alt_name << 'DNS:' + d }
+ @subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
+ elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
+ @subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
+ @subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
+ @subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
end
+ @key_usage = %w{digitalSignature keyEncipherment}
+ @ext_key_usage = %w{serverAuth clientAuth emailProtection}
+ end
+
+ # Um, no idea.
+ def add_ocsp_extensions
+ @basic_constraint = "CA:FALSE"
+ @key_usage = %w{nonRepudiation digitalSignature}
+ @ext_key_usage = %w{serverAuth OCSPSigning}
+ end
+
+ # Normal client.
+ def add_client_extensions
+ @basic_constraint = "CA:FALSE"
+ @key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
+ @ext_key_usage = %w{clientAuth emailProtection}
+
+ @extensions << @ef.create_extension("nsCertType", "client,email")
+ end
end
diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb
index 3cd3ce0be..e4d06a039 100644
--- a/lib/puppet/ssl/certificate_request.rb
+++ b/lib/puppet/ssl/certificate_request.rb
@@ -2,57 +2,57 @@ require 'puppet/ssl/base'
# Manage certificate requests.
class Puppet::SSL::CertificateRequest < Puppet::SSL::Base
- wraps OpenSSL::X509::Request
-
- extend Puppet::Indirector
- indirects :certificate_request, :terminus_class => :file
-
- # Convert a string into an instance.
- def self.from_s(string)
- instance = wrapped_class.new(string)
- name = instance.subject.to_s.sub(/\/CN=/i, '').downcase
- result = new(name)
- result.content = instance
- result
- end
-
- # Because of how the format handler class is included, this
- # can't be in the base class.
- def self.supported_formats
- [:s]
- end
-
- # How to create a certificate request with our system defaults.
- def generate(key)
- Puppet.info "Creating a new SSL certificate request for #{name}"
-
- # Support either an actual SSL key, or a Puppet key.
- key = key.content if key.is_a?(Puppet::SSL::Key)
-
- # If we're a CSR for the CA, then use the real certname, rather than the
- # fake 'ca' name. This is mostly for backward compatibility with 0.24.x,
- # but it's also just a good idea.
- common_name = name == Puppet::SSL::CA_NAME ? Puppet.settings[:ca_name] : name
-
- csr = OpenSSL::X509::Request.new
- csr.version = 0
- csr.subject = OpenSSL::X509::Name.new([["CN", common_name]])
- csr.public_key = key.public_key
- csr.sign(key, OpenSSL::Digest::MD5.new)
-
- raise Puppet::Error, "CSR sign verification failed; you need to clean the certificate request for #{name} on the server" unless csr.verify(key.public_key)
-
- @content = csr
- Puppet.info "Certificate Request fingerprint (md5): #{fingerprint}"
- @content
- end
-
- def save(args = {})
- super()
-
- # Try to autosign the CSR.
- if ca = Puppet::SSL::CertificateAuthority.instance
- ca.autosign
- end
+ wraps OpenSSL::X509::Request
+
+ extend Puppet::Indirector
+ indirects :certificate_request, :terminus_class => :file
+
+ # Convert a string into an instance.
+ def self.from_s(string)
+ instance = wrapped_class.new(string)
+ name = instance.subject.to_s.sub(/\/CN=/i, '').downcase
+ result = new(name)
+ result.content = instance
+ result
+ end
+
+ # Because of how the format handler class is included, this
+ # can't be in the base class.
+ def self.supported_formats
+ [:s]
+ end
+
+ # How to create a certificate request with our system defaults.
+ def generate(key)
+ Puppet.info "Creating a new SSL certificate request for #{name}"
+
+ # Support either an actual SSL key, or a Puppet key.
+ key = key.content if key.is_a?(Puppet::SSL::Key)
+
+ # If we're a CSR for the CA, then use the real certname, rather than the
+ # fake 'ca' name. This is mostly for backward compatibility with 0.24.x,
+ # but it's also just a good idea.
+ common_name = name == Puppet::SSL::CA_NAME ? Puppet.settings[:ca_name] : name
+
+ csr = OpenSSL::X509::Request.new
+ csr.version = 0
+ csr.subject = OpenSSL::X509::Name.new([["CN", common_name]])
+ csr.public_key = key.public_key
+ csr.sign(key, OpenSSL::Digest::MD5.new)
+
+ raise Puppet::Error, "CSR sign verification failed; you need to clean the certificate request for #{name} on the server" unless csr.verify(key.public_key)
+
+ @content = csr
+ Puppet.info "Certificate Request fingerprint (md5): #{fingerprint}"
+ @content
+ end
+
+ def save(args = {})
+ super()
+
+ # Try to autosign the CSR.
+ if ca = Puppet::SSL::CertificateAuthority.instance
+ ca.autosign
end
+ end
end
diff --git a/lib/puppet/ssl/certificate_revocation_list.rb b/lib/puppet/ssl/certificate_revocation_list.rb
index b2bff4830..44e0a9e22 100644
--- a/lib/puppet/ssl/certificate_revocation_list.rb
+++ b/lib/puppet/ssl/certificate_revocation_list.rb
@@ -3,82 +3,82 @@ require 'puppet/indirector'
# Manage the CRL.
class Puppet::SSL::CertificateRevocationList < Puppet::SSL::Base
- wraps OpenSSL::X509::CRL
-
- extend Puppet::Indirector
- indirects :certificate_revocation_list, :terminus_class => :file
-
- # Convert a string into an instance.
- def self.from_s(string)
- instance = wrapped_class.new(string)
- result = new('foo') # The name doesn't matter
- result.content = instance
- result
- end
-
- # Because of how the format handler class is included, this
- # can't be in the base class.
- def self.supported_formats
- [:s]
- end
-
- # Knows how to create a CRL with our system defaults.
- def generate(cert, cakey)
- Puppet.info "Creating a new certificate revocation list"
- @content = wrapped_class.new
- @content.issuer = cert.subject
- @content.version = 1
-
- # Init the CRL number.
- crlNum = OpenSSL::ASN1::Integer(0)
- @content.extensions = [OpenSSL::X509::Extension.new("crlNumber", crlNum)]
-
- # Set last/next update
- @content.last_update = Time.now
- # Keep CRL valid for 5 years
- @content.next_update = Time.now + 5 * 365*24*60*60
-
- @content.sign(cakey, OpenSSL::Digest::SHA1.new)
-
- @content
- end
-
- # The name doesn't actually matter; there's only one CRL.
- # We just need the name so our Indirector stuff all works more easily.
- def initialize(fakename)
- @name = "crl"
- end
-
- # Revoke the certificate with serial number SERIAL issued by this
- # CA, then write the CRL back to disk. The REASON must be one of the
- # OpenSSL::OCSP::REVOKED_* reasons
- def revoke(serial, cakey, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
- Puppet.notice "Revoked certificate with serial #{serial}"
- time = Time.now
-
- # Add our revocation to the CRL.
- revoked = OpenSSL::X509::Revoked.new
- revoked.serial = serial
- revoked.time = time
- enum = OpenSSL::ASN1::Enumerated(reason)
- ext = OpenSSL::X509::Extension.new("CRLReason", enum)
- revoked.add_extension(ext)
- @content.add_revoked(revoked)
-
- # Increment the crlNumber
- e = @content.extensions.find { |e| e.oid == 'crlNumber' }
- ext = @content.extensions.reject { |e| e.oid == 'crlNumber' }
- crlNum = OpenSSL::ASN1::Integer(e ? e.value.to_i + 1 : 0)
- ext << OpenSSL::X509::Extension.new("crlNumber", crlNum)
- @content.extensions = ext
-
- # Set last/next update
- @content.last_update = time
- # Keep CRL valid for 5 years
- @content.next_update = time + 5 * 365*24*60*60
-
- @content.sign(cakey, OpenSSL::Digest::SHA1.new)
-
- save
- end
+ wraps OpenSSL::X509::CRL
+
+ extend Puppet::Indirector
+ indirects :certificate_revocation_list, :terminus_class => :file
+
+ # Convert a string into an instance.
+ def self.from_s(string)
+ instance = wrapped_class.new(string)
+ result = new('foo') # The name doesn't matter
+ result.content = instance
+ result
+ end
+
+ # Because of how the format handler class is included, this
+ # can't be in the base class.
+ def self.supported_formats
+ [:s]
+ end
+
+ # Knows how to create a CRL with our system defaults.
+ def generate(cert, cakey)
+ Puppet.info "Creating a new certificate revocation list"
+ @content = wrapped_class.new
+ @content.issuer = cert.subject
+ @content.version = 1
+
+ # Init the CRL number.
+ crlNum = OpenSSL::ASN1::Integer(0)
+ @content.extensions = [OpenSSL::X509::Extension.new("crlNumber", crlNum)]
+
+ # Set last/next update
+ @content.last_update = Time.now
+ # Keep CRL valid for 5 years
+ @content.next_update = Time.now + 5 * 365*24*60*60
+
+ @content.sign(cakey, OpenSSL::Digest::SHA1.new)
+
+ @content
+ end
+
+ # The name doesn't actually matter; there's only one CRL.
+ # We just need the name so our Indirector stuff all works more easily.
+ def initialize(fakename)
+ @name = "crl"
+ end
+
+ # Revoke the certificate with serial number SERIAL issued by this
+ # CA, then write the CRL back to disk. The REASON must be one of the
+ # OpenSSL::OCSP::REVOKED_* reasons
+ def revoke(serial, cakey, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
+ Puppet.notice "Revoked certificate with serial #{serial}"
+ time = Time.now
+
+ # Add our revocation to the CRL.
+ revoked = OpenSSL::X509::Revoked.new
+ revoked.serial = serial
+ revoked.time = time
+ enum = OpenSSL::ASN1::Enumerated(reason)
+ ext = OpenSSL::X509::Extension.new("CRLReason", enum)
+ revoked.add_extension(ext)
+ @content.add_revoked(revoked)
+
+ # Increment the crlNumber
+ e = @content.extensions.find { |e| e.oid == 'crlNumber' }
+ ext = @content.extensions.reject { |e| e.oid == 'crlNumber' }
+ crlNum = OpenSSL::ASN1::Integer(e ? e.value.to_i + 1 : 0)
+ ext << OpenSSL::X509::Extension.new("crlNumber", crlNum)
+ @content.extensions = ext
+
+ # Set last/next update
+ @content.last_update = time
+ # Keep CRL valid for 5 years
+ @content.next_update = time + 5 * 365*24*60*60
+
+ @content.sign(cakey, OpenSSL::Digest::SHA1.new)
+
+ save
+ end
end
diff --git a/lib/puppet/ssl/host.rb b/lib/puppet/ssl/host.rb
index 9aaff8ad2..8a6f0aa6d 100644
--- a/lib/puppet/ssl/host.rb
+++ b/lib/puppet/ssl/host.rb
@@ -8,255 +8,255 @@ require 'puppet/util/cacher'
# The class that manages all aspects of our SSL certificates --
# private keys, public keys, requests, etc.
class Puppet::SSL::Host
- # Yay, ruby's strange constant lookups.
- Key = Puppet::SSL::Key
- CA_NAME = Puppet::SSL::CA_NAME
- Certificate = Puppet::SSL::Certificate
- CertificateRequest = Puppet::SSL::CertificateRequest
- CertificateRevocationList = Puppet::SSL::CertificateRevocationList
-
- attr_reader :name
- attr_accessor :ca
-
- attr_writer :key, :certificate, :certificate_request
-
- class << self
- include Puppet::Util::Cacher
-
- cached_attr(:localhost) do
- result = new
- result.generate unless result.certificate
- result.key # Make sure it's read in
- result
- end
+ # Yay, ruby's strange constant lookups.
+ Key = Puppet::SSL::Key
+ CA_NAME = Puppet::SSL::CA_NAME
+ Certificate = Puppet::SSL::Certificate
+ CertificateRequest = Puppet::SSL::CertificateRequest
+ CertificateRevocationList = Puppet::SSL::CertificateRevocationList
+
+ attr_reader :name
+ attr_accessor :ca
+
+ attr_writer :key, :certificate, :certificate_request
+
+ class << self
+ include Puppet::Util::Cacher
+
+ cached_attr(:localhost) do
+ result = new
+ result.generate unless result.certificate
+ result.key # Make sure it's read in
+ result
end
-
- # This is the constant that people will use to mark that a given host is
- # a certificate authority.
- def self.ca_name
- CA_NAME
+ end
+
+ # This is the constant that people will use to mark that a given host is
+ # a certificate authority.
+ def self.ca_name
+ CA_NAME
+ end
+
+ class << self
+ attr_reader :ca_location
+ end
+
+ # Configure how our various classes interact with their various terminuses.
+ def self.configure_indirection(terminus, cache = nil)
+ Certificate.terminus_class = terminus
+ CertificateRequest.terminus_class = terminus
+ CertificateRevocationList.terminus_class = terminus
+
+ if cache
+ # This is weird; we don't actually cache our keys, we
+ # use what would otherwise be the cache as our normal
+ # terminus.
+ Key.terminus_class = cache
+ else
+ Key.terminus_class = terminus
end
- class << self
- attr_reader :ca_location
+ if cache
+ Certificate.cache_class = cache
+ CertificateRequest.cache_class = cache
+ CertificateRevocationList.cache_class = cache
+ else
+ # Make sure we have no cache configured. puppet master
+ # switches the configurations around a bit, so it's important
+ # that we specify the configs for absolutely everything, every
+ # time.
+ Certificate.cache_class = nil
+ CertificateRequest.cache_class = nil
+ CertificateRevocationList.cache_class = nil
end
-
- # Configure how our various classes interact with their various terminuses.
- def self.configure_indirection(terminus, cache = nil)
- Certificate.terminus_class = terminus
- CertificateRequest.terminus_class = terminus
- CertificateRevocationList.terminus_class = terminus
-
- if cache
- # This is weird; we don't actually cache our keys, we
- # use what would otherwise be the cache as our normal
- # terminus.
- Key.terminus_class = cache
- else
- Key.terminus_class = terminus
- end
-
- if cache
- Certificate.cache_class = cache
- CertificateRequest.cache_class = cache
- CertificateRevocationList.cache_class = cache
- else
- # Make sure we have no cache configured. puppet master
- # switches the configurations around a bit, so it's important
- # that we specify the configs for absolutely everything, every
- # time.
- Certificate.cache_class = nil
- CertificateRequest.cache_class = nil
- CertificateRevocationList.cache_class = nil
- end
+ end
+
+ CA_MODES = {
+ # Our ca is local, so we use it as the ultimate source of information
+ # And we cache files locally.
+ :local => [:ca, :file],
+ # We're a remote CA client.
+ :remote => [:rest, :file],
+ # We are the CA, so we don't have read/write access to the normal certificates.
+ :only => [:ca],
+ # We have no CA, so we just look in the local file store.
+ :none => [:file]
+ }
+
+ # Specify how we expect to interact with our certificate authority.
+ def self.ca_location=(mode)
+ raise ArgumentError, "CA Mode can only be #{CA_MODES.collect { |m| m.to_s }.join(", ")}" unless CA_MODES.include?(mode)
+
+ @ca_location = mode
+
+ configure_indirection(*CA_MODES[@ca_location])
+ end
+
+ # Remove all traces of a given host
+ def self.destroy(name)
+ [Key, Certificate, CertificateRequest].collect { |part| part.destroy(name) }.any? { |x| x }
+ end
+
+ # Search for more than one host, optionally only specifying
+ # an interest in hosts with a given file type.
+ # This just allows our non-indirected class to have one of
+ # indirection methods.
+ def self.search(options = {})
+ classlist = [options[:for] || [Key, CertificateRequest, Certificate]].flatten
+
+ # Collect the results from each class, flatten them, collect all of the names, make the name list unique,
+ # then create a Host instance for each one.
+ classlist.collect { |klass| klass.search }.flatten.collect { |r| r.name }.uniq.collect do |name|
+ new(name)
end
-
- CA_MODES = {
- # Our ca is local, so we use it as the ultimate source of information
- # And we cache files locally.
- :local => [:ca, :file],
- # We're a remote CA client.
- :remote => [:rest, :file],
- # We are the CA, so we don't have read/write access to the normal certificates.
- :only => [:ca],
- # We have no CA, so we just look in the local file store.
- :none => [:file]
- }
-
- # Specify how we expect to interact with our certificate authority.
- def self.ca_location=(mode)
- raise ArgumentError, "CA Mode can only be #{CA_MODES.collect { |m| m.to_s }.join(", ")}" unless CA_MODES.include?(mode)
-
- @ca_location = mode
-
- configure_indirection(*CA_MODES[@ca_location])
+ end
+
+ # Is this a ca host, meaning that all of its files go in the CA location?
+ def ca?
+ ca
+ end
+
+ def key
+ @key ||= Key.find(name)
+ end
+
+ # This is the private key; we can create it from scratch
+ # with no inputs.
+ def generate_key
+ @key = Key.new(name)
+ @key.generate
+ begin
+ @key.save
+ rescue
+ @key = nil
+ raise
end
-
- # Remove all traces of a given host
- def self.destroy(name)
- [Key, Certificate, CertificateRequest].collect { |part| part.destroy(name) }.any? { |x| x }
+ true
+ end
+
+ def certificate_request
+ @certificate_request ||= CertificateRequest.find(name)
+ end
+
+ # Our certificate request requires the key but that's all.
+ def generate_certificate_request
+ generate_key unless key
+ @certificate_request = CertificateRequest.new(name)
+ @certificate_request.generate(key.content)
+ begin
+ @certificate_request.save
+ rescue
+ @certificate_request = nil
+ raise
end
- # Search for more than one host, optionally only specifying
- # an interest in hosts with a given file type.
- # This just allows our non-indirected class to have one of
- # indirection methods.
- def self.search(options = {})
- classlist = [options[:for] || [Key, CertificateRequest, Certificate]].flatten
-
- # Collect the results from each class, flatten them, collect all of the names, make the name list unique,
- # then create a Host instance for each one.
- classlist.collect { |klass| klass.search }.flatten.collect { |r| r.name }.uniq.collect do |name|
- new(name)
- end
- end
+ true
+ end
- # Is this a ca host, meaning that all of its files go in the CA location?
- def ca?
- ca
- end
+ def certificate
+ unless @certificate
+ generate_key unless key
- def key
- @key ||= Key.find(name)
- end
+ # get the CA cert first, since it's required for the normal cert
+ # to be of any use.
+ return nil unless Certificate.find("ca") unless ca?
+ return nil unless @certificate = Certificate.find(name)
- # This is the private key; we can create it from scratch
- # with no inputs.
- def generate_key
- @key = Key.new(name)
- @key.generate
- begin
- @key.save
- rescue
- @key = nil
- raise
- end
- true
+ unless certificate_matches_key?
+ raise Puppet::Error, "Retrieved certificate does not match private key; please remove certificate from server and regenerate it with the current key"
+ end
end
-
- def certificate_request
- @certificate_request ||= CertificateRequest.find(name)
+ @certificate
+ end
+
+ def certificate_matches_key?
+ return false unless key
+ return false unless certificate
+
+ certificate.content.check_private_key(key.content)
+ end
+
+ # Generate all necessary parts of our ssl host.
+ def generate
+ generate_key unless key
+ generate_certificate_request unless certificate_request
+
+ # If we can get a CA instance, then we're a valid CA, and we
+ # should use it to sign our request; else, just try to read
+ # the cert.
+ if ! certificate and ca = Puppet::SSL::CertificateAuthority.instance
+ ca.sign(self.name)
end
-
- # Our certificate request requires the key but that's all.
- def generate_certificate_request
- generate_key unless key
- @certificate_request = CertificateRequest.new(name)
- @certificate_request.generate(key.content)
- begin
- @certificate_request.save
- rescue
- @certificate_request = nil
- raise
- end
-
- true
+ end
+
+ def initialize(name = nil)
+ @name = (name || Puppet[:certname]).downcase
+ @key = @certificate = @certificate_request = nil
+ @ca = (name == self.class.ca_name)
+ end
+
+ # Extract the public key from the private key.
+ def public_key
+ key.content.public_key
+ end
+
+ # Create/return a store that uses our SSL info to validate
+ # connections.
+ def ssl_store(purpose = OpenSSL::X509::PURPOSE_ANY)
+ unless @ssl_store
+ @ssl_store = OpenSSL::X509::Store.new
+ @ssl_store.purpose = purpose
+
+ # Use the file path here, because we don't want to cause
+ # a lookup in the middle of setting our ssl connection.
+ @ssl_store.add_file(Puppet[:localcacert])
+
+ # If there's a CRL, add it to our store.
+ if crl = Puppet::SSL::CertificateRevocationList.find(CA_NAME)
+ @ssl_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
+ @ssl_store.add_crl(crl.content)
+ end
+ return @ssl_store
end
-
- def certificate
- unless @certificate
- generate_key unless key
-
- # get the CA cert first, since it's required for the normal cert
- # to be of any use.
- return nil unless Certificate.find("ca") unless ca?
- return nil unless @certificate = Certificate.find(name)
-
- unless certificate_matches_key?
- raise Puppet::Error, "Retrieved certificate does not match private key; please remove certificate from server and regenerate it with the current key"
- end
- end
- @certificate
- end
-
- def certificate_matches_key?
- return false unless key
- return false unless certificate
-
- certificate.content.check_private_key(key.content)
- end
-
- # Generate all necessary parts of our ssl host.
- def generate
- generate_key unless key
- generate_certificate_request unless certificate_request
-
- # If we can get a CA instance, then we're a valid CA, and we
- # should use it to sign our request; else, just try to read
- # the cert.
- if ! certificate and ca = Puppet::SSL::CertificateAuthority.instance
- ca.sign(self.name)
- end
- end
-
- def initialize(name = nil)
- @name = (name || Puppet[:certname]).downcase
- @key = @certificate = @certificate_request = nil
- @ca = (name == self.class.ca_name)
- end
-
- # Extract the public key from the private key.
- def public_key
- key.content.public_key
+ @ssl_store
+ end
+
+ # Attempt to retrieve a cert, if we don't already have one.
+ def wait_for_cert(time)
+ begin
+ return if certificate
+ generate
+ return if certificate
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not request certificate: #{detail}"
+ if time < 1
+ puts "Exiting; failed to retrieve certificate and waitforcert is disabled"
+ exit(1)
+ else
+ sleep(time)
+ end
+ retry
end
- # Create/return a store that uses our SSL info to validate
- # connections.
- def ssl_store(purpose = OpenSSL::X509::PURPOSE_ANY)
- unless @ssl_store
- @ssl_store = OpenSSL::X509::Store.new
- @ssl_store.purpose = purpose
-
- # Use the file path here, because we don't want to cause
- # a lookup in the middle of setting our ssl connection.
- @ssl_store.add_file(Puppet[:localcacert])
-
- # If there's a CRL, add it to our store.
- if crl = Puppet::SSL::CertificateRevocationList.find(CA_NAME)
- @ssl_store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL|OpenSSL::X509::V_FLAG_CRL_CHECK if Puppet.settings[:certificate_revocation]
- @ssl_store.add_crl(crl.content)
- end
- return @ssl_store
- end
- @ssl_store
+ if time < 1
+ puts "Exiting; no certificate found and waitforcert is disabled"
+ exit(1)
end
- # Attempt to retrieve a cert, if we don't already have one.
- def wait_for_cert(time)
- begin
- return if certificate
- generate
- return if certificate
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not request certificate: #{detail}"
- if time < 1
- puts "Exiting; failed to retrieve certificate and waitforcert is disabled"
- exit(1)
- else
- sleep(time)
- end
- retry
- end
-
- if time < 1
- puts "Exiting; no certificate found and waitforcert is disabled"
- exit(1)
- end
-
- while true
- sleep time
- begin
- break if certificate
- Puppet.notice "Did not receive certificate"
- rescue StandardError => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not request certificate: #{detail}"
- end
- end
+ while true
+ sleep time
+ begin
+ break if certificate
+ Puppet.notice "Did not receive certificate"
+ rescue StandardError => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not request certificate: #{detail}"
+ end
end
+ end
end
require 'puppet/ssl/certificate_authority'
diff --git a/lib/puppet/ssl/inventory.rb b/lib/puppet/ssl/inventory.rb
index 6fb2ea8c2..b2b402a53 100644
--- a/lib/puppet/ssl/inventory.rb
+++ b/lib/puppet/ssl/inventory.rb
@@ -3,50 +3,50 @@ require 'puppet/ssl/certificate'
# Keep track of all of our known certificates.
class Puppet::SSL::Inventory
- attr_reader :path
+ attr_reader :path
- # Add a certificate to our inventory.
- def add(cert)
- cert = cert.content if cert.is_a?(Puppet::SSL::Certificate)
+ # Add a certificate to our inventory.
+ def add(cert)
+ cert = cert.content if cert.is_a?(Puppet::SSL::Certificate)
- # Create our file, if one does not already exist.
- rebuild unless FileTest.exist?(@path)
+ # Create our file, if one does not already exist.
+ rebuild unless FileTest.exist?(@path)
- Puppet.settings.write(:cert_inventory, "a") do |f|
- f.print format(cert)
- end
+ Puppet.settings.write(:cert_inventory, "a") do |f|
+ f.print format(cert)
end
+ end
- # Format our certificate for output.
- def format(cert)
- iso = '%Y-%m-%dT%H:%M:%S%Z'
- "0x%04x %s %s %s\n" % [cert.serial, cert.not_before.strftime(iso), cert.not_after.strftime(iso), cert.subject]
- end
-
- def initialize
- @path = Puppet[:cert_inventory]
- end
+ # Format our certificate for output.
+ def format(cert)
+ iso = '%Y-%m-%dT%H:%M:%S%Z'
+ "0x%04x %s %s %s\n" % [cert.serial, cert.not_before.strftime(iso), cert.not_after.strftime(iso), cert.subject]
+ end
- # Rebuild the inventory from scratch. This should happen if
- # the file is entirely missing or if it's somehow corrupted.
- def rebuild
- Puppet.notice "Rebuilding inventory file"
+ def initialize
+ @path = Puppet[:cert_inventory]
+ end
- Puppet.settings.write(:cert_inventory) do |f|
- f.print "# Inventory of signed certificates\n# SERIAL NOT_BEFORE NOT_AFTER SUBJECT\n"
- end
+ # Rebuild the inventory from scratch. This should happen if
+ # the file is entirely missing or if it's somehow corrupted.
+ def rebuild
+ Puppet.notice "Rebuilding inventory file"
- Puppet::SSL::Certificate.search("*").each { |cert| add(cert) }
+ Puppet.settings.write(:cert_inventory) do |f|
+ f.print "# Inventory of signed certificates\n# SERIAL NOT_BEFORE NOT_AFTER SUBJECT\n"
end
- # Find the serial number for a given certificate.
- def serial(name)
- return nil unless FileTest.exist?(@path)
+ Puppet::SSL::Certificate.search("*").each { |cert| add(cert) }
+ end
+
+ # Find the serial number for a given certificate.
+ def serial(name)
+ return nil unless FileTest.exist?(@path)
- File.readlines(@path).each do |line|
- next unless line =~ /^(\S+).+\/CN=#{name}$/
+ File.readlines(@path).each do |line|
+ next unless line =~ /^(\S+).+\/CN=#{name}$/
- return Integer($1)
- end
+ return Integer($1)
end
+ end
end
diff --git a/lib/puppet/ssl/key.rb b/lib/puppet/ssl/key.rb
index cb03729c1..0ddc9623c 100644
--- a/lib/puppet/ssl/key.rb
+++ b/lib/puppet/ssl/key.rb
@@ -3,54 +3,54 @@ require 'puppet/indirector'
# Manage private and public keys as a pair.
class Puppet::SSL::Key < Puppet::SSL::Base
- wraps OpenSSL::PKey::RSA
+ wraps OpenSSL::PKey::RSA
- extend Puppet::Indirector
- indirects :key, :terminus_class => :file
+ extend Puppet::Indirector
+ indirects :key, :terminus_class => :file
- # Because of how the format handler class is included, this
- # can't be in the base class.
- def self.supported_formats
- [:s]
- end
+ # Because of how the format handler class is included, this
+ # can't be in the base class.
+ def self.supported_formats
+ [:s]
+ end
- attr_accessor :password_file
+ attr_accessor :password_file
- # Knows how to create keys with our system defaults.
- def generate
- Puppet.info "Creating a new SSL key for #{name}"
- @content = OpenSSL::PKey::RSA.new(Puppet[:keylength].to_i)
- end
+ # Knows how to create keys with our system defaults.
+ def generate
+ Puppet.info "Creating a new SSL key for #{name}"
+ @content = OpenSSL::PKey::RSA.new(Puppet[:keylength].to_i)
+ end
- def initialize(name)
- super
+ def initialize(name)
+ super
- if ca?
- @password_file = Puppet[:capass]
- else
- @password_file = Puppet[:passfile]
- end
+ if ca?
+ @password_file = Puppet[:capass]
+ else
+ @password_file = Puppet[:passfile]
end
+ end
- def password
- return nil unless password_file and FileTest.exist?(password_file)
+ def password
+ return nil unless password_file and FileTest.exist?(password_file)
- ::File.read(password_file)
- end
+ ::File.read(password_file)
+ end
- # Optionally support specifying a password file.
- def read(path)
- return super unless password_file
+ # Optionally support specifying a password file.
+ def read(path)
+ return super unless password_file
- #@content = wrapped_class.new(::File.read(path), password)
- @content = wrapped_class.new(::File.read(path), password)
- end
+ #@content = wrapped_class.new(::File.read(path), password)
+ @content = wrapped_class.new(::File.read(path), password)
+ end
- def to_s
- if pass = password
- @content.export(OpenSSL::Cipher::DES.new(:EDE3, :CBC), pass)
- else
- return super
- end
+ def to_s
+ if pass = password
+ @content.export(OpenSSL::Cipher::DES.new(:EDE3, :CBC), pass)
+ else
+ return super
end
+ end
end
diff --git a/lib/puppet/sslcertificates.rb b/lib/puppet/sslcertificates.rb
index 02cb9fe03..4e941244e 100755
--- a/lib/puppet/sslcertificates.rb
+++ b/lib/puppet/sslcertificates.rb
@@ -5,142 +5,142 @@ require 'puppet'
raise Puppet::Error, "You must have the Ruby openssl library installed" unless Puppet.features.openssl?
module Puppet::SSLCertificates
- #def self.mkcert(type, name, dnsnames, ttl, issuercert, issuername, serial, publickey)
- def self.mkcert(hash)
- [:type, :name, :ttl, :issuer, :serial, :publickey].each { |param|
- raise ArgumentError, "mkcert called without #{param}" unless hash.include?(param)
- }
-
- cert = OpenSSL::X509::Certificate.new
- # Make the certificate valid as of yesterday, because
- # so many people's clocks are out of sync.
- from = Time.now - (60*60*24)
-
- cert.subject = hash[:name]
- if hash[:issuer]
- cert.issuer = hash[:issuer].subject
- else
- # we're a self-signed cert
- cert.issuer = hash[:name]
- end
- cert.not_before = from
- cert.not_after = from + hash[:ttl]
- cert.version = 2 # X509v3
-
- cert.public_key = hash[:publickey]
- cert.serial = hash[:serial]
-
- basic_constraint = nil
- key_usage = nil
- ext_key_usage = nil
- subject_alt_name = []
-
- ef = OpenSSL::X509::ExtensionFactory.new
-
- ef.subject_certificate = cert
-
- if hash[:issuer]
- ef.issuer_certificate = hash[:issuer]
- else
- ef.issuer_certificate = cert
- end
-
- ex = []
- case hash[:type]
- when :ca
- basic_constraint = "CA:TRUE"
- key_usage = %w{cRLSign keyCertSign}
- when :terminalsubca
- basic_constraint = "CA:TRUE,pathlen:0"
- key_usage = %w{cRLSign keyCertSign}
- when :server
- basic_constraint = "CA:FALSE"
- dnsnames = Puppet[:certdnsnames]
- name = hash[:name].to_s.sub(%r{/CN=},'')
- if dnsnames != ""
- dnsnames.split(':').each { |d| subject_alt_name << 'DNS:' + d }
- subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
- elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
- subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
- subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
- subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
- end
- key_usage = %w{digitalSignature keyEncipherment}
- ext_key_usage = %w{serverAuth clientAuth emailProtection}
- when :ocsp
- basic_constraint = "CA:FALSE"
- key_usage = %w{nonRepudiation digitalSignature}
- ext_key_usage = %w{serverAuth OCSPSigning}
- when :client
- basic_constraint = "CA:FALSE"
- key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
- ext_key_usage = %w{clientAuth emailProtection}
- ex << ef.create_extension("nsCertType", "client,email")
- else
- raise Puppet::Error, "unknown cert type '#{hash[:type]}'"
- end
-
-
- ex << ef.create_extension(
- "nsComment",
+ #def self.mkcert(type, name, dnsnames, ttl, issuercert, issuername, serial, publickey)
+ def self.mkcert(hash)
+ [:type, :name, :ttl, :issuer, :serial, :publickey].each { |param|
+ raise ArgumentError, "mkcert called without #{param}" unless hash.include?(param)
+ }
+
+ cert = OpenSSL::X509::Certificate.new
+ # Make the certificate valid as of yesterday, because
+ # so many people's clocks are out of sync.
+ from = Time.now - (60*60*24)
+
+ cert.subject = hash[:name]
+ if hash[:issuer]
+ cert.issuer = hash[:issuer].subject
+ else
+ # we're a self-signed cert
+ cert.issuer = hash[:name]
+ end
+ cert.not_before = from
+ cert.not_after = from + hash[:ttl]
+ cert.version = 2 # X509v3
- "Puppet Ruby/OpenSSL Generated Certificate")
- ex << ef.create_extension("basicConstraints", basic_constraint, true)
- ex << ef.create_extension("subjectKeyIdentifier", "hash")
+ cert.public_key = hash[:publickey]
+ cert.serial = hash[:serial]
- ex << ef.create_extension("keyUsage", key_usage.join(",")) if key_usage
- ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) if ext_key_usage
- ex << ef.create_extension("subjectAltName", subject_alt_name.join(",")) if ! subject_alt_name.empty?
+ basic_constraint = nil
+ key_usage = nil
+ ext_key_usage = nil
+ subject_alt_name = []
- #if @ca_config[:cdp_location] then
- # ex << ef.create_extension("crlDistributionPoints",
- # @ca_config[:cdp_location])
- #end
+ ef = OpenSSL::X509::ExtensionFactory.new
- #if @ca_config[:ocsp_location] then
- # ex << ef.create_extension("authorityInfoAccess",
- # "OCSP;" << @ca_config[:ocsp_location])
- #end
- cert.extensions = ex
+ ef.subject_certificate = cert
- # for some reason this _must_ be the last extension added
- ex << ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if hash[:type] == :ca
+ if hash[:issuer]
+ ef.issuer_certificate = hash[:issuer]
+ else
+ ef.issuer_certificate = cert
+ end
- cert
+ ex = []
+ case hash[:type]
+ when :ca
+ basic_constraint = "CA:TRUE"
+ key_usage = %w{cRLSign keyCertSign}
+ when :terminalsubca
+ basic_constraint = "CA:TRUE,pathlen:0"
+ key_usage = %w{cRLSign keyCertSign}
+ when :server
+ basic_constraint = "CA:FALSE"
+ dnsnames = Puppet[:certdnsnames]
+ name = hash[:name].to_s.sub(%r{/CN=},'')
+ if dnsnames != ""
+ dnsnames.split(':').each { |d| subject_alt_name << 'DNS:' + d }
+ subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
+ elsif name == Facter.value(:fqdn) # we're a CA server, and thus probably the server
+ subject_alt_name << 'DNS:' + "puppet" # Add 'puppet' as an alias
+ subject_alt_name << 'DNS:' + name # Add the fqdn as an alias
+ subject_alt_name << 'DNS:' + name.sub(/^[^.]+./, "puppet.") # add puppet.domain as an alias
+ end
+ key_usage = %w{digitalSignature keyEncipherment}
+ ext_key_usage = %w{serverAuth clientAuth emailProtection}
+ when :ocsp
+ basic_constraint = "CA:FALSE"
+ key_usage = %w{nonRepudiation digitalSignature}
+ ext_key_usage = %w{serverAuth OCSPSigning}
+ when :client
+ basic_constraint = "CA:FALSE"
+ key_usage = %w{nonRepudiation digitalSignature keyEncipherment}
+ ext_key_usage = %w{clientAuth emailProtection}
+ ex << ef.create_extension("nsCertType", "client,email")
+ else
+ raise Puppet::Error, "unknown cert type '#{hash[:type]}'"
end
- def self.mkhash(dir, cert, certfile)
- # Make sure the hash is zero-padded to 8 chars
- hash = "%08x" % cert.issuer.hash
- hashpath = nil
- 10.times { |i|
- path = File.join(dir, "#{hash}.#{i}")
- if FileTest.exists?(path)
- if FileTest.symlink?(path)
- dest = File.readlink(path)
- if dest == certfile
- # the correct link already exists
- hashpath = path
- break
- else
- next
- end
- else
- next
- end
- end
-
- File.symlink(certfile, path)
+ ex << ef.create_extension(
+ "nsComment",
+
+ "Puppet Ruby/OpenSSL Generated Certificate")
+ ex << ef.create_extension("basicConstraints", basic_constraint, true)
+ ex << ef.create_extension("subjectKeyIdentifier", "hash")
+
+ ex << ef.create_extension("keyUsage", key_usage.join(",")) if key_usage
+ ex << ef.create_extension("extendedKeyUsage", ext_key_usage.join(",")) if ext_key_usage
+ ex << ef.create_extension("subjectAltName", subject_alt_name.join(",")) if ! subject_alt_name.empty?
+
+ #if @ca_config[:cdp_location] then
+ # ex << ef.create_extension("crlDistributionPoints",
+ # @ca_config[:cdp_location])
+ #end
+
+ #if @ca_config[:ocsp_location] then
+ # ex << ef.create_extension("authorityInfoAccess",
+ # "OCSP;" << @ca_config[:ocsp_location])
+ #end
+ cert.extensions = ex
+
+ # for some reason this _must_ be the last extension added
+ ex << ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") if hash[:type] == :ca
+
+ cert
+ end
+
+ def self.mkhash(dir, cert, certfile)
+ # Make sure the hash is zero-padded to 8 chars
+ hash = "%08x" % cert.issuer.hash
+ hashpath = nil
+ 10.times { |i|
+ path = File.join(dir, "#{hash}.#{i}")
+ if FileTest.exists?(path)
+ if FileTest.symlink?(path)
+ dest = File.readlink(path)
+ if dest == certfile
+ # the correct link already exists
hashpath = path
break
- }
+ else
+ next
+ end
+ else
+ next
+ end
+ end
+ File.symlink(certfile, path)
- hashpath
- end
- require 'puppet/sslcertificates/certificate'
- require 'puppet/sslcertificates/inventory'
- require 'puppet/sslcertificates/ca'
+ hashpath = path
+ break
+ }
+
+
+ hashpath
+ end
+ require 'puppet/sslcertificates/certificate'
+ require 'puppet/sslcertificates/inventory'
+ require 'puppet/sslcertificates/ca'
end
diff --git a/lib/puppet/sslcertificates/ca.rb b/lib/puppet/sslcertificates/ca.rb
index e9e66bc61..63e6b922a 100644
--- a/lib/puppet/sslcertificates/ca.rb
+++ b/lib/puppet/sslcertificates/ca.rb
@@ -1,381 +1,381 @@
require 'sync'
class Puppet::SSLCertificates::CA
- include Puppet::Util::Warnings
+ include Puppet::Util::Warnings
- Certificate = Puppet::SSLCertificates::Certificate
- attr_accessor :keyfile, :file, :config, :dir, :cert, :crl
+ Certificate = Puppet::SSLCertificates::Certificate
+ attr_accessor :keyfile, :file, :config, :dir, :cert, :crl
- def certfile
- @config[:cacert]
- end
-
- # Remove all traces of a given host. This is kind of hackish, but, eh.
- def clean(host)
- host = host.downcase
- [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir].each do |name|
- dir = Puppet[name]
-
- file = File.join(dir, host + ".pem")
-
- if FileTest.exists?(file)
- begin
- if Puppet[:name] == "cert"
- puts "Removing #{file}"
- else
- Puppet.info "Removing #{file}"
- end
- File.unlink(file)
- rescue => detail
- raise Puppet::Error, "Could not delete #{file}: #{detail}"
- end
- end
-
- end
- end
-
- def host2csrfile(hostname)
- File.join(Puppet[:csrdir], [hostname.downcase, "pem"].join("."))
- end
+ def certfile
+ @config[:cacert]
+ end
- # this stores signed certs in a directory unrelated to
- # normal client certs
- def host2certfile(hostname)
- File.join(Puppet[:signeddir], [hostname.downcase, "pem"].join("."))
- end
-
- # Turn our hostname into a Name object
- def thing2name(thing)
- thing.subject.to_a.find { |ary|
- ary[0] == "CN"
- }[1]
- end
-
- def initialize(hash = {})
- Puppet.settings.use(:main, :ca, :ssl)
- self.setconfig(hash)
-
- if Puppet[:capass]
- if FileTest.exists?(Puppet[:capass])
- #puts "Reading #{Puppet[:capass]}"
- #system "ls -al #{Puppet[:capass]}"
- #File.read Puppet[:capass]
- @config[:password] = self.getpass
- else
- # Don't create a password if the cert already exists
- @config[:password] = self.genpass unless FileTest.exists?(@config[:cacert])
- end
- end
-
- self.getcert
- init_crl
- unless FileTest.exists?(@config[:serial])
- Puppet.settings.write(:serial) do |f|
- f << "%04X" % 1
- end
- end
- end
+ # Remove all traces of a given host. This is kind of hackish, but, eh.
+ def clean(host)
+ host = host.downcase
+ [:csrdir, :signeddir, :publickeydir, :privatekeydir, :certdir].each do |name|
+ dir = Puppet[name]
- # Generate a new password for the CA.
- def genpass
- pass = ""
- 20.times { pass += (rand(74) + 48).chr }
+ file = File.join(dir, host + ".pem")
+ if FileTest.exists?(file)
begin
- Puppet.settings.write(:capass) { |f| f.print pass }
- rescue Errno::EACCES => detail
- raise Puppet::Error, detail.to_s
+ if Puppet[:name] == "cert"
+ puts "Removing #{file}"
+ else
+ Puppet.info "Removing #{file}"
+ end
+ File.unlink(file)
+ rescue => detail
+ raise Puppet::Error, "Could not delete #{file}: #{detail}"
end
- pass
- end
+ end
- # Get the CA password.
- def getpass
- if @config[:capass] and File.readable?(@config[:capass])
- return File.read(@config[:capass])
- else
- raise Puppet::Error, "Could not decrypt CA key with password: #{detail}"
- end
end
-
- # Get the CA cert.
- def getcert
- if FileTest.exists?(@config[:cacert])
- @cert = OpenSSL::X509::Certificate.new(
- File.read(@config[:cacert])
- )
- else
- self.mkrootcert
- end
+ end
+
+ def host2csrfile(hostname)
+ File.join(Puppet[:csrdir], [hostname.downcase, "pem"].join("."))
+ end
+
+ # this stores signed certs in a directory unrelated to
+ # normal client certs
+ def host2certfile(hostname)
+ File.join(Puppet[:signeddir], [hostname.downcase, "pem"].join("."))
+ end
+
+ # Turn our hostname into a Name object
+ def thing2name(thing)
+ thing.subject.to_a.find { |ary|
+ ary[0] == "CN"
+ }[1]
+ end
+
+ def initialize(hash = {})
+ Puppet.settings.use(:main, :ca, :ssl)
+ self.setconfig(hash)
+
+ if Puppet[:capass]
+ if FileTest.exists?(Puppet[:capass])
+ #puts "Reading #{Puppet[:capass]}"
+ #system "ls -al #{Puppet[:capass]}"
+ #File.read Puppet[:capass]
+ @config[:password] = self.getpass
+ else
+ # Don't create a password if the cert already exists
+ @config[:password] = self.genpass unless FileTest.exists?(@config[:cacert])
+ end
end
- # Retrieve a client's CSR.
- def getclientcsr(host)
- csrfile = host2csrfile(host)
- return nil unless File.exists?(csrfile)
-
- OpenSSL::X509::Request.new(File.read(csrfile))
+ self.getcert
+ init_crl
+ unless FileTest.exists?(@config[:serial])
+ Puppet.settings.write(:serial) do |f|
+ f << "%04X" % 1
+ end
end
+ end
- # Retrieve a client's certificate.
- def getclientcert(host)
- certfile = host2certfile(host)
- return [nil, nil] unless File.exists?(certfile)
+ # Generate a new password for the CA.
+ def genpass
+ pass = ""
+ 20.times { pass += (rand(74) + 48).chr }
- [OpenSSL::X509::Certificate.new(File.read(certfile)), @cert]
+ begin
+ Puppet.settings.write(:capass) { |f| f.print pass }
+ rescue Errno::EACCES => detail
+ raise Puppet::Error, detail.to_s
end
-
- # List certificates waiting to be signed. This returns a list of hostnames, not actual
- # files -- the names can be converted to full paths with host2csrfile.
- def list(dummy_argument=:work_arround_for_ruby_GC_bug)
- return Dir.entries(Puppet[:csrdir]).find_all { |file|
- file =~ /\.pem$/
- }.collect { |file|
- file.sub(/\.pem$/, '')
- }
+ pass
+ end
+
+ # Get the CA password.
+ def getpass
+ if @config[:capass] and File.readable?(@config[:capass])
+ return File.read(@config[:capass])
+ else
+ raise Puppet::Error, "Could not decrypt CA key with password: #{detail}"
end
-
- # List signed certificates. This returns a list of hostnames, not actual
- # files -- the names can be converted to full paths with host2csrfile.
- def list_signed(dummy_argument=:work_arround_for_ruby_GC_bug)
- return Dir.entries(Puppet[:signeddir]).find_all { |file|
- file =~ /\.pem$/
- }.collect { |file|
- file.sub(/\.pem$/, '')
- }
+ end
+
+ # Get the CA cert.
+ def getcert
+ if FileTest.exists?(@config[:cacert])
+ @cert = OpenSSL::X509::Certificate.new(
+ File.read(@config[:cacert])
+ )
+ else
+ self.mkrootcert
+ end
+ end
+
+ # Retrieve a client's CSR.
+ def getclientcsr(host)
+ csrfile = host2csrfile(host)
+ return nil unless File.exists?(csrfile)
+
+ OpenSSL::X509::Request.new(File.read(csrfile))
+ end
+
+ # Retrieve a client's certificate.
+ def getclientcert(host)
+ certfile = host2certfile(host)
+ return [nil, nil] unless File.exists?(certfile)
+
+ [OpenSSL::X509::Certificate.new(File.read(certfile)), @cert]
+ end
+
+ # List certificates waiting to be signed. This returns a list of hostnames, not actual
+ # files -- the names can be converted to full paths with host2csrfile.
+ def list(dummy_argument=:work_arround_for_ruby_GC_bug)
+ return Dir.entries(Puppet[:csrdir]).find_all { |file|
+ file =~ /\.pem$/
+ }.collect { |file|
+ file.sub(/\.pem$/, '')
+ }
+ end
+
+ # List signed certificates. This returns a list of hostnames, not actual
+ # files -- the names can be converted to full paths with host2csrfile.
+ def list_signed(dummy_argument=:work_arround_for_ruby_GC_bug)
+ return Dir.entries(Puppet[:signeddir]).find_all { |file|
+ file =~ /\.pem$/
+ }.collect { |file|
+ file.sub(/\.pem$/, '')
+ }
+ end
+
+ # Create the root certificate.
+ def mkrootcert
+ # Make the root cert's name the FQDN of the host running the CA.
+ name = Facter["hostname"].value
+ if domain = Facter["domain"].value
+ name += ".#{domain}"
end
- # Create the root certificate.
- def mkrootcert
- # Make the root cert's name the FQDN of the host running the CA.
- name = Facter["hostname"].value
- if domain = Facter["domain"].value
- name += ".#{domain}"
- end
-
- cert = Certificate.new(
+ cert = Certificate.new(
- :name => name,
- :cert => @config[:cacert],
- :encrypt => @config[:capass],
- :key => @config[:cakey],
- :selfsign => true,
- :ttl => ttl,
+ :name => name,
+ :cert => @config[:cacert],
+ :encrypt => @config[:capass],
+ :key => @config[:cakey],
+ :selfsign => true,
+ :ttl => ttl,
- :type => :ca
- )
+ :type => :ca
+ )
- # This creates the cakey file
- Puppet::Util::SUIDManager.asuser(Puppet[:user], Puppet[:group]) do
- @cert = cert.mkselfsigned
- end
- Puppet.settings.write(:cacert) do |f|
- f.puts @cert.to_pem
- end
- Puppet.settings.write(:capub) do |f|
- f.puts @cert.public_key
- end
- cert
+ # This creates the cakey file
+ Puppet::Util::SUIDManager.asuser(Puppet[:user], Puppet[:group]) do
+ @cert = cert.mkselfsigned
end
-
- def removeclientcsr(host)
- csrfile = host2csrfile(host)
- raise Puppet::Error, "No certificate request for #{host}" unless File.exists?(csrfile)
-
- File.unlink(csrfile)
+ Puppet.settings.write(:cacert) do |f|
+ f.puts @cert.to_pem
end
-
- # Revoke the certificate with serial number SERIAL issued by this
- # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons
- def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
- time = Time.now
- revoked = OpenSSL::X509::Revoked.new
- revoked.serial = serial
- revoked.time = time
- enum = OpenSSL::ASN1::Enumerated(reason)
- ext = OpenSSL::X509::Extension.new("CRLReason", enum)
- revoked.add_extension(ext)
- @crl.add_revoked(revoked)
- store_crl
+ Puppet.settings.write(:capub) do |f|
+ f.puts @cert.public_key
+ end
+ cert
+ end
+
+ def removeclientcsr(host)
+ csrfile = host2csrfile(host)
+ raise Puppet::Error, "No certificate request for #{host}" unless File.exists?(csrfile)
+
+ File.unlink(csrfile)
+ end
+
+ # Revoke the certificate with serial number SERIAL issued by this
+ # CA. The REASON must be one of the OpenSSL::OCSP::REVOKED_* reasons
+ def revoke(serial, reason = OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE)
+ time = Time.now
+ revoked = OpenSSL::X509::Revoked.new
+ revoked.serial = serial
+ revoked.time = time
+ enum = OpenSSL::ASN1::Enumerated(reason)
+ ext = OpenSSL::X509::Extension.new("CRLReason", enum)
+ revoked.add_extension(ext)
+ @crl.add_revoked(revoked)
+ store_crl
+ end
+
+ # Take the Puppet config and store it locally.
+ def setconfig(hash)
+ @config = {}
+ Puppet.settings.params("ca").each { |param|
+ param = param.intern if param.is_a? String
+ if hash.include?(param)
+ @config[param] = hash[param]
+ Puppet[param] = hash[param]
+ hash.delete(param)
+ else
+ @config[param] = Puppet[param]
+ end
+ }
+
+ if hash.include?(:password)
+ @config[:password] = hash[:password]
+ hash.delete(:password)
end
- # Take the Puppet config and store it locally.
- def setconfig(hash)
- @config = {}
- Puppet.settings.params("ca").each { |param|
- param = param.intern if param.is_a? String
- if hash.include?(param)
- @config[param] = hash[param]
- Puppet[param] = hash[param]
- hash.delete(param)
- else
- @config[param] = Puppet[param]
- end
- }
-
- if hash.include?(:password)
- @config[:password] = hash[:password]
- hash.delete(:password)
- end
+ raise ArgumentError, "Unknown parameters #{hash.keys.join(",")}" if hash.length > 0
- raise ArgumentError, "Unknown parameters #{hash.keys.join(",")}" if hash.length > 0
+ [:cadir, :csrdir, :signeddir].each { |dir|
+ raise Puppet::DevError, "#{dir} is undefined" unless @config[dir]
+ }
+ end
- [:cadir, :csrdir, :signeddir].each { |dir|
- raise Puppet::DevError, "#{dir} is undefined" unless @config[dir]
- }
+ # Sign a given certificate request.
+ def sign(csr)
+ unless csr.is_a?(OpenSSL::X509::Request)
+ raise Puppet::Error,
+ "CA#sign only accepts OpenSSL::X509::Request objects, not #{csr.class}"
end
- # Sign a given certificate request.
- def sign(csr)
- unless csr.is_a?(OpenSSL::X509::Request)
- raise Puppet::Error,
- "CA#sign only accepts OpenSSL::X509::Request objects, not #{csr.class}"
- end
-
- raise Puppet::Error, "CSR sign verification failed" unless csr.verify(csr.public_key)
+ raise Puppet::Error, "CSR sign verification failed" unless csr.verify(csr.public_key)
- serial = nil
- Puppet.settings.readwritelock(:serial) { |f|
- serial = File.read(@config[:serial]).chomp.hex
- # increment the serial
- f << "%04X" % (serial + 1)
- }
+ serial = nil
+ Puppet.settings.readwritelock(:serial) { |f|
+ serial = File.read(@config[:serial]).chomp.hex
+ # increment the serial
+ f << "%04X" % (serial + 1)
+ }
- newcert = Puppet::SSLCertificates.mkcert(
+ newcert = Puppet::SSLCertificates.mkcert(
- :type => :server,
- :name => csr.subject,
- :ttl => ttl,
- :issuer => @cert,
- :serial => serial,
+ :type => :server,
+ :name => csr.subject,
+ :ttl => ttl,
+ :issuer => @cert,
+ :serial => serial,
- :publickey => csr.public_key
- )
+ :publickey => csr.public_key
+ )
- sign_with_key(newcert)
+ sign_with_key(newcert)
- self.storeclientcert(newcert)
+ self.storeclientcert(newcert)
- [newcert, @cert]
- end
+ [newcert, @cert]
+ end
- # Store the client's CSR for later signing. This is called from
- # server/ca.rb, and the CSRs are deleted once the certificate is actually
- # signed.
- def storeclientcsr(csr)
- host = thing2name(csr)
+ # Store the client's CSR for later signing. This is called from
+ # server/ca.rb, and the CSRs are deleted once the certificate is actually
+ # signed.
+ def storeclientcsr(csr)
+ host = thing2name(csr)
- csrfile = host2csrfile(host)
- raise Puppet::Error, "Certificate request for #{host} already exists" if File.exists?(csrfile)
+ csrfile = host2csrfile(host)
+ raise Puppet::Error, "Certificate request for #{host} already exists" if File.exists?(csrfile)
- Puppet.settings.writesub(:csrdir, csrfile) do |f|
- f.print csr.to_pem
- end
+ Puppet.settings.writesub(:csrdir, csrfile) do |f|
+ f.print csr.to_pem
end
+ end
- # Store the certificate that we generate.
- def storeclientcert(cert)
- host = thing2name(cert)
+ # Store the certificate that we generate.
+ def storeclientcert(cert)
+ host = thing2name(cert)
- certfile = host2certfile(host)
- Puppet.notice "Overwriting signed certificate #{certfile} for #{host}" if File.exists?(certfile)
+ certfile = host2certfile(host)
+ Puppet.notice "Overwriting signed certificate #{certfile} for #{host}" if File.exists?(certfile)
- Puppet::SSLCertificates::Inventory::add(cert)
- Puppet.settings.writesub(:signeddir, certfile) do |f|
- f.print cert.to_pem
- end
+ Puppet::SSLCertificates::Inventory::add(cert)
+ Puppet.settings.writesub(:signeddir, certfile) do |f|
+ f.print cert.to_pem
end
-
- # TTL for new certificates in seconds. If config param :ca_ttl is set,
- # use that, otherwise use :ca_days for backwards compatibility
- def ttl
- days = @config[:ca_days]
- if days && days.size > 0
- warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead."
- return @config[:ca_days] * 24 * 60 * 60
- else
- ttl = @config[:ca_ttl]
- if ttl.is_a?(String)
- unless ttl =~ /^(\d+)(y|d|h|s)$/
- raise ArgumentError, "Invalid ca_ttl #{ttl}"
- end
- case $2
- when 'y'
- unit = 365 * 24 * 60 * 60
- when 'd'
- unit = 24 * 60 * 60
- when 'h'
- unit = 60 * 60
- when 's'
- unit = 1
- else
- raise ArgumentError, "Invalid unit for ca_ttl #{ttl}"
- end
- return $1.to_i * unit
- else
- return ttl
- end
+ end
+
+ # TTL for new certificates in seconds. If config param :ca_ttl is set,
+ # use that, otherwise use :ca_days for backwards compatibility
+ def ttl
+ days = @config[:ca_days]
+ if days && days.size > 0
+ warnonce "Parameter ca_ttl is not set. Using depecated ca_days instead."
+ return @config[:ca_days] * 24 * 60 * 60
+ else
+ ttl = @config[:ca_ttl]
+ if ttl.is_a?(String)
+ unless ttl =~ /^(\d+)(y|d|h|s)$/
+ raise ArgumentError, "Invalid ca_ttl #{ttl}"
end
- end
-
- private
- def init_crl
- if FileTest.exists?(@config[:cacrl])
- @crl = OpenSSL::X509::CRL.new(
- File.read(@config[:cacrl])
- )
+ case $2
+ when 'y'
+ unit = 365 * 24 * 60 * 60
+ when 'd'
+ unit = 24 * 60 * 60
+ when 'h'
+ unit = 60 * 60
+ when 's'
+ unit = 1
else
- # Create new CRL
- @crl = OpenSSL::X509::CRL.new
- @crl.issuer = @cert.subject
- @crl.version = 1
- store_crl
- @crl
+ raise ArgumentError, "Invalid unit for ca_ttl #{ttl}"
end
+ return $1.to_i * unit
+ else
+ return ttl
+ end
end
-
- def store_crl
- # Increment the crlNumber
- e = @crl.extensions.find { |e| e.oid == 'crlNumber' }
- ext = @crl.extensions.reject { |e| e.oid == 'crlNumber' }
- crlNum = OpenSSL::ASN1::Integer(e ? e.value.to_i + 1 : 0)
- ext << OpenSSL::X509::Extension.new("crlNumber", crlNum)
- @crl.extensions = ext
-
- # Set last/next update
- now = Time.now
- @crl.last_update = now
- # Keep CRL valid for 5 years
- @crl.next_update = now + 5 * 365*24*60*60
-
- sign_with_key(@crl)
- Puppet.settings.write(:cacrl) do |f|
- f.puts @crl.to_pem
- end
+ end
+
+ private
+ def init_crl
+ if FileTest.exists?(@config[:cacrl])
+ @crl = OpenSSL::X509::CRL.new(
+ File.read(@config[:cacrl])
+ )
+ else
+ # Create new CRL
+ @crl = OpenSSL::X509::CRL.new
+ @crl.issuer = @cert.subject
+ @crl.version = 1
+ store_crl
+ @crl
+ end
+ end
+
+ def store_crl
+ # Increment the crlNumber
+ e = @crl.extensions.find { |e| e.oid == 'crlNumber' }
+ ext = @crl.extensions.reject { |e| e.oid == 'crlNumber' }
+ crlNum = OpenSSL::ASN1::Integer(e ? e.value.to_i + 1 : 0)
+ ext << OpenSSL::X509::Extension.new("crlNumber", crlNum)
+ @crl.extensions = ext
+
+ # Set last/next update
+ now = Time.now
+ @crl.last_update = now
+ # Keep CRL valid for 5 years
+ @crl.next_update = now + 5 * 365*24*60*60
+
+ sign_with_key(@crl)
+ Puppet.settings.write(:cacrl) do |f|
+ f.puts @crl.to_pem
+ end
+ end
+
+ def sign_with_key(signable, digest = OpenSSL::Digest::SHA1.new)
+ cakey = nil
+ if @config[:password]
+ begin
+ cakey = OpenSSL::PKey::RSA.new(
+ File.read(@config[:cakey]), @config[:password]
+ )
+ rescue
+ raise Puppet::Error,
+ "Decrypt of CA private key with password stored in @config[:capass] not possible"
+ end
+ else
+ cakey = OpenSSL::PKey::RSA.new(
+ File.read(@config[:cakey])
+ )
end
- def sign_with_key(signable, digest = OpenSSL::Digest::SHA1.new)
- cakey = nil
- if @config[:password]
- begin
- cakey = OpenSSL::PKey::RSA.new(
- File.read(@config[:cakey]), @config[:password]
- )
- rescue
- raise Puppet::Error,
- "Decrypt of CA private key with password stored in @config[:capass] not possible"
- end
- else
- cakey = OpenSSL::PKey::RSA.new(
- File.read(@config[:cakey])
- )
- end
-
- raise Puppet::Error, "CA Certificate is invalid" unless @cert.check_private_key(cakey)
+ raise Puppet::Error, "CA Certificate is invalid" unless @cert.check_private_key(cakey)
- signable.sign(cakey, digest)
- end
+ signable.sign(cakey, digest)
+ end
end
diff --git a/lib/puppet/sslcertificates/certificate.rb b/lib/puppet/sslcertificates/certificate.rb
index a9d1dd4ea..2d30bb09f 100644
--- a/lib/puppet/sslcertificates/certificate.rb
+++ b/lib/puppet/sslcertificates/certificate.rb
@@ -1,148 +1,148 @@
class Puppet::SSLCertificates::Certificate
- SSLCertificates = Puppet::SSLCertificates
-
- attr_accessor :certfile, :keyfile, :name, :dir, :hash, :type
- attr_accessor :key, :cert, :csr, :cacert
-
- @@params2names = {
- :name => "CN",
- :state => "ST",
- :country => "C",
- :email => "emailAddress",
- :org => "O",
- :city => "L",
- :ou => "OU"
+ SSLCertificates = Puppet::SSLCertificates
+
+ attr_accessor :certfile, :keyfile, :name, :dir, :hash, :type
+ attr_accessor :key, :cert, :csr, :cacert
+
+ @@params2names = {
+ :name => "CN",
+ :state => "ST",
+ :country => "C",
+ :email => "emailAddress",
+ :org => "O",
+ :city => "L",
+ :ou => "OU"
+ }
+
+ def certname
+ OpenSSL::X509::Name.new self.subject
+ end
+
+ def delete
+ [@certfile,@keyfile].each { |file|
+ File.unlink(file) if FileTest.exists?(file)
}
- def certname
- OpenSSL::X509::Name.new self.subject
+ if @hash
+ File.unlink(@hash) if FileTest.symlink?(@hash)
end
+ end
- def delete
- [@certfile,@keyfile].each { |file|
- File.unlink(file) if FileTest.exists?(file)
- }
-
- if @hash
- File.unlink(@hash) if FileTest.symlink?(@hash)
- end
- end
+ def exists?
+ FileTest.exists?(@certfile)
+ end
- def exists?
- FileTest.exists?(@certfile)
- end
-
- def getkey
- self.mkkey unless FileTest.exists?(@keyfile)
- if @password
+ def getkey
+ self.mkkey unless FileTest.exists?(@keyfile)
+ if @password
- @key = OpenSSL::PKey::RSA.new(
+ @key = OpenSSL::PKey::RSA.new(
- File.read(@keyfile),
+ File.read(@keyfile),
- @password
- )
- else
- @key = OpenSSL::PKey::RSA.new(
- File.read(@keyfile)
- )
- end
+ @password
+ )
+ else
+ @key = OpenSSL::PKey::RSA.new(
+ File.read(@keyfile)
+ )
end
+ end
- def initialize(hash)
- raise Puppet::Error, "You must specify the common name for the certificate" unless hash.include?(:name)
- @name = hash[:name]
-
- # init a few variables
- @cert = @key = @csr = nil
+ def initialize(hash)
+ raise Puppet::Error, "You must specify the common name for the certificate" unless hash.include?(:name)
+ @name = hash[:name]
- if hash.include?(:cert)
- @certfile = hash[:cert]
- @dir = File.dirname(@certfile)
- else
- @dir = hash[:dir] || Puppet[:certdir]
- @certfile = File.join(@dir, @name)
- end
+ # init a few variables
+ @cert = @key = @csr = nil
- @cacertfile ||= File.join(Puppet[:certdir], "ca.pem")
+ if hash.include?(:cert)
+ @certfile = hash[:cert]
+ @dir = File.dirname(@certfile)
+ else
+ @dir = hash[:dir] || Puppet[:certdir]
+ @certfile = File.join(@dir, @name)
+ end
- Puppet.recmkdir(@dir) unless FileTest.directory?(@dir)
+ @cacertfile ||= File.join(Puppet[:certdir], "ca.pem")
- unless @certfile =~ /\.pem$/
- @certfile += ".pem"
- end
- @keyfile = hash[:key] || File.join(
- Puppet[:privatekeydir], [@name,"pem"].join(".")
- )
- Puppet.recmkdir(@dir) unless FileTest.directory?(@dir)
+ Puppet.recmkdir(@dir) unless FileTest.directory?(@dir)
- [@keyfile].each { |file|
- dir = File.dirname(file)
+ unless @certfile =~ /\.pem$/
+ @certfile += ".pem"
+ end
+ @keyfile = hash[:key] || File.join(
+ Puppet[:privatekeydir], [@name,"pem"].join(".")
+ )
+ Puppet.recmkdir(@dir) unless FileTest.directory?(@dir)
- Puppet.recmkdir(dir) unless FileTest.directory?(dir)
- }
+ [@keyfile].each { |file|
+ dir = File.dirname(file)
- @ttl = hash[:ttl] || 365 * 24 * 60 * 60
- @selfsign = hash[:selfsign] || false
- @encrypt = hash[:encrypt] || false
- @replace = hash[:replace] || false
- @issuer = hash[:issuer] || nil
-
- if hash.include?(:type)
- case hash[:type]
- when :ca, :client, :server; @type = hash[:type]
- else
- raise "Invalid Cert type #{hash[:type]}"
- end
- else
- @type = :client
- end
+ Puppet.recmkdir(dir) unless FileTest.directory?(dir)
+ }
- @params = {:name => @name}
- [:state, :country, :email, :org, :ou].each { |param|
- @params[param] = hash[param] if hash.include?(param)
- }
+ @ttl = hash[:ttl] || 365 * 24 * 60 * 60
+ @selfsign = hash[:selfsign] || false
+ @encrypt = hash[:encrypt] || false
+ @replace = hash[:replace] || false
+ @issuer = hash[:issuer] || nil
+
+ if hash.include?(:type)
+ case hash[:type]
+ when :ca, :client, :server; @type = hash[:type]
+ else
+ raise "Invalid Cert type #{hash[:type]}"
+ end
+ else
+ @type = :client
+ end
- if @encrypt
- if @encrypt =~ /^\//
- File.open(@encrypt) { |f|
- @password = f.read.chomp
- }
- else
- raise Puppet::Error, ":encrypt must be a path to a pass phrase file"
- end
- else
- @password = nil
- end
+ @params = {:name => @name}
+ [:state, :country, :email, :org, :ou].each { |param|
+ @params[param] = hash[param] if hash.include?(param)
+ }
- @selfsign = hash.include?(:selfsign) && hash[:selfsign]
+ if @encrypt
+ if @encrypt =~ /^\//
+ File.open(@encrypt) { |f|
+ @password = f.read.chomp
+ }
+ else
+ raise Puppet::Error, ":encrypt must be a path to a pass phrase file"
+ end
+ else
+ @password = nil
end
- # this only works for servers, not for users
- def mkcsr
- self.getkey unless @key
+ @selfsign = hash.include?(:selfsign) && hash[:selfsign]
+ end
- name = OpenSSL::X509::Name.new self.subject
+ # this only works for servers, not for users
+ def mkcsr
+ self.getkey unless @key
- @csr = OpenSSL::X509::Request.new
- @csr.version = 0
- @csr.subject = name
- @csr.public_key = @key.public_key
- @csr.sign(@key, OpenSSL::Digest::SHA1.new)
+ name = OpenSSL::X509::Name.new self.subject
- #File.open(@csrfile, "w") { |f|
- # f << @csr.to_pem
- #}
+ @csr = OpenSSL::X509::Request.new
+ @csr.version = 0
+ @csr.subject = name
+ @csr.public_key = @key.public_key
+ @csr.sign(@key, OpenSSL::Digest::SHA1.new)
- raise Puppet::Error, "CSR sign verification failed" unless @csr.verify(@key.public_key)
+ #File.open(@csrfile, "w") { |f|
+ # f << @csr.to_pem
+ #}
- @csr
- end
+ raise Puppet::Error, "CSR sign verification failed" unless @csr.verify(@key.public_key)
- def mkkey
- # @key is the file
+ @csr
+ end
- @key = OpenSSL::PKey::RSA.new(1024)
+ def mkkey
+ # @key is the file
+
+ @key = OpenSSL::PKey::RSA.new(1024)
# { |p,n|
# case p
# when 0; Puppet.info "key info: ." # BN_generate_prime
@@ -156,100 +156,100 @@ class Puppet::SSLCertificates::Certificate
# end
# }
- if @password
- # passwdproc = proc { @password }
-
- keytext = @key.export(
+ if @password
+ # passwdproc = proc { @password }
- OpenSSL::Cipher::DES.new(:EDE3, :CBC),
+ keytext = @key.export(
- @password
- )
- File.open(@keyfile, "w", 0400) { |f|
- f << keytext
- }
- else
- File.open(@keyfile, "w", 0400) { |f|
- f << @key.to_pem
- }
- end
+ OpenSSL::Cipher::DES.new(:EDE3, :CBC),
- #cmd = "#{ossl} genrsa -out #{@key} 1024"
+ @password
+ )
+ File.open(@keyfile, "w", 0400) { |f|
+ f << keytext
+ }
+ else
+ File.open(@keyfile, "w", 0400) { |f|
+ f << @key.to_pem
+ }
end
- def mkselfsigned
- self.getkey unless @key
+ #cmd = "#{ossl} genrsa -out #{@key} 1024"
+ end
- raise Puppet::Error, "Cannot replace existing certificate" if @cert
+ def mkselfsigned
+ self.getkey unless @key
- args = {
- :name => self.certname,
- :ttl => @ttl,
- :issuer => nil,
- :serial => 0x0,
- :publickey => @key.public_key
- }
- if @type
- args[:type] = @type
- else
- args[:type] = :server
- end
- @cert = SSLCertificates.mkcert(args)
+ raise Puppet::Error, "Cannot replace existing certificate" if @cert
- @cert.sign(@key, OpenSSL::Digest::SHA1.new) if @selfsign
-
- @cert
+ args = {
+ :name => self.certname,
+ :ttl => @ttl,
+ :issuer => nil,
+ :serial => 0x0,
+ :publickey => @key.public_key
+ }
+ if @type
+ args[:type] = @type
+ else
+ args[:type] = :server
end
+ @cert = SSLCertificates.mkcert(args)
- def subject(string = false)
- subj = @@params2names.collect { |param, name|
- [name, @params[param]] if @params.include?(param)
- }.reject { |ary| ary.nil? }
+ @cert.sign(@key, OpenSSL::Digest::SHA1.new) if @selfsign
- if string
- return "/" + subj.collect { |ary|
- "%s=%s" % ary
- }.join("/") + "/"
- else
- return subj
- end
- end
+ @cert
+ end
- # verify that we can track down the cert chain or whatever
- def verify
- "openssl verify -verbose -CAfile /home/luke/.puppet/ssl/certs/ca.pem -purpose sslserver culain.madstop.com.pem"
+ def subject(string = false)
+ subj = @@params2names.collect { |param, name|
+ [name, @params[param]] if @params.include?(param)
+ }.reject { |ary| ary.nil? }
+
+ if string
+ return "/" + subj.collect { |ary|
+ "%s=%s" % ary
+ }.join("/") + "/"
+ else
+ return subj
end
+ end
- def write
- files = {
- @certfile => @cert,
- @keyfile => @key,
- }
- files[@cacertfile] = @cacert if defined?(@cacert)
+ # verify that we can track down the cert chain or whatever
+ def verify
+ "openssl verify -verbose -CAfile /home/luke/.puppet/ssl/certs/ca.pem -purpose sslserver culain.madstop.com.pem"
+ end
- files.each { |file,thing|
- if thing
- next if FileTest.exists?(file)
+ def write
+ files = {
+ @certfile => @cert,
+ @keyfile => @key,
+ }
+ files[@cacertfile] = @cacert if defined?(@cacert)
- text = nil
+ files.each { |file,thing|
+ if thing
+ next if FileTest.exists?(file)
- if thing.is_a?(OpenSSL::PKey::RSA) and @password
+ text = nil
- text = thing.export(
+ if thing.is_a?(OpenSSL::PKey::RSA) and @password
- OpenSSL::Cipher::DES.new(:EDE3, :CBC),
+ text = thing.export(
- @password
- )
- else
- text = thing.to_pem
- end
+ OpenSSL::Cipher::DES.new(:EDE3, :CBC),
- File.open(file, "w", 0660) { |f| f.print text }
- end
- }
+ @password
+ )
+ else
+ text = thing.to_pem
+ end
- SSLCertificates.mkhash(Puppet[:certdir], @cacert, @cacertfile) if defined?(@cacert)
- end
+ File.open(file, "w", 0660) { |f| f.print text }
+ end
+ }
+
+ SSLCertificates.mkhash(Puppet[:certdir], @cacert, @cacertfile) if defined?(@cacert)
+ end
end
diff --git a/lib/puppet/sslcertificates/inventory.rb b/lib/puppet/sslcertificates/inventory.rb
index c3f79ee6c..1075c1377 100644
--- a/lib/puppet/sslcertificates/inventory.rb
+++ b/lib/puppet/sslcertificates/inventory.rb
@@ -1,38 +1,38 @@
# A module for keeping track of all the certificates issued by the CA, ever
# Maintains the file "$cadir/inventory.txt"
module Puppet::SSLCertificates
- module Inventory
+ module Inventory
- # Add CERT to the inventory of issued certs in '$cadir/inventory.txt'
- # If no inventory exists yet, build an inventory and list all the
- # certificates that have been signed so far
- def self.add(cert)
- inited = false
- inited = true if FileTest.exists?(Puppet[:cert_inventory])
+ # Add CERT to the inventory of issued certs in '$cadir/inventory.txt'
+ # If no inventory exists yet, build an inventory and list all the
+ # certificates that have been signed so far
+ def self.add(cert)
+ inited = false
+ inited = true if FileTest.exists?(Puppet[:cert_inventory])
- Puppet.settings.write(:cert_inventory, "a") do |f|
- f.puts((inited ? nil : self.init).to_s + format(cert))
- end
- end
+ Puppet.settings.write(:cert_inventory, "a") do |f|
+ f.puts((inited ? nil : self.init).to_s + format(cert))
+ end
+ end
- private
+ private
- def self.init
- inv = "# Inventory of signed certificates\n"
- inv += "# SERIAL NOT_BEFORE NOT_AFTER SUBJECT\n"
- Dir.glob(File::join(Puppet[:signeddir], "*.pem")) do |f|
- inv += format(OpenSSL::X509::Certificate.new(File::read(f))) + "\n"
- end
- inv
- end
+ def self.init
+ inv = "# Inventory of signed certificates\n"
+ inv += "# SERIAL NOT_BEFORE NOT_AFTER SUBJECT\n"
+ Dir.glob(File::join(Puppet[:signeddir], "*.pem")) do |f|
+ inv += format(OpenSSL::X509::Certificate.new(File::read(f))) + "\n"
+ end
+ inv
+ end
- def self.format(cert)
- iso = '%Y-%m-%dT%H:%M:%S%Z'
- return "0x%04x %s %s %s" % [cert.serial,
- cert.not_before.strftime(iso),
- cert.not_after.strftime(iso),
- cert.subject]
- end
+ def self.format(cert)
+ iso = '%Y-%m-%dT%H:%M:%S%Z'
+ return "0x%04x %s %s %s" % [cert.serial,
+ cert.not_before.strftime(iso),
+ cert.not_after.strftime(iso),
+ cert.subject]
end
+ end
end
diff --git a/lib/puppet/sslcertificates/support.rb b/lib/puppet/sslcertificates/support.rb
index 919d68664..7d6708124 100644
--- a/lib/puppet/sslcertificates/support.rb
+++ b/lib/puppet/sslcertificates/support.rb
@@ -2,145 +2,145 @@ require 'puppet/sslcertificates'
# A module to handle reading of certificates.
module Puppet::SSLCertificates::Support
- class MissingCertificate < Puppet::Error; end
- class InvalidCertificate < Puppet::Error; end
+ class MissingCertificate < Puppet::Error; end
+ class InvalidCertificate < Puppet::Error; end
- attr_reader :cacert
+ attr_reader :cacert
- # Some metaprogramming to create methods for retrieving and creating keys.
- # This probably isn't fewer lines than defining each separately...
- def self.keytype(name, options, &block)
- var = "@#{name}"
+ # Some metaprogramming to create methods for retrieving and creating keys.
+ # This probably isn't fewer lines than defining each separately...
+ def self.keytype(name, options, &block)
+ var = "@#{name}"
- maker = "mk_#{name}"
- reader = "read_#{name}"
+ maker = "mk_#{name}"
+ reader = "read_#{name}"
- unless param = options[:param]
- raise ArgumentError, "You must specify the parameter for the key"
- end
-
- unless klass = options[:class]
- raise ArgumentError, "You must specify the class for the key"
- end
+ unless param = options[:param]
+ raise ArgumentError, "You must specify the parameter for the key"
+ end
- # Define the method that creates it.
- define_method(maker, &block)
+ unless klass = options[:class]
+ raise ArgumentError, "You must specify the class for the key"
+ end
- # Define the reading method.
- define_method(reader) do
- return nil unless FileTest.exists?(Puppet[param]) or rename_files_with_uppercase(Puppet[param])
+ # Define the method that creates it.
+ define_method(maker, &block)
- begin
- instance_variable_set(var, klass.new(File.read(Puppet[param])))
- rescue => detail
- raise InvalidCertificate, "Could not read #{param}: #{detail}"
- end
- end
+ # Define the reading method.
+ define_method(reader) do
+ return nil unless FileTest.exists?(Puppet[param]) or rename_files_with_uppercase(Puppet[param])
- # Define the overall method, which just calls the reader and maker
- # as appropriate.
- define_method(name) do
- unless cert = instance_variable_get(var)
- unless cert = send(reader)
- cert = send(maker)
- Puppet.settings.write(param) { |f| f.puts cert.to_pem }
- end
- instance_variable_set(var, cert)
- end
- cert
- end
+ begin
+ instance_variable_set(var, klass.new(File.read(Puppet[param])))
+ rescue => detail
+ raise InvalidCertificate, "Could not read #{param}: #{detail}"
+ end
end
- # The key pair.
- keytype :key, :param => :hostprivkey, :class => OpenSSL::PKey::RSA do
- Puppet.info "Creating a new SSL key at #{Puppet[:hostprivkey]}"
- key = OpenSSL::PKey::RSA.new(Puppet[:keylength])
-
- # Our key meta programming can only handle one file, so we have
- # to separately write out the public key.
- Puppet.settings.write(:hostpubkey) do |f|
- f.print key.public_key.to_pem
+ # Define the overall method, which just calls the reader and maker
+ # as appropriate.
+ define_method(name) do
+ unless cert = instance_variable_get(var)
+ unless cert = send(reader)
+ cert = send(maker)
+ Puppet.settings.write(param) { |f| f.puts cert.to_pem }
end
- return key
+ instance_variable_set(var, cert)
+ end
+ cert
end
+ end
- # Our certificate request
- keytype :csr, :param => :hostcsr, :class => OpenSSL::X509::Request do
- Puppet.info "Creating a new certificate request for #{Puppet[:certname]}"
+ # The key pair.
+ keytype :key, :param => :hostprivkey, :class => OpenSSL::PKey::RSA do
+ Puppet.info "Creating a new SSL key at #{Puppet[:hostprivkey]}"
+ key = OpenSSL::PKey::RSA.new(Puppet[:keylength])
- csr = OpenSSL::X509::Request.new
- csr.version = 0
- csr.subject = OpenSSL::X509::Name.new([["CN", Puppet[:certname]]])
- csr.public_key = key.public_key
- csr.sign(key, OpenSSL::Digest::MD5.new)
-
- return csr
+ # Our key meta programming can only handle one file, so we have
+ # to separately write out the public key.
+ Puppet.settings.write(:hostpubkey) do |f|
+ f.print key.public_key.to_pem
end
-
- keytype :cert, :param => :hostcert, :class => OpenSSL::X509::Certificate do
- raise MissingCertificate, "No host certificate"
+ return key
+ end
+
+ # Our certificate request
+ keytype :csr, :param => :hostcsr, :class => OpenSSL::X509::Request do
+ Puppet.info "Creating a new certificate request for #{Puppet[:certname]}"
+
+ csr = OpenSSL::X509::Request.new
+ csr.version = 0
+ csr.subject = OpenSSL::X509::Name.new([["CN", Puppet[:certname]]])
+ csr.public_key = key.public_key
+ csr.sign(key, OpenSSL::Digest::MD5.new)
+
+ return csr
+ end
+
+ keytype :cert, :param => :hostcert, :class => OpenSSL::X509::Certificate do
+ raise MissingCertificate, "No host certificate"
+ end
+
+ keytype :ca_cert, :param => :localcacert, :class => OpenSSL::X509::Certificate do
+ raise MissingCertificate, "No CA certificate"
+ end
+
+ # Request a certificate from the remote system. This does all of the work
+ # of creating the cert request, contacting the remote system, and
+ # storing the cert locally.
+ def requestcert
+ begin
+ cert, cacert = caclient.getcert(@csr.to_pem)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error.new("Certificate retrieval failed: #{detail}")
end
- keytype :ca_cert, :param => :localcacert, :class => OpenSSL::X509::Certificate do
- raise MissingCertificate, "No CA certificate"
+ if cert.nil? or cert == ""
+ return nil
end
-
- # Request a certificate from the remote system. This does all of the work
- # of creating the cert request, contacting the remote system, and
- # storing the cert locally.
- def requestcert
- begin
- cert, cacert = caclient.getcert(@csr.to_pem)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error.new("Certificate retrieval failed: #{detail}")
- end
-
- if cert.nil? or cert == ""
- return nil
- end
- Puppet.settings.write(:hostcert) do |f| f.print cert end
- Puppet.settings.write(:localcacert) do |f| f.print cacert end
- #File.open(@certfile, "w", 0644) { |f| f.print cert }
- #File.open(@cacertfile, "w", 0644) { |f| f.print cacert }
- begin
- @cert = OpenSSL::X509::Certificate.new(cert)
- @cacert = OpenSSL::X509::Certificate.new(cacert)
- retrieved = true
- rescue => detail
- raise Puppet::Error.new(
- "Invalid certificate: #{detail}"
- )
- end
-
- raise Puppet::DevError, "Received invalid certificate" unless @cert.check_private_key(@key)
- retrieved
+ Puppet.settings.write(:hostcert) do |f| f.print cert end
+ Puppet.settings.write(:localcacert) do |f| f.print cacert end
+ #File.open(@certfile, "w", 0644) { |f| f.print cert }
+ #File.open(@cacertfile, "w", 0644) { |f| f.print cacert }
+ begin
+ @cert = OpenSSL::X509::Certificate.new(cert)
+ @cacert = OpenSSL::X509::Certificate.new(cacert)
+ retrieved = true
+ rescue => detail
+ raise Puppet::Error.new(
+ "Invalid certificate: #{detail}"
+ )
end
- # A hack method to deal with files that exist with a different case.
- # Just renames it; doesn't read it in or anything.
- def rename_files_with_uppercase(file)
- dir = File.dirname(file)
- short = File.basename(file)
+ raise Puppet::DevError, "Received invalid certificate" unless @cert.check_private_key(@key)
+ retrieved
+ end
- # If the dir isn't present, we clearly don't have the file.
- #return nil unless FileTest.directory?(dir)
+ # A hack method to deal with files that exist with a different case.
+ # Just renames it; doesn't read it in or anything.
+ def rename_files_with_uppercase(file)
+ dir = File.dirname(file)
+ short = File.basename(file)
- raise ArgumentError, "Tried to fix SSL files to a file containing uppercase" unless short.downcase == short
+ # If the dir isn't present, we clearly don't have the file.
+ #return nil unless FileTest.directory?(dir)
- return false unless File.directory?(dir)
+ raise ArgumentError, "Tried to fix SSL files to a file containing uppercase" unless short.downcase == short
- real_file = Dir.entries(dir).reject { |f| f =~ /^\./ }.find do |other|
- other.downcase == short
- end
+ return false unless File.directory?(dir)
- return nil unless real_file
+ real_file = Dir.entries(dir).reject { |f| f =~ /^\./ }.find do |other|
+ other.downcase == short
+ end
- full_file = File.join(dir, real_file)
+ return nil unless real_file
- Puppet.notice "Fixing case in #{full_file}; renaming to #{file}"
- File.rename(full_file, file)
+ full_file = File.join(dir, real_file)
- true
- end
+ Puppet.notice "Fixing case in #{full_file}; renaming to #{file}"
+ File.rename(full_file, file)
+
+ true
+ end
end
diff --git a/lib/puppet/status.rb b/lib/puppet/status.rb
index aaec5d3ba..eecd0e18c 100644
--- a/lib/puppet/status.rb
+++ b/lib/puppet/status.rb
@@ -1,28 +1,28 @@
require 'puppet/indirector'
class Puppet::Status
- extend Puppet::Indirector
- indirects :status, :terminus_class => :local
+ extend Puppet::Indirector
+ indirects :status, :terminus_class => :local
- attr :status, true
+ attr :status, true
- def initialize( status = nil )
- @status = status || {"is_alive" => true}
- end
+ def initialize( status = nil )
+ @status = status || {"is_alive" => true}
+ end
- def to_pson
- @status.to_pson
- end
+ def to_pson
+ @status.to_pson
+ end
- def self.from_pson( pson )
- self.new( pson )
- end
+ def self.from_pson( pson )
+ self.new( pson )
+ end
- def name
- "status"
- end
+ def name
+ "status"
+ end
- def name=(name)
- # NOOP
- end
+ def name=(name)
+ # NOOP
+ end
end
diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb
index d70e06c85..dcd9aad0a 100644
--- a/lib/puppet/transaction.rb
+++ b/lib/puppet/transaction.rb
@@ -6,355 +6,355 @@ require 'puppet/util/tagging'
require 'puppet/application'
class Puppet::Transaction
- require 'puppet/transaction/change'
- require 'puppet/transaction/event'
- require 'puppet/transaction/event_manager'
- require 'puppet/transaction/resource_harness'
- require 'puppet/resource/status'
+ require 'puppet/transaction/change'
+ require 'puppet/transaction/event'
+ require 'puppet/transaction/event_manager'
+ require 'puppet/transaction/resource_harness'
+ require 'puppet/resource/status'
- attr_accessor :component, :catalog, :ignoreschedules
- attr_accessor :sorted_resources, :configurator
+ attr_accessor :component, :catalog, :ignoreschedules
+ attr_accessor :sorted_resources, :configurator
- # The report, once generated.
- attr_accessor :report
+ # The report, once generated.
+ attr_accessor :report
- # Routes and stores any events and subscriptions.
- attr_reader :event_manager
+ # Routes and stores any events and subscriptions.
+ attr_reader :event_manager
- # Handles most of the actual interacting with resources
- attr_reader :resource_harness
+ # Handles most of the actual interacting with resources
+ attr_reader :resource_harness
- include Puppet::Util
- include Puppet::Util::Tagging
+ include Puppet::Util
+ include Puppet::Util::Tagging
- # Wraps application run state check to flag need to interrupt processing
- def stop_processing?
- Puppet::Application.stop_requested?
- end
-
- # Add some additional times for reporting
- def add_times(hash)
- hash.each do |name, num|
- report.add_times(name, num)
- end
- end
-
- # Are there any failed resources in this transaction?
- def any_failed?
- report.resource_statuses.values.detect { |status| status.failed? }
- end
-
- # Apply all changes for a resource
- def apply(resource, ancestor = nil)
- status = resource_harness.evaluate(resource)
- add_resource_status(status)
- event_manager.queue_events(ancestor || resource, status.events)
- rescue => detail
- resource.err "Could not evaluate: #{detail}"
- end
+ # Wraps application run state check to flag need to interrupt processing
+ def stop_processing?
+ Puppet::Application.stop_requested?
+ end
- # Find all of the changed resources.
- def changed?
- report.resource_statuses.values.find_all { |status| status.changed }.collect { |status| catalog.resource(status.resource) }
+ # Add some additional times for reporting
+ def add_times(hash)
+ hash.each do |name, num|
+ report.add_times(name, num)
end
-
- # Copy an important relationships from the parent to the newly-generated
- # child resource.
- def make_parent_child_relationship(resource, children)
- depthfirst = resource.depthfirst?
-
- children.each do |gen_child|
- if depthfirst
- edge = [gen_child, resource]
- else
- edge = [resource, gen_child]
- end
- relationship_graph.add_vertex(gen_child)
-
- unless relationship_graph.edge?(edge[1], edge[0])
- relationship_graph.add_edge(*edge)
- else
- resource.debug "Skipping automatic relationship to #{gen_child}"
- end
- end
+ end
+
+ # Are there any failed resources in this transaction?
+ def any_failed?
+ report.resource_statuses.values.detect { |status| status.failed? }
+ end
+
+ # Apply all changes for a resource
+ def apply(resource, ancestor = nil)
+ status = resource_harness.evaluate(resource)
+ add_resource_status(status)
+ event_manager.queue_events(ancestor || resource, status.events)
+ rescue => detail
+ resource.err "Could not evaluate: #{detail}"
+ end
+
+ # Find all of the changed resources.
+ def changed?
+ report.resource_statuses.values.find_all { |status| status.changed }.collect { |status| catalog.resource(status.resource) }
+ end
+
+ # Copy an important relationships from the parent to the newly-generated
+ # child resource.
+ def make_parent_child_relationship(resource, children)
+ depthfirst = resource.depthfirst?
+
+ children.each do |gen_child|
+ if depthfirst
+ edge = [gen_child, resource]
+ else
+ edge = [resource, gen_child]
+ end
+ relationship_graph.add_vertex(gen_child)
+
+ unless relationship_graph.edge?(edge[1], edge[0])
+ relationship_graph.add_edge(*edge)
+ else
+ resource.debug "Skipping automatic relationship to #{gen_child}"
+ end
end
-
- # See if the resource generates new resources at evaluation time.
- def eval_generate(resource)
- generate_additional_resources(resource, :eval_generate)
- end
-
- # Evaluate a single resource.
- def eval_resource(resource, ancestor = nil)
- if skip?(resource)
- resource_status(resource).skipped = true
- else
- eval_children_and_apply_resource(resource, ancestor)
- end
-
- # Check to see if there are any events queued for this resource
- event_manager.process_events(resource)
+ end
+
+ # See if the resource generates new resources at evaluation time.
+ def eval_generate(resource)
+ generate_additional_resources(resource, :eval_generate)
+ end
+
+ # Evaluate a single resource.
+ def eval_resource(resource, ancestor = nil)
+ if skip?(resource)
+ resource_status(resource).skipped = true
+ else
+ eval_children_and_apply_resource(resource, ancestor)
end
- def eval_children_and_apply_resource(resource, ancestor = nil)
- resource_status(resource).scheduled = true
+ # Check to see if there are any events queued for this resource
+ event_manager.process_events(resource)
+ end
- # We need to generate first regardless, because the recursive
- # actions sometimes change how the top resource is applied.
- children = eval_generate(resource)
-
- if ! children.empty? and resource.depthfirst?
- children.each do |child|
- # The child will never be skipped when the parent isn't
- eval_resource(child, ancestor || resource)
- end
- end
+ def eval_children_and_apply_resource(resource, ancestor = nil)
+ resource_status(resource).scheduled = true
- # Perform the actual changes
- apply(resource, ancestor)
+ # We need to generate first regardless, because the recursive
+ # actions sometimes change how the top resource is applied.
+ children = eval_generate(resource)
- if ! children.empty? and ! resource.depthfirst?
- children.each do |child|
- eval_resource(child, ancestor || resource)
- end
- end
+ if ! children.empty? and resource.depthfirst?
+ children.each do |child|
+ # The child will never be skipped when the parent isn't
+ eval_resource(child, ancestor || resource)
+ end
end
- # This method does all the actual work of running a transaction. It
- # collects all of the changes, executes them, and responds to any
- # necessary events.
- def evaluate
- # Start logging.
- Puppet::Util::Log.newdestination(@report)
-
- prepare
-
- Puppet.info "Applying configuration version '#{catalog.version}'" if catalog.version
-
- begin
- @sorted_resources.each do |resource|
- next if stop_processing?
- if resource.is_a?(Puppet::Type::Component)
- Puppet.warning "Somehow left a component in the relationship graph"
- next
- end
- ret = nil
- seconds = thinmark do
- ret = eval_resource(resource)
- end
-
- resource.info "Evaluated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config?
- ret
- end
- ensure
- # And then close the transaction log.
- Puppet::Util::Log.close(@report)
- end
-
- Puppet.debug "Finishing transaction #{object_id}"
- end
+ # Perform the actual changes
+ apply(resource, ancestor)
- def events
- event_manager.events
+ if ! children.empty? and ! resource.depthfirst?
+ children.each do |child|
+ eval_resource(child, ancestor || resource)
+ end
end
+ end
- def failed?(resource)
- s = resource_status(resource) and s.failed?
- end
+ # This method does all the actual work of running a transaction. It
+ # collects all of the changes, executes them, and responds to any
+ # necessary events.
+ def evaluate
+ # Start logging.
+ Puppet::Util::Log.newdestination(@report)
- # Does this resource have any failed dependencies?
- def failed_dependencies?(resource)
- # First make sure there are no failed dependencies. To do this,
- # we check for failures in any of the vertexes above us. It's not
- # enough to check the immediate dependencies, which is why we use
- # a tree from the reversed graph.
- found_failed = false
- relationship_graph.dependencies(resource).each do |dep|
- next unless failed?(dep)
- resource.notice "Dependency #{dep} has failures: #{resource_status(dep).failed}"
- found_failed = true
- end
+ prepare
- found_failed
- end
+ Puppet.info "Applying configuration version '#{catalog.version}'" if catalog.version
- # A general method for recursively generating new resources from a
- # resource.
- def generate_additional_resources(resource, method)
- return [] unless resource.respond_to?(method)
- begin
- made = resource.send(method)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- resource.err "Failed to generate additional resources using '#{method}': #{detail}"
+ begin
+ @sorted_resources.each do |resource|
+ next if stop_processing?
+ if resource.is_a?(Puppet::Type::Component)
+ Puppet.warning "Somehow left a component in the relationship graph"
+ next
end
- return [] unless made
- made = [made] unless made.is_a?(Array)
- made.uniq.find_all do |res|
- begin
- res.tag(*resource.tags)
- @catalog.add_resource(res) do |r|
- r.finish
- make_parent_child_relationship(resource, [r])
-
- # Call 'generate' recursively
- generate_additional_resources(r, method)
- end
- true
- rescue Puppet::Resource::Catalog::DuplicateResourceError
- res.info "Duplicate generated resource; skipping"
- false
- end
+ ret = nil
+ seconds = thinmark do
+ ret = eval_resource(resource)
end
- end
- # Collect any dynamically generated resources. This method is called
- # before the transaction starts.
- def generate
- list = @catalog.vertices
- newlist = []
- while ! list.empty?
- list.each do |resource|
- newlist += generate_additional_resources(resource, :generate)
- end
- list = newlist
- newlist = []
- end
+ resource.info "Evaluated in %0.2f seconds" % seconds if Puppet[:evaltrace] and @catalog.host_config?
+ ret
+ end
+ ensure
+ # And then close the transaction log.
+ Puppet::Util::Log.close(@report)
end
- # Generate a transaction report.
- def generate_report
- @report.calculate_metrics
- @report
+ Puppet.debug "Finishing transaction #{object_id}"
+ end
+
+ def events
+ event_manager.events
+ end
+
+ def failed?(resource)
+ s = resource_status(resource) and s.failed?
+ end
+
+ # Does this resource have any failed dependencies?
+ def failed_dependencies?(resource)
+ # First make sure there are no failed dependencies. To do this,
+ # we check for failures in any of the vertexes above us. It's not
+ # enough to check the immediate dependencies, which is why we use
+ # a tree from the reversed graph.
+ found_failed = false
+ relationship_graph.dependencies(resource).each do |dep|
+ next unless failed?(dep)
+ resource.notice "Dependency #{dep} has failures: #{resource_status(dep).failed}"
+ found_failed = true
end
- # Should we ignore tags?
- def ignore_tags?
- ! (@catalog.host_config? or Puppet[:name] == "puppet")
- end
+ found_failed
+ end
- # this should only be called by a Puppet::Type::Component resource now
- # and it should only receive an array
- def initialize(catalog)
- @catalog = catalog
-
- @report = Report.new
-
- @event_manager = Puppet::Transaction::EventManager.new(self)
-
- @resource_harness = Puppet::Transaction::ResourceHarness.new(self)
+ # A general method for recursively generating new resources from a
+ # resource.
+ def generate_additional_resources(resource, method)
+ return [] unless resource.respond_to?(method)
+ begin
+ made = resource.send(method)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ resource.err "Failed to generate additional resources using '#{method}': #{detail}"
end
-
- # Prefetch any providers that support it. We don't support prefetching
- # types, just providers.
- def prefetch
- prefetchers = {}
- @catalog.vertices.each do |resource|
- if provider = resource.provider and provider.class.respond_to?(:prefetch)
- prefetchers[provider.class] ||= {}
- prefetchers[provider.class][resource.name] = resource
- end
- end
-
- # Now call prefetch, passing in the resources so that the provider instances can be replaced.
- prefetchers.each do |provider, resources|
- Puppet.debug "Prefetching #{provider.name} resources for #{provider.resource_type.name}"
- begin
- provider.prefetch(resources)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not prefetch #{provider.resource_type.name} provider '#{provider.name}': #{detail}"
- end
+ return [] unless made
+ made = [made] unless made.is_a?(Array)
+ made.uniq.find_all do |res|
+ begin
+ res.tag(*resource.tags)
+ @catalog.add_resource(res) do |r|
+ r.finish
+ make_parent_child_relationship(resource, [r])
+
+ # Call 'generate' recursively
+ generate_additional_resources(r, method)
end
+ true
+ rescue Puppet::Resource::Catalog::DuplicateResourceError
+ res.info "Duplicate generated resource; skipping"
+ false
+ end
end
-
- # Prepare to evaluate the resources in a transaction.
- def prepare
- # Now add any dynamically generated resources
- generate
-
- # Then prefetch. It's important that we generate and then prefetch,
- # so that any generated resources also get prefetched.
- prefetch
-
- # This will throw an error if there are cycles in the graph.
- @sorted_resources = relationship_graph.topsort
+ end
+
+ # Collect any dynamically generated resources. This method is called
+ # before the transaction starts.
+ def generate
+ list = @catalog.vertices
+ newlist = []
+ while ! list.empty?
+ list.each do |resource|
+ newlist += generate_additional_resources(resource, :generate)
+ end
+ list = newlist
+ newlist = []
end
-
- def relationship_graph
- catalog.relationship_graph
+ end
+
+ # Generate a transaction report.
+ def generate_report
+ @report.calculate_metrics
+ @report
+ end
+
+ # Should we ignore tags?
+ def ignore_tags?
+ ! (@catalog.host_config? or Puppet[:name] == "puppet")
+ end
+
+ # this should only be called by a Puppet::Type::Component resource now
+ # and it should only receive an array
+ def initialize(catalog)
+ @catalog = catalog
+
+ @report = Report.new
+
+ @event_manager = Puppet::Transaction::EventManager.new(self)
+
+ @resource_harness = Puppet::Transaction::ResourceHarness.new(self)
+ end
+
+ # Prefetch any providers that support it. We don't support prefetching
+ # types, just providers.
+ def prefetch
+ prefetchers = {}
+ @catalog.vertices.each do |resource|
+ if provider = resource.provider and provider.class.respond_to?(:prefetch)
+ prefetchers[provider.class] ||= {}
+ prefetchers[provider.class][resource.name] = resource
+ end
end
- # Send off the transaction report.
- def send_report
- begin
- report = generate_report
- rescue => detail
- Puppet.err "Could not generate report: #{detail}"
- return
- end
-
- puts report.summary if Puppet[:summarize]
-
- if Puppet[:report]
- begin
- report.save
- rescue => detail
- Puppet.err "Reporting failed: #{detail}"
- end
- end
+ # Now call prefetch, passing in the resources so that the provider instances can be replaced.
+ prefetchers.each do |provider, resources|
+ Puppet.debug "Prefetching #{provider.name} resources for #{provider.resource_type.name}"
+ begin
+ provider.prefetch(resources)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not prefetch #{provider.resource_type.name} provider '#{provider.name}': #{detail}"
+ end
end
+ end
- def add_resource_status(status)
- report.add_resource_status status
- end
+ # Prepare to evaluate the resources in a transaction.
+ def prepare
+ # Now add any dynamically generated resources
+ generate
- def resource_status(resource)
- report.resource_statuses[resource.to_s] || add_resource_status(Puppet::Resource::Status.new(resource))
- end
+ # Then prefetch. It's important that we generate and then prefetch,
+ # so that any generated resources also get prefetched.
+ prefetch
- # Is the resource currently scheduled?
- def scheduled?(resource)
- self.ignoreschedules or resource_harness.scheduled?(resource_status(resource), resource)
- end
+ # This will throw an error if there are cycles in the graph.
+ @sorted_resources = relationship_graph.topsort
+ end
- # Should this resource be skipped?
- def skip?(resource)
- if missing_tags?(resource)
- resource.debug "Not tagged with #{tags.join(", ")}"
- elsif ! scheduled?(resource)
- resource.debug "Not scheduled"
- elsif failed_dependencies?(resource)
- resource.warning "Skipping because of failed dependencies"
- elsif resource.virtual?
- resource.debug "Skipping because virtual"
- else
- return false
- end
- true
- end
-
- # The tags we should be checking.
- def tags
- self.tags = Puppet[:tags] unless defined?(@tags)
-
- super
- end
+ def relationship_graph
+ catalog.relationship_graph
+ end
- def handle_qualified_tags( qualified )
- # The default behavior of Puppet::Util::Tagging is
- # to split qualified tags into parts. That would cause
- # qualified tags to match too broadly here.
- return
+ # Send off the transaction report.
+ def send_report
+ begin
+ report = generate_report
+ rescue => detail
+ Puppet.err "Could not generate report: #{detail}"
+ return
end
- # Is this resource tagged appropriately?
- def missing_tags?(resource)
- return false if ignore_tags?
- return false if tags.empty?
+ puts report.summary if Puppet[:summarize]
- not resource.tagged?(*tags)
+ if Puppet[:report]
+ begin
+ report.save
+ rescue => detail
+ Puppet.err "Reporting failed: #{detail}"
+ end
+ end
+ end
+
+ def add_resource_status(status)
+ report.add_resource_status status
+ end
+
+ def resource_status(resource)
+ report.resource_statuses[resource.to_s] || add_resource_status(Puppet::Resource::Status.new(resource))
+ end
+
+ # Is the resource currently scheduled?
+ def scheduled?(resource)
+ self.ignoreschedules or resource_harness.scheduled?(resource_status(resource), resource)
+ end
+
+ # Should this resource be skipped?
+ def skip?(resource)
+ if missing_tags?(resource)
+ resource.debug "Not tagged with #{tags.join(", ")}"
+ elsif ! scheduled?(resource)
+ resource.debug "Not scheduled"
+ elsif failed_dependencies?(resource)
+ resource.warning "Skipping because of failed dependencies"
+ elsif resource.virtual?
+ resource.debug "Skipping because virtual"
+ else
+ return false
end
+ true
+ end
+
+ # The tags we should be checking.
+ def tags
+ self.tags = Puppet[:tags] unless defined?(@tags)
+
+ super
+ end
+
+ def handle_qualified_tags( qualified )
+ # The default behavior of Puppet::Util::Tagging is
+ # to split qualified tags into parts. That would cause
+ # qualified tags to match too broadly here.
+ return
+ end
+
+ # Is this resource tagged appropriately?
+ def missing_tags?(resource)
+ return false if ignore_tags?
+ return false if tags.empty?
+
+ not resource.tagged?(*tags)
+ end
end
require 'puppet/transaction/report'
diff --git a/lib/puppet/transaction/change.rb b/lib/puppet/transaction/change.rb
index c8acec88b..ecc3b5a5f 100644
--- a/lib/puppet/transaction/change.rb
+++ b/lib/puppet/transaction/change.rb
@@ -4,84 +4,84 @@ require 'puppet/transaction/event'
# Handle all of the work around performing an actual change,
# including calling 'sync' on the properties and producing events.
class Puppet::Transaction::Change
- attr_accessor :is, :should, :property, :proxy, :auditing
-
- def auditing?
- auditing
- end
-
- # Create our event object.
- def event
- result = property.event
- result.previous_value = is
- result.desired_value = should
- result
- end
-
- def initialize(property, currentvalue)
- @property = property
- @is = currentvalue
-
- @should = property.should
-
- @changed = false
- end
-
- def apply
- return audit_event if auditing?
- return noop_event if noop?
-
- property.sync
-
- result = event
- result.message = property.change_to_s(is, should)
- result.status = "success"
- result.send_log
- result
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- result = event
- result.status = "failure"
-
- result.message = "change from #{property.is_to_s(is)} to #{property.should_to_s(should)} failed: #{detail}"
- result.send_log
- result
- end
-
- # Is our property noop? This is used for generating special events.
- def noop?
- @property.noop
- end
-
- # The resource that generated this change. This is used for handling events,
- # and the proxy resource is used for generated resources, since we can't
- # send an event to a resource we don't have a direct relationship with. If we
- # have a proxy resource, then the events will be considered to be from
- # that resource, rather than us, so the graph resolution will still work.
- def resource
- self.proxy || @property.resource
- end
-
- def to_s
- "change #{@property.change_to_s(@is, @should)}"
- end
-
- private
-
- def audit_event
- # This needs to store the appropriate value, and then produce a new event
- result = event
- result.message = "audit change: previously recorded value #{property.should_to_s(should)} has been changed to #{property.is_to_s(is)}"
- result.status = "audit"
- result.send_log
- result
- end
-
- def noop_event
- result = event
- result.message = "is #{property.is_to_s(is)}, should be #{property.should_to_s(should)} (noop)"
- result.status = "noop"
- result.send_log
- result
- end
+ attr_accessor :is, :should, :property, :proxy, :auditing
+
+ def auditing?
+ auditing
+ end
+
+ # Create our event object.
+ def event
+ result = property.event
+ result.previous_value = is
+ result.desired_value = should
+ result
+ end
+
+ def initialize(property, currentvalue)
+ @property = property
+ @is = currentvalue
+
+ @should = property.should
+
+ @changed = false
+ end
+
+ def apply
+ return audit_event if auditing?
+ return noop_event if noop?
+
+ property.sync
+
+ result = event
+ result.message = property.change_to_s(is, should)
+ result.status = "success"
+ result.send_log
+ result
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ result = event
+ result.status = "failure"
+
+ result.message = "change from #{property.is_to_s(is)} to #{property.should_to_s(should)} failed: #{detail}"
+ result.send_log
+ result
+ end
+
+ # Is our property noop? This is used for generating special events.
+ def noop?
+ @property.noop
+ end
+
+ # The resource that generated this change. This is used for handling events,
+ # and the proxy resource is used for generated resources, since we can't
+ # send an event to a resource we don't have a direct relationship with. If we
+ # have a proxy resource, then the events will be considered to be from
+ # that resource, rather than us, so the graph resolution will still work.
+ def resource
+ self.proxy || @property.resource
+ end
+
+ def to_s
+ "change #{@property.change_to_s(@is, @should)}"
+ end
+
+ private
+
+ def audit_event
+ # This needs to store the appropriate value, and then produce a new event
+ result = event
+ result.message = "audit change: previously recorded value #{property.should_to_s(should)} has been changed to #{property.is_to_s(is)}"
+ result.status = "audit"
+ result.send_log
+ result
+ end
+
+ def noop_event
+ result = event
+ result.message = "is #{property.is_to_s(is)}, should be #{property.should_to_s(should)} (noop)"
+ result.status = "noop"
+ result.send_log
+ result
+ end
end
diff --git a/lib/puppet/transaction/event.rb b/lib/puppet/transaction/event.rb
index cb6c24edb..e5e5793da 100644
--- a/lib/puppet/transaction/event.rb
+++ b/lib/puppet/transaction/event.rb
@@ -4,58 +4,58 @@ require 'puppet/util/logging'
# A simple struct for storing what happens on the system.
class Puppet::Transaction::Event
- include Puppet::Util::Tagging
- include Puppet::Util::Logging
+ include Puppet::Util::Tagging
+ include Puppet::Util::Logging
- ATTRIBUTES = [:name, :resource, :property, :previous_value, :desired_value, :status, :message, :node, :version, :file, :line, :source_description]
- attr_accessor *ATTRIBUTES
- attr_writer :tags
- attr_accessor :time
- attr_reader :default_log_level
+ ATTRIBUTES = [:name, :resource, :property, :previous_value, :desired_value, :status, :message, :node, :version, :file, :line, :source_description]
+ attr_accessor *ATTRIBUTES
+ attr_writer :tags
+ attr_accessor :time
+ attr_reader :default_log_level
- EVENT_STATUSES = %w{noop success failure audit}
+ EVENT_STATUSES = %w{noop success failure audit}
- def initialize(*args)
- options = args.last.is_a?(Hash) ? args.pop : ATTRIBUTES.inject({}) { |hash, attr| hash[attr] = args.pop; hash }
- options.each { |attr, value| send(attr.to_s + "=", value) unless value.nil? }
+ def initialize(*args)
+ options = args.last.is_a?(Hash) ? args.pop : ATTRIBUTES.inject({}) { |hash, attr| hash[attr] = args.pop; hash }
+ options.each { |attr, value| send(attr.to_s + "=", value) unless value.nil? }
- @time = Time.now
- end
+ @time = Time.now
+ end
- def property=(prop)
- @property = prop.to_s
- end
+ def property=(prop)
+ @property = prop.to_s
+ end
- def resource=(res)
- if res.respond_to?(:[]) and level = res[:loglevel]
- @default_log_level = level
- end
- @resource = res.to_s
+ def resource=(res)
+ if res.respond_to?(:[]) and level = res[:loglevel]
+ @default_log_level = level
end
+ @resource = res.to_s
+ end
- def send_log
- super(log_level, message)
- end
+ def send_log
+ super(log_level, message)
+ end
- def status=(value)
- raise ArgumentError, "Event status can only be #{EVENT_STATUSES.join(', ')}" unless EVENT_STATUSES.include?(value)
- @status = value
- end
+ def status=(value)
+ raise ArgumentError, "Event status can only be #{EVENT_STATUSES.join(', ')}" unless EVENT_STATUSES.include?(value)
+ @status = value
+ end
- def to_s
- message
- end
+ def to_s
+ message
+ end
- private
+ private
- # If it's a failure, use 'err', else use either the resource's log level (if available)
- # or 'notice'.
- def log_level
- status == "failure" ? :err : (@default_log_level || :notice)
- end
+ # If it's a failure, use 'err', else use either the resource's log level (if available)
+ # or 'notice'.
+ def log_level
+ status == "failure" ? :err : (@default_log_level || :notice)
+ end
- # Used by the Logging module
- def log_source
- source_description || property || resource
- end
+ # Used by the Logging module
+ def log_source
+ source_description || property || resource
+ end
end
diff --git a/lib/puppet/transaction/event_manager.rb b/lib/puppet/transaction/event_manager.rb
index 34a434248..3ebb0a9d3 100644
--- a/lib/puppet/transaction/event_manager.rb
+++ b/lib/puppet/transaction/event_manager.rb
@@ -1,99 +1,99 @@
require 'puppet/transaction'
class Puppet::Transaction::EventManager
- attr_reader :transaction, :events
-
- def initialize(transaction)
- @transaction = transaction
- @event_queues = {}
- @events = []
- end
-
- def relationship_graph
- transaction.relationship_graph
+ attr_reader :transaction, :events
+
+ def initialize(transaction)
+ @transaction = transaction
+ @event_queues = {}
+ @events = []
+ end
+
+ def relationship_graph
+ transaction.relationship_graph
+ end
+
+ # Respond to any queued events for this resource.
+ def process_events(resource)
+ restarted = false
+ queued_events(resource) do |callback, events|
+ r = process_callback(resource, callback, events)
+ restarted ||= r
end
- # Respond to any queued events for this resource.
- def process_events(resource)
- restarted = false
- queued_events(resource) do |callback, events|
- r = process_callback(resource, callback, events)
- restarted ||= r
- end
-
- if restarted
- queue_events(resource, [resource.event(:name => :restarted, :status => "success")])
+ if restarted
+ queue_events(resource, [resource.event(:name => :restarted, :status => "success")])
- transaction.resource_status(resource).restarted = true
- end
+ transaction.resource_status(resource).restarted = true
end
-
- # Queue events for other resources to respond to. All of these events have
- # to be from the same resource.
- def queue_events(resource, events)
- @events += events
-
- # Do some basic normalization so we're not doing so many
- # graph queries for large sets of events.
- events.inject({}) do |collection, event|
- collection[event.name] ||= []
- collection[event.name] << event
- collection
- end.collect do |name, list|
- # It doesn't matter which event we use - they all have the same source
- # and name here.
- event = list[0]
-
- # Collect the targets of any subscriptions to those events. We pass
- # the parent resource in so it will override the source in the events,
- # since eval_generated children can't have direct relationships.
- relationship_graph.matching_edges(event, resource).each do |edge|
- next unless method = edge.callback
- next unless edge.target.respond_to?(method)
-
- queue_events_for_resource(resource, edge.target, method, list)
- end
-
- queue_events_for_resource(resource, resource, :refresh, [event]) if resource.self_refresh? and ! resource.deleting?
- end
+ end
+
+ # Queue events for other resources to respond to. All of these events have
+ # to be from the same resource.
+ def queue_events(resource, events)
+ @events += events
+
+ # Do some basic normalization so we're not doing so many
+ # graph queries for large sets of events.
+ events.inject({}) do |collection, event|
+ collection[event.name] ||= []
+ collection[event.name] << event
+ collection
+ end.collect do |name, list|
+ # It doesn't matter which event we use - they all have the same source
+ # and name here.
+ event = list[0]
+
+ # Collect the targets of any subscriptions to those events. We pass
+ # the parent resource in so it will override the source in the events,
+ # since eval_generated children can't have direct relationships.
+ relationship_graph.matching_edges(event, resource).each do |edge|
+ next unless method = edge.callback
+ next unless edge.target.respond_to?(method)
+
+ queue_events_for_resource(resource, edge.target, method, list)
+ end
+
+ queue_events_for_resource(resource, resource, :refresh, [event]) if resource.self_refresh? and ! resource.deleting?
end
+ end
- def queue_events_for_resource(source, target, callback, events)
- source.info "Scheduling #{callback} of #{target}"
+ def queue_events_for_resource(source, target, callback, events)
+ source.info "Scheduling #{callback} of #{target}"
- @event_queues[target] ||= {}
- @event_queues[target][callback] ||= []
- @event_queues[target][callback] += events
- end
+ @event_queues[target] ||= {}
+ @event_queues[target][callback] ||= []
+ @event_queues[target][callback] += events
+ end
- def queued_events(resource)
- return unless callbacks = @event_queues[resource]
- callbacks.each do |callback, events|
- yield callback, events
- end
+ def queued_events(resource)
+ return unless callbacks = @event_queues[resource]
+ callbacks.each do |callback, events|
+ yield callback, events
end
+ end
- private
+ private
- def process_callback(resource, callback, events)
- process_noop_events(resource, callback, events) and return false unless events.detect { |e| e.status != "noop" }
- resource.send(callback)
+ def process_callback(resource, callback, events)
+ process_noop_events(resource, callback, events) and return false unless events.detect { |e| e.status != "noop" }
+ resource.send(callback)
- resource.notice "Triggered '#{callback}' from #{events.length} events"
- return true
- rescue => detail
- resource.err "Failed to call #{callback}: #{detail}"
+ resource.notice "Triggered '#{callback}' from #{events.length} events"
+ return true
+ rescue => detail
+ resource.err "Failed to call #{callback}: #{detail}"
- transaction.resource_status(resource).failed_to_restart = true
- puts detail.backtrace if Puppet[:trace]
- return false
- end
+ transaction.resource_status(resource).failed_to_restart = true
+ puts detail.backtrace if Puppet[:trace]
+ return false
+ end
- def process_noop_events(resource, callback, events)
- resource.notice "Would have triggered '#{callback}' from #{events.length} events"
+ def process_noop_events(resource, callback, events)
+ resource.notice "Would have triggered '#{callback}' from #{events.length} events"
- # And then add an event for it.
- queue_events(resource, [resource.event(:status => "noop", :name => :noop_restart)])
- true # so the 'and if' works
- end
+ # And then add an event for it.
+ queue_events(resource, [resource.event(:status => "noop", :name => :noop_restart)])
+ true # so the 'and if' works
+ end
end
diff --git a/lib/puppet/transaction/report.rb b/lib/puppet/transaction/report.rb
index 021c0200a..e6d1e0528 100644
--- a/lib/puppet/transaction/report.rb
+++ b/lib/puppet/transaction/report.rb
@@ -6,144 +6,144 @@ require 'puppet/indirector'
# change produces, and Metrics are all of the numerical data involved
# in the transaction.
class Puppet::Transaction::Report
- extend Puppet::Indirector
+ extend Puppet::Indirector
- indirects :report, :terminus_class => :processor
+ indirects :report, :terminus_class => :processor
- attr_reader :resource_statuses, :logs, :metrics, :host, :time
+ attr_reader :resource_statuses, :logs, :metrics, :host, :time
- # This is necessary since Marshall doesn't know how to
- # dump hash with default proc (see below @records)
- def self.default_format
- :yaml
- end
-
- def <<(msg)
- @logs << msg
- self
- end
+ # This is necessary since Marshall doesn't know how to
+ # dump hash with default proc (see below @records)
+ def self.default_format
+ :yaml
+ end
- def add_times(name, value)
- @external_times[name] = value
- end
+ def <<(msg)
+ @logs << msg
+ self
+ end
- def add_metric(name, hash)
- metric = Puppet::Util::Metric.new(name)
+ def add_times(name, value)
+ @external_times[name] = value
+ end
- hash.each do |name, value|
- metric.newvalue(name, value)
- end
+ def add_metric(name, hash)
+ metric = Puppet::Util::Metric.new(name)
- @metrics[metric.name] = metric
- metric
+ hash.each do |name, value|
+ metric.newvalue(name, value)
end
- def add_resource_status(status)
- @resource_statuses[status.resource] = status
+ @metrics[metric.name] = metric
+ metric
+ end
+
+ def add_resource_status(status)
+ @resource_statuses[status.resource] = status
+ end
+
+ def calculate_metrics
+ calculate_resource_metrics
+ calculate_time_metrics
+ calculate_change_metrics
+ calculate_event_metrics
+ end
+
+ def initialize
+ @metrics = {}
+ @logs = []
+ @resource_statuses = {}
+ @external_times ||= {}
+ @host = Puppet[:certname]
+ @time = Time.now
+ end
+
+ def name
+ host
+ end
+
+ # Provide a summary of this report.
+ def summary
+ ret = ""
+
+ @metrics.sort { |a,b| a[1].label <=> b[1].label }.each do |name, metric|
+ ret += "#{metric.label}:\n"
+ metric.values.sort { |a,b|
+ # sort by label
+ if a[0] == :total
+ 1
+ elsif b[0] == :total
+ -1
+ else
+ a[1] <=> b[1]
+ end
+ }.each do |name, label, value|
+ next if value == 0
+ value = "%0.2f" % value if value.is_a?(Float)
+ ret += " %15s %s\n" % [label + ":", value]
+ end
end
-
- def calculate_metrics
- calculate_resource_metrics
- calculate_time_metrics
- calculate_change_metrics
- calculate_event_metrics
+ ret
+ end
+
+ # Based on the contents of this report's metrics, compute a single number
+ # that represents the report. The resulting number is a bitmask where
+ # individual bits represent the presence of different metrics.
+ def exit_status
+ status = 0
+ status |= 2 if @metrics["changes"][:total] > 0
+ status |= 4 if @metrics["resources"][:failed] > 0
+ status
+ end
+
+ private
+
+ def calculate_change_metrics
+ metrics = Hash.new(0)
+ resource_statuses.each do |name, status|
+ metrics[:total] += status.change_count if status.change_count
end
- def initialize
- @metrics = {}
- @logs = []
- @resource_statuses = {}
- @external_times ||= {}
- @host = Puppet[:certname]
- @time = Time.now
- end
+ add_metric(:changes, metrics)
+ end
- def name
- host
+ def calculate_event_metrics
+ metrics = Hash.new(0)
+ resource_statuses.each do |name, status|
+ metrics[:total] += status.events.length
+ status.events.each do |event|
+ metrics[event.status] += 1
+ end
end
- # Provide a summary of this report.
- def summary
- ret = ""
-
- @metrics.sort { |a,b| a[1].label <=> b[1].label }.each do |name, metric|
- ret += "#{metric.label}:\n"
- metric.values.sort { |a,b|
- # sort by label
- if a[0] == :total
- 1
- elsif b[0] == :total
- -1
- else
- a[1] <=> b[1]
- end
- }.each do |name, label, value|
- next if value == 0
- value = "%0.2f" % value if value.is_a?(Float)
- ret += " %15s %s\n" % [label + ":", value]
- end
- end
- ret
- end
+ add_metric(:events, metrics)
+ end
- # Based on the contents of this report's metrics, compute a single number
- # that represents the report. The resulting number is a bitmask where
- # individual bits represent the presence of different metrics.
- def exit_status
- status = 0
- status |= 2 if @metrics["changes"][:total] > 0
- status |= 4 if @metrics["resources"][:failed] > 0
- status
- end
+ def calculate_resource_metrics
+ metrics = Hash.new(0)
+ metrics[:total] = resource_statuses.length
- private
+ resource_statuses.each do |name, status|
- def calculate_change_metrics
- metrics = Hash.new(0)
- resource_statuses.each do |name, status|
- metrics[:total] += status.change_count if status.change_count
- end
-
- add_metric(:changes, metrics)
+ Puppet::Resource::Status::STATES.each do |state|
+ metrics[state] += 1 if status.send(state)
+ end
end
- def calculate_event_metrics
- metrics = Hash.new(0)
- resource_statuses.each do |name, status|
- metrics[:total] += status.events.length
- status.events.each do |event|
- metrics[event.status] += 1
- end
- end
+ add_metric(:resources, metrics)
+ end
- add_metric(:events, metrics)
+ def calculate_time_metrics
+ metrics = Hash.new(0)
+ resource_statuses.each do |name, status|
+ type = Puppet::Resource.new(name).type
+ metrics[type.to_s.downcase] += status.evaluation_time if status.evaluation_time
end
- def calculate_resource_metrics
- metrics = Hash.new(0)
- metrics[:total] = resource_statuses.length
-
- resource_statuses.each do |name, status|
-
- Puppet::Resource::Status::STATES.each do |state|
- metrics[state] += 1 if status.send(state)
- end
- end
-
- add_metric(:resources, metrics)
+ @external_times.each do |name, value|
+ metrics[name.to_s.downcase] = value
end
- def calculate_time_metrics
- metrics = Hash.new(0)
- resource_statuses.each do |name, status|
- type = Puppet::Resource.new(name).type
- metrics[type.to_s.downcase] += status.evaluation_time if status.evaluation_time
- end
-
- @external_times.each do |name, value|
- metrics[name.to_s.downcase] = value
- end
-
- add_metric(:time, metrics)
- end
+ add_metric(:time, metrics)
+ end
end
diff --git a/lib/puppet/transaction/resource_harness.rb b/lib/puppet/transaction/resource_harness.rb
index 5f90df5b9..aace6a38a 100644
--- a/lib/puppet/transaction/resource_harness.rb
+++ b/lib/puppet/transaction/resource_harness.rb
@@ -1,150 +1,150 @@
require 'puppet/resource/status'
class Puppet::Transaction::ResourceHarness
- extend Forwardable
- def_delegators :@transaction, :relationship_graph
+ extend Forwardable
+ def_delegators :@transaction, :relationship_graph
- attr_reader :transaction
+ attr_reader :transaction
- def allow_changes?(resource)
- return true unless resource.purging? and resource.deleting?
- return true unless deps = relationship_graph.dependents(resource) and ! deps.empty? and deps.detect { |d| ! d.deleting? }
+ def allow_changes?(resource)
+ return true unless resource.purging? and resource.deleting?
+ return true unless deps = relationship_graph.dependents(resource) and ! deps.empty? and deps.detect { |d| ! d.deleting? }
- deplabel = deps.collect { |r| r.ref }.join(",")
- plurality = deps.length > 1 ? "":"s"
- resource.warning "#{deplabel} still depend#{plurality} on me -- not purging"
- false
- end
-
- def apply_changes(status, changes)
- changes.each do |change|
- status << change.apply
+ deplabel = deps.collect { |r| r.ref }.join(",")
+ plurality = deps.length > 1 ? "":"s"
+ resource.warning "#{deplabel} still depend#{plurality} on me -- not purging"
+ false
+ end
- cache(change.property.resource, change.property.name, change.is) if change.auditing?
- end
- status.changed = true
- end
+ def apply_changes(status, changes)
+ changes.each do |change|
+ status << change.apply
- # Used mostly for scheduling at this point.
- def cached(resource, name)
- Puppet::Util::Storage.cache(resource)[name]
+ cache(change.property.resource, change.property.name, change.is) if change.auditing?
end
+ status.changed = true
+ end
- # Used mostly for scheduling at this point.
- def cache(resource, name, value)
- Puppet::Util::Storage.cache(resource)[name] = value
- end
+ # Used mostly for scheduling at this point.
+ def cached(resource, name)
+ Puppet::Util::Storage.cache(resource)[name]
+ end
- def changes_to_perform(status, resource)
- current = resource.retrieve_resource
+ # Used mostly for scheduling at this point.
+ def cache(resource, name, value)
+ Puppet::Util::Storage.cache(resource)[name] = value
+ end
- cache resource, :checked, Time.now
+ def changes_to_perform(status, resource)
+ current = resource.retrieve_resource
- return [] if ! allow_changes?(resource)
+ cache resource, :checked, Time.now
- audited = copy_audited_parameters(resource, current)
+ return [] if ! allow_changes?(resource)
- if param = resource.parameter(:ensure)
- return [] if absent_and_not_being_created?(current, param)
- return [Puppet::Transaction::Change.new(param, current[:ensure])] unless ensure_is_insync?(current, param)
- return [] if ensure_should_be_absent?(current, param)
- end
+ audited = copy_audited_parameters(resource, current)
- resource.properties.reject { |p| p.name == :ensure }.reject do |param|
- param.should.nil?
- end.reject do |param|
- param_is_insync?(current, param)
- end.collect do |param|
- change = Puppet::Transaction::Change.new(param, current[param.name])
- change.auditing = true if audited.include?(param.name)
- change
- end
+ if param = resource.parameter(:ensure)
+ return [] if absent_and_not_being_created?(current, param)
+ return [Puppet::Transaction::Change.new(param, current[:ensure])] unless ensure_is_insync?(current, param)
+ return [] if ensure_should_be_absent?(current, param)
end
- def copy_audited_parameters(resource, current)
- return [] unless audit = resource[:audit]
- audit = Array(audit).collect { |p| p.to_sym }
- audited = []
- audit.find_all do |param|
- next if resource[param]
-
- if value = cached(resource, param)
- resource[param] = value
- audited << param
- else
- resource.info "Storing newly-audited value #{current[param]} for #{param}"
- cache(resource, param, current[param])
- end
- end
-
- audited
+ resource.properties.reject { |p| p.name == :ensure }.reject do |param|
+ param.should.nil?
+ end.reject do |param|
+ param_is_insync?(current, param)
+ end.collect do |param|
+ change = Puppet::Transaction::Change.new(param, current[param.name])
+ change.auditing = true if audited.include?(param.name)
+ change
end
-
- def evaluate(resource)
- start = Time.now
- status = Puppet::Resource::Status.new(resource)
-
- if changes = changes_to_perform(status, resource) and ! changes.empty?
- status.out_of_sync = true
- status.change_count = changes.length
- apply_changes(status, changes)
- if ! resource.noop?
- cache(resource, :synced, Time.now)
- resource.flush if resource.respond_to?(:flush)
- end
- end
- return status
- rescue => detail
- resource.fail "Could not create resource status: #{detail}" unless status
- puts detail.backtrace if Puppet[:trace]
- resource.err "Could not evaluate: #{detail}"
- status.failed = true
- return status
- ensure
- (status.evaluation_time = Time.now - start) if status
+ end
+
+ def copy_audited_parameters(resource, current)
+ return [] unless audit = resource[:audit]
+ audit = Array(audit).collect { |p| p.to_sym }
+ audited = []
+ audit.find_all do |param|
+ next if resource[param]
+
+ if value = cached(resource, param)
+ resource[param] = value
+ audited << param
+ else
+ resource.info "Storing newly-audited value #{current[param]} for #{param}"
+ cache(resource, param, current[param])
+ end
end
- def initialize(transaction)
- @transaction = transaction
+ audited
+ end
+
+ def evaluate(resource)
+ start = Time.now
+ status = Puppet::Resource::Status.new(resource)
+
+ if changes = changes_to_perform(status, resource) and ! changes.empty?
+ status.out_of_sync = true
+ status.change_count = changes.length
+ apply_changes(status, changes)
+ if ! resource.noop?
+ cache(resource, :synced, Time.now)
+ resource.flush if resource.respond_to?(:flush)
+ end
end
-
- def scheduled?(status, resource)
- return true if Puppet[:ignoreschedules]
- return true unless schedule = schedule(resource)
-
- # We use 'checked' here instead of 'synced' because otherwise we'll
- # end up checking most resources most times, because they will generally
- # have been synced a long time ago (e.g., a file only gets updated
- # once a month on the server and its schedule is daily; the last sync time
- # will have been a month ago, so we'd end up checking every run).
- schedule.match?(cached(resource, :checked).to_i)
+ return status
+ rescue => detail
+ resource.fail "Could not create resource status: #{detail}" unless status
+ puts detail.backtrace if Puppet[:trace]
+ resource.err "Could not evaluate: #{detail}"
+ status.failed = true
+ return status
+ ensure
+ (status.evaluation_time = Time.now - start) if status
+ end
+
+ def initialize(transaction)
+ @transaction = transaction
+ end
+
+ def scheduled?(status, resource)
+ return true if Puppet[:ignoreschedules]
+ return true unless schedule = schedule(resource)
+
+ # We use 'checked' here instead of 'synced' because otherwise we'll
+ # end up checking most resources most times, because they will generally
+ # have been synced a long time ago (e.g., a file only gets updated
+ # once a month on the server and its schedule is daily; the last sync time
+ # will have been a month ago, so we'd end up checking every run).
+ schedule.match?(cached(resource, :checked).to_i)
+ end
+
+ def schedule(resource)
+ unless resource.catalog
+ resource.warning "Cannot schedule without a schedule-containing catalog"
+ return nil
end
- def schedule(resource)
- unless resource.catalog
- resource.warning "Cannot schedule without a schedule-containing catalog"
- return nil
- end
+ return nil unless name = resource[:schedule]
+ resource.catalog.resource(:schedule, name) || resource.fail("Could not find schedule #{name}")
+ end
- return nil unless name = resource[:schedule]
- resource.catalog.resource(:schedule, name) || resource.fail("Could not find schedule #{name}")
- end
-
- private
+ private
- def absent_and_not_being_created?(current, param)
- current[:ensure] == :absent and param.should.nil?
- end
+ def absent_and_not_being_created?(current, param)
+ current[:ensure] == :absent and param.should.nil?
+ end
- def ensure_is_insync?(current, param)
- param.insync?(current[:ensure])
- end
+ def ensure_is_insync?(current, param)
+ param.insync?(current[:ensure])
+ end
- def ensure_should_be_absent?(current, param)
- param.should == :absent
- end
+ def ensure_should_be_absent?(current, param)
+ param.should == :absent
+ end
- def param_is_insync?(current, param)
- param.insync?(current[param.name])
- end
+ def param_is_insync?(current, param)
+ param.insync?(current[param.name])
+ end
end
diff --git a/lib/puppet/transportable.rb b/lib/puppet/transportable.rb
index 74c1bbf6a..f7b839c14 100644
--- a/lib/puppet/transportable.rb
+++ b/lib/puppet/transportable.rb
@@ -2,247 +2,247 @@ require 'puppet'
require 'yaml'
module Puppet
- # The transportable objects themselves. Basically just a hash with some
- # metadata and a few extra methods. I used to have the object actually
- # be a subclass of Hash, but I could never correctly dump them using
- # YAML.
- class TransObject
- include Enumerable
- attr_accessor :type, :name, :file, :line, :catalog
-
- attr_writer :tags
-
- %w{has_key? include? length delete empty? << [] []=}.each { |method|
- define_method(method) do |*args|
- @params.send(method, *args)
- end
- }
-
- def each
- @params.each { |p,v| yield p, v }
- end
-
- def initialize(name,type)
- @type = type.to_s.downcase
- @name = name
- @params = {}
- @tags = []
- end
-
- def longname
- [@type,@name].join('--')
- end
+ # The transportable objects themselves. Basically just a hash with some
+ # metadata and a few extra methods. I used to have the object actually
+ # be a subclass of Hash, but I could never correctly dump them using
+ # YAML.
+ class TransObject
+ include Enumerable
+ attr_accessor :type, :name, :file, :line, :catalog
+
+ attr_writer :tags
+
+ %w{has_key? include? length delete empty? << [] []=}.each { |method|
+ define_method(method) do |*args|
+ @params.send(method, *args)
+ end
+ }
+
+ def each
+ @params.each { |p,v| yield p, v }
+ end
- def ref
- @ref ||= Puppet::Resource.new(@type, @name)
- @ref.to_s
- end
+ def initialize(name,type)
+ @type = type.to_s.downcase
+ @name = name
+ @params = {}
+ @tags = []
+ end
- def tags
- @tags
- end
+ def longname
+ [@type,@name].join('--')
+ end
- # Convert a defined type into a component.
- def to_component
- trans = TransObject.new(ref, :component)
- @params.each { |param,value|
- next unless Puppet::Type::Component.valid_parameter?(param)
- Puppet.debug "Defining #{param} on #{ref}"
- trans[param] = value
- }
- trans.catalog = self.catalog
- Puppet::Type::Component.create(trans)
- end
+ def ref
+ @ref ||= Puppet::Resource.new(@type, @name)
+ @ref.to_s
+ end
- def to_hash
- @params.dup
- end
+ def tags
+ @tags
+ end
- def to_s
- "#{@type}(#{@name}) => #{super}"
- end
+ # Convert a defined type into a component.
+ def to_component
+ trans = TransObject.new(ref, :component)
+ @params.each { |param,value|
+ next unless Puppet::Type::Component.valid_parameter?(param)
+ Puppet.debug "Defining #{param} on #{ref}"
+ trans[param] = value
+ }
+ trans.catalog = self.catalog
+ Puppet::Type::Component.create(trans)
+ end
- def to_manifest
- "%s { '%s':\n%s\n}" % [self.type.to_s, self.name,
- @params.collect { |p, v|
- if v.is_a? Array
- " #{p} => [\'#{v.join("','")}\']"
- else
- " #{p} => \'#{v}\'"
- end
- }.join(",\n")
- ]
- end
+ def to_hash
+ @params.dup
+ end
- # Create a normalized resource from our TransObject.
- def to_resource
- result = Puppet::Resource.new(type, name, :parameters => @params.dup)
- result.tag(*tags)
+ def to_s
+ "#{@type}(#{@name}) => #{super}"
+ end
- result
- end
+ def to_manifest
+ "%s { '%s':\n%s\n}" % [self.type.to_s, self.name,
+ @params.collect { |p, v|
+ if v.is_a? Array
+ " #{p} => [\'#{v.join("','")}\']"
+ else
+ " #{p} => \'#{v}\'"
+ end
+ }.join(",\n")
+ ]
+ end
- def to_yaml_properties
- instance_variables.reject { |v| %w{@ref}.include?(v) }
- end
+ # Create a normalized resource from our TransObject.
+ def to_resource
+ result = Puppet::Resource.new(type, name, :parameters => @params.dup)
+ result.tag(*tags)
- def to_ref
- ref
- end
+ result
+ end
- def to_ral
- to_resource.to_ral
- end
+ def to_yaml_properties
+ instance_variables.reject { |v| %w{@ref}.include?(v) }
end
- # Just a linear container for objects. Behaves mostly like an array, except
- # that YAML will correctly dump them even with their instance variables.
- class TransBucket
- include Enumerable
-
- attr_accessor :name, :type, :file, :line, :classes, :keyword, :top, :catalog
-
- %w{delete shift include? length empty? << []}.each { |method|
- define_method(method) do |*args|
- #Puppet.warning "Calling #{method} with #{args.inspect}"
- @children.send(method, *args)
- #Puppet.warning @params.inspect
- end
- }
-
- # Recursively yield everything.
- def delve(&block)
- @children.each do |obj|
- block.call(obj)
- if obj.is_a? self.class
- obj.delve(&block)
- else
- obj
- end
- end
- end
+ def to_ref
+ ref
+ end
- def each
- @children.each { |c| yield c }
- end
+ def to_ral
+ to_resource.to_ral
+ end
+ end
+
+ # Just a linear container for objects. Behaves mostly like an array, except
+ # that YAML will correctly dump them even with their instance variables.
+ class TransBucket
+ include Enumerable
+
+ attr_accessor :name, :type, :file, :line, :classes, :keyword, :top, :catalog
+
+ %w{delete shift include? length empty? << []}.each { |method|
+ define_method(method) do |*args|
+ #Puppet.warning "Calling #{method} with #{args.inspect}"
+ @children.send(method, *args)
+ #Puppet.warning @params.inspect
+ end
+ }
+
+ # Recursively yield everything.
+ def delve(&block)
+ @children.each do |obj|
+ block.call(obj)
+ if obj.is_a? self.class
+ obj.delve(&block)
+ else
+ obj
+ end
+ end
+ end
- # Turn our heirarchy into a flat list
- def flatten
- @children.collect do |obj|
- if obj.is_a? Puppet::TransBucket
- obj.flatten
- else
- obj
- end
- end.flatten
- end
+ def each
+ @children.each { |c| yield c }
+ end
- def initialize(children = [])
- @children = children
+ # Turn our heirarchy into a flat list
+ def flatten
+ @children.collect do |obj|
+ if obj.is_a? Puppet::TransBucket
+ obj.flatten
+ else
+ obj
end
+ end.flatten
+ end
- def push(*args)
- args.each { |arg|
- case arg
- when Puppet::TransBucket, Puppet::TransObject
- # nada
- else
- raise Puppet::DevError,
- "TransBuckets cannot handle objects of type #{arg.class}"
- end
- }
- @children += args
- end
+ def initialize(children = [])
+ @children = children
+ end
- # Convert to a parseable manifest
- def to_manifest
- unless self.top
- raise Puppet::DevError, "No keyword; cannot convert to manifest" unless @keyword
- end
-
- str = "#{@keyword} #{@name} {\n%s\n}"
- str % @children.collect { |child|
- child.to_manifest
- }.collect { |str|
- if self.top
- str
- else
- str.gsub(/^/, " ") # indent everything once
- end
- }.join("\n\n") # and throw in a blank line
- end
+ def push(*args)
+ args.each { |arg|
+ case arg
+ when Puppet::TransBucket, Puppet::TransObject
+ # nada
+ else
+ raise Puppet::DevError,
+ "TransBuckets cannot handle objects of type #{arg.class}"
+ end
+ }
+ @children += args
+ end
- def to_yaml_properties
- instance_variables
- end
+ # Convert to a parseable manifest
+ def to_manifest
+ unless self.top
+ raise Puppet::DevError, "No keyword; cannot convert to manifest" unless @keyword
+ end
+
+ str = "#{@keyword} #{@name} {\n%s\n}"
+ str % @children.collect { |child|
+ child.to_manifest
+ }.collect { |str|
+ if self.top
+ str
+ else
+ str.gsub(/^/, " ") # indent everything once
+ end
+ }.join("\n\n") # and throw in a blank line
+ end
- # Create a resource graph from our structure.
- def to_catalog(clear_on_failure = true)
- catalog = Puppet::Resource::Catalog.new(Facter.value("hostname"))
-
- # This should really use the 'delve' method, but this
- # whole class is going away relatively soon, hopefully,
- # so it's not worth it.
- delver = proc do |obj|
- obj.catalog = catalog
- unless container = catalog.resource(obj.to_ref)
- container = obj.to_ral
- catalog.add_resource container
- end
- obj.each do |child|
- child.catalog = catalog
- unless resource = catalog.resource(child.to_ref)
- resource = child.to_ral
- catalog.add_resource resource
- end
-
- catalog.add_edge(container, resource)
- delver.call(child) if child.is_a?(self.class)
- end
- end
-
- begin
- delver.call(self)
- catalog.finalize
- rescue => detail
- # This is important until we lose the global resource references.
- catalog.clear if (clear_on_failure)
- raise
- end
-
- catalog
- end
+ def to_yaml_properties
+ instance_variables
+ end
- def to_ref
- unless defined?(@ref)
- if self.type and self.name
- @ref = Puppet::Resource.new(self.type, self.name)
- elsif self.type and ! self.name # This is old-school node types
- @ref = Puppet::Resource.new("node", self.type)
- elsif ! self.type and self.name
- @ref = Puppet::Resource.new("component", self.name)
- else
- @ref = nil
- end
- end
- @ref.to_s if @ref
- end
+ # Create a resource graph from our structure.
+ def to_catalog(clear_on_failure = true)
+ catalog = Puppet::Resource::Catalog.new(Facter.value("hostname"))
+
+ # This should really use the 'delve' method, but this
+ # whole class is going away relatively soon, hopefully,
+ # so it's not worth it.
+ delver = proc do |obj|
+ obj.catalog = catalog
+ unless container = catalog.resource(obj.to_ref)
+ container = obj.to_ral
+ catalog.add_resource container
+ end
+ obj.each do |child|
+ child.catalog = catalog
+ unless resource = catalog.resource(child.to_ref)
+ resource = child.to_ral
+ catalog.add_resource resource
+ end
+
+ catalog.add_edge(container, resource)
+ delver.call(child) if child.is_a?(self.class)
+ end
+ end
+
+ begin
+ delver.call(self)
+ catalog.finalize
+ rescue => detail
+ # This is important until we lose the global resource references.
+ catalog.clear if (clear_on_failure)
+ raise
+ end
+
+ catalog
+ end
- def to_ral
- to_resource.to_ral
- end
+ def to_ref
+ unless defined?(@ref)
+ if self.type and self.name
+ @ref = Puppet::Resource.new(self.type, self.name)
+ elsif self.type and ! self.name # This is old-school node types
+ @ref = Puppet::Resource.new("node", self.type)
+ elsif ! self.type and self.name
+ @ref = Puppet::Resource.new("component", self.name)
+ else
+ @ref = nil
+ end
+ end
+ @ref.to_s if @ref
+ end
- # Create a normalized resource from our TransObject.
- def to_resource
- params = defined?(@parameters) ? @parameters.dup : {}
- Puppet::Resource.new(type, name, :parameters => params)
- end
+ def to_ral
+ to_resource.to_ral
+ end
- def param(param,value)
- @parameters ||= {}
- @parameters[param] = value
- end
+ # Create a normalized resource from our TransObject.
+ def to_resource
+ params = defined?(@parameters) ? @parameters.dup : {}
+ Puppet::Resource.new(type, name, :parameters => params)
+ end
+ def param(param,value)
+ @parameters ||= {}
+ @parameters[param] = value
end
+
+ end
end
diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb
index 1e0bde5e7..d0fea9731 100644
--- a/lib/puppet/type.rb
+++ b/lib/puppet/type.rb
@@ -17,1868 +17,1868 @@ require 'puppet/util/tagging'
module Puppet
class Type
- include Puppet::Util
- include Puppet::Util::Errors
- include Puppet::Util::LogPaths
- include Puppet::Util::Logging
- include Puppet::Util::Cacher
- include Puppet::FileCollection::Lookup
- include Puppet::Util::Tagging
-
- ###############################
- # Code related to resource type attributes.
- class << self
- include Puppet::Util::ClassGen
- include Puppet::Util::Warnings
- attr_reader :properties
- end
-
- def self.states
- warnonce "The states method is deprecated; use properties"
- properties
- end
-
- # All parameters, in the appropriate order. The key_attributes come first, then
- # the provider, then the properties, and finally the params and metaparams
- # in the order they were specified in the files.
- def self.allattrs
- key_attributes | (parameters & [:provider]) | properties.collect { |property| property.name } | parameters | metaparams
- end
-
- # Retrieve an attribute alias, if there is one.
- def self.attr_alias(param)
- @attr_aliases[symbolize(param)]
- end
-
- # Create an alias to an existing attribute. This will cause the aliased
- # attribute to be valid when setting and retrieving values on the instance.
- def self.set_attr_alias(hash)
- hash.each do |new, old|
- @attr_aliases[symbolize(new)] = symbolize(old)
- end
- end
-
- # Find the class associated with any given attribute.
- def self.attrclass(name)
- @attrclasses ||= {}
-
- # We cache the value, since this method gets called such a huge number
- # of times (as in, hundreds of thousands in a given run).
- unless @attrclasses.include?(name)
- @attrclasses[name] = case self.attrtype(name)
- when :property; @validproperties[name]
- when :meta; @@metaparamhash[name]
- when :param; @paramhash[name]
- end
- end
- @attrclasses[name]
- end
-
- # What type of parameter are we dealing with? Cache the results, because
- # this method gets called so many times.
- def self.attrtype(attr)
- @attrtypes ||= {}
- unless @attrtypes.include?(attr)
- @attrtypes[attr] = case
- when @validproperties.include?(attr); :property
- when @paramhash.include?(attr); :param
- when @@metaparamhash.include?(attr); :meta
- end
- end
-
- @attrtypes[attr]
- end
-
- def self.eachmetaparam
- @@metaparams.each { |p| yield p.name }
- end
+ include Puppet::Util
+ include Puppet::Util::Errors
+ include Puppet::Util::LogPaths
+ include Puppet::Util::Logging
+ include Puppet::Util::Cacher
+ include Puppet::FileCollection::Lookup
+ include Puppet::Util::Tagging
+
+ ###############################
+ # Code related to resource type attributes.
+ class << self
+ include Puppet::Util::ClassGen
+ include Puppet::Util::Warnings
+ attr_reader :properties
+ end
+
+ def self.states
+ warnonce "The states method is deprecated; use properties"
+ properties
+ end
+
+ # All parameters, in the appropriate order. The key_attributes come first, then
+ # the provider, then the properties, and finally the params and metaparams
+ # in the order they were specified in the files.
+ def self.allattrs
+ key_attributes | (parameters & [:provider]) | properties.collect { |property| property.name } | parameters | metaparams
+ end
+
+ # Retrieve an attribute alias, if there is one.
+ def self.attr_alias(param)
+ @attr_aliases[symbolize(param)]
+ end
+
+ # Create an alias to an existing attribute. This will cause the aliased
+ # attribute to be valid when setting and retrieving values on the instance.
+ def self.set_attr_alias(hash)
+ hash.each do |new, old|
+ @attr_aliases[symbolize(new)] = symbolize(old)
+ end
+ end
+
+ # Find the class associated with any given attribute.
+ def self.attrclass(name)
+ @attrclasses ||= {}
+
+ # We cache the value, since this method gets called such a huge number
+ # of times (as in, hundreds of thousands in a given run).
+ unless @attrclasses.include?(name)
+ @attrclasses[name] = case self.attrtype(name)
+ when :property; @validproperties[name]
+ when :meta; @@metaparamhash[name]
+ when :param; @paramhash[name]
+ end
+ end
+ @attrclasses[name]
+ end
+
+ # What type of parameter are we dealing with? Cache the results, because
+ # this method gets called so many times.
+ def self.attrtype(attr)
+ @attrtypes ||= {}
+ unless @attrtypes.include?(attr)
+ @attrtypes[attr] = case
+ when @validproperties.include?(attr); :property
+ when @paramhash.include?(attr); :param
+ when @@metaparamhash.include?(attr); :meta
+ end
+ end
+
+ @attrtypes[attr]
+ end
+
+ def self.eachmetaparam
+ @@metaparams.each { |p| yield p.name }
+ end
+
+ # Create the 'ensure' class. This is a separate method so other types
+ # can easily call it and create their own 'ensure' values.
+ def self.ensurable(&block)
+ if block_given?
+ self.newproperty(:ensure, :parent => Puppet::Property::Ensure, &block)
+ else
+ self.newproperty(:ensure, :parent => Puppet::Property::Ensure) do
+ self.defaultvalues
+ end
+ end
+ end
+
+ # Should we add the 'ensure' property to this class?
+ def self.ensurable?
+ # If the class has all three of these methods defined, then it's
+ # ensurable.
+ ens = [:exists?, :create, :destroy].inject { |set, method|
+ set &&= self.public_method_defined?(method)
+ }
+
+ ens
+ end
+
+ # Deal with any options passed into parameters.
+ def self.handle_param_options(name, options)
+ # If it's a boolean parameter, create a method to test the value easily
+ if options[:boolean]
+ define_method(name.to_s + "?") do
+ val = self[name]
+ if val == :true or val == true
+ return true
+ end
+ end
+ end
+ end
+
+ # Is the parameter in question a meta-parameter?
+ def self.metaparam?(param)
+ @@metaparamhash.include?(symbolize(param))
+ end
+
+ # Find the metaparameter class associated with a given metaparameter name.
+ def self.metaparamclass(name)
+ @@metaparamhash[symbolize(name)]
+ end
+
+ def self.metaparams
+ @@metaparams.collect { |param| param.name }
+ end
+
+ def self.metaparamdoc(metaparam)
+ @@metaparamhash[metaparam].doc
+ end
+
+ # Create a new metaparam. Requires a block and a name, stores it in the
+ # @parameters array, and does some basic checking on it.
+ def self.newmetaparam(name, options = {}, &block)
+ @@metaparams ||= []
+ @@metaparamhash ||= {}
+ name = symbolize(name)
+
+
+ param = genclass(
+ name,
+ :parent => options[:parent] || Puppet::Parameter,
+ :prefix => "MetaParam",
+ :hash => @@metaparamhash,
+ :array => @@metaparams,
+ :attributes => options[:attributes],
+
+ &block
+ )
+
+ # Grr.
+ param.required_features = options[:required_features] if options[:required_features]
+
+ handle_param_options(name, options)
+
+ param.metaparam = true
+
+ param
+ end
+
+ def self.key_attribute_parameters
+ @key_attribute_parameters ||= (
+ params = @parameters.find_all { |param|
+ param.isnamevar? or param.name == :name
+ }
+ )
+ end
- # Create the 'ensure' class. This is a separate method so other types
- # can easily call it and create their own 'ensure' values.
- def self.ensurable(&block)
- if block_given?
- self.newproperty(:ensure, :parent => Puppet::Property::Ensure, &block)
- else
- self.newproperty(:ensure, :parent => Puppet::Property::Ensure) do
- self.defaultvalues
- end
- end
- end
+ def self.key_attributes
+ key_attribute_parameters.collect { |p| p.name }
+ end
+
+ def self.title_patterns
+ case key_attributes.length
+ when 0; []
+ when 1;
+ identity = lambda {|x| x}
+ [ [ /(.*)/, [ [key_attributes.first, identity ] ] ] ]
+ else
+ raise Puppet::DevError,"you must specify title patterns when there are two or more key attributes"
+ end
+ end
+
+ def uniqueness_key
+ to_resource.uniqueness_key
+ end
+
+ # Create a new parameter. Requires a block and a name, stores it in the
+ # @parameters array, and does some basic checking on it.
+ def self.newparam(name, options = {}, &block)
+ options[:attributes] ||= {}
+
+ param = genclass(
+ name,
+ :parent => options[:parent] || Puppet::Parameter,
+ :attributes => options[:attributes],
+ :block => block,
+ :prefix => "Parameter",
+ :array => @parameters,
- # Should we add the 'ensure' property to this class?
- def self.ensurable?
- # If the class has all three of these methods defined, then it's
- # ensurable.
- ens = [:exists?, :create, :destroy].inject { |set, method|
- set &&= self.public_method_defined?(method)
- }
+ :hash => @paramhash
+ )
+
+ handle_param_options(name, options)
- ens
- end
+ # Grr.
+ param.required_features = options[:required_features] if options[:required_features]
- # Deal with any options passed into parameters.
- def self.handle_param_options(name, options)
- # If it's a boolean parameter, create a method to test the value easily
- if options[:boolean]
- define_method(name.to_s + "?") do
- val = self[name]
- if val == :true or val == true
- return true
- end
- end
- end
- end
+ param.isnamevar if options[:namevar]
- # Is the parameter in question a meta-parameter?
- def self.metaparam?(param)
- @@metaparamhash.include?(symbolize(param))
- end
+ param
+ end
- # Find the metaparameter class associated with a given metaparameter name.
- def self.metaparamclass(name)
- @@metaparamhash[symbolize(name)]
- end
+ def self.newstate(name, options = {}, &block)
+ Puppet.warning "newstate() has been deprecrated; use newproperty(#{name})"
+ newproperty(name, options, &block)
+ end
- def self.metaparams
- @@metaparams.collect { |param| param.name }
- end
+ # Create a new property. The first parameter must be the name of the property;
+ # this is how users will refer to the property when creating new instances.
+ # The second parameter is a hash of options; the options are:
+ # * <tt>:parent</tt>: The parent class for the property. Defaults to Puppet::Property.
+ # * <tt>:retrieve</tt>: The method to call on the provider or @parent object (if
+ # the provider is not set) to retrieve the current value.
+ def self.newproperty(name, options = {}, &block)
+ name = symbolize(name)
+
+ # This is here for types that might still have the old method of defining
+ # a parent class.
+ unless options.is_a? Hash
+ raise Puppet::DevError,
+ "Options must be a hash, not #{options.inspect}"
+ end
+
+ raise Puppet::DevError, "Class #{self.name} already has a property named #{name}" if @validproperties.include?(name)
+
+ if parent = options[:parent]
+ options.delete(:parent)
+ else
+ parent = Puppet::Property
+ end
+
+ # We have to create our own, new block here because we want to define
+ # an initial :retrieve method, if told to, and then eval the passed
+ # block if available.
+ prop = genclass(name, :parent => parent, :hash => @validproperties, :attributes => options) do
+ # If they've passed a retrieve method, then override the retrieve
+ # method on the class.
+ if options[:retrieve]
+ define_method(:retrieve) do
+ provider.send(options[:retrieve])
+ end
+ end
+
+ class_eval(&block) if block
+ end
+
+ # If it's the 'ensure' property, always put it first.
+ if name == :ensure
+ @properties.unshift prop
+ else
+ @properties << prop
+ end
+
+ prop
+ end
+
+ def self.paramdoc(param)
+ @paramhash[param].doc
+ end
+
+ # Return the parameter names
+ def self.parameters
+ return [] unless defined?(@parameters)
+ @parameters.collect { |klass| klass.name }
+ end
+
+ # Find the parameter class associated with a given parameter name.
+ def self.paramclass(name)
+ @paramhash[name]
+ end
+
+ # Return the property class associated with a name
+ def self.propertybyname(name)
+ @validproperties[name]
+ end
+
+ def self.validattr?(name)
+ name = symbolize(name)
+ return true if name == :name
+ @validattrs ||= {}
- def self.metaparamdoc(metaparam)
- @@metaparamhash[metaparam].doc
+ unless @validattrs.include?(name)
+ @validattrs[name] = !!(self.validproperty?(name) or self.validparameter?(name) or self.metaparam?(name))
end
- # Create a new metaparam. Requires a block and a name, stores it in the
- # @parameters array, and does some basic checking on it.
- def self.newmetaparam(name, options = {}, &block)
- @@metaparams ||= []
- @@metaparamhash ||= {}
- name = symbolize(name)
-
+ @validattrs[name]
+ end
- param = genclass(
- name,
- :parent => options[:parent] || Puppet::Parameter,
- :prefix => "MetaParam",
- :hash => @@metaparamhash,
- :array => @@metaparams,
- :attributes => options[:attributes],
+ # does the name reflect a valid property?
+ def self.validproperty?(name)
+ name = symbolize(name)
+ @validproperties.include?(name) && @validproperties[name]
+ end
- &block
- )
-
- # Grr.
- param.required_features = options[:required_features] if options[:required_features]
-
- handle_param_options(name, options)
-
- param.metaparam = true
-
- param
- end
-
- def self.key_attribute_parameters
- @key_attribute_parameters ||= (
- params = @parameters.find_all { |param|
- param.isnamevar? or param.name == :name
- }
- )
- end
-
- def self.key_attributes
- key_attribute_parameters.collect { |p| p.name }
- end
-
- def self.title_patterns
- case key_attributes.length
- when 0; []
- when 1;
- identity = lambda {|x| x}
- [ [ /(.*)/, [ [key_attributes.first, identity ] ] ] ]
+ # Return the list of validproperties
+ def self.validproperties
+ return {} unless defined?(@parameters)
+
+ @validproperties.keys
+ end
+
+ # does the name reflect a valid parameter?
+ def self.validparameter?(name)
+ raise Puppet::DevError, "Class #{self} has not defined parameters" unless defined?(@parameters)
+ !!(@paramhash.include?(name) or @@metaparamhash.include?(name))
+ end
+
+ # This is a forward-compatibility method - it's the validity interface we'll use in Puppet::Resource.
+ def self.valid_parameter?(name)
+ validattr?(name)
+ end
+
+ # Return either the attribute alias or the attribute.
+ def attr_alias(name)
+ name = symbolize(name)
+ if synonym = self.class.attr_alias(name)
+ return synonym
+ else
+ return name
+ end
+ end
+
+ # Are we deleting this resource?
+ def deleting?
+ obj = @parameters[:ensure] and obj.should == :absent
+ end
+
+ # Create a new property if it is valid but doesn't exist
+ # Returns: true if a new parameter was added, false otherwise
+ def add_property_parameter(prop_name)
+ if self.class.validproperty?(prop_name) && !@parameters[prop_name]
+ self.newattr(prop_name)
+ return true
+ end
+ false
+ end
+
+ #
+ # The name_var is the key_attribute in the case that there is only one.
+ #
+ def name_var
+ key_attributes = self.class.key_attributes
+ (key_attributes.length == 1) && key_attributes.first
+ end
+
+ # abstract accessing parameters and properties, and normalize
+ # access to always be symbols, not strings
+ # This returns a value, not an object. It returns the 'is'
+ # value, but you can also specifically return 'is' and 'should'
+ # values using 'object.is(:property)' or 'object.should(:property)'.
+ def [](name)
+ name = attr_alias(name)
+
+ fail("Invalid parameter #{name}(#{name.inspect})") unless self.class.validattr?(name)
+
+ if name == :name
+ name = name_var
+ end
+
+ if obj = @parameters[name]
+ # Note that if this is a property, then the value is the "should" value,
+ # not the current value.
+ obj.value
+ else
+ return nil
+ end
+ end
+
+ # Abstract setting parameters and properties, and normalize
+ # access to always be symbols, not strings. This sets the 'should'
+ # value on properties, and otherwise just sets the appropriate parameter.
+ def []=(name,value)
+ name = attr_alias(name)
+
+ fail("Invalid parameter #{name}") unless self.class.validattr?(name)
+
+ if name == :name
+ name = name_var
+ end
+ raise Puppet::Error.new("Got nil value for #{name}") if value.nil?
+
+ property = self.newattr(name)
+
+ begin
+ # make sure the parameter doesn't have any errors
+ property.value = value
+ rescue => detail
+ error = Puppet::Error.new("Parameter #{name} failed: #{detail}")
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
+
+ nil
+ end
+
+ # remove a property from the object; useful in testing or in cleanup
+ # when an error has been encountered
+ def delete(attr)
+ attr = symbolize(attr)
+ if @parameters.has_key?(attr)
+ @parameters.delete(attr)
+ else
+ raise Puppet::DevError.new("Undefined attribute '#{attr}' in #{self}")
+ end
+ end
+
+ # iterate across the existing properties
+ def eachproperty
+ # properties is a private method
+ properties.each { |property|
+ yield property
+ }
+ end
+
+ # Create a transaction event. Called by Transaction or by
+ # a property.
+ def event(options = {})
+ Puppet::Transaction::Event.new({:resource => self, :file => file, :line => line, :tags => tags, :version => version}.merge(options))
+ end
+
+ # Let the catalog determine whether a given cached value is
+ # still valid or has expired.
+ def expirer
+ catalog
+ end
+
+ # retrieve the 'should' value for a specified property
+ def should(name)
+ name = attr_alias(name)
+ (prop = @parameters[name] and prop.is_a?(Puppet::Property)) ? prop.should : nil
+ end
+
+ # Create the actual attribute instance. Requires either the attribute
+ # name or class as the first argument, then an optional hash of
+ # attributes to set during initialization.
+ def newattr(name)
+ if name.is_a?(Class)
+ klass = name
+ name = klass.name
+ end
+
+ unless klass = self.class.attrclass(name)
+ raise Puppet::Error, "Resource type #{self.class.name} does not support parameter #{name}"
+ end
+
+ return @parameters[name] if @parameters.include?(name)
+
+ @parameters[name] = klass.new(:resource => self)
+ end
+
+ # return the value of a parameter
+ def parameter(name)
+ @parameters[name.to_sym]
+ end
+
+ def parameters
+ @parameters.dup
+ end
+
+ # Is the named property defined?
+ def propertydefined?(name)
+ name = name.intern unless name.is_a? Symbol
+ @parameters.include?(name)
+ end
+
+ # Return an actual property instance by name; to return the value, use 'resource[param]'
+ # LAK:NOTE(20081028) Since the 'parameter' method is now a superset of this method,
+ # this one should probably go away at some point.
+ def property(name)
+ (obj = @parameters[symbolize(name)] and obj.is_a?(Puppet::Property)) ? obj : nil
+ end
+
+ # For any parameters or properties that have defaults and have not yet been
+ # set, set them now. This method can be handed a list of attributes,
+ # and if so it will only set defaults for those attributes.
+ def set_default(attr)
+ return unless klass = self.class.attrclass(attr)
+ return unless klass.method_defined?(:default)
+ return if @parameters.include?(klass.name)
+
+ return unless parameter = newattr(klass.name)
+
+ if value = parameter.default and ! value.nil?
+ parameter.value = value
+ else
+ @parameters.delete(parameter.name)
+ end
+ end
+
+ # Convert our object to a hash. This just includes properties.
+ def to_hash
+ rethash = {}
+
+ @parameters.each do |name, obj|
+ rethash[name] = obj.value
+ end
+
+ rethash
+ end
+
+ def type
+ self.class.name
+ end
+
+ # Return a specific value for an attribute.
+ def value(name)
+ name = attr_alias(name)
+
+ (obj = @parameters[name] and obj.respond_to?(:value)) ? obj.value : nil
+ end
+
+ def version
+ return 0 unless catalog
+ catalog.version
+ end
+
+ # Return all of the property objects, in the order specified in the
+ # class.
+ def properties
+ self.class.properties.collect { |prop| @parameters[prop.name] }.compact
+ end
+
+ # Is this type's name isomorphic with the object? That is, if the
+ # name conflicts, does it necessarily mean that the objects conflict?
+ # Defaults to true.
+ def self.isomorphic?
+ if defined?(@isomorphic)
+ return @isomorphic
+ else
+ return true
+ end
+ end
+
+ def isomorphic?
+ self.class.isomorphic?
+ end
+
+ # is the instance a managed instance? A 'yes' here means that
+ # the instance was created from the language, vs. being created
+ # in order resolve other questions, such as finding a package
+ # in a list
+ def managed?
+ # Once an object is managed, it always stays managed; but an object
+ # that is listed as unmanaged might become managed later in the process,
+ # so we have to check that every time
+ if @managed
+ return @managed
+ else
+ @managed = false
+ properties.each { |property|
+ s = property.should
+ if s and ! property.class.unmanaged
+ @managed = true
+ break
+ end
+ }
+ return @managed
+ end
+ end
+
+ ###############################
+ # Code related to the container behaviour.
+
+ # this is a retarded hack method to get around the difference between
+ # component children and file children
+ def self.depthfirst?
+ @depthfirst
+ end
+
+ def depthfirst?
+ self.class.depthfirst?
+ end
+
+ # Remove an object. The argument determines whether the object's
+ # subscriptions get eliminated, too.
+ def remove(rmdeps = true)
+ # This is hackish (mmm, cut and paste), but it works for now, and it's
+ # better than warnings.
+ @parameters.each do |name, obj|
+ obj.remove
+ end
+ @parameters.clear
+
+ @parent = nil
+
+ # Remove the reference to the provider.
+ if self.provider
+ @provider.clear
+ @provider = nil
+ end
+ end
+
+ ###############################
+ # Code related to evaluating the resources.
+
+ # Flush the provider, if it supports it. This is called by the
+ # transaction.
+ def flush
+ self.provider.flush if self.provider and self.provider.respond_to?(:flush)
+ end
+
+ # if all contained objects are in sync, then we're in sync
+ # FIXME I don't think this is used on the type instances any more,
+ # it's really only used for testing
+ def insync?(is)
+ insync = true
+
+ if property = @parameters[:ensure]
+ unless is.include? property
+ raise Puppet::DevError,
+ "The is value is not in the is array for '#{property.name}'"
+ end
+ ensureis = is[property]
+ if property.insync?(ensureis) and property.should == :absent
+ return true
+ end
+ end
+
+ properties.each { |property|
+ unless is.include? property
+ raise Puppet::DevError,
+ "The is value is not in the is array for '#{property.name}'"
+ end
+
+ propis = is[property]
+ unless property.insync?(propis)
+ property.debug("Not in sync: #{propis.inspect} vs #{property.should.inspect}")
+ insync = false
+ #else
+ # property.debug("In sync")
+ end
+ }
+
+ #self.debug("#{self} sync status is #{insync}")
+ insync
+ end
+
+ # retrieve the current value of all contained properties
+ def retrieve
+ fail "Provider #{provider.class.name} is not functional on this host" if self.provider.is_a?(Puppet::Provider) and ! provider.class.suitable?
+
+ result = Puppet::Resource.new(type, title)
+
+ # Provide the name, so we know we'll always refer to a real thing
+ result[:name] = self[:name] unless self[:name] == title
+
+ if ensure_prop = property(:ensure) or (self.class.validattr?(:ensure) and ensure_prop = newattr(:ensure))
+ result[:ensure] = ensure_state = ensure_prop.retrieve
+ else
+ ensure_state = nil
+ end
+
+ properties.each do |property|
+ next if property.name == :ensure
+ if ensure_state == :absent
+ result[property] = :absent
+ else
+ result[property] = property.retrieve
+ end
+ end
+
+ result
+ end
+
+ def retrieve_resource
+ resource = retrieve
+ resource = Resource.new(type, title, :parameters => resource) if resource.is_a? Hash
+ resource
+ end
+
+ # Get a hash of the current properties. Returns a hash with
+ # the actual property instance as the key and the current value
+ # as the, um, value.
+ def currentpropvalues
+ # It's important to use the 'properties' method here, as it follows the order
+ # in which they're defined in the class. It also guarantees that 'ensure'
+ # is the first property, which is important for skipping 'retrieve' on
+ # all the properties if the resource is absent.
+ ensure_state = false
+ return properties.inject({}) do | prophash, property|
+ if property.name == :ensure
+ ensure_state = property.retrieve
+ prophash[property] = ensure_state
+ else
+ if ensure_state == :absent
+ prophash[property] = :absent
else
- raise Puppet::DevError,"you must specify title patterns when there are two or more key attributes"
- end
- end
-
- def uniqueness_key
- to_resource.uniqueness_key
- end
-
- # Create a new parameter. Requires a block and a name, stores it in the
- # @parameters array, and does some basic checking on it.
- def self.newparam(name, options = {}, &block)
- options[:attributes] ||= {}
-
- param = genclass(
- name,
- :parent => options[:parent] || Puppet::Parameter,
- :attributes => options[:attributes],
- :block => block,
- :prefix => "Parameter",
- :array => @parameters,
-
- :hash => @paramhash
+ prophash[property] = property.retrieve
+ end
+ end
+ prophash
+ end
+ end
+
+ # Are we running in noop mode?
+ def noop?
+ if defined?(@noop)
+ @noop
+ else
+ Puppet[:noop]
+ end
+ end
+
+ def noop
+ noop?
+ end
+
+ ###############################
+ # Code related to managing resource instances.
+ require 'puppet/transportable'
+
+ # retrieve a named instance of the current type
+ def self.[](name)
+ raise "Global resource access is deprecated"
+ @objects[name] || @aliases[name]
+ end
+
+ # add an instance by name to the class list of instances
+ def self.[]=(name,object)
+ raise "Global resource storage is deprecated"
+ newobj = nil
+ if object.is_a?(Puppet::Type)
+ newobj = object
+ else
+ raise Puppet::DevError, "must pass a Puppet::Type object"
+ end
+
+ if exobj = @objects[name] and self.isomorphic?
+ msg = "Object '#{newobj.class.name}[#{name}]' already exists"
+
+ msg += ("in file #{object.file} at line #{object.line}") if exobj.file and exobj.line
+ msg += ("and cannot be redefined in file #{object.file} at line #{object.line}") if object.file and object.line
+ error = Puppet::Error.new(msg)
+ raise error
+ else
+ #Puppet.info("adding %s of type %s to class list" %
+ # [name,object.class])
+ @objects[name] = newobj
+ end
+ end
+
+ # Create an alias. We keep these in a separate hash so that we don't encounter
+ # the objects multiple times when iterating over them.
+ def self.alias(name, obj)
+ raise "Global resource aliasing is deprecated"
+ if @objects.include?(name)
+ unless @objects[name] == obj
+ raise Puppet::Error.new(
+ "Cannot create alias #{name}: object already exists"
)
-
- handle_param_options(name, options)
-
- # Grr.
- param.required_features = options[:required_features] if options[:required_features]
-
- param.isnamevar if options[:namevar]
-
- param
- end
-
- def self.newstate(name, options = {}, &block)
- Puppet.warning "newstate() has been deprecrated; use newproperty(#{name})"
- newproperty(name, options, &block)
+ end
end
- # Create a new property. The first parameter must be the name of the property;
- # this is how users will refer to the property when creating new instances.
- # The second parameter is a hash of options; the options are:
- # * <tt>:parent</tt>: The parent class for the property. Defaults to Puppet::Property.
- # * <tt>:retrieve</tt>: The method to call on the provider or @parent object (if
- # the provider is not set) to retrieve the current value.
- def self.newproperty(name, options = {}, &block)
- name = symbolize(name)
-
- # This is here for types that might still have the old method of defining
- # a parent class.
- unless options.is_a? Hash
- raise Puppet::DevError,
- "Options must be a hash, not #{options.inspect}"
- end
-
- raise Puppet::DevError, "Class #{self.name} already has a property named #{name}" if @validproperties.include?(name)
-
- if parent = options[:parent]
- options.delete(:parent)
- else
- parent = Puppet::Property
- end
-
- # We have to create our own, new block here because we want to define
- # an initial :retrieve method, if told to, and then eval the passed
- # block if available.
- prop = genclass(name, :parent => parent, :hash => @validproperties, :attributes => options) do
- # If they've passed a retrieve method, then override the retrieve
- # method on the class.
- if options[:retrieve]
- define_method(:retrieve) do
- provider.send(options[:retrieve])
- end
- end
-
- class_eval(&block) if block
- end
-
- # If it's the 'ensure' property, always put it first.
- if name == :ensure
- @properties.unshift prop
- else
- @properties << prop
- end
-
- prop
- end
-
- def self.paramdoc(param)
- @paramhash[param].doc
- end
-
- # Return the parameter names
- def self.parameters
- return [] unless defined?(@parameters)
- @parameters.collect { |klass| klass.name }
- end
-
- # Find the parameter class associated with a given parameter name.
- def self.paramclass(name)
- @paramhash[name]
- end
-
- # Return the property class associated with a name
- def self.propertybyname(name)
- @validproperties[name]
- end
-
- def self.validattr?(name)
- name = symbolize(name)
- return true if name == :name
- @validattrs ||= {}
-
- unless @validattrs.include?(name)
- @validattrs[name] = !!(self.validproperty?(name) or self.validparameter?(name) or self.metaparam?(name))
- end
-
- @validattrs[name]
- end
-
- # does the name reflect a valid property?
- def self.validproperty?(name)
- name = symbolize(name)
- @validproperties.include?(name) && @validproperties[name]
- end
+ if @aliases.include?(name)
+ unless @aliases[name] == obj
+ raise Puppet::Error.new(
+ "Object #{@aliases[name].name} already has alias #{name}"
+ )
+ end
+ end
+
+ @aliases[name] = obj
+ end
+
+ # remove all of the instances of a single type
+ def self.clear
+ raise "Global resource removal is deprecated"
+ if defined?(@objects)
+ @objects.each do |name, obj|
+ obj.remove(true)
+ end
+ @objects.clear
+ end
+ @aliases.clear if defined?(@aliases)
+ end
+
+ # Force users to call this, so that we can merge objects if
+ # necessary.
+ def self.create(args)
+ # LAK:DEP Deprecation notice added 12/17/2008
+ Puppet.warning "Puppet::Type.create is deprecated; use Puppet::Type.new"
+ new(args)
+ end
+
+ # remove a specified object
+ def self.delete(resource)
+ raise "Global resource removal is deprecated"
+ return unless defined?(@objects)
+ @objects.delete(resource.title) if @objects.include?(resource.title)
+ @aliases.delete(resource.title) if @aliases.include?(resource.title)
+ if @aliases.has_value?(resource)
+ names = []
+ @aliases.each do |name, otherres|
+ if otherres == resource
+ names << name
+ end
+ end
+ names.each { |name| @aliases.delete(name) }
+ end
+ end
+
+ # iterate across each of the type's instances
+ def self.each
+ raise "Global resource iteration is deprecated"
+ return unless defined?(@objects)
+ @objects.each { |name,instance|
+ yield instance
+ }
+ end
+
+ # does the type have an object with the given name?
+ def self.has_key?(name)
+ raise "Global resource access is deprecated"
+ @objects.has_key?(name)
+ end
+
+ # Retrieve all known instances. Either requires providers or must be overridden.
+ def self.instances
+ raise Puppet::DevError, "#{self.name} has no providers and has not overridden 'instances'" if provider_hash.empty?
+
+ # Put the default provider first, then the rest of the suitable providers.
+ provider_instances = {}
+ providers_by_source.collect do |provider|
+ provider.instances.collect do |instance|
+ # We always want to use the "first" provider instance we find, unless the resource
+ # is already managed and has a different provider set
+ if other = provider_instances[instance.name]
+ Puppet.warning "%s %s found in both %s and %s; skipping the %s version" %
+ [self.name.to_s.capitalize, instance.name, other.class.name, instance.class.name, instance.class.name]
+ next
+ end
+ provider_instances[instance.name] = instance
+
+ new(:name => instance.name, :provider => instance, :audit => :all)
+ end
+ end.flatten.compact
+ end
+
+ # Return a list of one suitable provider per source, with the default provider first.
+ def self.providers_by_source
+ # Put the default provider first, then the rest of the suitable providers.
+ sources = []
+ [defaultprovider, suitableprovider].flatten.uniq.collect do |provider|
+ next if sources.include?(provider.source)
+
+ sources << provider.source
+ provider
+ end.compact
+ end
+
+ # Convert a simple hash into a Resource instance.
+ def self.hash2resource(hash)
+ hash = hash.inject({}) { |result, ary| result[ary[0].to_sym] = ary[1]; result }
+
+ title = hash.delete(:title)
+ title ||= hash[:name]
+ title ||= hash[key_attributes.first] if key_attributes.length == 1
+
+ raise Puppet::Error, "Title or name must be provided" unless title
+
+ # Now create our resource.
+ resource = Puppet::Resource.new(self.name, title)
+ [:catalog].each do |attribute|
+ if value = hash[attribute]
+ hash.delete(attribute)
+ resource.send(attribute.to_s + "=", value)
+ end
+ end
+
+ hash.each do |param, value|
+ resource[param] = value
+ end
+ resource
+ end
+
+ # Create the path for logging and such.
+ def pathbuilder
+ if p = parent
+ [p.pathbuilder, self.ref].flatten
+ else
+ [self.ref]
+ end
+ end
+
+ ###############################
+ # Add all of the meta parameters.
+ newmetaparam(:noop) do
+ desc "Boolean flag indicating whether work should actually
+ be done."
+
+ newvalues(:true, :false)
+ munge do |value|
+ case value
+ when true, :true, "true"; @resource.noop = true
+ when false, :false, "false"; @resource.noop = false
+ end
+ end
+ end
+
+ newmetaparam(:schedule) do
+ desc "On what schedule the object should be managed. You must create a
+ schedule object, and then reference the name of that object to use
+ that for your schedule::
+
+ schedule { daily:
+ period => daily,
+ range => \"2-4\"
+ }
- # Return the list of validproperties
- def self.validproperties
- return {} unless defined?(@parameters)
+ exec { \"/usr/bin/apt-get update\":
+ schedule => daily
+ }
- @validproperties.keys
- end
+ The creation of the schedule object does not need to appear in the
+ configuration before objects that use it."
+ end
- # does the name reflect a valid parameter?
- def self.validparameter?(name)
- raise Puppet::DevError, "Class #{self} has not defined parameters" unless defined?(@parameters)
- !!(@paramhash.include?(name) or @@metaparamhash.include?(name))
- end
+ newmetaparam(:audit) do
+ desc "Audit specified attributes of resources over time, and report if any have changed.
+ This attribute can be used to track changes to any resource over time, and can
+ provide an audit trail of every change that happens on any given machine.
- # This is a forward-compatibility method - it's the validity interface we'll use in Puppet::Resource.
- def self.valid_parameter?(name)
- validattr?(name)
- end
+ Note that you cannot both audit and manage an attribute - managing it guarantees
+ the value, and any changes already get logged."
- # Return either the attribute alias or the attribute.
- def attr_alias(name)
- name = symbolize(name)
- if synonym = self.class.attr_alias(name)
- return synonym
- else
- return name
+ validate do |list|
+ list = Array(list)
+ unless list == [:all]
+ list.each do |param|
+ next if @resource.class.validattr?(param)
+ fail "Cannot audit #{param}: not a valid attribute for #{resource}"
end
+ end
end
- # Are we deleting this resource?
- def deleting?
- obj = @parameters[:ensure] and obj.should == :absent
+ munge do |args|
+ properties_to_audit(args).each do |param|
+ next unless resource.class.validproperty?(param)
+ resource.newattr(param)
+ end
end
- # Create a new property if it is valid but doesn't exist
- # Returns: true if a new parameter was added, false otherwise
- def add_property_parameter(prop_name)
- if self.class.validproperty?(prop_name) && !@parameters[prop_name]
- self.newattr(prop_name)
- return true
- end
- false
+ def all_properties
+ resource.class.properties.find_all do |property|
+ resource.provider.nil? or resource.provider.class.supports_parameter?(property)
+ end.collect do |property|
+ property.name
+ end
end
- #
- # The name_var is the key_attribute in the case that there is only one.
- #
- def name_var
- key_attributes = self.class.key_attributes
- (key_attributes.length == 1) && key_attributes.first
+ def properties_to_audit(list)
+ if list == :all
+ list = all_properties if list == :all
+ else
+ list = Array(list).collect { |p| p.to_sym }
+ end
end
+ end
- # abstract accessing parameters and properties, and normalize
- # access to always be symbols, not strings
- # This returns a value, not an object. It returns the 'is'
- # value, but you can also specifically return 'is' and 'should'
- # values using 'object.is(:property)' or 'object.should(:property)'.
- def [](name)
- name = attr_alias(name)
-
- fail("Invalid parameter #{name}(#{name.inspect})") unless self.class.validattr?(name)
+ newmetaparam(:check) do
+ desc "Audit specified attributes of resources over time, and report if any have changed.
+ This parameter has been deprecated in favor of 'audit'."
- if name == :name
- name = name_var
- end
-
- if obj = @parameters[name]
- # Note that if this is a property, then the value is the "should" value,
- # not the current value.
- obj.value
- else
- return nil
- end
+ munge do |args|
+ resource.warning "'check' attribute is deprecated; use 'audit' instead"
+ resource[:audit] = args
end
+ end
- # Abstract setting parameters and properties, and normalize
- # access to always be symbols, not strings. This sets the 'should'
- # value on properties, and otherwise just sets the appropriate parameter.
- def []=(name,value)
- name = attr_alias(name)
-
- fail("Invalid parameter #{name}") unless self.class.validattr?(name)
-
- if name == :name
- name = name_var
- end
- raise Puppet::Error.new("Got nil value for #{name}") if value.nil?
-
- property = self.newattr(name)
+ newmetaparam(:loglevel) do
+ desc "Sets the level that information will be logged.
+ The log levels have the biggest impact when logs are sent to
+ syslog (which is currently the default)."
+ defaultto :notice
- begin
- # make sure the parameter doesn't have any errors
- property.value = value
- rescue => detail
- error = Puppet::Error.new("Parameter #{name} failed: #{detail}")
- error.set_backtrace(detail.backtrace)
- raise error
- end
+ newvalues(*Puppet::Util::Log.levels)
+ newvalues(:verbose)
- nil
+ munge do |loglevel|
+ val = super(loglevel)
+ if val == :verbose
+ val = :info
+ end
+ val
end
+ end
- # remove a property from the object; useful in testing or in cleanup
- # when an error has been encountered
- def delete(attr)
- attr = symbolize(attr)
- if @parameters.has_key?(attr)
- @parameters.delete(attr)
- else
- raise Puppet::DevError.new("Undefined attribute '#{attr}' in #{self}")
- end
- end
+ newmetaparam(:alias) do
+ desc "Creates an alias for the object. Puppet uses this internally when you
+ provide a symbolic name::
- # iterate across the existing properties
- def eachproperty
- # properties is a private method
- properties.each { |property|
- yield property
+ file { sshdconfig:
+ path => $operatingsystem ? {
+ solaris => \"/usr/local/etc/ssh/sshd_config\",
+ default => \"/etc/ssh/sshd_config\"
+ },
+ source => \"...\"
}
- end
- # Create a transaction event. Called by Transaction or by
- # a property.
- def event(options = {})
- Puppet::Transaction::Event.new({:resource => self, :file => file, :line => line, :tags => tags, :version => version}.merge(options))
- end
-
- # Let the catalog determine whether a given cached value is
- # still valid or has expired.
- def expirer
- catalog
- end
-
- # retrieve the 'should' value for a specified property
- def should(name)
- name = attr_alias(name)
- (prop = @parameters[name] and prop.is_a?(Puppet::Property)) ? prop.should : nil
- end
-
- # Create the actual attribute instance. Requires either the attribute
- # name or class as the first argument, then an optional hash of
- # attributes to set during initialization.
- def newattr(name)
- if name.is_a?(Class)
- klass = name
- name = klass.name
- end
-
- unless klass = self.class.attrclass(name)
- raise Puppet::Error, "Resource type #{self.class.name} does not support parameter #{name}"
- end
+ service { sshd:
+ subscribe => file[sshdconfig]
+ }
- return @parameters[name] if @parameters.include?(name)
+ When you use this feature, the parser sets ``sshdconfig`` as the name,
+ and the library sets that as an alias for the file so the dependency
+ lookup for ``sshd`` works. You can use this parameter yourself,
+ but note that only the library can use these aliases; for instance,
+ the following code will not work::
- @parameters[name] = klass.new(:resource => self)
- end
+ file { \"/etc/ssh/sshd_config\":
+ owner => root,
+ group => root,
+ alias => sshdconfig
+ }
- # return the value of a parameter
- def parameter(name)
- @parameters[name.to_sym]
- end
+ file { sshdconfig:
+ mode => 644
+ }
- def parameters
- @parameters.dup
- end
+ There's no way here for the Puppet parser to know that these two stanzas
+ should be affecting the same file.
- # Is the named property defined?
- def propertydefined?(name)
- name = name.intern unless name.is_a? Symbol
- @parameters.include?(name)
- end
+ See the `LanguageTutorial language tutorial`:trac: for more information.
- # Return an actual property instance by name; to return the value, use 'resource[param]'
- # LAK:NOTE(20081028) Since the 'parameter' method is now a superset of this method,
- # this one should probably go away at some point.
- def property(name)
- (obj = @parameters[symbolize(name)] and obj.is_a?(Puppet::Property)) ? obj : nil
- end
+ "
- # For any parameters or properties that have defaults and have not yet been
- # set, set them now. This method can be handed a list of attributes,
- # and if so it will only set defaults for those attributes.
- def set_default(attr)
- return unless klass = self.class.attrclass(attr)
- return unless klass.method_defined?(:default)
- return if @parameters.include?(klass.name)
+ munge do |aliases|
+ aliases = [aliases] unless aliases.is_a?(Array)
- return unless parameter = newattr(klass.name)
+ raise(ArgumentError, "Cannot add aliases without a catalog") unless @resource.catalog
- if value = parameter.default and ! value.nil?
- parameter.value = value
- else
- @parameters.delete(parameter.name)
+ aliases.each do |other|
+ if obj = @resource.catalog.resource(@resource.class.name, other)
+ unless obj.object_id == @resource.object_id
+ self.fail("#{@resource.title} can not create alias #{other}: object already exists")
+ end
+ next
end
+
+ # Newschool, add it to the catalog.
+ @resource.catalog.alias(@resource, other)
+ end
end
+ end
- # Convert our object to a hash. This just includes properties.
- def to_hash
- rethash = {}
+ newmetaparam(:tag) do
+ desc "Add the specified tags to the associated resource. While all resources
+ are automatically tagged with as much information as possible
+ (e.g., each class and definition containing the resource), it can
+ be useful to add your own tags to a given resource.
- @parameters.each do |name, obj|
- rethash[name] = obj.value
- end
-
- rethash
- end
+ Tags are currently useful for things like applying a subset of a
+ host's configuration::
- def type
- self.class.name
- end
+ puppet agent --test --tags mytag
- # Return a specific value for an attribute.
- def value(name)
- name = attr_alias(name)
+ This way, when you're testing a configuration you can run just the
+ portion you're testing."
- (obj = @parameters[name] and obj.respond_to?(:value)) ? obj.value : nil
- end
+ munge do |tags|
+ tags = [tags] unless tags.is_a? Array
- def version
- return 0 unless catalog
- catalog.version
+ tags.each do |tag|
+ @resource.tag(tag)
+ end
end
+ end
- # Return all of the property objects, in the order specified in the
- # class.
- def properties
- self.class.properties.collect { |prop| @parameters[prop.name] }.compact
+ class RelationshipMetaparam < Puppet::Parameter
+ class << self
+ attr_accessor :direction, :events, :callback, :subclasses
end
- # Is this type's name isomorphic with the object? That is, if the
- # name conflicts, does it necessarily mean that the objects conflict?
- # Defaults to true.
- def self.isomorphic?
- if defined?(@isomorphic)
- return @isomorphic
- else
- return true
- end
- end
+ @subclasses = []
- def isomorphic?
- self.class.isomorphic?
+ def self.inherited(sub)
+ @subclasses << sub
end
- # is the instance a managed instance? A 'yes' here means that
- # the instance was created from the language, vs. being created
- # in order resolve other questions, such as finding a package
- # in a list
- def managed?
- # Once an object is managed, it always stays managed; but an object
- # that is listed as unmanaged might become managed later in the process,
- # so we have to check that every time
- if @managed
- return @managed
+ def munge(references)
+ references = [references] unless references.is_a?(Array)
+ references.collect do |ref|
+ if ref.is_a?(Puppet::Resource)
+ ref
else
- @managed = false
- properties.each { |property|
- s = property.should
- if s and ! property.class.unmanaged
- @managed = true
- break
- end
- }
- return @managed
+ Puppet::Resource.new(ref)
end
+ end
end
- ###############################
- # Code related to the container behaviour.
-
- # this is a retarded hack method to get around the difference between
- # component children and file children
- def self.depthfirst?
- @depthfirst
- end
-
- def depthfirst?
- self.class.depthfirst?
- end
-
- # Remove an object. The argument determines whether the object's
- # subscriptions get eliminated, too.
- def remove(rmdeps = true)
- # This is hackish (mmm, cut and paste), but it works for now, and it's
- # better than warnings.
- @parameters.each do |name, obj|
- obj.remove
- end
- @parameters.clear
-
- @parent = nil
-
- # Remove the reference to the provider.
- if self.provider
- @provider.clear
- @provider = nil
+ def validate_relationship
+ @value.each do |ref|
+ unless @resource.catalog.resource(ref.to_s)
+ description = self.class.direction == :in ? "dependency" : "dependent"
+ fail "Could not find #{description} #{ref} for #{resource.ref}"
end
+ end
end
- ###############################
- # Code related to evaluating the resources.
-
- # Flush the provider, if it supports it. This is called by the
- # transaction.
- def flush
- self.provider.flush if self.provider and self.provider.respond_to?(:flush)
- end
+ # Create edges from each of our relationships. :in
+ # relationships are specified by the event-receivers, and :out
+ # relationships are specified by the event generator. This
+ # way 'source' and 'target' are consistent terms in both edges
+ # and events -- that is, an event targets edges whose source matches
+ # the event's source. The direction of the relationship determines
+ # which resource is applied first and which resource is considered
+ # to be the event generator.
+ def to_edges
+ @value.collect do |reference|
+ reference.catalog = resource.catalog
- # if all contained objects are in sync, then we're in sync
- # FIXME I don't think this is used on the type instances any more,
- # it's really only used for testing
- def insync?(is)
- insync = true
-
- if property = @parameters[:ensure]
- unless is.include? property
- raise Puppet::DevError,
- "The is value is not in the is array for '#{property.name}'"
- end
- ensureis = is[property]
- if property.insync?(ensureis) and property.should == :absent
- return true
- end
+ # Either of the two retrieval attempts could have returned
+ # nil.
+ unless related_resource = reference.resolve
+ self.fail "Could not retrieve dependency '#{reference}' of #{@resource.ref}"
end
- properties.each { |property|
- unless is.include? property
- raise Puppet::DevError,
- "The is value is not in the is array for '#{property.name}'"
- end
-
- propis = is[property]
- unless property.insync?(propis)
- property.debug("Not in sync: #{propis.inspect} vs #{property.should.inspect}")
- insync = false
- #else
- # property.debug("In sync")
- end
- }
-
- #self.debug("#{self} sync status is #{insync}")
- insync
- end
-
- # retrieve the current value of all contained properties
- def retrieve
- fail "Provider #{provider.class.name} is not functional on this host" if self.provider.is_a?(Puppet::Provider) and ! provider.class.suitable?
-
- result = Puppet::Resource.new(type, title)
-
- # Provide the name, so we know we'll always refer to a real thing
- result[:name] = self[:name] unless self[:name] == title
-
- if ensure_prop = property(:ensure) or (self.class.validattr?(:ensure) and ensure_prop = newattr(:ensure))
- result[:ensure] = ensure_state = ensure_prop.retrieve
+ # Are we requiring them, or vice versa? See the method docs
+ # for futher info on this.
+ if self.class.direction == :in
+ source = related_resource
+ target = @resource
else
- ensure_state = nil
+ source = @resource
+ target = related_resource
end
- properties.each do |property|
- next if property.name == :ensure
- if ensure_state == :absent
- result[property] = :absent
- else
- result[property] = property.retrieve
- end
- end
-
- result
- end
-
- def retrieve_resource
- resource = retrieve
- resource = Resource.new(type, title, :parameters => resource) if resource.is_a? Hash
- resource
- end
-
- # Get a hash of the current properties. Returns a hash with
- # the actual property instance as the key and the current value
- # as the, um, value.
- def currentpropvalues
- # It's important to use the 'properties' method here, as it follows the order
- # in which they're defined in the class. It also guarantees that 'ensure'
- # is the first property, which is important for skipping 'retrieve' on
- # all the properties if the resource is absent.
- ensure_state = false
- return properties.inject({}) do | prophash, property|
- if property.name == :ensure
- ensure_state = property.retrieve
- prophash[property] = ensure_state
- else
- if ensure_state == :absent
- prophash[property] = :absent
- else
- prophash[property] = property.retrieve
- end
- end
- prophash
- end
- end
-
- # Are we running in noop mode?
- def noop?
- if defined?(@noop)
- @noop
+ if method = self.class.callback
+ subargs = {
+ :event => self.class.events,
+ :callback => method
+ }
+ self.debug("subscribes to #{related_resource.ref}")
else
- Puppet[:noop]
+ # If there's no callback, there's no point in even adding
+ # a label.
+ subargs = nil
+ self.debug("requires #{related_resource.ref}")
end
- end
- def noop
- noop?
+ rel = Puppet::Relationship.new(source, target, subargs)
+ end
end
+ end
- ###############################
- # Code related to managing resource instances.
- require 'puppet/transportable'
+ def self.relationship_params
+ RelationshipMetaparam.subclasses
+ end
- # retrieve a named instance of the current type
- def self.[](name)
- raise "Global resource access is deprecated"
- @objects[name] || @aliases[name]
- end
- # add an instance by name to the class list of instances
- def self.[]=(name,object)
- raise "Global resource storage is deprecated"
- newobj = nil
- if object.is_a?(Puppet::Type)
- newobj = object
- else
- raise Puppet::DevError, "must pass a Puppet::Type object"
- end
-
- if exobj = @objects[name] and self.isomorphic?
- msg = "Object '#{newobj.class.name}[#{name}]' already exists"
-
- msg += ("in file #{object.file} at line #{object.line}") if exobj.file and exobj.line
- msg += ("and cannot be redefined in file #{object.file} at line #{object.line}") if object.file and object.line
- error = Puppet::Error.new(msg)
- raise error
- else
- #Puppet.info("adding %s of type %s to class list" %
- # [name,object.class])
- @objects[name] = newobj
- end
- end
+ # Note that the order in which the relationships params is defined
+ # matters. The labelled params (notify and subcribe) must be later,
+ # so that if both params are used, those ones win. It's a hackish
+ # solution, but it works.
- # Create an alias. We keep these in a separate hash so that we don't encounter
- # the objects multiple times when iterating over them.
- def self.alias(name, obj)
- raise "Global resource aliasing is deprecated"
- if @objects.include?(name)
- unless @objects[name] == obj
- raise Puppet::Error.new(
- "Cannot create alias #{name}: object already exists"
- )
- end
- end
+ newmetaparam(:require, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do
+ desc "One or more objects that this object depends on.
+ This is used purely for guaranteeing that changes to required objects
+ happen before the dependent object. For instance::
- if @aliases.include?(name)
- unless @aliases[name] == obj
- raise Puppet::Error.new(
- "Object #{@aliases[name].name} already has alias #{name}"
- )
- end
- end
-
- @aliases[name] = obj
- end
+ # Create the destination directory before you copy things down
+ file { \"/usr/local/scripts\":
+ ensure => directory
+ }
- # remove all of the instances of a single type
- def self.clear
- raise "Global resource removal is deprecated"
- if defined?(@objects)
- @objects.each do |name, obj|
- obj.remove(true)
- end
- @objects.clear
- end
- @aliases.clear if defined?(@aliases)
- end
-
- # Force users to call this, so that we can merge objects if
- # necessary.
- def self.create(args)
- # LAK:DEP Deprecation notice added 12/17/2008
- Puppet.warning "Puppet::Type.create is deprecated; use Puppet::Type.new"
- new(args)
- end
-
- # remove a specified object
- def self.delete(resource)
- raise "Global resource removal is deprecated"
- return unless defined?(@objects)
- @objects.delete(resource.title) if @objects.include?(resource.title)
- @aliases.delete(resource.title) if @aliases.include?(resource.title)
- if @aliases.has_value?(resource)
- names = []
- @aliases.each do |name, otherres|
- if otherres == resource
- names << name
- end
- end
- names.each { |name| @aliases.delete(name) }
- end
- end
+ file { \"/usr/local/scripts/myscript\":
+ source => \"puppet://server/module/myscript\",
+ mode => 755,
+ require => File[\"/usr/local/scripts\"]
+ }
- # iterate across each of the type's instances
- def self.each
- raise "Global resource iteration is deprecated"
- return unless defined?(@objects)
- @objects.each { |name,instance|
- yield instance
+ Multiple dependencies can be specified by providing a comma-seperated list
+ of resources, enclosed in square brackets::
+
+ require => [ File[\"/usr/local\"], File[\"/usr/local/scripts\"] ]
+
+ Note that Puppet will autorequire everything that it can, and
+ there are hooks in place so that it's easy for resources to add new
+ ways to autorequire objects, so if you think Puppet could be
+ smarter here, let us know.
+
+ In fact, the above code was redundant -- Puppet will autorequire
+ any parent directories that are being managed; it will
+ automatically realize that the parent directory should be created
+ before the script is pulled down.
+
+ Currently, exec resources will autorequire their CWD (if it is
+ specified) plus any fully qualified paths that appear in the
+ command. For instance, if you had an ``exec`` command that ran
+ the ``myscript`` mentioned above, the above code that pulls the
+ file down would be automatically listed as a requirement to the
+ ``exec`` code, so that you would always be running againts the
+ most recent version.
+ "
+ end
+
+ newmetaparam(:subscribe, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :ALL_EVENTS, :callback => :refresh}) do
+ desc "One or more objects that this object depends on. Changes in the
+ subscribed to objects result in the dependent objects being
+ refreshed (e.g., a service will get restarted). For instance::
+
+ class nagios {
+ file { \"/etc/nagios/nagios.conf\":
+ source => \"puppet://server/module/nagios.conf\",
+ alias => nagconf # just to make things easier for me
+ }
+ service { nagios:
+ ensure => running,
+ subscribe => File[nagconf]
+ }
}
- end
- # does the type have an object with the given name?
- def self.has_key?(name)
- raise "Global resource access is deprecated"
- @objects.has_key?(name)
- end
+ Currently the ``exec``, ``mount`` and ``service`` type support
+ refreshing.
+ "
+ end
- # Retrieve all known instances. Either requires providers or must be overridden.
- def self.instances
- raise Puppet::DevError, "#{self.name} has no providers and has not overridden 'instances'" if provider_hash.empty?
+ newmetaparam(:before, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do
+ desc %{This parameter is the opposite of **require** -- it guarantees
+ that the specified object is applied later than the specifying
+ object::
- # Put the default provider first, then the rest of the suitable providers.
- provider_instances = {}
- providers_by_source.collect do |provider|
- provider.instances.collect do |instance|
- # We always want to use the "first" provider instance we find, unless the resource
- # is already managed and has a different provider set
- if other = provider_instances[instance.name]
- Puppet.warning "%s %s found in both %s and %s; skipping the %s version" %
- [self.name.to_s.capitalize, instance.name, other.class.name, instance.class.name, instance.class.name]
- next
- end
- provider_instances[instance.name] = instance
+ file { "/var/nagios/configuration":
+ source => "...",
+ recurse => true,
+ before => Exec["nagios-rebuid"]
+ }
- new(:name => instance.name, :provider => instance, :audit => :all)
- end
- end.flatten.compact
- end
+ exec { "nagios-rebuild":
+ command => "/usr/bin/make",
+ cwd => "/var/nagios/configuration"
+ }
- # Return a list of one suitable provider per source, with the default provider first.
- def self.providers_by_source
- # Put the default provider first, then the rest of the suitable providers.
- sources = []
- [defaultprovider, suitableprovider].flatten.uniq.collect do |provider|
- next if sources.include?(provider.source)
+ This will make sure all of the files are up to date before the
+ make command is run.}
+ end
- sources << provider.source
- provider
- end.compact
- end
+ newmetaparam(:notify, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :ALL_EVENTS, :callback => :refresh}) do
+ desc %{This parameter is the opposite of **subscribe** -- it sends events
+ to the specified object::
- # Convert a simple hash into a Resource instance.
- def self.hash2resource(hash)
- hash = hash.inject({}) { |result, ary| result[ary[0].to_sym] = ary[1]; result }
+ file { "/etc/sshd_config":
+ source => "....",
+ notify => Service[sshd]
+ }
- title = hash.delete(:title)
- title ||= hash[:name]
- title ||= hash[key_attributes.first] if key_attributes.length == 1
+ service { sshd:
+ ensure => running
+ }
- raise Puppet::Error, "Title or name must be provided" unless title
+ This will restart the sshd service if the sshd config file changes.}
+ end
- # Now create our resource.
- resource = Puppet::Resource.new(self.name, title)
- [:catalog].each do |attribute|
- if value = hash[attribute]
- hash.delete(attribute)
- resource.send(attribute.to_s + "=", value)
- end
- end
+ newmetaparam(:stage) do
+ desc %{Which run stage a given resource should reside in. This just creates
+ a dependency on or from the named milestone. For instance, saying that
+ this is in the 'bootstrap' stage creates a dependency on the 'bootstrap'
+ milestone.
- hash.each do |param, value|
- resource[param] = value
- end
- resource
- end
+ By default, all classes get directly added to the
+ 'main' stage. You can create new stages as resources:
- # Create the path for logging and such.
- def pathbuilder
- if p = parent
- [p.pathbuilder, self.ref].flatten
- else
- [self.ref]
- end
- end
+ stage { [pre, post]: }
- ###############################
- # Add all of the meta parameters.
- newmetaparam(:noop) do
- desc "Boolean flag indicating whether work should actually
- be done."
+ To order stages, use standard relationships:
- newvalues(:true, :false)
- munge do |value|
- case value
- when true, :true, "true"; @resource.noop = true
- when false, :false, "false"; @resource.noop = false
- end
- end
- end
+ stage { pre: before => Stage[main] }
- newmetaparam(:schedule) do
- desc "On what schedule the object should be managed. You must create a
- schedule object, and then reference the name of that object to use
- that for your schedule::
+ Or use the new relationship syntax:
- schedule { daily:
- period => daily,
- range => \"2-4\"
- }
+ Stage[pre] -> Stage[main] -> Stage[post]
- exec { \"/usr/bin/apt-get update\":
- schedule => daily
- }
+ Then use the new class parameters to specify a stage:
- The creation of the schedule object does not need to appear in the
- configuration before objects that use it."
- end
+ class { foo: stage => pre }
- newmetaparam(:audit) do
- desc "Audit specified attributes of resources over time, and report if any have changed.
- This attribute can be used to track changes to any resource over time, and can
- provide an audit trail of every change that happens on any given machine.
+ Stages can only be set on classes, not individual resources. This will
+ fail::
- Note that you cannot both audit and manage an attribute - managing it guarantees
- the value, and any changes already get logged."
+ file { '/foo': stage => pre, ensure => file }
+ }
+ end
- validate do |list|
- list = Array(list)
- unless list == [:all]
- list.each do |param|
- next if @resource.class.validattr?(param)
- fail "Cannot audit #{param}: not a valid attribute for #{resource}"
- end
- end
- end
+ ###############################
+ # All of the provider plumbing for the resource types.
+ require 'puppet/provider'
+ require 'puppet/util/provider_features'
- munge do |args|
- properties_to_audit(args).each do |param|
- next unless resource.class.validproperty?(param)
- resource.newattr(param)
- end
- end
+ # Add the feature handling module.
+ extend Puppet::Util::ProviderFeatures
- def all_properties
- resource.class.properties.find_all do |property|
- resource.provider.nil? or resource.provider.class.supports_parameter?(property)
- end.collect do |property|
- property.name
- end
- end
+ attr_reader :provider
- def properties_to_audit(list)
- if list == :all
- list = all_properties if list == :all
- else
- list = Array(list).collect { |p| p.to_sym }
- end
- end
- end
+ # the Type class attribute accessors
+ class << self
+ attr_accessor :providerloader
+ attr_writer :defaultprovider
+ end
- newmetaparam(:check) do
- desc "Audit specified attributes of resources over time, and report if any have changed.
- This parameter has been deprecated in favor of 'audit'."
+ # Find the default provider.
+ def self.defaultprovider
+ unless @defaultprovider
+ suitable = suitableprovider
- munge do |args|
- resource.warning "'check' attribute is deprecated; use 'audit' instead"
- resource[:audit] = args
- end
- end
+ # Find which providers are a default for this system.
+ defaults = suitable.find_all { |provider| provider.default? }
- newmetaparam(:loglevel) do
- desc "Sets the level that information will be logged.
- The log levels have the biggest impact when logs are sent to
- syslog (which is currently the default)."
- defaultto :notice
+ # If we don't have any default we use suitable providers
+ defaults = suitable if defaults.empty?
+ max = defaults.collect { |provider| provider.specificity }.max
+ defaults = defaults.find_all { |provider| provider.specificity == max }
- newvalues(*Puppet::Util::Log.levels)
- newvalues(:verbose)
+ retval = nil
+ if defaults.length > 1
+ Puppet.warning(
+ "Found multiple default providers for #{self.name}: #{defaults.collect { |i| i.name.to_s }.join(", ")}; using #{defaults[0].name}"
+ )
+ retval = defaults.shift
+ elsif defaults.length == 1
+ retval = defaults.shift
+ else
+ raise Puppet::DevError, "Could not find a default provider for #{self.name}"
+ end
- munge do |loglevel|
- val = super(loglevel)
- if val == :verbose
- val = :info
- end
- val
- end
+ @defaultprovider = retval
end
- newmetaparam(:alias) do
- desc "Creates an alias for the object. Puppet uses this internally when you
- provide a symbolic name::
-
- file { sshdconfig:
- path => $operatingsystem ? {
- solaris => \"/usr/local/etc/ssh/sshd_config\",
- default => \"/etc/ssh/sshd_config\"
- },
- source => \"...\"
- }
-
- service { sshd:
- subscribe => file[sshdconfig]
- }
+ @defaultprovider
+ end
- When you use this feature, the parser sets ``sshdconfig`` as the name,
- and the library sets that as an alias for the file so the dependency
- lookup for ``sshd`` works. You can use this parameter yourself,
- but note that only the library can use these aliases; for instance,
- the following code will not work::
+ def self.provider_hash_by_type(type)
+ @provider_hashes ||= {}
+ @provider_hashes[type] ||= {}
+ end
- file { \"/etc/ssh/sshd_config\":
- owner => root,
- group => root,
- alias => sshdconfig
- }
+ def self.provider_hash
+ Puppet::Type.provider_hash_by_type(self.name)
+ end
- file { sshdconfig:
- mode => 644
- }
+ # Retrieve a provider by name.
+ def self.provider(name)
+ name = Puppet::Util.symbolize(name)
- There's no way here for the Puppet parser to know that these two stanzas
- should be affecting the same file.
+ # If we don't have it yet, try loading it.
+ @providerloader.load(name) unless provider_hash.has_key?(name)
+ provider_hash[name]
+ end
- See the `LanguageTutorial language tutorial`:trac: for more information.
+ # Just list all of the providers.
+ def self.providers
+ provider_hash.keys
+ end
- "
+ def self.validprovider?(name)
+ name = Puppet::Util.symbolize(name)
- munge do |aliases|
- aliases = [aliases] unless aliases.is_a?(Array)
+ (provider_hash.has_key?(name) && provider_hash[name].suitable?)
+ end
- raise(ArgumentError, "Cannot add aliases without a catalog") unless @resource.catalog
+ # Create a new provider of a type. This method must be called
+ # directly on the type that it's implementing.
+ def self.provide(name, options = {}, &block)
+ name = Puppet::Util.symbolize(name)
- aliases.each do |other|
- if obj = @resource.catalog.resource(@resource.class.name, other)
- unless obj.object_id == @resource.object_id
- self.fail("#{@resource.title} can not create alias #{other}: object already exists")
- end
- next
- end
-
- # Newschool, add it to the catalog.
- @resource.catalog.alias(@resource, other)
- end
- end
- end
-
- newmetaparam(:tag) do
- desc "Add the specified tags to the associated resource. While all resources
- are automatically tagged with as much information as possible
- (e.g., each class and definition containing the resource), it can
- be useful to add your own tags to a given resource.
-
- Tags are currently useful for things like applying a subset of a
- host's configuration::
-
- puppet agent --test --tags mytag
-
- This way, when you're testing a configuration you can run just the
- portion you're testing."
-
- munge do |tags|
- tags = [tags] unless tags.is_a? Array
-
- tags.each do |tag|
- @resource.tag(tag)
- end
- end
+ if obj = provider_hash[name]
+ Puppet.debug "Reloading #{name} #{self.name} provider"
+ unprovide(name)
end
- class RelationshipMetaparam < Puppet::Parameter
- class << self
- attr_accessor :direction, :events, :callback, :subclasses
- end
-
- @subclasses = []
-
- def self.inherited(sub)
- @subclasses << sub
- end
-
- def munge(references)
- references = [references] unless references.is_a?(Array)
- references.collect do |ref|
- if ref.is_a?(Puppet::Resource)
- ref
- else
- Puppet::Resource.new(ref)
- end
- end
- end
-
- def validate_relationship
- @value.each do |ref|
- unless @resource.catalog.resource(ref.to_s)
- description = self.class.direction == :in ? "dependency" : "dependent"
- fail "Could not find #{description} #{ref} for #{resource.ref}"
- end
- end
- end
-
- # Create edges from each of our relationships. :in
- # relationships are specified by the event-receivers, and :out
- # relationships are specified by the event generator. This
- # way 'source' and 'target' are consistent terms in both edges
- # and events -- that is, an event targets edges whose source matches
- # the event's source. The direction of the relationship determines
- # which resource is applied first and which resource is considered
- # to be the event generator.
- def to_edges
- @value.collect do |reference|
- reference.catalog = resource.catalog
-
- # Either of the two retrieval attempts could have returned
- # nil.
- unless related_resource = reference.resolve
- self.fail "Could not retrieve dependency '#{reference}' of #{@resource.ref}"
- end
-
- # Are we requiring them, or vice versa? See the method docs
- # for futher info on this.
- if self.class.direction == :in
- source = related_resource
- target = @resource
- else
- source = @resource
- target = related_resource
- end
-
- if method = self.class.callback
- subargs = {
- :event => self.class.events,
- :callback => method
- }
- self.debug("subscribes to #{related_resource.ref}")
- else
- # If there's no callback, there's no point in even adding
- # a label.
- subargs = nil
- self.debug("requires #{related_resource.ref}")
- end
-
- rel = Puppet::Relationship.new(source, target, subargs)
- end
+ parent = if pname = options[:parent]
+ options.delete(:parent)
+ if pname.is_a? Class
+ pname
+ else
+ if provider = self.provider(pname)
+ provider
+ else
+ raise Puppet::DevError,
+ "Could not find parent provider #{pname} of #{name}"
end
+ end
+ else
+ Puppet::Provider
end
- def self.relationship_params
- RelationshipMetaparam.subclasses
- end
-
-
- # Note that the order in which the relationships params is defined
- # matters. The labelled params (notify and subcribe) must be later,
- # so that if both params are used, those ones win. It's a hackish
- # solution, but it works.
-
- newmetaparam(:require, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :NONE}) do
- desc "One or more objects that this object depends on.
- This is used purely for guaranteeing that changes to required objects
- happen before the dependent object. For instance::
+ options[:resource_type] ||= self
- # Create the destination directory before you copy things down
- file { \"/usr/local/scripts\":
- ensure => directory
- }
+ self.providify
- file { \"/usr/local/scripts/myscript\":
- source => \"puppet://server/module/myscript\",
- mode => 755,
- require => File[\"/usr/local/scripts\"]
- }
- Multiple dependencies can be specified by providing a comma-seperated list
- of resources, enclosed in square brackets::
+ provider = genclass(
+ name,
+ :parent => parent,
+ :hash => provider_hash,
+ :prefix => "Provider",
+ :block => block,
+ :include => feature_module,
+ :extend => feature_module,
- require => [ File[\"/usr/local\"], File[\"/usr/local/scripts\"] ]
+ :attributes => options
+ )
- Note that Puppet will autorequire everything that it can, and
- there are hooks in place so that it's easy for resources to add new
- ways to autorequire objects, so if you think Puppet could be
- smarter here, let us know.
+ provider
+ end
- In fact, the above code was redundant -- Puppet will autorequire
- any parent directories that are being managed; it will
- automatically realize that the parent directory should be created
- before the script is pulled down.
+ # Make sure we have a :provider parameter defined. Only gets called if there
+ # are providers.
+ def self.providify
+ return if @paramhash.has_key? :provider
- Currently, exec resources will autorequire their CWD (if it is
- specified) plus any fully qualified paths that appear in the
- command. For instance, if you had an ``exec`` command that ran
- the ``myscript`` mentioned above, the above code that pulls the
- file down would be automatically listed as a requirement to the
- ``exec`` code, so that you would always be running againts the
- most recent version.
- "
- end
-
- newmetaparam(:subscribe, :parent => RelationshipMetaparam, :attributes => {:direction => :in, :events => :ALL_EVENTS, :callback => :refresh}) do
- desc "One or more objects that this object depends on. Changes in the
- subscribed to objects result in the dependent objects being
- refreshed (e.g., a service will get restarted). For instance::
+ newparam(:provider) do
+ desc "The specific backend for #{self.name.to_s} to use. You will
+ seldom need to specify this -- Puppet will usually discover the
+ appropriate provider for your platform."
- class nagios {
- file { \"/etc/nagios/nagios.conf\":
- source => \"puppet://server/module/nagios.conf\",
- alias => nagconf # just to make things easier for me
- }
- service { nagios:
- ensure => running,
- subscribe => File[nagconf]
- }
- }
+ # This is so we can refer back to the type to get a list of
+ # providers for documentation.
+ class << self
+ attr_accessor :parenttype
+ end
- Currently the ``exec``, ``mount`` and ``service`` type support
- refreshing.
- "
- end
-
- newmetaparam(:before, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :NONE}) do
- desc %{This parameter is the opposite of **require** -- it guarantees
- that the specified object is applied later than the specifying
- object::
-
- file { "/var/nagios/configuration":
- source => "...",
- recurse => true,
- before => Exec["nagios-rebuid"]
- }
-
- exec { "nagios-rebuild":
- command => "/usr/bin/make",
- cwd => "/var/nagios/configuration"
- }
-
- This will make sure all of the files are up to date before the
- make command is run.}
- end
+ # We need to add documentation for each provider.
+ def self.doc
+ @doc + " Available providers are:\n\n" + parenttype.providers.sort { |a,b|
+ a.to_s <=> b.to_s
+ }.collect { |i|
+ "* **#{i}**: #{parenttype().provider(i).doc}"
+ }.join("\n")
+ end
- newmetaparam(:notify, :parent => RelationshipMetaparam, :attributes => {:direction => :out, :events => :ALL_EVENTS, :callback => :refresh}) do
- desc %{This parameter is the opposite of **subscribe** -- it sends events
- to the specified object::
+ defaultto {
+ @resource.class.defaultprovider.name
+ }
- file { "/etc/sshd_config":
- source => "....",
- notify => Service[sshd]
- }
+ validate do |provider_class|
+ provider_class = provider_class[0] if provider_class.is_a? Array
+ provider_class = provider_class.class.name if provider_class.is_a?(Puppet::Provider)
- service { sshd:
- ensure => running
- }
-
- This will restart the sshd service if the sshd config file changes.}
- end
-
- newmetaparam(:stage) do
- desc %{Which run stage a given resource should reside in. This just creates
- a dependency on or from the named milestone. For instance, saying that
- this is in the 'bootstrap' stage creates a dependency on the 'bootstrap'
- milestone.
-
- By default, all classes get directly added to the
- 'main' stage. You can create new stages as resources:
-
- stage { [pre, post]: }
-
- To order stages, use standard relationships:
-
- stage { pre: before => Stage[main] }
-
- Or use the new relationship syntax:
-
- Stage[pre] -> Stage[main] -> Stage[post]
-
- Then use the new class parameters to specify a stage:
-
- class { foo: stage => pre }
-
- Stages can only be set on classes, not individual resources. This will
- fail::
-
- file { '/foo': stage => pre, ensure => file }
- }
- end
-
- ###############################
- # All of the provider plumbing for the resource types.
- require 'puppet/provider'
- require 'puppet/util/provider_features'
-
- # Add the feature handling module.
- extend Puppet::Util::ProviderFeatures
-
- attr_reader :provider
-
- # the Type class attribute accessors
- class << self
- attr_accessor :providerloader
- attr_writer :defaultprovider
- end
-
- # Find the default provider.
- def self.defaultprovider
- unless @defaultprovider
- suitable = suitableprovider
-
- # Find which providers are a default for this system.
- defaults = suitable.find_all { |provider| provider.default? }
-
- # If we don't have any default we use suitable providers
- defaults = suitable if defaults.empty?
- max = defaults.collect { |provider| provider.specificity }.max
- defaults = defaults.find_all { |provider| provider.specificity == max }
-
- retval = nil
- if defaults.length > 1
- Puppet.warning(
- "Found multiple default providers for #{self.name}: #{defaults.collect { |i| i.name.to_s }.join(", ")}; using #{defaults[0].name}"
- )
- retval = defaults.shift
- elsif defaults.length == 1
- retval = defaults.shift
- else
- raise Puppet::DevError, "Could not find a default provider for #{self.name}"
- end
-
- @defaultprovider = retval
+ unless provider = @resource.class.provider(provider_class)
+ raise ArgumentError, "Invalid #{@resource.class.name} provider '#{provider_class}'"
end
+ end
- @defaultprovider
- end
-
- def self.provider_hash_by_type(type)
- @provider_hashes ||= {}
- @provider_hashes[type] ||= {}
- end
-
- def self.provider_hash
- Puppet::Type.provider_hash_by_type(self.name)
- end
-
- # Retrieve a provider by name.
- def self.provider(name)
- name = Puppet::Util.symbolize(name)
-
- # If we don't have it yet, try loading it.
- @providerloader.load(name) unless provider_hash.has_key?(name)
- provider_hash[name]
- end
-
- # Just list all of the providers.
- def self.providers
- provider_hash.keys
- end
-
- def self.validprovider?(name)
- name = Puppet::Util.symbolize(name)
-
- (provider_hash.has_key?(name) && provider_hash[name].suitable?)
- end
-
- # Create a new provider of a type. This method must be called
- # directly on the type that it's implementing.
- def self.provide(name, options = {}, &block)
- name = Puppet::Util.symbolize(name)
-
- if obj = provider_hash[name]
- Puppet.debug "Reloading #{name} #{self.name} provider"
- unprovide(name)
- end
+ munge do |provider|
+ provider = provider[0] if provider.is_a? Array
+ provider = provider.intern if provider.is_a? String
+ @resource.provider = provider
- parent = if pname = options[:parent]
- options.delete(:parent)
- if pname.is_a? Class
- pname
- else
- if provider = self.provider(pname)
- provider
- else
- raise Puppet::DevError,
- "Could not find parent provider #{pname} of #{name}"
- end
- end
+ if provider.is_a?(Puppet::Provider)
+ provider.class.name
else
- Puppet::Provider
- end
-
- options[:resource_type] ||= self
-
- self.providify
-
-
- provider = genclass(
- name,
- :parent => parent,
- :hash => provider_hash,
- :prefix => "Provider",
- :block => block,
- :include => feature_module,
- :extend => feature_module,
-
- :attributes => options
- )
+ provider
+ end
+ end
+ end.parenttype = self
+ end
+
+ def self.unprovide(name)
+ if provider_hash.has_key? name
+
+ rmclass(
+ name,
+ :hash => provider_hash,
+
+ :prefix => "Provider"
+ )
+ if @defaultprovider and @defaultprovider.name == name
+ @defaultprovider = nil
+ end
+ end
+ end
+
+ # Return an array of all of the suitable providers.
+ def self.suitableprovider
+ providerloader.loadall if provider_hash.empty?
+ provider_hash.find_all { |name, provider|
+ provider.suitable?
+ }.collect { |name, provider|
+ provider
+ }.reject { |p| p.name == :fake } # For testing
+ end
+
+ def provider=(name)
+ if name.is_a?(Puppet::Provider)
+ @provider = name
+ @provider.resource = self
+ elsif klass = self.class.provider(name)
+ @provider = klass.new(self)
+ else
+ raise ArgumentError, "Could not find #{name} provider of #{self.class.name}"
+ end
+ end
+
+ ###############################
+ # All of the relationship code.
+
+ # Specify a block for generating a list of objects to autorequire. This
+ # makes it so that you don't have to manually specify things that you clearly
+ # require.
+ def self.autorequire(name, &block)
+ @autorequires ||= {}
+ @autorequires[name] = block
+ end
+
+ # Yield each of those autorequires in turn, yo.
+ def self.eachautorequire
+ @autorequires ||= {}
+ @autorequires.each { |type, block|
+ yield(type, block)
+ }
+ end
+
+ # Figure out of there are any objects we can automatically add as
+ # dependencies.
+ def autorequire(rel_catalog = nil)
+ rel_catalog ||= catalog
+ raise(Puppet::DevError, "You cannot add relationships without a catalog") unless rel_catalog
+
+ reqs = []
+ self.class.eachautorequire { |type, block|
+ # Ignore any types we can't find, although that would be a bit odd.
+ next unless typeobj = Puppet::Type.type(type)
+
+ # Retrieve the list of names from the block.
+ next unless list = self.instance_eval(&block)
+ list = [list] unless list.is_a?(Array)
+
+ # Collect the current prereqs
+ list.each { |dep|
+ obj = nil
+ # Support them passing objects directly, to save some effort.
+ unless dep.is_a? Puppet::Type
+ # Skip autorequires that we aren't managing
+ unless dep = rel_catalog.resource(type, dep)
+ next
+ end
+ end
+
+ reqs << Puppet::Relationship.new(dep, self)
+ }
+ }
+
+ reqs
+ end
+
+ # Build the dependencies associated with an individual object.
+ def builddepends
+ # Handle the requires
+ self.class.relationship_params.collect do |klass|
+ if param = @parameters[klass.name]
+ param.to_edges
+ end
+ end.flatten.reject { |r| r.nil? }
+ end
+
+ # Define the initial list of tags.
+ def tags=(list)
+ tag(self.class.name)
+ tag(*list)
+ end
+
+ # Types (which map to resources in the languages) are entirely composed of
+ # attribute value pairs. Generally, Puppet calls any of these things an
+ # 'attribute', but these attributes always take one of three specific
+ # forms: parameters, metaparams, or properties.
+
+ # In naming methods, I have tried to consistently name the method so
+ # that it is clear whether it operates on all attributes (thus has 'attr' in
+ # the method name, or whether it operates on a specific type of attributes.
+ attr_writer :title
+ attr_writer :noop
+
+ include Enumerable
+
+ # class methods dealing with Type management
+
+ public
+
+ # the Type class attribute accessors
+ class << self
+ attr_reader :name
+ attr_accessor :self_refresh
+ include Enumerable, Puppet::Util::ClassGen
+ include Puppet::MetaType::Manager
- provider
- end
-
- # Make sure we have a :provider parameter defined. Only gets called if there
- # are providers.
- def self.providify
- return if @paramhash.has_key? :provider
-
- newparam(:provider) do
- desc "The specific backend for #{self.name.to_s} to use. You will
- seldom need to specify this -- Puppet will usually discover the
- appropriate provider for your platform."
-
- # This is so we can refer back to the type to get a list of
- # providers for documentation.
- class << self
- attr_accessor :parenttype
- end
-
- # We need to add documentation for each provider.
- def self.doc
- @doc + " Available providers are:\n\n" + parenttype.providers.sort { |a,b|
- a.to_s <=> b.to_s
- }.collect { |i|
- "* **#{i}**: #{parenttype().provider(i).doc}"
- }.join("\n")
- end
-
- defaultto {
- @resource.class.defaultprovider.name
- }
-
- validate do |provider_class|
- provider_class = provider_class[0] if provider_class.is_a? Array
- provider_class = provider_class.class.name if provider_class.is_a?(Puppet::Provider)
-
- unless provider = @resource.class.provider(provider_class)
- raise ArgumentError, "Invalid #{@resource.class.name} provider '#{provider_class}'"
- end
- end
-
- munge do |provider|
- provider = provider[0] if provider.is_a? Array
- provider = provider.intern if provider.is_a? String
- @resource.provider = provider
-
- if provider.is_a?(Puppet::Provider)
- provider.class.name
- else
- provider
- end
- end
- end.parenttype = self
- end
-
- def self.unprovide(name)
- if provider_hash.has_key? name
-
- rmclass(
- name,
- :hash => provider_hash,
-
- :prefix => "Provider"
- )
- if @defaultprovider and @defaultprovider.name == name
- @defaultprovider = nil
- end
- end
- end
+ include Puppet::Util
+ include Puppet::Util::Logging
+ end
- # Return an array of all of the suitable providers.
- def self.suitableprovider
- providerloader.loadall if provider_hash.empty?
- provider_hash.find_all { |name, provider|
- provider.suitable?
- }.collect { |name, provider|
- provider
- }.reject { |p| p.name == :fake } # For testing
- end
+ # all of the variables that must be initialized for each subclass
+ def self.initvars
+ # all of the instances of this class
+ @objects = Hash.new
+ @aliases = Hash.new
- def provider=(name)
- if name.is_a?(Puppet::Provider)
- @provider = name
- @provider.resource = self
- elsif klass = self.class.provider(name)
- @provider = klass.new(self)
- else
- raise ArgumentError, "Could not find #{name} provider of #{self.class.name}"
- end
- end
+ @defaults = {}
- ###############################
- # All of the relationship code.
+ @parameters ||= []
- # Specify a block for generating a list of objects to autorequire. This
- # makes it so that you don't have to manually specify things that you clearly
- # require.
- def self.autorequire(name, &block)
- @autorequires ||= {}
- @autorequires[name] = block
- end
+ @validproperties = {}
+ @properties = []
+ @parameters = []
+ @paramhash = {}
- # Yield each of those autorequires in turn, yo.
- def self.eachautorequire
- @autorequires ||= {}
- @autorequires.each { |type, block|
- yield(type, block)
- }
- end
+ @attr_aliases = {}
- # Figure out of there are any objects we can automatically add as
- # dependencies.
- def autorequire(rel_catalog = nil)
- rel_catalog ||= catalog
- raise(Puppet::DevError, "You cannot add relationships without a catalog") unless rel_catalog
-
- reqs = []
- self.class.eachautorequire { |type, block|
- # Ignore any types we can't find, although that would be a bit odd.
- next unless typeobj = Puppet::Type.type(type)
-
- # Retrieve the list of names from the block.
- next unless list = self.instance_eval(&block)
- list = [list] unless list.is_a?(Array)
-
- # Collect the current prereqs
- list.each { |dep|
- obj = nil
- # Support them passing objects directly, to save some effort.
- unless dep.is_a? Puppet::Type
- # Skip autorequires that we aren't managing
- unless dep = rel_catalog.resource(type, dep)
- next
- end
- end
-
- reqs << Puppet::Relationship.new(dep, self)
- }
- }
+ @paramdoc = Hash.new { |hash,key|
+ key = key.intern if key.is_a?(String)
+ if hash.include?(key)
+ hash[key]
+ else
+ "Param Documentation for #{key} not found"
+ end
+ }
- reqs
- end
+ @doc ||= ""
- # Build the dependencies associated with an individual object.
- def builddepends
- # Handle the requires
- self.class.relationship_params.collect do |klass|
- if param = @parameters[klass.name]
- param.to_edges
- end
- end.flatten.reject { |r| r.nil? }
- end
+ end
- # Define the initial list of tags.
- def tags=(list)
- tag(self.class.name)
- tag(*list)
+ def self.to_s
+ if defined?(@name)
+ "Puppet::Type::#{@name.to_s.capitalize}"
+ else
+ super
end
+ end
- # Types (which map to resources in the languages) are entirely composed of
- # attribute value pairs. Generally, Puppet calls any of these things an
- # 'attribute', but these attributes always take one of three specific
- # forms: parameters, metaparams, or properties.
+ # Create a block to validate that our object is set up entirely. This will
+ # be run before the object is operated on.
+ def self.validate(&block)
+ define_method(:validate, &block)
+ #@validate = block
+ end
- # In naming methods, I have tried to consistently name the method so
- # that it is clear whether it operates on all attributes (thus has 'attr' in
- # the method name, or whether it operates on a specific type of attributes.
- attr_writer :title
- attr_writer :noop
+ # The catalog that this resource is stored in.
+ attr_accessor :catalog
- include Enumerable
+ # is the resource exported
+ attr_accessor :exported
- # class methods dealing with Type management
+ # is the resource virtual (it should not :-))
+ attr_accessor :virtual
- public
-
- # the Type class attribute accessors
- class << self
- attr_reader :name
- attr_accessor :self_refresh
- include Enumerable, Puppet::Util::ClassGen
- include Puppet::MetaType::Manager
+ # create a log at specified level
+ def log(msg)
- include Puppet::Util
- include Puppet::Util::Logging
- end
+ Puppet::Util::Log.create(
- # all of the variables that must be initialized for each subclass
- def self.initvars
- # all of the instances of this class
- @objects = Hash.new
- @aliases = Hash.new
+ :level => @parameters[:loglevel].value,
+ :message => msg,
- @defaults = {}
+ :source => self
+ )
+ end
- @parameters ||= []
- @validproperties = {}
- @properties = []
- @parameters = []
- @paramhash = {}
+ # instance methods related to instance intrinsics
+ # e.g., initialize and name
- @attr_aliases = {}
+ public
- @paramdoc = Hash.new { |hash,key|
- key = key.intern if key.is_a?(String)
- if hash.include?(key)
- hash[key]
- else
- "Param Documentation for #{key} not found"
- end
- }
+ attr_reader :original_parameters
- @doc ||= ""
+ # initialize the type instance
+ def initialize(resource)
+ raise Puppet::DevError, "Got TransObject instead of Resource or hash" if resource.is_a?(Puppet::TransObject)
+ resource = self.class.hash2resource(resource) unless resource.is_a?(Puppet::Resource)
- end
+ # The list of parameter/property instances.
+ @parameters = {}
- def self.to_s
- if defined?(@name)
- "Puppet::Type::#{@name.to_s.capitalize}"
- else
- super
- end
+ # Set the title first, so any failures print correctly.
+ if resource.type.to_s.downcase.to_sym == self.class.name
+ self.title = resource.title
+ else
+ # This should only ever happen for components
+ self.title = resource.ref
end
- # Create a block to validate that our object is set up entirely. This will
- # be run before the object is operated on.
- def self.validate(&block)
- define_method(:validate, &block)
- #@validate = block
+ [:file, :line, :catalog, :exported, :virtual].each do |getter|
+ setter = getter.to_s + "="
+ if val = resource.send(getter)
+ self.send(setter, val)
+ end
end
- # The catalog that this resource is stored in.
- attr_accessor :catalog
+ @tags = resource.tags
- # is the resource exported
- attr_accessor :exported
+ @original_parameters = resource.to_hash
- # is the resource virtual (it should not :-))
- attr_accessor :virtual
+ set_name(@original_parameters)
- # create a log at specified level
- def log(msg)
+ set_default(:provider)
- Puppet::Util::Log.create(
+ set_parameters(@original_parameters)
- :level => @parameters[:loglevel].value,
- :message => msg,
+ self.validate if self.respond_to?(:validate)
+ end
- :source => self
- )
- end
-
-
- # instance methods related to instance intrinsics
- # e.g., initialize and name
-
- public
-
- attr_reader :original_parameters
+ private
- # initialize the type instance
- def initialize(resource)
- raise Puppet::DevError, "Got TransObject instead of Resource or hash" if resource.is_a?(Puppet::TransObject)
- resource = self.class.hash2resource(resource) unless resource.is_a?(Puppet::Resource)
+ # Set our resource's name.
+ def set_name(hash)
+ self[name_var] = hash.delete(name_var) if name_var
+ end
- # The list of parameter/property instances.
- @parameters = {}
-
- # Set the title first, so any failures print correctly.
- if resource.type.to_s.downcase.to_sym == self.class.name
- self.title = resource.title
+ # Set all of the parameters from a hash, in the appropriate order.
+ def set_parameters(hash)
+ # Use the order provided by allattrs, but add in any
+ # extra attributes from the resource so we get failures
+ # on invalid attributes.
+ no_values = []
+ (self.class.allattrs + hash.keys).uniq.each do |attr|
+ begin
+ # Set any defaults immediately. This is mostly done so
+ # that the default provider is available for any other
+ # property validation.
+ if hash.has_key?(attr)
+ self[attr] = hash[attr]
else
- # This should only ever happen for components
- self.title = resource.ref
- end
-
- [:file, :line, :catalog, :exported, :virtual].each do |getter|
- setter = getter.to_s + "="
- if val = resource.send(getter)
- self.send(setter, val)
- end
- end
-
- @tags = resource.tags
-
- @original_parameters = resource.to_hash
-
- set_name(@original_parameters)
-
- set_default(:provider)
-
- set_parameters(@original_parameters)
-
- self.validate if self.respond_to?(:validate)
+ no_values << attr
+ end
+ rescue ArgumentError, Puppet::Error, TypeError
+ raise
+ rescue => detail
+ error = Puppet::DevError.new( "Could not set #{attr} on #{self.class.name}: #{detail}")
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
+ end
+ no_values.each do |attr|
+ set_default(attr)
+ end
+ end
+
+ public
+
+ # Set up all of our autorequires.
+ def finish
+ # Make sure all of our relationships are valid. Again, must be done
+ # when the entire catalog is instantiated.
+ self.class.relationship_params.collect do |klass|
+ if param = @parameters[klass.name]
+ param.validate_relationship
+ end
+ end.flatten.reject { |r| r.nil? }
+ end
+
+ # For now, leave the 'name' method functioning like it used to. Once 'title'
+ # works everywhere, I'll switch it.
+ def name
+ self[:name]
+ end
+
+ # Look up our parent in the catalog, if we have one.
+ def parent
+ return nil unless catalog
+
+ unless defined?(@parent)
+ if parents = catalog.adjacent(self, :direction => :in)
+ # We should never have more than one parent, so let's just ignore
+ # it if we happen to.
+ @parent = parents.shift
+ else
+ @parent = nil
+ end
end
+ @parent
+ end
- private
+ # Return the "type[name]" style reference.
+ def ref
+ "#{self.class.name.to_s.capitalize}[#{self.title}]"
+ end
- # Set our resource's name.
- def set_name(hash)
- self[name_var] = hash.delete(name_var) if name_var
- end
-
- # Set all of the parameters from a hash, in the appropriate order.
- def set_parameters(hash)
- # Use the order provided by allattrs, but add in any
- # extra attributes from the resource so we get failures
- # on invalid attributes.
- no_values = []
- (self.class.allattrs + hash.keys).uniq.each do |attr|
- begin
- # Set any defaults immediately. This is mostly done so
- # that the default provider is available for any other
- # property validation.
- if hash.has_key?(attr)
- self[attr] = hash[attr]
- else
- no_values << attr
- end
- rescue ArgumentError, Puppet::Error, TypeError
- raise
- rescue => detail
- error = Puppet::DevError.new( "Could not set #{attr} on #{self.class.name}: #{detail}")
- error.set_backtrace(detail.backtrace)
- raise error
- end
- end
- no_values.each do |attr|
- set_default(attr)
- end
- end
+ def self_refresh?
+ self.class.self_refresh
+ end
- public
+ # Mark that we're purging.
+ def purging
+ @purging = true
+ end
- # Set up all of our autorequires.
- def finish
- # Make sure all of our relationships are valid. Again, must be done
- # when the entire catalog is instantiated.
- self.class.relationship_params.collect do |klass|
- if param = @parameters[klass.name]
- param.validate_relationship
- end
- end.flatten.reject { |r| r.nil? }
+ # Is this resource being purged? Used by transactions to forbid
+ # deletion when there are dependencies.
+ def purging?
+ if defined?(@purging)
+ @purging
+ else
+ false
end
+ end
- # For now, leave the 'name' method functioning like it used to. Once 'title'
- # works everywhere, I'll switch it.
- def name
- self[:name]
+ # Retrieve the title of an object. If no title was set separately,
+ # then use the object's name.
+ def title
+ unless @title
+ if self.class.validparameter?(name_var)
+ @title = self[:name]
+ elsif self.class.validproperty?(name_var)
+ @title = self.should(name_var)
+ else
+ self.devfail "Could not find namevar #{name_var} for #{self.class.name}"
+ end
end
- # Look up our parent in the catalog, if we have one.
- def parent
- return nil unless catalog
+ @title
+ end
- unless defined?(@parent)
- if parents = catalog.adjacent(self, :direction => :in)
- # We should never have more than one parent, so let's just ignore
- # it if we happen to.
- @parent = parents.shift
- else
- @parent = nil
- end
- end
- @parent
- end
+ # convert to a string
+ def to_s
+ self.ref
+ end
- # Return the "type[name]" style reference.
- def ref
- "#{self.class.name.to_s.capitalize}[#{self.title}]"
- end
+ # Convert to a transportable object
+ def to_trans(ret = true)
+ trans = TransObject.new(self.title, self.class.name)
- def self_refresh?
- self.class.self_refresh
+ values = retrieve_resource
+ values.each do |name, value|
+ name = name.name if name.respond_to? :name
+ trans[name] = value
end
- # Mark that we're purging.
- def purging
- @purging = true
- end
+ @parameters.each do |name, param|
+ # Avoid adding each instance name twice
+ next if param.class.isnamevar? and param.value == self.title
- # Is this resource being purged? Used by transactions to forbid
- # deletion when there are dependencies.
- def purging?
- if defined?(@purging)
- @purging
- else
- false
- end
+ # We've already got property values
+ next if param.is_a?(Puppet::Property)
+ trans[name] = param.value
end
- # Retrieve the title of an object. If no title was set separately,
- # then use the object's name.
- def title
- unless @title
- if self.class.validparameter?(name_var)
- @title = self[:name]
- elsif self.class.validproperty?(name_var)
- @title = self.should(name_var)
- else
- self.devfail "Could not find namevar #{name_var} for #{self.class.name}"
- end
- end
+ trans.tags = self.tags
- @title
- end
+ # FIXME I'm currently ignoring 'parent' and 'path'
- # convert to a string
- def to_s
- self.ref
- end
+ trans
+ end
- # Convert to a transportable object
- def to_trans(ret = true)
- trans = TransObject.new(self.title, self.class.name)
-
- values = retrieve_resource
- values.each do |name, value|
- name = name.name if name.respond_to? :name
- trans[name] = value
- end
+ def to_resource
+ # this 'type instance' versus 'resource' distinction seems artificial
+ # I'd like to see it collapsed someday ~JW
+ self.to_trans.to_resource
+ end
- @parameters.each do |name, param|
- # Avoid adding each instance name twice
- next if param.class.isnamevar? and param.value == self.title
-
- # We've already got property values
- next if param.is_a?(Puppet::Property)
- trans[name] = param.value
- end
-
- trans.tags = self.tags
-
- # FIXME I'm currently ignoring 'parent' and 'path'
-
- trans
- end
-
- def to_resource
- # this 'type instance' versus 'resource' distinction seems artificial
- # I'd like to see it collapsed someday ~JW
- self.to_trans.to_resource
- end
-
- %w{exported virtual}.each do |m|
- define_method(m+"?") do
- self.send(m)
- end
+ %w{exported virtual}.each do |m|
+ define_method(m+"?") do
+ self.send(m)
end
+ end
end
end
diff --git a/lib/puppet/type/augeas.rb b/lib/puppet/type/augeas.rb
index 5a6fb54de..7fcfdd7a3 100644
--- a/lib/puppet/type/augeas.rb
+++ b/lib/puppet/type/augeas.rb
@@ -18,166 +18,166 @@
# Author: Bryan Kearney <bkearney@redhat.com>
Puppet::Type.newtype(:augeas) do
- include Puppet::Util
-
- feature :parse_commands, "Parse the command string"
- feature :need_to_run?, "If the command should run"
- feature :execute_changes, "Actually make the changes"
-
- @doc = "Apply the changes (single or array of changes) to the filesystem
- via the augeas tool.
-
- Requires:
- - augeas to be installed (http://www.augeas.net)
- - ruby-augeas bindings
-
- Sample usage with a string::
-
- augeas{\"test1\" :
- context => \"/files/etc/sysconfig/firstboot\",
- changes => \"set RUN_FIRSTBOOT YES\",
- onlyif => \"match other_value size > 0\",
- }
-
- Sample usage with an array and custom lenses::
-
- augeas{\"jboss_conf\":
- context => \"/files\",
- changes => [
- \"set /etc/jbossas/jbossas.conf/JBOSS_IP $ipaddress\",
- \"set /etc/jbossas/jbossas.conf/JAVA_HOME /usr\"
- ],
- load_path => \"$/usr/share/jbossas/lenses\",
- }
-
- "
-
- newparam (:name) do
- desc "The name of this task. Used for uniqueness"
- isnamevar
- end
-
- newparam (:context) do
- desc "Optional context path. This value is prepended to the paths of all changes if the path is relative. If INCL is set, defaults to '/files' + INCL, otherwise the empty string"
- defaultto ""
- munge do |value|
- if value.empty? and resource[:incl]
- "/files" + resource[:incl]
- else
- value
- end
- end
- end
-
- newparam (:onlyif) do
- desc "Optional augeas command and comparisons to control the execution of this type.
- Supported onlyif syntax::
-
- get [AUGEAS_PATH] [COMPARATOR] [STRING]
- match [MATCH_PATH] size [COMPARATOR] [INT]
- match [MATCH_PATH] include [STRING]
- match [MATCH_PATH] not_include [STRING]
- match [MATCH_PATH] == [AN_ARRAY]
- match [MATCH_PATH] != [AN_ARRAY]
-
- where::
-
- AUGEAS_PATH is a valid path scoped by the context
- MATCH_PATH is a valid match synatx scoped by the context
- COMPARATOR is in the set [> >= != == <= <]
- STRING is a string
- INT is a number
- AN_ARRAY is in the form ['a string', 'another']"
- defaultto ""
- end
-
-
- newparam(:changes) do
- desc "The changes which should be applied to the filesystem. This
- can be either a string which contains a command or an array of commands.
- Commands supported are::
-
- set [PATH] [VALUE] Sets the value VALUE at loction PATH
- rm [PATH] Removes the node at location PATH
- remove [PATH] Synonym for rm
- clear [PATH] Keeps the node at PATH, but removes the value.
- ins [LABEL] [WHERE] [PATH]
- Inserts an empty node LABEL either [WHERE={before|after}] PATH.
- insert [LABEL] [WHERE] [PATH]
- Synonym for ins
-
- If the parameter 'context' is set that value is prepended to PATH"
- end
-
-
- newparam(:root) do
- desc "A file system path; all files loaded by Augeas are loaded underneath ROOT"
- defaultto "/"
- end
-
- newparam(:load_path) do
- desc "Optional colon separated list of directories; these directories are searched for schema definitions"
- defaultto ""
- end
-
- newparam(:force) do
- desc "Optional command to force the augeas type to execute even if it thinks changes
- will not be made. This does not overide the only setting. If onlyif is set, then the
- foce setting will not override that result"
-
- defaultto false
- end
-
- newparam(:type_check) do
- desc "Set to true if augeas should perform typechecking. Optional, defaults to false"
- newvalues(:true, :false)
-
- defaultto :false
+ include Puppet::Util
+
+ feature :parse_commands, "Parse the command string"
+ feature :need_to_run?, "If the command should run"
+ feature :execute_changes, "Actually make the changes"
+
+ @doc = "Apply the changes (single or array of changes) to the filesystem
+ via the augeas tool.
+
+ Requires:
+ - augeas to be installed (http://www.augeas.net)
+ - ruby-augeas bindings
+
+ Sample usage with a string::
+
+ augeas{\"test1\" :
+ context => \"/files/etc/sysconfig/firstboot\",
+ changes => \"set RUN_FIRSTBOOT YES\",
+ onlyif => \"match other_value size > 0\",
+ }
+
+ Sample usage with an array and custom lenses::
+
+ augeas{\"jboss_conf\":
+ context => \"/files\",
+ changes => [
+ \"set /etc/jbossas/jbossas.conf/JBOSS_IP $ipaddress\",
+ \"set /etc/jbossas/jbossas.conf/JAVA_HOME /usr\"
+ ],
+ load_path => \"$/usr/share/jbossas/lenses\",
+ }
+
+ "
+
+ newparam (:name) do
+ desc "The name of this task. Used for uniqueness"
+ isnamevar
+ end
+
+ newparam (:context) do
+ desc "Optional context path. This value is prepended to the paths of all changes if the path is relative. If INCL is set, defaults to '/files' + INCL, otherwise the empty string"
+ defaultto ""
+ munge do |value|
+ if value.empty? and resource[:incl]
+ "/files" + resource[:incl]
+ else
+ value
+ end
end
+ end
+
+ newparam (:onlyif) do
+ desc "Optional augeas command and comparisons to control the execution of this type.
+ Supported onlyif syntax::
+
+ get [AUGEAS_PATH] [COMPARATOR] [STRING]
+ match [MATCH_PATH] size [COMPARATOR] [INT]
+ match [MATCH_PATH] include [STRING]
+ match [MATCH_PATH] not_include [STRING]
+ match [MATCH_PATH] == [AN_ARRAY]
+ match [MATCH_PATH] != [AN_ARRAY]
+
+ where::
+
+ AUGEAS_PATH is a valid path scoped by the context
+ MATCH_PATH is a valid match synatx scoped by the context
+ COMPARATOR is in the set [> >= != == <= <]
+ STRING is a string
+ INT is a number
+ AN_ARRAY is in the form ['a string', 'another']"
+ defaultto ""
+ end
+
+
+ newparam(:changes) do
+ desc "The changes which should be applied to the filesystem. This
+ can be either a string which contains a command or an array of commands.
+ Commands supported are::
+
+ set [PATH] [VALUE] Sets the value VALUE at loction PATH
+ rm [PATH] Removes the node at location PATH
+ remove [PATH] Synonym for rm
+ clear [PATH] Keeps the node at PATH, but removes the value.
+ ins [LABEL] [WHERE] [PATH]
+ Inserts an empty node LABEL either [WHERE={before|after}] PATH.
+ insert [LABEL] [WHERE] [PATH]
+ Synonym for ins
+
+ If the parameter 'context' is set that value is prepended to PATH"
+ end
+
+
+ newparam(:root) do
+ desc "A file system path; all files loaded by Augeas are loaded underneath ROOT"
+ defaultto "/"
+ end
+
+ newparam(:load_path) do
+ desc "Optional colon separated list of directories; these directories are searched for schema definitions"
+ defaultto ""
+ end
+
+ newparam(:force) do
+ desc "Optional command to force the augeas type to execute even if it thinks changes
+ will not be made. This does not overide the only setting. If onlyif is set, then the
+ foce setting will not override that result"
+
+ defaultto false
+ end
+
+ newparam(:type_check) do
+ desc "Set to true if augeas should perform typechecking. Optional, defaults to false"
+ newvalues(:true, :false)
+
+ defaultto :false
+ end
+
+ newparam(:lens) do
+ desc "Use a specific lens, e.g. 'Hosts.lns'. When this parameter is set, you must also set the incl parameter to indicate which file to load. Only that file will be loaded, which greatly speeds up execution of the type"
+ end
+
+ newparam(:incl) do
+ desc "Load only a specific file, e.g. '/etc/hosts'. When this parameter is set, you must also set the lens parameter to indicate which lens to use."
+ end
+
+ validate do
+ has_lens = !self[:lens].nil?
+ has_incl = !self[:incl].nil?
+ self.fail "You must specify both the lens and incl parameters, or neither" if has_lens != has_incl
+ end
+
+ # This is the acutal meat of the code. It forces
+ # augeas to be run and fails or not based on the augeas return
+ # code.
+ newproperty(:returns) do |property|
+ include Puppet::Util
+ desc "The expected return code from the augeas command. Should not be set"
- newparam(:lens) do
- desc "Use a specific lens, e.g. 'Hosts.lns'. When this parameter is set, you must also set the incl parameter to indicate which file to load. Only that file will be loaded, which greatly speeds up execution of the type"
- end
+ defaultto 0
- newparam(:incl) do
- desc "Load only a specific file, e.g. '/etc/hosts'. When this parameter is set, you must also set the lens parameter to indicate which lens to use."
+ # Make output a bit prettier
+ def change_to_s(currentvalue, newvalue)
+ "executed successfully"
end
- validate do
- has_lens = !self[:lens].nil?
- has_incl = !self[:incl].nil?
- self.fail "You must specify both the lens and incl parameters, or neither" if has_lens != has_incl
+ # if the onlyif resource is provided, then the value is parsed.
+ # a return value of 0 will stop exection because it matches the
+ # default value.
+ def retrieve
+ if @resource.provider.need_to_run?()
+ :need_to_run
+ else
+ 0
+ end
end
- # This is the acutal meat of the code. It forces
- # augeas to be run and fails or not based on the augeas return
- # code.
- newproperty(:returns) do |property|
- include Puppet::Util
- desc "The expected return code from the augeas command. Should not be set"
-
- defaultto 0
-
- # Make output a bit prettier
- def change_to_s(currentvalue, newvalue)
- "executed successfully"
- end
-
- # if the onlyif resource is provided, then the value is parsed.
- # a return value of 0 will stop exection because it matches the
- # default value.
- def retrieve
- if @resource.provider.need_to_run?()
- :need_to_run
- else
- 0
- end
- end
-
- # Actually execute the command.
- def sync
- @resource.provider.execute_changes
- end
+ # Actually execute the command.
+ def sync
+ @resource.provider.execute_changes
end
+ end
end
diff --git a/lib/puppet/type/component.rb b/lib/puppet/type/component.rb
index 9e885233c..c8c09409b 100644
--- a/lib/puppet/type/component.rb
+++ b/lib/puppet/type/component.rb
@@ -4,82 +4,82 @@ require 'puppet/type'
require 'puppet/transaction'
Puppet::Type.newtype(:component) do
- include Enumerable
+ include Enumerable
- newparam(:name) do
- desc "The name of the component. Generally optional."
- isnamevar
- end
+ newparam(:name) do
+ desc "The name of the component. Generally optional."
+ isnamevar
+ end
- # Override how parameters are handled so that we support the extra
- # parameters that are used with defined resource types.
- def [](param)
- return super if self.class.valid_parameter?(param)
- @extra_parameters[param.to_sym]
- end
+ # Override how parameters are handled so that we support the extra
+ # parameters that are used with defined resource types.
+ def [](param)
+ return super if self.class.valid_parameter?(param)
+ @extra_parameters[param.to_sym]
+ end
- # Override how parameters are handled so that we support the extra
- # parameters that are used with defined resource types.
- def []=(param, value)
- return super if self.class.valid_parameter?(param)
- @extra_parameters[param.to_sym] = value
- end
+ # Override how parameters are handled so that we support the extra
+ # parameters that are used with defined resource types.
+ def []=(param, value)
+ return super if self.class.valid_parameter?(param)
+ @extra_parameters[param.to_sym] = value
+ end
- # Initialize a new component
- def initialize(*args)
- @extra_parameters = {}
- super
+ # Initialize a new component
+ def initialize(*args)
+ @extra_parameters = {}
+ super
- catalog.alias(self, ref) if catalog and ! catalog.resource(ref)
- end
+ catalog.alias(self, ref) if catalog and ! catalog.resource(ref)
+ end
- # Component paths are special because they function as containers.
- def pathbuilder
- if reference.type == "Class"
- # 'main' is the top class, so we want to see '//' instead of
- # its name.
- if reference.title.to_s.downcase == "main"
- myname = ""
- else
- myname = reference.title
- end
- else
- myname = reference.to_s
- end
- if p = self.parent
- return [p.pathbuilder, myname]
- else
- return [myname]
- end
+ # Component paths are special because they function as containers.
+ def pathbuilder
+ if reference.type == "Class"
+ # 'main' is the top class, so we want to see '//' instead of
+ # its name.
+ if reference.title.to_s.downcase == "main"
+ myname = ""
+ else
+ myname = reference.title
+ end
+ else
+ myname = reference.to_s
end
-
- def ref
- reference.to_s
+ if p = self.parent
+ return [p.pathbuilder, myname]
+ else
+ return [myname]
end
+ end
- # We want our title to just be the whole reference, rather than @title.
- def title
- ref
- end
+ def ref
+ reference.to_s
+ end
- def title=(str)
- @reference = Puppet::Resource.new(str)
- end
+ # We want our title to just be the whole reference, rather than @title.
+ def title
+ ref
+ end
- def refresh
- catalog.adjacent(self).each do |child|
- if child.respond_to?(:refresh)
- child.refresh
- child.log "triggering #{:refresh}"
- end
- end
- end
+ def title=(str)
+ @reference = Puppet::Resource.new(str)
+ end
- def to_s
- reference.to_s
+ def refresh
+ catalog.adjacent(self).each do |child|
+ if child.respond_to?(:refresh)
+ child.refresh
+ child.log "triggering #{:refresh}"
+ end
end
+ end
+
+ def to_s
+ reference.to_s
+ end
- private
+ private
- attr_reader :reference
+ attr_reader :reference
end
diff --git a/lib/puppet/type/computer.rb b/lib/puppet/type/computer.rb
index b27d8a481..86a30be27 100644
--- a/lib/puppet/type/computer.rb
+++ b/lib/puppet/type/computer.rb
@@ -1,62 +1,62 @@
Puppet::Type.newtype(:computer) do
- @doc = "Computer object management using DirectoryService
- on OS X.
+ @doc = "Computer object management using DirectoryService
+ on OS X.
- Note that these are distinctly different kinds of objects to 'hosts',
- as they require a MAC address and can have all sorts of policy attached to
- them.
+ Note that these are distinctly different kinds of objects to 'hosts',
+ as they require a MAC address and can have all sorts of policy attached to
+ them.
- This provider only manages Computer objects in the local directory service
- domain, not in remote directories.
+ This provider only manages Computer objects in the local directory service
+ domain, not in remote directories.
- If you wish to manage /etc/hosts on Mac OS X, then simply use the host
- type as per other platforms.
+ If you wish to manage /etc/hosts on Mac OS X, then simply use the host
+ type as per other platforms.
- This type primarily exists to create localhost Computer objects that MCX
- policy can then be attached to."
+ This type primarily exists to create localhost Computer objects that MCX
+ policy can then be attached to."
- # ensurable
+ # ensurable
- # We autorequire the computer object in case it is being managed at the
- # file level by Puppet.
+ # We autorequire the computer object in case it is being managed at the
+ # file level by Puppet.
- autorequire(:file) do
- if self[:name]
- "/var/db/dslocal/nodes/Default/computers/#{self[:name]}.plist"
- else
- nil
- end
+ autorequire(:file) do
+ if self[:name]
+ "/var/db/dslocal/nodes/Default/computers/#{self[:name]}.plist"
+ else
+ nil
end
-
- newproperty(:ensure, :parent => Puppet::Property::Ensure) do
- desc "Control the existences of this computer record. Set this attribute to
- ``present`` to ensure the computer record exists. Set it to ``absent``
- to delete any computer records with this name"
- newvalue(:present) do
- provider.create
- end
-
- newvalue(:absent) do
- provider.delete
- end
+ end
+
+ newproperty(:ensure, :parent => Puppet::Property::Ensure) do
+ desc "Control the existences of this computer record. Set this attribute to
+ ``present`` to ensure the computer record exists. Set it to ``absent``
+ to delete any computer records with this name"
+ newvalue(:present) do
+ provider.create
end
- newparam(:name) do
- desc "The authoritative 'short' name of the computer record."
- isnamevar
+ newvalue(:absent) do
+ provider.delete
end
+ end
- newparam(:realname) do
- desc "The 'long' name of the computer record."
- end
+ newparam(:name) do
+ desc "The authoritative 'short' name of the computer record."
+ isnamevar
+ end
- newproperty(:en_address) do
- desc "The MAC address of the primary network interface. Must match en0."
- end
+ newparam(:realname) do
+ desc "The 'long' name of the computer record."
+ end
- newproperty(:ip_address) do
- desc "The IP Address of the Computer object."
- end
+ newproperty(:en_address) do
+ desc "The MAC address of the primary network interface. Must match en0."
+ end
+
+ newproperty(:ip_address) do
+ desc "The IP Address of the Computer object."
+ end
end
diff --git a/lib/puppet/type/cron.rb b/lib/puppet/type/cron.rb
index 5a2533289..b3f5e608d 100755
--- a/lib/puppet/type/cron.rb
+++ b/lib/puppet/type/cron.rb
@@ -3,411 +3,411 @@ require 'facter'
require 'puppet/util/filetype'
Puppet::Type.newtype(:cron) do
- @doc = "Installs and manages cron jobs. All fields except the command
- and the user are optional, although specifying no periodic
- fields would result in the command being executed every
- minute. While the name of the cron job is not part of the actual
- job, it is used by Puppet to store and retrieve it.
-
- If you specify a cron job that matches an existing job in every way
- except name, then the jobs will be considered equivalent and the
- new name will be permanently associated with that job. Once this
- association is made and synced to disk, you can then manage the job
- normally (e.g., change the schedule of the job).
-
- Example::
-
- cron { logrotate:
- command => \"/usr/sbin/logrotate\",
- user => root,
- hour => 2,
- minute => 0
- }
-
- Note that all cron values can be specified as an array of values::
-
- cron { logrotate:
- command => \"/usr/sbin/logrotate\",
- user => root,
- hour => [2, 4]
- }
-
- Or using ranges, or the step syntax ``*/2`` (although there's no guarantee that
- your ``cron`` daemon supports it)::
-
- cron { logrotate:
- command => \"/usr/sbin/logrotate\",
- user => root,
- hour => ['2-4'],
- minute => '*/10'
- }
- "
- ensurable
-
- # A base class for all of the Cron parameters, since they all have
- # similar argument checking going on.
- class CronParam < Puppet::Property
- class << self
- attr_accessor :boundaries, :default
- end
-
- # We have to override the parent method, because we consume the entire
- # "should" array
- def insync?(is)
- if @should
- self.is_to_s(is) == self.should_to_s
- else
- true
- end
- end
-
- # A method used to do parameter input handling. Converts integers
- # in string form to actual integers, and returns the value if it's
- # an integer or false if it's just a normal string.
- def numfix(num)
- if num =~ /^\d+$/
- return num.to_i
- elsif num.is_a?(Integer)
- return num
- else
- return false
- end
- end
-
- # Verify that a number is within the specified limits. Return the
- # number if it is, or false if it is not.
- def limitcheck(num, lower, upper)
- (num >= lower and num <= upper) && num
- end
-
- # Verify that a value falls within the specified array. Does case
- # insensitive matching, and supports matching either the entire word
- # or the first three letters of the word.
- def alphacheck(value, ary)
- tmp = value.downcase
-
- # If they specified a shortened version of the name, then see
- # if we can lengthen it (e.g., mon => monday).
- if tmp.length == 3
- ary.each_with_index { |name, index|
- if name =~ /#{tmp}/i
- return index
- end
- }
- else
- return ary.index(tmp) if ary.include?(tmp)
- end
-
- false
- end
+ @doc = "Installs and manages cron jobs. All fields except the command
+ and the user are optional, although specifying no periodic
+ fields would result in the command being executed every
+ minute. While the name of the cron job is not part of the actual
+ job, it is used by Puppet to store and retrieve it.
+
+ If you specify a cron job that matches an existing job in every way
+ except name, then the jobs will be considered equivalent and the
+ new name will be permanently associated with that job. Once this
+ association is made and synced to disk, you can then manage the job
+ normally (e.g., change the schedule of the job).
+
+ Example::
+
+ cron { logrotate:
+ command => \"/usr/sbin/logrotate\",
+ user => root,
+ hour => 2,
+ minute => 0
+ }
+
+ Note that all cron values can be specified as an array of values::
+
+ cron { logrotate:
+ command => \"/usr/sbin/logrotate\",
+ user => root,
+ hour => [2, 4]
+ }
+
+ Or using ranges, or the step syntax ``*/2`` (although there's no guarantee that
+ your ``cron`` daemon supports it)::
+
+ cron { logrotate:
+ command => \"/usr/sbin/logrotate\",
+ user => root,
+ hour => ['2-4'],
+ minute => '*/10'
+ }
+ "
+ ensurable
+
+ # A base class for all of the Cron parameters, since they all have
+ # similar argument checking going on.
+ class CronParam < Puppet::Property
+ class << self
+ attr_accessor :boundaries, :default
+ end
- def should_to_s(newvalue = @should)
- if newvalue
- newvalue = [newvalue] unless newvalue.is_a?(Array)
- if self.name == :command or newvalue[0].is_a? Symbol
- newvalue[0]
- else
- newvalue.join(",")
- end
- else
- nil
- end
- end
+ # We have to override the parent method, because we consume the entire
+ # "should" array
+ def insync?(is)
+ if @should
+ self.is_to_s(is) == self.should_to_s
+ else
+ true
+ end
+ end
- def is_to_s(currentvalue = @is)
- if currentvalue
- return currentvalue unless currentvalue.is_a?(Array)
-
- if self.name == :command or currentvalue[0].is_a? Symbol
- currentvalue[0]
- else
- currentvalue.join(",")
- end
- else
- nil
- end
- end
+ # A method used to do parameter input handling. Converts integers
+ # in string form to actual integers, and returns the value if it's
+ # an integer or false if it's just a normal string.
+ def numfix(num)
+ if num =~ /^\d+$/
+ return num.to_i
+ elsif num.is_a?(Integer)
+ return num
+ else
+ return false
+ end
+ end
- def should
- if @should and @should[0] == :absent
- :absent
- else
- @should
- end
- end
+ # Verify that a number is within the specified limits. Return the
+ # number if it is, or false if it is not.
+ def limitcheck(num, lower, upper)
+ (num >= lower and num <= upper) && num
+ end
- def should=(ary)
- super
- @should.flatten!
- end
+ # Verify that a value falls within the specified array. Does case
+ # insensitive matching, and supports matching either the entire word
+ # or the first three letters of the word.
+ def alphacheck(value, ary)
+ tmp = value.downcase
+
+ # If they specified a shortened version of the name, then see
+ # if we can lengthen it (e.g., mon => monday).
+ if tmp.length == 3
+ ary.each_with_index { |name, index|
+ if name =~ /#{tmp}/i
+ return index
+ end
+ }
+ else
+ return ary.index(tmp) if ary.include?(tmp)
+ end
- # The method that does all of the actual parameter value
- # checking; called by all of the +param<name>=+ methods.
- # Requires the value, type, and bounds, and optionally supports
- # a boolean of whether to do alpha checking, and if so requires
- # the ary against which to do the checking.
- munge do |value|
- # Support 'absent' as a value, so that they can remove
- # a value
- if value == "absent" or value == :absent
- return :absent
- end
-
- # Allow the */2 syntax
- if value =~ /^\*\/[0-9]+$/
- return value
- end
-
- # Allow ranges
- if value =~ /^[0-9]+-[0-9]+$/
- return value
- end
-
- # Allow ranges + */2
- if value =~ /^[0-9]+-[0-9]+\/[0-9]+$/
- return value
- end
-
- if value == "*"
- return value
- end
-
- return value unless self.class.boundaries
- lower, upper = self.class.boundaries
- retval = nil
- if num = numfix(value)
- retval = limitcheck(num, lower, upper)
- elsif respond_to?(:alpha)
- # If it has an alpha method defined, then we check
- # to see if our value is in that list and if so we turn
- # it into a number
- retval = alphacheck(value, alpha)
- end
-
- if retval
- return retval.to_s
- else
- self.fail "#{value} is not a valid #{self.class.name}"
- end
- end
+ false
end
- # Somewhat uniquely, this property does not actually change anything -- it
- # just calls +@resource.sync+, which writes out the whole cron tab for
- # the user in question. There is no real way to change individual cron
- # jobs without rewriting the entire cron file.
- #
- # Note that this means that managing many cron jobs for a given user
- # could currently result in multiple write sessions for that user.
- newproperty(:command, :parent => CronParam) do
- desc "The command to execute in the cron job. The environment
- provided to the command varies by local system rules, and it is
- best to always provide a fully qualified command. The user's
- profile is not sourced when the command is run, so if the
- user's environment is desired it should be sourced manually.
-
- All cron parameters support ``absent`` as a value; this will
- remove any existing values for that field."
-
- def retrieve
- return_value = super
- return_value = return_value[0] if return_value && return_value.is_a?(Array)
-
- return_value
- end
-
- def should
- if @should
- if @should.is_a? Array
- @should[0]
- else
- devfail "command is not an array"
- end
- else
- nil
- end
+ def should_to_s(newvalue = @should)
+ if newvalue
+ newvalue = [newvalue] unless newvalue.is_a?(Array)
+ if self.name == :command or newvalue[0].is_a? Symbol
+ newvalue[0]
+ else
+ newvalue.join(",")
end
+ else
+ nil
+ end
end
- newproperty(:special) do
- desc "Special schedules only supported on FreeBSD."
+ def is_to_s(currentvalue = @is)
+ if currentvalue
+ return currentvalue unless currentvalue.is_a?(Array)
- def specials
- %w{reboot yearly annually monthly weekly daily midnight hourly}
- end
-
- validate do |value|
- raise ArgumentError, "Invalid special schedule #{value.inspect}" unless specials.include?(value)
+ if self.name == :command or currentvalue[0].is_a? Symbol
+ currentvalue[0]
+ else
+ currentvalue.join(",")
end
+ else
+ nil
+ end
end
- newproperty(:minute, :parent => CronParam) do
- self.boundaries = [0, 59]
- desc "The minute at which to run the cron job.
- Optional; if specified, must be between 0 and 59, inclusive."
+ def should
+ if @should and @should[0] == :absent
+ :absent
+ else
+ @should
+ end
end
- newproperty(:hour, :parent => CronParam) do
- self.boundaries = [0, 23]
- desc "The hour at which to run the cron job. Optional;
- if specified, must be between 0 and 23, inclusive."
+ def should=(ary)
+ super
+ @should.flatten!
end
- newproperty(:weekday, :parent => CronParam) do
- def alpha
- %w{sunday monday tuesday wednesday thursday friday saturday}
- end
- self.boundaries = [0, 7]
- desc "The weekday on which to run the command.
- Optional; if specified, must be between 0 and 7, inclusive, with
- 0 (or 7) being Sunday, or must be the name of the day (e.g., Tuesday)."
+ # The method that does all of the actual parameter value
+ # checking; called by all of the +param<name>=+ methods.
+ # Requires the value, type, and bounds, and optionally supports
+ # a boolean of whether to do alpha checking, and if so requires
+ # the ary against which to do the checking.
+ munge do |value|
+ # Support 'absent' as a value, so that they can remove
+ # a value
+ if value == "absent" or value == :absent
+ return :absent
+ end
+
+ # Allow the */2 syntax
+ if value =~ /^\*\/[0-9]+$/
+ return value
+ end
+
+ # Allow ranges
+ if value =~ /^[0-9]+-[0-9]+$/
+ return value
+ end
+
+ # Allow ranges + */2
+ if value =~ /^[0-9]+-[0-9]+\/[0-9]+$/
+ return value
+ end
+
+ if value == "*"
+ return value
+ end
+
+ return value unless self.class.boundaries
+ lower, upper = self.class.boundaries
+ retval = nil
+ if num = numfix(value)
+ retval = limitcheck(num, lower, upper)
+ elsif respond_to?(:alpha)
+ # If it has an alpha method defined, then we check
+ # to see if our value is in that list and if so we turn
+ # it into a number
+ retval = alphacheck(value, alpha)
+ end
+
+ if retval
+ return retval.to_s
+ else
+ self.fail "#{value} is not a valid #{self.class.name}"
+ end
end
-
- newproperty(:month, :parent => CronParam) do
- def alpha
- %w{january february march april may june july
- august september october november december}
- end
- self.boundaries = [1, 12]
- desc "The month of the year. Optional; if specified
- must be between 1 and 12 or the month name (e.g., December)."
- end
-
- newproperty(:monthday, :parent => CronParam) do
- self.boundaries = [1, 31]
- desc "The day of the month on which to run the
- command. Optional; if specified, must be between 1 and 31."
+ end
+
+ # Somewhat uniquely, this property does not actually change anything -- it
+ # just calls +@resource.sync+, which writes out the whole cron tab for
+ # the user in question. There is no real way to change individual cron
+ # jobs without rewriting the entire cron file.
+ #
+ # Note that this means that managing many cron jobs for a given user
+ # could currently result in multiple write sessions for that user.
+ newproperty(:command, :parent => CronParam) do
+ desc "The command to execute in the cron job. The environment
+ provided to the command varies by local system rules, and it is
+ best to always provide a fully qualified command. The user's
+ profile is not sourced when the command is run, so if the
+ user's environment is desired it should be sourced manually.
+
+ All cron parameters support ``absent`` as a value; this will
+ remove any existing values for that field."
+
+ def retrieve
+ return_value = super
+ return_value = return_value[0] if return_value && return_value.is_a?(Array)
+
+ return_value
end
- newproperty(:environment) do
- desc "Any environment settings associated with this cron job. They
- will be stored between the header and the job in the crontab. There
- can be no guarantees that other, earlier settings will not also
- affect a given cron job.
-
-
- Also, Puppet cannot automatically determine whether an existing,
- unmanaged environment setting is associated with a given cron
- job. If you already have cron jobs with environment settings,
- then Puppet will keep those settings in the same place in the file,
- but will not associate them with a specific job.
-
- Settings should be specified exactly as they should appear in
- the crontab, e.g., ``PATH=/bin:/usr/bin:/usr/sbin``."
-
- validate do |value|
- unless value =~ /^\s*(\w+)\s*=\s*(.*)\s*$/ or value == :absent or value == "absent"
- raise ArgumentError, "Invalid environment setting #{value.inspect}"
- end
- end
-
- def insync?(is)
- if is.is_a? Array
- return is.sort == @should.sort
- else
- return is == @should
- end
- end
-
- def is_to_s(newvalue)
- if newvalue
- if newvalue.is_a?(Array)
- newvalue.join(",")
- else
- newvalue
- end
- else
- nil
- end
- end
-
- def should
- @should
- end
-
- def should_to_s(newvalue = @should)
- if newvalue
- newvalue.join(",")
- else
- nil
- end
+ def should
+ if @should
+ if @should.is_a? Array
+ @should[0]
+ else
+ devfail "command is not an array"
end
+ else
+ nil
+ end
end
+ end
- newparam(:name) do
- desc "The symbolic name of the cron job. This name
- is used for human reference only and is generated automatically
- for cron jobs found on the system. This generally won't
- matter, as Puppet will do its best to match existing cron jobs
- against specified jobs (and Puppet adds a comment to cron jobs it adds), but it is at least possible that converting from
- unmanaged jobs to managed jobs might require manual
- intervention."
+ newproperty(:special) do
+ desc "Special schedules only supported on FreeBSD."
- isnamevar
+ def specials
+ %w{reboot yearly annually monthly weekly daily midnight hourly}
end
- newproperty(:user) do
- desc "The user to run the command as. This user must
- be allowed to run cron jobs, which is not currently checked by
- Puppet.
+ validate do |value|
+ raise ArgumentError, "Invalid special schedule #{value.inspect}" unless specials.include?(value)
+ end
+ end
+
+ newproperty(:minute, :parent => CronParam) do
+ self.boundaries = [0, 59]
+ desc "The minute at which to run the cron job.
+ Optional; if specified, must be between 0 and 59, inclusive."
+ end
+
+ newproperty(:hour, :parent => CronParam) do
+ self.boundaries = [0, 23]
+ desc "The hour at which to run the cron job. Optional;
+ if specified, must be between 0 and 23, inclusive."
+ end
+
+ newproperty(:weekday, :parent => CronParam) do
+ def alpha
+ %w{sunday monday tuesday wednesday thursday friday saturday}
+ end
+ self.boundaries = [0, 7]
+ desc "The weekday on which to run the command.
+ Optional; if specified, must be between 0 and 7, inclusive, with
+ 0 (or 7) being Sunday, or must be the name of the day (e.g., Tuesday)."
+ end
+
+ newproperty(:month, :parent => CronParam) do
+ def alpha
+ %w{january february march april may june july
+ august september october november december}
+ end
+ self.boundaries = [1, 12]
+ desc "The month of the year. Optional; if specified
+ must be between 1 and 12 or the month name (e.g., December)."
+ end
+
+ newproperty(:monthday, :parent => CronParam) do
+ self.boundaries = [1, 31]
+ desc "The day of the month on which to run the
+ command. Optional; if specified, must be between 1 and 31."
+ end
+
+ newproperty(:environment) do
+ desc "Any environment settings associated with this cron job. They
+ will be stored between the header and the job in the crontab. There
+ can be no guarantees that other, earlier settings will not also
+ affect a given cron job.
+
+
+ Also, Puppet cannot automatically determine whether an existing,
+ unmanaged environment setting is associated with a given cron
+ job. If you already have cron jobs with environment settings,
+ then Puppet will keep those settings in the same place in the file,
+ but will not associate them with a specific job.
+
+ Settings should be specified exactly as they should appear in
+ the crontab, e.g., ``PATH=/bin:/usr/bin:/usr/sbin``."
+
+ validate do |value|
+ unless value =~ /^\s*(\w+)\s*=\s*(.*)\s*$/ or value == :absent or value == "absent"
+ raise ArgumentError, "Invalid environment setting #{value.inspect}"
+ end
+ end
- The user defaults to whomever Puppet is running as."
+ def insync?(is)
+ if is.is_a? Array
+ return is.sort == @should.sort
+ else
+ return is == @should
+ end
+ end
- defaultto { Etc.getpwuid(Process.uid).name || "root" }
+ def is_to_s(newvalue)
+ if newvalue
+ if newvalue.is_a?(Array)
+ newvalue.join(",")
+ else
+ newvalue
+ end
+ else
+ nil
+ end
end
- newproperty(:target) do
- desc "Where the cron job should be stored. For crontab-style
- entries this is the same as the user and defaults that way.
- Other providers default accordingly."
-
- defaultto {
- if provider.is_a?(@resource.class.provider(:crontab))
- if val = @resource.should(:user)
- val
- else
- raise ArgumentError,
- "You must provide a user with crontab entries"
- end
- elsif provider.class.ancestors.include?(Puppet::Provider::ParsedFile)
- provider.class.default_target
- else
- nil
- end
- }
+ def should
+ @should
end
- # We have to reorder things so that :provide is before :target
+ def should_to_s(newvalue = @should)
+ if newvalue
+ newvalue.join(",")
+ else
+ nil
+ end
+ end
+ end
+
+ newparam(:name) do
+ desc "The symbolic name of the cron job. This name
+ is used for human reference only and is generated automatically
+ for cron jobs found on the system. This generally won't
+ matter, as Puppet will do its best to match existing cron jobs
+ against specified jobs (and Puppet adds a comment to cron jobs it adds), but it is at least possible that converting from
+ unmanaged jobs to managed jobs might require manual
+ intervention."
+
+ isnamevar
+ end
+
+ newproperty(:user) do
+ desc "The user to run the command as. This user must
+ be allowed to run cron jobs, which is not currently checked by
+ Puppet.
+
+ The user defaults to whomever Puppet is running as."
+
+ defaultto { Etc.getpwuid(Process.uid).name || "root" }
+ end
+
+ newproperty(:target) do
+ desc "Where the cron job should be stored. For crontab-style
+ entries this is the same as the user and defaults that way.
+ Other providers default accordingly."
+
+ defaultto {
+ if provider.is_a?(@resource.class.provider(:crontab))
+ if val = @resource.should(:user)
+ val
+ else
+ raise ArgumentError,
+ "You must provide a user with crontab entries"
+ end
+ elsif provider.class.ancestors.include?(Puppet::Provider::ParsedFile)
+ provider.class.default_target
+ else
+ nil
+ end
+ }
+ end
- attr_accessor :uid
+ # We have to reorder things so that :provide is before :target
- def value(name)
- name = symbolize(name)
- ret = nil
- if obj = @parameters[name]
- ret = obj.should
+ attr_accessor :uid
- ret ||= obj.retrieve
+ def value(name)
+ name = symbolize(name)
+ ret = nil
+ if obj = @parameters[name]
+ ret = obj.should
- if ret == :absent
- ret = nil
- end
- end
+ ret ||= obj.retrieve
- unless ret
- case name
- when :command
- devfail "No command, somehow"
- when :special
- # nothing
- else
- #ret = (self.class.validproperty?(name).default || "*").to_s
- ret = "*"
- end
- end
+ if ret == :absent
+ ret = nil
+ end
+ end
- ret
+ unless ret
+ case name
+ when :command
+ devfail "No command, somehow"
+ when :special
+ # nothing
+ else
+ #ret = (self.class.validproperty?(name).default || "*").to_s
+ ret = "*"
+ end
end
+
+ ret
+ end
end
diff --git a/lib/puppet/type/exec.rb b/lib/puppet/type/exec.rb
index a60cdb481..bfeaaad34 100755
--- a/lib/puppet/type/exec.rb
+++ b/lib/puppet/type/exec.rb
@@ -1,686 +1,686 @@
module Puppet
- newtype(:exec) do
- include Puppet::Util::Execution
- require 'timeout'
-
- @doc = "Executes external commands. It is critical that all commands
- executed using this mechanism can be run multiple times without
- harm, i.e., they are *idempotent*. One useful way to create idempotent
- commands is to use the checks like ``creates`` to avoid running the
- command unless some condition is met.
-
- Note also that you can restrict an ``exec`` to only run when it receives
- events by using the ``refreshonly`` parameter; this is a useful way to
- have your configuration respond to events with arbitrary commands.
-
- It is worth noting that ``exec`` is special, in that it is not
- currently considered an error to have multiple ``exec`` instances
- with the same name. This was done purely because it had to be this
- way in order to get certain functionality, but it complicates things.
- In particular, you will not be able to use ``exec`` instances that
- share their commands with other instances as a dependency, since
- Puppet has no way of knowing which instance you mean.
-
- For example::
-
- # defined in the production class
- exec { \"make\":
- cwd => \"/prod/build/dir\",
- path => \"/usr/bin:/usr/sbin:/bin\"
- }
-
- . etc. .
-
- # defined in the test class
- exec { \"make\":
- cwd => \"/test/build/dir\",
- path => \"/usr/bin:/usr/sbin:/bin\"
- }
-
- Any other type would throw an error, complaining that you had
- the same instance being managed in multiple places, but these are
- obviously different images, so ``exec`` had to be treated specially.
-
- It is recommended to avoid duplicate names whenever possible.
-
- Note that if an ``exec`` receives an event from another resource,
- it will get executed again (or execute the command specified in ``refresh``, if there is one).
-
- There is a strong tendency to use ``exec`` to do whatever work Puppet
- can't already do; while this is obviously acceptable (and unavoidable)
- in the short term, it is highly recommended to migrate work from ``exec``
- to native Puppet types as quickly as possible. If you find that
- you are doing a lot of work with ``exec``, please at least notify
- us at Puppet Labs what you are doing, and hopefully we can work with
- you to get a native resource type for the work you are doing."
-
- require 'open3'
-
- # Create a new check mechanism. It's basically just a parameter that
- # provides one extra 'check' method.
- def self.newcheck(name, &block)
- @checks ||= {}
-
- check = newparam(name, &block)
- @checks[name] = check
- end
-
- def self.checks
- @checks.keys
- end
-
- newproperty(:returns, :array_matching => :all, :event => :executed_command) do |property|
- include Puppet::Util::Execution
- munge do |value|
- value.to_s
- end
-
- def event_name
- :executed_command
- end
-
- defaultto "0"
+ newtype(:exec) do
+ include Puppet::Util::Execution
+ require 'timeout'
+
+ @doc = "Executes external commands. It is critical that all commands
+ executed using this mechanism can be run multiple times without
+ harm, i.e., they are *idempotent*. One useful way to create idempotent
+ commands is to use the checks like ``creates`` to avoid running the
+ command unless some condition is met.
+
+ Note also that you can restrict an ``exec`` to only run when it receives
+ events by using the ``refreshonly`` parameter; this is a useful way to
+ have your configuration respond to events with arbitrary commands.
+
+ It is worth noting that ``exec`` is special, in that it is not
+ currently considered an error to have multiple ``exec`` instances
+ with the same name. This was done purely because it had to be this
+ way in order to get certain functionality, but it complicates things.
+ In particular, you will not be able to use ``exec`` instances that
+ share their commands with other instances as a dependency, since
+ Puppet has no way of knowing which instance you mean.
+
+ For example::
+
+ # defined in the production class
+ exec { \"make\":
+ cwd => \"/prod/build/dir\",
+ path => \"/usr/bin:/usr/sbin:/bin\"
+ }
+
+ . etc. .
+
+ # defined in the test class
+ exec { \"make\":
+ cwd => \"/test/build/dir\",
+ path => \"/usr/bin:/usr/sbin:/bin\"
+ }
+
+ Any other type would throw an error, complaining that you had
+ the same instance being managed in multiple places, but these are
+ obviously different images, so ``exec`` had to be treated specially.
+
+ It is recommended to avoid duplicate names whenever possible.
+
+ Note that if an ``exec`` receives an event from another resource,
+ it will get executed again (or execute the command specified in ``refresh``, if there is one).
+
+ There is a strong tendency to use ``exec`` to do whatever work Puppet
+ can't already do; while this is obviously acceptable (and unavoidable)
+ in the short term, it is highly recommended to migrate work from ``exec``
+ to native Puppet types as quickly as possible. If you find that
+ you are doing a lot of work with ``exec``, please at least notify
+ us at Puppet Labs what you are doing, and hopefully we can work with
+ you to get a native resource type for the work you are doing."
+
+ require 'open3'
+
+ # Create a new check mechanism. It's basically just a parameter that
+ # provides one extra 'check' method.
+ def self.newcheck(name, &block)
+ @checks ||= {}
+
+ check = newparam(name, &block)
+ @checks[name] = check
+ end
- attr_reader :output
- desc "The expected return code(s). An error will be returned if the
- executed command returns something else. Defaults to 0. Can be
- specified as an array of acceptable return codes or a single value."
+ def self.checks
+ @checks.keys
+ end
- # Make output a bit prettier
- def change_to_s(currentvalue, newvalue)
- "executed successfully"
- end
+ newproperty(:returns, :array_matching => :all, :event => :executed_command) do |property|
+ include Puppet::Util::Execution
+ munge do |value|
+ value.to_s
+ end
- # First verify that all of our checks pass.
- def retrieve
- # Default to somethinng
+ def event_name
+ :executed_command
+ end
- if @resource.check
- return :notrun
- else
- return self.should
- end
- end
+ defaultto "0"
- # Actually execute the command.
- def sync
- olddir = nil
-
- # We need a dir to change to, even if it's just the cwd
- dir = self.resource[:cwd] || Dir.pwd
-
- event = :executed_command
- tries = self.resource[:tries]
- try_sleep = self.resource[:try_sleep]
-
- begin
- tries.times do |try|
- # Only add debug messages for tries > 1 to reduce log spam.
- debug("Exec try #{try+1}/#{tries}") if tries > 1
- @output, @status = @resource.run(self.resource[:command])
- break if self.should.include?(@status.exitstatus.to_s)
- if try_sleep > 0 and tries > 1
- debug("Sleeping for #{try_sleep} seconds between tries")
- sleep try_sleep
- end
- end
- rescue Timeout::Error
- self.fail "Command exceeded timeout" % value.inspect
- end
+ attr_reader :output
+ desc "The expected return code(s). An error will be returned if the
+ executed command returns something else. Defaults to 0. Can be
+ specified as an array of acceptable return codes or a single value."
- if log = @resource[:logoutput]
- case log
- when :true
- log = @resource[:loglevel]
- when :on_failure
- unless self.should.include?(@status.exitstatus.to_s)
- log = @resource[:loglevel]
- else
- log = :false
- end
- end
- unless log == :false
- @output.split(/\n/).each { |line|
- self.send(log, line)
- }
- end
- end
+ # Make output a bit prettier
+ def change_to_s(currentvalue, newvalue)
+ "executed successfully"
+ end
- unless self.should.include?(@status.exitstatus.to_s)
- self.fail("#{self.resource[:command]} returned #{@status.exitstatus} instead of one of [#{self.should.join(",")}]")
- end
+ # First verify that all of our checks pass.
+ def retrieve
+ # Default to somethinng
- event
+ if @resource.check
+ return :notrun
+ else
+ return self.should
+ end
+ end
+
+ # Actually execute the command.
+ def sync
+ olddir = nil
+
+ # We need a dir to change to, even if it's just the cwd
+ dir = self.resource[:cwd] || Dir.pwd
+
+ event = :executed_command
+ tries = self.resource[:tries]
+ try_sleep = self.resource[:try_sleep]
+
+ begin
+ tries.times do |try|
+ # Only add debug messages for tries > 1 to reduce log spam.
+ debug("Exec try #{try+1}/#{tries}") if tries > 1
+ @output, @status = @resource.run(self.resource[:command])
+ break if self.should.include?(@status.exitstatus.to_s)
+ if try_sleep > 0 and tries > 1
+ debug("Sleeping for #{try_sleep} seconds between tries")
+ sleep try_sleep
end
+ end
+ rescue Timeout::Error
+ self.fail "Command exceeded timeout" % value.inspect
end
- newparam(:command) do
- isnamevar
- desc "The actual command to execute. Must either be fully qualified
- or a search path for the command must be provided. If the command
- succeeds, any output produced will be logged at the instance's
- normal log level (usually ``notice``), but if the command fails
- (meaning its return code does not match the specified code) then
- any output is logged at the ``err`` log level."
+ if log = @resource[:logoutput]
+ case log
+ when :true
+ log = @resource[:loglevel]
+ when :on_failure
+ unless self.should.include?(@status.exitstatus.to_s)
+ log = @resource[:loglevel]
+ else
+ log = :false
+ end
+ end
+ unless log == :false
+ @output.split(/\n/).each { |line|
+ self.send(log, line)
+ }
+ end
end
- newparam(:path) do
- desc "The search path used for command execution.
- Commands must be fully qualified if no path is specified. Paths
- can be specified as an array or as a colon-separated list."
-
- # Support both arrays and colon-separated fields.
- def value=(*values)
- @value = values.flatten.collect { |val|
- if val =~ /;/ # recognize semi-colon separated paths
- val.split(";")
- elsif val =~ /^\w:[^:]*$/ # heuristic to avoid splitting a driveletter away
- val
- else
- val.split(":")
- end
- }.flatten
- end
+ unless self.should.include?(@status.exitstatus.to_s)
+ self.fail("#{self.resource[:command]} returned #{@status.exitstatus} instead of one of [#{self.should.join(",")}]")
end
- newparam(:user) do
- desc "The user to run the command as. Note that if you
- use this then any error output is not currently captured. This
- is because of a bug within Ruby. If you are using Puppet to
- create this user, the exec will automatically require the user,
- as long as it is specified by name."
+ event
+ end
+ end
- # Most validation is handled by the SUIDManager class.
- validate do |user|
- self.fail "Only root can execute commands as other users" unless Puppet.features.root?
- end
- end
+ newparam(:command) do
+ isnamevar
+ desc "The actual command to execute. Must either be fully qualified
+ or a search path for the command must be provided. If the command
+ succeeds, any output produced will be logged at the instance's
+ normal log level (usually ``notice``), but if the command fails
+ (meaning its return code does not match the specified code) then
+ any output is logged at the ``err`` log level."
+ end
- newparam(:group) do
- desc "The group to run the command as. This seems to work quite
- haphazardly on different platforms -- it is a platform issue
- not a Ruby or Puppet one, since the same variety exists when
- running commnands as different users in the shell."
- # Validation is handled by the SUIDManager class.
- end
+ newparam(:path) do
+ desc "The search path used for command execution.
+ Commands must be fully qualified if no path is specified. Paths
+ can be specified as an array or as a colon-separated list."
+
+ # Support both arrays and colon-separated fields.
+ def value=(*values)
+ @value = values.flatten.collect { |val|
+ if val =~ /;/ # recognize semi-colon separated paths
+ val.split(";")
+ elsif val =~ /^\w:[^:]*$/ # heuristic to avoid splitting a driveletter away
+ val
+ else
+ val.split(":")
+ end
+ }.flatten
+ end
+ end
- newparam(:cwd) do
- desc "The directory from which to run the command. If
- this directory does not exist, the command will fail."
+ newparam(:user) do
+ desc "The user to run the command as. Note that if you
+ use this then any error output is not currently captured. This
+ is because of a bug within Ruby. If you are using Puppet to
+ create this user, the exec will automatically require the user,
+ as long as it is specified by name."
+
+ # Most validation is handled by the SUIDManager class.
+ validate do |user|
+ self.fail "Only root can execute commands as other users" unless Puppet.features.root?
+ end
+ end
- validate do |dir|
- unless dir =~ /^#{File::SEPARATOR}/
- self.fail("CWD must be a fully qualified path")
- end
- end
+ newparam(:group) do
+ desc "The group to run the command as. This seems to work quite
+ haphazardly on different platforms -- it is a platform issue
+ not a Ruby or Puppet one, since the same variety exists when
+ running commnands as different users in the shell."
+ # Validation is handled by the SUIDManager class.
+ end
- munge do |dir|
- dir = dir[0] if dir.is_a?(Array)
+ newparam(:cwd) do
+ desc "The directory from which to run the command. If
+ this directory does not exist, the command will fail."
- dir
- end
+ validate do |dir|
+ unless dir =~ /^#{File::SEPARATOR}/
+ self.fail("CWD must be a fully qualified path")
end
+ end
- newparam(:logoutput) do
- desc "Whether to log output. Defaults to logging output at the
- loglevel for the ``exec`` resource. Use *on_failure* to only
- log the output when the command reports an error. Values are
- **true**, *false*, *on_failure*, and any legal log level."
+ munge do |dir|
+ dir = dir[0] if dir.is_a?(Array)
- newvalues(:true, :false, :on_failure)
- end
+ dir
+ end
+ end
- newparam(:refresh) do
- desc "How to refresh this command. By default, the exec is just
- called again when it receives an event from another resource,
- but this parameter allows you to define a different command
- for refreshing."
+ newparam(:logoutput) do
+ desc "Whether to log output. Defaults to logging output at the
+ loglevel for the ``exec`` resource. Use *on_failure* to only
+ log the output when the command reports an error. Values are
+ **true**, *false*, *on_failure*, and any legal log level."
- validate do |command|
- @resource.validatecmd(command)
- end
- end
+ newvalues(:true, :false, :on_failure)
+ end
- newparam(:env) do
- desc "This parameter is deprecated. Use 'environment' instead."
+ newparam(:refresh) do
+ desc "How to refresh this command. By default, the exec is just
+ called again when it receives an event from another resource,
+ but this parameter allows you to define a different command
+ for refreshing."
- munge do |value|
- warning "'env' is deprecated on exec; use 'environment' instead."
- resource[:environment] = value
- end
- end
+ validate do |command|
+ @resource.validatecmd(command)
+ end
+ end
- newparam(:environment) do
- desc "Any additional environment variables you want to set for a
- command. Note that if you use this to set PATH, it will override
- the ``path`` attribute. Multiple environment variables should be
- specified as an array."
-
- validate do |values|
- values = [values] unless values.is_a? Array
- values.each do |value|
- unless value =~ /\w+=/
- raise ArgumentError, "Invalid environment setting '#{value}'"
- end
- end
- end
- end
+ newparam(:env) do
+ desc "This parameter is deprecated. Use 'environment' instead."
- newparam(:timeout) do
- desc "The maximum time the command should take. If the command takes
- longer than the timeout, the command is considered to have failed
- and will be stopped. Use any negative number to disable the timeout.
- The time is specified in seconds."
-
- munge do |value|
- value = value.shift if value.is_a?(Array)
- if value.is_a?(String)
- unless value =~ /^[-\d.]+$/
- raise ArgumentError, "The timeout must be a number."
- end
- Float(value)
- else
- value
- end
- end
+ munge do |value|
+ warning "'env' is deprecated on exec; use 'environment' instead."
+ resource[:environment] = value
+ end
+ end
- defaultto 300
+ newparam(:environment) do
+ desc "Any additional environment variables you want to set for a
+ command. Note that if you use this to set PATH, it will override
+ the ``path`` attribute. Multiple environment variables should be
+ specified as an array."
+
+ validate do |values|
+ values = [values] unless values.is_a? Array
+ values.each do |value|
+ unless value =~ /\w+=/
+ raise ArgumentError, "Invalid environment setting '#{value}'"
+ end
end
+ end
+ end
- newparam(:tries) do
- desc "The number of times execution of the command should be tried.
- Defaults to '1'. This many attempts will be made to execute
- the command until an acceptable return code is returned.
- Note that the timeout paramater applies to each try rather than
- to the complete set of tries."
-
- munge do |value|
- if value.is_a?(String)
- unless value =~ /^[\d]+$/
- raise ArgumentError, "Tries must be an integer"
- end
- value = Integer(value)
- end
- raise ArgumentError, "Tries must be an integer >= 1" if value < 1
- value
- end
+ newparam(:timeout) do
+ desc "The maximum time the command should take. If the command takes
+ longer than the timeout, the command is considered to have failed
+ and will be stopped. Use any negative number to disable the timeout.
+ The time is specified in seconds."
+
+ munge do |value|
+ value = value.shift if value.is_a?(Array)
+ if value.is_a?(String)
+ unless value =~ /^[-\d.]+$/
+ raise ArgumentError, "The timeout must be a number."
+ end
+ Float(value)
+ else
+ value
+ end
+ end
- defaultto 1
+ defaultto 300
+ end
+
+ newparam(:tries) do
+ desc "The number of times execution of the command should be tried.
+ Defaults to '1'. This many attempts will be made to execute
+ the command until an acceptable return code is returned.
+ Note that the timeout paramater applies to each try rather than
+ to the complete set of tries."
+
+ munge do |value|
+ if value.is_a?(String)
+ unless value =~ /^[\d]+$/
+ raise ArgumentError, "Tries must be an integer"
+ end
+ value = Integer(value)
end
+ raise ArgumentError, "Tries must be an integer >= 1" if value < 1
+ value
+ end
- newparam(:try_sleep) do
- desc "The time to sleep in seconds between 'tries'."
+ defaultto 1
+ end
- munge do |value|
- if value.is_a?(String)
- unless value =~ /^[-\d.]+$/
- raise ArgumentError, "try_sleep must be a number"
- end
- value = Float(value)
- end
- raise ArgumentError, "try_sleep cannot be a negative number" if value < 0
- value
- end
+ newparam(:try_sleep) do
+ desc "The time to sleep in seconds between 'tries'."
- defaultto 0
+ munge do |value|
+ if value.is_a?(String)
+ unless value =~ /^[-\d.]+$/
+ raise ArgumentError, "try_sleep must be a number"
+ end
+ value = Float(value)
end
+ raise ArgumentError, "try_sleep cannot be a negative number" if value < 0
+ value
+ end
+ defaultto 0
+ end
- newcheck(:refreshonly) do
- desc "The command should only be run as a
- refresh mechanism for when a dependent object is changed. It only
- makes sense to use this option when this command depends on some
- other object; it is useful for triggering an action::
-
- # Pull down the main aliases file
- file { \"/etc/aliases\":
- source => \"puppet://server/module/aliases\"
- }
-
- # Rebuild the database, but only when the file changes
- exec { newaliases:
- path => [\"/usr/bin\", \"/usr/sbin\"],
- subscribe => File[\"/etc/aliases\"],
- refreshonly => true
- }
-
- Note that only ``subscribe`` and ``notify`` can trigger actions, not ``require``,
- so it only makes sense to use ``refreshonly`` with ``subscribe`` or ``notify``."
-
- newvalues(:true, :false)
-
- # We always fail this test, because we're only supposed to run
- # on refresh.
- def check(value)
- # We have to invert the values.
- if value == :true
- false
- else
- true
- end
- end
+
+ newcheck(:refreshonly) do
+ desc "The command should only be run as a
+ refresh mechanism for when a dependent object is changed. It only
+ makes sense to use this option when this command depends on some
+ other object; it is useful for triggering an action::
+
+ # Pull down the main aliases file
+ file { \"/etc/aliases\":
+ source => \"puppet://server/module/aliases\"
+ }
+
+ # Rebuild the database, but only when the file changes
+ exec { newaliases:
+ path => [\"/usr/bin\", \"/usr/sbin\"],
+ subscribe => File[\"/etc/aliases\"],
+ refreshonly => true
+ }
+
+ Note that only ``subscribe`` and ``notify`` can trigger actions, not ``require``,
+ so it only makes sense to use ``refreshonly`` with ``subscribe`` or ``notify``."
+
+ newvalues(:true, :false)
+
+ # We always fail this test, because we're only supposed to run
+ # on refresh.
+ def check(value)
+ # We have to invert the values.
+ if value == :true
+ false
+ else
+ true
end
+ end
+ end
- newcheck(:creates) do
- desc "A file that this command creates. If this
- parameter is provided, then the command will only be run
- if the specified file does not exist::
+ newcheck(:creates) do
+ desc "A file that this command creates. If this
+ parameter is provided, then the command will only be run
+ if the specified file does not exist::
- exec { \"tar xf /my/tar/file.tar\":
- cwd => \"/var/tmp\",
- creates => \"/var/tmp/myfile\",
- path => [\"/usr/bin\", \"/usr/sbin\"]
- }
+ exec { \"tar xf /my/tar/file.tar\":
+ cwd => \"/var/tmp\",
+ creates => \"/var/tmp/myfile\",
+ path => [\"/usr/bin\", \"/usr/sbin\"]
+ }
- "
+ "
- # FIXME if they try to set this and fail, then we should probably
- # fail the entire exec, right?
- validate do |files|
- files = [files] unless files.is_a? Array
+ # FIXME if they try to set this and fail, then we should probably
+ # fail the entire exec, right?
+ validate do |files|
+ files = [files] unless files.is_a? Array
- files.each do |file|
- self.fail("'creates' must be set to a fully qualified path") unless file
+ files.each do |file|
+ self.fail("'creates' must be set to a fully qualified path") unless file
- unless file =~ %r{^#{File::SEPARATOR}}
- self.fail "'creates' files must be fully qualified."
- end
- end
- end
-
- # If the file exists, return false (i.e., don't run the command),
- # else return true
- def check(value)
- ! FileTest.exists?(value)
- end
+ unless file =~ %r{^#{File::SEPARATOR}}
+ self.fail "'creates' files must be fully qualified."
+ end
end
+ end
- newcheck(:unless) do
- desc "If this parameter is set, then this ``exec`` will run unless
- the command returns 0. For example::
-
- exec { \"/bin/echo root >> /usr/lib/cron/cron.allow\":
- path => \"/usr/bin:/usr/sbin:/bin\",
- unless => \"grep root /usr/lib/cron/cron.allow 2>/dev/null\"
- }
+ # If the file exists, return false (i.e., don't run the command),
+ # else return true
+ def check(value)
+ ! FileTest.exists?(value)
+ end
+ end
- This would add ``root`` to the cron.allow file (on Solaris) unless
- ``grep`` determines it's already there.
+ newcheck(:unless) do
+ desc "If this parameter is set, then this ``exec`` will run unless
+ the command returns 0. For example::
- Note that this command follows the same rules as the main command,
- which is to say that it must be fully qualified if the path is not set.
- "
+ exec { \"/bin/echo root >> /usr/lib/cron/cron.allow\":
+ path => \"/usr/bin:/usr/sbin:/bin\",
+ unless => \"grep root /usr/lib/cron/cron.allow 2>/dev/null\"
+ }
- validate do |cmds|
- cmds = [cmds] unless cmds.is_a? Array
+ This would add ``root`` to the cron.allow file (on Solaris) unless
+ ``grep`` determines it's already there.
- cmds.each do |cmd|
- @resource.validatecmd(cmd)
- end
- end
+ Note that this command follows the same rules as the main command,
+ which is to say that it must be fully qualified if the path is not set.
+ "
- # Return true if the command does not return 0.
- def check(value)
- begin
- output, status = @resource.run(value, true)
- rescue Timeout::Error
- err "Check #{value.inspect} exceeded timeout"
- return false
- end
+ validate do |cmds|
+ cmds = [cmds] unless cmds.is_a? Array
- status.exitstatus != 0
- end
+ cmds.each do |cmd|
+ @resource.validatecmd(cmd)
+ end
+ end
+
+ # Return true if the command does not return 0.
+ def check(value)
+ begin
+ output, status = @resource.run(value, true)
+ rescue Timeout::Error
+ err "Check #{value.inspect} exceeded timeout"
+ return false
end
- newcheck(:onlyif) do
- desc "If this parameter is set, then this ``exec`` will only run if
- the command returns 0. For example::
+ status.exitstatus != 0
+ end
+ end
- exec { \"logrotate\":
- path => \"/usr/bin:/usr/sbin:/bin\",
- onlyif => \"test `du /var/log/messages | cut -f1` -gt 100000\"
- }
+ newcheck(:onlyif) do
+ desc "If this parameter is set, then this ``exec`` will only run if
+ the command returns 0. For example::
- This would run ``logrotate`` only if that test returned true.
+ exec { \"logrotate\":
+ path => \"/usr/bin:/usr/sbin:/bin\",
+ onlyif => \"test `du /var/log/messages | cut -f1` -gt 100000\"
+ }
- Note that this command follows the same rules as the main command,
- which is to say that it must be fully qualified if the path is not set.
+ This would run ``logrotate`` only if that test returned true.
- Also note that onlyif can take an array as its value, eg::
+ Note that this command follows the same rules as the main command,
+ which is to say that it must be fully qualified if the path is not set.
- onlyif => [\"test -f /tmp/file1\", \"test -f /tmp/file2\"]
+ Also note that onlyif can take an array as its value, eg::
- This will only run the exec if /all/ conditions in the array return true.
- "
+ onlyif => [\"test -f /tmp/file1\", \"test -f /tmp/file2\"]
- validate do |cmds|
- cmds = [cmds] unless cmds.is_a? Array
+ This will only run the exec if /all/ conditions in the array return true.
+ "
- cmds.each do |cmd|
- @resource.validatecmd(cmd)
- end
- end
-
- # Return true if the command returns 0.
- def check(value)
- begin
- output, status = @resource.run(value, true)
- rescue Timeout::Error
- err "Check #{value.inspect} exceeded timeout"
- return false
- end
+ validate do |cmds|
+ cmds = [cmds] unless cmds.is_a? Array
- status.exitstatus == 0
- end
+ cmds.each do |cmd|
+ @resource.validatecmd(cmd)
end
-
- # Exec names are not isomorphic with the objects.
- @isomorphic = false
-
- validate do
- validatecmd(self[:command])
+ end
+
+ # Return true if the command returns 0.
+ def check(value)
+ begin
+ output, status = @resource.run(value, true)
+ rescue Timeout::Error
+ err "Check #{value.inspect} exceeded timeout"
+ return false
end
- # FIXME exec should autorequire any exec that 'creates' our cwd
- autorequire(:file) do
- reqs = []
+ status.exitstatus == 0
+ end
+ end
- # Stick the cwd in there if we have it
- reqs << self[:cwd] if self[:cwd]
+ # Exec names are not isomorphic with the objects.
+ @isomorphic = false
- self[:command].scan(/^(#{File::SEPARATOR}\S+)/) { |str|
- reqs << str
- }
+ validate do
+ validatecmd(self[:command])
+ end
- self[:command].scan(/^"([^"]+)"/) { |str|
- reqs << str
- }
+ # FIXME exec should autorequire any exec that 'creates' our cwd
+ autorequire(:file) do
+ reqs = []
- [:onlyif, :unless].each { |param|
- next unless tmp = self[param]
+ # Stick the cwd in there if we have it
+ reqs << self[:cwd] if self[:cwd]
- tmp = [tmp] unless tmp.is_a? Array
+ self[:command].scan(/^(#{File::SEPARATOR}\S+)/) { |str|
+ reqs << str
+ }
- tmp.each do |line|
- # And search the command line for files, adding any we
- # find. This will also catch the command itself if it's
- # fully qualified. It might not be a bad idea to add
- # unqualified files, but, well, that's a bit more annoying
- # to do.
- reqs += line.scan(%r{(#{File::SEPARATOR}\S+)})
- end
- }
+ self[:command].scan(/^"([^"]+)"/) { |str|
+ reqs << str
+ }
- # For some reason, the += isn't causing a flattening
- reqs.flatten!
+ [:onlyif, :unless].each { |param|
+ next unless tmp = self[param]
- reqs
- end
+ tmp = [tmp] unless tmp.is_a? Array
- autorequire(:user) do
- # Autorequire users if they are specified by name
- if user = self[:user] and user !~ /^\d+$/
- user
- end
+ tmp.each do |line|
+ # And search the command line for files, adding any we
+ # find. This will also catch the command itself if it's
+ # fully qualified. It might not be a bad idea to add
+ # unqualified files, but, well, that's a bit more annoying
+ # to do.
+ reqs += line.scan(%r{(#{File::SEPARATOR}\S+)})
end
+ }
- def self.instances
- []
- end
+ # For some reason, the += isn't causing a flattening
+ reqs.flatten!
- # Verify that we pass all of the checks. The argument determines whether
- # we skip the :refreshonly check, which is necessary because we now check
- # within refresh
- def check(refreshing = false)
- self.class.checks.each { |check|
- next if refreshing and check == :refreshonly
- if @parameters.include?(check)
- val = @parameters[check].value
- val = [val] unless val.is_a? Array
- val.each do |value|
- return false unless @parameters[check].check(value)
- end
- end
- }
+ reqs
+ end
- true
- end
+ autorequire(:user) do
+ # Autorequire users if they are specified by name
+ if user = self[:user] and user !~ /^\d+$/
+ user
+ end
+ end
- # Verify that we have the executable
- def checkexe(cmd)
- exe = extractexe(cmd)
-
- if self[:path]
- if Puppet.features.posix? and !File.exists?(exe)
- withenv :PATH => self[:path].join(File::PATH_SEPARATOR) do
- path = %x{which #{exe}}.chomp
- if path == ""
- raise ArgumentError,
- "Could not find command '#{exe}'"
- else
- exe = path
- end
- end
- elsif Puppet.features.microsoft_windows? and !File.exists?(exe)
- self[:path].each do |path|
- [".exe", ".ps1", ".bat", ".com", ""].each do |extension|
- file = File.join(path, exe+extension)
- return if File.exists?(file)
- end
- end
- end
- end
+ def self.instances
+ []
+ end
- raise ArgumentError, "Could not find executable '#{exe}'" unless FileTest.exists?(exe)
- unless FileTest.executable?(exe)
- raise ArgumentError,
- "'#{exe}' is not executable"
- end
+ # Verify that we pass all of the checks. The argument determines whether
+ # we skip the :refreshonly check, which is necessary because we now check
+ # within refresh
+ def check(refreshing = false)
+ self.class.checks.each { |check|
+ next if refreshing and check == :refreshonly
+ if @parameters.include?(check)
+ val = @parameters[check].value
+ val = [val] unless val.is_a? Array
+ val.each do |value|
+ return false unless @parameters[check].check(value)
+ end
end
+ }
+
+ true
+ end
- def output
- if self.property(:returns).nil?
- return nil
+ # Verify that we have the executable
+ def checkexe(cmd)
+ exe = extractexe(cmd)
+
+ if self[:path]
+ if Puppet.features.posix? and !File.exists?(exe)
+ withenv :PATH => self[:path].join(File::PATH_SEPARATOR) do
+ path = %x{which #{exe}}.chomp
+ if path == ""
+ raise ArgumentError,
+ "Could not find command '#{exe}'"
else
- return self.property(:returns).output
+ exe = path
end
+ end
+ elsif Puppet.features.microsoft_windows? and !File.exists?(exe)
+ self[:path].each do |path|
+ [".exe", ".ps1", ".bat", ".com", ""].each do |extension|
+ file = File.join(path, exe+extension)
+ return if File.exists?(file)
+ end
+ end
end
+ end
- # Run the command, or optionally run a separately-specified command.
- def refresh
- if self.check(true)
- if cmd = self[:refresh]
- self.run(cmd)
- else
- self.property(:returns).sync
- end
- end
+ raise ArgumentError, "Could not find executable '#{exe}'" unless FileTest.exists?(exe)
+ unless FileTest.executable?(exe)
+ raise ArgumentError,
+ "'#{exe}' is not executable"
+ end
+ end
+
+ def output
+ if self.property(:returns).nil?
+ return nil
+ else
+ return self.property(:returns).output
+ end
+ end
+
+ # Run the command, or optionally run a separately-specified command.
+ def refresh
+ if self.check(true)
+ if cmd = self[:refresh]
+ self.run(cmd)
+ else
+ self.property(:returns).sync
end
+ end
+ end
- # Run a command.
- def run(command, check = false)
- output = nil
- status = nil
+ # Run a command.
+ def run(command, check = false)
+ output = nil
+ status = nil
- dir = nil
+ dir = nil
- checkexe(command)
+ checkexe(command)
- if dir = self[:cwd]
- unless File.directory?(dir)
- if check
- dir = nil
- else
- self.fail "Working directory '#{dir}' does not exist"
- end
+ if dir = self[:cwd]
+ unless File.directory?(dir)
+ if check
+ dir = nil
+ else
+ self.fail "Working directory '#{dir}' does not exist"
+ end
+ end
+ end
+
+ dir ||= Dir.pwd
+
+ if check
+ debug "Executing check '#{command}'"
+ else
+ debug "Executing '#{command}'"
+ end
+ begin
+ # Do our chdir
+ Dir.chdir(dir) do
+ environment = {}
+
+ environment[:PATH] = self[:path].join(":") if self[:path]
+
+ if envlist = self[:environment]
+ envlist = [envlist] unless envlist.is_a? Array
+ envlist.each do |setting|
+ if setting =~ /^(\w+)=((.|\n)+)$/
+ name = $1
+ value = $2
+ if environment.include? name
+ warning(
+ "Overriding environment setting '#{name}' with '#{value}'"
+ )
end
+ environment[name] = value
+ else
+ warning "Cannot understand environment setting #{setting.inspect}"
+ end
end
+ end
- dir ||= Dir.pwd
-
- if check
- debug "Executing check '#{command}'"
- else
- debug "Executing '#{command}'"
+ withenv environment do
+ Timeout::timeout(self[:timeout]) do
+ output, status = Puppet::Util::SUIDManager.run_and_capture(
+ [command], self[:user], self[:group]
+ )
end
- begin
- # Do our chdir
- Dir.chdir(dir) do
- environment = {}
-
- environment[:PATH] = self[:path].join(":") if self[:path]
-
- if envlist = self[:environment]
- envlist = [envlist] unless envlist.is_a? Array
- envlist.each do |setting|
- if setting =~ /^(\w+)=((.|\n)+)$/
- name = $1
- value = $2
- if environment.include? name
- warning(
- "Overriding environment setting '#{name}' with '#{value}'"
- )
- end
- environment[name] = value
- else
- warning "Cannot understand environment setting #{setting.inspect}"
- end
- end
- end
-
- withenv environment do
- Timeout::timeout(self[:timeout]) do
- output, status = Puppet::Util::SUIDManager.run_and_capture(
- [command], self[:user], self[:group]
- )
- end
- # The shell returns 127 if the command is missing.
- if status.exitstatus == 127
- raise ArgumentError, output
- end
- end
- end
- rescue Errno::ENOENT => detail
- self.fail detail.to_s
+ # The shell returns 127 if the command is missing.
+ if status.exitstatus == 127
+ raise ArgumentError, output
end
-
- return output, status
+ end
end
+ rescue Errno::ENOENT => detail
+ self.fail detail.to_s
+ end
- def validatecmd(cmd)
- exe = extractexe(cmd)
- # if we're not fully qualified, require a path
- self.fail "'#{cmd}' is both unqualifed and specified no search path" if File.expand_path(exe) != exe and self[:path].nil?
- end
+ return output, status
+ end
- def extractexe(cmd)
- # easy case: command was quoted
- if cmd =~ /^"([^"]+)"/
- $1
- else
- cmd.split(/ /)[0]
- end
- end
+ def validatecmd(cmd)
+ exe = extractexe(cmd)
+ # if we're not fully qualified, require a path
+ self.fail "'#{cmd}' is both unqualifed and specified no search path" if File.expand_path(exe) != exe and self[:path].nil?
+ end
+
+ def extractexe(cmd)
+ # easy case: command was quoted
+ if cmd =~ /^"([^"]+)"/
+ $1
+ else
+ cmd.split(/ /)[0]
+ end
end
+ end
end
diff --git a/lib/puppet/type/file.rb b/lib/puppet/type/file.rb
index afa990d7f..195e8c86f 100644
--- a/lib/puppet/type/file.rb
+++ b/lib/puppet/type/file.rb
@@ -10,777 +10,777 @@ require 'puppet/network/client'
require 'puppet/util/backups'
Puppet::Type.newtype(:file) do
- include Puppet::Util::MethodHelper
- include Puppet::Util::Checksums
- include Puppet::Util::Backups
- @doc = "Manages local files, including setting ownership and
- permissions, creation of both files and directories, and
- retrieving entire files from remote servers. As Puppet matures, it
- expected that the ``file`` resource will be used less and less to
- manage content, and instead native resources will be used to do so.
-
- If you find that you are often copying files in from a central
- location, rather than using native resources, please contact
- Puppet Labs and we can hopefully work with you to develop a
- native resource to support what you are doing."
-
- def self.title_patterns
- [ [ /^(.*?)\/?$/, [ [ :path, lambda{|x| x} ] ] ] ]
- end
-
- newparam(:path) do
- desc "The path to the file to manage. Must be fully qualified."
- isnamevar
-
- validate do |value|
- # accept various path syntaxes: lone slash, posix, win32, unc
- unless (Puppet.features.posix? and (value =~ /^\/$/ or value =~ /^\/[^\/]/)) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
- fail Puppet::Error, "File paths must be fully qualified, not '#{value}'"
- end
- end
-
- # convert the current path in an index into the collection and the last
- # path name. The aim is to use less storage for all common paths in a hierarchy
- munge do |value|
- path, name = File.split(value.gsub(/\/+/,'/'))
- { :index => Puppet::FileCollection.collection.index(path), :name => name }
- end
-
- # and the reverse
- unmunge do |value|
- basedir = Puppet::FileCollection.collection.path(value[:index])
- # a lone slash as :name indicates a root dir on windows
- if value[:name] == '/'
- basedir
- else
- File.join( basedir, value[:name] )
- end
- end
- end
-
- newparam(:backup) do
- desc "Whether files should be backed up before
- being replaced. The preferred method of backing files up is via
- a ``filebucket``, which stores files by their MD5 sums and allows
- easy retrieval without littering directories with backups. You
- can specify a local filebucket or a network-accessible
- server-based filebucket by setting ``backup => bucket-name``.
- Alternatively, if you specify any value that begins with a ``.``
- (e.g., ``.puppet-bak``), then Puppet will use copy the file in
- the same directory with that value as the extension of the
- backup. Setting ``backup => false`` disables all backups of the
- file in question.
-
- Puppet automatically creates a local filebucket named ``puppet`` and
- defaults to backing up there. To use a server-based filebucket,
- you must specify one in your configuration::
-
- filebucket { main:
- server => puppet
- }
-
- The ``puppet master`` daemon creates a filebucket by default,
- so you can usually back up to your main server with this
- configuration. Once you've described the bucket in your
- configuration, you can use it in any file::
-
- file { \"/my/file\":
- source => \"/path/in/nfs/or/something\",
- backup => main
- }
-
- This will back the file up to the central server.
-
- At this point, the benefits of using a filebucket are that you do not
- have backup files lying around on each of your machines, a given
- version of a file is only backed up once, and you can restore
- any given file manually, no matter how old. Eventually,
- transactional support will be able to automatically restore
- filebucketed files.
- "
-
- defaultto "puppet"
-
- munge do |value|
- # I don't really know how this is happening.
- value = value.shift if value.is_a?(Array)
-
- case value
- when false, "false", :false
- false
- when true, "true", ".puppet-bak", :true
- ".puppet-bak"
- when String
- value
- else
- self.fail "Invalid backup type #{value.inspect}"
- end
- end
- end
-
- newparam(:recurse) do
- desc "Whether and how deeply to do recursive
- management."
-
- newvalues(:true, :false, :inf, :remote, /^[0-9]+$/)
-
- # Replace the validation so that we allow numbers in
- # addition to string representations of them.
- validate { |arg| }
- munge do |value|
- newval = super(value)
- case newval
- when :true, :inf; true
- when :false; false
- when :remote; :remote
- when Integer, Fixnum, Bignum
- self.warning "Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit"
-
- # recurse == 0 means no recursion
- return false if value == 0
-
- resource[:recurselimit] = value
- true
- when /^\d+$/
- self.warning "Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit"
- value = Integer(value)
-
- # recurse == 0 means no recursion
- return false if value == 0
-
- resource[:recurselimit] = value
- true
- else
- self.fail "Invalid recurse value #{value.inspect}"
- end
- end
- end
-
- newparam(:recurselimit) do
- desc "How deeply to do recursive management."
-
- newvalues(/^[0-9]+$/)
-
- munge do |value|
- newval = super(value)
- case newval
- when Integer, Fixnum, Bignum; value
- when /^\d+$/; Integer(value)
- else
- self.fail "Invalid recurselimit value #{value.inspect}"
- end
- end
- end
-
- newparam(:replace, :boolean => true) do
- desc "Whether or not to replace a file that is
- sourced but exists. This is useful for using file sources
- purely for initialization."
- newvalues(:true, :false)
- aliasvalue(:yes, :true)
- aliasvalue(:no, :false)
- defaultto :true
- end
-
- newparam(:force, :boolean => true) do
- desc "Force the file operation. Currently only used when replacing
- directories with links."
- newvalues(:true, :false)
- defaultto false
- end
-
- newparam(:ignore) do
- desc "A parameter which omits action on files matching
- specified patterns during recursion. Uses Ruby's builtin globbing
- engine, so shell metacharacters are fully supported, e.g. ``[a-z]*``.
- Matches that would descend into the directory structure are ignored,
- e.g., ``*/*``."
-
- validate do |value|
- unless value.is_a?(Array) or value.is_a?(String) or value == false
- self.devfail "Ignore must be a string or an Array"
- end
- end
- end
-
- newparam(:links) do
- desc "How to handle links during file actions. During file copying,
- ``follow`` will copy the target file instead of the link, ``manage``
- will copy the link itself, and ``ignore`` will just pass it by.
- When not copying, ``manage`` and ``ignore`` behave equivalently
- (because you cannot really ignore links entirely during local recursion), and ``follow`` will manage the file to which the
- link points."
-
- newvalues(:follow, :manage)
-
- defaultto :manage
- end
-
- newparam(:purge, :boolean => true) do
- desc "Whether unmanaged files should be purged. If you have a filebucket
- configured the purged files will be uploaded, but if you do not,
- this will destroy data. Only use this option for generated
- files unless you really know what you are doing. This option only
- makes sense when recursively managing directories.
-
- Note that when using ``purge`` with ``source``, Puppet will purge any files
- that are not on the remote system."
-
- defaultto :false
-
- newvalues(:true, :false)
- end
-
- newparam(:sourceselect) do
- desc "Whether to copy all valid sources, or just the first one. This parameter
- is only used in recursive copies; by default, the first valid source is the
- only one used as a recursive source, but if this parameter is set to ``all``,
- then all valid sources will have all of their contents copied to the local host,
- and for sources that have the same file, the source earlier in the list will
- be used."
-
- defaultto :first
-
- newvalues(:first, :all)
- end
-
- # Autorequire any parent directories.
- autorequire(:file) do
- basedir = File.dirname(self[:path])
- if basedir != self[:path]
- basedir
- else
- nil
- end
- end
-
- # Autorequire the owner and group of the file.
- {:user => :owner, :group => :group}.each do |type, property|
- autorequire(type) do
- if @parameters.include?(property)
- # The user/group property automatically converts to IDs
- next unless should = @parameters[property].shouldorig
- val = should[0]
- if val.is_a?(Integer) or val =~ /^\d+$/
- nil
- else
- val
- end
- end
- end
- end
-
- CREATORS = [:content, :source, :target]
-
- validate do
- count = 0
- CREATORS.each do |param|
- count += 1 if self.should(param)
- end
- count += 1 if @parameters.include?(:source)
- self.fail "You cannot specify more than one of #{CREATORS.collect { |p| p.to_s}.join(", ")}" if count > 1
-
- self.fail "You cannot specify a remote recursion without a source" if !self[:source] and self[:recurse] == :remote
-
- self.warning "Possible error: recurselimit is set but not recurse, no recursion will happen" if !self[:recurse] and self[:recurselimit]
- end
-
- def self.[](path)
- return nil unless path
- super(path.gsub(/\/+/, '/').sub(/\/$/, ''))
- end
-
- # List files, but only one level deep.
- def self.instances(base = "/")
- return [] unless FileTest.directory?(base)
-
- files = []
- Dir.entries(base).reject { |e|
- e == "." or e == ".."
- }.each do |name|
- path = File.join(base, name)
- if obj = self[path]
- obj[:audit] = :all
- files << obj
- else
- files << self.new(
- :name => path, :audit => :all
- )
- end
- end
- files
- end
-
- @depthfirst = false
-
- # Determine the user to write files as.
- def asuser
- if self.should(:owner) and ! self.should(:owner).is_a?(Symbol)
- writeable = Puppet::Util::SUIDManager.asuser(self.should(:owner)) {
- FileTest.writable?(File.dirname(self[:path]))
- }
-
- # If the parent directory is writeable, then we execute
- # as the user in question. Otherwise we'll rely on
- # the 'owner' property to do things.
- asuser = self.should(:owner) if writeable
- end
-
- asuser
- end
-
- def bucket
- return @bucket if @bucket
-
- backup = self[:backup]
- return nil unless backup
- return nil if backup =~ /^\./
-
- unless catalog or backup == "puppet"
- fail "Can not find filebucket for backups without a catalog"
- end
-
- unless catalog and filebucket = catalog.resource(:filebucket, backup) or backup == "puppet"
- fail "Could not find filebucket #{backup} specified in backup"
- end
-
- return default_bucket unless filebucket
-
- @bucket = filebucket.bucket
-
- @bucket
- end
-
- def default_bucket
- Puppet::Type.type(:filebucket).mkdefaultbucket.bucket
- end
-
- # Does the file currently exist? Just checks for whether
- # we have a stat
- def exist?
- stat ? true : false
- end
-
- # We have to do some extra finishing, to retrieve our bucket if
- # there is one.
- def finish
- # Look up our bucket, if there is one
- bucket
- super
- end
-
- # Create any children via recursion or whatever.
- def eval_generate
- return [] unless self.recurse?
-
- recurse
- #recurse.reject do |resource|
- # catalog.resource(:file, resource[:path])
- #end.each do |child|
- # catalog.add_resource child
- # catalog.relationship_graph.add_edge self, child
- #end
- end
-
- def flush
- # We want to make sure we retrieve metadata anew on each transaction.
- @parameters.each do |name, param|
- param.flush if param.respond_to?(:flush)
- end
- @stat = nil
- end
-
- def initialize(hash)
- # Used for caching clients
- @clients = {}
-
- super
-
- # If they've specified a source, we get our 'should' values
- # from it.
- unless self[:ensure]
- if self[:target]
- self[:ensure] = :symlink
- elsif self[:content]
- self[:ensure] = :file
- end
- end
-
- @stat = nil
- end
-
- # Configure discovered resources to be purged.
- def mark_children_for_purging(children)
- children.each do |name, child|
- next if child[:source]
- child[:ensure] = :absent
- end
- end
-
- # Create a new file or directory object as a child to the current
- # object.
- def newchild(path)
- full_path = File.join(self[:path], path)
-
- # Add some new values to our original arguments -- these are the ones
- # set at initialization. We specifically want to exclude any param
- # values set by the :source property or any default values.
- # LAK:NOTE This is kind of silly, because the whole point here is that
- # the values set at initialization should live as long as the resource
- # but values set by default or by :source should only live for the transaction
- # or so. Unfortunately, we don't have a straightforward way to manage
- # the different lifetimes of this data, so we kludge it like this.
- # The right-side hash wins in the merge.
- options = @original_parameters.merge(:path => full_path).reject { |param, value| value.nil? }
-
- # These should never be passed to our children.
- [:parent, :ensure, :recurse, :recurselimit, :target, :alias, :source].each do |param|
- options.delete(param) if options.include?(param)
- end
-
- self.class.new(options)
- end
-
- # Files handle paths specially, because they just lengthen their
- # path names, rather than including the full parent's title each
- # time.
- def pathbuilder
- # We specifically need to call the method here, so it looks
- # up our parent in the catalog graph.
- if parent = parent()
- # We only need to behave specially when our parent is also
- # a file
- if parent.is_a?(self.class)
- # Remove the parent file name
- list = parent.pathbuilder
- list.pop # remove the parent's path info
- return list << self.ref
- else
- return super
- end
+ include Puppet::Util::MethodHelper
+ include Puppet::Util::Checksums
+ include Puppet::Util::Backups
+ @doc = "Manages local files, including setting ownership and
+ permissions, creation of both files and directories, and
+ retrieving entire files from remote servers. As Puppet matures, it
+ expected that the ``file`` resource will be used less and less to
+ manage content, and instead native resources will be used to do so.
+
+ If you find that you are often copying files in from a central
+ location, rather than using native resources, please contact
+ Puppet Labs and we can hopefully work with you to develop a
+ native resource to support what you are doing."
+
+ def self.title_patterns
+ [ [ /^(.*?)\/?$/, [ [ :path, lambda{|x| x} ] ] ] ]
+ end
+
+ newparam(:path) do
+ desc "The path to the file to manage. Must be fully qualified."
+ isnamevar
+
+ validate do |value|
+ # accept various path syntaxes: lone slash, posix, win32, unc
+ unless (Puppet.features.posix? and (value =~ /^\/$/ or value =~ /^\/[^\/]/)) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
+ fail Puppet::Error, "File paths must be fully qualified, not '#{value}'"
+ end
+ end
+
+ # convert the current path in an index into the collection and the last
+ # path name. The aim is to use less storage for all common paths in a hierarchy
+ munge do |value|
+ path, name = File.split(value.gsub(/\/+/,'/'))
+ { :index => Puppet::FileCollection.collection.index(path), :name => name }
+ end
+
+ # and the reverse
+ unmunge do |value|
+ basedir = Puppet::FileCollection.collection.path(value[:index])
+ # a lone slash as :name indicates a root dir on windows
+ if value[:name] == '/'
+ basedir
+ else
+ File.join( basedir, value[:name] )
+ end
+ end
+ end
+
+ newparam(:backup) do
+ desc "Whether files should be backed up before
+ being replaced. The preferred method of backing files up is via
+ a ``filebucket``, which stores files by their MD5 sums and allows
+ easy retrieval without littering directories with backups. You
+ can specify a local filebucket or a network-accessible
+ server-based filebucket by setting ``backup => bucket-name``.
+ Alternatively, if you specify any value that begins with a ``.``
+ (e.g., ``.puppet-bak``), then Puppet will use copy the file in
+ the same directory with that value as the extension of the
+ backup. Setting ``backup => false`` disables all backups of the
+ file in question.
+
+ Puppet automatically creates a local filebucket named ``puppet`` and
+ defaults to backing up there. To use a server-based filebucket,
+ you must specify one in your configuration::
+
+ filebucket { main:
+ server => puppet
+ }
+
+ The ``puppet master`` daemon creates a filebucket by default,
+ so you can usually back up to your main server with this
+ configuration. Once you've described the bucket in your
+ configuration, you can use it in any file::
+
+ file { \"/my/file\":
+ source => \"/path/in/nfs/or/something\",
+ backup => main
+ }
+
+ This will back the file up to the central server.
+
+ At this point, the benefits of using a filebucket are that you do not
+ have backup files lying around on each of your machines, a given
+ version of a file is only backed up once, and you can restore
+ any given file manually, no matter how old. Eventually,
+ transactional support will be able to automatically restore
+ filebucketed files.
+ "
+
+ defaultto "puppet"
+
+ munge do |value|
+ # I don't really know how this is happening.
+ value = value.shift if value.is_a?(Array)
+
+ case value
+ when false, "false", :false
+ false
+ when true, "true", ".puppet-bak", :true
+ ".puppet-bak"
+ when String
+ value
+ else
+ self.fail "Invalid backup type #{value.inspect}"
+ end
+ end
+ end
+
+ newparam(:recurse) do
+ desc "Whether and how deeply to do recursive
+ management."
+
+ newvalues(:true, :false, :inf, :remote, /^[0-9]+$/)
+
+ # Replace the validation so that we allow numbers in
+ # addition to string representations of them.
+ validate { |arg| }
+ munge do |value|
+ newval = super(value)
+ case newval
+ when :true, :inf; true
+ when :false; false
+ when :remote; :remote
+ when Integer, Fixnum, Bignum
+ self.warning "Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit"
+
+ # recurse == 0 means no recursion
+ return false if value == 0
+
+ resource[:recurselimit] = value
+ true
+ when /^\d+$/
+ self.warning "Setting recursion depth with the recurse parameter is now deprecated, please use recurselimit"
+ value = Integer(value)
+
+ # recurse == 0 means no recursion
+ return false if value == 0
+
+ resource[:recurselimit] = value
+ true
+ else
+ self.fail "Invalid recurse value #{value.inspect}"
+ end
+ end
+ end
+
+ newparam(:recurselimit) do
+ desc "How deeply to do recursive management."
+
+ newvalues(/^[0-9]+$/)
+
+ munge do |value|
+ newval = super(value)
+ case newval
+ when Integer, Fixnum, Bignum; value
+ when /^\d+$/; Integer(value)
+ else
+ self.fail "Invalid recurselimit value #{value.inspect}"
+ end
+ end
+ end
+
+ newparam(:replace, :boolean => true) do
+ desc "Whether or not to replace a file that is
+ sourced but exists. This is useful for using file sources
+ purely for initialization."
+ newvalues(:true, :false)
+ aliasvalue(:yes, :true)
+ aliasvalue(:no, :false)
+ defaultto :true
+ end
+
+ newparam(:force, :boolean => true) do
+ desc "Force the file operation. Currently only used when replacing
+ directories with links."
+ newvalues(:true, :false)
+ defaultto false
+ end
+
+ newparam(:ignore) do
+ desc "A parameter which omits action on files matching
+ specified patterns during recursion. Uses Ruby's builtin globbing
+ engine, so shell metacharacters are fully supported, e.g. ``[a-z]*``.
+ Matches that would descend into the directory structure are ignored,
+ e.g., ``*/*``."
+
+ validate do |value|
+ unless value.is_a?(Array) or value.is_a?(String) or value == false
+ self.devfail "Ignore must be a string or an Array"
+ end
+ end
+ end
+
+ newparam(:links) do
+ desc "How to handle links during file actions. During file copying,
+ ``follow`` will copy the target file instead of the link, ``manage``
+ will copy the link itself, and ``ignore`` will just pass it by.
+ When not copying, ``manage`` and ``ignore`` behave equivalently
+ (because you cannot really ignore links entirely during local recursion), and ``follow`` will manage the file to which the
+ link points."
+
+ newvalues(:follow, :manage)
+
+ defaultto :manage
+ end
+
+ newparam(:purge, :boolean => true) do
+ desc "Whether unmanaged files should be purged. If you have a filebucket
+ configured the purged files will be uploaded, but if you do not,
+ this will destroy data. Only use this option for generated
+ files unless you really know what you are doing. This option only
+ makes sense when recursively managing directories.
+
+ Note that when using ``purge`` with ``source``, Puppet will purge any files
+ that are not on the remote system."
+
+ defaultto :false
+
+ newvalues(:true, :false)
+ end
+
+ newparam(:sourceselect) do
+ desc "Whether to copy all valid sources, or just the first one. This parameter
+ is only used in recursive copies; by default, the first valid source is the
+ only one used as a recursive source, but if this parameter is set to ``all``,
+ then all valid sources will have all of their contents copied to the local host,
+ and for sources that have the same file, the source earlier in the list will
+ be used."
+
+ defaultto :first
+
+ newvalues(:first, :all)
+ end
+
+ # Autorequire any parent directories.
+ autorequire(:file) do
+ basedir = File.dirname(self[:path])
+ if basedir != self[:path]
+ basedir
+ else
+ nil
+ end
+ end
+
+ # Autorequire the owner and group of the file.
+ {:user => :owner, :group => :group}.each do |type, property|
+ autorequire(type) do
+ if @parameters.include?(property)
+ # The user/group property automatically converts to IDs
+ next unless should = @parameters[property].shouldorig
+ val = should[0]
+ if val.is_a?(Integer) or val =~ /^\d+$/
+ nil
else
- return [self.ref]
- end
- end
-
- # Should we be purging?
- def purge?
- @parameters.include?(:purge) and (self[:purge] == :true or self[:purge] == "true")
- end
-
- # Recursively generate a list of file resources, which will
- # be used to copy remote files, manage local files, and/or make links
- # to map to another directory.
- def recurse
- children = {}
- children = recurse_local if self[:recurse] != :remote
-
- if self[:target]
- recurse_link(children)
- elsif self[:source]
- recurse_remote(children)
- end
-
- # If we're purging resources, then delete any resource that isn't on the
- # remote system.
- mark_children_for_purging(children) if self.purge?
-
- result = children.values.sort { |a, b| a[:path] <=> b[:path] }
- remove_less_specific_files(result)
- end
-
- # This is to fix bug #2296, where two files recurse over the same
- # set of files. It's a rare case, and when it does happen you're
- # not likely to have many actual conflicts, which is good, because
- # this is a pretty inefficient implementation.
- def remove_less_specific_files(files)
- mypath = self[:path].split(File::Separator)
- other_paths = catalog.vertices.
- select { |r| r.is_a?(self.class) and r[:path] != self[:path] }.
- collect { |r| r[:path].split(File::Separator) }.
- select { |p| p[0,mypath.length] == mypath }
-
- return files if other_paths.empty?
-
- files.reject { |file|
- path = file[:path].split(File::Separator)
- other_paths.any? { |p| path[0,p.length] == p }
- }
- end
-
- # A simple method for determining whether we should be recursing.
- def recurse?
- return false unless @parameters.include?(:recurse)
-
- val = @parameters[:recurse].value
-
- !!(val and (val == true or val == :remote))
- end
-
- # Recurse the target of the link.
- def recurse_link(children)
- perform_recursion(self[:target]).each do |meta|
- if meta.relative_path == "."
- self[:ensure] = :directory
- next
- end
-
- children[meta.relative_path] ||= newchild(meta.relative_path)
- if meta.ftype == "directory"
- children[meta.relative_path][:ensure] = :directory
- else
- children[meta.relative_path][:ensure] = :link
- children[meta.relative_path][:target] = meta.full_path
- end
+ val
end
- children
+ end
end
+ end
- # Recurse the file itself, returning a Metadata instance for every found file.
- def recurse_local
- result = perform_recursion(self[:path])
- return {} unless result
- result.inject({}) do |hash, meta|
- next hash if meta.relative_path == "."
+ CREATORS = [:content, :source, :target]
- hash[meta.relative_path] = newchild(meta.relative_path)
- hash
- end
+ validate do
+ count = 0
+ CREATORS.each do |param|
+ count += 1 if self.should(param)
end
+ count += 1 if @parameters.include?(:source)
+ self.fail "You cannot specify more than one of #{CREATORS.collect { |p| p.to_s}.join(", ")}" if count > 1
- # Recurse against our remote file.
- def recurse_remote(children)
- sourceselect = self[:sourceselect]
-
- total = self[:source].collect do |source|
- next unless result = perform_recursion(source)
- return if top = result.find { |r| r.relative_path == "." } and top.ftype != "directory"
- result.each { |data| data.source = "#{source}/#{data.relative_path}" }
- break result if result and ! result.empty? and sourceselect == :first
- result
- end.flatten
-
- # This only happens if we have sourceselect == :all
- unless sourceselect == :first
- found = []
- total.reject! do |data|
- result = found.include?(data.relative_path)
- found << data.relative_path unless found.include?(data.relative_path)
- result
- end
- end
-
- total.each do |meta|
- if meta.relative_path == "."
- parameter(:source).metadata = meta
- next
- end
- children[meta.relative_path] ||= newchild(meta.relative_path)
- children[meta.relative_path][:source] = meta.source
- children[meta.relative_path][:checksum] = :md5 if meta.ftype == "file"
+ self.fail "You cannot specify a remote recursion without a source" if !self[:source] and self[:recurse] == :remote
- children[meta.relative_path].parameter(:source).metadata = meta
- end
-
- children
- end
+ self.warning "Possible error: recurselimit is set but not recurse, no recursion will happen" if !self[:recurse] and self[:recurselimit]
+ end
- def perform_recursion(path)
+ def self.[](path)
+ return nil unless path
+ super(path.gsub(/\/+/, '/').sub(/\/$/, ''))
+ end
- Puppet::FileServing::Metadata.search(
+ # List files, but only one level deep.
+ def self.instances(base = "/")
+ return [] unless FileTest.directory?(base)
- path,
- :links => self[:links],
- :recurse => (self[:recurse] == :remote ? true : self[:recurse]),
-
- :recurselimit => self[:recurselimit],
- :ignore => self[:ignore],
- :checksum_type => (self[:source] || self[:content]) ? self[:checksum] : :none
+ files = []
+ Dir.entries(base).reject { |e|
+ e == "." or e == ".."
+ }.each do |name|
+ path = File.join(base, name)
+ if obj = self[path]
+ obj[:audit] = :all
+ files << obj
+ else
+ files << self.new(
+ :name => path, :audit => :all
)
+ end
end
+ files
+ end
- # Remove any existing data. This is only used when dealing with
- # links or directories.
- def remove_existing(should)
- return unless s = stat
-
- self.fail "Could not back up; will not replace" unless perform_backup
-
- unless should.to_s == "link"
- return if s.ftype.to_s == should.to_s
- end
-
- case s.ftype
- when "directory"
- if self[:force] == :true
- debug "Removing existing directory for replacement with #{should}"
- FileUtils.rmtree(self[:path])
- else
- notice "Not removing directory; use 'force' to override"
- end
- when "link", "file"
- debug "Removing existing #{s.ftype} for replacement with #{should}"
- File.unlink(self[:path])
- else
- self.fail "Could not back up files of type #{s.ftype}"
- end
- expire
- end
-
- def retrieve
- if source = parameter(:source)
- source.copy_source_values
- end
- super
- end
-
- # Set the checksum, from another property. There are multiple
- # properties that modify the contents of a file, and they need the
- # ability to make sure that the checksum value is in sync.
- def setchecksum(sum = nil)
- if @parameters.include? :checksum
- if sum
- @parameters[:checksum].checksum = sum
- else
- # If they didn't pass in a sum, then tell checksum to
- # figure it out.
- currentvalue = @parameters[:checksum].retrieve
- @parameters[:checksum].checksum = currentvalue
- end
- end
- end
-
- # Should this thing be a normal file? This is a relatively complex
- # way of determining whether we're trying to create a normal file,
- # and it's here so that the logic isn't visible in the content property.
- def should_be_file?
- return true if self[:ensure] == :file
-
- # I.e., it's set to something like "directory"
- return false if e = self[:ensure] and e != :present
-
- # The user doesn't really care, apparently
- if self[:ensure] == :present
- return true unless s = stat
- return(s.ftype == "file" ? true : false)
- end
-
- # If we've gotten here, then :ensure isn't set
- return true if self[:content]
- return true if stat and stat.ftype == "file"
- false
- end
-
- # Stat our file. Depending on the value of the 'links' attribute, we
- # use either 'stat' or 'lstat', and we expect the properties to use the
- # resulting stat object accordingly (mostly by testing the 'ftype'
- # value).
- cached_attr(:stat) do
- method = :stat
-
- # Files are the only types that support links
- if (self.class.name == :file and self[:links] != :follow) or self.class.name == :tidy
- method = :lstat
- end
- path = self[:path]
-
- begin
- File.send(method, self[:path])
- rescue Errno::ENOENT => error
- return nil
- rescue Errno::EACCES => error
- warning "Could not stat; permission denied"
- return nil
- end
- end
-
- # We have to hack this just a little bit, because otherwise we'll get
- # an error when the target and the contents are created as properties on
- # the far side.
- def to_trans(retrieve = true)
- obj = super
- obj.delete(:target) if obj[:target] == :notlink
- obj
- end
-
- # Write out the file. Requires the property name for logging.
- # Write will be done by the content property, along with checksum computation
- def write(property)
- remove_existing(:file)
+ @depthfirst = false
- use_temporary_file = write_temporary_file?
- if use_temporary_file
- path = "#{self[:path]}.puppettmp_#{rand(10000)}"
- path = "#{self[:path]}.puppettmp_#{rand(10000)}" while File.exists?(path) or File.symlink?(path)
- else
- path = self[:path]
- end
-
- mode = self.should(:mode) # might be nil
- umask = mode ? 000 : 022
-
- content_checksum = Puppet::Util.withumask(umask) { File.open(path, 'w', mode) { |f| write_content(f) } }
-
- # And put our new file in place
- if use_temporary_file # This is only not true when our file is empty.
- begin
- fail_if_checksum_is_wrong(path, content_checksum) if validate_checksum?
- File.rename(path, self[:path])
- rescue => detail
- fail "Could not rename temporary file #{path} to #{self[:path]}: #{detail}"
- ensure
- # Make sure the created file gets removed
- File.unlink(path) if FileTest.exists?(path)
- end
- end
-
- # make sure all of the modes are actually correct
- property_fix
+ # Determine the user to write files as.
+ def asuser
+ if self.should(:owner) and ! self.should(:owner).is_a?(Symbol)
+ writeable = Puppet::Util::SUIDManager.asuser(self.should(:owner)) {
+ FileTest.writable?(File.dirname(self[:path]))
+ }
+ # If the parent directory is writeable, then we execute
+ # as the user in question. Otherwise we'll rely on
+ # the 'owner' property to do things.
+ asuser = self.should(:owner) if writeable
end
- private
+ asuser
+ end
- # Should we validate the checksum of the file we're writing?
- def validate_checksum?
- self[:checksum] !~ /time/
- end
+ def bucket
+ return @bucket if @bucket
- # Make sure the file we wrote out is what we think it is.
- def fail_if_checksum_is_wrong(path, content_checksum)
- newsum = parameter(:checksum).sum_file(path)
- return if [:absent, nil, content_checksum].include?(newsum)
+ backup = self[:backup]
+ return nil unless backup
+ return nil if backup =~ /^\./
- self.fail "File written to disk did not match checksum; discarding changes (#{content_checksum} vs #{newsum})"
+ unless catalog or backup == "puppet"
+ fail "Can not find filebucket for backups without a catalog"
end
- # write the current content. Note that if there is no content property
- # simply opening the file with 'w' as done in write is enough to truncate
- # or write an empty length file.
- def write_content(file)
- (content = property(:content)) && content.write(file)
+ unless catalog and filebucket = catalog.resource(:filebucket, backup) or backup == "puppet"
+ fail "Could not find filebucket #{backup} specified in backup"
end
- private
-
- def write_temporary_file?
- # unfortunately we don't know the source file size before fetching it
- # so let's assume the file won't be empty
- (c = property(:content) and c.length) || (s = @parameters[:source] and 1)
- end
+ return default_bucket unless filebucket
- # There are some cases where all of the work does not get done on
- # file creation/modification, so we have to do some extra checking.
- def property_fix
- properties.each do |thing|
- next unless [:mode, :owner, :group, :seluser, :selrole, :seltype, :selrange].include?(thing.name)
+ @bucket = filebucket.bucket
- # Make sure we get a new stat objct
- expire
- currentvalue = thing.retrieve
- thing.sync unless thing.insync?(currentvalue)
- end
- end
+ @bucket
+ end
+
+ def default_bucket
+ Puppet::Type.type(:filebucket).mkdefaultbucket.bucket
+ end
+
+ # Does the file currently exist? Just checks for whether
+ # we have a stat
+ def exist?
+ stat ? true : false
+ end
+
+ # We have to do some extra finishing, to retrieve our bucket if
+ # there is one.
+ def finish
+ # Look up our bucket, if there is one
+ bucket
+ super
+ end
+
+ # Create any children via recursion or whatever.
+ def eval_generate
+ return [] unless self.recurse?
+
+ recurse
+ #recurse.reject do |resource|
+ # catalog.resource(:file, resource[:path])
+ #end.each do |child|
+ # catalog.add_resource child
+ # catalog.relationship_graph.add_edge self, child
+ #end
+ end
+
+ def flush
+ # We want to make sure we retrieve metadata anew on each transaction.
+ @parameters.each do |name, param|
+ param.flush if param.respond_to?(:flush)
+ end
+ @stat = nil
+ end
+
+ def initialize(hash)
+ # Used for caching clients
+ @clients = {}
+
+ super
+
+ # If they've specified a source, we get our 'should' values
+ # from it.
+ unless self[:ensure]
+ if self[:target]
+ self[:ensure] = :symlink
+ elsif self[:content]
+ self[:ensure] = :file
+ end
+ end
+
+ @stat = nil
+ end
+
+ # Configure discovered resources to be purged.
+ def mark_children_for_purging(children)
+ children.each do |name, child|
+ next if child[:source]
+ child[:ensure] = :absent
+ end
+ end
+
+ # Create a new file or directory object as a child to the current
+ # object.
+ def newchild(path)
+ full_path = File.join(self[:path], path)
+
+ # Add some new values to our original arguments -- these are the ones
+ # set at initialization. We specifically want to exclude any param
+ # values set by the :source property or any default values.
+ # LAK:NOTE This is kind of silly, because the whole point here is that
+ # the values set at initialization should live as long as the resource
+ # but values set by default or by :source should only live for the transaction
+ # or so. Unfortunately, we don't have a straightforward way to manage
+ # the different lifetimes of this data, so we kludge it like this.
+ # The right-side hash wins in the merge.
+ options = @original_parameters.merge(:path => full_path).reject { |param, value| value.nil? }
+
+ # These should never be passed to our children.
+ [:parent, :ensure, :recurse, :recurselimit, :target, :alias, :source].each do |param|
+ options.delete(param) if options.include?(param)
+ end
+
+ self.class.new(options)
+ end
+
+ # Files handle paths specially, because they just lengthen their
+ # path names, rather than including the full parent's title each
+ # time.
+ def pathbuilder
+ # We specifically need to call the method here, so it looks
+ # up our parent in the catalog graph.
+ if parent = parent()
+ # We only need to behave specially when our parent is also
+ # a file
+ if parent.is_a?(self.class)
+ # Remove the parent file name
+ list = parent.pathbuilder
+ list.pop # remove the parent's path info
+ return list << self.ref
+ else
+ return super
+ end
+ else
+ return [self.ref]
+ end
+ end
+
+ # Should we be purging?
+ def purge?
+ @parameters.include?(:purge) and (self[:purge] == :true or self[:purge] == "true")
+ end
+
+ # Recursively generate a list of file resources, which will
+ # be used to copy remote files, manage local files, and/or make links
+ # to map to another directory.
+ def recurse
+ children = {}
+ children = recurse_local if self[:recurse] != :remote
+
+ if self[:target]
+ recurse_link(children)
+ elsif self[:source]
+ recurse_remote(children)
+ end
+
+ # If we're purging resources, then delete any resource that isn't on the
+ # remote system.
+ mark_children_for_purging(children) if self.purge?
+
+ result = children.values.sort { |a, b| a[:path] <=> b[:path] }
+ remove_less_specific_files(result)
+ end
+
+ # This is to fix bug #2296, where two files recurse over the same
+ # set of files. It's a rare case, and when it does happen you're
+ # not likely to have many actual conflicts, which is good, because
+ # this is a pretty inefficient implementation.
+ def remove_less_specific_files(files)
+ mypath = self[:path].split(File::Separator)
+ other_paths = catalog.vertices.
+ select { |r| r.is_a?(self.class) and r[:path] != self[:path] }.
+ collect { |r| r[:path].split(File::Separator) }.
+ select { |p| p[0,mypath.length] == mypath }
+
+ return files if other_paths.empty?
+
+ files.reject { |file|
+ path = file[:path].split(File::Separator)
+ other_paths.any? { |p| path[0,p.length] == p }
+ }
+ end
+
+ # A simple method for determining whether we should be recursing.
+ def recurse?
+ return false unless @parameters.include?(:recurse)
+
+ val = @parameters[:recurse].value
+
+ !!(val and (val == true or val == :remote))
+ end
+
+ # Recurse the target of the link.
+ def recurse_link(children)
+ perform_recursion(self[:target]).each do |meta|
+ if meta.relative_path == "."
+ self[:ensure] = :directory
+ next
+ end
+
+ children[meta.relative_path] ||= newchild(meta.relative_path)
+ if meta.ftype == "directory"
+ children[meta.relative_path][:ensure] = :directory
+ else
+ children[meta.relative_path][:ensure] = :link
+ children[meta.relative_path][:target] = meta.full_path
+ end
+ end
+ children
+ end
+
+ # Recurse the file itself, returning a Metadata instance for every found file.
+ def recurse_local
+ result = perform_recursion(self[:path])
+ return {} unless result
+ result.inject({}) do |hash, meta|
+ next hash if meta.relative_path == "."
+
+ hash[meta.relative_path] = newchild(meta.relative_path)
+ hash
+ end
+ end
+
+ # Recurse against our remote file.
+ def recurse_remote(children)
+ sourceselect = self[:sourceselect]
+
+ total = self[:source].collect do |source|
+ next unless result = perform_recursion(source)
+ return if top = result.find { |r| r.relative_path == "." } and top.ftype != "directory"
+ result.each { |data| data.source = "#{source}/#{data.relative_path}" }
+ break result if result and ! result.empty? and sourceselect == :first
+ result
+ end.flatten
+
+ # This only happens if we have sourceselect == :all
+ unless sourceselect == :first
+ found = []
+ total.reject! do |data|
+ result = found.include?(data.relative_path)
+ found << data.relative_path unless found.include?(data.relative_path)
+ result
+ end
+ end
+
+ total.each do |meta|
+ if meta.relative_path == "."
+ parameter(:source).metadata = meta
+ next
+ end
+ children[meta.relative_path] ||= newchild(meta.relative_path)
+ children[meta.relative_path][:source] = meta.source
+ children[meta.relative_path][:checksum] = :md5 if meta.ftype == "file"
+
+ children[meta.relative_path].parameter(:source).metadata = meta
+ end
+
+ children
+ end
+
+ def perform_recursion(path)
+
+ Puppet::FileServing::Metadata.search(
+
+ path,
+ :links => self[:links],
+ :recurse => (self[:recurse] == :remote ? true : self[:recurse]),
+
+ :recurselimit => self[:recurselimit],
+ :ignore => self[:ignore],
+ :checksum_type => (self[:source] || self[:content]) ? self[:checksum] : :none
+ )
+ end
+
+ # Remove any existing data. This is only used when dealing with
+ # links or directories.
+ def remove_existing(should)
+ return unless s = stat
+
+ self.fail "Could not back up; will not replace" unless perform_backup
+
+ unless should.to_s == "link"
+ return if s.ftype.to_s == should.to_s
+ end
+
+ case s.ftype
+ when "directory"
+ if self[:force] == :true
+ debug "Removing existing directory for replacement with #{should}"
+ FileUtils.rmtree(self[:path])
+ else
+ notice "Not removing directory; use 'force' to override"
+ end
+ when "link", "file"
+ debug "Removing existing #{s.ftype} for replacement with #{should}"
+ File.unlink(self[:path])
+ else
+ self.fail "Could not back up files of type #{s.ftype}"
+ end
+ expire
+ end
+
+ def retrieve
+ if source = parameter(:source)
+ source.copy_source_values
+ end
+ super
+ end
+
+ # Set the checksum, from another property. There are multiple
+ # properties that modify the contents of a file, and they need the
+ # ability to make sure that the checksum value is in sync.
+ def setchecksum(sum = nil)
+ if @parameters.include? :checksum
+ if sum
+ @parameters[:checksum].checksum = sum
+ else
+ # If they didn't pass in a sum, then tell checksum to
+ # figure it out.
+ currentvalue = @parameters[:checksum].retrieve
+ @parameters[:checksum].checksum = currentvalue
+ end
+ end
+ end
+
+ # Should this thing be a normal file? This is a relatively complex
+ # way of determining whether we're trying to create a normal file,
+ # and it's here so that the logic isn't visible in the content property.
+ def should_be_file?
+ return true if self[:ensure] == :file
+
+ # I.e., it's set to something like "directory"
+ return false if e = self[:ensure] and e != :present
+
+ # The user doesn't really care, apparently
+ if self[:ensure] == :present
+ return true unless s = stat
+ return(s.ftype == "file" ? true : false)
+ end
+
+ # If we've gotten here, then :ensure isn't set
+ return true if self[:content]
+ return true if stat and stat.ftype == "file"
+ false
+ end
+
+ # Stat our file. Depending on the value of the 'links' attribute, we
+ # use either 'stat' or 'lstat', and we expect the properties to use the
+ # resulting stat object accordingly (mostly by testing the 'ftype'
+ # value).
+ cached_attr(:stat) do
+ method = :stat
+
+ # Files are the only types that support links
+ if (self.class.name == :file and self[:links] != :follow) or self.class.name == :tidy
+ method = :lstat
+ end
+ path = self[:path]
+
+ begin
+ File.send(method, self[:path])
+ rescue Errno::ENOENT => error
+ return nil
+ rescue Errno::EACCES => error
+ warning "Could not stat; permission denied"
+ return nil
+ end
+ end
+
+ # We have to hack this just a little bit, because otherwise we'll get
+ # an error when the target and the contents are created as properties on
+ # the far side.
+ def to_trans(retrieve = true)
+ obj = super
+ obj.delete(:target) if obj[:target] == :notlink
+ obj
+ end
+
+ # Write out the file. Requires the property name for logging.
+ # Write will be done by the content property, along with checksum computation
+ def write(property)
+ remove_existing(:file)
+
+ use_temporary_file = write_temporary_file?
+ if use_temporary_file
+ path = "#{self[:path]}.puppettmp_#{rand(10000)}"
+ path = "#{self[:path]}.puppettmp_#{rand(10000)}" while File.exists?(path) or File.symlink?(path)
+ else
+ path = self[:path]
+ end
+
+ mode = self.should(:mode) # might be nil
+ umask = mode ? 000 : 022
+
+ content_checksum = Puppet::Util.withumask(umask) { File.open(path, 'w', mode) { |f| write_content(f) } }
+
+ # And put our new file in place
+ if use_temporary_file # This is only not true when our file is empty.
+ begin
+ fail_if_checksum_is_wrong(path, content_checksum) if validate_checksum?
+ File.rename(path, self[:path])
+ rescue => detail
+ fail "Could not rename temporary file #{path} to #{self[:path]}: #{detail}"
+ ensure
+ # Make sure the created file gets removed
+ File.unlink(path) if FileTest.exists?(path)
+ end
+ end
+
+ # make sure all of the modes are actually correct
+ property_fix
+
+ end
+
+ private
+
+ # Should we validate the checksum of the file we're writing?
+ def validate_checksum?
+ self[:checksum] !~ /time/
+ end
+
+ # Make sure the file we wrote out is what we think it is.
+ def fail_if_checksum_is_wrong(path, content_checksum)
+ newsum = parameter(:checksum).sum_file(path)
+ return if [:absent, nil, content_checksum].include?(newsum)
+
+ self.fail "File written to disk did not match checksum; discarding changes (#{content_checksum} vs #{newsum})"
+ end
+
+ # write the current content. Note that if there is no content property
+ # simply opening the file with 'w' as done in write is enough to truncate
+ # or write an empty length file.
+ def write_content(file)
+ (content = property(:content)) && content.write(file)
+ end
+
+ private
+
+ def write_temporary_file?
+ # unfortunately we don't know the source file size before fetching it
+ # so let's assume the file won't be empty
+ (c = property(:content) and c.length) || (s = @parameters[:source] and 1)
+ end
+
+ # There are some cases where all of the work does not get done on
+ # file creation/modification, so we have to do some extra checking.
+ def property_fix
+ properties.each do |thing|
+ next unless [:mode, :owner, :group, :seluser, :selrole, :seltype, :selrange].include?(thing.name)
+
+ # Make sure we get a new stat objct
+ expire
+ currentvalue = thing.retrieve
+ thing.sync unless thing.insync?(currentvalue)
+ end
+ end
end
# We put all of the properties in separate files, because there are so many
diff --git a/lib/puppet/type/file/checksum.rb b/lib/puppet/type/file/checksum.rb
index 3e2fdbf09..732460738 100755
--- a/lib/puppet/type/file/checksum.rb
+++ b/lib/puppet/type/file/checksum.rb
@@ -3,31 +3,31 @@ require 'puppet/util/checksums'
# Specify which checksum algorithm to use when checksumming
# files.
Puppet::Type.type(:file).newparam(:checksum) do
- include Puppet::Util::Checksums
+ include Puppet::Util::Checksums
- desc "The checksum type to use when checksumming a file.
+ desc "The checksum type to use when checksumming a file.
- The default checksum parameter, if checksums are enabled, is md5."
+ The default checksum parameter, if checksums are enabled, is md5."
- newvalues "md5", "md5lite", "timestamp", "mtime", "time", "none"
+ newvalues "md5", "md5lite", "timestamp", "mtime", "time", "none"
- defaultto :md5
+ defaultto :md5
- def sum(content)
- type = value || :md5 # because this might be called before defaults are set
- "{#{type}}" + send(type, content)
- end
+ def sum(content)
+ type = value || :md5 # because this might be called before defaults are set
+ "{#{type}}" + send(type, content)
+ end
- def sum_file(path)
- type = value || :md5 # because this might be called before defaults are set
- method = type.to_s + "_file"
- "{#{type}}" + send(method, path).to_s
- end
+ def sum_file(path)
+ type = value || :md5 # because this might be called before defaults are set
+ method = type.to_s + "_file"
+ "{#{type}}" + send(method, path).to_s
+ end
- def sum_stream(&block)
- type = value || :md5 # same comment as above
- method = type.to_s + "_stream"
- checksum = send(method, &block)
- "{#{type}}#{checksum}"
- end
+ def sum_stream(&block)
+ type = value || :md5 # same comment as above
+ method = type.to_s + "_stream"
+ checksum = send(method, &block)
+ "{#{type}}#{checksum}"
+ end
end
diff --git a/lib/puppet/type/file/content.rb b/lib/puppet/type/file/content.rb
index 472fdb443..74b380f55 100755
--- a/lib/puppet/type/file/content.rb
+++ b/lib/puppet/type/file/content.rb
@@ -7,204 +7,204 @@ require 'puppet/network/http/api/v1'
require 'puppet/network/http/compression'
module Puppet
- Puppet::Type.type(:file).newproperty(:content) do
- include Puppet::Util::Diff
- include Puppet::Util::Checksums
- include Puppet::Network::HTTP::API::V1
- include Puppet::Network::HTTP::Compression.module
-
- attr_reader :actual_content
-
- desc "Specify the contents of a file as a string. Newlines, tabs, and
- spaces can be specified using the escaped syntax (e.g., \\n for a newline). The primary purpose of this parameter is to provide a
- kind of limited templating::
-
- define resolve(nameserver1, nameserver2, domain, search) {
- $str = \"search $search
- domain $domain
- nameserver $nameserver1
- nameserver $nameserver2
- \"
-
- file { \"/etc/resolv.conf\":
- content => $str
- }
- }
-
- This attribute is especially useful when used with
- `PuppetTemplating templating`:trac:."
-
- # Store a checksum as the value, rather than the actual content.
- # Simplifies everything.
- munge do |value|
- if value == :absent
- value
- elsif checksum?(value)
- # XXX This is potentially dangerous because it means users can't write a file whose
- # entire contents are a plain checksum
- value
- else
- @actual_content = value
- resource.parameter(:checksum).sum(value)
- end
- end
+ Puppet::Type.type(:file).newproperty(:content) do
+ include Puppet::Util::Diff
+ include Puppet::Util::Checksums
+ include Puppet::Network::HTTP::API::V1
+ include Puppet::Network::HTTP::Compression.module
+
+ attr_reader :actual_content
+
+ desc "Specify the contents of a file as a string. Newlines, tabs, and
+ spaces can be specified using the escaped syntax (e.g., \\n for a newline). The primary purpose of this parameter is to provide a
+ kind of limited templating::
+
+ define resolve(nameserver1, nameserver2, domain, search) {
+ $str = \"search $search
+ domain $domain
+ nameserver $nameserver1
+ nameserver $nameserver2
+ \"
+
+ file { \"/etc/resolv.conf\":
+ content => $str
+ }
+ }
+
+ This attribute is especially useful when used with
+ `PuppetTemplating templating`:trac:."
+
+ # Store a checksum as the value, rather than the actual content.
+ # Simplifies everything.
+ munge do |value|
+ if value == :absent
+ value
+ elsif checksum?(value)
+ # XXX This is potentially dangerous because it means users can't write a file whose
+ # entire contents are a plain checksum
+ value
+ else
+ @actual_content = value
+ resource.parameter(:checksum).sum(value)
+ end
+ end
- # Checksums need to invert how changes are printed.
- def change_to_s(currentvalue, newvalue)
- # Our "new" checksum value is provided by the source.
- if source = resource.parameter(:source) and tmp = source.checksum
- newvalue = tmp
- end
- if currentvalue == :absent
- return "defined content as '#{newvalue}'"
- elsif newvalue == :absent
- return "undefined content from '#{currentvalue}'"
- else
- return "content changed '#{currentvalue}' to '#{newvalue}'"
- end
- end
+ # Checksums need to invert how changes are printed.
+ def change_to_s(currentvalue, newvalue)
+ # Our "new" checksum value is provided by the source.
+ if source = resource.parameter(:source) and tmp = source.checksum
+ newvalue = tmp
+ end
+ if currentvalue == :absent
+ return "defined content as '#{newvalue}'"
+ elsif newvalue == :absent
+ return "undefined content from '#{currentvalue}'"
+ else
+ return "content changed '#{currentvalue}' to '#{newvalue}'"
+ end
+ end
- def checksum_type
- if source = resource.parameter(:source)
- result = source.checksum
- else checksum = resource.parameter(:checksum)
- result = resource[:checksum]
- end
- if result =~ /^\{(\w+)\}.+/
- return $1.to_sym
- else
- return result
- end
- end
+ def checksum_type
+ if source = resource.parameter(:source)
+ result = source.checksum
+ else checksum = resource.parameter(:checksum)
+ result = resource[:checksum]
+ end
+ if result =~ /^\{(\w+)\}.+/
+ return $1.to_sym
+ else
+ return result
+ end
+ end
- def length
- (actual_content and actual_content.length) || 0
- end
+ def length
+ (actual_content and actual_content.length) || 0
+ end
- def content
- self.should
- end
+ def content
+ self.should
+ end
- # Override this method to provide diffs if asked for.
- # Also, fix #872: when content is used, and replace is true, the file
- # should be insync when it exists
- def insync?(is)
- if resource.should_be_file?
- return false if is == :absent
- else
- return true
- end
-
- return true if ! @resource.replace?
- return true unless self.should
-
- result = super
-
- if ! result and Puppet[:show_diff]
- write_temporarily do |path|
- print diff(@resource[:path], path)
- end
- end
- result
- end
+ # Override this method to provide diffs if asked for.
+ # Also, fix #872: when content is used, and replace is true, the file
+ # should be insync when it exists
+ def insync?(is)
+ if resource.should_be_file?
+ return false if is == :absent
+ else
+ return true
+ end
- def retrieve
- return :absent unless stat = @resource.stat
- ftype = stat.ftype
- # Don't even try to manage the content on directories or links
- return nil if ["directory","link"].include?(ftype)
-
- begin
- resource.parameter(:checksum).sum_file(resource[:path])
- rescue => detail
- raise Puppet::Error, "Could not read #{ftype} #{@resource.title}: #{detail}"
- end
- end
+ return true if ! @resource.replace?
+ return true unless self.should
- # Make sure we're also managing the checksum property.
- def should=(value)
- @resource.newattr(:checksum) unless @resource.parameter(:checksum)
- super
+ result = super
+
+ if ! result and Puppet[:show_diff]
+ write_temporarily do |path|
+ print diff(@resource[:path], path)
end
+ end
+ result
+ end
- # Just write our content out to disk.
- def sync
- return_event = @resource.stat ? :file_changed : :file_created
+ def retrieve
+ return :absent unless stat = @resource.stat
+ ftype = stat.ftype
+ # Don't even try to manage the content on directories or links
+ return nil if ["directory","link"].include?(ftype)
+
+ begin
+ resource.parameter(:checksum).sum_file(resource[:path])
+ rescue => detail
+ raise Puppet::Error, "Could not read #{ftype} #{@resource.title}: #{detail}"
+ end
+ end
- # We're safe not testing for the 'source' if there's no 'should'
- # because we wouldn't have gotten this far if there weren't at least
- # one valid value somewhere.
- @resource.write(:content)
+ # Make sure we're also managing the checksum property.
+ def should=(value)
+ @resource.newattr(:checksum) unless @resource.parameter(:checksum)
+ super
+ end
- return_event
- end
+ # Just write our content out to disk.
+ def sync
+ return_event = @resource.stat ? :file_changed : :file_created
- def write_temporarily
- tempfile = Tempfile.new("puppet-file")
- tempfile.open
+ # We're safe not testing for the 'source' if there's no 'should'
+ # because we wouldn't have gotten this far if there weren't at least
+ # one valid value somewhere.
+ @resource.write(:content)
- write(tempfile)
+ return_event
+ end
- tempfile.close
+ def write_temporarily
+ tempfile = Tempfile.new("puppet-file")
+ tempfile.open
- yield tempfile.path
+ write(tempfile)
- tempfile.delete
- end
+ tempfile.close
- def write(file)
- resource.parameter(:checksum).sum_stream { |sum|
- each_chunk_from(actual_content || resource.parameter(:source)) { |chunk|
- sum << chunk
- file.print chunk
- }
- }
- end
+ yield tempfile.path
- def each_chunk_from(source_or_content)
- if source_or_content.is_a?(String)
- yield source_or_content
- elsif source_or_content.nil?
- yield read_file_from_filebucket
- elsif source_or_content.local?
- chunk_file_from_disk(source_or_content) { |chunk| yield chunk }
- else
- chunk_file_from_source(source_or_content) { |chunk| yield chunk }
- end
- end
+ tempfile.delete
+ end
- private
+ def write(file)
+ resource.parameter(:checksum).sum_stream { |sum|
+ each_chunk_from(actual_content || resource.parameter(:source)) { |chunk|
+ sum << chunk
+ file.print chunk
+ }
+ }
+ end
+
+ def each_chunk_from(source_or_content)
+ if source_or_content.is_a?(String)
+ yield source_or_content
+ elsif source_or_content.nil?
+ yield read_file_from_filebucket
+ elsif source_or_content.local?
+ chunk_file_from_disk(source_or_content) { |chunk| yield chunk }
+ else
+ chunk_file_from_source(source_or_content) { |chunk| yield chunk }
+ end
+ end
+
+ private
- def chunk_file_from_disk(source_or_content)
- File.open(source_or_content.full_path, "r") do |src|
- while chunk = src.read(8192)
- yield chunk
- end
- end
+ def chunk_file_from_disk(source_or_content)
+ File.open(source_or_content.full_path, "r") do |src|
+ while chunk = src.read(8192)
+ yield chunk
end
+ end
+ end
- def chunk_file_from_source(source_or_content)
- request = Puppet::Indirector::Request.new(:file_content, :find, source_or_content.full_path)
- connection = Puppet::Network::HttpPool.http_instance(source_or_content.server, source_or_content.port)
- connection.request_get(indirection2uri(request), add_accept_encoding({"Accept" => "raw"})) do |response|
- case response.code
- when "404"; nil
- when /^2/; uncompress(response) { |uncompressor| response.read_body { |chunk| yield uncompressor.uncompress(chunk) } }
- else
- # Raise the http error if we didn't get a 'success' of some kind.
- message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
- raise Net::HTTPError.new(message, response)
- end
- end
+ def chunk_file_from_source(source_or_content)
+ request = Puppet::Indirector::Request.new(:file_content, :find, source_or_content.full_path)
+ connection = Puppet::Network::HttpPool.http_instance(source_or_content.server, source_or_content.port)
+ connection.request_get(indirection2uri(request), add_accept_encoding({"Accept" => "raw"})) do |response|
+ case response.code
+ when "404"; nil
+ when /^2/; uncompress(response) { |uncompressor| response.read_body { |chunk| yield uncompressor.uncompress(chunk) } }
+ else
+ # Raise the http error if we didn't get a 'success' of some kind.
+ message = "Error #{response.code} on SERVER: #{(response.body||'').empty? ? response.message : uncompress_body(response)}"
+ raise Net::HTTPError.new(message, response)
end
+ end
+ end
- def read_file_from_filebucket
- raise "Could not get filebucket from file" unless dipper = resource.bucket
- sum = should.sub(/\{\w+\}/, '')
+ def read_file_from_filebucket
+ raise "Could not get filebucket from file" unless dipper = resource.bucket
+ sum = should.sub(/\{\w+\}/, '')
- dipper.getfile(sum)
- rescue => detail
- fail "Could not retrieve content for #{should} from filebucket: #{detail}"
- end
+ dipper.getfile(sum)
+ rescue => detail
+ fail "Could not retrieve content for #{should} from filebucket: #{detail}"
end
+ end
end
diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb
index a6eed8a1d..c74a1d47a 100755
--- a/lib/puppet/type/file/ensure.rb
+++ b/lib/puppet/type/file/ensure.rb
@@ -1,170 +1,170 @@
module Puppet
- Puppet::Type.type(:file).ensurable do
- require 'etc'
- desc "Whether to create files that don't currently exist.
- Possible values are *absent*, *present*, *file*, and *directory*.
- Specifying ``present`` will match any form of file existence, and
- if the file is missing will create an empty file. Specifying
- ``absent`` will delete the file (and directory if recurse => true).
-
- Anything other than those values will be considered to be a symlink.
- For instance, the following text creates a link::
-
- # Useful on solaris
- file { \"/etc/inetd.conf\":
- ensure => \"/etc/inet/inetd.conf\"
- }
-
- You can make relative links::
-
- # Useful on solaris
- file { \"/etc/inetd.conf\":
- ensure => \"inet/inetd.conf\"
- }
-
- If you need to make a relative link to a file named the same
- as one of the valid values, you must prefix it with ``./`` or
- something similar.
-
- You can also make recursive symlinks, which will create a
- directory structure that maps to the target directory,
- with directories corresponding to each directory
- and links corresponding to each file."
-
- # Most 'ensure' properties have a default, but with files we, um, don't.
- nodefault
-
- newvalue(:absent) do
- File.unlink(@resource[:path])
- end
+ Puppet::Type.type(:file).ensurable do
+ require 'etc'
+ desc "Whether to create files that don't currently exist.
+ Possible values are *absent*, *present*, *file*, and *directory*.
+ Specifying ``present`` will match any form of file existence, and
+ if the file is missing will create an empty file. Specifying
+ ``absent`` will delete the file (and directory if recurse => true).
+
+ Anything other than those values will be considered to be a symlink.
+ For instance, the following text creates a link::
+
+ # Useful on solaris
+ file { \"/etc/inetd.conf\":
+ ensure => \"/etc/inet/inetd.conf\"
+ }
+
+ You can make relative links::
+
+ # Useful on solaris
+ file { \"/etc/inetd.conf\":
+ ensure => \"inet/inetd.conf\"
+ }
+
+ If you need to make a relative link to a file named the same
+ as one of the valid values, you must prefix it with ``./`` or
+ something similar.
+
+ You can also make recursive symlinks, which will create a
+ directory structure that maps to the target directory,
+ with directories corresponding to each directory
+ and links corresponding to each file."
+
+ # Most 'ensure' properties have a default, but with files we, um, don't.
+ nodefault
+
+ newvalue(:absent) do
+ File.unlink(@resource[:path])
+ end
- aliasvalue(:false, :absent)
+ aliasvalue(:false, :absent)
- newvalue(:file, :event => :file_created) do
- # Make sure we're not managing the content some other way
- if property = @resource.property(:content)
- property.sync
- else
- @resource.write(:ensure)
- mode = @resource.should(:mode)
- end
- end
+ newvalue(:file, :event => :file_created) do
+ # Make sure we're not managing the content some other way
+ if property = @resource.property(:content)
+ property.sync
+ else
+ @resource.write(:ensure)
+ mode = @resource.should(:mode)
+ end
+ end
- #aliasvalue(:present, :file)
- newvalue(:present, :event => :file_created) do
- # Make a file if they want something, but this will match almost
- # anything.
- set_file
- end
+ #aliasvalue(:present, :file)
+ newvalue(:present, :event => :file_created) do
+ # Make a file if they want something, but this will match almost
+ # anything.
+ set_file
+ end
- newvalue(:directory, :event => :directory_created) do
- mode = @resource.should(:mode)
- parent = File.dirname(@resource[:path])
- unless FileTest.exists? parent
- raise Puppet::Error,
- "Cannot create #{@resource[:path]}; parent directory #{parent} does not exist"
- end
- if mode
- Puppet::Util.withumask(000) do
- Dir.mkdir(@resource[:path],mode)
- end
- else
- Dir.mkdir(@resource[:path])
- end
- @resource.send(:property_fix)
- return :directory_created
+ newvalue(:directory, :event => :directory_created) do
+ mode = @resource.should(:mode)
+ parent = File.dirname(@resource[:path])
+ unless FileTest.exists? parent
+ raise Puppet::Error,
+ "Cannot create #{@resource[:path]}; parent directory #{parent} does not exist"
+ end
+ if mode
+ Puppet::Util.withumask(000) do
+ Dir.mkdir(@resource[:path],mode)
end
+ else
+ Dir.mkdir(@resource[:path])
+ end
+ @resource.send(:property_fix)
+ return :directory_created
+ end
- newvalue(:link, :event => :link_created) do
- fail "Cannot create a symlink without a target" unless property = resource.property(:target)
- property.retrieve
- property.mklink
- end
+ newvalue(:link, :event => :link_created) do
+ fail "Cannot create a symlink without a target" unless property = resource.property(:target)
+ property.retrieve
+ property.mklink
+ end
- # Symlinks.
- newvalue(/./) do
- # This code never gets executed. We need the regex to support
- # specifying it, but the work is done in the 'symlink' code block.
- end
+ # Symlinks.
+ newvalue(/./) do
+ # This code never gets executed. We need the regex to support
+ # specifying it, but the work is done in the 'symlink' code block.
+ end
- munge do |value|
- value = super(value)
- value,resource[:target] = :link,value unless value.is_a? Symbol
- resource[:links] = :manage if value == :link and resource[:links] != :follow
- value
- end
+ munge do |value|
+ value = super(value)
+ value,resource[:target] = :link,value unless value.is_a? Symbol
+ resource[:links] = :manage if value == :link and resource[:links] != :follow
+ value
+ end
- def change_to_s(currentvalue, newvalue)
- return super unless newvalue.to_s == "file"
-
- return super unless property = @resource.property(:content)
-
- # We know that content is out of sync if we're here, because
- # it's essentially equivalent to 'ensure' in the transaction.
- if source = @resource.parameter(:source)
- should = source.checksum
- else
- should = property.should
- end
- if should == :absent
- is = property.retrieve
- else
- is = :absent
- end
-
- property.change_to_s(is, should)
- end
+ def change_to_s(currentvalue, newvalue)
+ return super unless newvalue.to_s == "file"
+
+ return super unless property = @resource.property(:content)
+
+ # We know that content is out of sync if we're here, because
+ # it's essentially equivalent to 'ensure' in the transaction.
+ if source = @resource.parameter(:source)
+ should = source.checksum
+ else
+ should = property.should
+ end
+ if should == :absent
+ is = property.retrieve
+ else
+ is = :absent
+ end
+
+ property.change_to_s(is, should)
+ end
- # Check that we can actually create anything
- def check
- basedir = File.dirname(@resource[:path])
-
- if ! FileTest.exists?(basedir)
- raise Puppet::Error,
- "Can not create #{@resource.title}; parent directory does not exist"
- elsif ! FileTest.directory?(basedir)
- raise Puppet::Error,
- "Can not create #{@resource.title}; #{dirname} is not a directory"
- end
- end
+ # Check that we can actually create anything
+ def check
+ basedir = File.dirname(@resource[:path])
+
+ if ! FileTest.exists?(basedir)
+ raise Puppet::Error,
+ "Can not create #{@resource.title}; parent directory does not exist"
+ elsif ! FileTest.directory?(basedir)
+ raise Puppet::Error,
+ "Can not create #{@resource.title}; #{dirname} is not a directory"
+ end
+ end
- # We have to treat :present specially, because it works with any
- # type of file.
- def insync?(currentvalue)
- unless currentvalue == :absent or resource.replace?
- return true
- end
-
- if self.should == :present
- return !(currentvalue.nil? or currentvalue == :absent)
- else
- return super(currentvalue)
- end
- end
+ # We have to treat :present specially, because it works with any
+ # type of file.
+ def insync?(currentvalue)
+ unless currentvalue == :absent or resource.replace?
+ return true
+ end
+
+ if self.should == :present
+ return !(currentvalue.nil? or currentvalue == :absent)
+ else
+ return super(currentvalue)
+ end
+ end
- def retrieve
- if stat = @resource.stat(false)
- return stat.ftype.intern
- else
- if self.should == :false
- return :false
- else
- return :absent
- end
- end
+ def retrieve
+ if stat = @resource.stat(false)
+ return stat.ftype.intern
+ else
+ if self.should == :false
+ return :false
+ else
+ return :absent
end
+ end
+ end
- def sync
- @resource.remove_existing(self.should)
- if self.should == :absent
- return :file_removed
- end
+ def sync
+ @resource.remove_existing(self.should)
+ if self.should == :absent
+ return :file_removed
+ end
- event = super
+ event = super
- event
- end
+ event
end
+ end
end
diff --git a/lib/puppet/type/file/group.rb b/lib/puppet/type/file/group.rb
index b00eb23e3..5ed5166bc 100755
--- a/lib/puppet/type/file/group.rb
+++ b/lib/puppet/type/file/group.rb
@@ -2,112 +2,112 @@ require 'puppet/util/posix'
# Manage file group ownership.
module Puppet
- Puppet::Type.type(:file).newproperty(:group) do
- include Puppet::Util::POSIX
+ Puppet::Type.type(:file).newproperty(:group) do
+ include Puppet::Util::POSIX
- require 'etc'
- desc "Which group should own the file. Argument can be either group
- name or group ID."
- @event = :file_changed
+ require 'etc'
+ desc "Which group should own the file. Argument can be either group
+ name or group ID."
+ @event = :file_changed
- validate do |group|
- raise(Puppet::Error, "Invalid group name '#{group.inspect}'") unless group and group != ""
- end
+ validate do |group|
+ raise(Puppet::Error, "Invalid group name '#{group.inspect}'") unless group and group != ""
+ end
- def id2name(id)
- return id.to_s if id.is_a?(Symbol)
- return nil if id > Puppet[:maximum_uid].to_i
- begin
- group = Etc.getgrgid(id)
- rescue ArgumentError
- return nil
- end
- if group.gid == ""
- return nil
- else
- return group.name
- end
- end
+ def id2name(id)
+ return id.to_s if id.is_a?(Symbol)
+ return nil if id > Puppet[:maximum_uid].to_i
+ begin
+ group = Etc.getgrgid(id)
+ rescue ArgumentError
+ return nil
+ end
+ if group.gid == ""
+ return nil
+ else
+ return group.name
+ end
+ end
- # We want to print names, not numbers
- def is_to_s(currentvalue)
- if currentvalue.is_a? Integer
- id2name(currentvalue) || currentvalue
- else
- return currentvalue.to_s
- end
- end
+ # We want to print names, not numbers
+ def is_to_s(currentvalue)
+ if currentvalue.is_a? Integer
+ id2name(currentvalue) || currentvalue
+ else
+ return currentvalue.to_s
+ end
+ end
- def should_to_s(newvalue = @should)
- if newvalue.is_a? Integer
- id2name(newvalue) || newvalue
- else
- return newvalue.to_s
- end
- end
+ def should_to_s(newvalue = @should)
+ if newvalue.is_a? Integer
+ id2name(newvalue) || newvalue
+ else
+ return newvalue.to_s
+ end
+ end
- def insync?(current)
- @should.each do |value|
- if value =~ /^\d+$/
- gid = Integer(value)
- elsif value.is_a?(String)
- fail "Could not find group #{value}" unless gid = gid(value)
- else
- gid = value
- end
-
- return true if gid == current
- end
- false
+ def insync?(current)
+ @should.each do |value|
+ if value =~ /^\d+$/
+ gid = Integer(value)
+ elsif value.is_a?(String)
+ fail "Could not find group #{value}" unless gid = gid(value)
+ else
+ gid = value
end
- def retrieve
- return :absent unless stat = resource.stat(false)
+ return true if gid == current
+ end
+ false
+ end
- currentvalue = stat.gid
+ def retrieve
+ return :absent unless stat = resource.stat(false)
- # On OS X, files that are owned by -2 get returned as really
- # large GIDs instead of negative ones. This isn't a Ruby bug,
- # it's an OS X bug, since it shows up in perl, too.
- if currentvalue > Puppet[:maximum_uid].to_i
- self.warning "Apparently using negative GID (#{currentvalue}) on a platform that does not consistently handle them"
- currentvalue = :silly
- end
+ currentvalue = stat.gid
- currentvalue
- end
+ # On OS X, files that are owned by -2 get returned as really
+ # large GIDs instead of negative ones. This isn't a Ruby bug,
+ # it's an OS X bug, since it shows up in perl, too.
+ if currentvalue > Puppet[:maximum_uid].to_i
+ self.warning "Apparently using negative GID (#{currentvalue}) on a platform that does not consistently handle them"
+ currentvalue = :silly
+ end
- # Determine if the group is valid, and if so, return the GID
- def validgroup?(value)
- Integer(value) rescue gid(value) || false
- end
+ currentvalue
+ end
- # Normal users will only be able to manage certain groups. Right now,
- # we'll just let it fail, but we should probably set things up so
- # that users get warned if they try to change to an unacceptable group.
- def sync
- # Set our method appropriately, depending on links.
- if resource[:links] == :manage
- method = :lchown
- else
- method = :chown
- end
-
- gid = nil
- @should.each do |group|
- break if gid = validgroup?(group)
- end
-
- raise Puppet::Error, "Could not find group(s) #{@should.join(",")}" unless gid
-
- begin
- # set owner to nil so it's ignored
- File.send(method, nil, gid, resource[:path])
- rescue => detail
- error = Puppet::Error.new( "failed to chgrp #{resource[:path]} to #{gid}: #{detail.message}")
- raise error
- end
- :file_changed
- end
+ # Determine if the group is valid, and if so, return the GID
+ def validgroup?(value)
+ Integer(value) rescue gid(value) || false
+ end
+
+ # Normal users will only be able to manage certain groups. Right now,
+ # we'll just let it fail, but we should probably set things up so
+ # that users get warned if they try to change to an unacceptable group.
+ def sync
+ # Set our method appropriately, depending on links.
+ if resource[:links] == :manage
+ method = :lchown
+ else
+ method = :chown
+ end
+
+ gid = nil
+ @should.each do |group|
+ break if gid = validgroup?(group)
+ end
+
+ raise Puppet::Error, "Could not find group(s) #{@should.join(",")}" unless gid
+
+ begin
+ # set owner to nil so it's ignored
+ File.send(method, nil, gid, resource[:path])
+ rescue => detail
+ error = Puppet::Error.new( "failed to chgrp #{resource[:path]} to #{gid}: #{detail.message}")
+ raise error
+ end
+ :file_changed
end
+ end
end
diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/mode.rb
index 31209f42e..9abf56d26 100755
--- a/lib/puppet/type/file/mode.rb
+++ b/lib/puppet/type/file/mode.rb
@@ -2,123 +2,123 @@
# for specification (e.g., u+rwx, or -0011), but for now only supports
# specifying the full mode.
module Puppet
- Puppet::Type.type(:file).newproperty(:mode) do
- require 'etc'
- desc "Mode the file should be. Currently relatively limited:
- you must specify the exact mode the file should be.
-
- Note that when you set the mode of a directory, Puppet always
- sets the search/traverse (1) bit anywhere the read (4) bit is set.
- This is almost always what you want: read allows you to list the
- entries in a directory, and search/traverse allows you to access
- (read/write/execute) those entries.) Because of this feature, you
- can recursively make a directory and all of the files in it
- world-readable by setting e.g.::
-
- file { '/some/dir':
- mode => 644,
- recurse => true,
- }
-
- In this case all of the files underneath ``/some/dir`` will have
- mode 644, and all of the directories will have mode 755."
-
- @event = :file_changed
-
- # Our modes are octal, so make sure they print correctly. Other
- # valid values are symbols, basically
- def is_to_s(currentvalue)
- case currentvalue
- when Integer
- return "%o" % currentvalue
- when Symbol
- return currentvalue
- else
- raise Puppet::DevError, "Invalid current value for mode: #{currentvalue.inspect}"
- end
- end
+ Puppet::Type.type(:file).newproperty(:mode) do
+ require 'etc'
+ desc "Mode the file should be. Currently relatively limited:
+ you must specify the exact mode the file should be.
+
+ Note that when you set the mode of a directory, Puppet always
+ sets the search/traverse (1) bit anywhere the read (4) bit is set.
+ This is almost always what you want: read allows you to list the
+ entries in a directory, and search/traverse allows you to access
+ (read/write/execute) those entries.) Because of this feature, you
+ can recursively make a directory and all of the files in it
+ world-readable by setting e.g.::
+
+ file { '/some/dir':
+ mode => 644,
+ recurse => true,
+ }
+
+ In this case all of the files underneath ``/some/dir`` will have
+ mode 644, and all of the directories will have mode 755."
+
+ @event = :file_changed
+
+ # Our modes are octal, so make sure they print correctly. Other
+ # valid values are symbols, basically
+ def is_to_s(currentvalue)
+ case currentvalue
+ when Integer
+ return "%o" % currentvalue
+ when Symbol
+ return currentvalue
+ else
+ raise Puppet::DevError, "Invalid current value for mode: #{currentvalue.inspect}"
+ end
+ end
- def should_to_s(newvalue = @should)
- case newvalue
- when Integer
- return "%o" % newvalue
- when Symbol
- return newvalue
- else
- raise Puppet::DevError, "Invalid 'should' value for mode: #{newvalue.inspect}"
- end
- end
+ def should_to_s(newvalue = @should)
+ case newvalue
+ when Integer
+ return "%o" % newvalue
+ when Symbol
+ return newvalue
+ else
+ raise Puppet::DevError, "Invalid 'should' value for mode: #{newvalue.inspect}"
+ end
+ end
- munge do |should|
- # this is pretty hackish, but i need to make sure the number is in
- # octal, yet the number can only be specified as a string right now
- value = should
- if value.is_a?(String)
- unless value =~ /^\d+$/
- raise Puppet::Error, "File modes can only be numbers, not #{value.inspect}"
- end
- # Make sure our number looks like octal.
- unless value =~ /^0/
- value = "0#{value}"
- end
- old = value
- begin
- value = Integer(value)
- rescue ArgumentError => detail
- raise Puppet::DevError, "Could not convert #{old.inspect} to integer"
- end
- end
-
- return value
+ munge do |should|
+ # this is pretty hackish, but i need to make sure the number is in
+ # octal, yet the number can only be specified as a string right now
+ value = should
+ if value.is_a?(String)
+ unless value =~ /^\d+$/
+ raise Puppet::Error, "File modes can only be numbers, not #{value.inspect}"
end
+ # Make sure our number looks like octal.
+ unless value =~ /^0/
+ value = "0#{value}"
+ end
+ old = value
+ begin
+ value = Integer(value)
+ rescue ArgumentError => detail
+ raise Puppet::DevError, "Could not convert #{old.inspect} to integer"
+ end
+ end
- # If we're a directory, we need to be executable for all cases
- # that are readable. This should probably be selectable, but eh.
- def dirmask(value)
- if FileTest.directory?(@resource[:path])
- value |= 0100 if value & 0400 != 0
- value |= 010 if value & 040 != 0
- value |= 01 if value & 04 != 0
- end
+ return value
+ end
- value
- end
+ # If we're a directory, we need to be executable for all cases
+ # that are readable. This should probably be selectable, but eh.
+ def dirmask(value)
+ if FileTest.directory?(@resource[:path])
+ value |= 0100 if value & 0400 != 0
+ value |= 010 if value & 040 != 0
+ value |= 01 if value & 04 != 0
+ end
- def insync?(currentvalue)
- if stat = @resource.stat and stat.ftype == "link" and @resource[:links] != :follow
- self.debug "Not managing symlink mode"
- return true
- else
- return super(currentvalue)
- end
- end
+ value
+ end
- def retrieve
- # If we're not following links and we're a link, then we just turn
- # off mode management entirely.
-
- if stat = @resource.stat(false)
- unless defined?(@fixed)
- @should &&= @should.collect { |s| self.dirmask(s) }
- end
- return stat.mode & 007777
- else
- return :absent
- end
- end
+ def insync?(currentvalue)
+ if stat = @resource.stat and stat.ftype == "link" and @resource[:links] != :follow
+ self.debug "Not managing symlink mode"
+ return true
+ else
+ return super(currentvalue)
+ end
+ end
- def sync
- mode = self.should
-
- begin
- File.chmod(mode, @resource[:path])
- rescue => detail
- error = Puppet::Error.new("failed to chmod #{@resource[:path]}: #{detail.message}")
- error.set_backtrace detail.backtrace
- raise error
- end
- :file_changed
+ def retrieve
+ # If we're not following links and we're a link, then we just turn
+ # off mode management entirely.
+
+ if stat = @resource.stat(false)
+ unless defined?(@fixed)
+ @should &&= @should.collect { |s| self.dirmask(s) }
end
+ return stat.mode & 007777
+ else
+ return :absent
+ end
+ end
+
+ def sync
+ mode = self.should
+
+ begin
+ File.chmod(mode, @resource[:path])
+ rescue => detail
+ error = Puppet::Error.new("failed to chmod #{@resource[:path]}: #{detail.message}")
+ error.set_backtrace detail.backtrace
+ raise error
+ end
+ :file_changed
end
+ end
end
diff --git a/lib/puppet/type/file/owner.rb b/lib/puppet/type/file/owner.rb
index 01c092382..d473da20e 100755
--- a/lib/puppet/type/file/owner.rb
+++ b/lib/puppet/type/file/owner.rb
@@ -1,52 +1,52 @@
module Puppet
- Puppet::Type.type(:file).newproperty(:owner) do
+ Puppet::Type.type(:file).newproperty(:owner) do
- desc "To whom the file should belong. Argument can be user name or
- user ID."
- @event = :file_changed
+ desc "To whom the file should belong. Argument can be user name or
+ user ID."
+ @event = :file_changed
- def insync?(current)
- provider.insync?(current, @should)
- end
+ def insync?(current)
+ provider.insync?(current, @should)
+ end
- # We want to print names, not numbers
- def is_to_s(currentvalue)
- provider.id2name(currentvalue) || currentvalue
- end
+ # We want to print names, not numbers
+ def is_to_s(currentvalue)
+ provider.id2name(currentvalue) || currentvalue
+ end
- def should_to_s(newvalue = @should)
- case newvalue
- when Symbol
- newvalue.to_s
- when Integer
- provider.id2name(newvalue) || newvalue
- when String
- newvalue
- else
- raise Puppet::DevError, "Invalid uid type #{newvalue.class}(#{newvalue})"
- end
- end
+ def should_to_s(newvalue = @should)
+ case newvalue
+ when Symbol
+ newvalue.to_s
+ when Integer
+ provider.id2name(newvalue) || newvalue
+ when String
+ newvalue
+ else
+ raise Puppet::DevError, "Invalid uid type #{newvalue.class}(#{newvalue})"
+ end
+ end
- def retrieve
- if self.should
- @should = @should.collect do |val|
- unless val.is_a?(Integer)
- if tmp = provider.validuser?(val)
- val = tmp
- else
- raise "Could not find user #{val}"
- end
- else
- val
- end
- end
+ def retrieve
+ if self.should
+ @should = @should.collect do |val|
+ unless val.is_a?(Integer)
+ if tmp = provider.validuser?(val)
+ val = tmp
+ else
+ raise "Could not find user #{val}"
end
- provider.retrieve(@resource)
+ else
+ val
+ end
end
+ end
+ provider.retrieve(@resource)
+ end
- def sync
- provider.sync(resource[:path], resource[:links], @should)
- end
+ def sync
+ provider.sync(resource[:path], resource[:links], @should)
end
+ end
end
diff --git a/lib/puppet/type/file/selcontext.rb b/lib/puppet/type/file/selcontext.rb
index 0a889fc3e..edcfb83b2 100644
--- a/lib/puppet/type/file/selcontext.rb
+++ b/lib/puppet/type/file/selcontext.rb
@@ -20,84 +20,84 @@
# See http://www.nsa.gov/selinux/ for complete docs on SELinux.
module Puppet
- require 'puppet/util/selinux'
-
- class SELFileContext < Puppet::Property
- include Puppet::Util::SELinux
-
- def retrieve
- return :absent unless @resource.stat(false)
- context = self.get_selinux_current_context(@resource[:path])
- parse_selinux_context(name, context)
- end
-
- def retrieve_default_context(property)
- unless context = self.get_selinux_default_context(@resource[:path])
- return nil
- end
- property_default = self.parse_selinux_context(property, context)
- self.debug "Found #{property} default '#{property_default}' for #{@resource[:path]}" if not property_default.nil?
- property_default
- end
-
- def insync?(value)
- if not selinux_support?
- debug("SELinux bindings not found. Ignoring parameter.")
- return true
- end
- super
- end
-
- def sync
- self.set_selinux_context(@resource[:path], @should, name)
- :file_changed
- end
- end
+ require 'puppet/util/selinux'
- Puppet::Type.type(:file).newproperty(:seluser, :parent => Puppet::SELFileContext) do
- desc "What the SELinux user component of the context of the file should be.
- Any valid SELinux user component is accepted. For example ``user_u``.
- If not specified it defaults to the value returned by matchpathcon for
- the file, if any exists. Only valid on systems with SELinux support
- enabled."
+ class SELFileContext < Puppet::Property
+ include Puppet::Util::SELinux
- @event = :file_changed
- defaultto { self.retrieve_default_context(:seluser) }
+ def retrieve
+ return :absent unless @resource.stat(false)
+ context = self.get_selinux_current_context(@resource[:path])
+ parse_selinux_context(name, context)
end
- Puppet::Type.type(:file).newproperty(:selrole, :parent => Puppet::SELFileContext) do
- desc "What the SELinux role component of the context of the file should be.
- Any valid SELinux role component is accepted. For example ``role_r``.
- If not specified it defaults to the value returned by matchpathcon for
- the file, if any exists. Only valid on systems with SELinux support
- enabled."
-
- @event = :file_changed
- defaultto { self.retrieve_default_context(:selrole) }
+ def retrieve_default_context(property)
+ unless context = self.get_selinux_default_context(@resource[:path])
+ return nil
+ end
+ property_default = self.parse_selinux_context(property, context)
+ self.debug "Found #{property} default '#{property_default}' for #{@resource[:path]}" if not property_default.nil?
+ property_default
end
- Puppet::Type.type(:file).newproperty(:seltype, :parent => Puppet::SELFileContext) do
- desc "What the SELinux type component of the context of the file should be.
- Any valid SELinux type component is accepted. For example ``tmp_t``.
- If not specified it defaults to the value returned by matchpathcon for
- the file, if any exists. Only valid on systems with SELinux support
- enabled."
-
- @event = :file_changed
- defaultto { self.retrieve_default_context(:seltype) }
+ def insync?(value)
+ if not selinux_support?
+ debug("SELinux bindings not found. Ignoring parameter.")
+ return true
+ end
+ super
end
- Puppet::Type.type(:file).newproperty(:selrange, :parent => Puppet::SELFileContext) do
- desc "What the SELinux range component of the context of the file should be.
- Any valid SELinux range component is accepted. For example ``s0`` or
- ``SystemHigh``. If not specified it defaults to the value returned by
- matchpathcon for the file, if any exists. Only valid on systems with
- SELinux support enabled and that have support for MCS (Multi-Category
- Security)."
-
- @event = :file_changed
- defaultto { self.retrieve_default_context(:selrange) }
+ def sync
+ self.set_selinux_context(@resource[:path], @should, name)
+ :file_changed
end
+ end
+
+ Puppet::Type.type(:file).newproperty(:seluser, :parent => Puppet::SELFileContext) do
+ desc "What the SELinux user component of the context of the file should be.
+ Any valid SELinux user component is accepted. For example ``user_u``.
+ If not specified it defaults to the value returned by matchpathcon for
+ the file, if any exists. Only valid on systems with SELinux support
+ enabled."
+
+ @event = :file_changed
+ defaultto { self.retrieve_default_context(:seluser) }
+ end
+
+ Puppet::Type.type(:file).newproperty(:selrole, :parent => Puppet::SELFileContext) do
+ desc "What the SELinux role component of the context of the file should be.
+ Any valid SELinux role component is accepted. For example ``role_r``.
+ If not specified it defaults to the value returned by matchpathcon for
+ the file, if any exists. Only valid on systems with SELinux support
+ enabled."
+
+ @event = :file_changed
+ defaultto { self.retrieve_default_context(:selrole) }
+ end
+
+ Puppet::Type.type(:file).newproperty(:seltype, :parent => Puppet::SELFileContext) do
+ desc "What the SELinux type component of the context of the file should be.
+ Any valid SELinux type component is accepted. For example ``tmp_t``.
+ If not specified it defaults to the value returned by matchpathcon for
+ the file, if any exists. Only valid on systems with SELinux support
+ enabled."
+
+ @event = :file_changed
+ defaultto { self.retrieve_default_context(:seltype) }
+ end
+
+ Puppet::Type.type(:file).newproperty(:selrange, :parent => Puppet::SELFileContext) do
+ desc "What the SELinux range component of the context of the file should be.
+ Any valid SELinux range component is accepted. For example ``s0`` or
+ ``SystemHigh``. If not specified it defaults to the value returned by
+ matchpathcon for the file, if any exists. Only valid on systems with
+ SELinux support enabled and that have support for MCS (Multi-Category
+ Security)."
+
+ @event = :file_changed
+ defaultto { self.retrieve_default_context(:selrange) }
+ end
end
diff --git a/lib/puppet/type/file/source.rb b/lib/puppet/type/file/source.rb
index 0053693f4..05da79b3d 100755
--- a/lib/puppet/type/file/source.rb
+++ b/lib/puppet/type/file/source.rb
@@ -3,187 +3,187 @@ require 'puppet/file_serving/content'
require 'puppet/file_serving/metadata'
module Puppet
- # Copy files from a local or remote source. This state *only* does any work
- # when the remote file is an actual file; in that case, this state copies
- # the file down. If the remote file is a dir or a link or whatever, then
- # this state, during retrieval, modifies the appropriate other states
- # so that things get taken care of appropriately.
- Puppet::Type.type(:file).newparam(:source) do
- include Puppet::Util::Diff
-
- attr_accessor :source, :local
- desc "Copy a file over the current file. Uses ``checksum`` to
- determine when a file should be copied. Valid values are either
- fully qualified paths to files, or URIs. Currently supported URI
- types are *puppet* and *file*.
-
- This is one of the primary mechanisms for getting content into
- applications that Puppet does not directly support and is very
- useful for those configuration files that don't change much across
- sytems. For instance::
-
- class sendmail {
- file { \"/etc/mail/sendmail.cf\":
- source => \"puppet://server/modules/module_name/sendmail.cf\"
- }
- }
-
- You can also leave out the server name, in which case ``puppet agent``
- will fill in the name of its configuration server and ``puppet apply``
- will use the local filesystem. This makes it easy to use the same
- configuration in both local and centralized forms.
-
- Currently, only the ``puppet`` scheme is supported for source
- URL's. Puppet will connect to the file server running on
- ``server`` to retrieve the contents of the file. If the
- ``server`` part is empty, the behavior of the command-line
- interpreter (``puppet apply``) and the client demon (``puppet agent``) differs
- slightly: ``apply`` will look such a file up on the module path
- on the local host, whereas ``agent`` will connect to the
- puppet server that it received the manifest from.
-
- See the `FileServingConfiguration fileserver configuration documentation`:trac: for information on how to configure
- and use file services within Puppet.
-
- If you specify multiple file sources for a file, then the first
- source that exists will be used. This allows you to specify
- what amount to search paths for files::
-
- file { \"/path/to/my/file\":
- source => [
- \"/modules/nfs/files/file.$host\",
- \"/modules/nfs/files/file.$operatingsystem\",
- \"/modules/nfs/files/file\"
- ]
- }
-
- This will use the first found file as the source.
-
- You cannot currently copy links using this mechanism; set ``links``
- to ``follow`` if any remote sources are links.
- "
-
- validate do |sources|
- sources = [sources] unless sources.is_a?(Array)
- sources.each do |source|
- begin
- uri = URI.parse(URI.escape(source))
- rescue => detail
- self.fail "Could not understand source #{source}: #{detail}"
- end
-
- self.fail "Cannot use URLs of type '#{uri.scheme}' as source for fileserving" unless uri.scheme.nil? or %w{file puppet}.include?(uri.scheme)
- end
+ # Copy files from a local or remote source. This state *only* does any work
+ # when the remote file is an actual file; in that case, this state copies
+ # the file down. If the remote file is a dir or a link or whatever, then
+ # this state, during retrieval, modifies the appropriate other states
+ # so that things get taken care of appropriately.
+ Puppet::Type.type(:file).newparam(:source) do
+ include Puppet::Util::Diff
+
+ attr_accessor :source, :local
+ desc "Copy a file over the current file. Uses ``checksum`` to
+ determine when a file should be copied. Valid values are either
+ fully qualified paths to files, or URIs. Currently supported URI
+ types are *puppet* and *file*.
+
+ This is one of the primary mechanisms for getting content into
+ applications that Puppet does not directly support and is very
+ useful for those configuration files that don't change much across
+ sytems. For instance::
+
+ class sendmail {
+ file { \"/etc/mail/sendmail.cf\":
+ source => \"puppet://server/modules/module_name/sendmail.cf\"
+ }
+ }
+
+ You can also leave out the server name, in which case ``puppet agent``
+ will fill in the name of its configuration server and ``puppet apply``
+ will use the local filesystem. This makes it easy to use the same
+ configuration in both local and centralized forms.
+
+ Currently, only the ``puppet`` scheme is supported for source
+ URL's. Puppet will connect to the file server running on
+ ``server`` to retrieve the contents of the file. If the
+ ``server`` part is empty, the behavior of the command-line
+ interpreter (``puppet apply``) and the client demon (``puppet agent``) differs
+ slightly: ``apply`` will look such a file up on the module path
+ on the local host, whereas ``agent`` will connect to the
+ puppet server that it received the manifest from.
+
+ See the `FileServingConfiguration fileserver configuration documentation`:trac: for information on how to configure
+ and use file services within Puppet.
+
+ If you specify multiple file sources for a file, then the first
+ source that exists will be used. This allows you to specify
+ what amount to search paths for files::
+
+ file { \"/path/to/my/file\":
+ source => [
+ \"/modules/nfs/files/file.$host\",
+ \"/modules/nfs/files/file.$operatingsystem\",
+ \"/modules/nfs/files/file\"
+ ]
+ }
+
+ This will use the first found file as the source.
+
+ You cannot currently copy links using this mechanism; set ``links``
+ to ``follow`` if any remote sources are links.
+ "
+
+ validate do |sources|
+ sources = [sources] unless sources.is_a?(Array)
+ sources.each do |source|
+ begin
+ uri = URI.parse(URI.escape(source))
+ rescue => detail
+ self.fail "Could not understand source #{source}: #{detail}"
end
- munge do |sources|
- sources = [sources] unless sources.is_a?(Array)
- sources.collect { |source| source.sub(/\/$/, '') }
- end
+ self.fail "Cannot use URLs of type '#{uri.scheme}' as source for fileserving" unless uri.scheme.nil? or %w{file puppet}.include?(uri.scheme)
+ end
+ end
- def change_to_s(currentvalue, newvalue)
- # newvalue = "{md5}#{@metadata.checksum}"
- if @resource.property(:ensure).retrieve == :absent
- return "creating from source #{metadata.source} with contents #{metadata.checksum}"
- else
- return "replacing from source #{metadata.source} with contents #{metadata.checksum}"
- end
- end
+ munge do |sources|
+ sources = [sources] unless sources.is_a?(Array)
+ sources.collect { |source| source.sub(/\/$/, '') }
+ end
- def checksum
- metadata && metadata.checksum
- end
+ def change_to_s(currentvalue, newvalue)
+ # newvalue = "{md5}#{@metadata.checksum}"
+ if @resource.property(:ensure).retrieve == :absent
+ return "creating from source #{metadata.source} with contents #{metadata.checksum}"
+ else
+ return "replacing from source #{metadata.source} with contents #{metadata.checksum}"
+ end
+ end
- # Copy the values from the source to the resource. Yay.
- def copy_source_values
- devfail "Somehow got asked to copy source values without any metadata" unless metadata
-
- # Take each of the stats and set them as states on the local file
- # if a value has not already been provided.
- [:owner, :mode, :group, :checksum].each do |metadata_method|
- param_name = (metadata_method == :checksum) ? :content : metadata_method
- next if metadata_method == :owner and !Puppet.features.root?
- next if metadata_method == :checksum and metadata.ftype == "directory"
-
- if resource[param_name].nil? or resource[param_name] == :absent
- v = metadata.send(metadata_method)
- resource.info "Setting #{param_name} to #{v}"
- resource[param_name] = metadata.send(metadata_method)
- end
- end
-
- if resource[:ensure] == :absent
- # We know all we need to
- elsif metadata.ftype != "link"
- resource[:ensure] = metadata.ftype
- elsif @resource[:links] == :follow
- resource[:ensure] = :present
- else
- resource[:ensure] = "link"
- resource[:target] = metadata.destination
- end
- end
+ def checksum
+ metadata && metadata.checksum
+ end
- def pinparams
- [:mode, :type, :owner, :group, :content]
+ # Copy the values from the source to the resource. Yay.
+ def copy_source_values
+ devfail "Somehow got asked to copy source values without any metadata" unless metadata
+
+ # Take each of the stats and set them as states on the local file
+ # if a value has not already been provided.
+ [:owner, :mode, :group, :checksum].each do |metadata_method|
+ param_name = (metadata_method == :checksum) ? :content : metadata_method
+ next if metadata_method == :owner and !Puppet.features.root?
+ next if metadata_method == :checksum and metadata.ftype == "directory"
+
+ if resource[param_name].nil? or resource[param_name] == :absent
+ v = metadata.send(metadata_method)
+ resource.info "Setting #{param_name} to #{v}"
+ resource[param_name] = metadata.send(metadata_method)
end
+ end
+
+ if resource[:ensure] == :absent
+ # We know all we need to
+ elsif metadata.ftype != "link"
+ resource[:ensure] = metadata.ftype
+ elsif @resource[:links] == :follow
+ resource[:ensure] = :present
+ else
+ resource[:ensure] = "link"
+ resource[:target] = metadata.destination
+ end
+ end
- def found?
- ! (metadata.nil? or metadata.ftype.nil?)
- end
+ def pinparams
+ [:mode, :type, :owner, :group, :content]
+ end
+
+ def found?
+ ! (metadata.nil? or metadata.ftype.nil?)
+ end
- # Provide, and retrieve if necessary, the metadata for this file. Fail
- # if we can't find data about this host, and fail if there are any
- # problems in our query.
- cached_attr(:metadata) do
- return nil unless value
- result = nil
- value.each do |source|
- begin
- if data = Puppet::FileServing::Metadata.find(source)
- result = data
- result.source = source
- break
- end
- rescue => detail
- fail detail, "Could not retrieve file metadata for #{source}: #{detail}"
- end
- end
- fail "Could not retrieve information from source(s) #{value.join(", ")}" unless result
- result
+ # Provide, and retrieve if necessary, the metadata for this file. Fail
+ # if we can't find data about this host, and fail if there are any
+ # problems in our query.
+ cached_attr(:metadata) do
+ return nil unless value
+ result = nil
+ value.each do |source|
+ begin
+ if data = Puppet::FileServing::Metadata.find(source)
+ result = data
+ result.source = source
+ break
+ end
+ rescue => detail
+ fail detail, "Could not retrieve file metadata for #{source}: #{detail}"
end
+ end
+ fail "Could not retrieve information from source(s) #{value.join(", ")}" unless result
+ result
+ end
- # Make sure we're also checking the checksum
- def value=(value)
- super
+ # Make sure we're also checking the checksum
+ def value=(value)
+ super
- checks = (pinparams + [:ensure])
- checks.delete(:checksum)
+ checks = (pinparams + [:ensure])
+ checks.delete(:checksum)
- resource[:audit] = checks
- resource[:checksum] = :md5 unless resource.property(:checksum)
- end
+ resource[:audit] = checks
+ resource[:checksum] = :md5 unless resource.property(:checksum)
+ end
- def local?
- found? and uri and (uri.scheme || "file") == "file"
- end
+ def local?
+ found? and uri and (uri.scheme || "file") == "file"
+ end
- def full_path
- URI.unescape(uri.path) if found? and uri
- end
+ def full_path
+ URI.unescape(uri.path) if found? and uri
+ end
- def server
- (uri and uri.host) or Puppet.settings[:server]
- end
+ def server
+ (uri and uri.host) or Puppet.settings[:server]
+ end
- def port
- (uri and uri.port) or Puppet.settings[:masterport]
- end
+ def port
+ (uri and uri.port) or Puppet.settings[:masterport]
+ end
- private
+ private
- def uri
- @uri ||= URI.parse(URI.escape(metadata.source))
- end
+ def uri
+ @uri ||= URI.parse(URI.escape(metadata.source))
end
+ end
end
diff --git a/lib/puppet/type/file/target.rb b/lib/puppet/type/file/target.rb
index 59f1e5972..9e7229dda 100644
--- a/lib/puppet/type/file/target.rb
+++ b/lib/puppet/type/file/target.rb
@@ -1,74 +1,74 @@
module Puppet
- Puppet::Type.type(:file).newproperty(:target) do
- desc "The target for creating a link. Currently, symlinks are the
- only type supported."
+ Puppet::Type.type(:file).newproperty(:target) do
+ desc "The target for creating a link. Currently, symlinks are the
+ only type supported."
- newvalue(:notlink) do
- # We do nothing if the value is absent
- return :nochange
- end
-
- # Anything else, basically
- newvalue(/./) do
- @resource[:ensure] = :link if ! @resource.should(:ensure)
-
- # Only call mklink if ensure didn't call us in the first place.
- currentensure = @resource.property(:ensure).retrieve
- mklink if @resource.property(:ensure).insync?(currentensure)
- end
+ newvalue(:notlink) do
+ # We do nothing if the value is absent
+ return :nochange
+ end
- # Create our link.
- def mklink
- raise Puppet::Error, "Cannot symlink on Microsoft Windows" if Puppet.features.microsoft_windows?
+ # Anything else, basically
+ newvalue(/./) do
+ @resource[:ensure] = :link if ! @resource.should(:ensure)
- target = self.should
+ # Only call mklink if ensure didn't call us in the first place.
+ currentensure = @resource.property(:ensure).retrieve
+ mklink if @resource.property(:ensure).insync?(currentensure)
+ end
- # Clean up any existing objects. The argument is just for logging,
- # it doesn't determine what's removed.
- @resource.remove_existing(target)
+ # Create our link.
+ def mklink
+ raise Puppet::Error, "Cannot symlink on Microsoft Windows" if Puppet.features.microsoft_windows?
- raise Puppet::Error, "Could not remove existing file" if FileTest.exists?(@resource[:path])
+ target = self.should
- Dir.chdir(File.dirname(@resource[:path])) do
- Puppet::Util::SUIDManager.asuser(@resource.asuser) do
- mode = @resource.should(:mode)
- if mode
- Puppet::Util.withumask(000) do
- File.symlink(target, @resource[:path])
- end
- else
- File.symlink(target, @resource[:path])
- end
- end
+ # Clean up any existing objects. The argument is just for logging,
+ # it doesn't determine what's removed.
+ @resource.remove_existing(target)
- @resource.send(:property_fix)
+ raise Puppet::Error, "Could not remove existing file" if FileTest.exists?(@resource[:path])
- :link_created
+ Dir.chdir(File.dirname(@resource[:path])) do
+ Puppet::Util::SUIDManager.asuser(@resource.asuser) do
+ mode = @resource.should(:mode)
+ if mode
+ Puppet::Util.withumask(000) do
+ File.symlink(target, @resource[:path])
end
+ else
+ File.symlink(target, @resource[:path])
+ end
end
- def insync?(currentvalue)
- if [:nochange, :notlink].include?(self.should) or @resource.recurse?
- return true
- elsif ! @resource.replace? and File.exists?(@resource[:path])
- return true
- else
- return super(currentvalue)
- end
- end
+ @resource.send(:property_fix)
+ :link_created
+ end
+ end
- def retrieve
- if stat = @resource.stat
- if stat.ftype == "link"
- return File.readlink(@resource[:path])
- else
- return :notlink
- end
- else
- return :absent
- end
+ def insync?(currentvalue)
+ if [:nochange, :notlink].include?(self.should) or @resource.recurse?
+ return true
+ elsif ! @resource.replace? and File.exists?(@resource[:path])
+ return true
+ else
+ return super(currentvalue)
+ end
+ end
+
+
+ def retrieve
+ if stat = @resource.stat
+ if stat.ftype == "link"
+ return File.readlink(@resource[:path])
+ else
+ return :notlink
end
+ else
+ return :absent
+ end
end
+ end
end
diff --git a/lib/puppet/type/file/type.rb b/lib/puppet/type/file/type.rb
index 95470bb28..eb50b81f9 100755
--- a/lib/puppet/type/file/type.rb
+++ b/lib/puppet/type/file/type.rb
@@ -1,26 +1,26 @@
module Puppet
- Puppet::Type.type(:file).newproperty(:type) do
- require 'etc'
- desc "A read-only state to check the file type."
+ Puppet::Type.type(:file).newproperty(:type) do
+ require 'etc'
+ desc "A read-only state to check the file type."
- #munge do |value|
- # raise Puppet::Error, ":type is read-only"
- #end
+ #munge do |value|
+ # raise Puppet::Error, ":type is read-only"
+ #end
- def retrieve
- currentvalue = :absent
- if stat = @resource.stat(false)
- currentvalue = stat.ftype
- end
- # so this state is never marked out of sync
- @should = [currentvalue]
- currentvalue
- end
+ def retrieve
+ currentvalue = :absent
+ if stat = @resource.stat(false)
+ currentvalue = stat.ftype
+ end
+ # so this state is never marked out of sync
+ @should = [currentvalue]
+ currentvalue
+ end
- def sync
- raise Puppet::Error, ":type is read-only"
- end
+ def sync
+ raise Puppet::Error, ":type is read-only"
end
+ end
end
diff --git a/lib/puppet/type/filebucket.rb b/lib/puppet/type/filebucket.rb
index 37ebd2d61..65ff88411 100755
--- a/lib/puppet/type/filebucket.rb
+++ b/lib/puppet/type/filebucket.rb
@@ -1,95 +1,95 @@
module Puppet
- require 'puppet/file_bucket/dipper'
-
- newtype(:filebucket) do
- @doc = "A repository for backing up files. If no filebucket is
- defined, then files will be backed up in their current directory,
- but the filebucket can be either a host- or site-global repository
- for backing up. It stores files and returns the MD5 sum, which
- can later be used to retrieve the file if restoration becomes
- necessary. A filebucket does not do any work itself; instead,
- it can be specified as the value of *backup* in a **file** object.
-
- Currently, filebuckets are only useful for manual retrieval of
- accidentally removed files (e.g., you look in the log for the md5 sum and retrieve the file with that sum from the filebucket), but
- when transactions are fully supported filebuckets will be used to
- undo transactions.
-
- You will normally want to define a single filebucket for your
- whole network and then use that as the default backup location::
-
- # Define the bucket
- filebucket { main: server => puppet }
-
- # Specify it as the default target
- File { backup => main }
-
- Puppetmaster servers create a filebucket by default, so this will
- work in a default configuration."
-
- newparam(:name) do
- desc "The name of the filebucket."
- isnamevar
- end
-
- newparam(:server) do
- desc "The server providing the remote filebucket. If this is not
- specified then *path* is checked. If it is set, then the
- bucket is local. Otherwise the puppetmaster server specified
- in the config or at the commandline is used."
- defaultto { Puppet[:server] }
- end
-
- newparam(:port) do
- desc "The port on which the remote server is listening.
- Defaults to the normal Puppet port, %s." % Puppet[:masterport]
-
- defaultto { Puppet[:masterport] }
- end
-
- newparam(:path) do
- desc "The path to the local filebucket. If this is
- unset, then the bucket is remote. The parameter *server* must
- can be specified to set the remote server."
-
- defaultto { Puppet[:clientbucketdir] }
- end
-
- # Create a default filebucket.
- def self.mkdefaultbucket
- new(:name => "puppet", :path => Puppet[:clientbucketdir])
- end
-
- def bucket
- mkbucket unless defined?(@bucket)
- @bucket
- end
-
- private
-
- def mkbucket
- # Default is a local filebucket, if no server is given.
- # If the default path has been removed, too, then
- # the puppetmaster is used as default server
-
- type = "local"
- args = {}
- if self[:path]
- args[:Path] = self[:path]
- else
- args[:Server] = self[:server]
- args[:Port] = self[:port]
- end
-
- begin
- @bucket = Puppet::FileBucket::Dipper.new(args)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- self.fail("Could not create #{type} filebucket: #{detail}")
- end
-
- @bucket.name = self.name
- end
+ require 'puppet/file_bucket/dipper'
+
+ newtype(:filebucket) do
+ @doc = "A repository for backing up files. If no filebucket is
+ defined, then files will be backed up in their current directory,
+ but the filebucket can be either a host- or site-global repository
+ for backing up. It stores files and returns the MD5 sum, which
+ can later be used to retrieve the file if restoration becomes
+ necessary. A filebucket does not do any work itself; instead,
+ it can be specified as the value of *backup* in a **file** object.
+
+ Currently, filebuckets are only useful for manual retrieval of
+ accidentally removed files (e.g., you look in the log for the md5 sum and retrieve the file with that sum from the filebucket), but
+ when transactions are fully supported filebuckets will be used to
+ undo transactions.
+
+ You will normally want to define a single filebucket for your
+ whole network and then use that as the default backup location::
+
+ # Define the bucket
+ filebucket { main: server => puppet }
+
+ # Specify it as the default target
+ File { backup => main }
+
+ Puppetmaster servers create a filebucket by default, so this will
+ work in a default configuration."
+
+ newparam(:name) do
+ desc "The name of the filebucket."
+ isnamevar
+ end
+
+ newparam(:server) do
+ desc "The server providing the remote filebucket. If this is not
+ specified then *path* is checked. If it is set, then the
+ bucket is local. Otherwise the puppetmaster server specified
+ in the config or at the commandline is used."
+ defaultto { Puppet[:server] }
+ end
+
+ newparam(:port) do
+ desc "The port on which the remote server is listening.
+ Defaults to the normal Puppet port, %s." % Puppet[:masterport]
+
+ defaultto { Puppet[:masterport] }
+ end
+
+ newparam(:path) do
+ desc "The path to the local filebucket. If this is
+ unset, then the bucket is remote. The parameter *server* must
+ can be specified to set the remote server."
+
+ defaultto { Puppet[:clientbucketdir] }
+ end
+
+ # Create a default filebucket.
+ def self.mkdefaultbucket
+ new(:name => "puppet", :path => Puppet[:clientbucketdir])
+ end
+
+ def bucket
+ mkbucket unless defined?(@bucket)
+ @bucket
+ end
+
+ private
+
+ def mkbucket
+ # Default is a local filebucket, if no server is given.
+ # If the default path has been removed, too, then
+ # the puppetmaster is used as default server
+
+ type = "local"
+ args = {}
+ if self[:path]
+ args[:Path] = self[:path]
+ else
+ args[:Server] = self[:server]
+ args[:Port] = self[:port]
+ end
+
+ begin
+ @bucket = Puppet::FileBucket::Dipper.new(args)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ self.fail("Could not create #{type} filebucket: #{detail}")
+ end
+
+ @bucket.name = self.name
end
+ end
end
diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb
index 7cf031a73..9f26d2243 100755
--- a/lib/puppet/type/group.rb
+++ b/lib/puppet/type/group.rb
@@ -3,98 +3,98 @@ require 'etc'
require 'facter'
module Puppet
- newtype(:group) do
- @doc = "Manage groups. On most platforms this can only create groups.
- Group membership must be managed on individual users.
+ newtype(:group) do
+ @doc = "Manage groups. On most platforms this can only create groups.
+ Group membership must be managed on individual users.
- On some platforms such as OS X, group membership is managed as an
- attribute of the group, not the user record. Providers must have
- the feature 'manages_members' to manage the 'members' property of
- a group record."
+ On some platforms such as OS X, group membership is managed as an
+ attribute of the group, not the user record. Providers must have
+ the feature 'manages_members' to manage the 'members' property of
+ a group record."
- feature :manages_members,
- "For directories where membership is an attribute of groups not users."
+ feature :manages_members,
+ "For directories where membership is an attribute of groups not users."
- ensurable do
- desc "Create or remove the group."
+ ensurable do
+ desc "Create or remove the group."
- newvalue(:present) do
- provider.create
- end
+ newvalue(:present) do
+ provider.create
+ end
- newvalue(:absent) do
- provider.delete
- end
- end
+ newvalue(:absent) do
+ provider.delete
+ end
+ end
- newproperty(:gid) do
- desc "The group ID. Must be specified numerically. If not
- specified, a number will be picked, which can result in ID
- differences across systems and thus is not recommended. The
- GID is picked according to local system standards."
-
- def retrieve
- provider.gid
- end
-
- def sync
- if self.should == :absent
- raise Puppet::DevError, "GID cannot be deleted"
- else
- provider.gid = self.should
- end
- end
-
- munge do |gid|
- case gid
- when String
- if gid =~ /^[-0-9]+$/
- gid = Integer(gid)
- else
- self.fail "Invalid GID #{gid}"
- end
- when Symbol
- unless gid == :absent
- self.devfail "Invalid GID #{gid}"
- end
- end
-
- return gid
- end
+ newproperty(:gid) do
+ desc "The group ID. Must be specified numerically. If not
+ specified, a number will be picked, which can result in ID
+ differences across systems and thus is not recommended. The
+ GID is picked according to local system standards."
+
+ def retrieve
+ provider.gid
+ end
+
+ def sync
+ if self.should == :absent
+ raise Puppet::DevError, "GID cannot be deleted"
+ else
+ provider.gid = self.should
+ end
+ end
+
+ munge do |gid|
+ case gid
+ when String
+ if gid =~ /^[-0-9]+$/
+ gid = Integer(gid)
+ else
+ self.fail "Invalid GID #{gid}"
+ end
+ when Symbol
+ unless gid == :absent
+ self.devfail "Invalid GID #{gid}"
+ end
end
- newproperty(:members, :array_matching => :all, :required_features => :manages_members) do
- desc "The members of the group. For directory services where group
- membership is stored in the group objects, not the users."
+ return gid
+ end
+ end
- def change_to_s(currentvalue, newvalue)
- currentvalue = currentvalue.join(",") if currentvalue != :absent
- newvalue = newvalue.join(",")
- super(currentvalue, newvalue)
- end
- end
+ newproperty(:members, :array_matching => :all, :required_features => :manages_members) do
+ desc "The members of the group. For directory services where group
+ membership is stored in the group objects, not the users."
- newparam(:auth_membership) do
- desc "whether the provider is authoritative for group membership."
- defaultto true
- end
+ def change_to_s(currentvalue, newvalue)
+ currentvalue = currentvalue.join(",") if currentvalue != :absent
+ newvalue = newvalue.join(",")
+ super(currentvalue, newvalue)
+ end
+ end
- newparam(:name) do
- desc "The group name. While naming limitations vary by
- system, it is advisable to keep the name to the degenerate
- limitations, which is a maximum of 8 characters beginning with
- a letter."
- isnamevar
- end
+ newparam(:auth_membership) do
+ desc "whether the provider is authoritative for group membership."
+ defaultto true
+ end
- newparam(:allowdupe, :boolean => true) do
- desc "Whether to allow duplicate GIDs. This option does not work on
- FreeBSD (contract to the ``pw`` man page)."
+ newparam(:name) do
+ desc "The group name. While naming limitations vary by
+ system, it is advisable to keep the name to the degenerate
+ limitations, which is a maximum of 8 characters beginning with
+ a letter."
+ isnamevar
+ end
- newvalues(:true, :false)
+ newparam(:allowdupe, :boolean => true) do
+ desc "Whether to allow duplicate GIDs. This option does not work on
+ FreeBSD (contract to the ``pw`` man page)."
- defaultto false
- end
+ newvalues(:true, :false)
+
+ defaultto false
end
+ end
end
diff --git a/lib/puppet/type/host.rb b/lib/puppet/type/host.rb
index bd7d4bde8..929542d7c 100755
--- a/lib/puppet/type/host.rb
+++ b/lib/puppet/type/host.rb
@@ -1,101 +1,101 @@
module Puppet
- newtype(:host) do
- ensurable
+ newtype(:host) do
+ ensurable
- newproperty(:ip) do
- desc "The host's IP address, IPv4 or IPv6."
+ newproperty(:ip) do
+ desc "The host's IP address, IPv4 or IPv6."
- validate do |value|
- unless value =~ /((([0-9a-fA-F]+:){7}[0-9a-fA-F]+)|(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?::(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?)|((25[0-5]|2[0-4][\d]|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})/
- raise Puppet::Error, "Invalid IP address"
- end
- end
+ validate do |value|
+ unless value =~ /((([0-9a-fA-F]+:){7}[0-9a-fA-F]+)|(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?::(([0-9a-fA-F]+:)*[0-9a-fA-F]+)?)|((25[0-5]|2[0-4][\d]|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3})/
+ raise Puppet::Error, "Invalid IP address"
+ end
+ end
- end
+ end
- newproperty(:host_aliases) do
- desc 'Any aliases the host might have. Multiple values must be
- specified as an array. Note that this property is not the same as
- the "alias" metaparam; use this property to add aliases to a host
- on disk, and "alias" to aliases for use in your Puppet scripts.'
-
- def insync?(is)
- is == @should
- end
-
- def is_to_s(currentvalue = @is)
- currentvalue = [currentvalue] unless currentvalue.is_a? Array
- currentvalue.join(" ")
- end
-
- def retrieve
- is = super
- case is
- when String
- is = is.split(/\s*,\s*/)
- when Symbol
- is = [is]
- when Array
- # nothing
- else
- raise Puppet::DevError, "Invalid @is type #{is.class}"
- end
- is
- end
-
- # We actually want to return the whole array here, not just the first
- # value.
- def should
- if defined?(@should)
- if @should == [:absent]
- return :absent
- else
- return @should
- end
- else
- return nil
- end
- end
-
- def should_to_s(newvalue = @should)
- newvalue.join(" ")
- end
-
- validate do |value|
- raise Puppet::Error, "Host aliases cannot include whitespace" if value =~ /\s/
- end
+ newproperty(:host_aliases) do
+ desc 'Any aliases the host might have. Multiple values must be
+ specified as an array. Note that this property is not the same as
+ the "alias" metaparam; use this property to add aliases to a host
+ on disk, and "alias" to aliases for use in your Puppet scripts.'
+
+ def insync?(is)
+ is == @should
+ end
+
+ def is_to_s(currentvalue = @is)
+ currentvalue = [currentvalue] unless currentvalue.is_a? Array
+ currentvalue.join(" ")
+ end
+
+ def retrieve
+ is = super
+ case is
+ when String
+ is = is.split(/\s*,\s*/)
+ when Symbol
+ is = [is]
+ when Array
+ # nothing
+ else
+ raise Puppet::DevError, "Invalid @is type #{is.class}"
+ end
+ is
+ end
+
+ # We actually want to return the whole array here, not just the first
+ # value.
+ def should
+ if defined?(@should)
+ if @should == [:absent]
+ return :absent
+ else
+ return @should
+ end
+ else
+ return nil
end
+ end
- newproperty(:target) do
- desc "The file in which to store service information. Only used by
- those providers that write to disk."
+ def should_to_s(newvalue = @should)
+ newvalue.join(" ")
+ end
- defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
- @resource.class.defaultprovider.default_target
- else
- nil
- end
- }
+ validate do |value|
+ raise Puppet::Error, "Host aliases cannot include whitespace" if value =~ /\s/
+ end
+ end
+
+ newproperty(:target) do
+ desc "The file in which to store service information. Only used by
+ those providers that write to disk."
+
+ defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
+ @resource.class.defaultprovider.default_target
+ else
+ nil
end
+ }
+ end
- newparam(:name) do
- desc "The host name."
+ newparam(:name) do
+ desc "The host name."
- isnamevar
+ isnamevar
- validate do |value|
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = value.split('.').each do |hostpart|
- unless hostpart =~ /^([\d\w]+|[\d\w][\d\w\-]+[\d\w])$/
- raise Puppet::Error, "Invalid host name"
- end
- end
- end
+ validate do |value|
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = value.split('.').each do |hostpart|
+ unless hostpart =~ /^([\d\w]+|[\d\w][\d\w\-]+[\d\w])$/
+ raise Puppet::Error, "Invalid host name"
+ end
end
-
- @doc = "Installs and manages host entries. For most systems, these
- entries will just be in ``/etc/hosts``, but some systems (notably OS X)
- will have different solutions."
+ end
end
+
+ @doc = "Installs and manages host entries. For most systems, these
+ entries will just be in ``/etc/hosts``, but some systems (notably OS X)
+ will have different solutions."
+ end
end
diff --git a/lib/puppet/type/k5login.rb b/lib/puppet/type/k5login.rb
index e192ce479..850e37733 100644
--- a/lib/puppet/type/k5login.rb
+++ b/lib/puppet/type/k5login.rb
@@ -3,85 +3,85 @@
# Plug-in type for handling k5login files
Puppet::Type.newtype(:k5login) do
- @doc = "Manage the .k5login file for a user. Specify the full path to
- the .k5login file as the name and an array of principals as the
- property principals."
+ @doc = "Manage the .k5login file for a user. Specify the full path to
+ the .k5login file as the name and an array of principals as the
+ property principals."
- ensurable
+ ensurable
- # Principals that should exist in the file
- newproperty(:principals, :array_matching => :all) do
- desc "The principals present in the .k5login file."
- end
+ # Principals that should exist in the file
+ newproperty(:principals, :array_matching => :all) do
+ desc "The principals present in the .k5login file."
+ end
- # The path/name of the k5login file
- newparam(:path) do
- isnamevar
- desc "The path to the file to manage. Must be fully qualified."
+ # The path/name of the k5login file
+ newparam(:path) do
+ isnamevar
+ desc "The path to the file to manage. Must be fully qualified."
- validate do |value|
- unless value =~ /^#{File::SEPARATOR}/
- raise Puppet::Error, "File paths must be fully qualified"
- end
- end
+ validate do |value|
+ unless value =~ /^#{File::SEPARATOR}/
+ raise Puppet::Error, "File paths must be fully qualified"
+ end
end
+ end
- # To manage the mode of the file
- newproperty(:mode) do
- desc "Manage the k5login file's mode"
- defaultto { "644" }
- end
+ # To manage the mode of the file
+ newproperty(:mode) do
+ desc "Manage the k5login file's mode"
+ defaultto { "644" }
+ end
- provide(:k5login) do
- desc "The k5login provider is the only provider for the k5login
- type."
+ provide(:k5login) do
+ desc "The k5login provider is the only provider for the k5login
+ type."
- # Does this file exist?
- def exists?
- File.exists?(@resource[:name])
- end
+ # Does this file exist?
+ def exists?
+ File.exists?(@resource[:name])
+ end
- # create the file
- def create
- write(@resource.should(:principals))
- should_mode = @resource.should(:mode)
- unless self.mode == should_mode
- self.mode = should_mode
- end
- end
+ # create the file
+ def create
+ write(@resource.should(:principals))
+ should_mode = @resource.should(:mode)
+ unless self.mode == should_mode
+ self.mode = should_mode
+ end
+ end
- # remove the file
- def destroy
- File.unlink(@resource[:name])
- end
+ # remove the file
+ def destroy
+ File.unlink(@resource[:name])
+ end
- # Return the principals
- def principals(dummy_argument=:work_arround_for_ruby_GC_bug)
- if File.exists?(@resource[:name])
- File.readlines(@resource[:name]).collect { |line| line.chomp }
- else
- :absent
- end
- end
+ # Return the principals
+ def principals(dummy_argument=:work_arround_for_ruby_GC_bug)
+ if File.exists?(@resource[:name])
+ File.readlines(@resource[:name]).collect { |line| line.chomp }
+ else
+ :absent
+ end
+ end
- # Write the principals out to the k5login file
- def principals=(value)
- write(value)
- end
+ # Write the principals out to the k5login file
+ def principals=(value)
+ write(value)
+ end
- # Return the mode as an octal string, not as an integer
- def mode
- "%o" % (File.stat(@resource[:name]).mode & 007777)
- end
+ # Return the mode as an octal string, not as an integer
+ def mode
+ "%o" % (File.stat(@resource[:name]).mode & 007777)
+ end
- # Set the file mode, converting from a string to an integer.
- def mode=(value)
- File.chmod(Integer("0#{value}"), @resource[:name])
- end
+ # Set the file mode, converting from a string to an integer.
+ def mode=(value)
+ File.chmod(Integer("0#{value}"), @resource[:name])
+ end
- private
- def write(value)
- File.open(@resource[:name], "w") { |f| f.puts value.join("\n") }
- end
+ private
+ def write(value)
+ File.open(@resource[:name], "w") { |f| f.puts value.join("\n") }
end
+ end
end
diff --git a/lib/puppet/type/macauthorization.rb b/lib/puppet/type/macauthorization.rb
index 5fe64fabe..9b17c279d 100644
--- a/lib/puppet/type/macauthorization.rb
+++ b/lib/puppet/type/macauthorization.rb
@@ -1,164 +1,164 @@
Puppet::Type.newtype(:macauthorization) do
- @doc = "Manage the Mac OS X authorization database.
- See:
- http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Security_Services/chapter_4_section_5.html for more information."
+ @doc = "Manage the Mac OS X authorization database.
+ See:
+ http://developer.apple.com/documentation/Security/Conceptual/Security_Overview/Security_Services/chapter_4_section_5.html for more information."
+
+ ensurable
+
+ autorequire(:file) do
+ ["/etc/authorization"]
+ end
+
+ def munge_boolean(value)
+ case value
+ when true, "true", :true
+ :true
+ when false, "false", :false
+ :false
+ else
+ fail("munge_boolean only takes booleans")
+ end
+ end
+
+ def munge_integer(value)
+ Integer(value)
+ rescue ArgumentError
+ fail("munge_integer only takes integers")
+ end
- ensurable
+ newparam(:name) do
+ desc "The name of the right or rule to be managed.
+ Corresponds to 'key' in Authorization Services. The key is the name
+ of a rule. A key uses the same naming conventions as a right. The
+ Security Server uses a rule’s key to match the rule with a right.
+ Wildcard keys end with a ‘.’. The generic rule has an empty key value.
+ Any rights that do not match a specific rule use the generic rule."
+
+ isnamevar
+ end
+
+ newproperty(:auth_type) do
+ desc "type - can be a 'right' or a 'rule'. 'comment' has not yet been
+ implemented."
- autorequire(:file) do
- ["/etc/authorization"]
- end
-
- def munge_boolean(value)
- case value
- when true, "true", :true
- :true
- when false, "false", :false
- :false
- else
- fail("munge_boolean only takes booleans")
- end
- end
-
- def munge_integer(value)
- Integer(value)
- rescue ArgumentError
- fail("munge_integer only takes integers")
- end
-
- newparam(:name) do
- desc "The name of the right or rule to be managed.
- Corresponds to 'key' in Authorization Services. The key is the name
- of a rule. A key uses the same naming conventions as a right. The
- Security Server uses a rule’s key to match the rule with a right.
- Wildcard keys end with a ‘.’. The generic rule has an empty key value.
- Any rights that do not match a specific rule use the generic rule."
+ newvalue(:right)
+ newvalue(:rule)
+ # newvalue(:comment) # not yet implemented.
+ end
+
+ newproperty(:allow_root, :boolean => true) do
+ desc "Corresponds to 'allow-root' in the authorization store, renamed
+ due to hyphens being problematic. Specifies whether a right should be
+ allowed automatically if the requesting process is running with
+ uid == 0. AuthorizationServices defaults this attribute to false if
+ not specified"
- isnamevar
+ newvalue(:true)
+ newvalue(:false)
+
+ munge do |value|
+ @resource.munge_boolean(value)
+ end
+ end
+
+ newproperty(:authenticate_user, :boolean => true) do
+ desc "Corresponds to 'authenticate-user' in the authorization store,
+ renamed due to hyphens being problematic."
+
+ newvalue(:true)
+ newvalue(:false)
+
+ munge do |value|
+ @resource.munge_boolean(value)
+ end
+ end
+
+ newproperty(:auth_class) do
+ desc "Corresponds to 'class' in the authorization store, renamed due
+ to 'class' being a reserved word."
+
+ newvalue(:user)
+ newvalue(:'evaluate-mechanisms')
+ newvalue(:allow)
+ newvalue(:deny)
+ newvalue(:rule)
+ end
+
+ newproperty(:comment) do
+ desc "The 'comment' attribute for authorization resources."
+ end
+
+ newproperty(:group) do
+ desc "The user must authenticate as a member of this group. This
+ attribute can be set to any one group."
+ end
+
+ newproperty(:k_of_n) do
+ desc "k-of-n describes how large a subset of rule mechanisms must
+ succeed for successful authentication. If there are 'n' mechanisms,
+ then 'k' (the integer value of this parameter) mechanisms must succeed.
+ The most common setting for this parameter is '1'. If k-of-n is not
+ set, then 'n-of-n' mechanisms must succeed."
+
+ munge do |value|
+ @resource.munge_integer(value)
end
+ end
- newproperty(:auth_type) do
- desc "type - can be a 'right' or a 'rule'. 'comment' has not yet been
- implemented."
-
- newvalue(:right)
- newvalue(:rule)
- # newvalue(:comment) # not yet implemented.
- end
+ newproperty(:mechanisms, :array_matching => :all) do
+ desc "an array of suitable mechanisms."
+ end
- newproperty(:allow_root, :boolean => true) do
- desc "Corresponds to 'allow-root' in the authorization store, renamed
- due to hyphens being problematic. Specifies whether a right should be
- allowed automatically if the requesting process is running with
- uid == 0. AuthorizationServices defaults this attribute to false if
- not specified"
-
- newvalue(:true)
- newvalue(:false)
-
- munge do |value|
- @resource.munge_boolean(value)
- end
- end
-
- newproperty(:authenticate_user, :boolean => true) do
- desc "Corresponds to 'authenticate-user' in the authorization store,
- renamed due to hyphens being problematic."
-
- newvalue(:true)
- newvalue(:false)
-
- munge do |value|
- @resource.munge_boolean(value)
- end
- end
-
- newproperty(:auth_class) do
- desc "Corresponds to 'class' in the authorization store, renamed due
- to 'class' being a reserved word."
-
- newvalue(:user)
- newvalue(:'evaluate-mechanisms')
- newvalue(:allow)
- newvalue(:deny)
- newvalue(:rule)
- end
-
- newproperty(:comment) do
- desc "The 'comment' attribute for authorization resources."
- end
-
- newproperty(:group) do
- desc "The user must authenticate as a member of this group. This
- attribute can be set to any one group."
- end
-
- newproperty(:k_of_n) do
- desc "k-of-n describes how large a subset of rule mechanisms must
- succeed for successful authentication. If there are 'n' mechanisms,
- then 'k' (the integer value of this parameter) mechanisms must succeed.
- The most common setting for this parameter is '1'. If k-of-n is not
- set, then 'n-of-n' mechanisms must succeed."
-
- munge do |value|
- @resource.munge_integer(value)
- end
- end
-
- newproperty(:mechanisms, :array_matching => :all) do
- desc "an array of suitable mechanisms."
- end
-
- newproperty(:rule, :array_matching => :all) do
- desc "The rule(s) that this right refers to."
- end
+ newproperty(:rule, :array_matching => :all) do
+ desc "The rule(s) that this right refers to."
+ end
- newproperty(:session_owner, :boolean => true) do
- desc "Corresponds to 'session-owner' in the authorization store,
- renamed due to hyphens being problematic. Whether the session owner
- automatically matches this rule or right."
+ newproperty(:session_owner, :boolean => true) do
+ desc "Corresponds to 'session-owner' in the authorization store,
+ renamed due to hyphens being problematic. Whether the session owner
+ automatically matches this rule or right."
- newvalue(:true)
- newvalue(:false)
+ newvalue(:true)
+ newvalue(:false)
- munge do |value|
- @resource.munge_boolean(value)
- end
+ munge do |value|
+ @resource.munge_boolean(value)
end
+ end
- newproperty(:shared, :boolean => true) do
- desc "If this is set to true, then the Security Server marks the
- credentials used to gain this right as shared. The Security Server
- may use any shared credentials to authorize this right. For maximum
- security, set sharing to false so credentials stored by the Security
- Server for one application may not be used by another application."
+ newproperty(:shared, :boolean => true) do
+ desc "If this is set to true, then the Security Server marks the
+ credentials used to gain this right as shared. The Security Server
+ may use any shared credentials to authorize this right. For maximum
+ security, set sharing to false so credentials stored by the Security
+ Server for one application may not be used by another application."
- newvalue(:true)
- newvalue(:false)
+ newvalue(:true)
+ newvalue(:false)
- munge do |value|
- @resource.munge_boolean(value)
- end
+ munge do |value|
+ @resource.munge_boolean(value)
end
+ end
- newproperty(:timeout) do
- desc "The credential used by this rule expires in the specified
- number of seconds. For maximum security where the user must
- authenticate every time, set the timeout to 0. For minimum security,
- remove the timeout attribute so the user authenticates only once per
- session."
+ newproperty(:timeout) do
+ desc "The credential used by this rule expires in the specified
+ number of seconds. For maximum security where the user must
+ authenticate every time, set the timeout to 0. For minimum security,
+ remove the timeout attribute so the user authenticates only once per
+ session."
- munge do |value|
- @resource.munge_integer(value)
- end
+ munge do |value|
+ @resource.munge_integer(value)
end
+ end
- newproperty(:tries) do
- desc "The number of tries allowed."
- munge do |value|
- @resource.munge_integer(value)
- end
+ newproperty(:tries) do
+ desc "The number of tries allowed."
+ munge do |value|
+ @resource.munge_integer(value)
end
+ end
end
diff --git a/lib/puppet/type/mailalias.rb b/lib/puppet/type/mailalias.rb
index 1044374a0..5534fdf25 100755
--- a/lib/puppet/type/mailalias.rb
+++ b/lib/puppet/type/mailalias.rb
@@ -1,49 +1,49 @@
module Puppet
- newtype(:mailalias) do
- @doc = "Creates an email alias in the local alias database."
+ newtype(:mailalias) do
+ @doc = "Creates an email alias in the local alias database."
- ensurable
+ ensurable
- newparam(:name, :namevar => true) do
- desc "The alias name."
+ newparam(:name, :namevar => true) do
+ desc "The alias name."
+ end
+
+ newproperty(:recipient, :array_matching => :all) do
+ desc "Where email should be sent. Multiple values
+ should be specified as an array."
+
+ def is_to_s(value)
+ if value.include?(:absent)
+ super
+ else
+ value.join(",")
end
+ end
- newproperty(:recipient, :array_matching => :all) do
- desc "Where email should be sent. Multiple values
- should be specified as an array."
-
- def is_to_s(value)
- if value.include?(:absent)
- super
- else
- value.join(",")
- end
- end
-
- def should
- @should
- end
-
- def should_to_s(value)
- if value.include?(:absent)
- super
- else
- value.join(",")
- end
- end
+ def should
+ @should
+ end
+
+ def should_to_s(value)
+ if value.include?(:absent)
+ super
+ else
+ value.join(",")
end
+ end
+ end
- newproperty(:target) do
- desc "The file in which to store the aliases. Only used by
- those providers that write to disk."
+ newproperty(:target) do
+ desc "The file in which to store the aliases. Only used by
+ those providers that write to disk."
- defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
- @resource.class.defaultprovider.default_target
- else
- nil
- end
- }
+ defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
+ @resource.class.defaultprovider.default_target
+ else
+ nil
end
+ }
end
+ end
end
diff --git a/lib/puppet/type/maillist.rb b/lib/puppet/type/maillist.rb
index af5ed51e4..7ac0e4e4f 100755
--- a/lib/puppet/type/maillist.rb
+++ b/lib/puppet/type/maillist.rb
@@ -1,63 +1,63 @@
module Puppet
- newtype(:maillist) do
- @doc = "Manage email lists. This resource type currently can only create
- and remove lists, it cannot reconfigure them."
-
- ensurable do
- defaultvalues
-
- newvalue(:purged) do
- provider.purge
- end
-
- def change_to_s(current_value, newvalue)
- return "Purged #{resource}" if newvalue == :purged
- super
- end
-
- def insync?(is)
- return true if is == :absent && should == :purged
- super
- end
- end
+ newtype(:maillist) do
+ @doc = "Manage email lists. This resource type currently can only create
+ and remove lists, it cannot reconfigure them."
+
+ ensurable do
+ defaultvalues
+
+ newvalue(:purged) do
+ provider.purge
+ end
+
+ def change_to_s(current_value, newvalue)
+ return "Purged #{resource}" if newvalue == :purged
+ super
+ end
+
+ def insync?(is)
+ return true if is == :absent && should == :purged
+ super
+ end
+ end
- newparam(:name, :namevar => true) do
- desc "The name of the email list."
- end
+ newparam(:name, :namevar => true) do
+ desc "The name of the email list."
+ end
- newparam(:description) do
- desc "The description of the mailing list."
- end
+ newparam(:description) do
+ desc "The description of the mailing list."
+ end
- newparam(:password) do
- desc "The admin password."
- end
+ newparam(:password) do
+ desc "The admin password."
+ end
- newparam(:webserver) do
- desc "The name of the host providing web archives and the administrative interface."
- end
+ newparam(:webserver) do
+ desc "The name of the host providing web archives and the administrative interface."
+ end
- newparam(:mailserver) do
- desc "The name of the host handling email for the list."
- end
+ newparam(:mailserver) do
+ desc "The name of the host handling email for the list."
+ end
- newparam(:admin) do
- desc "The email address of the administrator."
- end
+ newparam(:admin) do
+ desc "The email address of the administrator."
+ end
- def generate
- if provider.respond_to?(:aliases)
- should = self.should(:ensure) || :present
- if should == :purged
- should = :absent
- end
- atype = Puppet::Type.type(:mailalias)
-
- provider.aliases.
- reject { |name,recipient| catalog.resource(:mailalias, name) }.
- collect { |name,recipient| atype.new(:name => name, :recipient => recipient, :ensure => should) }
- end
+ def generate
+ if provider.respond_to?(:aliases)
+ should = self.should(:ensure) || :present
+ if should == :purged
+ should = :absent
end
+ atype = Puppet::Type.type(:mailalias)
+
+ provider.aliases.
+ reject { |name,recipient| catalog.resource(:mailalias, name) }.
+ collect { |name,recipient| atype.new(:name => name, :recipient => recipient, :ensure => should) }
+ end
end
+ end
end
diff --git a/lib/puppet/type/mcx.rb b/lib/puppet/type/mcx.rb
index 6e0266948..e56b11938 100644
--- a/lib/puppet/type/mcx.rb
+++ b/lib/puppet/type/mcx.rb
@@ -19,7 +19,7 @@
Puppet::Type.newtype(:mcx) do
- @doc = "MCX object management using DirectoryService on OS X.
+ @doc = "MCX object management using DirectoryService on OS X.
Original Author: Jeff McCune <mccune.jeff@gmail.com>
@@ -32,84 +32,84 @@ to manage users and groups on the local computer, record the resulting
puppet manifest using the command 'ralsh mcx' then deploying this
to other machines.
"
- feature :manages_content, \
- "The provider can manage MCXSettings as a string.",
- :methods => [:content, :content=]
+ feature :manages_content, \
+ "The provider can manage MCXSettings as a string.",
+ :methods => [:content, :content=]
- ensurable do
- desc "Create or remove the MCX setting."
+ ensurable do
+ desc "Create or remove the MCX setting."
- newvalue(:present) do
- provider.create
- end
-
- newvalue(:absent) do
- provider.destroy
- end
+ newvalue(:present) do
+ provider.create
+ end
+ newvalue(:absent) do
+ provider.destroy
end
- newparam(:name) do
- desc "The name of the resource being managed.
- The default naming convention follows Directory Service paths::
+ end
- /Computers/localhost
- /Groups/admin
- /Users/localadmin
+ newparam(:name) do
+ desc "The name of the resource being managed.
+ The default naming convention follows Directory Service paths::
- The ds_type and ds_name type parameters are not necessary if the
- default naming convention is followed."
- isnamevar
- end
+ /Computers/localhost
+ /Groups/admin
+ /Users/localadmin
- newparam(:ds_type) do
+ The ds_type and ds_name type parameters are not necessary if the
+ default naming convention is followed."
+ isnamevar
+ end
- desc "The DirectoryService type this MCX setting attaches to."
+ newparam(:ds_type) do
- newvalues(:user, :group, :computer, :computerlist)
+ desc "The DirectoryService type this MCX setting attaches to."
- end
+ newvalues(:user, :group, :computer, :computerlist)
- newparam(:ds_name) do
- desc "The name to attach the MCX Setting to.
- e.g. 'localhost' when ds_type => computer. This setting is not
- required, as it may be parsed so long as the resource name is
- parseable. e.g. /Groups/admin where 'group' is the dstype."
- end
+ end
- newproperty(:content, :required_features => :manages_content) do
- desc "The XML Plist. The value of MCXSettings in DirectoryService.
- This is the standard output from the system command:
- dscl localhost -mcxexport /Local/Default/<ds_type>/ds_name
- Note that ds_type is capitalized and plural in the dscl command."
- end
+ newparam(:ds_name) do
+ desc "The name to attach the MCX Setting to.
+ e.g. 'localhost' when ds_type => computer. This setting is not
+ required, as it may be parsed so long as the resource name is
+ parseable. e.g. /Groups/admin where 'group' is the dstype."
+ end
- # JJM Yes, this is not DRY at all. Because of the code blocks
- # autorequire must be done this way. I think.
-
- def setup_autorequire(type)
- # value returns a Symbol
- name = value(:name)
- ds_type = value(:ds_type)
- ds_name = value(:ds_name)
- if ds_type == type
- rval = [ ds_name.to_s ]
- else
- rval = [ ]
- end
- rval
- end
+ newproperty(:content, :required_features => :manages_content) do
+ desc "The XML Plist. The value of MCXSettings in DirectoryService.
+ This is the standard output from the system command:
+ dscl localhost -mcxexport /Local/Default/<ds_type>/ds_name
+ Note that ds_type is capitalized and plural in the dscl command."
+ end
- autorequire(:user) do
- setup_autorequire(:user)
- end
+ # JJM Yes, this is not DRY at all. Because of the code blocks
+ # autorequire must be done this way. I think.
- autorequire(:group) do
- setup_autorequire(:group)
+ def setup_autorequire(type)
+ # value returns a Symbol
+ name = value(:name)
+ ds_type = value(:ds_type)
+ ds_name = value(:ds_name)
+ if ds_type == type
+ rval = [ ds_name.to_s ]
+ else
+ rval = [ ]
end
+ rval
+ end
- autorequire(:computer) do
- setup_autorequire(:computer)
- end
+ autorequire(:user) do
+ setup_autorequire(:user)
+ end
+
+ autorequire(:group) do
+ setup_autorequire(:group)
+ end
+
+ autorequire(:computer) do
+ setup_autorequire(:computer)
+ end
end
diff --git a/lib/puppet/type/mount.rb b/lib/puppet/type/mount.rb
index cf9b40867..6ee5dd174 100755
--- a/lib/puppet/type/mount.rb
+++ b/lib/puppet/type/mount.rb
@@ -1,225 +1,225 @@
module Puppet
- # We want the mount to refresh when it changes.
- newtype(:mount, :self_refresh => true) do
- @doc = "Manages mounted filesystems, including putting mount
- information into the mount table. The actual behavior depends
- on the value of the 'ensure' parameter.
-
- Note that if a ``mount`` receives an event from another resource,
- it will try to remount the filesystems if ``ensure`` is set to ``mounted``."
-
- feature :refreshable, "The provider can remount the filesystem.",
- :methods => [:remount]
-
- # Use the normal parent class, because we actually want to
- # call code when sync is called.
- newproperty(:ensure) do
- desc "Control what to do with this mount. Set this attribute to
- ``umounted`` to make sure the filesystem is in the filesystem table
- but not mounted (if the filesystem is currently mounted, it will be unmounted). Set it to ``absent`` to unmount (if necessary) and remove
- the filesystem from the fstab. Set to ``mounted`` to add it to the
- fstab and mount it. Set to ``present`` to add to fstab but not change
- mount/unmount status"
-
- newvalue(:defined) do
- provider.create
- return :mount_created
- end
-
- aliasvalue :present, :defined
-
- newvalue(:unmounted) do
- if provider.mounted?
- syncothers
- provider.unmount
- return :mount_unmounted
- else
- provider.create
- return :mount_created
- end
- end
-
- newvalue(:absent, :event => :mount_deleted) do
- provider.unmount if provider.mounted?
-
- provider.destroy
- end
-
- newvalue(:mounted, :event => :mount_mounted) do
- # Create the mount point if it does not already exist.
- current_value = self.retrieve
- provider.create if current_value.nil? or current_value == :absent
-
- syncothers
-
- # The fs can be already mounted if it was absent but mounted
- provider.mount unless provider.mounted?
- end
-
- def insync?(is)
- if should == :defined and is != :absent
- true
- else
- super
- end
- end
-
- def retrieve
- # We need to special case :mounted; if we're absent, we still
- # want
- curval = super()
- if curval == :absent
- return :absent
- elsif provider.mounted?
- return :mounted
- else
- return :unmounted
- end
- end
-
- def syncothers
- # We have to flush any changes to disk.
- currentvalues = @resource.retrieve_resource
-
- # Determine if there are any out-of-sync properties.
- oos = @resource.send(:properties).find_all do |prop|
- unless currentvalues.include?(prop)
- raise Puppet::DevError, "Parent has property %s but it doesn't appear in the current values", [prop.name]
- end
- if prop.name == :ensure
- false
- else
- ! prop.insync?(currentvalues[prop])
- end
- end.each { |prop| prop.sync }.length
- @resource.flush if oos > 0
- end
+ # We want the mount to refresh when it changes.
+ newtype(:mount, :self_refresh => true) do
+ @doc = "Manages mounted filesystems, including putting mount
+ information into the mount table. The actual behavior depends
+ on the value of the 'ensure' parameter.
+
+ Note that if a ``mount`` receives an event from another resource,
+ it will try to remount the filesystems if ``ensure`` is set to ``mounted``."
+
+ feature :refreshable, "The provider can remount the filesystem.",
+ :methods => [:remount]
+
+ # Use the normal parent class, because we actually want to
+ # call code when sync is called.
+ newproperty(:ensure) do
+ desc "Control what to do with this mount. Set this attribute to
+ ``umounted`` to make sure the filesystem is in the filesystem table
+ but not mounted (if the filesystem is currently mounted, it will be unmounted). Set it to ``absent`` to unmount (if necessary) and remove
+ the filesystem from the fstab. Set to ``mounted`` to add it to the
+ fstab and mount it. Set to ``present`` to add to fstab but not change
+ mount/unmount status"
+
+ newvalue(:defined) do
+ provider.create
+ return :mount_created
+ end
+
+ aliasvalue :present, :defined
+
+ newvalue(:unmounted) do
+ if provider.mounted?
+ syncothers
+ provider.unmount
+ return :mount_unmounted
+ else
+ provider.create
+ return :mount_created
end
+ end
- newproperty(:device) do
- desc "The device providing the mount. This can be whatever
- device is supporting by the mount, including network
- devices or devices specified by UUID rather than device
- path, depending on the operating system."
- end
+ newvalue(:absent, :event => :mount_deleted) do
+ provider.unmount if provider.mounted?
- # Solaris specifies two devices, not just one.
- newproperty(:blockdevice) do
- desc "The device to fsck. This is property is only valid
- on Solaris, and in most cases will default to the correct
- value."
-
- # Default to the device but with "dsk" replaced with "rdsk".
- defaultto do
- if Facter["operatingsystem"].value == "Solaris"
- device = @resource.value(:device)
- if device =~ %r{/dsk/}
- device.sub(%r{/dsk/}, "/rdsk/")
- else
- nil
- end
- else
- nil
- end
- end
- end
+ provider.destroy
+ end
- newproperty(:fstype) do
- desc "The mount type. Valid values depend on the
- operating system. This is a required option."
- end
+ newvalue(:mounted, :event => :mount_mounted) do
+ # Create the mount point if it does not already exist.
+ current_value = self.retrieve
+ provider.create if current_value.nil? or current_value == :absent
- newproperty(:options) do
- desc "Mount options for the mounts, as they would
- appear in the fstab."
- end
+ syncothers
- newproperty(:pass) do
- desc "The pass in which the mount is checked."
+ # The fs can be already mounted if it was absent but mounted
+ provider.mount unless provider.mounted?
+ end
- defaultto {
- 0 if @resource.managed?
- }
+ def insync?(is)
+ if should == :defined and is != :absent
+ true
+ else
+ super
end
+ end
+
+ def retrieve
+ # We need to special case :mounted; if we're absent, we still
+ # want
+ curval = super()
+ if curval == :absent
+ return :absent
+ elsif provider.mounted?
+ return :mounted
+ else
+ return :unmounted
+ end
+ end
+
+ def syncothers
+ # We have to flush any changes to disk.
+ currentvalues = @resource.retrieve_resource
+
+ # Determine if there are any out-of-sync properties.
+ oos = @resource.send(:properties).find_all do |prop|
+ unless currentvalues.include?(prop)
+ raise Puppet::DevError, "Parent has property %s but it doesn't appear in the current values", [prop.name]
+ end
+ if prop.name == :ensure
+ false
+ else
+ ! prop.insync?(currentvalues[prop])
+ end
+ end.each { |prop| prop.sync }.length
+ @resource.flush if oos > 0
+ end
+ end
+
+ newproperty(:device) do
+ desc "The device providing the mount. This can be whatever
+ device is supporting by the mount, including network
+ devices or devices specified by UUID rather than device
+ path, depending on the operating system."
+ end
- newproperty(:atboot) do
- desc "Whether to mount the mount at boot. Not all platforms
- support this."
+ # Solaris specifies two devices, not just one.
+ newproperty(:blockdevice) do
+ desc "The device to fsck. This is property is only valid
+ on Solaris, and in most cases will default to the correct
+ value."
+
+ # Default to the device but with "dsk" replaced with "rdsk".
+ defaultto do
+ if Facter["operatingsystem"].value == "Solaris"
+ device = @resource.value(:device)
+ if device =~ %r{/dsk/}
+ device.sub(%r{/dsk/}, "/rdsk/")
+ else
+ nil
+ end
+ else
+ nil
end
+ end
+ end
- newproperty(:dump) do
- desc "Whether to dump the mount. Not all platform support this.
- Valid values are ``1`` or ``0``. or ``2`` on FreeBSD, Default is ``0``."
+ newproperty(:fstype) do
+ desc "The mount type. Valid values depend on the
+ operating system. This is a required option."
+ end
- if Facter["operatingsystem"].value == "FreeBSD"
- newvalue(%r{(0|1|2)})
- else
- newvalue(%r{(0|1)})
- end
+ newproperty(:options) do
+ desc "Mount options for the mounts, as they would
+ appear in the fstab."
+ end
- newvalue(%r{(0|1)})
+ newproperty(:pass) do
+ desc "The pass in which the mount is checked."
- defaultto {
- 0 if @resource.managed?
- }
- end
+ defaultto {
+ 0 if @resource.managed?
+ }
+ end
- newproperty(:target) do
- desc "The file in which to store the mount table. Only used by
- those providers that write to disk."
+ newproperty(:atboot) do
+ desc "Whether to mount the mount at boot. Not all platforms
+ support this."
+ end
- defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
- @resource.class.defaultprovider.default_target
- else
- nil
- end
- }
- end
+ newproperty(:dump) do
+ desc "Whether to dump the mount. Not all platform support this.
+ Valid values are ``1`` or ``0``. or ``2`` on FreeBSD, Default is ``0``."
- newparam(:name) do
- desc "The mount path for the mount."
+ if Facter["operatingsystem"].value == "FreeBSD"
+ newvalue(%r{(0|1|2)})
+ else
+ newvalue(%r{(0|1)})
+ end
- isnamevar
- end
+ newvalue(%r{(0|1)})
- newparam(:path) do
- desc "The deprecated name for the mount point. Please use ``name`` now."
+ defaultto {
+ 0 if @resource.managed?
+ }
+ end
- def value=(value)
- warning "'path' is deprecated for mounts. Please use 'name'."
- @resource[:name] = value
- super
- end
- end
+ newproperty(:target) do
+ desc "The file in which to store the mount table. Only used by
+ those providers that write to disk."
- newparam(:remounts) do
- desc "Whether the mount can be remounted ``mount -o remount``. If
- this is false, then the filesystem will be unmounted and remounted
- manually, which is prone to failure."
-
- newvalues(:true, :false)
- defaultto do
- case Facter.value(:operatingsystem)
- when "FreeBSD", "Darwin"
- false
- else
- true
- end
- end
+ defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
+ @resource.class.defaultprovider.default_target
+ else
+ nil
end
+ }
+ end
- def refresh
- # Only remount if we're supposed to be mounted.
- provider.remount if self.should(:fstype) != "swap" and provider.mounted?
- end
+ newparam(:name) do
+ desc "The mount path for the mount."
+
+ isnamevar
+ end
- def value(name)
- name = symbolize(name)
- ret = nil
- if property = @parameters[name]
- return property.value
- end
+ newparam(:path) do
+ desc "The deprecated name for the mount point. Please use ``name`` now."
+
+ def value=(value)
+ warning "'path' is deprecated for mounts. Please use 'name'."
+ @resource[:name] = value
+ super
+ end
+ end
+
+ newparam(:remounts) do
+ desc "Whether the mount can be remounted ``mount -o remount``. If
+ this is false, then the filesystem will be unmounted and remounted
+ manually, which is prone to failure."
+
+ newvalues(:true, :false)
+ defaultto do
+ case Facter.value(:operatingsystem)
+ when "FreeBSD", "Darwin"
+ false
+ else
+ true
end
+ end
+ end
+
+ def refresh
+ # Only remount if we're supposed to be mounted.
+ provider.remount if self.should(:fstype) != "swap" and provider.mounted?
+ end
+
+ def value(name)
+ name = symbolize(name)
+ ret = nil
+ if property = @parameters[name]
+ return property.value
+ end
end
+ end
end
diff --git a/lib/puppet/type/notify.rb b/lib/puppet/type/notify.rb
index d46ade7a5..97935e270 100644
--- a/lib/puppet/type/notify.rb
+++ b/lib/puppet/type/notify.rb
@@ -3,43 +3,43 @@
#
module Puppet
- newtype(:notify) do
- @doc = "Sends an arbitrary message to the agent run-time log."
-
- newproperty(:message) do
- desc "The message to be sent to the log."
- def sync
- case @resource["withpath"]
- when :true
- send(@resource[:loglevel], self.should)
- else
- Puppet.send(@resource[:loglevel], self.should)
- end
- return
- end
-
- def retrieve
- :absent
- end
-
- def insync?(is)
- false
- end
-
- defaultto { @resource[:name] }
+ newtype(:notify) do
+ @doc = "Sends an arbitrary message to the agent run-time log."
+
+ newproperty(:message) do
+ desc "The message to be sent to the log."
+ def sync
+ case @resource["withpath"]
+ when :true
+ send(@resource[:loglevel], self.should)
+ else
+ Puppet.send(@resource[:loglevel], self.should)
end
+ return
+ end
- newparam(:withpath) do
- desc "Whether to not to show the full object path."
- defaultto :false
+ def retrieve
+ :absent
+ end
- newvalues(:true, :false)
- end
+ def insync?(is)
+ false
+ end
- newparam(:name) do
- desc "An arbitrary tag for your own reference; the name of the message."
- isnamevar
- end
+ defaultto { @resource[:name] }
+ end
+
+ newparam(:withpath) do
+ desc "Whether to not to show the full object path."
+ defaultto :false
+
+ newvalues(:true, :false)
+ end
+
+ newparam(:name) do
+ desc "An arbitrary tag for your own reference; the name of the message."
+ isnamevar
end
+ end
end
diff --git a/lib/puppet/type/package.rb b/lib/puppet/type/package.rb
index 658901ee2..f25464db5 100644
--- a/lib/puppet/type/package.rb
+++ b/lib/puppet/type/package.rb
@@ -4,320 +4,320 @@
# systems.
module Puppet
- newtype(:package) do
- @doc = "Manage packages. There is a basic dichotomy in package
- support right now: Some package types (e.g., yum and apt) can
- retrieve their own package files, while others (e.g., rpm and sun) cannot. For those package formats that cannot retrieve
- their own files, you can use the ``source`` parameter to point to
- the correct file.
-
- Puppet will automatically guess the packaging format that you are
- using based on the platform you are on, but you can override it
- using the ``provider`` parameter; each provider defines what it
- requires in order to function, and you must meet those requirements
- to use a given provider."
-
- feature :installable, "The provider can install packages.",
- :methods => [:install]
- feature :uninstallable, "The provider can uninstall packages.",
- :methods => [:uninstall]
- feature :upgradeable, "The provider can upgrade to the latest version of a
- package. This feature is used by specifying ``latest`` as the
- desired value for the package.",
- :methods => [:update, :latest]
- feature :purgeable, "The provider can purge packages. This generally means
- that all traces of the package are removed, including
- existing configuration files. This feature is thus destructive
- and should be used with the utmost care.",
- :methods => [:purge]
- feature :versionable, "The provider is capable of interrogating the
- package database for installed version(s), and can select
- which out of a set of available versions of a package to
- install if asked."
- feature :holdable, "The provider is capable of placing packages on hold
- such that they are not automatically upgraded as a result of
- other package dependencies unless explicit action is taken by
- a user or another package. Held is considered a superset of
- installed.",
- :methods => [:hold]
-
- ensurable do
- desc "What state the package should be in.
- *latest* only makes sense for those packaging formats that can
- retrieve new packages on their own and will throw an error on
- those that cannot. For those packaging systems that allow you
- to specify package versions, specify them here. Similarly,
- *purged* is only useful for packaging systems that support
- the notion of managing configuration files separately from
- 'normal' system files."
-
- attr_accessor :latest
-
- newvalue(:present, :event => :package_installed) do
- provider.install
- end
-
- newvalue(:absent, :event => :package_removed) do
- provider.uninstall
- end
-
- newvalue(:purged, :event => :package_purged, :required_features => :purgeable) do
- provider.purge
- end
-
- newvalue(:held, :event => :package_held, :required_features => :holdable) do
- provider.hold
- end
-
- # Alias the 'present' value.
- aliasvalue(:installed, :present)
-
- newvalue(:latest, :required_features => :upgradeable) do
- # Because yum always exits with a 0 exit code, there's a retrieve
- # in the "install" method. So, check the current state now,
- # to compare against later.
- current = self.retrieve
- begin
- provider.update
- rescue => detail
- self.fail "Could not update: #{detail}"
- end
-
- if current == :absent
- :package_installed
- else
- :package_changed
- end
- end
-
- newvalue(/./, :required_features => :versionable) do
- begin
- provider.install
- rescue => detail
- self.fail "Could not update: #{detail}"
- end
-
- if self.retrieve == :absent
- :package_installed
- else
- :package_changed
- end
- end
+ newtype(:package) do
+ @doc = "Manage packages. There is a basic dichotomy in package
+ support right now: Some package types (e.g., yum and apt) can
+ retrieve their own package files, while others (e.g., rpm and sun) cannot. For those package formats that cannot retrieve
+ their own files, you can use the ``source`` parameter to point to
+ the correct file.
+
+ Puppet will automatically guess the packaging format that you are
+ using based on the platform you are on, but you can override it
+ using the ``provider`` parameter; each provider defines what it
+ requires in order to function, and you must meet those requirements
+ to use a given provider."
+
+ feature :installable, "The provider can install packages.",
+ :methods => [:install]
+ feature :uninstallable, "The provider can uninstall packages.",
+ :methods => [:uninstall]
+ feature :upgradeable, "The provider can upgrade to the latest version of a
+ package. This feature is used by specifying ``latest`` as the
+ desired value for the package.",
+ :methods => [:update, :latest]
+ feature :purgeable, "The provider can purge packages. This generally means
+ that all traces of the package are removed, including
+ existing configuration files. This feature is thus destructive
+ and should be used with the utmost care.",
+ :methods => [:purge]
+ feature :versionable, "The provider is capable of interrogating the
+ package database for installed version(s), and can select
+ which out of a set of available versions of a package to
+ install if asked."
+ feature :holdable, "The provider is capable of placing packages on hold
+ such that they are not automatically upgraded as a result of
+ other package dependencies unless explicit action is taken by
+ a user or another package. Held is considered a superset of
+ installed.",
+ :methods => [:hold]
+
+ ensurable do
+ desc "What state the package should be in.
+ *latest* only makes sense for those packaging formats that can
+ retrieve new packages on their own and will throw an error on
+ those that cannot. For those packaging systems that allow you
+ to specify package versions, specify them here. Similarly,
+ *purged* is only useful for packaging systems that support
+ the notion of managing configuration files separately from
+ 'normal' system files."
+
+ attr_accessor :latest
+
+ newvalue(:present, :event => :package_installed) do
+ provider.install
+ end
+
+ newvalue(:absent, :event => :package_removed) do
+ provider.uninstall
+ end
+
+ newvalue(:purged, :event => :package_purged, :required_features => :purgeable) do
+ provider.purge
+ end
+
+ newvalue(:held, :event => :package_held, :required_features => :holdable) do
+ provider.hold
+ end
+
+ # Alias the 'present' value.
+ aliasvalue(:installed, :present)
+
+ newvalue(:latest, :required_features => :upgradeable) do
+ # Because yum always exits with a 0 exit code, there's a retrieve
+ # in the "install" method. So, check the current state now,
+ # to compare against later.
+ current = self.retrieve
+ begin
+ provider.update
+ rescue => detail
+ self.fail "Could not update: #{detail}"
+ end
+ if current == :absent
+ :package_installed
+ else
+ :package_changed
+ end
+ end
- defaultto :installed
-
- # Override the parent method, because we've got all kinds of
- # funky definitions of 'in sync'.
- def insync?(is)
- @should ||= []
-
- @latest ||= nil
- @lateststamp ||= (Time.now.to_i - 1000)
- # Iterate across all of the should values, and see how they
- # turn out.
-
- @should.each { |should|
- case should
- when :present
- return true unless [:absent, :purged, :held].include?(is)
- when :latest
- # Short-circuit packages that are not present
- return false if is == :absent or is == :purged
-
- # Don't run 'latest' more than about every 5 minutes
- if @latest and ((Time.now.to_i - @lateststamp) / 60) < 5
- #self.debug "Skipping latest check"
- else
- begin
- @latest = provider.latest
- @lateststamp = Time.now.to_i
- rescue => detail
- error = Puppet::Error.new("Could not get latest version: #{detail}")
- error.set_backtrace(detail.backtrace)
- raise error
- end
- end
-
- case is
- when @latest
- return true
- when :present
- # This will only happen on retarded packaging systems
- # that can't query versions.
- return true
- else
- self.debug "#{@resource.name} #{is.inspect} is installed, latest is #{@latest.inspect}"
- end
- when :absent
- return true if is == :absent or is == :purged
- when :purged
- return true if is == :purged
- when is
- return true
- end
- }
-
- false
- end
+ newvalue(/./, :required_features => :versionable) do
+ begin
+ provider.install
+ rescue => detail
+ self.fail "Could not update: #{detail}"
+ end
- # This retrieves the current state. LAK: I think this method is unused.
- def retrieve
- provider.properties[:ensure]
+ if self.retrieve == :absent
+ :package_installed
+ else
+ :package_changed
+ end
+ end
+
+
+ defaultto :installed
+
+ # Override the parent method, because we've got all kinds of
+ # funky definitions of 'in sync'.
+ def insync?(is)
+ @should ||= []
+
+ @latest ||= nil
+ @lateststamp ||= (Time.now.to_i - 1000)
+ # Iterate across all of the should values, and see how they
+ # turn out.
+
+ @should.each { |should|
+ case should
+ when :present
+ return true unless [:absent, :purged, :held].include?(is)
+ when :latest
+ # Short-circuit packages that are not present
+ return false if is == :absent or is == :purged
+
+ # Don't run 'latest' more than about every 5 minutes
+ if @latest and ((Time.now.to_i - @lateststamp) / 60) < 5
+ #self.debug "Skipping latest check"
+ else
+ begin
+ @latest = provider.latest
+ @lateststamp = Time.now.to_i
+ rescue => detail
+ error = Puppet::Error.new("Could not get latest version: #{detail}")
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
end
- # Provide a bit more information when logging upgrades.
- def should_to_s(newvalue = @should)
- if @latest
- @latest.to_s
- else
- super(newvalue)
- end
+ case is
+ when @latest
+ return true
+ when :present
+ # This will only happen on retarded packaging systems
+ # that can't query versions.
+ return true
+ else
+ self.debug "#{@resource.name} #{is.inspect} is installed, latest is #{@latest.inspect}"
end
+ when :absent
+ return true if is == :absent or is == :purged
+ when :purged
+ return true if is == :purged
+ when is
+ return true
+ end
+ }
+
+ false
+ end
+
+ # This retrieves the current state. LAK: I think this method is unused.
+ def retrieve
+ provider.properties[:ensure]
+ end
+
+ # Provide a bit more information when logging upgrades.
+ def should_to_s(newvalue = @should)
+ if @latest
+ @latest.to_s
+ else
+ super(newvalue)
end
+ end
+ end
- newparam(:name) do
- desc "The package name. This is the name that the packaging
- system uses internally, which is sometimes (especially on Solaris)
- a name that is basically useless to humans. If you want to
- abstract package installation, then you can use aliases to provide
- a common name to packages::
-
- # In the 'openssl' class
- $ssl = $operatingsystem ? {
- solaris => SMCossl,
- default => openssl
- }
-
- # It is not an error to set an alias to the same value as the
- # object name.
- package { $ssl:
- ensure => installed,
- alias => openssl
- }
-
- . etc. .
-
- $ssh = $operatingsystem ? {
- solaris => SMCossh,
- default => openssh
- }
-
- # Use the alias to specify a dependency, rather than
- # having another selector to figure it out again.
- package { $ssh:
- ensure => installed,
- alias => openssh,
- require => Package[openssl]
- }
-
- "
- isnamevar
- end
+ newparam(:name) do
+ desc "The package name. This is the name that the packaging
+ system uses internally, which is sometimes (especially on Solaris)
+ a name that is basically useless to humans. If you want to
+ abstract package installation, then you can use aliases to provide
+ a common name to packages::
+
+ # In the 'openssl' class
+ $ssl = $operatingsystem ? {
+ solaris => SMCossl,
+ default => openssl
+ }
+
+ # It is not an error to set an alias to the same value as the
+ # object name.
+ package { $ssl:
+ ensure => installed,
+ alias => openssl
+ }
+
+ . etc. .
+
+ $ssh = $operatingsystem ? {
+ solaris => SMCossh,
+ default => openssh
+ }
+
+ # Use the alias to specify a dependency, rather than
+ # having another selector to figure it out again.
+ package { $ssh:
+ ensure => installed,
+ alias => openssh,
+ require => Package[openssl]
+ }
+
+ "
+ isnamevar
+ end
- newparam(:source) do
- desc "Where to find the actual package. This must be a local file
- (or on a network file system) or a URL that your specific
- packaging type understands; Puppet will not retrieve files for you."
- end
- newparam(:instance) do
- desc "A read-only parameter set by the package."
- end
- newparam(:status) do
- desc "A read-only parameter set by the package."
- end
+ newparam(:source) do
+ desc "Where to find the actual package. This must be a local file
+ (or on a network file system) or a URL that your specific
+ packaging type understands; Puppet will not retrieve files for you."
+ end
+ newparam(:instance) do
+ desc "A read-only parameter set by the package."
+ end
+ newparam(:status) do
+ desc "A read-only parameter set by the package."
+ end
- newparam(:type) do
- desc "Deprecated form of ``provider``."
+ newparam(:type) do
+ desc "Deprecated form of ``provider``."
- munge do |value|
- warning "'type' is deprecated; use 'provider' instead"
- @resource[:provider] = value
+ munge do |value|
+ warning "'type' is deprecated; use 'provider' instead"
+ @resource[:provider] = value
- @resource[:provider]
- end
- end
+ @resource[:provider]
+ end
+ end
- newparam(:adminfile) do
- desc "A file containing package defaults for installing packages.
- This is currently only used on Solaris. The value will be
- validated according to system rules, which in the case of
- Solaris means that it should either be a fully qualified path
- or it should be in /var/sadm/install/admin."
- end
+ newparam(:adminfile) do
+ desc "A file containing package defaults for installing packages.
+ This is currently only used on Solaris. The value will be
+ validated according to system rules, which in the case of
+ Solaris means that it should either be a fully qualified path
+ or it should be in /var/sadm/install/admin."
+ end
- newparam(:responsefile) do
- desc "A file containing any necessary answers to questions asked by
- the package. This is currently used on Solaris and Debian. The
- value will be validated according to system rules, but it should
- generally be a fully qualified path."
- end
+ newparam(:responsefile) do
+ desc "A file containing any necessary answers to questions asked by
+ the package. This is currently used on Solaris and Debian. The
+ value will be validated according to system rules, but it should
+ generally be a fully qualified path."
+ end
- newparam(:configfiles) do
- desc "Whether configfiles should be kept or replaced. Most packages
- types do not support this parameter."
+ newparam(:configfiles) do
+ desc "Whether configfiles should be kept or replaced. Most packages
+ types do not support this parameter."
- defaultto :keep
+ defaultto :keep
- newvalues(:keep, :replace)
- end
+ newvalues(:keep, :replace)
+ end
- newparam(:category) do
- desc "A read-only parameter set by the package."
- end
- newparam(:platform) do
- desc "A read-only parameter set by the package."
- end
- newparam(:root) do
- desc "A read-only parameter set by the package."
- end
- newparam(:vendor) do
- desc "A read-only parameter set by the package."
- end
- newparam(:description) do
- desc "A read-only parameter set by the package."
- end
+ newparam(:category) do
+ desc "A read-only parameter set by the package."
+ end
+ newparam(:platform) do
+ desc "A read-only parameter set by the package."
+ end
+ newparam(:root) do
+ desc "A read-only parameter set by the package."
+ end
+ newparam(:vendor) do
+ desc "A read-only parameter set by the package."
+ end
+ newparam(:description) do
+ desc "A read-only parameter set by the package."
+ end
- newparam(:allowcdrom) do
- desc "Tells apt to allow cdrom sources in the sources.list file.
- Normally apt will bail if you try this."
+ newparam(:allowcdrom) do
+ desc "Tells apt to allow cdrom sources in the sources.list file.
+ Normally apt will bail if you try this."
- newvalues(:true, :false)
- end
+ newvalues(:true, :false)
+ end
- newparam(:flavor) do
- desc "Newer versions of OpenBSD support 'flavors', which are
- further specifications for which type of package you want."
- end
+ newparam(:flavor) do
+ desc "Newer versions of OpenBSD support 'flavors', which are
+ further specifications for which type of package you want."
+ end
- autorequire(:file) do
- autos = []
- [:responsefile, :adminfile].each { |param|
- if val = self[param]
- autos << val
- end
- }
-
- if source = self[:source]
- if source =~ /^#{File::SEPARATOR}/
- autos << source
- end
- end
- autos
+ autorequire(:file) do
+ autos = []
+ [:responsefile, :adminfile].each { |param|
+ if val = self[param]
+ autos << val
end
+ }
- # This only exists for testing.
- def clear
- if obj = @parameters[:ensure]
- obj.latest = nil
- end
+ if source = self[:source]
+ if source =~ /^#{File::SEPARATOR}/
+ autos << source
end
+ end
+ autos
+ end
- # The 'query' method returns a hash of info if the package
- # exists and returns nil if it does not.
- def exists?
- @provider.get(:ensure) != :absent
- end
+ # This only exists for testing.
+ def clear
+ if obj = @parameters[:ensure]
+ obj.latest = nil
+ end
+ end
+
+ # The 'query' method returns a hash of info if the package
+ # exists and returns nil if it does not.
+ def exists?
+ @provider.get(:ensure) != :absent
end
+ end
end
diff --git a/lib/puppet/type/resources.rb b/lib/puppet/type/resources.rb
index 6e351f861..34382e067 100644
--- a/lib/puppet/type/resources.rb
+++ b/lib/puppet/type/resources.rb
@@ -4,132 +4,132 @@
require 'puppet'
Puppet::Type.newtype(:resources) do
- @doc = "This is a metatype that can manage other resource types. Any
- metaparams specified here will be passed on to any generated resources,
- so you can purge umanaged resources but set ``noop`` to true so the
- purging is only logged and does not actually happen."
+ @doc = "This is a metatype that can manage other resource types. Any
+ metaparams specified here will be passed on to any generated resources,
+ so you can purge umanaged resources but set ``noop`` to true so the
+ purging is only logged and does not actually happen."
- newparam(:name) do
- desc "The name of the type to be managed."
+ newparam(:name) do
+ desc "The name of the type to be managed."
- validate do |name|
- raise ArgumentError, "Could not find resource type '#{name}'" unless Puppet::Type.type(name)
- end
-
- munge { |v| v.to_s }
+ validate do |name|
+ raise ArgumentError, "Could not find resource type '#{name}'" unless Puppet::Type.type(name)
end
- newparam(:purge, :boolean => true) do
- desc "Purge unmanaged resources. This will delete any resource
- that is not specified in your configuration
- and is not required by any specified resources."
+ munge { |v| v.to_s }
+ end
- newvalues(:true, :false)
+ newparam(:purge, :boolean => true) do
+ desc "Purge unmanaged resources. This will delete any resource
+ that is not specified in your configuration
+ and is not required by any specified resources."
- validate do |value|
- if [:true, true, "true"].include?(value)
- unless @resource.resource_type.respond_to?(:instances)
- raise ArgumentError, "Purging resources of type #{@resource[:name]} is not supported, since they cannot be queried from the system"
- end
- raise ArgumentError, "Purging is only supported on types that accept 'ensure'" unless @resource.resource_type.validproperty?(:ensure)
- end
- end
- end
+ newvalues(:true, :false)
- newparam(:unless_system_user) do
- desc "This keeps system users from being purged. By default, it
- does not purge users whose UIDs are less than or equal to 500, but you can specify
- a different UID as the inclusive limit."
-
- newvalues(:true, :false, /^\d+$/)
-
- munge do |value|
- case value
- when /^\d+/
- Integer(value)
- when :true, true
- 500
- when :false, false
- false
- when Integer; value
- else
- raise ArgumentError, "Invalid value #{value.inspect}"
- end
+ validate do |value|
+ if [:true, true, "true"].include?(value)
+ unless @resource.resource_type.respond_to?(:instances)
+ raise ArgumentError, "Purging resources of type #{@resource[:name]} is not supported, since they cannot be queried from the system"
end
-
- defaultto {
- if @resource[:name] == "user"
- 500
- else
- nil
- end
- }
+ raise ArgumentError, "Purging is only supported on types that accept 'ensure'" unless @resource.resource_type.validproperty?(:ensure)
+ end
end
-
- def check(resource)
- @checkmethod ||= "#{self[:name]}_check"
- @hascheck ||= respond_to?(@checkmethod)
- if @hascheck
- return send(@checkmethod, resource)
- else
- return true
- end
+ end
+
+ newparam(:unless_system_user) do
+ desc "This keeps system users from being purged. By default, it
+ does not purge users whose UIDs are less than or equal to 500, but you can specify
+ a different UID as the inclusive limit."
+
+ newvalues(:true, :false, /^\d+$/)
+
+ munge do |value|
+ case value
+ when /^\d+/
+ Integer(value)
+ when :true, true
+ 500
+ when :false, false
+ false
+ when Integer; value
+ else
+ raise ArgumentError, "Invalid value #{value.inspect}"
+ end
end
- def able_to_ensure_absent?(resource)
- resource[:ensure] = :absent
- rescue ArgumentError, Puppet::Error => detail
- err "The 'ensure' attribute on #{self[:name]} resources does not accept 'absent' as a value"
- false
+ defaultto {
+ if @resource[:name] == "user"
+ 500
+ else
+ nil
+ end
+ }
+ end
+
+ def check(resource)
+ @checkmethod ||= "#{self[:name]}_check"
+ @hascheck ||= respond_to?(@checkmethod)
+ if @hascheck
+ return send(@checkmethod, resource)
+ else
+ return true
end
-
- # Generate any new resources we need to manage. This is pretty hackish
- # right now, because it only supports purging.
- def generate
- return [] unless self.purge?
- resource_type.instances.
- reject { |r| catalog.resource_refs.include? r.ref }.
- select { |r| check(r) }.
- select { |r| r.class.validproperty?(:ensure) }.
- select { |r| able_to_ensure_absent?(r) }.
- each { |resource|
- @parameters.each do |name, param|
- resource[name] = param.value if param.metaparam?
- end
-
- # Mark that we're purging, so transactions can handle relationships
- # correctly
- resource.purging
- }
- end
-
- def resource_type
- unless defined?(@resource_type)
- unless type = Puppet::Type.type(self[:name])
- raise Puppet::DevError, "Could not find resource type"
- end
- @resource_type = type
+ end
+
+ def able_to_ensure_absent?(resource)
+ resource[:ensure] = :absent
+ rescue ArgumentError, Puppet::Error => detail
+ err "The 'ensure' attribute on #{self[:name]} resources does not accept 'absent' as a value"
+ false
+ end
+
+ # Generate any new resources we need to manage. This is pretty hackish
+ # right now, because it only supports purging.
+ def generate
+ return [] unless self.purge?
+ resource_type.instances.
+ reject { |r| catalog.resource_refs.include? r.ref }.
+ select { |r| check(r) }.
+ select { |r| r.class.validproperty?(:ensure) }.
+ select { |r| able_to_ensure_absent?(r) }.
+ each { |resource|
+ @parameters.each do |name, param|
+ resource[name] = param.value if param.metaparam?
end
- @resource_type
+
+ # Mark that we're purging, so transactions can handle relationships
+ # correctly
+ resource.purging
+ }
+ end
+
+ def resource_type
+ unless defined?(@resource_type)
+ unless type = Puppet::Type.type(self[:name])
+ raise Puppet::DevError, "Could not find resource type"
+ end
+ @resource_type = type
end
+ @resource_type
+ end
- # Make sure we don't purge users below a certain uid, if the check
- # is enabled.
- def user_check(resource)
- return true unless self[:name] == "user"
- return true unless self[:unless_system_user]
+ # Make sure we don't purge users below a certain uid, if the check
+ # is enabled.
+ def user_check(resource)
+ return true unless self[:name] == "user"
+ return true unless self[:unless_system_user]
- resource[:audit] = :uid
- current_values = resource.retrieve_resource
+ resource[:audit] = :uid
+ current_values = resource.retrieve_resource
- return false if system_users.include?(resource[:name])
+ return false if system_users.include?(resource[:name])
- current_values[resource.property(:uid)] > self[:unless_system_user]
- end
+ current_values[resource.property(:uid)] > self[:unless_system_user]
+ end
- def system_users
- %w{root nobody bin noaccess daemon sys}
- end
+ def system_users
+ %w{root nobody bin noaccess daemon sys}
+ end
end
diff --git a/lib/puppet/type/schedule.rb b/lib/puppet/type/schedule.rb
index bcc62ce69..bedf1e536 100755
--- a/lib/puppet/type/schedule.rb
+++ b/lib/puppet/type/schedule.rb
@@ -1,352 +1,352 @@
module Puppet
- newtype(:schedule) do
- @doc = "Defined schedules for Puppet. The important thing to understand
- about how schedules are currently implemented in Puppet is that they
- can only be used to stop a resource from being applied, they never
- guarantee that it is applied.
-
- Every time Puppet applies its configuration, it will collect the
- list of resources whose schedule does not eliminate them from
- running right then, but there is currently no system in place to
- guarantee that a given resource runs at a given time. If you
- specify a very restrictive schedule and Puppet happens to run at a
- time within that schedule, then the resources will get applied;
- otherwise, that work may never get done.
-
- Thus, it behooves you to use wider scheduling (e.g., over a couple of
- hours) combined with periods and repetitions. For instance, if you
- wanted to restrict certain resources to only running once, between
- the hours of two and 4 AM, then you would use this schedule::
-
- schedule { maint:
- range => \"2 - 4\",
- period => daily,
- repeat => 1
- }
-
- With this schedule, the first time that Puppet runs between 2 and 4 AM,
- all resources with this schedule will get applied, but they won't
- get applied again between 2 and 4 because they will have already
- run once that day, and they won't get applied outside that schedule
- because they will be outside the scheduled range.
-
- Puppet automatically creates a schedule for each valid period with the
- same name as that period (e.g., hourly and daily). Additionally,
- a schedule named *puppet* is created and used as the default,
- with the following attributes::
-
- schedule { puppet:
- period => hourly,
- repeat => 2
- }
-
- This will cause resources to be applied every 30 minutes by default.
- "
-
- newparam(:name) do
- desc "The name of the schedule. This name is used to retrieve the
- schedule when assigning it to an object::
-
- schedule { daily:
- period => daily,
- range => [2, 4]
- }
-
- exec { \"/usr/bin/apt-get update\":
- schedule => daily
- }
-
- "
- isnamevar
- end
+ newtype(:schedule) do
+ @doc = "Defined schedules for Puppet. The important thing to understand
+ about how schedules are currently implemented in Puppet is that they
+ can only be used to stop a resource from being applied, they never
+ guarantee that it is applied.
+
+ Every time Puppet applies its configuration, it will collect the
+ list of resources whose schedule does not eliminate them from
+ running right then, but there is currently no system in place to
+ guarantee that a given resource runs at a given time. If you
+ specify a very restrictive schedule and Puppet happens to run at a
+ time within that schedule, then the resources will get applied;
+ otherwise, that work may never get done.
+
+ Thus, it behooves you to use wider scheduling (e.g., over a couple of
+ hours) combined with periods and repetitions. For instance, if you
+ wanted to restrict certain resources to only running once, between
+ the hours of two and 4 AM, then you would use this schedule::
+
+ schedule { maint:
+ range => \"2 - 4\",
+ period => daily,
+ repeat => 1
+ }
+
+ With this schedule, the first time that Puppet runs between 2 and 4 AM,
+ all resources with this schedule will get applied, but they won't
+ get applied again between 2 and 4 because they will have already
+ run once that day, and they won't get applied outside that schedule
+ because they will be outside the scheduled range.
+
+ Puppet automatically creates a schedule for each valid period with the
+ same name as that period (e.g., hourly and daily). Additionally,
+ a schedule named *puppet* is created and used as the default,
+ with the following attributes::
+
+ schedule { puppet:
+ period => hourly,
+ repeat => 2
+ }
+
+ This will cause resources to be applied every 30 minutes by default.
+ "
+
+ newparam(:name) do
+ desc "The name of the schedule. This name is used to retrieve the
+ schedule when assigning it to an object::
+
+ schedule { daily:
+ period => daily,
+ range => [2, 4]
+ }
+
+ exec { \"/usr/bin/apt-get update\":
+ schedule => daily
+ }
+
+ "
+ isnamevar
+ end
- newparam(:range) do
- desc "The earliest and latest that a resource can be applied. This
- is always a range within a 24 hour period, and hours must be
- specified in numbers between 0 and 23, inclusive. Minutes and
- seconds can be provided, using the normal colon as a separator.
- For instance::
-
- schedule { maintenance:
- range => \"1:30 - 4:30\"
- }
-
- This is mostly useful for restricting certain resources to being
- applied in maintenance windows or during off-peak hours."
-
- # This is lame; properties all use arrays as values, but parameters don't.
- # That's going to hurt eventually.
- validate do |values|
- values = [values] unless values.is_a?(Array)
- values.each { |value|
- unless value.is_a?(String) and
- value =~ /\d+(:\d+){0,2}\s*-\s*\d+(:\d+){0,2}/
- self.fail "Invalid range value '#{value}'"
- end
- }
+ newparam(:range) do
+ desc "The earliest and latest that a resource can be applied. This
+ is always a range within a 24 hour period, and hours must be
+ specified in numbers between 0 and 23, inclusive. Minutes and
+ seconds can be provided, using the normal colon as a separator.
+ For instance::
+
+ schedule { maintenance:
+ range => \"1:30 - 4:30\"
+ }
+
+ This is mostly useful for restricting certain resources to being
+ applied in maintenance windows or during off-peak hours."
+
+ # This is lame; properties all use arrays as values, but parameters don't.
+ # That's going to hurt eventually.
+ validate do |values|
+ values = [values] unless values.is_a?(Array)
+ values.each { |value|
+ unless value.is_a?(String) and
+ value =~ /\d+(:\d+){0,2}\s*-\s*\d+(:\d+){0,2}/
+ self.fail "Invalid range value '#{value}'"
+ end
+ }
+ end
+
+ munge do |values|
+ values = [values] unless values.is_a?(Array)
+ ret = []
+
+ values.each { |value|
+ range = []
+ # Split each range value into a hour, minute, second triad
+ value.split(/\s*-\s*/).each { |val|
+ # Add the values as an array.
+ range << val.split(":").collect { |n| n.to_i }
+ }
+
+ self.fail "Invalid range #{value}" if range.length != 2
+
+ # Make sure the hours are valid
+ [range[0][0], range[1][0]].each do |n|
+ raise ArgumentError, "Invalid hour '#{n}'" if n < 0 or n > 23
+ end
+
+ [range[0][1], range[1][1]].each do |n|
+ raise ArgumentError, "Invalid minute '#{n}'" if n and (n < 0 or n > 59)
+ end
+ if range[0][0] > range[1][0]
+ self.fail(("Invalid range #{value}; ") +
+ "ranges cannot span days."
+ )
+ end
+ ret << range
+ }
+
+ # Now our array of arrays
+ ret
+ end
+
+ def match?(previous, now)
+ # The lowest-level array is of the hour, minute, second triad
+ # then it's an array of two of those, to present the limits
+ # then it's array of those ranges
+ @value = [@value] unless @value[0][0].is_a?(Array)
+
+ @value.each do |value|
+ limits = value.collect do |range|
+ ary = [now.year, now.month, now.day, range[0]]
+ if range[1]
+ ary << range[1]
+ else
+ ary << now.min
end
- munge do |values|
- values = [values] unless values.is_a?(Array)
- ret = []
-
- values.each { |value|
- range = []
- # Split each range value into a hour, minute, second triad
- value.split(/\s*-\s*/).each { |val|
- # Add the values as an array.
- range << val.split(":").collect { |n| n.to_i }
- }
-
- self.fail "Invalid range #{value}" if range.length != 2
-
- # Make sure the hours are valid
- [range[0][0], range[1][0]].each do |n|
- raise ArgumentError, "Invalid hour '#{n}'" if n < 0 or n > 23
- end
-
- [range[0][1], range[1][1]].each do |n|
- raise ArgumentError, "Invalid minute '#{n}'" if n and (n < 0 or n > 59)
- end
- if range[0][0] > range[1][0]
- self.fail(("Invalid range #{value}; ") +
- "ranges cannot span days."
- )
- end
- ret << range
- }
-
- # Now our array of arrays
- ret
+ if range[2]
+ ary << range[2]
+ else
+ ary << now.sec
end
- def match?(previous, now)
- # The lowest-level array is of the hour, minute, second triad
- # then it's an array of two of those, to present the limits
- # then it's array of those ranges
- @value = [@value] unless @value[0][0].is_a?(Array)
-
- @value.each do |value|
- limits = value.collect do |range|
- ary = [now.year, now.month, now.day, range[0]]
- if range[1]
- ary << range[1]
- else
- ary << now.min
- end
-
- if range[2]
- ary << range[2]
- else
- ary << now.sec
- end
-
- time = Time.local(*ary)
-
- unless time.hour == range[0]
- self.devfail(
- "Incorrectly converted time: #{time}: #{time.hour} vs #{range[0]}"
- )
- end
-
- time
- end
-
- unless limits[0] < limits[1]
- self.info(
- "Assuming upper limit should be that time the next day"
- )
-
- ary = limits[1].to_a
- ary[3] += 1
- limits[1] = Time.local(*ary)
-
- #self.devfail("Lower limit is above higher limit: %s" %
- # limits.inspect
- #)
- end
-
- #self.info limits.inspect
- #self.notice now
- return now.between?(*limits)
- end
-
- # Else, return false, since our current time isn't between
- # any valid times
- false
+ time = Time.local(*ary)
+
+ unless time.hour == range[0]
+ self.devfail(
+ "Incorrectly converted time: #{time}: #{time.hour} vs #{range[0]}"
+ )
end
- end
- newparam(:periodmatch) do
- desc "Whether periods should be matched by number (e.g., the two times
- are in the same hour) or by distance (e.g., the two times are
- 60 minutes apart)."
+ time
+ end
- newvalues(:number, :distance)
+ unless limits[0] < limits[1]
+ self.info(
+ "Assuming upper limit should be that time the next day"
+ )
- defaultto :distance
- end
+ ary = limits[1].to_a
+ ary[3] += 1
+ limits[1] = Time.local(*ary)
- newparam(:period) do
- desc "The period of repetition for a resource. Choose from among
- a fixed list of *hourly*, *daily*, *weekly*, and *monthly*.
- The default is for a resource to get applied every time that
- Puppet runs, whatever that period is.
-
- Note that the period defines how often a given resource will get
- applied but not when; if you would like to restrict the hours
- that a given resource can be applied (e.g., only at night during
- a maintenance window) then use the ``range`` attribute.
-
- If the provided periods are not sufficient, you can provide a
- value to the *repeat* attribute, which will cause Puppet to
- schedule the affected resources evenly in the period the
- specified number of times. Take this schedule::
-
- schedule { veryoften:
- period => hourly,
- repeat => 6
- }
-
- This can cause Puppet to apply that resource up to every 10 minutes.
-
- At the moment, Puppet cannot guarantee that level of
- repetition; that is, it can run up to every 10 minutes, but
- internal factors might prevent it from actually running that
- often (e.g., long-running Puppet runs will squash conflictingly scheduled runs).
-
- See the ``periodmatch`` attribute for tuning whether to match
- times by their distance apart or by their specific value."
-
- newvalues(:hourly, :daily, :weekly, :monthly, :never)
-
- @@scale = {
- :hourly => 3600,
- :daily => 86400,
- :weekly => 604800,
- :monthly => 2592000
- }
- @@methods = {
- :hourly => :hour,
- :daily => :day,
- :monthly => :month,
- :weekly => proc do |prev, now|
- # Run the resource if the previous day was after this weekday (e.g., prev is wed, current is tue)
- # or if it's been more than a week since we ran
- prev.wday > now.wday or (now - prev) > (24 * 3600 * 7)
- end
- }
-
- def match?(previous, now)
- return false if value == :never
-
- value = self.value
- case @resource[:periodmatch]
- when :number
- method = @@methods[value]
- if method.is_a?(Proc)
- return method.call(previous, now)
- else
- # We negate it, because if they're equal we don't run
- return now.send(method) != previous.send(method)
- end
- when :distance
- scale = @@scale[value]
-
- # If the number of seconds between the two times is greater
- # than the unit of time, we match. We divide the scale
- # by the repeat, so that we'll repeat that often within
- # the scale.
- diff = (now.to_i - previous.to_i)
- comparison = (scale / @resource[:repeat])
-
- return (now.to_i - previous.to_i) >= (scale / @resource[:repeat])
- end
- end
+ #self.devfail("Lower limit is above higher limit: %s" %
+ # limits.inspect
+ #)
+ end
+
+ #self.info limits.inspect
+ #self.notice now
+ return now.between?(*limits)
end
- newparam(:repeat) do
- desc "How often the application gets repeated in a given period.
- Defaults to 1. Must be an integer."
+ # Else, return false, since our current time isn't between
+ # any valid times
+ false
+ end
+ end
- defaultto 1
+ newparam(:periodmatch) do
+ desc "Whether periods should be matched by number (e.g., the two times
+ are in the same hour) or by distance (e.g., the two times are
+ 60 minutes apart)."
- validate do |value|
- unless value.is_a?(Integer) or value =~ /^\d+$/
- raise Puppet::Error,
- "Repeat must be a number"
- end
+ newvalues(:number, :distance)
- # This implicitly assumes that 'periodmatch' is distance -- that
- # is, if there's no value, we assume it's a valid value.
- return unless @resource[:periodmatch]
+ defaultto :distance
+ end
- if value != 1 and @resource[:periodmatch] != :distance
- raise Puppet::Error,
- "Repeat must be 1 unless periodmatch is 'distance', not '#{@resource[:periodmatch]}'"
- end
- end
+ newparam(:period) do
+ desc "The period of repetition for a resource. Choose from among
+ a fixed list of *hourly*, *daily*, *weekly*, and *monthly*.
+ The default is for a resource to get applied every time that
+ Puppet runs, whatever that period is.
+
+ Note that the period defines how often a given resource will get
+ applied but not when; if you would like to restrict the hours
+ that a given resource can be applied (e.g., only at night during
+ a maintenance window) then use the ``range`` attribute.
+
+ If the provided periods are not sufficient, you can provide a
+ value to the *repeat* attribute, which will cause Puppet to
+ schedule the affected resources evenly in the period the
+ specified number of times. Take this schedule::
+
+ schedule { veryoften:
+ period => hourly,
+ repeat => 6
+ }
+
+ This can cause Puppet to apply that resource up to every 10 minutes.
+
+ At the moment, Puppet cannot guarantee that level of
+ repetition; that is, it can run up to every 10 minutes, but
+ internal factors might prevent it from actually running that
+ often (e.g., long-running Puppet runs will squash conflictingly scheduled runs).
+
+ See the ``periodmatch`` attribute for tuning whether to match
+ times by their distance apart or by their specific value."
+
+ newvalues(:hourly, :daily, :weekly, :monthly, :never)
+
+ @@scale = {
+ :hourly => 3600,
+ :daily => 86400,
+ :weekly => 604800,
+ :monthly => 2592000
+ }
+ @@methods = {
+ :hourly => :hour,
+ :daily => :day,
+ :monthly => :month,
+ :weekly => proc do |prev, now|
+ # Run the resource if the previous day was after this weekday (e.g., prev is wed, current is tue)
+ # or if it's been more than a week since we ran
+ prev.wday > now.wday or (now - prev) > (24 * 3600 * 7)
+ end
+ }
+
+ def match?(previous, now)
+ return false if value == :never
+
+ value = self.value
+ case @resource[:periodmatch]
+ when :number
+ method = @@methods[value]
+ if method.is_a?(Proc)
+ return method.call(previous, now)
+ else
+ # We negate it, because if they're equal we don't run
+ return now.send(method) != previous.send(method)
+ end
+ when :distance
+ scale = @@scale[value]
+
+ # If the number of seconds between the two times is greater
+ # than the unit of time, we match. We divide the scale
+ # by the repeat, so that we'll repeat that often within
+ # the scale.
+ diff = (now.to_i - previous.to_i)
+ comparison = (scale / @resource[:repeat])
+
+ return (now.to_i - previous.to_i) >= (scale / @resource[:repeat])
+ end
+ end
+ end
- munge do |value|
- value = Integer(value) unless value.is_a?(Integer)
+ newparam(:repeat) do
+ desc "How often the application gets repeated in a given period.
+ Defaults to 1. Must be an integer."
- value
- end
+ defaultto 1
- def match?(previous, now)
- true
- end
+ validate do |value|
+ unless value.is_a?(Integer) or value =~ /^\d+$/
+ raise Puppet::Error,
+ "Repeat must be a number"
end
- def self.instances
- []
+ # This implicitly assumes that 'periodmatch' is distance -- that
+ # is, if there's no value, we assume it's a valid value.
+ return unless @resource[:periodmatch]
+
+ if value != 1 and @resource[:periodmatch] != :distance
+ raise Puppet::Error,
+ "Repeat must be 1 unless periodmatch is 'distance', not '#{@resource[:periodmatch]}'"
end
+ end
+
+ munge do |value|
+ value = Integer(value) unless value.is_a?(Integer)
+
+ value
+ end
+
+ def match?(previous, now)
+ true
+ end
+ end
- def self.mkdefaultschedules
- result = []
- Puppet.debug "Creating default schedules"
+ def self.instances
+ []
+ end
+
+ def self.mkdefaultschedules
+ result = []
+ Puppet.debug "Creating default schedules"
- result << self.new(
+ result << self.new(
- :name => "puppet",
- :period => :hourly,
+ :name => "puppet",
+ :period => :hourly,
- :repeat => "2"
- )
+ :repeat => "2"
+ )
- # And then one for every period
- @parameters.find { |p| p.name == :period }.value_collection.values.each { |value|
+ # And then one for every period
+ @parameters.find { |p| p.name == :period }.value_collection.values.each { |value|
- result << self.new(
+ result << self.new(
- :name => value.to_s,
+ :name => value.to_s,
- :period => value
- )
- }
+ :period => value
+ )
+ }
- result
- end
-
- def match?(previous = nil, now = nil)
+ result
+ end
- # If we've got a value, then convert it to a Time instance
- previous &&= Time.at(previous)
+ def match?(previous = nil, now = nil)
- now ||= Time.now
+ # If we've got a value, then convert it to a Time instance
+ previous &&= Time.at(previous)
- # Pull them in order
- self.class.allattrs.each { |param|
- if @parameters.include?(param) and
- @parameters[param].respond_to?(:match?)
- return false unless @parameters[param].match?(previous, now)
- end
- }
+ now ||= Time.now
- # If we haven't returned false, then return true; in other words,
- # any provided schedules need to all match
- true
+ # Pull them in order
+ self.class.allattrs.each { |param|
+ if @parameters.include?(param) and
+ @parameters[param].respond_to?(:match?)
+ return false unless @parameters[param].match?(previous, now)
end
+ }
+
+ # If we haven't returned false, then return true; in other words,
+ # any provided schedules need to all match
+ true
end
+ end
end
diff --git a/lib/puppet/type/selboolean.rb b/lib/puppet/type/selboolean.rb
index b1f12cae4..cf873e987 100644
--- a/lib/puppet/type/selboolean.rb
+++ b/lib/puppet/type/selboolean.rb
@@ -3,29 +3,29 @@
#
module Puppet
- newtype(:selboolean) do
- @doc = "Manages SELinux booleans on systems with SELinux support. The supported booleans
- are any of the ones found in /selinux/booleans/."
+ newtype(:selboolean) do
+ @doc = "Manages SELinux booleans on systems with SELinux support. The supported booleans
+ are any of the ones found in /selinux/booleans/."
- newparam(:name) do
- desc "The name of the SELinux boolean to be managed."
- isnamevar
- end
-
- newproperty(:value) do
- desc "Whether the the SELinux boolean should be enabled or disabled."
- newvalue(:on)
- newvalue(:off)
- end
+ newparam(:name) do
+ desc "The name of the SELinux boolean to be managed."
+ isnamevar
+ end
- newparam(:persistent) do
- desc "If set true, SELinux booleans will be written to disk and persist accross reboots.
- The default is ``false``."
+ newproperty(:value) do
+ desc "Whether the the SELinux boolean should be enabled or disabled."
+ newvalue(:on)
+ newvalue(:off)
+ end
- defaultto :false
- newvalues(:true, :false)
- end
+ newparam(:persistent) do
+ desc "If set true, SELinux booleans will be written to disk and persist accross reboots.
+ The default is ``false``."
+ defaultto :false
+ newvalues(:true, :false)
end
+
+ end
end
diff --git a/lib/puppet/type/selmodule.rb b/lib/puppet/type/selmodule.rb
index 90b28b094..240d6e6d1 100644
--- a/lib/puppet/type/selmodule.rb
+++ b/lib/puppet/type/selmodule.rb
@@ -3,52 +3,52 @@
#
Puppet::Type.newtype(:selmodule) do
- @doc = "Manages loading and unloading of SELinux policy modules
- on the system. Requires SELinux support. See man semodule(8)
- for more information on SELinux policy modules."
+ @doc = "Manages loading and unloading of SELinux policy modules
+ on the system. Requires SELinux support. See man semodule(8)
+ for more information on SELinux policy modules."
- ensurable
+ ensurable
- newparam(:name) do
- desc "The name of the SELinux policy to be managed. You should not
- include the customary trailing .pp extension."
- isnamevar
- end
+ newparam(:name) do
+ desc "The name of the SELinux policy to be managed. You should not
+ include the customary trailing .pp extension."
+ isnamevar
+ end
- newparam(:selmoduledir) do
+ newparam(:selmoduledir) do
- desc "The directory to look for the compiled pp module file in.
- Currently defaults to /usr/share/selinux/targeted. If selmodulepath
- is not specified the module will be looked for in this directory in a
- in a file called NAME.pp, where NAME is the value of the name parameter."
+ desc "The directory to look for the compiled pp module file in.
+ Currently defaults to /usr/share/selinux/targeted. If selmodulepath
+ is not specified the module will be looked for in this directory in a
+ in a file called NAME.pp, where NAME is the value of the name parameter."
- defaultto "/usr/share/selinux/targeted"
- end
+ defaultto "/usr/share/selinux/targeted"
+ end
- newparam(:selmodulepath) do
+ newparam(:selmodulepath) do
- desc "The full path to the compiled .pp policy module. You only need to use
- this if the module file is not in the directory pointed at by selmoduledir."
+ desc "The full path to the compiled .pp policy module. You only need to use
+ this if the module file is not in the directory pointed at by selmoduledir."
- end
+ end
- newproperty(:syncversion) do
+ newproperty(:syncversion) do
- desc "If set to ``true``, the policy will be reloaded if the
- version found in the on-disk file differs from the loaded
- version. If set to ``false`` (the default) the the only check
- that will be made is if the policy is loaded at all or not."
+ desc "If set to ``true``, the policy will be reloaded if the
+ version found in the on-disk file differs from the loaded
+ version. If set to ``false`` (the default) the the only check
+ that will be made is if the policy is loaded at all or not."
- newvalue(:true)
- newvalue(:false)
- end
+ newvalue(:true)
+ newvalue(:false)
+ end
- autorequire(:file) do
- if self[:selmodulepath]
- [self[:selmodulepath]]
- else
- ["#{self[:selmoduledir]}/#{self[:name]}.pp"]
- end
+ autorequire(:file) do
+ if self[:selmodulepath]
+ [self[:selmodulepath]]
+ else
+ ["#{self[:selmoduledir]}/#{self[:name]}.pp"]
end
+ end
end
diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb
index e1a2685a1..8f5c6ee37 100644
--- a/lib/puppet/type/service.rb
+++ b/lib/puppet/type/service.rb
@@ -6,180 +6,180 @@
module Puppet
- newtype(:service) do
- @doc = "Manage running services. Service support unfortunately varies
- widely by platform -- some platforms have very little if any
- concept of a running service, and some have a very codified and
- powerful concept. Puppet's service support will generally be able
- to make up for any inherent shortcomings (e.g., if there is no
- 'status' command, then Puppet will look in the process table for a
- command matching the service name), but the more information you
- can provide the better behaviour you will get. Or, you can just
- use a platform that has very good service support.
-
- Note that if a ``service`` receives an event from another resource,
- the service will get restarted. The actual command to restart the
- service depends on the platform. You can provide a special command
- for restarting with the ``restart`` attribute."
-
- feature :refreshable, "The provider can restart the service.",
- :methods => [:restart]
-
- feature :enableable, "The provider can enable and disable the service",
- :methods => [:disable, :enable, :enabled?]
-
- feature :controllable, "The provider uses a control variable."
-
- newproperty(:enable, :required_features => :enableable) do
- desc "Whether a service should be enabled to start at boot.
- This property behaves quite differently depending on the platform;
- wherever possible, it relies on local tools to enable or disable
- a given service."
-
- newvalue(:true, :event => :service_enabled) do
- provider.enable
- end
-
- newvalue(:false, :event => :service_disabled) do
- provider.disable
- end
-
- def retrieve
- provider.enabled?
- end
- end
-
- # Handle whether the service should actually be running right now.
- newproperty(:ensure) do
- desc "Whether a service should be running."
+ newtype(:service) do
+ @doc = "Manage running services. Service support unfortunately varies
+ widely by platform -- some platforms have very little if any
+ concept of a running service, and some have a very codified and
+ powerful concept. Puppet's service support will generally be able
+ to make up for any inherent shortcomings (e.g., if there is no
+ 'status' command, then Puppet will look in the process table for a
+ command matching the service name), but the more information you
+ can provide the better behaviour you will get. Or, you can just
+ use a platform that has very good service support.
+
+ Note that if a ``service`` receives an event from another resource,
+ the service will get restarted. The actual command to restart the
+ service depends on the platform. You can provide a special command
+ for restarting with the ``restart`` attribute."
+
+ feature :refreshable, "The provider can restart the service.",
+ :methods => [:restart]
+
+ feature :enableable, "The provider can enable and disable the service",
+ :methods => [:disable, :enable, :enabled?]
+
+ feature :controllable, "The provider uses a control variable."
+
+ newproperty(:enable, :required_features => :enableable) do
+ desc "Whether a service should be enabled to start at boot.
+ This property behaves quite differently depending on the platform;
+ wherever possible, it relies on local tools to enable or disable
+ a given service."
+
+ newvalue(:true, :event => :service_enabled) do
+ provider.enable
+ end
+
+ newvalue(:false, :event => :service_disabled) do
+ provider.disable
+ end
+
+ def retrieve
+ provider.enabled?
+ end
+ end
- newvalue(:stopped, :event => :service_stopped) do
- provider.stop
- end
+ # Handle whether the service should actually be running right now.
+ newproperty(:ensure) do
+ desc "Whether a service should be running."
- newvalue(:running, :event => :service_started) do
- provider.start
- end
+ newvalue(:stopped, :event => :service_stopped) do
+ provider.stop
+ end
- aliasvalue(:false, :stopped)
- aliasvalue(:true, :running)
+ newvalue(:running, :event => :service_started) do
+ provider.start
+ end
- def retrieve
- provider.status
- end
+ aliasvalue(:false, :stopped)
+ aliasvalue(:true, :running)
- def sync
- event = super()
+ def retrieve
+ provider.status
+ end
- if property = @resource.property(:enable)
- val = property.retrieve
- property.sync unless property.insync?(val)
- end
+ def sync
+ event = super()
- event
- end
+ if property = @resource.property(:enable)
+ val = property.retrieve
+ property.sync unless property.insync?(val)
end
- newparam(:binary) do
- desc "The path to the daemon. This is only used for
- systems that do not support init scripts. This binary will be
- used to start the service if no ``start`` parameter is
- provided."
- end
+ event
+ end
+ end
- newparam(:hasstatus) do
- desc "Declare the the service's init script has a
- functional status command. Based on testing, it was found
- that a large number of init scripts on different platforms do
- not support any kind of status command; thus, you must specify
- manually whether the service you are running has such a
- command (or you can specify a specific command using the
- ``status`` parameter).
+ newparam(:binary) do
+ desc "The path to the daemon. This is only used for
+ systems that do not support init scripts. This binary will be
+ used to start the service if no ``start`` parameter is
+ provided."
+ end
- If you do not specify anything, then the service name will be
- looked for in the process table."
+ newparam(:hasstatus) do
+ desc "Declare the the service's init script has a
+ functional status command. Based on testing, it was found
+ that a large number of init scripts on different platforms do
+ not support any kind of status command; thus, you must specify
+ manually whether the service you are running has such a
+ command (or you can specify a specific command using the
+ ``status`` parameter).
- newvalues(:true, :false)
- end
- newparam(:name) do
- desc "The name of the service to run. This name is used to find
- the service in whatever service subsystem it is in."
- isnamevar
- end
+ If you do not specify anything, then the service name will be
+ looked for in the process table."
- newparam(:path) do
- desc "The search path for finding init scripts. Multiple values should
- be separated by colons or provided as an array."
+ newvalues(:true, :false)
+ end
+ newparam(:name) do
+ desc "The name of the service to run. This name is used to find
+ the service in whatever service subsystem it is in."
+ isnamevar
+ end
- munge do |value|
- value = [value] unless value.is_a?(Array)
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- # It affects stand-alone blocks, too.
- paths = value.flatten.collect { |p| x = p.split(":") }.flatten
- end
+ newparam(:path) do
+ desc "The search path for finding init scripts. Multiple values should
+ be separated by colons or provided as an array."
- defaultto { provider.class.defpath if provider.class.respond_to?(:defpath) }
- end
- newparam(:pattern) do
- desc "The pattern to search for in the process table.
- This is used for stopping services on platforms that do not
- support init scripts, and is also used for determining service
- status on those service whose init scripts do not include a status
- command.
+ munge do |value|
+ value = [value] unless value.is_a?(Array)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ # It affects stand-alone blocks, too.
+ paths = value.flatten.collect { |p| x = p.split(":") }.flatten
+ end
- If this is left unspecified and is needed to check the status
- of a service, then the service name will be used instead.
+ defaultto { provider.class.defpath if provider.class.respond_to?(:defpath) }
+ end
+ newparam(:pattern) do
+ desc "The pattern to search for in the process table.
+ This is used for stopping services on platforms that do not
+ support init scripts, and is also used for determining service
+ status on those service whose init scripts do not include a status
+ command.
- The pattern can be a simple string or any legal Ruby pattern."
+ If this is left unspecified and is needed to check the status
+ of a service, then the service name will be used instead.
- defaultto { @resource[:binary] || @resource[:name] }
- end
- newparam(:restart) do
- desc "Specify a *restart* command manually. If left
- unspecified, the service will be stopped and then started."
- end
- newparam(:start) do
- desc "Specify a *start* command manually. Most service subsystems
- support a ``start`` command, so this will not need to be
- specified."
- end
- newparam(:status) do
- desc "Specify a *status* command manually. If left
- unspecified, the status method will be determined
- automatically, usually by looking for the service in the
- process table."
- end
+ The pattern can be a simple string or any legal Ruby pattern."
- newparam(:stop) do
- desc "Specify a *stop* command manually."
- end
+ defaultto { @resource[:binary] || @resource[:name] }
+ end
+ newparam(:restart) do
+ desc "Specify a *restart* command manually. If left
+ unspecified, the service will be stopped and then started."
+ end
+ newparam(:start) do
+ desc "Specify a *start* command manually. Most service subsystems
+ support a ``start`` command, so this will not need to be
+ specified."
+ end
+ newparam(:status) do
+ desc "Specify a *status* command manually. If left
+ unspecified, the status method will be determined
+ automatically, usually by looking for the service in the
+ process table."
+ end
- newparam(:control) do
- desc "The control variable used to manage services (originally for HP-UX).
- Defaults to the upcased service name plus ``START`` replacing dots with
- underscores, for those providers that support the ``controllable`` feature."
- defaultto { resource.name.gsub(".","_").upcase + "_START" if resource.provider.controllable? }
- end
+ newparam(:stop) do
+ desc "Specify a *stop* command manually."
+ end
- newparam :hasrestart do
- desc "Specify that an init script has a ``restart`` option. Otherwise,
- the init script's ``stop`` and ``start`` methods are used."
- newvalues(:true, :false)
- end
+ newparam(:control) do
+ desc "The control variable used to manage services (originally for HP-UX).
+ Defaults to the upcased service name plus ``START`` replacing dots with
+ underscores, for those providers that support the ``controllable`` feature."
+ defaultto { resource.name.gsub(".","_").upcase + "_START" if resource.provider.controllable? }
+ end
- newparam(:manifest) do
- desc "Specify a command to config a service, or a path to a manifest to do so."
- end
+ newparam :hasrestart do
+ desc "Specify that an init script has a ``restart`` option. Otherwise,
+ the init script's ``stop`` and ``start`` methods are used."
+ newvalues(:true, :false)
+ end
- # Basically just a synonym for restarting. Used to respond
- # to events.
- def refresh
- # Only restart if we're actually running
- if (@parameters[:ensure] || newattr(:ensure)).retrieve == :running
- provider.restart
- else
- debug "Skipping restart; service is not running"
- end
- end
+ newparam(:manifest) do
+ desc "Specify a command to config a service, or a path to a manifest to do so."
+ end
+
+ # Basically just a synonym for restarting. Used to respond
+ # to events.
+ def refresh
+ # Only restart if we're actually running
+ if (@parameters[:ensure] || newattr(:ensure)).retrieve == :running
+ provider.restart
+ else
+ debug "Skipping restart; service is not running"
+ end
end
+ end
end
diff --git a/lib/puppet/type/ssh_authorized_key.rb b/lib/puppet/type/ssh_authorized_key.rb
index 306af8973..2bfa87b0f 100644
--- a/lib/puppet/type/ssh_authorized_key.rb
+++ b/lib/puppet/type/ssh_authorized_key.rb
@@ -1,99 +1,99 @@
module Puppet
- newtype(:ssh_authorized_key) do
- @doc = "Manages SSH authorized keys. Currently only type 2 keys are
- supported."
+ newtype(:ssh_authorized_key) do
+ @doc = "Manages SSH authorized keys. Currently only type 2 keys are
+ supported."
- ensurable
+ ensurable
- newparam(:name) do
- desc "The SSH key comment. This attribute is currently used as a
- system-wide primary key and therefore has to be unique."
+ newparam(:name) do
+ desc "The SSH key comment. This attribute is currently used as a
+ system-wide primary key and therefore has to be unique."
- isnamevar
- end
+ isnamevar
+ end
- newproperty(:type) do
- desc "The encryption type used: ssh-dss or ssh-rsa."
+ newproperty(:type) do
+ desc "The encryption type used: ssh-dss or ssh-rsa."
- newvalue("ssh-dss")
- newvalue("ssh-rsa")
+ newvalue("ssh-dss")
+ newvalue("ssh-rsa")
- aliasvalue(:dsa, "ssh-dss")
- aliasvalue(:rsa, "ssh-rsa")
- end
-
- newproperty(:key) do
- desc "The key itself; generally a long string of hex digits."
- end
+ aliasvalue(:dsa, "ssh-dss")
+ aliasvalue(:rsa, "ssh-rsa")
+ end
- newproperty(:user) do
- desc "The user account in which the SSH key should be installed.
- The resource will automatically depend on this user."
- end
+ newproperty(:key) do
+ desc "The key itself; generally a long string of hex digits."
+ end
- newproperty(:target) do
- desc "The absolute filename in which to store the SSH key. This
- property is optional and should only be used in cases where keys
- are stored in a non-standard location (ie not in
- ~user/.ssh/authorized_keys)."
+ newproperty(:user) do
+ desc "The user account in which the SSH key should be installed.
+ The resource will automatically depend on this user."
+ end
- defaultto :absent
+ newproperty(:target) do
+ desc "The absolute filename in which to store the SSH key. This
+ property is optional and should only be used in cases where keys
+ are stored in a non-standard location (ie not in
+ ~user/.ssh/authorized_keys)."
- def should
- return super if defined?(@should) and @should[0] != :absent
+ defaultto :absent
- return nil unless user = resource[:user]
+ def should
+ return super if defined?(@should) and @should[0] != :absent
- begin
- return File.expand_path("~#{user}/.ssh/authorized_keys")
- rescue
- Puppet.debug "The required user is not yet present on the system"
- return nil
- end
- end
+ return nil unless user = resource[:user]
- def insync?(is)
- is == should
- end
+ begin
+ return File.expand_path("~#{user}/.ssh/authorized_keys")
+ rescue
+ Puppet.debug "The required user is not yet present on the system"
+ return nil
end
+ end
- newproperty(:options, :array_matching => :all) do
- desc "Key options, see sshd(8) for possible values. Multiple values
- should be specified as an array."
-
- defaultto do :absent end
-
- def is_to_s(value)
- if value == :absent or value.include?(:absent)
- super
- else
- value.join(",")
- end
- end
-
- def should_to_s(value)
- if value == :absent or value.include?(:absent)
- super
- else
- value.join(",")
- end
- end
+ def insync?(is)
+ is == should
+ end
+ end
+
+ newproperty(:options, :array_matching => :all) do
+ desc "Key options, see sshd(8) for possible values. Multiple values
+ should be specified as an array."
+
+ defaultto do :absent end
+
+ def is_to_s(value)
+ if value == :absent or value.include?(:absent)
+ super
+ else
+ value.join(",")
end
+ end
- autorequire(:user) do
- should(:user) if should(:user)
+ def should_to_s(value)
+ if value == :absent or value.include?(:absent)
+ super
+ else
+ value.join(",")
end
+ end
+ end
+
+ autorequire(:user) do
+ should(:user) if should(:user)
+ end
- validate do
- # Go ahead if target attribute is defined
- return if @parameters[:target].shouldorig[0] != :absent
+ validate do
+ # Go ahead if target attribute is defined
+ return if @parameters[:target].shouldorig[0] != :absent
- # Go ahead if user attribute is defined
- return if @parameters.include?(:user)
+ # Go ahead if user attribute is defined
+ return if @parameters.include?(:user)
- # If neither target nor user is defined, this is an error
- raise Puppet::Error, "Attribute 'user' or 'target' is mandatory"
- end
+ # If neither target nor user is defined, this is an error
+ raise Puppet::Error, "Attribute 'user' or 'target' is mandatory"
end
+ end
end
diff --git a/lib/puppet/type/sshkey.rb b/lib/puppet/type/sshkey.rb
index 6051a52d2..e1adc7173 100755
--- a/lib/puppet/type/sshkey.rb
+++ b/lib/puppet/type/sshkey.rb
@@ -1,70 +1,70 @@
module Puppet
- newtype(:sshkey) do
- @doc = "Installs and manages ssh host keys. At this point, this type
- only knows how to install keys into /etc/ssh/ssh_known_hosts, and
- it cannot manage user authorized keys yet."
+ newtype(:sshkey) do
+ @doc = "Installs and manages ssh host keys. At this point, this type
+ only knows how to install keys into /etc/ssh/ssh_known_hosts, and
+ it cannot manage user authorized keys yet."
- ensurable
+ ensurable
- newproperty(:type) do
- desc "The encryption type used. Probably ssh-dss or ssh-rsa."
+ newproperty(:type) do
+ desc "The encryption type used. Probably ssh-dss or ssh-rsa."
- newvalue("ssh-dss")
- newvalue("ssh-rsa")
- aliasvalue(:dsa, "ssh-dss")
- aliasvalue(:rsa, "ssh-rsa")
- end
+ newvalue("ssh-dss")
+ newvalue("ssh-rsa")
+ aliasvalue(:dsa, "ssh-dss")
+ aliasvalue(:rsa, "ssh-rsa")
+ end
- newproperty(:key) do
- desc "The key itself; generally a long string of hex digits."
- end
+ newproperty(:key) do
+ desc "The key itself; generally a long string of hex digits."
+ end
- # FIXME This should automagically check for aliases to the hosts, just
- # to see if we can automatically glean any aliases.
- newproperty(:host_aliases) do
- desc 'Any aliases the host might have. Multiple values must be
- specified as an array. Note that this property is not the same as
- the "alias" metaparam; use this property to add aliases to a host
- on disk, and "alias" to aliases for use in your Puppet scripts.'
+ # FIXME This should automagically check for aliases to the hosts, just
+ # to see if we can automatically glean any aliases.
+ newproperty(:host_aliases) do
+ desc 'Any aliases the host might have. Multiple values must be
+ specified as an array. Note that this property is not the same as
+ the "alias" metaparam; use this property to add aliases to a host
+ on disk, and "alias" to aliases for use in your Puppet scripts.'
- attr_accessor :meta
+ attr_accessor :meta
- def insync?(is)
- is == @should
- end
- # We actually want to return the whole array here, not just the first
- # value.
- def should
- defined?(@should) ? @should : nil
- end
+ def insync?(is)
+ is == @should
+ end
+ # We actually want to return the whole array here, not just the first
+ # value.
+ def should
+ defined?(@should) ? @should : nil
+ end
- validate do |value|
- if value =~ /\s/
- raise Puppet::Error, "Aliases cannot include whitespace"
- end
- if value =~ /,/
- raise Puppet::Error, "Aliases cannot include whitespace"
- end
- end
+ validate do |value|
+ if value =~ /\s/
+ raise Puppet::Error, "Aliases cannot include whitespace"
end
+ if value =~ /,/
+ raise Puppet::Error, "Aliases cannot include whitespace"
+ end
+ end
+ end
- newparam(:name) do
- desc "The host name that the key is associated with."
+ newparam(:name) do
+ desc "The host name that the key is associated with."
- isnamevar
- end
+ isnamevar
+ end
- newproperty(:target) do
- desc "The file in which to store the ssh key. Only used by
- the ``parsed`` provider."
+ newproperty(:target) do
+ desc "The file in which to store the ssh key. Only used by
+ the ``parsed`` provider."
- defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
- @resource.class.defaultprovider.default_target
- else
- nil
- end
- }
+ defaultto { if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
+ @resource.class.defaultprovider.default_target
+ else
+ nil
end
+ }
end
+ end
end
diff --git a/lib/puppet/type/stage.rb b/lib/puppet/type/stage.rb
index c11acdcd8..d22cd7b70 100644
--- a/lib/puppet/type/stage.rb
+++ b/lib/puppet/type/stage.rb
@@ -1,18 +1,18 @@
Puppet::Type.newtype(:stage) do
- desc "A resource type for specifying run stages. The actual stage should
- be specified on resources::
- class { foo: stage => pre }
+ desc "A resource type for specifying run stages. The actual stage should
+ be specified on resources::
+ class { foo: stage => pre }
- And you must manually control stage order::
+ And you must manually control stage order::
- stage { pre: before => Stage[main] }
+ stage { pre: before => Stage[main] }
- You automatically get a 'main' stage created, and by default all resources
- get inserted into that stage.
+ You automatically get a 'main' stage created, and by default all resources
+ get inserted into that stage.
- You can only set stages on class resources, not normal builtin resources."
+ You can only set stages on class resources, not normal builtin resources."
- newparam :name do
- desc "The name of the stage. This will be used as the 'stage' for each resource."
- end
+ newparam :name do
+ desc "The name of the stage. This will be used as the 'stage' for each resource."
+ end
end
diff --git a/lib/puppet/type/tidy.rb b/lib/puppet/type/tidy.rb
index 6923b455c..a6605211e 100755
--- a/lib/puppet/type/tidy.rb
+++ b/lib/puppet/type/tidy.rb
@@ -1,330 +1,330 @@
Puppet::Type.newtype(:tidy) do
- require 'puppet/file_serving/fileset'
-
- @doc = "Remove unwanted files based on specific criteria. Multiple
- criteria are OR'd together, so a file that is too large but is not
- old enough will still get tidied.
-
- If you don't specify either 'age' or 'size', then all files will
- be removed.
-
- This resource type works by generating a file resource for every file
- that should be deleted and then letting that resource perform the
- actual deletion.
- "
-
- newparam(:path) do
- desc "The path to the file or directory to manage. Must be fully
- qualified."
- isnamevar
+ require 'puppet/file_serving/fileset'
+
+ @doc = "Remove unwanted files based on specific criteria. Multiple
+ criteria are OR'd together, so a file that is too large but is not
+ old enough will still get tidied.
+
+ If you don't specify either 'age' or 'size', then all files will
+ be removed.
+
+ This resource type works by generating a file resource for every file
+ that should be deleted and then letting that resource perform the
+ actual deletion.
+ "
+
+ newparam(:path) do
+ desc "The path to the file or directory to manage. Must be fully
+ qualified."
+ isnamevar
+ end
+
+ newparam(:recurse) do
+ desc "If target is a directory, recursively descend
+ into the directory looking for files to tidy."
+
+ newvalues(:true, :false, :inf, /^[0-9]+$/)
+
+ # Replace the validation so that we allow numbers in
+ # addition to string representations of them.
+ validate { |arg| }
+ munge do |value|
+ newval = super(value)
+ case newval
+ when :true, :inf; true
+ when :false; false
+ when Integer, Fixnum, Bignum; value
+ when /^\d+$/; Integer(value)
+ else
+ raise ArgumentError, "Invalid recurse value #{value.inspect}"
+ end
+ end
+ end
+
+ newparam(:matches) do
+ desc "One or more (shell type) file glob patterns, which restrict
+ the list of files to be tidied to those whose basenames match
+ at least one of the patterns specified. Multiple patterns can
+ be specified using an array.
+
+ Example::
+
+ tidy { \"/tmp\":
+ age => \"1w\",
+ recurse => 1,
+ matches => [ \"[0-9]pub*.tmp\", \"*.temp\", \"tmpfile?\" ]
+ }
+
+ This removes files from \/tmp if they are one week old or older,
+ are not in a subdirectory and match one of the shell globs given.
+
+ Note that the patterns are matched against the basename of each
+ file -- that is, your glob patterns should not have any '/'
+ characters in them, since you are only specifying against the last
+ bit of the file.
+
+ Finally, note that you must now specify a non-zero/non-false value
+ for recurse if matches is used, as matches only apply to files found
+ by recursion (there's no reason to use static patterns match against
+ a statically determined path). Requiering explicit recursion clears
+ up a common source of confusion."
+
+ # Make sure we convert to an array.
+ munge do |value|
+ fail "Tidy can't use matches with recurse 0, false, or undef" if "#{@resource[:recurse]}" =~ /^(0|false|)$/
+ [value].flatten
end
- newparam(:recurse) do
- desc "If target is a directory, recursively descend
- into the directory looking for files to tidy."
-
- newvalues(:true, :false, :inf, /^[0-9]+$/)
-
- # Replace the validation so that we allow numbers in
- # addition to string representations of them.
- validate { |arg| }
- munge do |value|
- newval = super(value)
- case newval
- when :true, :inf; true
- when :false; false
- when Integer, Fixnum, Bignum; value
- when /^\d+$/; Integer(value)
- else
- raise ArgumentError, "Invalid recurse value #{value.inspect}"
- end
- end
+ # Does a given path match our glob patterns, if any? Return true
+ # if no patterns have been provided.
+ def tidy?(path, stat)
+ basename = File.basename(path)
+ flags = File::FNM_DOTMATCH | File::FNM_PATHNAME
+ return(value.find {|pattern| File.fnmatch(pattern, basename, flags) } ? true : false)
+ end
+ end
+
+ newparam(:backup) do
+ desc "Whether tidied files should be backed up. Any values are passed
+ directly to the file resources used for actual file deletion, so use
+ its backup documentation to determine valid values."
+ end
+
+ newparam(:age) do
+ desc "Tidy files whose age is equal to or greater than
+ the specified time. You can choose seconds, minutes,
+ hours, days, or weeks by specifying the first letter of any
+ of those words (e.g., '1w').
+
+ Specifying 0 will remove all files."
+
+ @@ageconvertors = {
+ :s => 1,
+ :m => 60
+ }
+
+ @@ageconvertors[:h] = @@ageconvertors[:m] * 60
+ @@ageconvertors[:d] = @@ageconvertors[:h] * 24
+ @@ageconvertors[:w] = @@ageconvertors[:d] * 7
+
+ def convert(unit, multi)
+ if num = @@ageconvertors[unit]
+ return num * multi
+ else
+ self.fail "Invalid age unit '#{unit}'"
+ end
end
- newparam(:matches) do
- desc "One or more (shell type) file glob patterns, which restrict
- the list of files to be tidied to those whose basenames match
- at least one of the patterns specified. Multiple patterns can
- be specified using an array.
-
- Example::
-
- tidy { \"/tmp\":
- age => \"1w\",
- recurse => 1,
- matches => [ \"[0-9]pub*.tmp\", \"*.temp\", \"tmpfile?\" ]
- }
-
- This removes files from \/tmp if they are one week old or older,
- are not in a subdirectory and match one of the shell globs given.
-
- Note that the patterns are matched against the basename of each
- file -- that is, your glob patterns should not have any '/'
- characters in them, since you are only specifying against the last
- bit of the file.
-
- Finally, note that you must now specify a non-zero/non-false value
- for recurse if matches is used, as matches only apply to files found
- by recursion (there's no reason to use static patterns match against
- a statically determined path). Requiering explicit recursion clears
- up a common source of confusion."
-
- # Make sure we convert to an array.
- munge do |value|
- fail "Tidy can't use matches with recurse 0, false, or undef" if "#{@resource[:recurse]}" =~ /^(0|false|)$/
- [value].flatten
- end
-
- # Does a given path match our glob patterns, if any? Return true
- # if no patterns have been provided.
- def tidy?(path, stat)
- basename = File.basename(path)
- flags = File::FNM_DOTMATCH | File::FNM_PATHNAME
- return(value.find {|pattern| File.fnmatch(pattern, basename, flags) } ? true : false)
- end
+ def tidy?(path, stat)
+ # If the file's older than we allow, we should get rid of it.
+ (Time.now.to_i - stat.send(resource[:type]).to_i) > value
end
- newparam(:backup) do
- desc "Whether tidied files should be backed up. Any values are passed
- directly to the file resources used for actual file deletion, so use
- its backup documentation to determine valid values."
+ munge do |age|
+ unit = multi = nil
+ case age
+ when /^([0-9]+)(\w)\w*$/
+ multi = Integer($1)
+ unit = $2.downcase.intern
+ when /^([0-9]+)$/
+ multi = Integer($1)
+ unit = :d
+ else
+ self.fail "Invalid tidy age #{age}"
+ end
+
+ convert(unit, multi)
+ end
+ end
+
+ newparam(:size) do
+ desc "Tidy files whose size is equal to or greater than
+ the specified size. Unqualified values are in kilobytes, but
+ *b*, *k*, and *m* can be appended to specify *bytes*, *kilobytes*,
+ and *megabytes*, respectively. Only the first character is
+ significant, so the full word can also be used."
+
+ @@sizeconvertors = {
+ :b => 0,
+ :k => 1,
+ :m => 2,
+ :g => 3
+ }
+
+ def convert(unit, multi)
+ if num = @@sizeconvertors[unit]
+ result = multi
+ num.times do result *= 1024 end
+ return result
+ else
+ self.fail "Invalid size unit '#{unit}'"
+ end
end
- newparam(:age) do
- desc "Tidy files whose age is equal to or greater than
- the specified time. You can choose seconds, minutes,
- hours, days, or weeks by specifying the first letter of any
- of those words (e.g., '1w').
-
- Specifying 0 will remove all files."
-
- @@ageconvertors = {
- :s => 1,
- :m => 60
- }
-
- @@ageconvertors[:h] = @@ageconvertors[:m] * 60
- @@ageconvertors[:d] = @@ageconvertors[:h] * 24
- @@ageconvertors[:w] = @@ageconvertors[:d] * 7
-
- def convert(unit, multi)
- if num = @@ageconvertors[unit]
- return num * multi
- else
- self.fail "Invalid age unit '#{unit}'"
- end
- end
-
- def tidy?(path, stat)
- # If the file's older than we allow, we should get rid of it.
- (Time.now.to_i - stat.send(resource[:type]).to_i) > value
- end
-
- munge do |age|
- unit = multi = nil
- case age
- when /^([0-9]+)(\w)\w*$/
- multi = Integer($1)
- unit = $2.downcase.intern
- when /^([0-9]+)$/
- multi = Integer($1)
- unit = :d
- else
- self.fail "Invalid tidy age #{age}"
- end
-
- convert(unit, multi)
- end
+ def tidy?(path, stat)
+ stat.size >= value
end
- newparam(:size) do
- desc "Tidy files whose size is equal to or greater than
- the specified size. Unqualified values are in kilobytes, but
- *b*, *k*, and *m* can be appended to specify *bytes*, *kilobytes*,
- and *megabytes*, respectively. Only the first character is
- significant, so the full word can also be used."
-
- @@sizeconvertors = {
- :b => 0,
- :k => 1,
- :m => 2,
- :g => 3
- }
-
- def convert(unit, multi)
- if num = @@sizeconvertors[unit]
- result = multi
- num.times do result *= 1024 end
- return result
- else
- self.fail "Invalid size unit '#{unit}'"
- end
- end
-
- def tidy?(path, stat)
- stat.size >= value
- end
-
- munge do |size|
- case size
- when /^([0-9]+)(\w)\w*$/
- multi = Integer($1)
- unit = $2.downcase.intern
- when /^([0-9]+)$/
- multi = Integer($1)
- unit = :k
- else
- self.fail "Invalid tidy size #{age}"
- end
-
- convert(unit, multi)
- end
+ munge do |size|
+ case size
+ when /^([0-9]+)(\w)\w*$/
+ multi = Integer($1)
+ unit = $2.downcase.intern
+ when /^([0-9]+)$/
+ multi = Integer($1)
+ unit = :k
+ else
+ self.fail "Invalid tidy size #{age}"
+ end
+
+ convert(unit, multi)
end
+ end
- newparam(:type) do
- desc "Set the mechanism for determining age."
+ newparam(:type) do
+ desc "Set the mechanism for determining age."
- newvalues(:atime, :mtime, :ctime)
+ newvalues(:atime, :mtime, :ctime)
- defaultto :atime
- end
+ defaultto :atime
+ end
- newparam(:rmdirs, :boolean => true) do
- desc "Tidy directories in addition to files; that is, remove
- directories whose age is older than the specified criteria.
- This will only remove empty directories, so all contained
- files must also be tidied before a directory gets removed."
+ newparam(:rmdirs, :boolean => true) do
+ desc "Tidy directories in addition to files; that is, remove
+ directories whose age is older than the specified criteria.
+ This will only remove empty directories, so all contained
+ files must also be tidied before a directory gets removed."
- newvalues :true, :false
- end
+ newvalues :true, :false
+ end
- # Erase PFile's validate method
- validate do
- end
+ # Erase PFile's validate method
+ validate do
+ end
- def self.instances
- []
- end
+ def self.instances
+ []
+ end
- @depthfirst = true
+ @depthfirst = true
- def initialize(hash)
- super
+ def initialize(hash)
+ super
- # only allow backing up into filebuckets
- self[:backup] = false unless self[:backup].is_a? Puppet::FileBucket::Dipper
- end
+ # only allow backing up into filebuckets
+ self[:backup] = false unless self[:backup].is_a? Puppet::FileBucket::Dipper
+ end
- # Make a file resource to remove a given file.
- def mkfile(path)
- # Force deletion, so directories actually get deleted.
- Puppet::Type.type(:file).new :path => path, :backup => self[:backup], :ensure => :absent, :force => true
- end
+ # Make a file resource to remove a given file.
+ def mkfile(path)
+ # Force deletion, so directories actually get deleted.
+ Puppet::Type.type(:file).new :path => path, :backup => self[:backup], :ensure => :absent, :force => true
+ end
- def retrieve
- # Our ensure property knows how to retrieve everything for us.
- if obj = @parameters[:ensure]
- return obj.retrieve
- else
- return {}
- end
+ def retrieve
+ # Our ensure property knows how to retrieve everything for us.
+ if obj = @parameters[:ensure]
+ return obj.retrieve
+ else
+ return {}
end
+ end
- # Hack things a bit so we only ever check the ensure property.
- def properties
- []
- end
+ # Hack things a bit so we only ever check the ensure property.
+ def properties
+ []
+ end
- def eval_generate
- []
- end
+ def eval_generate
+ []
+ end
- def generate
- return [] unless stat(self[:path])
-
- case self[:recurse]
- when Integer, Fixnum, Bignum, /^\d+$/
- parameter = { :recurse => true, :recurselimit => self[:recurse] }
- when true, :true, :inf
- parameter = { :recurse => true }
- end
-
- if parameter
- files = Puppet::FileServing::Fileset.new(self[:path], parameter).files.collect do |f|
- f == "." ? self[:path] : File.join(self[:path], f)
- end
- else
- files = [self[:path]]
- end
- result = files.find_all { |path| tidy?(path) }.collect { |path| mkfile(path) }.each { |file| notice "Tidying #{file.ref}" }.sort { |a,b| b[:path] <=> a[:path] }
-
- # No need to worry about relationships if we don't have rmdirs; there won't be
- # any directories.
- return result unless rmdirs?
-
- # Now make sure that all directories require the files they contain, if all are available,
- # so that a directory is emptied before we try to remove it.
- files_by_name = result.inject({}) { |hash, file| hash[file[:path]] = file; hash }
-
- files_by_name.keys.sort { |a,b| b <=> b }.each do |path|
- dir = File.dirname(path)
- next unless resource = files_by_name[dir]
- if resource[:require]
- resource[:require] << Puppet::Resource.new(:file, path)
- else
- resource[:require] = [Puppet::Resource.new(:file, path)]
- end
- end
-
- result
+ def generate
+ return [] unless stat(self[:path])
+
+ case self[:recurse]
+ when Integer, Fixnum, Bignum, /^\d+$/
+ parameter = { :recurse => true, :recurselimit => self[:recurse] }
+ when true, :true, :inf
+ parameter = { :recurse => true }
end
- # Does a given path match our glob patterns, if any? Return true
- # if no patterns have been provided.
- def matches?(path)
- return true unless self[:matches]
-
- basename = File.basename(path)
- flags = File::FNM_DOTMATCH | File::FNM_PATHNAME
- if self[:matches].find {|pattern| File.fnmatch(pattern, basename, flags) }
- return true
- else
- debug "No specified patterns match #{path}, not tidying"
- return false
- end
+ if parameter
+ files = Puppet::FileServing::Fileset.new(self[:path], parameter).files.collect do |f|
+ f == "." ? self[:path] : File.join(self[:path], f)
+ end
+ else
+ files = [self[:path]]
+ end
+ result = files.find_all { |path| tidy?(path) }.collect { |path| mkfile(path) }.each { |file| notice "Tidying #{file.ref}" }.sort { |a,b| b[:path] <=> a[:path] }
+
+ # No need to worry about relationships if we don't have rmdirs; there won't be
+ # any directories.
+ return result unless rmdirs?
+
+ # Now make sure that all directories require the files they contain, if all are available,
+ # so that a directory is emptied before we try to remove it.
+ files_by_name = result.inject({}) { |hash, file| hash[file[:path]] = file; hash }
+
+ files_by_name.keys.sort { |a,b| b <=> b }.each do |path|
+ dir = File.dirname(path)
+ next unless resource = files_by_name[dir]
+ if resource[:require]
+ resource[:require] << Puppet::Resource.new(:file, path)
+ else
+ resource[:require] = [Puppet::Resource.new(:file, path)]
+ end
end
- # Should we remove the specified file?
- def tidy?(path)
- return false unless stat = self.stat(path)
+ result
+ end
+
+ # Does a given path match our glob patterns, if any? Return true
+ # if no patterns have been provided.
+ def matches?(path)
+ return true unless self[:matches]
+
+ basename = File.basename(path)
+ flags = File::FNM_DOTMATCH | File::FNM_PATHNAME
+ if self[:matches].find {|pattern| File.fnmatch(pattern, basename, flags) }
+ return true
+ else
+ debug "No specified patterns match #{path}, not tidying"
+ return false
+ end
+ end
- return false if stat.ftype == "directory" and ! rmdirs?
+ # Should we remove the specified file?
+ def tidy?(path)
+ return false unless stat = self.stat(path)
- # The 'matches' parameter isn't OR'ed with the other tests --
- # it's just used to reduce the list of files we can match.
- return false if param = parameter(:matches) and ! param.tidy?(path, stat)
+ return false if stat.ftype == "directory" and ! rmdirs?
- tested = false
- [:age, :size].each do |name|
- next unless param = parameter(name)
- tested = true
- return true if param.tidy?(path, stat)
- end
+ # The 'matches' parameter isn't OR'ed with the other tests --
+ # it's just used to reduce the list of files we can match.
+ return false if param = parameter(:matches) and ! param.tidy?(path, stat)
- # If they don't specify either, then the file should always be removed.
- return true unless tested
- false
+ tested = false
+ [:age, :size].each do |name|
+ next unless param = parameter(name)
+ tested = true
+ return true if param.tidy?(path, stat)
end
- def stat(path)
- begin
- File.lstat(path)
- rescue Errno::ENOENT => error
- info "File does not exist"
- return nil
- rescue Errno::EACCES => error
- warning "Could not stat; permission denied"
- return nil
- end
+ # If they don't specify either, then the file should always be removed.
+ return true unless tested
+ false
+ end
+
+ def stat(path)
+ begin
+ File.lstat(path)
+ rescue Errno::ENOENT => error
+ info "File does not exist"
+ return nil
+ rescue Errno::EACCES => error
+ warning "Could not stat; permission denied"
+ return nil
end
+ end
end
diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb
index 4c472275c..c7ac796a3 100755
--- a/lib/puppet/type/user.rb
+++ b/lib/puppet/type/user.rb
@@ -5,380 +5,380 @@ require 'puppet/property/ordered_list'
require 'puppet/property/keyvalue'
module Puppet
- newtype(:user) do
- @doc = "Manage users. This type is mostly built to manage system
- users, so it is lacking some features useful for managing normal
- users.
-
- This resource type uses the prescribed native tools for creating
- groups and generally uses POSIX APIs for retrieving information
- about them. It does not directly modify /etc/passwd or anything."
-
- feature :allows_duplicates,
- "The provider supports duplicate users with the same UID."
-
- feature :manages_homedir,
- "The provider can create and remove home directories."
-
- feature :manages_passwords,
- "The provider can modify user passwords, by accepting a password
- hash."
-
- feature :manages_solaris_rbac,
- "The provider can manage roles and normal users"
+ newtype(:user) do
+ @doc = "Manage users. This type is mostly built to manage system
+ users, so it is lacking some features useful for managing normal
+ users.
+
+ This resource type uses the prescribed native tools for creating
+ groups and generally uses POSIX APIs for retrieving information
+ about them. It does not directly modify /etc/passwd or anything."
+
+ feature :allows_duplicates,
+ "The provider supports duplicate users with the same UID."
+
+ feature :manages_homedir,
+ "The provider can create and remove home directories."
+
+ feature :manages_passwords,
+ "The provider can modify user passwords, by accepting a password
+ hash."
+
+ feature :manages_solaris_rbac,
+ "The provider can manage roles and normal users"
+
+ newproperty(:ensure, :parent => Puppet::Property::Ensure) do
+ newvalue(:present, :event => :user_created) do
+ provider.create
+ end
+
+ newvalue(:absent, :event => :user_removed) do
+ provider.delete
+ end
+
+ newvalue(:role, :event => :role_created, :required_features => :manages_solaris_rbac) do
+ provider.create_role
+ end
+
+ desc "The basic state that the object should be in."
+
+ # If they're talking about the thing at all, they generally want to
+ # say it should exist.
+ defaultto do
+ if @resource.managed?
+ :present
+ else
+ nil
+ end
+ end
+
+ def retrieve
+ if provider.exists?
+ if provider.respond_to?(:is_role?) and provider.is_role?
+ return :role
+ else
+ return :present
+ end
+ else
+ return :absent
+ end
+ end
+ end
- newproperty(:ensure, :parent => Puppet::Property::Ensure) do
- newvalue(:present, :event => :user_created) do
- provider.create
- end
+ newproperty(:uid) do
+ desc "The user ID. Must be specified numerically. For new users
+ being created, if no user ID is specified then one will be
+ chosen automatically, which will likely result in the same user
+ having different IDs on different systems, which is not
+ recommended. This is especially noteworthy if you use Puppet
+ to manage the same user on both Darwin and other platforms,
+ since Puppet does the ID generation for you on Darwin, but the
+ tools do so on other platforms."
+
+ munge do |value|
+ case value
+ when String
+ if value =~ /^[-0-9]+$/
+ value = Integer(value)
+ end
+ end
- newvalue(:absent, :event => :user_removed) do
- provider.delete
- end
+ return value
+ end
+ end
- newvalue(:role, :event => :role_created, :required_features => :manages_solaris_rbac) do
- provider.create_role
- end
+ newproperty(:gid) do
+ desc "The user's primary group. Can be specified numerically or
+ by name."
- desc "The basic state that the object should be in."
+ munge do |value|
+ if value.is_a?(String) and value =~ /^[-0-9]+$/
+ Integer(value)
+ else
+ value
+ end
+ end
- # If they're talking about the thing at all, they generally want to
- # say it should exist.
- defaultto do
- if @resource.managed?
- :present
- else
- nil
- end
- end
+ def insync?(is)
+ return true unless self.should
- def retrieve
- if provider.exists?
- if provider.respond_to?(:is_role?) and provider.is_role?
- return :role
- else
- return :present
- end
- else
- return :absent
- end
- end
+ # We know the 'is' is a number, so we need to convert the 'should' to a number,
+ # too.
+ @should.each do |value|
+ return true if number = Puppet::Util.gid(value) and is == number
end
- newproperty(:uid) do
- desc "The user ID. Must be specified numerically. For new users
- being created, if no user ID is specified then one will be
- chosen automatically, which will likely result in the same user
- having different IDs on different systems, which is not
- recommended. This is especially noteworthy if you use Puppet
- to manage the same user on both Darwin and other platforms,
- since Puppet does the ID generation for you on Darwin, but the
- tools do so on other platforms."
-
- munge do |value|
- case value
- when String
- if value =~ /^[-0-9]+$/
- value = Integer(value)
- end
- end
-
- return value
- end
+ false
+ end
+
+ def sync
+ found = false
+ @should.each do |value|
+ if number = Puppet::Util.gid(value)
+ provider.gid = number
+ found = true
+ break
+ end
end
- newproperty(:gid) do
- desc "The user's primary group. Can be specified numerically or
- by name."
+ fail "Could not find group(s) #{@should.join(",")}" unless found
- munge do |value|
- if value.is_a?(String) and value =~ /^[-0-9]+$/
- Integer(value)
- else
- value
- end
- end
+ # Use the default event.
+ end
+ end
- def insync?(is)
- return true unless self.should
+ newproperty(:comment) do
+ desc "A description of the user. Generally is a user's full name."
+ end
- # We know the 'is' is a number, so we need to convert the 'should' to a number,
- # too.
- @should.each do |value|
- return true if number = Puppet::Util.gid(value) and is == number
- end
+ newproperty(:home) do
+ desc "The home directory of the user. The directory must be created
+ separately and is not currently checked for existence."
+ end
- false
- end
+ newproperty(:shell) do
+ desc "The user's login shell. The shell must exist and be
+ executable."
+ end
- def sync
- found = false
- @should.each do |value|
- if number = Puppet::Util.gid(value)
- provider.gid = number
- found = true
- break
- end
- end
+ newproperty(:password, :required_features => :manages_passwords) do
+ desc "The user's password, in whatever encrypted format the local machine requires. Be sure to enclose any value that includes a dollar sign ($) in single quotes (\')."
- fail "Could not find group(s) #{@should.join(",")}" unless found
+ validate do |value|
+ raise ArgumentError, "Passwords cannot include ':'" if value.is_a?(String) and value.include?(":")
+ end
- # Use the default event.
- end
+ def change_to_s(currentvalue, newvalue)
+ if currentvalue == :absent
+ return "created password"
+ else
+ return "changed password"
end
+ end
+ end
- newproperty(:comment) do
- desc "A description of the user. Generally is a user's full name."
- end
- newproperty(:home) do
- desc "The home directory of the user. The directory must be created
- separately and is not currently checked for existence."
- end
+ newproperty(:groups, :parent => Puppet::Property::List) do
+ desc "The groups of which the user is a member. The primary
+ group should not be listed. Multiple groups should be
+ specified as an array."
- newproperty(:shell) do
- desc "The user's login shell. The shell must exist and be
- executable."
+ validate do |value|
+ if value =~ /^\d+$/
+ raise ArgumentError, "Group names must be provided, not numbers"
end
+ raise ArgumentError, "Group names must be provided as an array, not a comma-separated list" if value.include?(",")
+ end
+ end
- newproperty(:password, :required_features => :manages_passwords) do
- desc "The user's password, in whatever encrypted format the local machine requires. Be sure to enclose any value that includes a dollar sign ($) in single quotes (\')."
-
- validate do |value|
- raise ArgumentError, "Passwords cannot include ':'" if value.is_a?(String) and value.include?(":")
- end
+ newparam(:name) do
+ desc "User name. While limitations are determined for
+ each operating system, it is generally a good idea to keep to
+ the degenerate 8 characters, beginning with a letter."
+ isnamevar
+ end
- def change_to_s(currentvalue, newvalue)
- if currentvalue == :absent
- return "created password"
- else
- return "changed password"
- end
- end
- end
+ newparam(:membership) do
+ desc "Whether specified groups should be treated as the only groups
+ of which the user is a member or whether they should merely
+ be treated as the minimum membership list."
+ newvalues(:inclusive, :minimum)
- newproperty(:groups, :parent => Puppet::Property::List) do
- desc "The groups of which the user is a member. The primary
- group should not be listed. Multiple groups should be
- specified as an array."
+ defaultto :minimum
+ end
- validate do |value|
- if value =~ /^\d+$/
- raise ArgumentError, "Group names must be provided, not numbers"
- end
- raise ArgumentError, "Group names must be provided as an array, not a comma-separated list" if value.include?(",")
- end
- end
+ newparam(:allowdupe, :boolean => true) do
+ desc "Whether to allow duplicate UIDs."
- newparam(:name) do
- desc "User name. While limitations are determined for
- each operating system, it is generally a good idea to keep to
- the degenerate 8 characters, beginning with a letter."
- isnamevar
- end
+ newvalues(:true, :false)
- newparam(:membership) do
- desc "Whether specified groups should be treated as the only groups
- of which the user is a member or whether they should merely
- be treated as the minimum membership list."
+ defaultto false
+ end
- newvalues(:inclusive, :minimum)
+ newparam(:managehome, :boolean => true) do
+ desc "Whether to manage the home directory when managing the user."
- defaultto :minimum
- end
+ newvalues(:true, :false)
- newparam(:allowdupe, :boolean => true) do
- desc "Whether to allow duplicate UIDs."
+ defaultto false
- newvalues(:true, :false)
-
- defaultto false
+ validate do |val|
+ if val.to_s == "true"
+ raise ArgumentError, "User provider #{provider.class.name} can not manage home directories" unless provider.class.manages_homedir?
end
+ end
+ end
- newparam(:managehome, :boolean => true) do
- desc "Whether to manage the home directory when managing the user."
-
- newvalues(:true, :false)
-
- defaultto false
-
- validate do |val|
- if val.to_s == "true"
- raise ArgumentError, "User provider #{provider.class.name} can not manage home directories" unless provider.class.manages_homedir?
- end
+ # Autorequire the group, if it's around
+ autorequire(:group) do
+ autos = []
+
+ if obj = @parameters[:gid] and groups = obj.shouldorig
+ groups = groups.collect { |group|
+ if group =~ /^\d+$/
+ Integer(group)
+ else
+ group
+ end
+ }
+ groups.each { |group|
+ case group
+ when Integer
+ if resource = catalog.resources.find { |r| r.is_a?(Puppet::Type.type(:group)) and r.should(:gid) == group }
+ autos << resource
end
- end
+ else
+ autos << group
+ end
+ }
+ end
- # Autorequire the group, if it's around
- autorequire(:group) do
- autos = []
-
- if obj = @parameters[:gid] and groups = obj.shouldorig
- groups = groups.collect { |group|
- if group =~ /^\d+$/
- Integer(group)
- else
- group
- end
- }
- groups.each { |group|
- case group
- when Integer
- if resource = catalog.resources.find { |r| r.is_a?(Puppet::Type.type(:group)) and r.should(:gid) == group }
- autos << resource
- end
- else
- autos << group
- end
- }
- end
+ if obj = @parameters[:groups] and groups = obj.should
+ autos += groups.split(",")
+ end
- if obj = @parameters[:groups] and groups = obj.should
- autos += groups.split(",")
- end
+ autos
+ end
- autos
- end
+ # Provide an external hook. Yay breaking out of APIs.
+ def exists?
+ provider.exists?
+ end
+
+ def retrieve
+ absent = false
+ properties.inject({}) { |prophash, property|
+ current_value = :absent
- # Provide an external hook. Yay breaking out of APIs.
- def exists?
- provider.exists?
+ if absent
+ prophash[property] = :absent
+ else
+ current_value = property.retrieve
+ prophash[property] = current_value
end
- def retrieve
- absent = false
- properties.inject({}) { |prophash, property|
- current_value = :absent
-
- if absent
- prophash[property] = :absent
- else
- current_value = property.retrieve
- prophash[property] = current_value
- end
-
- if property.name == :ensure and current_value == :absent
- absent = true
- end
- prophash
- }
+ if property.name == :ensure and current_value == :absent
+ absent = true
end
+ prophash
+ }
+ end
- newproperty(:roles, :parent => Puppet::Property::List, :required_features => :manages_solaris_rbac) do
- desc "The roles the user has. Multiple roles should be
- specified as an array."
+ newproperty(:roles, :parent => Puppet::Property::List, :required_features => :manages_solaris_rbac) do
+ desc "The roles the user has. Multiple roles should be
+ specified as an array."
- def membership
- :role_membership
- end
+ def membership
+ :role_membership
+ end
- validate do |value|
- if value =~ /^\d+$/
- raise ArgumentError, "Role names must be provided, not numbers"
- end
- raise ArgumentError, "Role names must be provided as an array, not a comma-separated list" if value.include?(",")
- end
+ validate do |value|
+ if value =~ /^\d+$/
+ raise ArgumentError, "Role names must be provided, not numbers"
end
+ raise ArgumentError, "Role names must be provided as an array, not a comma-separated list" if value.include?(",")
+ end
+ end
- #autorequire the roles that the user has
- autorequire(:user) do
- reqs = []
+ #autorequire the roles that the user has
+ autorequire(:user) do
+ reqs = []
- if roles_property = @parameters[:roles] and roles = roles_property.should
- reqs += roles.split(',')
- end
+ if roles_property = @parameters[:roles] and roles = roles_property.should
+ reqs += roles.split(',')
+ end
- reqs
- end
+ reqs
+ end
- newparam(:role_membership) do
- desc "Whether specified roles should be treated as the only roles
- of which the user is a member or whether they should merely
- be treated as the minimum membership list."
+ newparam(:role_membership) do
+ desc "Whether specified roles should be treated as the only roles
+ of which the user is a member or whether they should merely
+ be treated as the minimum membership list."
- newvalues(:inclusive, :minimum)
+ newvalues(:inclusive, :minimum)
- defaultto :minimum
- end
+ defaultto :minimum
+ end
- newproperty(:auths, :parent => Puppet::Property::List, :required_features => :manages_solaris_rbac) do
- desc "The auths the user has. Multiple auths should be
- specified as an array."
+ newproperty(:auths, :parent => Puppet::Property::List, :required_features => :manages_solaris_rbac) do
+ desc "The auths the user has. Multiple auths should be
+ specified as an array."
- def membership
- :auth_membership
- end
+ def membership
+ :auth_membership
+ end
- validate do |value|
- if value =~ /^\d+$/
- raise ArgumentError, "Auth names must be provided, not numbers"
- end
- raise ArgumentError, "Auth names must be provided as an array, not a comma-separated list" if value.include?(",")
- end
+ validate do |value|
+ if value =~ /^\d+$/
+ raise ArgumentError, "Auth names must be provided, not numbers"
end
+ raise ArgumentError, "Auth names must be provided as an array, not a comma-separated list" if value.include?(",")
+ end
+ end
- newparam(:auth_membership) do
- desc "Whether specified auths should be treated as the only auths
- of which the user is a member or whether they should merely
- be treated as the minimum membership list."
+ newparam(:auth_membership) do
+ desc "Whether specified auths should be treated as the only auths
+ of which the user is a member or whether they should merely
+ be treated as the minimum membership list."
- newvalues(:inclusive, :minimum)
+ newvalues(:inclusive, :minimum)
- defaultto :minimum
- end
+ defaultto :minimum
+ end
- newproperty(:profiles, :parent => Puppet::Property::OrderedList, :required_features => :manages_solaris_rbac) do
- desc "The profiles the user has. Multiple profiles should be
- specified as an array."
+ newproperty(:profiles, :parent => Puppet::Property::OrderedList, :required_features => :manages_solaris_rbac) do
+ desc "The profiles the user has. Multiple profiles should be
+ specified as an array."
- def membership
- :profile_membership
- end
+ def membership
+ :profile_membership
+ end
- validate do |value|
- if value =~ /^\d+$/
- raise ArgumentError, "Profile names must be provided, not numbers"
- end
- raise ArgumentError, "Profile names must be provided as an array, not a comma-separated list" if value.include?(",")
- end
+ validate do |value|
+ if value =~ /^\d+$/
+ raise ArgumentError, "Profile names must be provided, not numbers"
end
+ raise ArgumentError, "Profile names must be provided as an array, not a comma-separated list" if value.include?(",")
+ end
+ end
- newparam(:profile_membership) do
- desc "Whether specified roles should be treated as the only roles
- of which the user is a member or whether they should merely
- be treated as the minimum membership list."
+ newparam(:profile_membership) do
+ desc "Whether specified roles should be treated as the only roles
+ of which the user is a member or whether they should merely
+ be treated as the minimum membership list."
- newvalues(:inclusive, :minimum)
+ newvalues(:inclusive, :minimum)
- defaultto :minimum
- end
+ defaultto :minimum
+ end
- newproperty(:keys, :parent => Puppet::Property::KeyValue, :required_features => :manages_solaris_rbac) do
- desc "Specify user attributes in an array of keyvalue pairs"
+ newproperty(:keys, :parent => Puppet::Property::KeyValue, :required_features => :manages_solaris_rbac) do
+ desc "Specify user attributes in an array of keyvalue pairs"
- def membership
- :key_membership
- end
+ def membership
+ :key_membership
+ end
- validate do |value|
- raise ArgumentError, "key value pairs must be seperated by an =" unless value.include?("=")
- end
- end
+ validate do |value|
+ raise ArgumentError, "key value pairs must be seperated by an =" unless value.include?("=")
+ end
+ end
- newparam(:key_membership) do
- desc "Whether specified key value pairs should be treated as the only attributes
- of the user or whether they should merely
- be treated as the minimum list."
+ newparam(:key_membership) do
+ desc "Whether specified key value pairs should be treated as the only attributes
+ of the user or whether they should merely
+ be treated as the minimum list."
- newvalues(:inclusive, :minimum)
+ newvalues(:inclusive, :minimum)
- defaultto :minimum
- end
+ defaultto :minimum
+ end
- newproperty(:project, :required_features => :manages_solaris_rbac) do
- desc "The name of the project associated with a user"
- end
+ newproperty(:project, :required_features => :manages_solaris_rbac) do
+ desc "The name of the project associated with a user"
end
+ end
end
diff --git a/lib/puppet/type/yumrepo.rb b/lib/puppet/type/yumrepo.rb
index d37da0291..e0ed3ad37 100644
--- a/lib/puppet/type/yumrepo.rb
+++ b/lib/puppet/type/yumrepo.rb
@@ -3,344 +3,344 @@
require 'puppet/util/inifile'
module Puppet
- # A property for one entry in a .ini-style file
- class IniProperty < Puppet::Property
- def insync?(is)
- # A should property of :absent is the same as nil
- if is.nil? && (should.nil? || should == :absent)
- return true
- end
- super(is)
- end
-
- def sync
- if insync?(retrieve)
- result = nil
- else
- result = set(self.should)
- if should == :absent
- resource.section[inikey] = nil
- else
- resource.section[inikey] = should
- end
- end
- result
- end
+ # A property for one entry in a .ini-style file
+ class IniProperty < Puppet::Property
+ def insync?(is)
+ # A should property of :absent is the same as nil
+ if is.nil? && (should.nil? || should == :absent)
+ return true
+ end
+ super(is)
+ end
- def retrieve
- resource.section[inikey]
- end
+ def sync
+ if insync?(retrieve)
+ result = nil
+ else
+ result = set(self.should)
+ if should == :absent
+ resource.section[inikey] = nil
+ else
+ resource.section[inikey] = should
+ end
+ end
+ result
+ end
- def inikey
- name.to_s
- end
+ def retrieve
+ resource.section[inikey]
+ end
- # Set the key associated with this property to KEY, instead
- # of using the property's NAME
- def self.inikey(key)
- # Override the inikey instance method
- # Is there a way to do this without resorting to strings ?
- # Using a block fails because the block can't access
- # the variable 'key' in the outer scope
- self.class_eval("def inikey ; \"#{key.to_s}\" ; end")
- end
+ def inikey
+ name.to_s
+ end
+ # Set the key associated with this property to KEY, instead
+ # of using the property's NAME
+ def self.inikey(key)
+ # Override the inikey instance method
+ # Is there a way to do this without resorting to strings ?
+ # Using a block fails because the block can't access
+ # the variable 'key' in the outer scope
+ self.class_eval("def inikey ; \"#{key.to_s}\" ; end")
end
- # Doc string for properties that can be made 'absent'
- ABSENT_DOC="Set this to 'absent' to remove it from the file completely"
+ end
- newtype(:yumrepo) do
- @doc = "The client-side description of a yum repository. Repository
- configurations are found by parsing /etc/yum.conf and
- the files indicated by reposdir in that file (see yum.conf(5) for details)
+ # Doc string for properties that can be made 'absent'
+ ABSENT_DOC="Set this to 'absent' to remove it from the file completely"
- Most parameters are identical to the ones documented
- in yum.conf(5)
+ newtype(:yumrepo) do
+ @doc = "The client-side description of a yum repository. Repository
+ configurations are found by parsing /etc/yum.conf and
+ the files indicated by reposdir in that file (see yum.conf(5) for details)
- Continuation lines that yum supports for example for the
- baseurl are not supported. No attempt is made to access
- files included with the **include** directive"
+ Most parameters are identical to the ones documented
+ in yum.conf(5)
- class << self
- attr_accessor :filetype
- # The writer is only used for testing, there should be no need
- # to change yumconf or inifile in any other context
- attr_accessor :yumconf
- attr_writer :inifile
- end
+ Continuation lines that yum supports for example for the
+ baseurl are not supported. No attempt is made to access
+ files included with the **include** directive"
- self.filetype = Puppet::Util::FileType.filetype(:flat)
-
- @inifile = nil
-
- @yumconf = "/etc/yum.conf"
-
- # Where to put files for brand new sections
- @defaultrepodir = nil
-
- def self.instances
- l = []
- check = validproperties
- clear
- inifile.each_section do |s|
- next if s.name == "main"
- obj = create(:name => s.name, :audit => check)
- current_values = obj.retrieve
- obj.eachproperty do |property|
- if current_values[property].nil?
- obj.delete(property.name)
- else
- property.should = current_values[property]
- end
- end
- obj.delete(:audit)
- l << obj
- end
- l
- end
+ class << self
+ attr_accessor :filetype
+ # The writer is only used for testing, there should be no need
+ # to change yumconf or inifile in any other context
+ attr_accessor :yumconf
+ attr_writer :inifile
+ end
- # Return the Puppet::Util::IniConfig::File for the whole yum config
- def self.inifile
- if @inifile.nil?
- @inifile = read
- main = @inifile['main']
- raise Puppet::Error, "File #{yumconf} does not contain a main section" if main.nil?
- reposdir = main['reposdir']
- reposdir ||= "/etc/yum.repos.d, /etc/yum/repos.d"
- reposdir.gsub!(/[\n,]/, " ")
- reposdir.split.each do |dir|
- Dir::glob("#{dir}/*.repo").each do |file|
- @inifile.read(file) if File.file?(file)
- end
- end
- reposdir.split.each do |dir|
- if File::directory?(dir) && File::writable?(dir)
- @defaultrepodir = dir
- break
- end
- end
- end
- @inifile
- end
+ self.filetype = Puppet::Util::FileType.filetype(:flat)
+
+ @inifile = nil
+
+ @yumconf = "/etc/yum.conf"
+
+ # Where to put files for brand new sections
+ @defaultrepodir = nil
+
+ def self.instances
+ l = []
+ check = validproperties
+ clear
+ inifile.each_section do |s|
+ next if s.name == "main"
+ obj = create(:name => s.name, :audit => check)
+ current_values = obj.retrieve
+ obj.eachproperty do |property|
+ if current_values[property].nil?
+ obj.delete(property.name)
+ else
+ property.should = current_values[property]
+ end
+ end
+ obj.delete(:audit)
+ l << obj
+ end
+ l
+ end
- # Parse the yum config files. Only exposed for the tests
- # Non-test code should use self.inifile to get at the
- # underlying file
- def self.read
- result = Puppet::Util::IniConfig::File.new
- result.read(yumconf)
- main = result['main']
- raise Puppet::Error, "File #{yumconf} does not contain a main section" if main.nil?
- reposdir = main['reposdir']
- reposdir ||= "/etc/yum.repos.d, /etc/yum/repos.d"
- reposdir.gsub!(/[\n,]/, " ")
- reposdir.split.each do |dir|
- Dir::glob("#{dir}/*.repo").each do |file|
- result.read(file) if File.file?(file)
- end
- end
- if @defaultrepodir.nil?
- reposdir.split.each do |dir|
- if File::directory?(dir) && File::writable?(dir)
- @defaultrepodir = dir
- break
- end
- end
- end
- result
- end
+ # Return the Puppet::Util::IniConfig::File for the whole yum config
+ def self.inifile
+ if @inifile.nil?
+ @inifile = read
+ main = @inifile['main']
+ raise Puppet::Error, "File #{yumconf} does not contain a main section" if main.nil?
+ reposdir = main['reposdir']
+ reposdir ||= "/etc/yum.repos.d, /etc/yum/repos.d"
+ reposdir.gsub!(/[\n,]/, " ")
+ reposdir.split.each do |dir|
+ Dir::glob("#{dir}/*.repo").each do |file|
+ @inifile.read(file) if File.file?(file)
+ end
+ end
+ reposdir.split.each do |dir|
+ if File::directory?(dir) && File::writable?(dir)
+ @defaultrepodir = dir
+ break
+ end
+ end
+ end
+ @inifile
+ end
- # Return the Puppet::Util::IniConfig::Section with name NAME
- # from the yum config
- def self.section(name)
- result = inifile[name]
- if result.nil?
- # Brand new section
- path = yumconf
- path = File::join(@defaultrepodir, "#{name}.repo") unless @defaultrepodir.nil?
- Puppet::info "create new repo #{name} in file #{path}"
- result = inifile.add_section(name, path)
- end
- result
- end
+ # Parse the yum config files. Only exposed for the tests
+ # Non-test code should use self.inifile to get at the
+ # underlying file
+ def self.read
+ result = Puppet::Util::IniConfig::File.new
+ result.read(yumconf)
+ main = result['main']
+ raise Puppet::Error, "File #{yumconf} does not contain a main section" if main.nil?
+ reposdir = main['reposdir']
+ reposdir ||= "/etc/yum.repos.d, /etc/yum/repos.d"
+ reposdir.gsub!(/[\n,]/, " ")
+ reposdir.split.each do |dir|
+ Dir::glob("#{dir}/*.repo").each do |file|
+ result.read(file) if File.file?(file)
+ end
+ end
+ if @defaultrepodir.nil?
+ reposdir.split.each do |dir|
+ if File::directory?(dir) && File::writable?(dir)
+ @defaultrepodir = dir
+ break
+ end
+ end
+ end
+ result
+ end
- # Store all modifications back to disk
- def self.store
- inifile.store
- unless Puppet[:noop]
- target_mode = 0644 # FIXME: should be configurable
- inifile.each_file do |file|
- current_mode = File.stat(file).mode & 0777
- unless current_mode == target_mode
- Puppet::info "changing mode of #{file} from %03o to %03o" % [current_mode, target_mode]
- File.chmod(target_mode, file)
- end
- end
- end
- end
+ # Return the Puppet::Util::IniConfig::Section with name NAME
+ # from the yum config
+ def self.section(name)
+ result = inifile[name]
+ if result.nil?
+ # Brand new section
+ path = yumconf
+ path = File::join(@defaultrepodir, "#{name}.repo") unless @defaultrepodir.nil?
+ Puppet::info "create new repo #{name} in file #{path}"
+ result = inifile.add_section(name, path)
+ end
+ result
+ end
- # This is only used during testing.
- def self.clear
- @inifile = nil
- @yumconf = "/etc/yum.conf"
- @defaultrepodir = nil
- end
+ # Store all modifications back to disk
+ def self.store
+ inifile.store
+ unless Puppet[:noop]
+ target_mode = 0644 # FIXME: should be configurable
+ inifile.each_file do |file|
+ current_mode = File.stat(file).mode & 0777
+ unless current_mode == target_mode
+ Puppet::info "changing mode of #{file} from %03o to %03o" % [current_mode, target_mode]
+ File.chmod(target_mode, file)
+ end
+ end
+ end
+ end
- # Return the Puppet::Util::IniConfig::Section for this yumrepo resource
- def section
- self.class.section(self[:name])
- end
+ # This is only used during testing.
+ def self.clear
+ @inifile = nil
+ @yumconf = "/etc/yum.conf"
+ @defaultrepodir = nil
+ end
- # Store modifications to this yumrepo resource back to disk
- def flush
- self.class.store
- end
+ # Return the Puppet::Util::IniConfig::Section for this yumrepo resource
+ def section
+ self.class.section(self[:name])
+ end
- newparam(:name) do
- desc "The name of the repository. This corresponds to the
- repositoryid parameter in yum.conf(5)."
- isnamevar
- end
+ # Store modifications to this yumrepo resource back to disk
+ def flush
+ self.class.store
+ end
- newproperty(:descr, :parent => Puppet::IniProperty) do
- desc "A human readable description of the repository.
- This corresponds to the name parameter in yum.conf(5).
- #{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(/.*/) { }
- inikey "name"
- end
+ newparam(:name) do
+ desc "The name of the repository. This corresponds to the
+ repositoryid parameter in yum.conf(5)."
+ isnamevar
+ end
- newproperty(:mirrorlist, :parent => Puppet::IniProperty) do
- desc "The URL that holds the list of mirrors for this repository.
- #{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- # Should really check that it's a valid URL
- newvalue(/.*/) { }
- end
+ newproperty(:descr, :parent => Puppet::IniProperty) do
+ desc "A human readable description of the repository.
+ This corresponds to the name parameter in yum.conf(5).
+ #{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(/.*/) { }
+ inikey "name"
+ end
- newproperty(:baseurl, :parent => Puppet::IniProperty) do
- desc "The URL for this repository.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- # Should really check that it's a valid URL
- newvalue(/.*/) { }
- end
+ newproperty(:mirrorlist, :parent => Puppet::IniProperty) do
+ desc "The URL that holds the list of mirrors for this repository.
+ #{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ # Should really check that it's a valid URL
+ newvalue(/.*/) { }
+ end
- newproperty(:enabled, :parent => Puppet::IniProperty) do
- desc "Whether this repository is enabled or disabled. Possible
- values are '0', and '1'.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(%r{(0|1)}) { }
- end
+ newproperty(:baseurl, :parent => Puppet::IniProperty) do
+ desc "The URL for this repository.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ # Should really check that it's a valid URL
+ newvalue(/.*/) { }
+ end
- newproperty(:gpgcheck, :parent => Puppet::IniProperty) do
- desc "Whether to check the GPG signature on packages installed
- from this repository. Possible values are '0', and '1'.
- \n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(%r{(0|1)}) { }
- end
+ newproperty(:enabled, :parent => Puppet::IniProperty) do
+ desc "Whether this repository is enabled or disabled. Possible
+ values are '0', and '1'.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(%r{(0|1)}) { }
+ end
- newproperty(:gpgkey, :parent => Puppet::IniProperty) do
- desc "The URL for the GPG key with which packages from this
- repository are signed.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- # Should really check that it's a valid URL
- newvalue(/.*/) { }
- end
+ newproperty(:gpgcheck, :parent => Puppet::IniProperty) do
+ desc "Whether to check the GPG signature on packages installed
+ from this repository. Possible values are '0', and '1'.
+ \n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(%r{(0|1)}) { }
+ end
- newproperty(:include, :parent => Puppet::IniProperty) do
- desc "A URL from which to include the config.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- # Should really check that it's a valid URL
- newvalue(/.*/) { }
- end
+ newproperty(:gpgkey, :parent => Puppet::IniProperty) do
+ desc "The URL for the GPG key with which packages from this
+ repository are signed.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ # Should really check that it's a valid URL
+ newvalue(/.*/) { }
+ end
- newproperty(:exclude, :parent => Puppet::IniProperty) do
- desc "List of shell globs. Matching packages will never be
- considered in updates or installs for this repo.
- #{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(/.*/) { }
- end
+ newproperty(:include, :parent => Puppet::IniProperty) do
+ desc "A URL from which to include the config.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ # Should really check that it's a valid URL
+ newvalue(/.*/) { }
+ end
- newproperty(:includepkgs, :parent => Puppet::IniProperty) do
- desc "List of shell globs. If this is set, only packages
- matching one of the globs will be considered for
- update or install.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(/.*/) { }
- end
+ newproperty(:exclude, :parent => Puppet::IniProperty) do
+ desc "List of shell globs. Matching packages will never be
+ considered in updates or installs for this repo.
+ #{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(/.*/) { }
+ end
- newproperty(:enablegroups, :parent => Puppet::IniProperty) do
- desc "Determines whether yum will allow the use of
- package groups for this repository. Possible
- values are '0', and '1'.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(%r{(0|1)}) { }
- end
+ newproperty(:includepkgs, :parent => Puppet::IniProperty) do
+ desc "List of shell globs. If this is set, only packages
+ matching one of the globs will be considered for
+ update or install.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(/.*/) { }
+ end
- newproperty(:failovermethod, :parent => Puppet::IniProperty) do
- desc "Either 'roundrobin' or 'priority'.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(%r{roundrobin|priority}) { }
- end
+ newproperty(:enablegroups, :parent => Puppet::IniProperty) do
+ desc "Determines whether yum will allow the use of
+ package groups for this repository. Possible
+ values are '0', and '1'.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(%r{(0|1)}) { }
+ end
- newproperty(:keepalive, :parent => Puppet::IniProperty) do
- desc "Either '1' or '0'. This tells yum whether or not HTTP/1.1
- keepalive should be used with this repository.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(%r{(0|1)}) { }
- end
+ newproperty(:failovermethod, :parent => Puppet::IniProperty) do
+ desc "Either 'roundrobin' or 'priority'.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(%r{roundrobin|priority}) { }
+ end
- newproperty(:timeout, :parent => Puppet::IniProperty) do
- desc "Number of seconds to wait for a connection before timing
- out.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(%r{[0-9]+}) { }
- end
+ newproperty(:keepalive, :parent => Puppet::IniProperty) do
+ desc "Either '1' or '0'. This tells yum whether or not HTTP/1.1
+ keepalive should be used with this repository.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(%r{(0|1)}) { }
+ end
- newproperty(:metadata_expire, :parent => Puppet::IniProperty) do
- desc "Number of seconds after which the metadata will expire.
- #{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(%r{[0-9]+}) { }
- end
+ newproperty(:timeout, :parent => Puppet::IniProperty) do
+ desc "Number of seconds to wait for a connection before timing
+ out.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(%r{[0-9]+}) { }
+ end
- newproperty(:protect, :parent => Puppet::IniProperty) do
- desc "Enable or disable protection for this repository. Requires
- that the protectbase plugin is installed and enabled.
- #{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(%r{(0|1)}) { }
- end
+ newproperty(:metadata_expire, :parent => Puppet::IniProperty) do
+ desc "Number of seconds after which the metadata will expire.
+ #{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(%r{[0-9]+}) { }
+ end
- newproperty(:priority, :parent => Puppet::IniProperty) do
- desc "Priority of this repository from 1-99. Requires that
- the priorities plugin is installed and enabled.
- #{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(%r{[1-9][0-9]?}) { }
- end
+ newproperty(:protect, :parent => Puppet::IniProperty) do
+ desc "Enable or disable protection for this repository. Requires
+ that the protectbase plugin is installed and enabled.
+ #{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(%r{(0|1)}) { }
+ end
- newproperty(:proxy, :parent => Puppet::IniProperty) do
- desc "URL to the proxy server for this repository.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- # Should really check that it's a valid URL
- newvalue(/.*/) { }
- end
+ newproperty(:priority, :parent => Puppet::IniProperty) do
+ desc "Priority of this repository from 1-99. Requires that
+ the priorities plugin is installed and enabled.
+ #{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(%r{[1-9][0-9]?}) { }
+ end
- newproperty(:proxy_username, :parent => Puppet::IniProperty) do
- desc "Username for this proxy.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(/.*/) { }
- end
+ newproperty(:proxy, :parent => Puppet::IniProperty) do
+ desc "URL to the proxy server for this repository.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ # Should really check that it's a valid URL
+ newvalue(/.*/) { }
+ end
- newproperty(:proxy_password, :parent => Puppet::IniProperty) do
- desc "Password for this proxy.\n#{ABSENT_DOC}"
- newvalue(:absent) { self.should = :absent }
- newvalue(/.*/) { }
- end
+ newproperty(:proxy_username, :parent => Puppet::IniProperty) do
+ desc "Username for this proxy.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(/.*/) { }
+ end
+
+ newproperty(:proxy_password, :parent => Puppet::IniProperty) do
+ desc "Password for this proxy.\n#{ABSENT_DOC}"
+ newvalue(:absent) { self.should = :absent }
+ newvalue(/.*/) { }
end
+ end
end
diff --git a/lib/puppet/type/zfs.rb b/lib/puppet/type/zfs.rb
index 3a8806a5e..e1a972ddf 100755
--- a/lib/puppet/type/zfs.rb
+++ b/lib/puppet/type/zfs.rb
@@ -1,51 +1,51 @@
module Puppet
- newtype(:zfs) do
- @doc = "Manage zfs. Create destroy and set properties on zfs instances."
+ newtype(:zfs) do
+ @doc = "Manage zfs. Create destroy and set properties on zfs instances."
- ensurable
+ ensurable
- newparam(:name) do
- desc "The full name for this filesystem. (including the zpool)"
- end
+ newparam(:name) do
+ desc "The full name for this filesystem. (including the zpool)"
+ end
- newproperty(:mountpoint) do
- desc "The mountpoint property."
- end
+ newproperty(:mountpoint) do
+ desc "The mountpoint property."
+ end
- newproperty(:compression) do
- desc "The compression property."
- end
+ newproperty(:compression) do
+ desc "The compression property."
+ end
- newproperty(:copies) do
- desc "The copies property."
- end
+ newproperty(:copies) do
+ desc "The copies property."
+ end
- newproperty(:quota) do
- desc "The quota property."
- end
+ newproperty(:quota) do
+ desc "The quota property."
+ end
- newproperty(:reservation) do
- desc "The reservation property."
- end
+ newproperty(:reservation) do
+ desc "The reservation property."
+ end
- newproperty(:sharenfs) do
- desc "The sharenfs property."
- end
+ newproperty(:sharenfs) do
+ desc "The sharenfs property."
+ end
- newproperty(:snapdir) do
- desc "The sharenfs property."
- end
+ newproperty(:snapdir) do
+ desc "The sharenfs property."
+ end
- autorequire(:zpool) do
- #strip the zpool off the zfs name and autorequire it
- [@parameters[:name].value.split('/')[0]]
- end
+ autorequire(:zpool) do
+ #strip the zpool off the zfs name and autorequire it
+ [@parameters[:name].value.split('/')[0]]
+ end
- autorequire(:zfs) do
- #slice and dice, we want all the zfs before this one
- names = @parameters[:name].value.split('/')
- names.slice(1..-2).inject([]) { |a,v| a << "#{a.last}/#{v}" }.collect { |fs| names[0] + fs }
- end
+ autorequire(:zfs) do
+ #slice and dice, we want all the zfs before this one
+ names = @parameters[:name].value.split('/')
+ names.slice(1..-2).inject([]) { |a,v| a << "#{a.last}/#{v}" }.collect { |fs| names[0] + fs }
end
+ end
end
diff --git a/lib/puppet/type/zone.rb b/lib/puppet/type/zone.rb
index 9d972a17a..d523c469a 100644
--- a/lib/puppet/type/zone.rb
+++ b/lib/puppet/type/zone.rb
@@ -1,444 +1,444 @@
Puppet::Type.newtype(:zone) do
- @doc = "Solaris zones."
-
- # These properties modify the zone configuration, and they need to provide
- # the text separately from syncing it, so all config statements can be rolled
- # into a single creation statement.
- class ZoneConfigProperty < Puppet::Property
- # Perform the config operation.
- def sync
- provider.setconfig self.configtext
- end
+ @doc = "Solaris zones."
+
+ # These properties modify the zone configuration, and they need to provide
+ # the text separately from syncing it, so all config statements can be rolled
+ # into a single creation statement.
+ class ZoneConfigProperty < Puppet::Property
+ # Perform the config operation.
+ def sync
+ provider.setconfig self.configtext
end
+ end
- # Those properties that can have multiple instances.
- class ZoneMultiConfigProperty < ZoneConfigProperty
- def configtext
- list = @should
-
- current_value = self.retrieve
-
- unless current_value.is_a? Symbol
- if current_value.is_a? Array
- list += current_value
- else
- list << current_value if current_value
- end
- end
-
- # Some hackery so we can test whether current_value is an array or a symbol
- if current_value.is_a? Array
- tmpis = current_value
- else
- if current_value
- tmpis = [current_value]
- else
- tmpis = []
- end
- end
+ # Those properties that can have multiple instances.
+ class ZoneMultiConfigProperty < ZoneConfigProperty
+ def configtext
+ list = @should
- rms = []
- adds = []
+ current_value = self.retrieve
- # Collect the modifications to make
- list.sort.uniq.collect do |obj|
- # Skip objectories that are configured and should be
- next if tmpis.include?(obj) and @should.include?(obj)
-
- if tmpis.include?(obj)
- rms << obj
- else
- adds << obj
- end
- end
-
-
- # And then perform all of the removals before any of the adds.
- (rms.collect { |o| rm(o) } + adds.collect { |o| add(o) }).join("\n")
+ unless current_value.is_a? Symbol
+ if current_value.is_a? Array
+ list += current_value
+ else
+ list << current_value if current_value
end
-
- # We want all specified directories to be included.
- def insync?(current_value)
- if current_value.is_a? Array and @should.is_a? Array
- current_value.sort == @should.sort
- else
- current_value == @should
- end
+ end
+
+ # Some hackery so we can test whether current_value is an array or a symbol
+ if current_value.is_a? Array
+ tmpis = current_value
+ else
+ if current_value
+ tmpis = [current_value]
+ else
+ tmpis = []
end
- end
+ end
- ensurable do
- desc "The running state of the zone. The valid states directly reflect
- the states that ``zoneadm`` provides. The states are linear,
- in that a zone must be ``configured`` then ``installed``, and
- only then can be ``running``. Note also that ``halt`` is currently
- used to stop zones."
+ rms = []
+ adds = []
- @states = {}
- @parametervalues = []
+ # Collect the modifications to make
+ list.sort.uniq.collect do |obj|
+ # Skip objectories that are configured and should be
+ next if tmpis.include?(obj) and @should.include?(obj)
- def self.alias_state(values)
- @state_aliases ||= {}
- values.each do |nick, name|
- @state_aliases[nick] = name
- end
+ if tmpis.include?(obj)
+ rms << obj
+ else
+ adds << obj
end
+ end
- def self.newvalue(name, hash)
- @parametervalues = [] if @parametervalues.is_a? Hash
- @parametervalues << name
+ # And then perform all of the removals before any of the adds.
+ (rms.collect { |o| rm(o) } + adds.collect { |o| add(o) }).join("\n")
+ end
- @states[name] = hash
- hash[:name] = name
- end
+ # We want all specified directories to be included.
+ def insync?(current_value)
+ if current_value.is_a? Array and @should.is_a? Array
+ current_value.sort == @should.sort
+ else
+ current_value == @should
+ end
+ end
+ end
+
+ ensurable do
+ desc "The running state of the zone. The valid states directly reflect
+ the states that ``zoneadm`` provides. The states are linear,
+ in that a zone must be ``configured`` then ``installed``, and
+ only then can be ``running``. Note also that ``halt`` is currently
+ used to stop zones."
+
+ @states = {}
+ @parametervalues = []
+
+ def self.alias_state(values)
+ @state_aliases ||= {}
+ values.each do |nick, name|
+ @state_aliases[nick] = name
+ end
+ end
- def self.state_name(name)
- if other = @state_aliases[name]
- other
- else
- name
- end
- end
+ def self.newvalue(name, hash)
+ @parametervalues = [] if @parametervalues.is_a? Hash
- newvalue :absent, :down => :destroy
- newvalue :configured, :up => :configure, :down => :uninstall
- newvalue :installed, :up => :install, :down => :stop
- newvalue :running, :up => :start
+ @parametervalues << name
- alias_state :incomplete => :installed, :ready => :installed, :shutting_down => :running
+ @states[name] = hash
+ hash[:name] = name
+ end
- defaultto :running
+ def self.state_name(name)
+ if other = @state_aliases[name]
+ other
+ else
+ name
+ end
+ end
- def self.state_index(value)
- @parametervalues.index(state_name(value))
- end
+ newvalue :absent, :down => :destroy
+ newvalue :configured, :up => :configure, :down => :uninstall
+ newvalue :installed, :up => :install, :down => :stop
+ newvalue :running, :up => :start
- # Return all of the states between two listed values, exclusive
- # of the first item.
- def self.state_sequence(first, second)
- findex = sindex = nil
- unless findex = @parametervalues.index(state_name(first))
- raise ArgumentError, "'#{first}' is not a valid zone state"
- end
- unless sindex = @parametervalues.index(state_name(second))
- raise ArgumentError, "'#{first}' is not a valid zone state"
- end
- list = nil
-
- # Apparently ranges are unidirectional, so we have to reverse
- # the range op twice.
- if findex > sindex
- list = @parametervalues[sindex..findex].collect do |name|
- @states[name]
- end.reverse
- else
- list = @parametervalues[findex..sindex].collect do |name|
- @states[name]
- end
- end
+ alias_state :incomplete => :installed, :ready => :installed, :shutting_down => :running
- # The first result is the current state, so don't return it.
- list[1..-1]
- end
+ defaultto :running
- def retrieve
- provider.properties[:ensure]
+ def self.state_index(value)
+ @parametervalues.index(state_name(value))
+ end
+
+ # Return all of the states between two listed values, exclusive
+ # of the first item.
+ def self.state_sequence(first, second)
+ findex = sindex = nil
+ unless findex = @parametervalues.index(state_name(first))
+ raise ArgumentError, "'#{first}' is not a valid zone state"
+ end
+ unless sindex = @parametervalues.index(state_name(second))
+ raise ArgumentError, "'#{first}' is not a valid zone state"
+ end
+ list = nil
+
+ # Apparently ranges are unidirectional, so we have to reverse
+ # the range op twice.
+ if findex > sindex
+ list = @parametervalues[sindex..findex].collect do |name|
+ @states[name]
+ end.reverse
+ else
+ list = @parametervalues[findex..sindex].collect do |name|
+ @states[name]
end
+ end
- def sync
- method = nil
- if up?
- direction = :up
- else
- direction = :down
- end
+ # The first result is the current state, so don't return it.
+ list[1..-1]
+ end
- # We need to get the state we're currently in and just call
- # everything between it and us.
- self.class.state_sequence(self.retrieve, self.should).each do |state|
- if method = state[direction]
- warned = false
- while provider.processing?
- unless warned
- info "Waiting for zone to finish processing"
- warned = true
- end
- sleep 1
- end
- provider.send(method)
- else
- raise Puppet::DevError, "Cannot move #{direction} from #{st[:name]}"
- end
- end
+ def retrieve
+ provider.properties[:ensure]
+ end
- ("zone_#{self.should}").intern
+ def sync
+ method = nil
+ if up?
+ direction = :up
+ else
+ direction = :down
+ end
+
+ # We need to get the state we're currently in and just call
+ # everything between it and us.
+ self.class.state_sequence(self.retrieve, self.should).each do |state|
+ if method = state[direction]
+ warned = false
+ while provider.processing?
+ unless warned
+ info "Waiting for zone to finish processing"
+ warned = true
+ end
+ sleep 1
+ end
+ provider.send(method)
+ else
+ raise Puppet::DevError, "Cannot move #{direction} from #{st[:name]}"
end
+ end
- # Are we moving up the property tree?
- def up?
- current_value = self.retrieve
- self.class.state_index(current_value) < self.class.state_index(self.should)
- end
+ ("zone_#{self.should}").intern
end
- newparam(:name) do
- desc "The name of the zone."
-
- isnamevar
+ # Are we moving up the property tree?
+ def up?
+ current_value = self.retrieve
+ self.class.state_index(current_value) < self.class.state_index(self.should)
end
-
- newparam(:id) do
- desc "The numerical ID of the zone. This number is autogenerated
- and cannot be changed."
+ end
+
+ newparam(:name) do
+ desc "The name of the zone."
+
+ isnamevar
+ end
+
+ newparam(:id) do
+ desc "The numerical ID of the zone. This number is autogenerated
+ and cannot be changed."
+ end
+
+ newparam(:clone) do
+ desc "Instead of installing the zone, clone it from another zone.
+ If the zone root resides on a zfs file system, a snapshot will be
+ used to create the clone, is it redisides on ufs, a copy of the zone
+ will be used. The zone you clone from must not be running."
+ end
+
+ newproperty(:ip, :parent => ZoneMultiConfigProperty) do
+ require 'ipaddr'
+
+ desc "The IP address of the zone. IP addresses must be specified
+ with the interface, separated by a colon, e.g.: bge0:192.168.0.1.
+ For multiple interfaces, specify them in an array."
+
+ # Add an interface.
+ def add(str)
+ interface, ip, defrouter = ipsplit(str)
+ cmd = "add net\n"
+ cmd += "set physical=#{interface}\n" if interface
+ cmd += "set address=#{ip}\n" if ip
+ cmd += "set defrouter=#{defrouter}\n" if defrouter
+ #if @resource[:iptype] == :shared
+ cmd += "end\n"
end
- newparam(:clone) do
- desc "Instead of installing the zone, clone it from another zone.
- If the zone root resides on a zfs file system, a snapshot will be
- used to create the clone, is it redisides on ufs, a copy of the zone
- will be used. The zone you clone from must not be running."
+ # Convert a string into the component interface, address and defrouter
+ def ipsplit(str)
+ interface, address, defrouter = str.split(':')
+ return interface, address, defrouter
end
- newproperty(:ip, :parent => ZoneMultiConfigProperty) do
- require 'ipaddr'
-
- desc "The IP address of the zone. IP addresses must be specified
- with the interface, separated by a colon, e.g.: bge0:192.168.0.1.
- For multiple interfaces, specify them in an array."
-
- # Add an interface.
- def add(str)
- interface, ip, defrouter = ipsplit(str)
- cmd = "add net\n"
- cmd += "set physical=#{interface}\n" if interface
- cmd += "set address=#{ip}\n" if ip
- cmd += "set defrouter=#{defrouter}\n" if defrouter
- #if @resource[:iptype] == :shared
- cmd += "end\n"
- end
-
- # Convert a string into the component interface, address and defrouter
- def ipsplit(str)
- interface, address, defrouter = str.split(':')
- return interface, address, defrouter
- end
-
- # Remove an interface.
- def rm(str)
- interface, ip, defrouter = ipsplit(str)
- # Reality seems to disagree with the documentation here; the docs
- # specify that braces are required, but they're apparently only
- # required if you're specifying multiple values.
- if ip
- "remove net address=#{ip}"
- elsif interface
- "remove net interface=#{interface}"
- else
- raise ArgumentError, "can not remove network based on default router"
- end
- end
+ # Remove an interface.
+ def rm(str)
+ interface, ip, defrouter = ipsplit(str)
+ # Reality seems to disagree with the documentation here; the docs
+ # specify that braces are required, but they're apparently only
+ # required if you're specifying multiple values.
+ if ip
+ "remove net address=#{ip}"
+ elsif interface
+ "remove net interface=#{interface}"
+ else
+ raise ArgumentError, "can not remove network based on default router"
+ end
end
+ end
- newproperty(:iptype, :parent => ZoneConfigProperty) do
- desc "The IP stack type of the zone. Can either be 'shared' or 'exclusive'."
+ newproperty(:iptype, :parent => ZoneConfigProperty) do
+ desc "The IP stack type of the zone. Can either be 'shared' or 'exclusive'."
- defaultto :shared
+ defaultto :shared
- newvalue :shared
- newvalue :exclusive
+ newvalue :shared
+ newvalue :exclusive
- def configtext
- "set ip-type=#{self.should}"
- end
+ def configtext
+ "set ip-type=#{self.should}"
end
+ end
- newproperty(:autoboot, :parent => ZoneConfigProperty) do
- desc "Whether the zone should automatically boot."
+ newproperty(:autoboot, :parent => ZoneConfigProperty) do
+ desc "Whether the zone should automatically boot."
- defaultto true
+ defaultto true
- newvalue(:true) {}
- newvalue(:false) {}
+ newvalue(:true) {}
+ newvalue(:false) {}
- def configtext
- "set autoboot=#{self.should}"
- end
+ def configtext
+ "set autoboot=#{self.should}"
end
+ end
- newproperty(:pool, :parent => ZoneConfigProperty) do
- desc "The resource pool for this zone."
+ newproperty(:pool, :parent => ZoneConfigProperty) do
+ desc "The resource pool for this zone."
- def configtext
- "set pool=#{self.should}"
- end
+ def configtext
+ "set pool=#{self.should}"
end
+ end
- newproperty(:shares, :parent => ZoneConfigProperty) do
- desc "Number of FSS CPU shares allocated to the zone."
+ newproperty(:shares, :parent => ZoneConfigProperty) do
+ desc "Number of FSS CPU shares allocated to the zone."
- def configtext
- "add rctl\nset name=zone.cpu-shares\nadd value (priv=privileged,limit=#{self.should},action=none)\nend"
- end
+ def configtext
+ "add rctl\nset name=zone.cpu-shares\nadd value (priv=privileged,limit=#{self.should},action=none)\nend"
end
+ end
- newproperty(:inherit, :parent => ZoneMultiConfigProperty) do
- desc "The list of directories that the zone inherits from the global
- zone. All directories must be fully qualified."
+ newproperty(:inherit, :parent => ZoneMultiConfigProperty) do
+ desc "The list of directories that the zone inherits from the global
+ zone. All directories must be fully qualified."
- validate do |value|
- unless value =~ /^\//
- raise ArgumentError, "Inherited filesystems must be fully qualified"
- end
- end
-
- # Add a directory to our list of inherited directories.
- def add(dir)
- "add inherit-pkg-dir\nset dir=#{dir}\nend"
- end
-
- def rm(dir)
- # Reality seems to disagree with the documentation here; the docs
- # specify that braces are required, but they're apparently only
- # required if you're specifying multiple values.
- "remove inherit-pkg-dir dir=#{dir}"
- end
-
- def should
- @should
- end
- end
-
- # Specify the sysidcfg file. This is pretty hackish, because it's
- # only used to boot the zone the very first time.
- newparam(:sysidcfg) do
- desc %{The text to go into the sysidcfg file when the zone is first
- booted. The best way is to use a template::
-
- # $templatedir/sysidcfg
- system_locale=en_US
- timezone=GMT
- terminal=xterms
- security_policy=NONE
- root_password=&lt;%= password %>
- timeserver=localhost
- name_service=DNS {domain_name=&lt;%= domain %> name_server=&lt;%= nameserver %>}
- network_interface=primary {hostname=&lt;%= realhostname %>
- ip_address=&lt;%= ip %>
- netmask=&lt;%= netmask %>
- protocol_ipv6=no
- default_route=&lt;%= defaultroute %>}
- nfs4_domain=dynamic
-
- And then call that::
-
- zone { myzone:
- ip => "bge0:192.168.0.23",
- sysidcfg => template(sysidcfg),
- path => "/opt/zones/myzone",
- realhostname => "fully.qualified.domain.name"
- }
-
- The sysidcfg only matters on the first booting of the zone,
- so Puppet only checks for it at that time.}
+ validate do |value|
+ unless value =~ /^\//
+ raise ArgumentError, "Inherited filesystems must be fully qualified"
+ end
end
- newparam(:path) do
- desc "The root of the zone's filesystem. Must be a fully qualified
- file name. If you include '%s' in the path, then it will be
- replaced with the zone's name. At this point, you cannot use
- Puppet to move a zone."
-
- validate do |value|
- unless value =~ /^\//
- raise ArgumentError, "The zone base must be fully qualified"
- end
- end
-
- munge do |value|
- if value =~ /%s/
- value % @resource[:name]
- else
- value
- end
- end
+ # Add a directory to our list of inherited directories.
+ def add(dir)
+ "add inherit-pkg-dir\nset dir=#{dir}\nend"
end
- newparam(:create_args) do
- desc "Arguments to the zonecfg create command. This can be used to create branded zones."
+ def rm(dir)
+ # Reality seems to disagree with the documentation here; the docs
+ # specify that braces are required, but they're apparently only
+ # required if you're specifying multiple values.
+ "remove inherit-pkg-dir dir=#{dir}"
end
- newparam(:install_args) do
- desc "Arguments to the zoneadm install command. This can be used to create branded zones."
+ def should
+ @should
end
-
- newparam(:realhostname) do
- desc "The actual hostname of the zone."
+ end
+
+ # Specify the sysidcfg file. This is pretty hackish, because it's
+ # only used to boot the zone the very first time.
+ newparam(:sysidcfg) do
+ desc %{The text to go into the sysidcfg file when the zone is first
+ booted. The best way is to use a template::
+
+ # $templatedir/sysidcfg
+ system_locale=en_US
+ timezone=GMT
+ terminal=xterms
+ security_policy=NONE
+ root_password=&lt;%= password %>
+ timeserver=localhost
+ name_service=DNS {domain_name=&lt;%= domain %> name_server=&lt;%= nameserver %>}
+ network_interface=primary {hostname=&lt;%= realhostname %>
+ ip_address=&lt;%= ip %>
+ netmask=&lt;%= netmask %>
+ protocol_ipv6=no
+ default_route=&lt;%= defaultroute %>}
+ nfs4_domain=dynamic
+
+ And then call that::
+
+ zone { myzone:
+ ip => "bge0:192.168.0.23",
+ sysidcfg => template(sysidcfg),
+ path => "/opt/zones/myzone",
+ realhostname => "fully.qualified.domain.name"
+ }
+
+ The sysidcfg only matters on the first booting of the zone,
+ so Puppet only checks for it at that time.}
+ end
+
+ newparam(:path) do
+ desc "The root of the zone's filesystem. Must be a fully qualified
+ file name. If you include '%s' in the path, then it will be
+ replaced with the zone's name. At this point, you cannot use
+ Puppet to move a zone."
+
+ validate do |value|
+ unless value =~ /^\//
+ raise ArgumentError, "The zone base must be fully qualified"
+ end
end
- # If Puppet is also managing the base dir or its parent dir, list them
- # both as prerequisites.
- autorequire(:file) do
- if @parameters.include? :path
- [@parameters[:path].value, File.dirname(@parameters[:path].value)]
- else
- nil
- end
+ munge do |value|
+ if value =~ /%s/
+ value % @resource[:name]
+ else
+ value
+ end
end
-
- def validate_ip(ip, name)
- IPAddr.new(ip) if ip
- rescue ArgumentError
- self.fail "'#{ip}' is an invalid #{name}"
+ end
+
+ newparam(:create_args) do
+ desc "Arguments to the zonecfg create command. This can be used to create branded zones."
+ end
+
+ newparam(:install_args) do
+ desc "Arguments to the zoneadm install command. This can be used to create branded zones."
+ end
+
+ newparam(:realhostname) do
+ desc "The actual hostname of the zone."
+ end
+
+ # If Puppet is also managing the base dir or its parent dir, list them
+ # both as prerequisites.
+ autorequire(:file) do
+ if @parameters.include? :path
+ [@parameters[:path].value, File.dirname(@parameters[:path].value)]
+ else
+ nil
end
-
- validate do
- value = self[:ip]
- interface, address, defrouter = value.split(':')
- if self[:iptype] == :shared
- if (interface && address && defrouter.nil?) ||
- (interface && address && defrouter)
- validate_ip(address, "IP address")
- validate_ip(defrouter, "default router")
- else
- self.fail "ip must contain interface name and ip address separated by a \":\""
- end
- else
- self.fail "only interface may be specified when using exclusive IP stack: #{value}" unless interface && address.nil? && defrouter.nil?
- end
-
- self.fail "zone path is required" unless self[:path]
+ end
+
+ def validate_ip(ip, name)
+ IPAddr.new(ip) if ip
+ rescue ArgumentError
+ self.fail "'#{ip}' is an invalid #{name}"
+ end
+
+ validate do
+ value = self[:ip]
+ interface, address, defrouter = value.split(':')
+ if self[:iptype] == :shared
+ if (interface && address && defrouter.nil?) ||
+ (interface && address && defrouter)
+ validate_ip(address, "IP address")
+ validate_ip(defrouter, "default router")
+ else
+ self.fail "ip must contain interface name and ip address separated by a \":\""
+ end
+ else
+ self.fail "only interface may be specified when using exclusive IP stack: #{value}" unless interface && address.nil? && defrouter.nil?
end
- def retrieve
- provider.flush
- if hash = provider.properties and hash[:ensure] != :absent
- result = setstatus(hash)
- result
- else
- # Return all properties as absent.
- return properties.inject({}) do | prophash, property|
- prophash[property] = :absent
- prophash
- end
- end
+ self.fail "zone path is required" unless self[:path]
+ end
+
+ def retrieve
+ provider.flush
+ if hash = provider.properties and hash[:ensure] != :absent
+ result = setstatus(hash)
+ result
+ else
+ # Return all properties as absent.
+ return properties.inject({}) do | prophash, property|
+ prophash[property] = :absent
+ prophash
+ end
end
-
- # Take the results of a listing and set everything appropriately.
- def setstatus(hash)
- prophash = {}
- hash.each do |param, value|
- next if param == :name
- case self.class.attrtype(param)
- when :property
- # Only try to provide values for the properties we're managing
- if prop = self.property(param)
- prophash[prop] = value
- end
- else
- self[param] = value
- end
+ end
+
+ # Take the results of a listing and set everything appropriately.
+ def setstatus(hash)
+ prophash = {}
+ hash.each do |param, value|
+ next if param == :name
+ case self.class.attrtype(param)
+ when :property
+ # Only try to provide values for the properties we're managing
+ if prop = self.property(param)
+ prophash[prop] = value
end
- prophash
+ else
+ self[param] = value
+ end
end
+ prophash
+ end
end
diff --git a/lib/puppet/type/zpool.rb b/lib/puppet/type/zpool.rb
index e6dec62fc..80e635504 100755
--- a/lib/puppet/type/zpool.rb
+++ b/lib/puppet/type/zpool.rb
@@ -1,87 +1,87 @@
module Puppet
- class Property
+ class Property
- class VDev < Property
+ class VDev < Property
- def flatten_and_sort(array)
- array.collect { |a| a.split(' ') }.flatten.sort
- end
+ def flatten_and_sort(array)
+ array.collect { |a| a.split(' ') }.flatten.sort
+ end
- def insync?(is)
- return true unless self.should
+ def insync?(is)
+ return true unless self.should
- return @should == [:absent] if is == :absent
+ return @should == [:absent] if is == :absent
- flatten_and_sort(is) == flatten_and_sort(@should)
- end
- end
+ flatten_and_sort(is) == flatten_and_sort(@should)
+ end
+ end
- class MultiVDev < VDev
- def insync?(is)
- return true unless self.should
+ class MultiVDev < VDev
+ def insync?(is)
+ return true unless self.should
- return @should == [:absent] if is == :absent
+ return @should == [:absent] if is == :absent
- return false unless is.length == @should.length
+ return false unless is.length == @should.length
- is.each_with_index { |list, i| return false unless flatten_and_sort(list) == flatten_and_sort(@should[i]) }
+ is.each_with_index { |list, i| return false unless flatten_and_sort(list) == flatten_and_sort(@should[i]) }
- #if we made it this far we are in sync
- true
- end
- end
+ #if we made it this far we are in sync
+ true
+ end
end
+ end
- newtype(:zpool) do
- @doc = "Manage zpools. Create and delete zpools. The provider WILL NOT SYNC, only report differences.
+ newtype(:zpool) do
+ @doc = "Manage zpools. Create and delete zpools. The provider WILL NOT SYNC, only report differences.
- Supports vdevs with mirrors, raidz, logs and spares."
+ Supports vdevs with mirrors, raidz, logs and spares."
- ensurable
+ ensurable
- newproperty(:disk, :array_matching => :all, :parent => Puppet::Property::VDev) do
- desc "The disk(s) for this pool. Can be an array or space separated string"
- end
+ newproperty(:disk, :array_matching => :all, :parent => Puppet::Property::VDev) do
+ desc "The disk(s) for this pool. Can be an array or space separated string"
+ end
- newproperty(:mirror, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do
- desc "List of all the devices to mirror for this pool. Each mirror should be a space separated string.
- mirror => [\"disk1 disk2\", \"disk3 disk4\"]"
+ newproperty(:mirror, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do
+ desc "List of all the devices to mirror for this pool. Each mirror should be a space separated string.
+ mirror => [\"disk1 disk2\", \"disk3 disk4\"]"
- validate do |value|
- raise ArgumentError, "mirror names must be provided as string separated, not a comma-separated list" if value.include?(",")
- end
- end
+ validate do |value|
+ raise ArgumentError, "mirror names must be provided as string separated, not a comma-separated list" if value.include?(",")
+ end
+ end
- newproperty(:raidz, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do
- desc "List of all the devices to raid for this pool. Should be an array of space separated strings.
- raidz => [\"disk1 disk2\", \"disk3 disk4\"]"
+ newproperty(:raidz, :array_matching => :all, :parent => Puppet::Property::MultiVDev) do
+ desc "List of all the devices to raid for this pool. Should be an array of space separated strings.
+ raidz => [\"disk1 disk2\", \"disk3 disk4\"]"
- validate do |value|
- raise ArgumentError, "raid names must be provided as string separated, not a comma-separated list" if value.include?(",")
- end
- end
+ validate do |value|
+ raise ArgumentError, "raid names must be provided as string separated, not a comma-separated list" if value.include?(",")
+ end
+ end
- newproperty(:spare, :array_matching => :all, :parent => Puppet::Property::VDev) do
- desc "Spare disk(s) for this pool."
- end
+ newproperty(:spare, :array_matching => :all, :parent => Puppet::Property::VDev) do
+ desc "Spare disk(s) for this pool."
+ end
- newproperty(:log, :array_matching => :all, :parent => Puppet::Property::VDev) do
- desc "Log disks for this pool. (doesn't support mirroring yet)"
- end
+ newproperty(:log, :array_matching => :all, :parent => Puppet::Property::VDev) do
+ desc "Log disks for this pool. (doesn't support mirroring yet)"
+ end
- newparam(:pool) do
- desc "The name for this pool."
- isnamevar
- end
+ newparam(:pool) do
+ desc "The name for this pool."
+ isnamevar
+ end
- newparam(:raid_parity) do
- desc "Determines parity when using raidz property."
- end
+ newparam(:raid_parity) do
+ desc "Determines parity when using raidz property."
+ end
- validate do
- has_should = [:disk, :mirror, :raidz].select { |prop| self.should(prop) }
- self.fail "You cannot specify #{has_should.join(" and ")} on this type (only one)" if has_should.length > 1
- end
+ validate do
+ has_should = [:disk, :mirror, :raidz].select { |prop| self.should(prop) }
+ self.fail "You cannot specify #{has_should.join(" and ")} on this type (only one)" if has_should.length > 1
end
+ end
end
diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb
index 221365a03..bb4127089 100644
--- a/lib/puppet/util.rb
+++ b/lib/puppet/util.rb
@@ -5,441 +5,441 @@ require 'sync'
require 'puppet/external/lock'
module Puppet
- # A command failed to execute.
- require 'puppet/error'
- class ExecutionFailure < Puppet::Error
- end
+ # A command failed to execute.
+ require 'puppet/error'
+ class ExecutionFailure < Puppet::Error
+ end
module Util
- require 'benchmark'
-
- # These are all for backward compatibility -- these are methods that used
- # to be in Puppet::Util but have been moved into external modules.
- require 'puppet/util/posix'
- extend Puppet::Util::POSIX
-
- # Create a hash to store the different sync objects.
- @@syncresources = {}
-
- # Return the sync object associated with a given resource.
- def self.sync(resource)
- @@syncresources[resource] ||= Sync.new
- @@syncresources[resource]
- end
-
- # Change the process to a different user
- def self.chuser
- if group = Puppet[:group]
- group = self.gid(group)
- raise Puppet::Error, "No such group #{Puppet[:group]}" unless group
- unless Puppet::Util::SUIDManager.gid == group
- begin
- Puppet::Util::SUIDManager.egid = group
- Puppet::Util::SUIDManager.gid = group
- rescue => detail
- Puppet.warning "could not change to group #{group.inspect}: #{detail}"
- $stderr.puts "could not change to group #{group.inspect}"
-
- # Don't exit on failed group changes, since it's
- # not fatal
- #exit(74)
- end
- end
+ require 'benchmark'
+
+ # These are all for backward compatibility -- these are methods that used
+ # to be in Puppet::Util but have been moved into external modules.
+ require 'puppet/util/posix'
+ extend Puppet::Util::POSIX
+
+ # Create a hash to store the different sync objects.
+ @@syncresources = {}
+
+ # Return the sync object associated with a given resource.
+ def self.sync(resource)
+ @@syncresources[resource] ||= Sync.new
+ @@syncresources[resource]
+ end
+
+ # Change the process to a different user
+ def self.chuser
+ if group = Puppet[:group]
+ group = self.gid(group)
+ raise Puppet::Error, "No such group #{Puppet[:group]}" unless group
+ unless Puppet::Util::SUIDManager.gid == group
+ begin
+ Puppet::Util::SUIDManager.egid = group
+ Puppet::Util::SUIDManager.gid = group
+ rescue => detail
+ Puppet.warning "could not change to group #{group.inspect}: #{detail}"
+ $stderr.puts "could not change to group #{group.inspect}"
+
+ # Don't exit on failed group changes, since it's
+ # not fatal
+ #exit(74)
end
+ end
+ end
- if user = Puppet[:user]
- user = self.uid(user)
- raise Puppet::Error, "No such user #{Puppet[:user]}" unless user
- unless Puppet::Util::SUIDManager.uid == user
- begin
- Puppet::Util::SUIDManager.initgroups(user)
- Puppet::Util::SUIDManager.uid = user
- Puppet::Util::SUIDManager.euid = user
- rescue => detail
- $stderr.puts "Could not change to user #{user}: #{detail}"
- exit(74)
- end
- end
+ if user = Puppet[:user]
+ user = self.uid(user)
+ raise Puppet::Error, "No such user #{Puppet[:user]}" unless user
+ unless Puppet::Util::SUIDManager.uid == user
+ begin
+ Puppet::Util::SUIDManager.initgroups(user)
+ Puppet::Util::SUIDManager.uid = user
+ Puppet::Util::SUIDManager.euid = user
+ rescue => detail
+ $stderr.puts "Could not change to user #{user}: #{detail}"
+ exit(74)
end
+ end
end
+ end
- # Create instance methods for each of the log levels. This allows
- # the messages to be a little richer. Most classes will be calling this
- # method.
- def self.logmethods(klass, useself = true)
- Puppet::Util::Log.eachlevel { |level|
- klass.send(:define_method, level, proc { |args|
- args = args.join(" ") if args.is_a?(Array)
- if useself
+ # Create instance methods for each of the log levels. This allows
+ # the messages to be a little richer. Most classes will be calling this
+ # method.
+ def self.logmethods(klass, useself = true)
+ Puppet::Util::Log.eachlevel { |level|
+ klass.send(:define_method, level, proc { |args|
+ args = args.join(" ") if args.is_a?(Array)
+ if useself
- Puppet::Util::Log.create(
+ Puppet::Util::Log.create(
- :level => level,
- :source => self,
+ :level => level,
+ :source => self,
- :message => args
- )
- else
-
- Puppet::Util::Log.create(
+ :message => args
+ )
+ else
- :level => level,
+ Puppet::Util::Log.create(
- :message => args
- )
- end
- })
- }
- end
+ :level => level,
- # Proxy a bunch of methods to another object.
- def self.classproxy(klass, objmethod, *methods)
- classobj = class << klass; self; end
- methods.each do |method|
- classobj.send(:define_method, method) do |*args|
- obj = self.send(objmethod)
-
- obj.send(method, *args)
- end
+ :message => args
+ )
end
+ })
+ }
+ end
+
+ # Proxy a bunch of methods to another object.
+ def self.classproxy(klass, objmethod, *methods)
+ classobj = class << klass; self; end
+ methods.each do |method|
+ classobj.send(:define_method, method) do |*args|
+ obj = self.send(objmethod)
+
+ obj.send(method, *args)
+ end
end
+ end
- # Proxy a bunch of methods to another object.
- def self.proxy(klass, objmethod, *methods)
- methods.each do |method|
- klass.send(:define_method, method) do |*args|
- obj = self.send(objmethod)
+ # Proxy a bunch of methods to another object.
+ def self.proxy(klass, objmethod, *methods)
+ methods.each do |method|
+ klass.send(:define_method, method) do |*args|
+ obj = self.send(objmethod)
- obj.send(method, *args)
- end
- end
+ obj.send(method, *args)
+ end
end
-
- # XXX this should all be done using puppet objects, not using
- # normal mkdir
- def self.recmkdir(dir,mode = 0755)
- if FileTest.exist?(dir)
- return false
- else
- tmp = dir.sub(/^\//,'')
- path = [File::SEPARATOR]
- tmp.split(File::SEPARATOR).each { |dir|
- path.push dir
- if ! FileTest.exist?(File.join(path))
- Dir.mkdir(File.join(path), mode)
- elsif FileTest.directory?(File.join(path))
- next
- else FileTest.exist?(File.join(path))
- raise "Cannot create #{dir}: basedir #{File.join(path)} is a file"
- end
- }
- return true
+ end
+
+ # XXX this should all be done using puppet objects, not using
+ # normal mkdir
+ def self.recmkdir(dir,mode = 0755)
+ if FileTest.exist?(dir)
+ return false
+ else
+ tmp = dir.sub(/^\//,'')
+ path = [File::SEPARATOR]
+ tmp.split(File::SEPARATOR).each { |dir|
+ path.push dir
+ if ! FileTest.exist?(File.join(path))
+ Dir.mkdir(File.join(path), mode)
+ elsif FileTest.directory?(File.join(path))
+ next
+ else FileTest.exist?(File.join(path))
+ raise "Cannot create #{dir}: basedir #{File.join(path)} is a file"
end
+ }
+ return true
end
+ end
- # Execute a given chunk of code with a new umask.
- def self.withumask(mask)
- cur = File.umask(mask)
+ # Execute a given chunk of code with a new umask.
+ def self.withumask(mask)
+ cur = File.umask(mask)
- begin
- yield
- ensure
- File.umask(cur)
- end
+ begin
+ yield
+ ensure
+ File.umask(cur)
+ end
+ end
+
+ def benchmark(*args)
+ msg = args.pop
+ level = args.pop
+ object = nil
+
+ if args.empty?
+ if respond_to?(level)
+ object = self
+ else
+ object = Puppet
+ end
+ else
+ object = args.pop
end
- def benchmark(*args)
- msg = args.pop
- level = args.pop
- object = nil
-
- if args.empty?
- if respond_to?(level)
- object = self
- else
- object = Puppet
- end
- else
- object = args.pop
- end
-
- raise Puppet::DevError, "Failed to provide level to :benchmark" unless level
+ raise Puppet::DevError, "Failed to provide level to :benchmark" unless level
- unless level == :none or object.respond_to? level
- raise Puppet::DevError, "Benchmarked object does not respond to #{level}"
- end
-
- # Only benchmark if our log level is high enough
- if level != :none and Puppet::Util::Log.sendlevel?(level)
- result = nil
- seconds = Benchmark.realtime {
- yield
- }
- object.send(level, msg + (" in %0.2f seconds" % seconds))
- return seconds
- else
- yield
- end
+ unless level == :none or object.respond_to? level
+ raise Puppet::DevError, "Benchmarked object does not respond to #{level}"
end
- def binary(bin)
- if bin =~ /^\//
- return bin if FileTest.file? bin and FileTest.executable? bin
- else
- ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
- dest=File.join(dir, bin)
- return dest if FileTest.file? dest and FileTest.executable? dest
- end
- end
- nil
+ # Only benchmark if our log level is high enough
+ if level != :none and Puppet::Util::Log.sendlevel?(level)
+ result = nil
+ seconds = Benchmark.realtime {
+ yield
+ }
+ object.send(level, msg + (" in %0.2f seconds" % seconds))
+ return seconds
+ else
+ yield
end
- module_function :binary
-
- # Execute the provided command in a pipe, yielding the pipe object.
- def execpipe(command, failonfail = true)
- if respond_to? :debug
- debug "Executing '#{command}'"
- else
- Puppet.debug "Executing '#{command}'"
- end
-
- output = open("| #{command} 2>&1") do |pipe|
- yield pipe
- end
-
- if failonfail
- unless $CHILD_STATUS == 0
- raise ExecutionFailure, output
- end
- end
-
- output
+ end
+
+ def binary(bin)
+ if bin =~ /^\//
+ return bin if FileTest.file? bin and FileTest.executable? bin
+ else
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |dir|
+ dest=File.join(dir, bin)
+ return dest if FileTest.file? dest and FileTest.executable? dest
+ end
+ end
+ nil
+ end
+ module_function :binary
+
+ # Execute the provided command in a pipe, yielding the pipe object.
+ def execpipe(command, failonfail = true)
+ if respond_to? :debug
+ debug "Executing '#{command}'"
+ else
+ Puppet.debug "Executing '#{command}'"
end
- def execfail(command, exception)
- output = execute(command)
- return output
- rescue ExecutionFailure
- raise exception, output
+ output = open("| #{command} 2>&1") do |pipe|
+ yield pipe
end
- # Execute the desired command, and return the status and output.
- # def execute(command, failonfail = true, uid = nil, gid = nil)
- # :combine sets whether or not to combine stdout/stderr in the output
- # :stdinfile sets a file that can be used for stdin. Passing a string
- # for stdin is not currently supported.
- def execute(command, arguments = {:failonfail => true, :combine => true})
- if command.is_a?(Array)
- command = command.flatten.collect { |i| i.to_s }
- str = command.join(" ")
- else
- # We require an array here so we know where we're incorrectly
- # using a string instead of an array. Once everything is
- # switched to an array, we might relax this requirement.
- raise ArgumentError, "Must pass an array to execute()"
- end
+ if failonfail
+ unless $CHILD_STATUS == 0
+ raise ExecutionFailure, output
+ end
+ end
- if respond_to? :debug
- debug "Executing '#{str}'"
- else
- Puppet.debug "Executing '#{str}'"
- end
+ output
+ end
+
+ def execfail(command, exception)
+ output = execute(command)
+ return output
+ rescue ExecutionFailure
+ raise exception, output
+ end
+
+ # Execute the desired command, and return the status and output.
+ # def execute(command, failonfail = true, uid = nil, gid = nil)
+ # :combine sets whether or not to combine stdout/stderr in the output
+ # :stdinfile sets a file that can be used for stdin. Passing a string
+ # for stdin is not currently supported.
+ def execute(command, arguments = {:failonfail => true, :combine => true})
+ if command.is_a?(Array)
+ command = command.flatten.collect { |i| i.to_s }
+ str = command.join(" ")
+ else
+ # We require an array here so we know where we're incorrectly
+ # using a string instead of an array. Once everything is
+ # switched to an array, we might relax this requirement.
+ raise ArgumentError, "Must pass an array to execute()"
+ end
- arguments[:uid] = Puppet::Util::SUIDManager.convert_xid(:uid, arguments[:uid]) if arguments[:uid]
- arguments[:gid] = Puppet::Util::SUIDManager.convert_xid(:gid, arguments[:gid]) if arguments[:gid]
-
- @@os ||= Facter.value(:operatingsystem)
- output = nil
- child_pid, child_status = nil
- # There are problems with read blocking with badly behaved children
- # read.partialread doesn't seem to capture either stdout or stderr
- # We hack around this using a temporary file
-
- # The idea here is to avoid IO#read whenever possible.
- output_file="/dev/null"
- error_file="/dev/null"
- if ! arguments[:squelch]
- require "tempfile"
- output_file = Tempfile.new("puppet")
- error_file=output_file if arguments[:combine]
- end
+ if respond_to? :debug
+ debug "Executing '#{str}'"
+ else
+ Puppet.debug "Executing '#{str}'"
+ end
- if Puppet.features.posix?
- oldverb = $VERBOSE
- $VERBOSE = nil
- child_pid = Kernel.fork
- $VERBOSE = oldverb
- if child_pid
- # Parent process executes this
- child_status = (Process.waitpid2(child_pid)[1]).to_i >> 8
- else
- # Child process executes this
- Process.setsid
- begin
- if arguments[:stdinfile]
- $stdin.reopen(arguments[:stdinfile])
- else
- $stdin.reopen("/dev/null")
- end
- $stdout.reopen(output_file)
- $stderr.reopen(error_file)
-
- 3.upto(256){|fd| IO::new(fd).close rescue nil}
- if arguments[:gid]
- Process.egid = arguments[:gid]
- Process.gid = arguments[:gid] unless @@os == "Darwin"
- end
- if arguments[:uid]
- Process.euid = arguments[:uid]
- Process.uid = arguments[:uid] unless @@os == "Darwin"
- end
- ENV['LANG'] = ENV['LC_ALL'] = ENV['LC_MESSAGES'] = ENV['LANGUAGE'] = 'C'
- if command.is_a?(Array)
- Kernel.exec(*command)
- else
- Kernel.exec(command)
- end
- rescue => detail
- puts detail.to_s
- exit!(1)
- end
- end
- elsif Puppet.features.microsoft_windows?
- command = command.collect {|part| '"' + part.gsub(/"/, '\\"') + '"'}.join(" ") if command.is_a?(Array)
- Puppet.debug "Creating process '#{command}'"
- processinfo = Process.create( :command_line => command )
- child_status = (Process.waitpid2(child_pid)[1]).to_i >> 8
- end
+ arguments[:uid] = Puppet::Util::SUIDManager.convert_xid(:uid, arguments[:uid]) if arguments[:uid]
+ arguments[:gid] = Puppet::Util::SUIDManager.convert_xid(:gid, arguments[:gid]) if arguments[:gid]
+
+ @@os ||= Facter.value(:operatingsystem)
+ output = nil
+ child_pid, child_status = nil
+ # There are problems with read blocking with badly behaved children
+ # read.partialread doesn't seem to capture either stdout or stderr
+ # We hack around this using a temporary file
+
+ # The idea here is to avoid IO#read whenever possible.
+ output_file="/dev/null"
+ error_file="/dev/null"
+ if ! arguments[:squelch]
+ require "tempfile"
+ output_file = Tempfile.new("puppet")
+ error_file=output_file if arguments[:combine]
+ end
- # read output in if required
- if ! arguments[:squelch]
-
- # Make sure the file's actually there. This is
- # basically a race condition, and is probably a horrible
- # way to handle it, but, well, oh well.
- unless FileTest.exists?(output_file.path)
- Puppet.warning "sleeping"
- sleep 0.5
- unless FileTest.exists?(output_file.path)
- Puppet.warning "sleeping 2"
- sleep 1
- unless FileTest.exists?(output_file.path)
- Puppet.warning "Could not get output"
- output = ""
- end
- end
- end
- unless output
- # We have to explicitly open here, so that it reopens
- # after the child writes.
- output = output_file.open.read
-
- # The 'true' causes the file to get unlinked right away.
- output_file.close(true)
- end
+ if Puppet.features.posix?
+ oldverb = $VERBOSE
+ $VERBOSE = nil
+ child_pid = Kernel.fork
+ $VERBOSE = oldverb
+ if child_pid
+ # Parent process executes this
+ child_status = (Process.waitpid2(child_pid)[1]).to_i >> 8
+ else
+ # Child process executes this
+ Process.setsid
+ begin
+ if arguments[:stdinfile]
+ $stdin.reopen(arguments[:stdinfile])
+ else
+ $stdin.reopen("/dev/null")
+ end
+ $stdout.reopen(output_file)
+ $stderr.reopen(error_file)
+
+ 3.upto(256){|fd| IO::new(fd).close rescue nil}
+ if arguments[:gid]
+ Process.egid = arguments[:gid]
+ Process.gid = arguments[:gid] unless @@os == "Darwin"
+ end
+ if arguments[:uid]
+ Process.euid = arguments[:uid]
+ Process.uid = arguments[:uid] unless @@os == "Darwin"
+ end
+ ENV['LANG'] = ENV['LC_ALL'] = ENV['LC_MESSAGES'] = ENV['LANGUAGE'] = 'C'
+ if command.is_a?(Array)
+ Kernel.exec(*command)
+ else
+ Kernel.exec(command)
+ end
+ rescue => detail
+ puts detail.to_s
+ exit!(1)
end
+ end
+ elsif Puppet.features.microsoft_windows?
+ command = command.collect {|part| '"' + part.gsub(/"/, '\\"') + '"'}.join(" ") if command.is_a?(Array)
+ Puppet.debug "Creating process '#{command}'"
+ processinfo = Process.create( :command_line => command )
+ child_status = (Process.waitpid2(child_pid)[1]).to_i >> 8
+ end
- if arguments[:failonfail]
- unless child_status == 0
- raise ExecutionFailure, "Execution of '#{str}' returned #{child_status}: #{output}"
- end
+ # read output in if required
+ if ! arguments[:squelch]
+
+ # Make sure the file's actually there. This is
+ # basically a race condition, and is probably a horrible
+ # way to handle it, but, well, oh well.
+ unless FileTest.exists?(output_file.path)
+ Puppet.warning "sleeping"
+ sleep 0.5
+ unless FileTest.exists?(output_file.path)
+ Puppet.warning "sleeping 2"
+ sleep 1
+ unless FileTest.exists?(output_file.path)
+ Puppet.warning "Could not get output"
+ output = ""
+ end
end
+ end
+ unless output
+ # We have to explicitly open here, so that it reopens
+ # after the child writes.
+ output = output_file.open.read
+
+ # The 'true' causes the file to get unlinked right away.
+ output_file.close(true)
+ end
+ end
- output
+ if arguments[:failonfail]
+ unless child_status == 0
+ raise ExecutionFailure, "Execution of '#{str}' returned #{child_status}: #{output}"
+ end
end
- module_function :execute
+ output
+ end
- # Create an exclusive lock.
- def threadlock(resource, type = Sync::EX)
- Puppet::Util.sync(resource).synchronize(type) do
- yield
- end
+ module_function :execute
+
+ # Create an exclusive lock.
+ def threadlock(resource, type = Sync::EX)
+ Puppet::Util.sync(resource).synchronize(type) do
+ yield
end
+ end
- # Because some modules provide their own version of this method.
- alias util_execute execute
+ # Because some modules provide their own version of this method.
+ alias util_execute execute
- module_function :benchmark
+ module_function :benchmark
- def memory
- unless defined?(@pmap)
- pmap = %x{which pmap 2>/dev/null}.chomp
- if $CHILD_STATUS != 0 or pmap =~ /^no/
- @pmap = nil
- else
- @pmap = pmap
- end
- end
- if @pmap
- return %x{pmap #{Process.pid}| grep total}.chomp.sub(/^\s*total\s+/, '').sub(/K$/, '').to_i
- else
- 0
- end
+ def memory
+ unless defined?(@pmap)
+ pmap = %x{which pmap 2>/dev/null}.chomp
+ if $CHILD_STATUS != 0 or pmap =~ /^no/
+ @pmap = nil
+ else
+ @pmap = pmap
+ end
end
-
- def symbolize(value)
- if value.respond_to? :intern
- value.intern
- else
- value
- end
+ if @pmap
+ return %x{pmap #{Process.pid}| grep total}.chomp.sub(/^\s*total\s+/, '').sub(/K$/, '').to_i
+ else
+ 0
end
+ end
- def symbolizehash(hash)
- newhash = {}
- hash.each do |name, val|
- if name.is_a? String
- newhash[name.intern] = val
- else
- newhash[name] = val
- end
- end
+ def symbolize(value)
+ if value.respond_to? :intern
+ value.intern
+ else
+ value
end
-
- def symbolizehash!(hash)
- hash.each do |name, val|
- if name.is_a? String
- hash[name.intern] = val
- hash.delete(name)
- end
- end
-
- hash
+ end
+
+ def symbolizehash(hash)
+ newhash = {}
+ hash.each do |name, val|
+ if name.is_a? String
+ newhash[name.intern] = val
+ else
+ newhash[name] = val
+ end
end
- module_function :symbolize, :symbolizehash, :symbolizehash!
-
- # Just benchmark, with no logging.
- def thinmark
- seconds = Benchmark.realtime {
- yield
- }
-
- seconds
+ end
+
+ def symbolizehash!(hash)
+ hash.each do |name, val|
+ if name.is_a? String
+ hash[name.intern] = val
+ hash.delete(name)
+ end
end
- module_function :memory, :thinmark
-
- def secure_open(file,must_be_w,&block)
- raise Puppet::DevError,"secure_open only works with mode 'w'" unless must_be_w == 'w'
- raise Puppet::DevError,"secure_open only requires a block" unless block_given?
- Puppet.warning "#{file} was a symlink to #{File.readlink(file)}" if File.symlink?(file)
- if File.exists?(file) or File.symlink?(file)
- wait = File.symlink?(file) ? 5.0 : 0.1
- File.delete(file)
- sleep wait # give it a chance to reappear, just in case someone is actively trying something.
- end
- begin
- File.open(file,File::CREAT|File::EXCL|File::TRUNC|File::WRONLY,&block)
- rescue Errno::EEXIST
- desc = File.symlink?(file) ? "symlink to #{File.readlink(file)}" : File.stat(file).ftype
- puts "Warning: #{file} was apparently created by another process (as"
- puts "a #{desc}) as soon as it was deleted by this process. Someone may be trying"
- puts "to do something objectionable (such as tricking you into overwriting system"
- puts "files if you are running as root)."
- raise
- end
+ hash
+ end
+ module_function :symbolize, :symbolizehash, :symbolizehash!
+
+ # Just benchmark, with no logging.
+ def thinmark
+ seconds = Benchmark.realtime {
+ yield
+ }
+
+ seconds
+ end
+
+ module_function :memory, :thinmark
+
+ def secure_open(file,must_be_w,&block)
+ raise Puppet::DevError,"secure_open only works with mode 'w'" unless must_be_w == 'w'
+ raise Puppet::DevError,"secure_open only requires a block" unless block_given?
+ Puppet.warning "#{file} was a symlink to #{File.readlink(file)}" if File.symlink?(file)
+ if File.exists?(file) or File.symlink?(file)
+ wait = File.symlink?(file) ? 5.0 : 0.1
+ File.delete(file)
+ sleep wait # give it a chance to reappear, just in case someone is actively trying something.
+ end
+ begin
+ File.open(file,File::CREAT|File::EXCL|File::TRUNC|File::WRONLY,&block)
+ rescue Errno::EEXIST
+ desc = File.symlink?(file) ? "symlink to #{File.readlink(file)}" : File.stat(file).ftype
+ puts "Warning: #{file} was apparently created by another process (as"
+ puts "a #{desc}) as soon as it was deleted by this process. Someone may be trying"
+ puts "to do something objectionable (such as tricking you into overwriting system"
+ puts "files if you are running as root)."
+ raise
end
- module_function :secure_open
+ end
+ module_function :secure_open
end
end
diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb
index 21f99e4c0..c293ac14a 100644
--- a/lib/puppet/util/autoload.rb
+++ b/lib/puppet/util/autoload.rb
@@ -3,142 +3,142 @@ require 'puppet/util/cacher'
# Autoload paths, either based on names or all at once.
class Puppet::Util::Autoload
- require 'puppet/util/autoload/file_cache'
+ require 'puppet/util/autoload/file_cache'
- include Puppet::Util
- include Puppet::Util::Warnings
- include Puppet::Util::Cacher
- include Puppet::Util::Autoload::FileCache
+ include Puppet::Util
+ include Puppet::Util::Warnings
+ include Puppet::Util::Cacher
+ include Puppet::Util::Autoload::FileCache
- @autoloaders = {}
- @loaded = []
+ @autoloaders = {}
+ @loaded = []
- class << self
- attr_reader :autoloaders
- private :autoloaders
- end
-
- # Send [], []=, and :clear to the @autloaders hash
- Puppet::Util.classproxy self, :autoloaders, "[]", "[]="
+ class << self
+ attr_reader :autoloaders
+ private :autoloaders
+ end
- # List all loaded files.
- def self.list_loaded
- @loaded.sort { |a,b| a[0] <=> b[0] }.collect do |path, hash|
- "#{path}: #{hash[:file]}"
- end
- end
+ # Send [], []=, and :clear to the @autloaders hash
+ Puppet::Util.classproxy self, :autoloaders, "[]", "[]="
- # Has a given path been loaded? This is used for testing whether a
- # changed file should be loaded or just ignored. This is only
- # used in network/client/master, when downloading plugins, to
- # see if a given plugin is currently loaded and thus should be
- # reloaded.
- def self.loaded?(path)
- path = path.to_s.sub(/\.rb$/, '')
- @loaded.include?(path)
+ # List all loaded files.
+ def self.list_loaded
+ @loaded.sort { |a,b| a[0] <=> b[0] }.collect do |path, hash|
+ "#{path}: #{hash[:file]}"
end
-
- # Save the fact that a given path has been loaded. This is so
- # we can load downloaded plugins if they've already been loaded
- # into memory.
- def self.loaded(file)
- $" << file + ".rb" unless $".include?(file)
- @loaded << file unless @loaded.include?(file)
+ end
+
+ # Has a given path been loaded? This is used for testing whether a
+ # changed file should be loaded or just ignored. This is only
+ # used in network/client/master, when downloading plugins, to
+ # see if a given plugin is currently loaded and thus should be
+ # reloaded.
+ def self.loaded?(path)
+ path = path.to_s.sub(/\.rb$/, '')
+ @loaded.include?(path)
+ end
+
+ # Save the fact that a given path has been loaded. This is so
+ # we can load downloaded plugins if they've already been loaded
+ # into memory.
+ def self.loaded(file)
+ $" << file + ".rb" unless $".include?(file)
+ @loaded << file unless @loaded.include?(file)
+ end
+
+ attr_accessor :object, :path, :objwarn, :wrap
+
+ def initialize(obj, path, options = {})
+ @path = path.to_s
+ raise ArgumentError, "Autoload paths cannot be fully qualified" if @path !~ /^\w/
+ @object = obj
+
+ self.class[obj] = self
+
+ options.each do |opt, value|
+ opt = opt.intern if opt.is_a? String
+ begin
+ self.send(opt.to_s + "=", value)
+ rescue NoMethodError
+ raise ArgumentError, "#{opt} is not a valid option"
+ end
end
- attr_accessor :object, :path, :objwarn, :wrap
-
- def initialize(obj, path, options = {})
- @path = path.to_s
- raise ArgumentError, "Autoload paths cannot be fully qualified" if @path !~ /^\w/
- @object = obj
-
- self.class[obj] = self
-
- options.each do |opt, value|
- opt = opt.intern if opt.is_a? String
- begin
- self.send(opt.to_s + "=", value)
- rescue NoMethodError
- raise ArgumentError, "#{opt} is not a valid option"
- end
- end
-
- @wrap = true unless defined?(@wrap)
+ @wrap = true unless defined?(@wrap)
+ end
+
+ # Load a single plugin by name. We use 'load' here so we can reload a
+ # given plugin.
+ def load(name,env=nil)
+ path = name.to_s + ".rb"
+
+ searchpath(env).each do |dir|
+ file = File.join(dir, path)
+ next unless file_exist?(file)
+ begin
+ Kernel.load file, @wrap
+ name = symbolize(name)
+ loaded name, file
+ return true
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Could not autoload #{name}: #{detail}"
+ end
end
-
- # Load a single plugin by name. We use 'load' here so we can reload a
- # given plugin.
- def load(name,env=nil)
- path = name.to_s + ".rb"
-
- searchpath(env).each do |dir|
- file = File.join(dir, path)
- next unless file_exist?(file)
- begin
- Kernel.load file, @wrap
- name = symbolize(name)
- loaded name, file
- return true
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not autoload #{name}: #{detail}"
- end
+ false
+ end
+
+ # Mark the named object as loaded. Note that this supports unqualified
+ # queries, while we store the result as a qualified query in the class.
+ def loaded(name, file)
+ self.class.loaded(File.join(@path, name.to_s))
+ end
+
+ # Indicate whether the specfied plugin has been loaded.
+ def loaded?(name)
+ self.class.loaded?(File.join(@path, name.to_s))
+ end
+
+ # Load all instances that we can. This uses require, rather than load,
+ # so that already-loaded files don't get reloaded unnecessarily.
+ def loadall
+ # Load every instance of everything we can find.
+ searchpath.each do |dir|
+ Dir.glob("#{dir}/*.rb").each do |file|
+ name = File.basename(file).sub(".rb", '').intern
+ next if loaded?(name)
+ begin
+ Kernel.require file
+ loaded(name, file)
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "Could not autoload #{file}: #{detail}"
end
- false
+ end
end
-
- # Mark the named object as loaded. Note that this supports unqualified
- # queries, while we store the result as a qualified query in the class.
- def loaded(name, file)
- self.class.loaded(File.join(@path, name.to_s))
+ end
+
+ # The list of directories to search through for loadable plugins.
+ def searchpath(env=nil)
+ search_directories(env).collect { |d| File.join(d, @path) }.find_all { |d| FileTest.directory?(d) }
+ end
+
+ def module_directories(env=nil)
+ # We have to require this late in the process because otherwise we might have
+ # load order issues.
+ require 'puppet/node/environment'
+ Puppet::Node::Environment.new(env).modulepath.collect do |dir|
+ Dir.entries(dir).reject { |f| f =~ /^\./ }.collect { |f| File.join(dir, f) }
+ end.flatten.collect { |d| [File.join(d, "plugins"), File.join(d, "lib")] }.flatten.find_all do |d|
+ FileTest.directory?(d)
end
+ end
- # Indicate whether the specfied plugin has been loaded.
- def loaded?(name)
- self.class.loaded?(File.join(@path, name.to_s))
- end
-
- # Load all instances that we can. This uses require, rather than load,
- # so that already-loaded files don't get reloaded unnecessarily.
- def loadall
- # Load every instance of everything we can find.
- searchpath.each do |dir|
- Dir.glob("#{dir}/*.rb").each do |file|
- name = File.basename(file).sub(".rb", '').intern
- next if loaded?(name)
- begin
- Kernel.require file
- loaded(name, file)
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "Could not autoload #{file}: #{detail}"
- end
- end
- end
- end
-
- # The list of directories to search through for loadable plugins.
- def searchpath(env=nil)
- search_directories(env).collect { |d| File.join(d, @path) }.find_all { |d| FileTest.directory?(d) }
- end
-
- def module_directories(env=nil)
- # We have to require this late in the process because otherwise we might have
- # load order issues.
- require 'puppet/node/environment'
- Puppet::Node::Environment.new(env).modulepath.collect do |dir|
- Dir.entries(dir).reject { |f| f =~ /^\./ }.collect { |f| File.join(dir, f) }
- end.flatten.collect { |d| [File.join(d, "plugins"), File.join(d, "lib")] }.flatten.find_all do |d|
- FileTest.directory?(d)
- end
- end
-
- def search_directories(env=nil)
- [module_directories(env), Puppet[:libdir].split(File::PATH_SEPARATOR), $LOAD_PATH].flatten
- end
+ def search_directories(env=nil)
+ [module_directories(env), Puppet[:libdir].split(File::PATH_SEPARATOR), $LOAD_PATH].flatten
+ end
end
diff --git a/lib/puppet/util/autoload/file_cache.rb b/lib/puppet/util/autoload/file_cache.rb
index ce30eed73..b55547362 100644
--- a/lib/puppet/util/autoload/file_cache.rb
+++ b/lib/puppet/util/autoload/file_cache.rb
@@ -1,92 +1,92 @@
module Puppet::Util::Autoload::FileCache
- @found_files = {}
- @missing_files = {}
- class << self
- attr_reader :found_files, :missing_files
- end
+ @found_files = {}
+ @missing_files = {}
+ class << self
+ attr_reader :found_files, :missing_files
+ end
- # Only used for testing.
- def self.clear
- @found_files.clear
- @missing_files.clear
- end
+ # Only used for testing.
+ def self.clear
+ @found_files.clear
+ @missing_files.clear
+ end
- def found_files
- Puppet::Util::Autoload::FileCache.found_files
- end
+ def found_files
+ Puppet::Util::Autoload::FileCache.found_files
+ end
- def missing_files
- Puppet::Util::Autoload::FileCache.missing_files
- end
+ def missing_files
+ Puppet::Util::Autoload::FileCache.missing_files
+ end
- def directory_exist?(path)
- cache = cached_data?(path, :directory?)
- return cache unless cache.nil?
+ def directory_exist?(path)
+ cache = cached_data?(path, :directory?)
+ return cache unless cache.nil?
- protect(path) do
- stat = File.lstat(path)
- if stat.directory?
- found_file(path, stat)
- return true
- else
- missing_file(path)
- return false
- end
- end
+ protect(path) do
+ stat = File.lstat(path)
+ if stat.directory?
+ found_file(path, stat)
+ return true
+ else
+ missing_file(path)
+ return false
+ end
end
+ end
- def file_exist?(path)
- cache = cached_data?(path)
- return cache unless cache.nil?
+ def file_exist?(path)
+ cache = cached_data?(path)
+ return cache unless cache.nil?
- protect(path) do
- stat = File.lstat(path)
- found_file(path, stat)
- return true
- end
+ protect(path) do
+ stat = File.lstat(path)
+ found_file(path, stat)
+ return true
end
+ end
- def found_file?(path, type = nil)
- if data = found_files[path] and ! data_expired?(data[:time])
- return(type and ! data[:stat].send(type)) ? false : true
- else
- return false
- end
+ def found_file?(path, type = nil)
+ if data = found_files[path] and ! data_expired?(data[:time])
+ return(type and ! data[:stat].send(type)) ? false : true
+ else
+ return false
end
+ end
- def found_file(path, stat)
- found_files[path] = {:stat => stat, :time => Time.now}
- end
+ def found_file(path, stat)
+ found_files[path] = {:stat => stat, :time => Time.now}
+ end
- def missing_file?(path)
- !!(time = missing_files[path] and ! data_expired?(time))
- end
+ def missing_file?(path)
+ !!(time = missing_files[path] and ! data_expired?(time))
+ end
- def missing_file(path)
- missing_files[path] = Time.now
- end
+ def missing_file(path)
+ missing_files[path] = Time.now
+ end
- private
+ private
- def cached_data?(path, type = nil)
- if found_file?(path, type)
- return true
- elsif missing_file?(path)
- return false
- else
- return nil
- end
+ def cached_data?(path, type = nil)
+ if found_file?(path, type)
+ return true
+ elsif missing_file?(path)
+ return false
+ else
+ return nil
end
+ end
- def data_expired?(time)
- Time.now - time > 15
- end
+ def data_expired?(time)
+ Time.now - time > 15
+ end
- def protect(path)
- yield
- rescue => detail
- raise unless detail.class.to_s.include?("Errno")
- missing_file(path)
- return false
- end
+ def protect(path)
+ yield
+ rescue => detail
+ raise unless detail.class.to_s.include?("Errno")
+ missing_file(path)
+ return false
+ end
end
diff --git a/lib/puppet/util/backups.rb b/lib/puppet/util/backups.rb
index 1e051498c..c01bdd400 100644
--- a/lib/puppet/util/backups.rb
+++ b/lib/puppet/util/backups.rb
@@ -2,86 +2,86 @@ require 'find'
require 'fileutils'
module Puppet::Util::Backups
- # Deal with backups.
- def perform_backup(file = nil)
- # if they specifically don't want a backup, then just say
- # we're good
- return true unless self[:backup]
+ # Deal with backups.
+ def perform_backup(file = nil)
+ # if they specifically don't want a backup, then just say
+ # we're good
+ return true unless self[:backup]
- # let the path be specified
- file ||= self[:path]
- return true unless FileTest.exists?(file)
+ # let the path be specified
+ file ||= self[:path]
+ return true unless FileTest.exists?(file)
- return(self.bucket ? perform_backup_with_bucket(file) : perform_backup_with_backuplocal(file, self[:backup]))
- end
+ return(self.bucket ? perform_backup_with_bucket(file) : perform_backup_with_backuplocal(file, self[:backup]))
+ end
- private
+ private
- def perform_backup_with_bucket(fileobj)
- file = (fileobj.class == String) ? fileobj : fileobj.name
- case File.stat(file).ftype
- when "directory"
- # we don't need to backup directories when recurse is on
- return true if self[:recurse]
- info "Recursively backing up to filebucket"
- Find.find(self[:path]) { |f| backup_file_with_filebucket(f) if File.file?(f) }
- when "file"; backup_file_with_filebucket(file)
- when "link";
- end
- true
+ def perform_backup_with_bucket(fileobj)
+ file = (fileobj.class == String) ? fileobj : fileobj.name
+ case File.stat(file).ftype
+ when "directory"
+ # we don't need to backup directories when recurse is on
+ return true if self[:recurse]
+ info "Recursively backing up to filebucket"
+ Find.find(self[:path]) { |f| backup_file_with_filebucket(f) if File.file?(f) }
+ when "file"; backup_file_with_filebucket(file)
+ when "link";
end
+ true
+ end
- def perform_backup_with_backuplocal(fileobj, backup)
- file = (fileobj.class == String) ? fileobj : fileobj.name
- newfile = file + backup
+ def perform_backup_with_backuplocal(fileobj, backup)
+ file = (fileobj.class == String) ? fileobj : fileobj.name
+ newfile = file + backup
- remove_backup(newfile)
+ remove_backup(newfile)
- begin
- bfile = file + backup
+ begin
+ bfile = file + backup
- # Ruby 1.8.1 requires the 'preserve' addition, but
- # later versions do not appear to require it.
- # N.B. cp_r works on both files and directories
- FileUtils.cp_r(file, bfile, :preserve => true)
- return true
- rescue => detail
- # since they said they want a backup, let's error out
- # if we couldn't make one
- self.fail "Could not back #{file} up: #{detail.message}"
- end
+ # Ruby 1.8.1 requires the 'preserve' addition, but
+ # later versions do not appear to require it.
+ # N.B. cp_r works on both files and directories
+ FileUtils.cp_r(file, bfile, :preserve => true)
+ return true
+ rescue => detail
+ # since they said they want a backup, let's error out
+ # if we couldn't make one
+ self.fail "Could not back #{file} up: #{detail.message}"
end
+ end
- def remove_backup(newfile)
- if self.class.name == :file and self[:links] != :follow
- method = :lstat
- else
- method = :stat
- end
+ def remove_backup(newfile)
+ if self.class.name == :file and self[:links] != :follow
+ method = :lstat
+ else
+ method = :stat
+ end
- begin
- stat = File.send(method, newfile)
- rescue Errno::ENOENT
- return
- end
+ begin
+ stat = File.send(method, newfile)
+ rescue Errno::ENOENT
+ return
+ end
- if stat.ftype == "directory"
- raise Puppet::Error, "Will not remove directory backup #{newfile}; use a filebucket"
- end
+ if stat.ftype == "directory"
+ raise Puppet::Error, "Will not remove directory backup #{newfile}; use a filebucket"
+ end
- info "Removing old backup of type #{stat.ftype}"
+ info "Removing old backup of type #{stat.ftype}"
- begin
- File.unlink(newfile)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- self.fail "Could not remove old backup: #{detail}"
- end
+ begin
+ File.unlink(newfile)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ self.fail "Could not remove old backup: #{detail}"
end
+ end
- def backup_file_with_filebucket(f)
- sum = self.bucket.backup(f)
- self.info "Filebucketed #{f} to #{self.bucket.name} with sum #{sum}"
- return sum
- end
+ def backup_file_with_filebucket(f)
+ sum = self.bucket.backup(f)
+ self.info "Filebucketed #{f} to #{self.bucket.name} with sum #{sum}"
+ return sum
+ end
end
diff --git a/lib/puppet/util/cacher.rb b/lib/puppet/util/cacher.rb
index c87661a3a..8785c694f 100644
--- a/lib/puppet/util/cacher.rb
+++ b/lib/puppet/util/cacher.rb
@@ -1,127 +1,127 @@
module Puppet::Util::Cacher
- module Expirer
- attr_reader :timestamp
+ module Expirer
+ attr_reader :timestamp
- # Cause all cached values to be considered expired.
- def expire
- @timestamp = Time.now
- end
+ # Cause all cached values to be considered expired.
+ def expire
+ @timestamp = Time.now
+ end
+
+ # Is the provided timestamp earlier than our expiration timestamp?
+ # If it is, then the associated value is expired.
+ def dependent_data_expired?(ts)
+ return false unless timestamp
+
+ timestamp > ts
+ end
+ end
+
+ extend Expirer
+
+ # Our module has been extended in a class; we can only add the Instance methods,
+ # which become *class* methods in the class.
+ def self.extended(other)
+ class << other
+ extend ClassMethods
+ include InstanceMethods
+ end
+ end
+
+ # Our module has been included in a class, which means the class gets the class methods
+ # and all of its instances get the instance methods.
+ def self.included(other)
+ other.extend(ClassMethods)
+ other.send(:include, InstanceMethods)
+ end
+
+ # Methods that can get added to a class.
+ module ClassMethods
+ # Provide a means of defining an attribute whose value will be cached.
+ # Must provide a block capable of defining the value if it's flushed..
+ def cached_attr(name, options = {}, &block)
+ init_method = "init_#{name}"
+ define_method(init_method, &block)
+
+ define_method(name) do
+ cached_value(name)
+ end
+
+ define_method(name.to_s + "=") do |value|
+ # Make sure the cache timestamp is set
+ cache_timestamp
+ value_cache[name] = value
+ end
+
+ if ttl = options[:ttl]
+ set_attr_ttl(name, ttl)
+ end
+ end
- # Is the provided timestamp earlier than our expiration timestamp?
- # If it is, then the associated value is expired.
- def dependent_data_expired?(ts)
- return false unless timestamp
+ def attr_ttl(name)
+ return nil unless @attr_ttls
+ @attr_ttls[name]
+ end
+
+ def set_attr_ttl(name, value)
+ @attr_ttls ||= {}
+ @attr_ttls[name] = Integer(value)
+ end
+ end
+
+ # Methods that get added to instances.
+ module InstanceMethods
+ def expire
+ # Only expire if we have an expirer. This is
+ # mostly so that we can comfortably handle cases
+ # like Puppet::Type instances, which use their
+ # catalog as their expirer, and they often don't
+ # have a catalog.
+ if e = expirer
+ e.expire
+ end
+ end
- timestamp > ts
- end
+ def expirer
+ Puppet::Util::Cacher
end
- extend Expirer
+ private
- # Our module has been extended in a class; we can only add the Instance methods,
- # which become *class* methods in the class.
- def self.extended(other)
- class << other
- extend ClassMethods
- include InstanceMethods
- end
+ def cache_timestamp
+ @cache_timestamp ||= Time.now
end
- # Our module has been included in a class, which means the class gets the class methods
- # and all of its instances get the instance methods.
- def self.included(other)
- other.extend(ClassMethods)
- other.send(:include, InstanceMethods)
+ def cached_value(name)
+ # Allow a nil expirer, in which case we regenerate the value every time.
+ if expired_by_expirer?(name)
+ value_cache.clear
+ @cache_timestamp = Time.now
+ elsif expired_by_ttl?(name)
+ value_cache.delete(name)
+ end
+ value_cache[name] = send("init_#{name}") unless value_cache.include?(name)
+ value_cache[name]
end
- # Methods that can get added to a class.
- module ClassMethods
- # Provide a means of defining an attribute whose value will be cached.
- # Must provide a block capable of defining the value if it's flushed..
- def cached_attr(name, options = {}, &block)
- init_method = "init_#{name}"
- define_method(init_method, &block)
-
- define_method(name) do
- cached_value(name)
- end
-
- define_method(name.to_s + "=") do |value|
- # Make sure the cache timestamp is set
- cache_timestamp
- value_cache[name] = value
- end
-
- if ttl = options[:ttl]
- set_attr_ttl(name, ttl)
- end
- end
-
- def attr_ttl(name)
- return nil unless @attr_ttls
- @attr_ttls[name]
- end
-
- def set_attr_ttl(name, value)
- @attr_ttls ||= {}
- @attr_ttls[name] = Integer(value)
- end
+ def expired_by_expirer?(name)
+ if expirer.nil?
+ return true unless self.class.attr_ttl(name)
+ end
+ expirer.dependent_data_expired?(cache_timestamp)
+ end
+
+ def expired_by_ttl?(name)
+ return false unless self.class.respond_to?(:attr_ttl)
+ return false unless ttl = self.class.attr_ttl(name)
+
+ @ttl_timestamps ||= {}
+ @ttl_timestamps[name] ||= Time.now
+
+ (Time.now - @ttl_timestamps[name]) > ttl
end
- # Methods that get added to instances.
- module InstanceMethods
- def expire
- # Only expire if we have an expirer. This is
- # mostly so that we can comfortably handle cases
- # like Puppet::Type instances, which use their
- # catalog as their expirer, and they often don't
- # have a catalog.
- if e = expirer
- e.expire
- end
- end
-
- def expirer
- Puppet::Util::Cacher
- end
-
- private
-
- def cache_timestamp
- @cache_timestamp ||= Time.now
- end
-
- def cached_value(name)
- # Allow a nil expirer, in which case we regenerate the value every time.
- if expired_by_expirer?(name)
- value_cache.clear
- @cache_timestamp = Time.now
- elsif expired_by_ttl?(name)
- value_cache.delete(name)
- end
- value_cache[name] = send("init_#{name}") unless value_cache.include?(name)
- value_cache[name]
- end
-
- def expired_by_expirer?(name)
- if expirer.nil?
- return true unless self.class.attr_ttl(name)
- end
- expirer.dependent_data_expired?(cache_timestamp)
- end
-
- def expired_by_ttl?(name)
- return false unless self.class.respond_to?(:attr_ttl)
- return false unless ttl = self.class.attr_ttl(name)
-
- @ttl_timestamps ||= {}
- @ttl_timestamps[name] ||= Time.now
-
- (Time.now - @ttl_timestamps[name]) > ttl
- end
-
- def value_cache
- @value_cache ||= {}
- end
+ def value_cache
+ @value_cache ||= {}
end
+ end
end
diff --git a/lib/puppet/util/checksums.rb b/lib/puppet/util/checksums.rb
index 102ee98ac..5aebd8392 100644
--- a/lib/puppet/util/checksums.rb
+++ b/lib/puppet/util/checksums.rb
@@ -1,125 +1,125 @@
# A stand-alone module for calculating checksums
# in a generic way.
module Puppet::Util::Checksums
- # Is the provided string a checksum?
- def checksum?(string)
- string =~ /^\{(\w{3,5})\}\S+/
- end
-
- # Strip the checksum type from an existing checksum
- def sumdata(checksum)
- checksum =~ /^\{(\w+)\}(.+)/ ? $2 : nil
- end
-
- # Strip the checksum type from an existing checksum
- def sumtype(checksum)
- checksum =~ /^\{(\w+)\}/ ? $1 : nil
- end
-
- # Calculate a checksum using Digest::MD5.
- def md5(content)
- require 'digest/md5'
- Digest::MD5.hexdigest(content)
- end
-
- # Calculate a checksum of the first 500 chars of the content using Digest::MD5.
- def md5lite(content)
- md5(content[0..511])
- end
-
- # Calculate a checksum of a file's content using Digest::MD5.
- def md5_file(filename, lite = false)
- require 'digest/md5'
-
- digest = Digest::MD5.new
- checksum_file(digest, filename, lite)
- end
-
- # Calculate a checksum of the first 500 chars of a file's content using Digest::MD5.
- def md5lite_file(filename)
- md5_file(filename, true)
- end
-
- def md5_stream(&block)
- require 'digest/md5'
- digest = Digest::MD5.new
- yield digest
- digest.hexdigest
- end
-
- alias :md5lite_stream :md5_stream
-
- # Return the :mtime timestamp of a file.
- def mtime_file(filename)
- File.stat(filename).send(:mtime)
- end
-
- # by definition this doesn't exist
- def mtime_stream
- nil
- end
-
- alias :ctime_stream :mtime_stream
-
- # Calculate a checksum using Digest::SHA1.
- def sha1(content)
- require 'digest/sha1'
- Digest::SHA1.hexdigest(content)
- end
-
- # Calculate a checksum of the first 500 chars of the content using Digest::SHA1.
- def sha1lite(content)
- sha1(content[0..511])
- end
-
- # Calculate a checksum of a file's content using Digest::SHA1.
- def sha1_file(filename, lite = false)
- require 'digest/sha1'
-
- digest = Digest::SHA1.new
- checksum_file(digest, filename, lite)
- end
-
- # Calculate a checksum of the first 500 chars of a file's content using Digest::SHA1.
- def sha1lite_file(filename)
- sha1_file(filename, true)
- end
-
- def sha1_stream
- require 'digest/sha1'
- digest = Digest::SHA1.new
- yield digest
- digest.hexdigest
- end
-
- alias :sha1lite_stream :sha1_stream
-
- # Return the :ctime of a file.
- def ctime_file(filename)
- File.stat(filename).send(:ctime)
- end
-
- # Return a "no checksum"
- def none_file(filename)
- ""
- end
-
- def none_stream
- ""
- end
-
- private
-
- # Perform an incremental checksum on a file.
- def checksum_file(digest, filename, lite = false)
- buffer = lite ? 512 : 4096
- File.open(filename, 'r') do |file|
- while content = file.read(buffer)
- digest << content
- break if lite
- end
- end
-
- digest.hexdigest
- end
+ # Is the provided string a checksum?
+ def checksum?(string)
+ string =~ /^\{(\w{3,5})\}\S+/
+ end
+
+ # Strip the checksum type from an existing checksum
+ def sumdata(checksum)
+ checksum =~ /^\{(\w+)\}(.+)/ ? $2 : nil
+ end
+
+ # Strip the checksum type from an existing checksum
+ def sumtype(checksum)
+ checksum =~ /^\{(\w+)\}/ ? $1 : nil
+ end
+
+ # Calculate a checksum using Digest::MD5.
+ def md5(content)
+ require 'digest/md5'
+ Digest::MD5.hexdigest(content)
+ end
+
+ # Calculate a checksum of the first 500 chars of the content using Digest::MD5.
+ def md5lite(content)
+ md5(content[0..511])
+ end
+
+ # Calculate a checksum of a file's content using Digest::MD5.
+ def md5_file(filename, lite = false)
+ require 'digest/md5'
+
+ digest = Digest::MD5.new
+ checksum_file(digest, filename, lite)
+ end
+
+ # Calculate a checksum of the first 500 chars of a file's content using Digest::MD5.
+ def md5lite_file(filename)
+ md5_file(filename, true)
+ end
+
+ def md5_stream(&block)
+ require 'digest/md5'
+ digest = Digest::MD5.new
+ yield digest
+ digest.hexdigest
+ end
+
+ alias :md5lite_stream :md5_stream
+
+ # Return the :mtime timestamp of a file.
+ def mtime_file(filename)
+ File.stat(filename).send(:mtime)
+ end
+
+ # by definition this doesn't exist
+ def mtime_stream
+ nil
+ end
+
+ alias :ctime_stream :mtime_stream
+
+ # Calculate a checksum using Digest::SHA1.
+ def sha1(content)
+ require 'digest/sha1'
+ Digest::SHA1.hexdigest(content)
+ end
+
+ # Calculate a checksum of the first 500 chars of the content using Digest::SHA1.
+ def sha1lite(content)
+ sha1(content[0..511])
+ end
+
+ # Calculate a checksum of a file's content using Digest::SHA1.
+ def sha1_file(filename, lite = false)
+ require 'digest/sha1'
+
+ digest = Digest::SHA1.new
+ checksum_file(digest, filename, lite)
+ end
+
+ # Calculate a checksum of the first 500 chars of a file's content using Digest::SHA1.
+ def sha1lite_file(filename)
+ sha1_file(filename, true)
+ end
+
+ def sha1_stream
+ require 'digest/sha1'
+ digest = Digest::SHA1.new
+ yield digest
+ digest.hexdigest
+ end
+
+ alias :sha1lite_stream :sha1_stream
+
+ # Return the :ctime of a file.
+ def ctime_file(filename)
+ File.stat(filename).send(:ctime)
+ end
+
+ # Return a "no checksum"
+ def none_file(filename)
+ ""
+ end
+
+ def none_stream
+ ""
+ end
+
+ private
+
+ # Perform an incremental checksum on a file.
+ def checksum_file(digest, filename, lite = false)
+ buffer = lite ? 512 : 4096
+ File.open(filename, 'r') do |file|
+ while content = file.read(buffer)
+ digest << content
+ break if lite
+ end
+ end
+
+ digest.hexdigest
+ end
end
diff --git a/lib/puppet/util/classgen.rb b/lib/puppet/util/classgen.rb
index 92fcc6724..ed69c5878 100644
--- a/lib/puppet/util/classgen.rb
+++ b/lib/puppet/util/classgen.rb
@@ -1,197 +1,197 @@
module Puppet
- class ConstantAlreadyDefined < Error; end
- class SubclassAlreadyDefined < Error; end
+ class ConstantAlreadyDefined < Error; end
+ class SubclassAlreadyDefined < Error; end
end
module Puppet::Util::ClassGen
- include Puppet::Util::MethodHelper
- include Puppet::Util
-
- # Create a new subclass. Valid options are:
- # * <tt>:array</tt>: An array of existing classes. If specified, the new
- # class is added to this array.
- # * <tt>:attributes</tt>: A hash of attributes to set before the block is
- # evaluated.
- # * <tt>:block</tt>: The block to evaluate in the context of the class.
- # You can also just pass the block normally, but it will still be evaluated
- # with <tt>class_eval</tt>.
- # * <tt>:constant</tt>: What to set the constant as. Defaults to the
- # capitalized name.
- # * <tt>:hash</tt>: A hash of existing classes. If specified, the new
- # class is added to this hash, and it is also used for overwrite tests.
- # * <tt>:overwrite</tt>: Whether to overwrite an existing class.
- # * <tt>:parent</tt>: The parent class for the generated class. Defaults to
- # self.
- # * <tt>:prefix</tt>: The constant prefix. Default to nothing; if specified,
- # the capitalized name is appended and the result is set as the constant.
- def genclass(name, options = {}, &block)
- genthing(name, Class, options, block)
+ include Puppet::Util::MethodHelper
+ include Puppet::Util
+
+ # Create a new subclass. Valid options are:
+ # * <tt>:array</tt>: An array of existing classes. If specified, the new
+ # class is added to this array.
+ # * <tt>:attributes</tt>: A hash of attributes to set before the block is
+ # evaluated.
+ # * <tt>:block</tt>: The block to evaluate in the context of the class.
+ # You can also just pass the block normally, but it will still be evaluated
+ # with <tt>class_eval</tt>.
+ # * <tt>:constant</tt>: What to set the constant as. Defaults to the
+ # capitalized name.
+ # * <tt>:hash</tt>: A hash of existing classes. If specified, the new
+ # class is added to this hash, and it is also used for overwrite tests.
+ # * <tt>:overwrite</tt>: Whether to overwrite an existing class.
+ # * <tt>:parent</tt>: The parent class for the generated class. Defaults to
+ # self.
+ # * <tt>:prefix</tt>: The constant prefix. Default to nothing; if specified,
+ # the capitalized name is appended and the result is set as the constant.
+ def genclass(name, options = {}, &block)
+ genthing(name, Class, options, block)
+ end
+
+ # Create a new module. Valid options are:
+ # * <tt>:array</tt>: An array of existing classes. If specified, the new
+ # class is added to this array.
+ # * <tt>:attributes</tt>: A hash of attributes to set before the block is
+ # evaluated.
+ # * <tt>:block</tt>: The block to evaluate in the context of the class.
+ # You can also just pass the block normally, but it will still be evaluated
+ # with <tt>class_eval</tt>.
+ # * <tt>:constant</tt>: What to set the constant as. Defaults to the
+ # capitalized name.
+ # * <tt>:hash</tt>: A hash of existing classes. If specified, the new
+ # class is added to this hash, and it is also used for overwrite tests.
+ # * <tt>:overwrite</tt>: Whether to overwrite an existing class.
+ # * <tt>:prefix</tt>: The constant prefix. Default to nothing; if specified,
+ # the capitalized name is appended and the result is set as the constant.
+ def genmodule(name, options = {}, &block)
+ genthing(name, Module, options, block)
+ end
+
+ # Remove an existing class
+ def rmclass(name, options)
+ options = symbolize_options(options)
+ const = genconst_string(name, options)
+ retval = false
+ if const_defined?(const)
+ remove_const(const)
+ retval = true
end
- # Create a new module. Valid options are:
- # * <tt>:array</tt>: An array of existing classes. If specified, the new
- # class is added to this array.
- # * <tt>:attributes</tt>: A hash of attributes to set before the block is
- # evaluated.
- # * <tt>:block</tt>: The block to evaluate in the context of the class.
- # You can also just pass the block normally, but it will still be evaluated
- # with <tt>class_eval</tt>.
- # * <tt>:constant</tt>: What to set the constant as. Defaults to the
- # capitalized name.
- # * <tt>:hash</tt>: A hash of existing classes. If specified, the new
- # class is added to this hash, and it is also used for overwrite tests.
- # * <tt>:overwrite</tt>: Whether to overwrite an existing class.
- # * <tt>:prefix</tt>: The constant prefix. Default to nothing; if specified,
- # the capitalized name is appended and the result is set as the constant.
- def genmodule(name, options = {}, &block)
- genthing(name, Module, options, block)
+ if hash = options[:hash] and hash.include? name
+ hash.delete(name)
+ retval = true
end
- # Remove an existing class
- def rmclass(name, options)
- options = symbolize_options(options)
- const = genconst_string(name, options)
- retval = false
- if const_defined?(const)
- remove_const(const)
- retval = true
- end
+ # Let them know whether we did actually delete a subclass.
+ retval
+ end
- if hash = options[:hash] and hash.include? name
- hash.delete(name)
- retval = true
- end
+ private
- # Let them know whether we did actually delete a subclass.
- retval
+ # Generate the constant to create or remove.
+ def genconst_string(name, options)
+ unless const = options[:constant]
+ prefix = options[:prefix] || ""
+ const = prefix + name2const(name)
end
- private
+ const
+ end
- # Generate the constant to create or remove.
- def genconst_string(name, options)
- unless const = options[:constant]
- prefix = options[:prefix] || ""
- const = prefix + name2const(name)
- end
+ # This does the actual work of creating our class or module. It's just a
+ # slightly abstract version of genclass.
+ def genthing(name, type, options, block)
+ options = symbolize_options(options)
- const
- end
+ name = symbolize(name.to_s.downcase)
- # This does the actual work of creating our class or module. It's just a
- # slightly abstract version of genclass.
- def genthing(name, type, options, block)
- options = symbolize_options(options)
-
- name = symbolize(name.to_s.downcase)
-
- if type == Module
- #evalmethod = :module_eval
- evalmethod = :class_eval
- # Create the class, with the correct name.
- klass = Module.new do
- class << self
- attr_reader :name
- end
- @name = name
- end
- else
- options[:parent] ||= self
- evalmethod = :class_eval
- # Create the class, with the correct name.
- klass = Class.new(options[:parent]) do
- @name = name
- end
+ if type == Module
+ #evalmethod = :module_eval
+ evalmethod = :class_eval
+ # Create the class, with the correct name.
+ klass = Module.new do
+ class << self
+ attr_reader :name
end
+ @name = name
+ end
+ else
+ options[:parent] ||= self
+ evalmethod = :class_eval
+ # Create the class, with the correct name.
+ klass = Class.new(options[:parent]) do
+ @name = name
+ end
+ end
- # Create the constant as appropriation.
- handleclassconst(klass, name, options)
+ # Create the constant as appropriation.
+ handleclassconst(klass, name, options)
- # Initialize any necessary variables.
- initclass(klass, options)
+ # Initialize any necessary variables.
+ initclass(klass, options)
- block ||= options[:block]
+ block ||= options[:block]
- # Evaluate the passed block if there is one. This should usually
- # define all of the work.
- klass.send(evalmethod, &block) if block
+ # Evaluate the passed block if there is one. This should usually
+ # define all of the work.
+ klass.send(evalmethod, &block) if block
- klass.postinit if klass.respond_to? :postinit
+ klass.postinit if klass.respond_to? :postinit
- # Store the class in hashes or arrays or whatever.
- storeclass(klass, name, options)
+ # Store the class in hashes or arrays or whatever.
+ storeclass(klass, name, options)
- klass
- end
+ klass
+ end
- # Handle the setting and/or removing of the associated constant.
- def handleclassconst(klass, name, options)
- const = genconst_string(name, options)
-
- if const_defined?(const)
- if options[:overwrite]
- Puppet.info "Redefining #{name} in #{self}"
- remove_const(const)
- else
- raise Puppet::ConstantAlreadyDefined,
- "Class #{const} is already defined in #{self}"
- end
- end
- const_set(const, klass)
+ # Handle the setting and/or removing of the associated constant.
+ def handleclassconst(klass, name, options)
+ const = genconst_string(name, options)
- const
+ if const_defined?(const)
+ if options[:overwrite]
+ Puppet.info "Redefining #{name} in #{self}"
+ remove_const(const)
+ else
+ raise Puppet::ConstantAlreadyDefined,
+ "Class #{const} is already defined in #{self}"
+ end
end
+ const_set(const, klass)
- # Perform the initializations on the class.
- def initclass(klass, options)
- klass.initvars if klass.respond_to? :initvars
-
- if attrs = options[:attributes]
- attrs.each do |param, value|
- method = param.to_s + "="
- klass.send(method, value) if klass.respond_to? method
- end
- end
+ const
+ end
- [:include, :extend].each do |method|
- if set = options[method]
- set = [set] unless set.is_a?(Array)
- set.each do |mod|
- klass.send(method, mod)
- end
- end
- end
+ # Perform the initializations on the class.
+ def initclass(klass, options)
+ klass.initvars if klass.respond_to? :initvars
- klass.preinit if klass.respond_to? :preinit
+ if attrs = options[:attributes]
+ attrs.each do |param, value|
+ method = param.to_s + "="
+ klass.send(method, value) if klass.respond_to? method
+ end
end
- # Convert our name to a constant.
- def name2const(name)
- name.to_s.capitalize
+ [:include, :extend].each do |method|
+ if set = options[method]
+ set = [set] unless set.is_a?(Array)
+ set.each do |mod|
+ klass.send(method, mod)
+ end
+ end
end
- # Store the class in the appropriate places.
- def storeclass(klass, klassname, options)
- if hash = options[:hash]
- if hash.include? klassname and ! options[:overwrite]
- raise Puppet::SubclassAlreadyDefined,
- "Already a generated class named #{klassname}"
- end
+ klass.preinit if klass.respond_to? :preinit
+ end
- hash[klassname] = klass
- end
+ # Convert our name to a constant.
+ def name2const(name)
+ name.to_s.capitalize
+ end
- # If we were told to stick it in a hash, then do so
- if array = options[:array]
- if (klass.respond_to? :name and
- array.find { |c| c.name == klassname } and
- ! options[:overwrite])
- raise Puppet::SubclassAlreadyDefined,
- "Already a generated class named #{klassname}"
- end
+ # Store the class in the appropriate places.
+ def storeclass(klass, klassname, options)
+ if hash = options[:hash]
+ if hash.include? klassname and ! options[:overwrite]
+ raise Puppet::SubclassAlreadyDefined,
+ "Already a generated class named #{klassname}"
+ end
- array << klass
- end
+ hash[klassname] = klass
+ end
+
+ # If we were told to stick it in a hash, then do so
+ if array = options[:array]
+ if (klass.respond_to? :name and
+ array.find { |c| c.name == klassname } and
+ ! options[:overwrite])
+ raise Puppet::SubclassAlreadyDefined,
+ "Already a generated class named #{klassname}"
+ end
+
+ array << klass
end
+ end
end
diff --git a/lib/puppet/util/command_line.rb b/lib/puppet/util/command_line.rb
index 568d52c47..2a97ee069 100644
--- a/lib/puppet/util/command_line.rb
+++ b/lib/puppet/util/command_line.rb
@@ -1,95 +1,95 @@
module Puppet
- module Util
- class CommandLine
-
- LegacyName = Hash.new{|h,k| k}.update(
- {
- 'agent' => 'puppetd',
- 'cert' => 'puppetca',
- 'doc' => 'puppetdoc',
- 'filebucket' => 'filebucket',
- 'apply' => 'puppet',
- 'describe' => 'pi',
- 'queue' => 'puppetqd',
- 'resource' => 'ralsh',
- 'kick' => 'puppetrun',
- 'master' => 'puppetmasterd',
+ module Util
+ class CommandLine
+
+ LegacyName = Hash.new{|h,k| k}.update(
+ {
+ 'agent' => 'puppetd',
+ 'cert' => 'puppetca',
+ 'doc' => 'puppetdoc',
+ 'filebucket' => 'filebucket',
+ 'apply' => 'puppet',
+ 'describe' => 'pi',
+ 'queue' => 'puppetqd',
+ 'resource' => 'ralsh',
+ 'kick' => 'puppetrun',
+ 'master' => 'puppetmasterd',
- })
-
- def initialize( zero = $0, argv = ARGV, stdin = STDIN )
- @zero = zero
- @argv = argv.dup
- @stdin = stdin
-
- @subcommand_name, @args = subcommand_and_args( @zero, @argv, @stdin )
- end
-
- attr :subcommand_name
- attr :args
-
- def appdir
- File.join('puppet', 'application')
- end
-
- def available_subcommands
- absolute_appdir = $LOAD_PATH.collect { |x| File.join(x,'puppet','application') }.detect{ |x| File.directory?(x) }
- Dir[File.join(absolute_appdir, '*.rb')].map{|fn| File.basename(fn, '.rb')}
- end
-
- def usage_message
- usage = "Usage: puppet command <space separated arguments>"
- available = "Available commands are: #{available_subcommands.sort.join(', ')}"
- [usage, available].join("\n")
- end
-
- def require_application(application)
- require File.join(appdir, application)
- end
-
- def execute
- if subcommand_name.nil?
- puts usage_message
- elsif available_subcommands.include?(subcommand_name) #subcommand
- require_application subcommand_name
- Puppet::Application.find(subcommand_name).new(self).run
- else
- abort "Error: Unknown command #{subcommand_name}.\n#{usage_message}" unless execute_external_subcommand
- end
- end
-
- def execute_external_subcommand
- external_command = "puppet-#{subcommand_name}"
-
- require 'puppet/util'
- path_to_subcommand = Puppet::Util.binary( external_command )
- return false unless path_to_subcommand
-
- system( path_to_subcommand, *args )
- true
- end
-
- def legacy_executable_name
- LegacyName[ subcommand_name ]
- end
-
- private
-
- def subcommand_and_args( zero, argv, stdin )
- zero = File.basename(zero, '.rb')
-
- if zero == 'puppet'
- case argv.first
- when nil; [ stdin.tty? ? nil : "apply", argv] # ttys get usage info
- when "--help"; [nil, argv] # help should give you usage, not the help for `puppet apply`
- when /^-|\.pp$|\.rb$/; ["apply", argv]
- else [ argv.first, argv[1..-1] ]
- end
- else
- [ zero, argv ]
- end
- end
+ })
+
+ def initialize( zero = $0, argv = ARGV, stdin = STDIN )
+ @zero = zero
+ @argv = argv.dup
+ @stdin = stdin
+
+ @subcommand_name, @args = subcommand_and_args( @zero, @argv, @stdin )
+ end
+
+ attr :subcommand_name
+ attr :args
+
+ def appdir
+ File.join('puppet', 'application')
+ end
+
+ def available_subcommands
+ absolute_appdir = $LOAD_PATH.collect { |x| File.join(x,'puppet','application') }.detect{ |x| File.directory?(x) }
+ Dir[File.join(absolute_appdir, '*.rb')].map{|fn| File.basename(fn, '.rb')}
+ end
+
+ def usage_message
+ usage = "Usage: puppet command <space separated arguments>"
+ available = "Available commands are: #{available_subcommands.sort.join(', ')}"
+ [usage, available].join("\n")
+ end
+
+ def require_application(application)
+ require File.join(appdir, application)
+ end
+
+ def execute
+ if subcommand_name.nil?
+ puts usage_message
+ elsif available_subcommands.include?(subcommand_name) #subcommand
+ require_application subcommand_name
+ Puppet::Application.find(subcommand_name).new(self).run
+ else
+ abort "Error: Unknown command #{subcommand_name}.\n#{usage_message}" unless execute_external_subcommand
+ end
+ end
+
+ def execute_external_subcommand
+ external_command = "puppet-#{subcommand_name}"
+
+ require 'puppet/util'
+ path_to_subcommand = Puppet::Util.binary( external_command )
+ return false unless path_to_subcommand
+
+ system( path_to_subcommand, *args )
+ true
+ end
+ def legacy_executable_name
+ LegacyName[ subcommand_name ]
+ end
+
+ private
+
+ def subcommand_and_args( zero, argv, stdin )
+ zero = File.basename(zero, '.rb')
+
+ if zero == 'puppet'
+ case argv.first
+ when nil; [ stdin.tty? ? nil : "apply", argv] # ttys get usage info
+ when "--help"; [nil, argv] # help should give you usage, not the help for `puppet apply`
+ when /^-|\.pp$|\.rb$/; ["apply", argv]
+ else [ argv.first, argv[1..-1] ]
+ end
+ else
+ [ zero, argv ]
end
+ end
+
end
+ end
end
diff --git a/lib/puppet/util/constant_inflector.rb b/lib/puppet/util/constant_inflector.rb
index 20ad384d9..8f93e3255 100644
--- a/lib/puppet/util/constant_inflector.rb
+++ b/lib/puppet/util/constant_inflector.rb
@@ -4,12 +4,12 @@
# A common module for converting between constants and
# file names.
module Puppet::Util::ConstantInflector
- def file2constant(file)
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = file.split("/").collect { |name| name.capitalize }.join("::").gsub(/_+(.)/) { |term| $1.capitalize }
- end
+ def file2constant(file)
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = file.split("/").collect { |name| name.capitalize }.join("::").gsub(/_+(.)/) { |term| $1.capitalize }
+ end
- def constant2file(constant)
- constant.to_s.gsub(/([a-z])([A-Z])/) { |term| $1 + "_#{$2}" }.gsub("::", "/").downcase
- end
+ def constant2file(constant)
+ constant.to_s.gsub(/([a-z])([A-Z])/) { |term| $1 + "_#{$2}" }.gsub("::", "/").downcase
+ end
end
diff --git a/lib/puppet/util/diff.rb b/lib/puppet/util/diff.rb
index 0e5deab82..73e1bc014 100644
--- a/lib/puppet/util/diff.rb
+++ b/lib/puppet/util/diff.rb
@@ -1,74 +1,74 @@
# Provide a diff between two strings.
module Puppet::Util::Diff
- include Puppet::Util
- require 'tempfile'
+ include Puppet::Util
+ require 'tempfile'
- def diff(old, new)
- command = [Puppet[:diff]]
- if args = Puppet[:diff_args] and args != ""
- command << args
- end
- command << old << new
- execute(command, :failonfail => false)
+ def diff(old, new)
+ command = [Puppet[:diff]]
+ if args = Puppet[:diff_args] and args != ""
+ command << args
end
+ command << old << new
+ execute(command, :failonfail => false)
+ end
- module_function :diff
-
- # return diff string of two input strings
- # format defaults to unified
- # context defaults to 3 lines
- def lcs_diff(data_old, data_new, format=:unified, context_lines=3)
- unless Puppet.features.diff?
- Puppet.warning "Cannot provide diff without the diff/lcs Ruby library"
- return ""
- end
- data_old = data_old.split(/\n/).map! { |e| e.chomp }
- data_new = data_new.split(/\n/).map! { |e| e.chomp }
+ module_function :diff
- output = ""
+ # return diff string of two input strings
+ # format defaults to unified
+ # context defaults to 3 lines
+ def lcs_diff(data_old, data_new, format=:unified, context_lines=3)
+ unless Puppet.features.diff?
+ Puppet.warning "Cannot provide diff without the diff/lcs Ruby library"
+ return ""
+ end
+ data_old = data_old.split(/\n/).map! { |e| e.chomp }
+ data_new = data_new.split(/\n/).map! { |e| e.chomp }
- diffs = ::Diff::LCS.diff(data_old, data_new)
- return output if diffs.empty?
+ output = ""
- oldhunk = hunk = nil
- file_length_difference = 0
+ diffs = ::Diff::LCS.diff(data_old, data_new)
+ return output if diffs.empty?
- diffs.each do |piece|
- begin
+ oldhunk = hunk = nil
+ file_length_difference = 0
- hunk = ::Diff::LCS::Hunk.new(
- data_old, data_new, piece,
- context_lines,
+ diffs.each do |piece|
+ begin
- file_length_difference)
- file_length_difference = hunk.file_length_difference
- next unless oldhunk
- # Hunks may overlap, which is why we need to be careful when our
- # diff includes lines of context. Otherwise, we might print
- # redundant lines.
- if (context_lines > 0) and hunk.overlaps?(oldhunk)
- hunk.unshift(oldhunk)
- else
- output << oldhunk.diff(format)
- end
- ensure
- oldhunk = hunk
- output << "\n"
- end
- end
+ hunk = ::Diff::LCS::Hunk.new(
+ data_old, data_new, piece,
+ context_lines,
- # Handle the last remaining hunk
- output << oldhunk.diff(format) << "\n"
+ file_length_difference)
+ file_length_difference = hunk.file_length_difference
+ next unless oldhunk
+ # Hunks may overlap, which is why we need to be careful when our
+ # diff includes lines of context. Otherwise, we might print
+ # redundant lines.
+ if (context_lines > 0) and hunk.overlaps?(oldhunk)
+ hunk.unshift(oldhunk)
+ else
+ output << oldhunk.diff(format)
+ end
+ ensure
+ oldhunk = hunk
+ output << "\n"
+ end
end
- def string_file_diff(path, string)
- require 'tempfile'
- tempfile = Tempfile.new("puppet-diffing")
- tempfile.open
- tempfile.print string
- tempfile.close
- print diff(path, tempfile.path)
- tempfile.delete
- end
+ # Handle the last remaining hunk
+ output << oldhunk.diff(format) << "\n"
+ end
+
+ def string_file_diff(path, string)
+ require 'tempfile'
+ tempfile = Tempfile.new("puppet-diffing")
+ tempfile.open
+ tempfile.print string
+ tempfile.close
+ print diff(path, tempfile.path)
+ tempfile.delete
+ end
end
diff --git a/lib/puppet/util/docs.rb b/lib/puppet/util/docs.rb
index dc742d4b0..efd054d85 100644
--- a/lib/puppet/util/docs.rb
+++ b/lib/puppet/util/docs.rb
@@ -1,114 +1,114 @@
# Some simple methods for helping manage automatic documentation generation.
module Puppet::Util::Docs
- # Specify the actual doc string.
- def desc(str)
- @doc = str
+ # Specify the actual doc string.
+ def desc(str)
+ @doc = str
+ end
+
+ # Add a new autodoc block. We have to define these as class methods,
+ # rather than just sticking them in a hash, because otherwise they're
+ # too difficult to do inheritance with.
+ def dochook(name, &block)
+ method = "dochook_#{name}"
+
+ meta_def method, &block
+ end
+
+ attr_writer :doc
+
+ # Generate the full doc string.
+ def doc
+ extra = methods.find_all { |m| m.to_s =~ /^dochook_.+/ }.sort.collect { |m|
+ self.send(m)
+ }.join(" ")
+
+ if @doc
+ @doc + extra
+ else
+ extra
end
-
- # Add a new autodoc block. We have to define these as class methods,
- # rather than just sticking them in a hash, because otherwise they're
- # too difficult to do inheritance with.
- def dochook(name, &block)
- method = "dochook_#{name}"
-
- meta_def method, &block
+ end
+
+ # Build a table
+ def doctable(headers, data)
+ str = "\n\n"
+
+ lengths = []
+ # Figure out the longest field for all columns
+ data.each do |name, values|
+ [name, values].flatten.each_with_index do |value, i|
+ lengths[i] ||= 0
+ lengths[i] = value.to_s.length if value.to_s.length > lengths[i]
+ end
end
- attr_writer :doc
-
- # Generate the full doc string.
- def doc
- extra = methods.find_all { |m| m.to_s =~ /^dochook_.+/ }.sort.collect { |m|
- self.send(m)
- }.join(" ")
-
- if @doc
- @doc + extra
- else
- extra
- end
+ # The headers could also be longest
+ headers.each_with_index do |value, i|
+ lengths[i] = value.to_s.length if value.to_s.length > lengths[i]
end
- # Build a table
- def doctable(headers, data)
- str = "\n\n"
-
- lengths = []
- # Figure out the longest field for all columns
- data.each do |name, values|
- [name, values].flatten.each_with_index do |value, i|
- lengths[i] ||= 0
- lengths[i] = value.to_s.length if value.to_s.length > lengths[i]
- end
- end
-
- # The headers could also be longest
- headers.each_with_index do |value, i|
- lengths[i] = value.to_s.length if value.to_s.length > lengths[i]
- end
-
- # Add the top header row
- str += lengths.collect { |num| "=" * num }.join(" ") + "\n"
+ # Add the top header row
+ str += lengths.collect { |num| "=" * num }.join(" ") + "\n"
- # And the header names
- str += headers.zip(lengths).collect { |value, num| pad(value, num) }.join(" ") + "\n"
+ # And the header names
+ str += headers.zip(lengths).collect { |value, num| pad(value, num) }.join(" ") + "\n"
- # And the second header row
- str += lengths.collect { |num| "=" * num }.join(" ") + "\n"
+ # And the second header row
+ str += lengths.collect { |num| "=" * num }.join(" ") + "\n"
- # Now each data row
- data.sort { |a, b| a[0].to_s <=> b[0].to_s }.each do |name, rows|
- str += [name, rows].flatten.zip(lengths).collect do |value, length|
- pad(value, length)
- end.join(" ") + "\n"
- end
-
- # And the bottom line row
- str += lengths.collect { |num| "=" * num }.join(" ") + "\n"
-
- str + "\n"
- end
-
- attr_reader :nodoc
- def nodoc?
- nodoc
+ # Now each data row
+ data.sort { |a, b| a[0].to_s <=> b[0].to_s }.each do |name, rows|
+ str += [name, rows].flatten.zip(lengths).collect do |value, length|
+ pad(value, length)
+ end.join(" ") + "\n"
end
- # Pad a field with spaces
- def pad(value, length)
- value.to_s + (" " * (length - value.to_s.length))
+ # And the bottom line row
+ str += lengths.collect { |num| "=" * num }.join(" ") + "\n"
+
+ str + "\n"
+ end
+
+ attr_reader :nodoc
+ def nodoc?
+ nodoc
+ end
+
+ # Pad a field with spaces
+ def pad(value, length)
+ value.to_s + (" " * (length - value.to_s.length))
+ end
+
+ # Handle the inline indentation in the docs.
+ def scrub(text)
+ # Stupid markdown
+ #text = text.gsub("<%=", "&lt;%=")
+ # For text with no carriage returns, there's nothing to do.
+ return text if text !~ /\n/
+ indent = nil
+
+ # If we can match an indentation, then just remove that same level of
+ # indent from every line. However, ignore any indentation on the
+ # first line, since that can be inconsistent.
+ text = text.lstrip
+ text.gsub!(/^([\t]+)/) { |s| " "*8*s.length; } # Expand leading tabs
+ # Find first non-empty line after the first line:
+ line2start = (text =~ /(\n?\s*\n)/)
+ line2start += $1.length
+ if (text[line2start..-1] =~ /^([ ]+)\S/) == 0
+ indent = Regexp.quote($1)
+ begin
+ return text.gsub(/^#{indent}/,'')
+ rescue => detail
+ puts detail.backtrace
+ puts detail
+ end
+ else
+ return text
end
- # Handle the inline indentation in the docs.
- def scrub(text)
- # Stupid markdown
- #text = text.gsub("<%=", "&lt;%=")
- # For text with no carriage returns, there's nothing to do.
- return text if text !~ /\n/
- indent = nil
-
- # If we can match an indentation, then just remove that same level of
- # indent from every line. However, ignore any indentation on the
- # first line, since that can be inconsistent.
- text = text.lstrip
- text.gsub!(/^([\t]+)/) { |s| " "*8*s.length; } # Expand leading tabs
- # Find first non-empty line after the first line:
- line2start = (text =~ /(\n?\s*\n)/)
- line2start += $1.length
- if (text[line2start..-1] =~ /^([ ]+)\S/) == 0
- indent = Regexp.quote($1)
- begin
- return text.gsub(/^#{indent}/,'')
- rescue => detail
- puts detail.backtrace
- puts detail
- end
- else
- return text
- end
-
- end
+ end
- module_function :scrub
+ module_function :scrub
end
diff --git a/lib/puppet/util/errors.rb b/lib/puppet/util/errors.rb
index 6fa14d3df..5a7a7630b 100644
--- a/lib/puppet/util/errors.rb
+++ b/lib/puppet/util/errors.rb
@@ -1,63 +1,63 @@
# Some helper methods for throwing errors.
module Puppet::Util::Errors
- # Throw a dev error.
- def devfail(msg)
- self.fail(Puppet::DevError, msg)
+ # Throw a dev error.
+ def devfail(msg)
+ self.fail(Puppet::DevError, msg)
+ end
+
+ # Add line and file info if available and appropriate.
+ def adderrorcontext(error, other = nil)
+ error.line ||= self.line if self.respond_to?(:line) and self.line
+ error.file ||= self.file if self.respond_to?(:file) and self.file
+
+ error.set_backtrace other.backtrace if other and other.respond_to?(:backtrace)
+
+ error
+ end
+
+ def error_context
+ if file and line
+ " at #{file}:#{line}"
+ elsif line
+ " at line #{line}"
+ elsif file
+ " in #{file}"
+ else
+ ""
end
-
- # Add line and file info if available and appropriate.
- def adderrorcontext(error, other = nil)
- error.line ||= self.line if self.respond_to?(:line) and self.line
- error.file ||= self.file if self.respond_to?(:file) and self.file
-
- error.set_backtrace other.backtrace if other and other.respond_to?(:backtrace)
-
- error
+ end
+
+ # Wrap a call in such a way that we always throw the right exception and keep
+ # as much context as possible.
+ def exceptwrap(options = {})
+ options[:type] ||= Puppet::DevError
+ begin
+ return yield
+ rescue Puppet::Error => detail
+ raise adderrorcontext(detail)
+ rescue => detail
+ message = options[:message] || "#{self.class} failed with error #{detail.class}: #{detail}"
+
+ error = options[:type].new(message)
+ # We can't use self.fail here because it always expects strings,
+ # not exceptions.
+ raise adderrorcontext(error, detail)
end
- def error_context
- if file and line
- " at #{file}:#{line}"
- elsif line
- " at line #{line}"
- elsif file
- " in #{file}"
- else
- ""
- end
- end
+ retval
+ end
- # Wrap a call in such a way that we always throw the right exception and keep
- # as much context as possible.
- def exceptwrap(options = {})
- options[:type] ||= Puppet::DevError
- begin
- return yield
- rescue Puppet::Error => detail
- raise adderrorcontext(detail)
- rescue => detail
- message = options[:message] || "#{self.class} failed with error #{detail.class}: #{detail}"
-
- error = options[:type].new(message)
- # We can't use self.fail here because it always expects strings,
- # not exceptions.
- raise adderrorcontext(error, detail)
- end
-
- retval
+ # Throw an error, defaulting to a Puppet::Error.
+ def fail(*args)
+ if args[0].is_a?(Class)
+ type = args.shift
+ else
+ type = Puppet::Error
end
- # Throw an error, defaulting to a Puppet::Error.
- def fail(*args)
- if args[0].is_a?(Class)
- type = args.shift
- else
- type = Puppet::Error
- end
-
- error = adderrorcontext(type.new(args.join(" ")))
+ error = adderrorcontext(type.new(args.join(" ")))
- raise error
- end
+ raise error
+ end
end
diff --git a/lib/puppet/util/execution.rb b/lib/puppet/util/execution.rb
index 7db7137fb..dd820f856 100644
--- a/lib/puppet/util/execution.rb
+++ b/lib/puppet/util/execution.rb
@@ -1,21 +1,21 @@
module Puppet::Util::Execution
- module_function
+ module_function
- # Run some code with a specific environment. Resets the environment back to
- # what it was at the end of the code.
- def withenv(hash)
- oldvals = {}
- hash.each do |name, val|
- name = name.to_s
- oldvals[name] = ENV[name]
- ENV[name] = val
- end
+ # Run some code with a specific environment. Resets the environment back to
+ # what it was at the end of the code.
+ def withenv(hash)
+ oldvals = {}
+ hash.each do |name, val|
+ name = name.to_s
+ oldvals[name] = ENV[name]
+ ENV[name] = val
+ end
- yield
- ensure
- oldvals.each do |name, val|
- ENV[name] = val
- end
+ yield
+ ensure
+ oldvals.each do |name, val|
+ ENV[name] = val
end
+ end
end
diff --git a/lib/puppet/util/feature.rb b/lib/puppet/util/feature.rb
index 99587a06b..2f704104a 100644
--- a/lib/puppet/util/feature.rb
+++ b/lib/puppet/util/feature.rb
@@ -2,83 +2,83 @@
# Copyright (c) 2006. All rights reserved.
class Puppet::Util::Feature
- attr_reader :path
+ attr_reader :path
- # Create a new feature test. You have to pass the feature name,
- # and it must be unique. You can either provide a block that
- # will get executed immediately to determine if the feature
- # is present, or you can pass an option to determine it.
- # Currently, the only supported option is 'libs' (must be
- # passed as a symbol), which will make sure that each lib loads
- # successfully.
- def add(name, options = {})
- method = name.to_s + "?"
- raise ArgumentError, "Feature #{name} is already defined" if self.class.respond_to?(method)
+ # Create a new feature test. You have to pass the feature name,
+ # and it must be unique. You can either provide a block that
+ # will get executed immediately to determine if the feature
+ # is present, or you can pass an option to determine it.
+ # Currently, the only supported option is 'libs' (must be
+ # passed as a symbol), which will make sure that each lib loads
+ # successfully.
+ def add(name, options = {})
+ method = name.to_s + "?"
+ raise ArgumentError, "Feature #{name} is already defined" if self.class.respond_to?(method)
- if block_given?
- begin
- result = yield
- rescue Exception => detail
- warn "Failed to load feature test for #{name}: #{detail}"
- result = false
- end
- @results[name] = result
- end
-
- meta_def(method) do
- @results[name] = test(name, options) unless @results.include?(name)
- @results[name]
- end
+ if block_given?
+ begin
+ result = yield
+ rescue Exception => detail
+ warn "Failed to load feature test for #{name}: #{detail}"
+ result = false
+ end
+ @results[name] = result
end
- # Create a new feature collection.
- def initialize(path)
- @path = path
- @results = {}
- @loader = Puppet::Util::Autoload.new(self, @path)
+ meta_def(method) do
+ @results[name] = test(name, options) unless @results.include?(name)
+ @results[name]
end
+ end
- def load
- @loader.loadall
- end
+ # Create a new feature collection.
+ def initialize(path)
+ @path = path
+ @results = {}
+ @loader = Puppet::Util::Autoload.new(self, @path)
+ end
- def method_missing(method, *args)
- return super unless method.to_s =~ /\?$/
+ def load
+ @loader.loadall
+ end
- feature = method.to_s.sub(/\?$/, '')
- @loader.load(feature)
+ def method_missing(method, *args)
+ return super unless method.to_s =~ /\?$/
- respond_to?(method) && self.send(method)
- end
+ feature = method.to_s.sub(/\?$/, '')
+ @loader.load(feature)
- # Actually test whether the feature is present. We only want to test when
- # someone asks for the feature, so we don't unnecessarily load
- # files.
- def test(name, options)
- return true unless ary = options[:libs]
- ary = [ary] unless ary.is_a?(Array)
+ respond_to?(method) && self.send(method)
+ end
- ary.each do |lib|
- return false unless load_library(lib, name)
- end
+ # Actually test whether the feature is present. We only want to test when
+ # someone asks for the feature, so we don't unnecessarily load
+ # files.
+ def test(name, options)
+ return true unless ary = options[:libs]
+ ary = [ary] unless ary.is_a?(Array)
- # We loaded all of the required libraries
- true
+ ary.each do |lib|
+ return false unless load_library(lib, name)
end
- private
+ # We loaded all of the required libraries
+ true
+ end
+
+ private
- def load_library(lib, name)
- raise ArgumentError, "Libraries must be passed as strings not #{lib.class}" unless lib.is_a?(String)
+ def load_library(lib, name)
+ raise ArgumentError, "Libraries must be passed as strings not #{lib.class}" unless lib.is_a?(String)
- begin
- require lib
- rescue SystemExit,NoMemoryError
- raise
- rescue Exception
- Puppet.debug "Failed to load library '#{lib}' for feature '#{name}'"
- return false
- end
- true
+ begin
+ require lib
+ rescue SystemExit,NoMemoryError
+ raise
+ rescue Exception
+ Puppet.debug "Failed to load library '#{lib}' for feature '#{name}'"
+ return false
end
+ true
+ end
end
diff --git a/lib/puppet/util/file_locking.rb b/lib/puppet/util/file_locking.rb
index cfac5ba16..8b194ed83 100644
--- a/lib/puppet/util/file_locking.rb
+++ b/lib/puppet/util/file_locking.rb
@@ -1,44 +1,44 @@
require 'puppet/util'
module Puppet::Util::FileLocking
- module_function
+ module_function
- # Create a shared lock for reading
- def readlock(file)
- raise ArgumentError, "#{file} is not a file" unless !File.exists?(file) or File.file?(file)
- Puppet::Util.sync(file).synchronize(Sync::SH) do
- File.open(file) { |f|
- f.lock_shared { |lf| yield lf }
- }
- end
+ # Create a shared lock for reading
+ def readlock(file)
+ raise ArgumentError, "#{file} is not a file" unless !File.exists?(file) or File.file?(file)
+ Puppet::Util.sync(file).synchronize(Sync::SH) do
+ File.open(file) { |f|
+ f.lock_shared { |lf| yield lf }
+ }
end
+ end
- # Create an exclusive lock for writing, and do the writing in a
- # tmp file.
- def writelock(file, mode = nil)
- raise Puppet::DevError, "Cannot create #{file}; directory #{File.dirname(file)} does not exist" unless FileTest.directory?(File.dirname(file))
- raise ArgumentError, "#{file} is not a file" unless !File.exists?(file) or File.file?(file)
- tmpfile = file + ".tmp"
+ # Create an exclusive lock for writing, and do the writing in a
+ # tmp file.
+ def writelock(file, mode = nil)
+ raise Puppet::DevError, "Cannot create #{file}; directory #{File.dirname(file)} does not exist" unless FileTest.directory?(File.dirname(file))
+ raise ArgumentError, "#{file} is not a file" unless !File.exists?(file) or File.file?(file)
+ tmpfile = file + ".tmp"
- unless mode
- # It's far more likely that the file will be there than not, so it's
- # better to stat once to check for existence and mode.
- # If we can't stat, it's most likely because the file's not there,
- # but could also be because the directory isn't readable, in which case
- # we won't be able to write anyway.
- begin
- mode = File.stat(file).mode
- rescue
- mode = 0600
- end
- end
+ unless mode
+ # It's far more likely that the file will be there than not, so it's
+ # better to stat once to check for existence and mode.
+ # If we can't stat, it's most likely because the file's not there,
+ # but could also be because the directory isn't readable, in which case
+ # we won't be able to write anyway.
+ begin
+ mode = File.stat(file).mode
+ rescue
+ mode = 0600
+ end
+ end
- Puppet::Util.sync(file).synchronize(Sync::EX) do
- File.open(file, "w", mode) do |rf|
- rf.lock_exclusive do |lrf|
- yield lrf
- end
- end
+ Puppet::Util.sync(file).synchronize(Sync::EX) do
+ File.open(file, "w", mode) do |rf|
+ rf.lock_exclusive do |lrf|
+ yield lrf
end
+ end
end
+ end
end
diff --git a/lib/puppet/util/fileparsing.rb b/lib/puppet/util/fileparsing.rb
index bc3555915..5c2a29cd5 100644
--- a/lib/puppet/util/fileparsing.rb
+++ b/lib/puppet/util/fileparsing.rb
@@ -27,347 +27,347 @@
require 'puppet/util/methodhelper'
module Puppet::Util::FileParsing
- include Puppet::Util
- attr_writer :line_separator, :trailing_separator
-
- class FileRecord
- include Puppet::Util
- include Puppet::Util::MethodHelper
- attr_accessor :absent, :joiner, :rts, :separator, :rollup, :name, :match, :block_eval
-
- attr_reader :fields, :optional, :type
+ include Puppet::Util
+ attr_writer :line_separator, :trailing_separator
- INVALID_FIELDS = [:record_type, :target, :on_disk]
+ class FileRecord
+ include Puppet::Util
+ include Puppet::Util::MethodHelper
+ attr_accessor :absent, :joiner, :rts, :separator, :rollup, :name, :match, :block_eval
- # Customize this so we can do a bit of validation.
- def fields=(fields)
- @fields = fields.collect do |field|
- r = symbolize(field)
- raise ArgumentError.new("Cannot have fields named #{r}") if INVALID_FIELDS.include?(r)
- r
- end
- end
+ attr_reader :fields, :optional, :type
- def initialize(type, options = {}, &block)
- @type = symbolize(type)
- raise ArgumentError, "Invalid record type #{@type}" unless [:record, :text].include?(@type)
-
- set_options(options)
-
- if self.type == :record
- # Now set defaults.
- self.absent ||= ""
- self.separator ||= /\s+/
- self.joiner ||= " "
- self.optional ||= []
- @rollup = true unless defined?(@rollup)
- end
-
- if block_given?
- @block_eval ||= :process
-
- # Allow the developer to specify that a block should be instance-eval'ed.
- if @block_eval == :instance
- instance_eval(&block)
- else
- meta_def(@block_eval, &block)
- end
- end
- end
+ INVALID_FIELDS = [:record_type, :target, :on_disk]
- # Convert a record into a line by joining the fields together appropriately.
- # This is pulled into a separate method so it can be called by the hooks.
- def join(details)
- joinchar = self.joiner
-
- fields.collect { |field|
- # If the field is marked absent, use the appropriate replacement
- if details[field] == :absent or details[field] == [:absent] or details[field].nil?
- if self.optional.include?(field)
- self.absent
- else
- raise ArgumentError, "Field '#{field}' is required"
- end
- else
- details[field].to_s
- end
- }.reject { |c| c.nil?}.join(joinchar)
- end
+ # Customize this so we can do a bit of validation.
+ def fields=(fields)
+ @fields = fields.collect do |field|
+ r = symbolize(field)
+ raise ArgumentError.new("Cannot have fields named #{r}") if INVALID_FIELDS.include?(r)
+ r
+ end
+ end
- # Customize this so we can do a bit of validation.
- def optional=(optional)
- @optional = optional.collect do |field|
- symbolize(field)
- end
- end
+ def initialize(type, options = {}, &block)
+ @type = symbolize(type)
+ raise ArgumentError, "Invalid record type #{@type}" unless [:record, :text].include?(@type)
- # Create a hook that modifies the hash resulting from parsing.
- def post_parse=(block)
- meta_def(:post_parse, &block)
- end
+ set_options(options)
- # Create a hook that modifies the hash just prior to generation.
- def pre_gen=(block)
- meta_def(:pre_gen, &block)
- end
+ if self.type == :record
+ # Now set defaults.
+ self.absent ||= ""
+ self.separator ||= /\s+/
+ self.joiner ||= " "
+ self.optional ||= []
+ @rollup = true unless defined?(@rollup)
+ end
- # Are we a text type?
- def text?
- type == :text
- end
+ if block_given?
+ @block_eval ||= :process
- def to_line=(block)
- meta_def(:to_line, &block)
+ # Allow the developer to specify that a block should be instance-eval'ed.
+ if @block_eval == :instance
+ instance_eval(&block)
+ else
+ meta_def(@block_eval, &block)
end
+ end
end
- # Clear all existing record definitions. Only used for testing.
- def clear_records
- @record_types.clear
- @record_order.clear
- end
-
- def fields(type)
- if record = record_type(type)
- record.fields.dup
+ # Convert a record into a line by joining the fields together appropriately.
+ # This is pulled into a separate method so it can be called by the hooks.
+ def join(details)
+ joinchar = self.joiner
+
+ fields.collect { |field|
+ # If the field is marked absent, use the appropriate replacement
+ if details[field] == :absent or details[field] == [:absent] or details[field].nil?
+ if self.optional.include?(field)
+ self.absent
+ else
+ raise ArgumentError, "Field '#{field}' is required"
+ end
else
- nil
+ details[field].to_s
end
+ }.reject { |c| c.nil?}.join(joinchar)
end
- # Try to match a specific text line.
- def handle_text_line(line, record)
- line =~ record.match ? {:record_type => record.name, :line => line} : nil
+ # Customize this so we can do a bit of validation.
+ def optional=(optional)
+ @optional = optional.collect do |field|
+ symbolize(field)
+ end
end
- # Try to match a record.
- def handle_record_line(line, record)
- ret = nil
- if record.respond_to?(:process)
- if ret = record.send(:process, line.dup)
- unless ret.is_a?(Hash)
- raise Puppet::DevError,
- "Process record type #{record.name} returned non-hash"
- end
- else
- return nil
- end
- elsif regex = record.match
- # In this case, we try to match the whole line and then use the
- # match captures to get our fields.
- if match = regex.match(line)
- fields = []
- ret = {}
- record.fields.zip(match.captures).each do |field, value|
- if value == record.absent
- ret[field] = :absent
- else
- ret[field] = value
- end
- end
- else
- nil
- end
- else
- ret = {}
- sep = record.separator
-
- # String "helpfully" replaces ' ' with /\s+/ in splitting, so we
- # have to work around it.
- if sep == " "
- sep = / /
- end
- line_fields = line.split(sep)
- record.fields.each do |param|
- value = line_fields.shift
- if value and value != record.absent
- ret[param] = value
- else
- ret[param] = :absent
- end
- end
-
- if record.rollup and ! line_fields.empty?
- last_field = record.fields[-1]
- val = ([ret[last_field]] + line_fields).join(record.joiner)
- ret[last_field] = val
- end
- end
-
- if ret
- ret[:record_type] = record.name
- return ret
- else
- return nil
- end
+ # Create a hook that modifies the hash resulting from parsing.
+ def post_parse=(block)
+ meta_def(:post_parse, &block)
end
- def line_separator
- @line_separator ||= "\n"
-
- @line_separator
+ # Create a hook that modifies the hash just prior to generation.
+ def pre_gen=(block)
+ meta_def(:pre_gen, &block)
end
- # Split text into separate lines using the record separator.
- def lines(text)
- # Remove any trailing separators, and then split based on them
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- x = text.sub(/#{self.line_separator}\Q/,'').split(self.line_separator)
+ # Are we a text type?
+ def text?
+ type == :text
end
- # Split a bunch of text into lines and then parse them individually.
- def parse(text)
- count = 1
- lines(text).collect do |line|
- count += 1
- if val = parse_line(line)
- val
- else
- error = Puppet::Error.new("Could not parse line #{line.inspect}")
- error.line = count
- raise error
- end
- end
+ def to_line=(block)
+ meta_def(:to_line, &block)
end
-
- # Handle parsing a single line.
- def parse_line(line)
- raise Puppet::DevError, "No record types defined; cannot parse lines" unless records?
-
- @record_order.each do |record|
- # These are basically either text or record lines.
- method = "handle_#{record.type}_line"
- if respond_to?(method)
- if result = send(method, line, record)
- record.send(:post_parse, result) if record.respond_to?(:post_parse)
- return result
- end
- else
- raise Puppet::DevError,
- "Somehow got invalid line type #{record.type}"
- end
+ end
+
+ # Clear all existing record definitions. Only used for testing.
+ def clear_records
+ @record_types.clear
+ @record_order.clear
+ end
+
+ def fields(type)
+ if record = record_type(type)
+ record.fields.dup
+ else
+ nil
+ end
+ end
+
+ # Try to match a specific text line.
+ def handle_text_line(line, record)
+ line =~ record.match ? {:record_type => record.name, :line => line} : nil
+ end
+
+ # Try to match a record.
+ def handle_record_line(line, record)
+ ret = nil
+ if record.respond_to?(:process)
+ if ret = record.send(:process, line.dup)
+ unless ret.is_a?(Hash)
+ raise Puppet::DevError,
+ "Process record type #{record.name} returned non-hash"
end
-
+ else
+ return nil
+ end
+ elsif regex = record.match
+ # In this case, we try to match the whole line and then use the
+ # match captures to get our fields.
+ if match = regex.match(line)
+ fields = []
+ ret = {}
+ record.fields.zip(match.captures).each do |field, value|
+ if value == record.absent
+ ret[field] = :absent
+ else
+ ret[field] = value
+ end
+ end
+ else
nil
- end
+ end
+ else
+ ret = {}
+ sep = record.separator
+
+ # String "helpfully" replaces ' ' with /\s+/ in splitting, so we
+ # have to work around it.
+ if sep == " "
+ sep = / /
+ end
+ line_fields = line.split(sep)
+ record.fields.each do |param|
+ value = line_fields.shift
+ if value and value != record.absent
+ ret[param] = value
+ else
+ ret[param] = :absent
+ end
+ end
- # Define a new type of record. These lines get split into hashes. Valid
- # options are:
- # * <tt>:absent</tt>: What to use as value within a line, when a field is
- # absent. Note that in the record object, the literal :absent symbol is
- # used, and not this value. Defaults to "".
- # * <tt>:fields</tt>: The list of fields, as an array. By default, all
- # fields are considered required.
- # * <tt>:joiner</tt>: How to join fields together. Defaults to '\t'.
- # * <tt>:optional</tt>: Which fields are optional. If these are missing,
- # you'll just get the 'absent' value instead of an ArgumentError.
- # * <tt>:rts</tt>: Whether to remove trailing whitespace. Defaults to false.
- # If true, whitespace will be removed; if a regex, then whatever matches
- # the regex will be removed.
- # * <tt>:separator</tt>: The record separator. Defaults to /\s+/.
- def record_line(name, options, &block)
- raise ArgumentError, "Must include a list of fields" unless options.include?(:fields)
-
- record = FileRecord.new(:record, options, &block)
- record.name = symbolize(name)
-
- new_line_type(record)
+ if record.rollup and ! line_fields.empty?
+ last_field = record.fields[-1]
+ val = ([ret[last_field]] + line_fields).join(record.joiner)
+ ret[last_field] = val
+ end
end
- # Are there any record types defined?
- def records?
- defined?(@record_types) and ! @record_types.empty?
+ if ret
+ ret[:record_type] = record.name
+ return ret
+ else
+ return nil
end
-
- # Define a new type of text record.
- def text_line(name, options, &block)
- raise ArgumentError, "You must provide a :match regex for text lines" unless options.include?(:match)
-
- record = FileRecord.new(:text, options, &block)
- record.name = symbolize(name)
-
- new_line_type(record)
+ end
+
+ def line_separator
+ @line_separator ||= "\n"
+
+ @line_separator
+ end
+
+ # Split text into separate lines using the record separator.
+ def lines(text)
+ # Remove any trailing separators, and then split based on them
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ x = text.sub(/#{self.line_separator}\Q/,'').split(self.line_separator)
+ end
+
+ # Split a bunch of text into lines and then parse them individually.
+ def parse(text)
+ count = 1
+ lines(text).collect do |line|
+ count += 1
+ if val = parse_line(line)
+ val
+ else
+ error = Puppet::Error.new("Could not parse line #{line.inspect}")
+ error.line = count
+ raise error
+ end
+ end
+ end
+
+ # Handle parsing a single line.
+ def parse_line(line)
+ raise Puppet::DevError, "No record types defined; cannot parse lines" unless records?
+
+ @record_order.each do |record|
+ # These are basically either text or record lines.
+ method = "handle_#{record.type}_line"
+ if respond_to?(method)
+ if result = send(method, line, record)
+ record.send(:post_parse, result) if record.respond_to?(:post_parse)
+ return result
+ end
+ else
+ raise Puppet::DevError,
+ "Somehow got invalid line type #{record.type}"
+ end
end
- # Generate a file from a bunch of hash records.
- def to_file(records)
- text = records.collect { |record| to_line(record) }.join(line_separator)
-
- text += line_separator if trailing_separator
+ nil
+ end
+
+ # Define a new type of record. These lines get split into hashes. Valid
+ # options are:
+ # * <tt>:absent</tt>: What to use as value within a line, when a field is
+ # absent. Note that in the record object, the literal :absent symbol is
+ # used, and not this value. Defaults to "".
+ # * <tt>:fields</tt>: The list of fields, as an array. By default, all
+ # fields are considered required.
+ # * <tt>:joiner</tt>: How to join fields together. Defaults to '\t'.
+ # * <tt>:optional</tt>: Which fields are optional. If these are missing,
+ # you'll just get the 'absent' value instead of an ArgumentError.
+ # * <tt>:rts</tt>: Whether to remove trailing whitespace. Defaults to false.
+ # If true, whitespace will be removed; if a regex, then whatever matches
+ # the regex will be removed.
+ # * <tt>:separator</tt>: The record separator. Defaults to /\s+/.
+ def record_line(name, options, &block)
+ raise ArgumentError, "Must include a list of fields" unless options.include?(:fields)
+
+ record = FileRecord.new(:record, options, &block)
+ record.name = symbolize(name)
+
+ new_line_type(record)
+ end
+
+ # Are there any record types defined?
+ def records?
+ defined?(@record_types) and ! @record_types.empty?
+ end
+
+ # Define a new type of text record.
+ def text_line(name, options, &block)
+ raise ArgumentError, "You must provide a :match regex for text lines" unless options.include?(:match)
+
+ record = FileRecord.new(:text, options, &block)
+ record.name = symbolize(name)
+
+ new_line_type(record)
+ end
+
+ # Generate a file from a bunch of hash records.
+ def to_file(records)
+ text = records.collect { |record| to_line(record) }.join(line_separator)
+
+ text += line_separator if trailing_separator
+
+ text
+ end
+
+ # Convert our parsed record into a text record.
+ def to_line(details)
+ unless record = record_type(details[:record_type])
+ raise ArgumentError, "Invalid record type #{details[:record_type].inspect}"
+ end
- text
+ if record.respond_to?(:pre_gen)
+ details = details.dup
+ record.send(:pre_gen, details)
end
- # Convert our parsed record into a text record.
- def to_line(details)
- unless record = record_type(details[:record_type])
- raise ArgumentError, "Invalid record type #{details[:record_type].inspect}"
- end
+ case record.type
+ when :text; return details[:line]
+ else
+ return record.to_line(details) if record.respond_to?(:to_line)
- if record.respond_to?(:pre_gen)
- details = details.dup
- record.send(:pre_gen, details)
- end
+ line = record.join(details)
- case record.type
- when :text; return details[:line]
- else
- return record.to_line(details) if record.respond_to?(:to_line)
-
- line = record.join(details)
-
- if regex = record.rts
- # If they say true, then use whitespace; else, use their regex.
- if regex == true
- regex = /\s+$/
- end
- return line.sub(regex,'')
- else
- return line
- end
+ if regex = record.rts
+ # If they say true, then use whitespace; else, use their regex.
+ if regex == true
+ regex = /\s+$/
end
+ return line.sub(regex,'')
+ else
+ return line
+ end
end
-
- # Whether to add a trailing separator to the file. Defaults to true
- def trailing_separator
- if defined?(@trailing_separator)
- return @trailing_separator
- else
- return true
- end
+ end
+
+ # Whether to add a trailing separator to the file. Defaults to true
+ def trailing_separator
+ if defined?(@trailing_separator)
+ return @trailing_separator
+ else
+ return true
end
-
- def valid_attr?(type, attr)
- type = symbolize(type)
- if record = record_type(type) and record.fields.include?(symbolize(attr))
- return true
- else
- if symbolize(attr) == :ensure
- return true
- else
- false
- end
- end
+ end
+
+ def valid_attr?(type, attr)
+ type = symbolize(type)
+ if record = record_type(type) and record.fields.include?(symbolize(attr))
+ return true
+ else
+ if symbolize(attr) == :ensure
+ return true
+ else
+ false
+ end
end
+ end
- private
+ private
- # Define a new type of record.
- def new_line_type(record)
- @record_types ||= {}
- @record_order ||= []
+ # Define a new type of record.
+ def new_line_type(record)
+ @record_types ||= {}
+ @record_order ||= []
- raise ArgumentError, "Line type #{record.name} is already defined" if @record_types.include?(record.name)
+ raise ArgumentError, "Line type #{record.name} is already defined" if @record_types.include?(record.name)
- @record_types[record.name] = record
- @record_order << record
+ @record_types[record.name] = record
+ @record_order << record
- record
- end
+ record
+ end
- # Retrieve the record object.
- def record_type(type)
- @record_types[symbolize(type)]
- end
+ # Retrieve the record object.
+ def record_type(type)
+ @record_types[symbolize(type)]
+ end
end
diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb
index bacc7d2b6..fdc6ccd9b 100755
--- a/lib/puppet/util/filetype.rb
+++ b/lib/puppet/util/filetype.rb
@@ -5,279 +5,279 @@ require 'puppet/util/selinux'
require 'fileutils'
class Puppet::Util::FileType
- attr_accessor :loaded, :path, :synced
+ attr_accessor :loaded, :path, :synced
- include Puppet::Util::SELinux
+ include Puppet::Util::SELinux
- class << self
- attr_accessor :name
- include Puppet::Util::ClassGen
- end
+ class << self
+ attr_accessor :name
+ include Puppet::Util::ClassGen
+ end
- # Create a new filetype.
- def self.newfiletype(name, &block)
- @filetypes ||= {}
+ # Create a new filetype.
+ def self.newfiletype(name, &block)
+ @filetypes ||= {}
- klass = genclass(
- name,
- :block => block,
- :prefix => "FileType",
+ klass = genclass(
+ name,
+ :block => block,
+ :prefix => "FileType",
- :hash => @filetypes
- )
-
- # Rename the read and write methods, so that we're sure they
- # maintain the stats.
- klass.class_eval do
- # Rename the read method
- define_method(:real_read, instance_method(:read))
- define_method(:read) do
- begin
- val = real_read
- @loaded = Time.now
- if val
- return val.gsub(/# HEADER.*\n/,'')
- else
- return ""
- end
- rescue Puppet::Error => detail
- raise
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- raise Puppet::Error, "#{self.class} could not read #{@path}: #{detail}"
- end
- end
-
- # And then the write method
- define_method(:real_write, instance_method(:write))
- define_method(:write) do |text|
- begin
- val = real_write(text)
- @synced = Time.now
- return val
- rescue Puppet::Error => detail
- raise
- rescue => detail
- puts detail.backtrace if Puppet[:debug]
- raise Puppet::Error, "#{self.class} could not write #{@path}: #{detail}"
- end
- end
+ :hash => @filetypes
+ )
+
+ # Rename the read and write methods, so that we're sure they
+ # maintain the stats.
+ klass.class_eval do
+ # Rename the read method
+ define_method(:real_read, instance_method(:read))
+ define_method(:read) do
+ begin
+ val = real_read
+ @loaded = Time.now
+ if val
+ return val.gsub(/# HEADER.*\n/,'')
+ else
+ return ""
+ end
+ rescue Puppet::Error => detail
+ raise
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ raise Puppet::Error, "#{self.class} could not read #{@path}: #{detail}"
+ end
+ end
+
+ # And then the write method
+ define_method(:real_write, instance_method(:write))
+ define_method(:write) do |text|
+ begin
+ val = real_write(text)
+ @synced = Time.now
+ return val
+ rescue Puppet::Error => detail
+ raise
+ rescue => detail
+ puts detail.backtrace if Puppet[:debug]
+ raise Puppet::Error, "#{self.class} could not write #{@path}: #{detail}"
end
+ end
end
-
- def self.filetype(type)
- @filetypes[type]
+ end
+
+ def self.filetype(type)
+ @filetypes[type]
+ end
+
+ # Pick or create a filebucket to use.
+ def bucket
+ @bucket ||= Puppet::Type.type(:filebucket).mkdefaultbucket.bucket
+ end
+
+ def initialize(path)
+ raise ArgumentError.new("Path is nil") if path.nil?
+ @path = path
+ end
+
+ # Operate on plain files.
+ newfiletype(:flat) do
+ # Back the file up before replacing it.
+ def backup
+ bucket.backup(@path) if File.exists?(@path)
end
- # Pick or create a filebucket to use.
- def bucket
- @bucket ||= Puppet::Type.type(:filebucket).mkdefaultbucket.bucket
+ # Read the file.
+ def read
+ if File.exist?(@path)
+ File.read(@path)
+ else
+ return nil
+ end
end
- def initialize(path)
- raise ArgumentError.new("Path is nil") if path.nil?
- @path = path
+ # Remove the file.
+ def remove
+ File.unlink(@path) if File.exist?(@path)
end
- # Operate on plain files.
- newfiletype(:flat) do
- # Back the file up before replacing it.
- def backup
- bucket.backup(@path) if File.exists?(@path)
- end
-
- # Read the file.
- def read
- if File.exist?(@path)
- File.read(@path)
- else
- return nil
- end
- end
-
- # Remove the file.
- def remove
- File.unlink(@path) if File.exist?(@path)
- end
-
- # Overwrite the file.
- def write(text)
- require "tempfile"
- tf = Tempfile.new("puppet")
- tf.print text; tf.flush
- FileUtils.cp(tf.path, @path)
- tf.close
- # If SELinux is present, we need to ensure the file has its expected context
- set_selinux_default_context(@path)
- end
+ # Overwrite the file.
+ def write(text)
+ require "tempfile"
+ tf = Tempfile.new("puppet")
+ tf.print text; tf.flush
+ FileUtils.cp(tf.path, @path)
+ tf.close
+ # If SELinux is present, we need to ensure the file has its expected context
+ set_selinux_default_context(@path)
end
+ end
- # Operate on plain files.
- newfiletype(:ram) do
- @@tabs = {}
+ # Operate on plain files.
+ newfiletype(:ram) do
+ @@tabs = {}
- def self.clear
- @@tabs.clear
- end
-
- def initialize(path)
- super
- @@tabs[@path] ||= ""
- end
-
- # Read the file.
- def read
- Puppet.info "Reading #{@path} from RAM"
- @@tabs[@path]
- end
+ def self.clear
+ @@tabs.clear
+ end
- # Remove the file.
- def remove
- Puppet.info "Removing #{@path} from RAM"
- @@tabs[@path] = ""
- end
+ def initialize(path)
+ super
+ @@tabs[@path] ||= ""
+ end
- # Overwrite the file.
- def write(text)
- Puppet.info "Writing #{@path} to RAM"
- @@tabs[@path] = text
- end
+ # Read the file.
+ def read
+ Puppet.info "Reading #{@path} from RAM"
+ @@tabs[@path]
end
- # Handle Linux-style cron tabs.
- newfiletype(:crontab) do
- def initialize(user)
- self.path = user
- end
+ # Remove the file.
+ def remove
+ Puppet.info "Removing #{@path} from RAM"
+ @@tabs[@path] = ""
+ end
- def path=(user)
- begin
- @uid = Puppet::Util.uid(user)
- rescue Puppet::Error => detail
- raise Puppet::Error, "Could not retrieve user #{user}"
- end
+ # Overwrite the file.
+ def write(text)
+ Puppet.info "Writing #{@path} to RAM"
+ @@tabs[@path] = text
+ end
+ end
- # XXX We have to have the user name, not the uid, because some
- # systems *cough*linux*cough* require it that way
- @path = user
- end
+ # Handle Linux-style cron tabs.
+ newfiletype(:crontab) do
+ def initialize(user)
+ self.path = user
+ end
- # Read a specific @path's cron tab.
- def read
- %x{#{cmdbase} -l 2>/dev/null}
- end
+ def path=(user)
+ begin
+ @uid = Puppet::Util.uid(user)
+ rescue Puppet::Error => detail
+ raise Puppet::Error, "Could not retrieve user #{user}"
+ end
- # Remove a specific @path's cron tab.
- def remove
- if %w{Darwin FreeBSD}.include?(Facter.value("operatingsystem"))
- %x{/bin/echo yes | #{cmdbase} -r 2>/dev/null}
- else
- %x{#{cmdbase} -r 2>/dev/null}
- end
- end
+ # XXX We have to have the user name, not the uid, because some
+ # systems *cough*linux*cough* require it that way
+ @path = user
+ end
- # Overwrite a specific @path's cron tab; must be passed the @path name
- # and the text with which to create the cron tab.
- def write(text)
- IO.popen("#{cmdbase()} -", "w") { |p|
- p.print text
- }
- end
+ # Read a specific @path's cron tab.
+ def read
+ %x{#{cmdbase} -l 2>/dev/null}
+ end
- private
-
- # Only add the -u flag when the @path is different. Fedora apparently
- # does not think I should be allowed to set the @path to my own user name
- def cmdbase
- cmd = nil
- if @uid == Puppet::Util::SUIDManager.uid || Facter.value(:operatingsystem) == "HP-UX"
- return "crontab"
- else
- return "crontab -u #{@path}"
- end
- end
+ # Remove a specific @path's cron tab.
+ def remove
+ if %w{Darwin FreeBSD}.include?(Facter.value("operatingsystem"))
+ %x{/bin/echo yes | #{cmdbase} -r 2>/dev/null}
+ else
+ %x{#{cmdbase} -r 2>/dev/null}
+ end
end
- # SunOS has completely different cron commands; this class implements
- # its versions.
- newfiletype(:suntab) do
- # Read a specific @path's cron tab.
- def read
- output = Puppet::Util.execute(%w{crontab -l}, :uid => @path)
- return "" if output.include?("can't open your crontab")
- raise Puppet::Error, "User #{@path} not authorized to use cron" if output.include?("you are not authorized to use cron")
- return output
- rescue => detail
- raise Puppet::Error, "Could not read crontab for #{@path}: #{detail}"
- end
+ # Overwrite a specific @path's cron tab; must be passed the @path name
+ # and the text with which to create the cron tab.
+ def write(text)
+ IO.popen("#{cmdbase()} -", "w") { |p|
+ p.print text
+ }
+ end
- # Remove a specific @path's cron tab.
- def remove
- Puppet::Util.execute(%w{crontab -r}, :uid => @path)
- rescue => detail
- raise Puppet::Error, "Could not remove crontab for #{@path}: #{detail}"
- end
+ private
+
+ # Only add the -u flag when the @path is different. Fedora apparently
+ # does not think I should be allowed to set the @path to my own user name
+ def cmdbase
+ cmd = nil
+ if @uid == Puppet::Util::SUIDManager.uid || Facter.value(:operatingsystem) == "HP-UX"
+ return "crontab"
+ else
+ return "crontab -u #{@path}"
+ end
+ end
+ end
+
+ # SunOS has completely different cron commands; this class implements
+ # its versions.
+ newfiletype(:suntab) do
+ # Read a specific @path's cron tab.
+ def read
+ output = Puppet::Util.execute(%w{crontab -l}, :uid => @path)
+ return "" if output.include?("can't open your crontab")
+ raise Puppet::Error, "User #{@path} not authorized to use cron" if output.include?("you are not authorized to use cron")
+ return output
+ rescue => detail
+ raise Puppet::Error, "Could not read crontab for #{@path}: #{detail}"
+ end
- # Overwrite a specific @path's cron tab; must be passed the @path name
- # and the text with which to create the cron tab.
- def write(text)
- puts text
- require "tempfile"
- output_file = Tempfile.new("puppet")
- fh = output_file.open
- fh.print text
- fh.close
-
- # We have to chown the stupid file to the user.
- File.chown(Puppet::Util.uid(@path), nil, output_file.path)
-
- begin
- Puppet::Util.execute(["crontab", output_file.path], :uid => @path)
- rescue => detail
- raise Puppet::Error, "Could not write crontab for #{@path}: #{detail}"
- end
- output_file.delete
- end
+ # Remove a specific @path's cron tab.
+ def remove
+ Puppet::Util.execute(%w{crontab -r}, :uid => @path)
+ rescue => detail
+ raise Puppet::Error, "Could not remove crontab for #{@path}: #{detail}"
end
- # Support for AIX crontab with output different than suntab's crontab command.
- newfiletype(:aixtab) do
- # Read a specific @path's cron tab.
- def read
- output = Puppet::Util.execute(%w{crontab -l}, :uid => @path)
- raise Puppet::Error, "User #{@path} not authorized to use cron" if output.include?("You are not authorized to use the cron command")
- return output
- rescue => detail
- raise Puppet::Error, "Could not read crontab for #{@path}: #{detail}"
- end
+ # Overwrite a specific @path's cron tab; must be passed the @path name
+ # and the text with which to create the cron tab.
+ def write(text)
+ puts text
+ require "tempfile"
+ output_file = Tempfile.new("puppet")
+ fh = output_file.open
+ fh.print text
+ fh.close
+
+ # We have to chown the stupid file to the user.
+ File.chown(Puppet::Util.uid(@path), nil, output_file.path)
+
+ begin
+ Puppet::Util.execute(["crontab", output_file.path], :uid => @path)
+ rescue => detail
+ raise Puppet::Error, "Could not write crontab for #{@path}: #{detail}"
+ end
+ output_file.delete
+ end
+ end
+
+ # Support for AIX crontab with output different than suntab's crontab command.
+ newfiletype(:aixtab) do
+ # Read a specific @path's cron tab.
+ def read
+ output = Puppet::Util.execute(%w{crontab -l}, :uid => @path)
+ raise Puppet::Error, "User #{@path} not authorized to use cron" if output.include?("You are not authorized to use the cron command")
+ return output
+ rescue => detail
+ raise Puppet::Error, "Could not read crontab for #{@path}: #{detail}"
+ end
- # Remove a specific @path's cron tab.
- def remove
- Puppet::Util.execute(%w{crontab -r}, :uid => @path)
- rescue => detail
- raise Puppet::Error, "Could not remove crontab for #{@path}: #{detail}"
- end
+ # Remove a specific @path's cron tab.
+ def remove
+ Puppet::Util.execute(%w{crontab -r}, :uid => @path)
+ rescue => detail
+ raise Puppet::Error, "Could not remove crontab for #{@path}: #{detail}"
+ end
- # Overwrite a specific @path's cron tab; must be passed the @path name
- # and the text with which to create the cron tab.
- def write(text)
- require "tempfile"
- output_file = Tempfile.new("puppet")
- fh = output_file.open
- fh.print text
- fh.close
-
- # We have to chown the stupid file to the user.
- File.chown(Puppet::Util.uid(@path), nil, output_file.path)
-
- begin
- Puppet::Util.execute(["crontab", output_file.path], :uid => @path)
- rescue => detail
- raise Puppet::Error, "Could not write crontab for #{@path}: #{detail}"
- ensure
- output_file.delete
- end
- end
+ # Overwrite a specific @path's cron tab; must be passed the @path name
+ # and the text with which to create the cron tab.
+ def write(text)
+ require "tempfile"
+ output_file = Tempfile.new("puppet")
+ fh = output_file.open
+ fh.print text
+ fh.close
+
+ # We have to chown the stupid file to the user.
+ File.chown(Puppet::Util.uid(@path), nil, output_file.path)
+
+ begin
+ Puppet::Util.execute(["crontab", output_file.path], :uid => @path)
+ rescue => detail
+ raise Puppet::Error, "Could not write crontab for #{@path}: #{detail}"
+ ensure
+ output_file.delete
+ end
end
+ end
end
diff --git a/lib/puppet/util/graph.rb b/lib/puppet/util/graph.rb
index 5dd55e951..9598d281e 100644
--- a/lib/puppet/util/graph.rb
+++ b/lib/puppet/util/graph.rb
@@ -6,25 +6,25 @@ require 'puppet/simple_graph'
# A module that handles the small amount of graph stuff in Puppet.
module Puppet::Util::Graph
- # Make a graph where each of our children gets converted to
- # the receiving end of an edge. Call the same thing on all
- # of our children, optionally using a block
- def to_graph(graph = nil, &block)
- # Allow our calling function to send in a graph, so that we
- # can call this recursively with one graph.
- graph ||= Puppet::SimpleGraph.new
+ # Make a graph where each of our children gets converted to
+ # the receiving end of an edge. Call the same thing on all
+ # of our children, optionally using a block
+ def to_graph(graph = nil, &block)
+ # Allow our calling function to send in a graph, so that we
+ # can call this recursively with one graph.
+ graph ||= Puppet::SimpleGraph.new
- self.each do |child|
- unless block_given? and ! yield(child)
- graph.add_edge(self, child)
+ self.each do |child|
+ unless block_given? and ! yield(child)
+ graph.add_edge(self, child)
- child.to_graph(graph, &block) if child.respond_to?(:to_graph)
- end
- end
+ child.to_graph(graph, &block) if child.respond_to?(:to_graph)
+ end
+ end
- # Do a topsort, which will throw an exception if the graph is cyclic.
+ # Do a topsort, which will throw an exception if the graph is cyclic.
- graph
- end
+ graph
+ end
end
diff --git a/lib/puppet/util/inifile.rb b/lib/puppet/util/inifile.rb
index 276f741c5..82f074d53 100644
--- a/lib/puppet/util/inifile.rb
+++ b/lib/puppet/util/inifile.rb
@@ -11,193 +11,193 @@
require 'puppet/util/filetype'
module Puppet::Util::IniConfig
- # A section in a .ini file
- class Section
- attr_reader :name, :file
-
- def initialize(name, file)
- @name = name
- @file = file
- @dirty = false
- @entries = []
- end
-
- # Has this section been modified since it's been read in
- # or written back to disk
- def dirty?
- @dirty
- end
+ # A section in a .ini file
+ class Section
+ attr_reader :name, :file
+
+ def initialize(name, file)
+ @name = name
+ @file = file
+ @dirty = false
+ @entries = []
+ end
- # Should only be used internally
- def mark_clean
- @dirty = false
- end
+ # Has this section been modified since it's been read in
+ # or written back to disk
+ def dirty?
+ @dirty
+ end
- # Add a line of text (e.g., a comment) Such lines
- # will be written back out in exactly the same
- # place they were read in
- def add_line(line)
- @entries << line
- end
+ # Should only be used internally
+ def mark_clean
+ @dirty = false
+ end
- # Set the entry 'key=value'. If no entry with the
- # given key exists, one is appended to teh end of the section
- def []=(key, value)
- entry = find_entry(key)
- @dirty = true
- if entry.nil?
- @entries << [key, value]
- else
- entry[1] = value
- end
- end
+ # Add a line of text (e.g., a comment) Such lines
+ # will be written back out in exactly the same
+ # place they were read in
+ def add_line(line)
+ @entries << line
+ end
- # Return the value associated with KEY. If no such entry
- # exists, return nil
- def [](key)
- entry = find_entry(key)
- return(entry.nil? ? nil : entry[1])
- end
+ # Set the entry 'key=value'. If no entry with the
+ # given key exists, one is appended to teh end of the section
+ def []=(key, value)
+ entry = find_entry(key)
+ @dirty = true
+ if entry.nil?
+ @entries << [key, value]
+ else
+ entry[1] = value
+ end
+ end
- # Format the section as text in the way it should be
- # written to file
- def format
- text = "[#{name}]\n"
- @entries.each do |entry|
- if entry.is_a?(Array)
- key, value = entry
- text << "#{key}=#{value}\n" unless value.nil?
- else
- text << entry
- end
- end
- text
- end
+ # Return the value associated with KEY. If no such entry
+ # exists, return nil
+ def [](key)
+ entry = find_entry(key)
+ return(entry.nil? ? nil : entry[1])
+ end
- private
- def find_entry(key)
- @entries.each do |entry|
- return entry if entry.is_a?(Array) && entry[0] == key
- end
- nil
- end
+ # Format the section as text in the way it should be
+ # written to file
+ def format
+ text = "[#{name}]\n"
+ @entries.each do |entry|
+ if entry.is_a?(Array)
+ key, value = entry
+ text << "#{key}=#{value}\n" unless value.nil?
+ else
+ text << entry
+ end
+ end
+ text
+ end
+ private
+ def find_entry(key)
+ @entries.each do |entry|
+ return entry if entry.is_a?(Array) && entry[0] == key
+ end
+ nil
end
- # A logical .ini-file that can be spread across several physical
- # files. For each physical file, call #read with the filename
- class File
- def initialize
- @files = {}
- end
+ end
- # Add the contents of the file with name FILE to the
- # already existing sections
- def read(file)
- text = Puppet::Util::FileType.filetype(:flat).new(file).read
- raise "Could not find #{file}" if text.nil?
-
- section = nil # The name of the current section
- optname = nil # The name of the last option in section
- line = 0
- @files[file] = []
- text.each_line do |l|
- line += 1
- if l.strip.empty? || "#;".include?(l[0,1]) ||
- (l.split(nil, 2)[0].downcase == "rem" && l[0,1].downcase == "r")
- # Whitespace or comment
- if section.nil?
- @files[file] << l
- else
- section.add_line(l)
- end
- elsif " \t\r\n\f".include?(l[0,1]) && section && optname
- # continuation line
- section[optname] += "\n#{l.chomp}"
- elsif l =~ /^\[([^\]]+)\]/
- # section heading
- section.mark_clean unless section.nil?
- section = add_section($1, file)
- optname = nil
- elsif l =~ /^\s*([^\s=]+)\s*\=(.*)$/
- # We allow space around the keys, but not the values
- # For the values, we don't know if space is significant
- if section.nil?
- raise "#{file}:#{line}:Key/value pair outside of a section for key #{$1}"
- else
- section[$1] = $2
- optname = $1
- end
- else
- raise "#{file}:#{line}: Can't parse '#{l.chomp}'"
- end
- end
- section.mark_clean unless section.nil?
- end
+ # A logical .ini-file that can be spread across several physical
+ # files. For each physical file, call #read with the filename
+ class File
+ def initialize
+ @files = {}
+ end
- # Store all modifications made to sections in this file back
- # to the physical files. If no modifications were made to
- # a physical file, nothing is written
- def store
- @files.each do |file, lines|
- text = ""
- dirty = false
- lines.each do |l|
- if l.is_a?(Section)
- dirty ||= l.dirty?
- text << l.format
- l.mark_clean
- else
- text << l
- end
- end
- if dirty
- Puppet::Util::FileType.filetype(:flat).new(file).write(text)
- return file
- end
- end
- end
+ # Add the contents of the file with name FILE to the
+ # already existing sections
+ def read(file)
+ text = Puppet::Util::FileType.filetype(:flat).new(file).read
+ raise "Could not find #{file}" if text.nil?
+
+ section = nil # The name of the current section
+ optname = nil # The name of the last option in section
+ line = 0
+ @files[file] = []
+ text.each_line do |l|
+ line += 1
+ if l.strip.empty? || "#;".include?(l[0,1]) ||
+ (l.split(nil, 2)[0].downcase == "rem" && l[0,1].downcase == "r")
+ # Whitespace or comment
+ if section.nil?
+ @files[file] << l
+ else
+ section.add_line(l)
+ end
+ elsif " \t\r\n\f".include?(l[0,1]) && section && optname
+ # continuation line
+ section[optname] += "\n#{l.chomp}"
+ elsif l =~ /^\[([^\]]+)\]/
+ # section heading
+ section.mark_clean unless section.nil?
+ section = add_section($1, file)
+ optname = nil
+ elsif l =~ /^\s*([^\s=]+)\s*\=(.*)$/
+ # We allow space around the keys, but not the values
+ # For the values, we don't know if space is significant
+ if section.nil?
+ raise "#{file}:#{line}:Key/value pair outside of a section for key #{$1}"
+ else
+ section[$1] = $2
+ optname = $1
+ end
+ else
+ raise "#{file}:#{line}: Can't parse '#{l.chomp}'"
+ end
+ end
+ section.mark_clean unless section.nil?
+ end
- # Execute BLOCK, passing each section in this file
- # as an argument
- def each_section(&block)
- @files.each do |file, list|
- list.each do |entry|
- yield(entry) if entry.is_a?(Section)
- end
- end
- end
+ # Store all modifications made to sections in this file back
+ # to the physical files. If no modifications were made to
+ # a physical file, nothing is written
+ def store
+ @files.each do |file, lines|
+ text = ""
+ dirty = false
+ lines.each do |l|
+ if l.is_a?(Section)
+ dirty ||= l.dirty?
+ text << l.format
+ l.mark_clean
+ else
+ text << l
+ end
+ end
+ if dirty
+ Puppet::Util::FileType.filetype(:flat).new(file).write(text)
+ return file
+ end
+ end
+ end
- # Execute BLOCK, passing each file constituting this inifile
- # as an argument
- def each_file(&block)
- @files.keys.each do |file|
- yield(file)
- end
+ # Execute BLOCK, passing each section in this file
+ # as an argument
+ def each_section(&block)
+ @files.each do |file, list|
+ list.each do |entry|
+ yield(entry) if entry.is_a?(Section)
end
+ end
+ end
- # Return the Section with the given name or nil
- def [](name)
- name = name.to_s
- each_section do |section|
- return section if section.name == name
- end
- nil
- end
+ # Execute BLOCK, passing each file constituting this inifile
+ # as an argument
+ def each_file(&block)
+ @files.keys.each do |file|
+ yield(file)
+ end
+ end
- # Return true if the file contains a section with name NAME
- def include?(name)
- ! self[name].nil?
- end
+ # Return the Section with the given name or nil
+ def [](name)
+ name = name.to_s
+ each_section do |section|
+ return section if section.name == name
+ end
+ nil
+ end
- # Add a section to be stored in FILE when store is called
- def add_section(name, file)
- raise "A section with name #{name} already exists" if include?(name)
- result = Section.new(name, file)
- @files[file] ||= []
- @files[file] << result
- result
- end
+ # Return true if the file contains a section with name NAME
+ def include?(name)
+ ! self[name].nil?
+ end
+
+ # Add a section to be stored in FILE when store is called
+ def add_section(name, file)
+ raise "A section with name #{name} already exists" if include?(name)
+ result = Section.new(name, file)
+ @files[file] ||= []
+ @files[file] << result
+ result
end
+ end
end
diff --git a/lib/puppet/util/inline_docs.rb b/lib/puppet/util/inline_docs.rb
index 1e5450696..62818c1b8 100644
--- a/lib/puppet/util/inline_docs.rb
+++ b/lib/puppet/util/inline_docs.rb
@@ -1,26 +1,26 @@
module Puppet::Util::InlineDocs
- def self.included(klass)
- klass.send(:include, InstanceMethods)
- klass.extend ClassMethods
- end
+ def self.included(klass)
+ klass.send(:include, InstanceMethods)
+ klass.extend ClassMethods
+ end
- module ClassMethods
- attr_accessor :use_docs
- def associates_doc
- self.use_docs = true
- end
+ module ClassMethods
+ attr_accessor :use_docs
+ def associates_doc
+ self.use_docs = true
end
+ end
- module InstanceMethods
- attr_writer :doc
+ module InstanceMethods
+ attr_writer :doc
- def doc
- @doc ||= ""
- end
+ def doc
+ @doc ||= ""
+ end
- # don't fetch lexer comment by default
- def use_docs
- self.class.use_docs
- end
+ # don't fetch lexer comment by default
+ def use_docs
+ self.class.use_docs
end
+ end
end
diff --git a/lib/puppet/util/instance_loader.rb b/lib/puppet/util/instance_loader.rb
index 56d75b698..5e16bd7fa 100755
--- a/lib/puppet/util/instance_loader.rb
+++ b/lib/puppet/util/instance_loader.rb
@@ -4,78 +4,78 @@ require 'puppet/util'
# A module that can easily autoload things for us. Uses an instance
# of Puppet::Util::Autoload
module Puppet::Util::InstanceLoader
- include Puppet::Util
+ include Puppet::Util
- # Are we instance-loading this type?
- def instance_loading?(type)
- defined?(@autoloaders) and @autoloaders.include?(symbolize(type))
- end
-
- # Define a new type of autoloading.
- def instance_load(type, path, options = {})
- @autoloaders ||= {}
- @instances ||= {}
- type = symbolize(type)
- @instances[type] = {}
- @autoloaders[type] = Puppet::Util::Autoload.new(self, path, options)
+ # Are we instance-loading this type?
+ def instance_loading?(type)
+ defined?(@autoloaders) and @autoloaders.include?(symbolize(type))
+ end
- # Now define our new simple methods
- unless respond_to?(type)
- meta_def(type) do |name|
- loaded_instance(type, name)
- end
- end
- end
+ # Define a new type of autoloading.
+ def instance_load(type, path, options = {})
+ @autoloaders ||= {}
+ @instances ||= {}
+ type = symbolize(type)
+ @instances[type] = {}
+ @autoloaders[type] = Puppet::Util::Autoload.new(self, path, options)
- # Return a list of the names of all instances
- def loaded_instances(type)
- @instances[type].keys
+ # Now define our new simple methods
+ unless respond_to?(type)
+ meta_def(type) do |name|
+ loaded_instance(type, name)
+ end
end
+ end
- # Collect the docs for all of our instances.
- def instance_docs(type)
- docs = ""
+ # Return a list of the names of all instances
+ def loaded_instances(type)
+ @instances[type].keys
+ end
- # Load all instances.
- instance_loader(type).loadall
+ # Collect the docs for all of our instances.
+ def instance_docs(type)
+ docs = ""
- # Use this method so they all get loaded
- loaded_instances(type).sort { |a,b| a.to_s <=> b.to_s }.each do |name|
- mod = self.loaded_instance(name)
- docs += "#{name}\n#{"-" * name.to_s.length}\n"
+ # Load all instances.
+ instance_loader(type).loadall
- docs += Puppet::Util::Docs.scrub(mod.doc) + "\n\n"
- end
+ # Use this method so they all get loaded
+ loaded_instances(type).sort { |a,b| a.to_s <=> b.to_s }.each do |name|
+ mod = self.loaded_instance(name)
+ docs += "#{name}\n#{"-" * name.to_s.length}\n"
- docs
+ docs += Puppet::Util::Docs.scrub(mod.doc) + "\n\n"
end
- # Return the instance hash for our type.
- def instance_hash(type)
- @instances[symbolize(type)]
- end
+ docs
+ end
- # Return the Autoload object for a given type.
- def instance_loader(type)
- @autoloaders[symbolize(type)]
- end
+ # Return the instance hash for our type.
+ def instance_hash(type)
+ @instances[symbolize(type)]
+ end
+
+ # Return the Autoload object for a given type.
+ def instance_loader(type)
+ @autoloaders[symbolize(type)]
+ end
- # Retrieve an alread-loaded instance, or attempt to load our instance.
- def loaded_instance(type, name)
- name = symbolize(name)
- return nil unless instances = instance_hash(type)
+ # Retrieve an alread-loaded instance, or attempt to load our instance.
+ def loaded_instance(type, name)
+ name = symbolize(name)
+ return nil unless instances = instance_hash(type)
+ unless instances.include? name
+ if instance_loader(type).load(name)
unless instances.include? name
- if instance_loader(type).load(name)
- unless instances.include? name
- Puppet.warning(
- "Loaded #{type} file for #{name} but #{type} was not defined"
- )
- return nil
- end
- else
- return nil
- end
+ Puppet.warning(
+ "Loaded #{type} file for #{name} but #{type} was not defined"
+ )
+ return nil
end
- instances[name]
+ else
+ return nil
+ end
end
+ instances[name]
+ end
end
diff --git a/lib/puppet/util/ldap/connection.rb b/lib/puppet/util/ldap/connection.rb
index 624bc6f14..03240eae9 100644
--- a/lib/puppet/util/ldap/connection.rb
+++ b/lib/puppet/util/ldap/connection.rb
@@ -4,74 +4,74 @@
require 'puppet/util/ldap'
class Puppet::Util::Ldap::Connection
- attr_accessor :host, :port, :user, :password, :reset, :ssl
+ attr_accessor :host, :port, :user, :password, :reset, :ssl
- attr_reader :connection
+ attr_reader :connection
- # Return a default connection, using our default settings.
- def self.instance
- ssl = if Puppet[:ldaptls]
- :tls
- elsif Puppet[:ldapssl]
- true
- else
- false
- end
-
- options = {}
- options[:ssl] = ssl
- if user = Puppet.settings[:ldapuser] and user != ""
- options[:user] = user
- if pass = Puppet.settings[:ldappassword] and pass != ""
- options[:password] = pass
- end
+ # Return a default connection, using our default settings.
+ def self.instance
+ ssl = if Puppet[:ldaptls]
+ :tls
+ elsif Puppet[:ldapssl]
+ true
+ else
+ false
end
- new(Puppet[:ldapserver], Puppet[:ldapport], options)
+ options = {}
+ options[:ssl] = ssl
+ if user = Puppet.settings[:ldapuser] and user != ""
+ options[:user] = user
+ if pass = Puppet.settings[:ldappassword] and pass != ""
+ options[:password] = pass
+ end
end
- def close
- connection.unbind if connection.bound?
- end
+ new(Puppet[:ldapserver], Puppet[:ldapport], options)
+ end
- def initialize(host, port, options = {})
- raise Puppet::Error, "Could not set up LDAP Connection: Missing ruby/ldap libraries" unless Puppet.features.ldap?
+ def close
+ connection.unbind if connection.bound?
+ end
- @host, @port = host, port
+ def initialize(host, port, options = {})
+ raise Puppet::Error, "Could not set up LDAP Connection: Missing ruby/ldap libraries" unless Puppet.features.ldap?
- options.each do |param, value|
- begin
- send(param.to_s + "=", value)
- rescue
- raise ArgumentError, "LDAP connections do not support #{param} parameters"
- end
- end
- end
+ @host, @port = host, port
- # Create a per-connection unique name.
- def name
- [host, port, user, password, ssl].collect { |p| p.to_s }.join("/")
+ options.each do |param, value|
+ begin
+ send(param.to_s + "=", value)
+ rescue
+ raise ArgumentError, "LDAP connections do not support #{param} parameters"
+ end
end
+ end
- # Should we reset the connection?
- def reset?
- reset
- end
+ # Create a per-connection unique name.
+ def name
+ [host, port, user, password, ssl].collect { |p| p.to_s }.join("/")
+ end
- # Start our ldap connection.
- def start
- case ssl
- when :tls
- @connection = LDAP::SSLConn.new(host, port, true)
- when true
- @connection = LDAP::SSLConn.new(host, port)
- else
- @connection = LDAP::Conn.new(host, port)
- end
- @connection.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
- @connection.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON)
- @connection.simple_bind(user, password)
- rescue => detail
- raise Puppet::Error, "Could not connect to LDAP: #{detail}"
- end
+ # Should we reset the connection?
+ def reset?
+ reset
+ end
+
+ # Start our ldap connection.
+ def start
+ case ssl
+ when :tls
+ @connection = LDAP::SSLConn.new(host, port, true)
+ when true
+ @connection = LDAP::SSLConn.new(host, port)
+ else
+ @connection = LDAP::Conn.new(host, port)
+ end
+ @connection.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
+ @connection.set_option(LDAP::LDAP_OPT_REFERRALS, LDAP::LDAP_OPT_ON)
+ @connection.simple_bind(user, password)
+ rescue => detail
+ raise Puppet::Error, "Could not connect to LDAP: #{detail}"
+ end
end
diff --git a/lib/puppet/util/ldap/generator.rb b/lib/puppet/util/ldap/generator.rb
index 2320c203c..2aaa9c370 100644
--- a/lib/puppet/util/ldap/generator.rb
+++ b/lib/puppet/util/ldap/generator.rb
@@ -4,42 +4,42 @@
require 'puppet/util/ldap'
class Puppet::Util::Ldap::Generator
- # Declare the attribute we'll use to generate the value.
- def from(source)
- @source = source
- self
- end
+ # Declare the attribute we'll use to generate the value.
+ def from(source)
+ @source = source
+ self
+ end
- # Actually do the generation.
- def generate(value = nil)
- if value.nil?
- @generator.call
- else
- @generator.call(value)
- end
+ # Actually do the generation.
+ def generate(value = nil)
+ if value.nil?
+ @generator.call
+ else
+ @generator.call(value)
end
+ end
- # Initialize our generator with the name of the parameter
- # being generated.
- def initialize(name)
- @name = name
- end
+ # Initialize our generator with the name of the parameter
+ # being generated.
+ def initialize(name)
+ @name = name
+ end
- def name
- @name.to_s
- end
+ def name
+ @name.to_s
+ end
- def source
- if @source
- @source.to_s
- else
- nil
- end
+ def source
+ if @source
+ @source.to_s
+ else
+ nil
end
+ end
- # Provide the code that does the generation.
- def with(&block)
- @generator = block
- self
- end
+ # Provide the code that does the generation.
+ def with(&block)
+ @generator = block
+ self
+ end
end
diff --git a/lib/puppet/util/ldap/manager.rb b/lib/puppet/util/ldap/manager.rb
index 501a3cd4a..2ccd102bc 100644
--- a/lib/puppet/util/ldap/manager.rb
+++ b/lib/puppet/util/ldap/manager.rb
@@ -5,275 +5,275 @@ require 'puppet/util/ldap/generator'
# The configuration class for LDAP providers, plus
# connection handling for actually interacting with ldap.
class Puppet::Util::Ldap::Manager
- attr_reader :objectclasses, :puppet2ldap, :location, :rdn
-
- # A null-op that just returns the config.
- def and
- self
+ attr_reader :objectclasses, :puppet2ldap, :location, :rdn
+
+ # A null-op that just returns the config.
+ def and
+ self
+ end
+
+ # Set the offset from the search base and return the config.
+ def at(location)
+ @location = location
+ self
+ end
+
+ # The basic search base.
+ def base
+ [location, Puppet[:ldapbase]].join(",")
+ end
+
+ # Convert the name to a dn, then pass the args along to
+ # our connection.
+ def create(name, attributes)
+ attributes = attributes.dup
+
+ # Add the objectclasses
+ attributes["objectClass"] = objectclasses.collect { |o| o.to_s }
+ attributes["objectClass"] << "top" unless attributes["objectClass"].include?("top")
+
+ attributes[rdn.to_s] = [name]
+
+ # Generate any new values we might need.
+ generate(attributes)
+
+ # And create our resource.
+ connect { |conn| conn.add dn(name), attributes }
+ end
+
+ # Open, yield, and close the connection. Cannot be left
+ # open, at this point.
+ def connect
+ raise ArgumentError, "You must pass a block to #connect" unless block_given?
+
+ unless @connection
+ if Puppet[:ldaptls]
+ ssl = :tls
+ elsif Puppet[:ldapssl]
+ ssl = true
+ else
+ ssl = false
+ end
+ options = {:ssl => ssl}
+ if user = Puppet[:ldapuser] and user != ""
+ options[:user] = user
+ end
+ if password = Puppet[:ldappassword] and password != ""
+ options[:password] = password
+ end
+ @connection = Puppet::Util::Ldap::Connection.new(Puppet[:ldapserver], Puppet[:ldapport], options)
end
-
- # Set the offset from the search base and return the config.
- def at(location)
- @location = location
- self
+ @connection.start
+ begin
+ yield @connection.connection
+ ensure
+ @connection.close
end
+ nil
+ end
- # The basic search base.
- def base
- [location, Puppet[:ldapbase]].join(",")
- end
+ # Convert the name to a dn, then pass the args along to
+ # our connection.
+ def delete(name)
+ connect { |connection| connection.delete dn(name) }
+ end
- # Convert the name to a dn, then pass the args along to
- # our connection.
- def create(name, attributes)
- attributes = attributes.dup
+ # Calculate the dn for a given resource.
+ def dn(name)
+ ["#{rdn}=#{name}", base].join(",")
+ end
- # Add the objectclasses
- attributes["objectClass"] = objectclasses.collect { |o| o.to_s }
- attributes["objectClass"] << "top" unless attributes["objectClass"].include?("top")
+ # Convert an ldap-style entry hash to a provider-style hash.
+ def entry2provider(entry)
+ raise ArgumentError, "Could not get dn from ldap entry" unless entry["dn"]
- attributes[rdn.to_s] = [name]
+ # DN is always a single-entry array. Strip off the bits before the
+ # first comma, then the bits after the remaining equal sign. This is the
+ # name.
+ name = entry["dn"].dup.pop.split(",").shift.split("=").pop
- # Generate any new values we might need.
- generate(attributes)
+ result = {:name => name}
- # And create our resource.
- connect { |conn| conn.add dn(name), attributes }
+ @ldap2puppet.each do |ldap, puppet|
+ result[puppet] = entry[ldap.to_s] || :absent
end
- # Open, yield, and close the connection. Cannot be left
- # open, at this point.
- def connect
- raise ArgumentError, "You must pass a block to #connect" unless block_given?
-
- unless @connection
- if Puppet[:ldaptls]
- ssl = :tls
- elsif Puppet[:ldapssl]
- ssl = true
- else
- ssl = false
- end
- options = {:ssl => ssl}
- if user = Puppet[:ldapuser] and user != ""
- options[:user] = user
- end
- if password = Puppet[:ldappassword] and password != ""
- options[:password] = password
- end
- @connection = Puppet::Util::Ldap::Connection.new(Puppet[:ldapserver], Puppet[:ldapport], options)
+ result
+ end
+
+ # Create our normal search filter.
+ def filter
+ return(objectclasses.length == 1 ? "objectclass=#{objectclasses[0]}" : "(&(objectclass=" + objectclasses.join(")(objectclass=") + "))")
+ end
+
+ # Find the associated entry for a resource. Returns a hash, minus
+ # 'dn', or nil if the entry cannot be found.
+ def find(name)
+ result = nil
+ connect do |conn|
+ begin
+ conn.search2(dn(name), 0, "objectclass=*") do |result|
+ # Convert to puppet-appropriate attributes
+ return entry2provider(result)
end
- @connection.start
- begin
- yield @connection.connection
- ensure
- @connection.close
- end
- nil
+ rescue => detail
+ return nil
+ end
end
+ end
- # Convert the name to a dn, then pass the args along to
- # our connection.
- def delete(name)
- connect { |connection| connection.delete dn(name) }
- end
+ # Declare a new attribute generator.
+ def generates(parameter)
+ @generators << Puppet::Util::Ldap::Generator.new(parameter)
+ @generators[-1]
+ end
- # Calculate the dn for a given resource.
- def dn(name)
- ["#{rdn}=#{name}", base].join(",")
- end
+ # Generate any extra values we need to make the ldap entry work.
+ def generate(values)
+ return unless @generators.length > 0
- # Convert an ldap-style entry hash to a provider-style hash.
- def entry2provider(entry)
- raise ArgumentError, "Could not get dn from ldap entry" unless entry["dn"]
+ @generators.each do |generator|
+ # Don't override any values that might exist.
+ next if values[generator.name]
- # DN is always a single-entry array. Strip off the bits before the
- # first comma, then the bits after the remaining equal sign. This is the
- # name.
- name = entry["dn"].dup.pop.split(",").shift.split("=").pop
-
- result = {:name => name}
-
- @ldap2puppet.each do |ldap, puppet|
- result[puppet] = entry[ldap.to_s] || :absent
+ if generator.source
+ unless value = values[generator.source]
+ raise ArgumentError, "#{generator.source} must be defined to generate #{generator.name}"
end
+ result = generator.generate(value)
+ else
+ result = generator.generate
+ end
- result
- end
-
- # Create our normal search filter.
- def filter
- return(objectclasses.length == 1 ? "objectclass=#{objectclasses[0]}" : "(&(objectclass=" + objectclasses.join(")(objectclass=") + "))")
- end
-
- # Find the associated entry for a resource. Returns a hash, minus
- # 'dn', or nil if the entry cannot be found.
- def find(name)
- result = nil
- connect do |conn|
- begin
- conn.search2(dn(name), 0, "objectclass=*") do |result|
- # Convert to puppet-appropriate attributes
- return entry2provider(result)
- end
- rescue => detail
- return nil
- end
- end
- end
+ result = [result] unless result.is_a?(Array)
+ result = result.collect { |r| r.to_s }
- # Declare a new attribute generator.
- def generates(parameter)
- @generators << Puppet::Util::Ldap::Generator.new(parameter)
- @generators[-1]
+ values[generator.name] = result
end
-
- # Generate any extra values we need to make the ldap entry work.
- def generate(values)
- return unless @generators.length > 0
-
- @generators.each do |generator|
- # Don't override any values that might exist.
- next if values[generator.name]
-
- if generator.source
- unless value = values[generator.source]
- raise ArgumentError, "#{generator.source} must be defined to generate #{generator.name}"
- end
- result = generator.generate(value)
- else
- result = generator.generate
- end
-
- result = [result] unless result.is_a?(Array)
- result = result.collect { |r| r.to_s }
-
- values[generator.name] = result
- end
+ end
+
+ def initialize
+ @rdn = :cn
+ @generators = []
+ end
+
+ # Specify what classes this provider models.
+ def manages(*classes)
+ @objectclasses = classes
+ self
+ end
+
+ # Specify the attribute map. Assumes the keys are the puppet
+ # attributes, and the values are the ldap attributes, and creates a map
+ # for each direction.
+ def maps(attributes)
+ # The map with the puppet attributes as the keys
+ @puppet2ldap = attributes
+
+ # and the ldap attributes as the keys.
+ @ldap2puppet = attributes.inject({}) { |map, ary| map[ary[1]] = ary[0]; map }
+
+ self
+ end
+
+ # Return the ldap name for a puppet attribute.
+ def ldap_name(attribute)
+ @puppet2ldap[attribute].to_s
+ end
+
+ # Convert the name to a dn, then pass the args along to
+ # our connection.
+ def modify(name, mods)
+ connect { |connection| connection.modify dn(name), mods }
+ end
+
+ # Specify the rdn that we use to build up our dn.
+ def named_by(attribute)
+ @rdn = attribute
+ self
+ end
+
+ # Return the puppet name for an ldap attribute.
+ def puppet_name(attribute)
+ @ldap2puppet[attribute]
+ end
+
+ # Search for all entries at our base. A potentially expensive search.
+ def search(sfilter = nil)
+ sfilter ||= filter
+
+ result = []
+ connect do |conn|
+ conn.search2(base, 1, sfilter) do |entry|
+ result << entry2provider(entry)
+ end
end
-
- def initialize
- @rdn = :cn
- @generators = []
+ return(result.empty? ? nil : result)
+ end
+
+ # Update the ldap entry with the desired state.
+ def update(name, is, should)
+ if should[:ensure] == :absent
+ Puppet.info "Removing #{dn(name)} from ldap"
+ delete(name)
+ return
end
- # Specify what classes this provider models.
- def manages(*classes)
- @objectclasses = classes
- self
+ # We're creating a new entry
+ if is.empty? or is[:ensure] == :absent
+ Puppet.info "Creating #{dn(name)} in ldap"
+ # Remove any :absent params and :ensure, then convert the names to ldap names.
+ attrs = ldap_convert(should)
+ create(name, attrs)
+ return
end
- # Specify the attribute map. Assumes the keys are the puppet
- # attributes, and the values are the ldap attributes, and creates a map
- # for each direction.
- def maps(attributes)
- # The map with the puppet attributes as the keys
- @puppet2ldap = attributes
-
- # and the ldap attributes as the keys.
- @ldap2puppet = attributes.inject({}) { |map, ary| map[ary[1]] = ary[0]; map }
+ # We're modifying an existing entry. Yuck.
- self
- end
-
- # Return the ldap name for a puppet attribute.
- def ldap_name(attribute)
- @puppet2ldap[attribute].to_s
- end
+ mods = []
+ # For each attribute we're deleting that is present, create a
+ # modify instance for deletion.
+ [is.keys, should.keys].flatten.uniq.each do |property|
+ # They're equal, so do nothing.
+ next if is[property] == should[property]
- # Convert the name to a dn, then pass the args along to
- # our connection.
- def modify(name, mods)
- connect { |connection| connection.modify dn(name), mods }
- end
+ attributes = ldap_convert(should)
- # Specify the rdn that we use to build up our dn.
- def named_by(attribute)
- @rdn = attribute
- self
- end
+ prop_name = ldap_name(property).to_s
- # Return the puppet name for an ldap attribute.
- def puppet_name(attribute)
- @ldap2puppet[attribute]
- end
+ # We're creating it.
+ if is[property] == :absent or is[property].nil?
+ mods << LDAP::Mod.new(LDAP::LDAP_MOD_ADD, prop_name, attributes[prop_name])
+ next
+ end
- # Search for all entries at our base. A potentially expensive search.
- def search(sfilter = nil)
- sfilter ||= filter
+ # We're deleting it
+ if should[property] == :absent or should[property].nil?
+ mods << LDAP::Mod.new(LDAP::LDAP_MOD_DELETE, prop_name, [])
+ next
+ end
- result = []
- connect do |conn|
- conn.search2(base, 1, sfilter) do |entry|
- result << entry2provider(entry)
- end
- end
- return(result.empty? ? nil : result)
+ # We're replacing an existing value
+ mods << LDAP::Mod.new(LDAP::LDAP_MOD_REPLACE, prop_name, attributes[prop_name])
end
- # Update the ldap entry with the desired state.
- def update(name, is, should)
- if should[:ensure] == :absent
- Puppet.info "Removing #{dn(name)} from ldap"
- delete(name)
- return
- end
-
- # We're creating a new entry
- if is.empty? or is[:ensure] == :absent
- Puppet.info "Creating #{dn(name)} in ldap"
- # Remove any :absent params and :ensure, then convert the names to ldap names.
- attrs = ldap_convert(should)
- create(name, attrs)
- return
- end
-
- # We're modifying an existing entry. Yuck.
+ modify(name, mods)
+ end
- mods = []
- # For each attribute we're deleting that is present, create a
- # modify instance for deletion.
- [is.keys, should.keys].flatten.uniq.each do |property|
- # They're equal, so do nothing.
- next if is[property] == should[property]
+ # Is this a complete ldap configuration?
+ def valid?
+ location and objectclasses and ! objectclasses.empty? and puppet2ldap
+ end
- attributes = ldap_convert(should)
+ private
- prop_name = ldap_name(property).to_s
-
- # We're creating it.
- if is[property] == :absent or is[property].nil?
- mods << LDAP::Mod.new(LDAP::LDAP_MOD_ADD, prop_name, attributes[prop_name])
- next
- end
-
- # We're deleting it
- if should[property] == :absent or should[property].nil?
- mods << LDAP::Mod.new(LDAP::LDAP_MOD_DELETE, prop_name, [])
- next
- end
-
- # We're replacing an existing value
- mods << LDAP::Mod.new(LDAP::LDAP_MOD_REPLACE, prop_name, attributes[prop_name])
- end
-
- modify(name, mods)
- end
-
- # Is this a complete ldap configuration?
- def valid?
- location and objectclasses and ! objectclasses.empty? and puppet2ldap
- end
-
- private
-
- # Convert a hash of attributes to ldap-like forms. This mostly means
- # getting rid of :ensure and making sure everything's an array of strings.
- def ldap_convert(attributes)
- attributes.reject { |param, value| value == :absent or param == :ensure }.inject({}) do |result, ary|
- value = (ary[1].is_a?(Array) ? ary[1] : [ary[1]]).collect { |v| v.to_s }
- result[ldap_name(ary[0])] = value
- result
- end
+ # Convert a hash of attributes to ldap-like forms. This mostly means
+ # getting rid of :ensure and making sure everything's an array of strings.
+ def ldap_convert(attributes)
+ attributes.reject { |param, value| value == :absent or param == :ensure }.inject({}) do |result, ary|
+ value = (ary[1].is_a?(Array) ? ary[1] : [ary[1]]).collect { |v| v.to_s }
+ result[ldap_name(ary[0])] = value
+ result
end
+ end
end
diff --git a/lib/puppet/util/loadedfile.rb b/lib/puppet/util/loadedfile.rb
index 9eaca552b..735dba459 100755
--- a/lib/puppet/util/loadedfile.rb
+++ b/lib/puppet/util/loadedfile.rb
@@ -4,62 +4,62 @@
require 'puppet'
module Puppet
- class NoSuchFile < Puppet::Error; end
- class Util::LoadedFile
- attr_reader :file, :statted
+ class NoSuchFile < Puppet::Error; end
+ class Util::LoadedFile
+ attr_reader :file, :statted
- # Provide a hook for setting the timestamp during testing, so we don't
- # have to depend on the granularity of the filesystem.
- attr_writer :tstamp
+ # Provide a hook for setting the timestamp during testing, so we don't
+ # have to depend on the granularity of the filesystem.
+ attr_writer :tstamp
- # Determine whether the file has changed and thus whether it should
- # be reparsed.
- def changed?
- # Allow the timeout to be disabled entirely.
- return true if Puppet[:filetimeout] < 0
- tmp = stamp
+ # Determine whether the file has changed and thus whether it should
+ # be reparsed.
+ def changed?
+ # Allow the timeout to be disabled entirely.
+ return true if Puppet[:filetimeout] < 0
+ tmp = stamp
- # We use a different internal variable than the stamp method
- # because it doesn't keep historical state and we do -- that is,
- # we will always be comparing two timestamps, whereas
- # stamp just always wants the latest one.
- if tmp == @tstamp
- return false
- else
- @tstamp = tmp
- return @tstamp
- end
- end
+ # We use a different internal variable than the stamp method
+ # because it doesn't keep historical state and we do -- that is,
+ # we will always be comparing two timestamps, whereas
+ # stamp just always wants the latest one.
+ if tmp == @tstamp
+ return false
+ else
+ @tstamp = tmp
+ return @tstamp
+ end
+ end
- # Create the file. Must be passed the file path.
- def initialize(file)
- @file = file
- unless FileTest.exists?(@file)
- raise Puppet::NoSuchFile,
- "Can not use a non-existent file for parsing"
- end
- @statted = 0
- @stamp = nil
- @tstamp = stamp
- end
+ # Create the file. Must be passed the file path.
+ def initialize(file)
+ @file = file
+ unless FileTest.exists?(@file)
+ raise Puppet::NoSuchFile,
+ "Can not use a non-existent file for parsing"
+ end
+ @statted = 0
+ @stamp = nil
+ @tstamp = stamp
+ end
- # Retrieve the filestamp, but only refresh it if we're beyond our
- # filetimeout
- def stamp
- if @stamp.nil? or (Time.now.to_i - @statted >= Puppet[:filetimeout])
- @statted = Time.now.to_i
- begin
- @stamp = File.stat(@file).ctime
- rescue Errno::ENOENT
- @stamp = Time.now
- end
- end
- @stamp
+ # Retrieve the filestamp, but only refresh it if we're beyond our
+ # filetimeout
+ def stamp
+ if @stamp.nil? or (Time.now.to_i - @statted >= Puppet[:filetimeout])
+ @statted = Time.now.to_i
+ begin
+ @stamp = File.stat(@file).ctime
+ rescue Errno::ENOENT
+ @stamp = Time.now
end
+ end
+ @stamp
+ end
- def to_s
- @file
- end
+ def to_s
+ @file
end
+ end
end
diff --git a/lib/puppet/util/log.rb b/lib/puppet/util/log.rb
index c47aa0d6f..36a765c61 100644
--- a/lib/puppet/util/log.rb
+++ b/lib/puppet/util/log.rb
@@ -5,250 +5,250 @@ require 'puppet/util/classgen'
# expected that that will be the most common log destination. Supports
# multiple destinations, one of which is a remote server.
class Puppet::Util::Log
- include Puppet::Util
- extend Puppet::Util::ClassGen
- include Puppet::Util::Tagging
+ include Puppet::Util
+ extend Puppet::Util::ClassGen
+ include Puppet::Util::Tagging
- @levels = [:debug,:info,:notice,:warning,:err,:alert,:emerg,:crit]
- @loglevel = 2
+ @levels = [:debug,:info,:notice,:warning,:err,:alert,:emerg,:crit]
+ @loglevel = 2
- @desttypes = {}
+ @desttypes = {}
- # Create a new destination type.
- def self.newdesttype(name, options = {}, &block)
+ # Create a new destination type.
+ def self.newdesttype(name, options = {}, &block)
- dest = genclass(
- name, :parent => Puppet::Util::Log::Destination, :prefix => "Dest",
- :block => block,
- :hash => @desttypes,
+ dest = genclass(
+ name, :parent => Puppet::Util::Log::Destination, :prefix => "Dest",
+ :block => block,
+ :hash => @desttypes,
- :attributes => options
- )
- dest.match(dest.name)
-
- dest
- end
+ :attributes => options
+ )
+ dest.match(dest.name)
- require 'puppet/util/log/destination'
- require 'puppet/util/log/destinations'
+ dest
+ end
- @destinations = {}
+ require 'puppet/util/log/destination'
+ require 'puppet/util/log/destinations'
- @queued = []
+ @destinations = {}
- class << self
- include Puppet::Util
- include Puppet::Util::ClassGen
-
- attr_reader :desttypes
- end
-
- # Reset log to basics. Basically just flushes and closes files and
- # undefs other objects.
- def Log.close(destination)
- if @destinations.include?(destination)
- @destinations[destination].flush if @destinations[destination].respond_to?(:flush)
- @destinations[destination].close if @destinations[destination].respond_to?(:close)
- @destinations.delete(destination)
- end
- end
-
- def self.close_all
- destinations.keys.each { |dest|
- close(dest)
- }
- end
-
- # Flush any log destinations that support such operations.
- def Log.flush
- @destinations.each { |type, dest|
- dest.flush if dest.respond_to?(:flush)
- }
- end
-
- # Create a new log message. The primary role of this method is to
- # avoid creating log messages below the loglevel.
- def Log.create(hash)
- raise Puppet::DevError, "Logs require a level" unless hash.include?(:level)
- raise Puppet::DevError, "Invalid log level #{hash[:level]}" unless @levels.index(hash[:level])
- @levels.index(hash[:level]) >= @loglevel ? Puppet::Util::Log.new(hash) : nil
- end
-
- def Log.destinations
- @destinations
- end
-
- # Yield each valid level in turn
- def Log.eachlevel
- @levels.each { |level| yield level }
- end
+ @queued = []
- # Return the current log level.
- def Log.level
- @levels[@loglevel]
+ class << self
+ include Puppet::Util
+ include Puppet::Util::ClassGen
+
+ attr_reader :desttypes
+ end
+
+ # Reset log to basics. Basically just flushes and closes files and
+ # undefs other objects.
+ def Log.close(destination)
+ if @destinations.include?(destination)
+ @destinations[destination].flush if @destinations[destination].respond_to?(:flush)
+ @destinations[destination].close if @destinations[destination].respond_to?(:close)
+ @destinations.delete(destination)
end
-
- # Set the current log level.
- def Log.level=(level)
- level = level.intern unless level.is_a?(Symbol)
-
- raise Puppet::DevError, "Invalid loglevel #{level}" unless @levels.include?(level)
-
- @loglevel = @levels.index(level)
+ end
+
+ def self.close_all
+ destinations.keys.each { |dest|
+ close(dest)
+ }
+ end
+
+ # Flush any log destinations that support such operations.
+ def Log.flush
+ @destinations.each { |type, dest|
+ dest.flush if dest.respond_to?(:flush)
+ }
+ end
+
+ # Create a new log message. The primary role of this method is to
+ # avoid creating log messages below the loglevel.
+ def Log.create(hash)
+ raise Puppet::DevError, "Logs require a level" unless hash.include?(:level)
+ raise Puppet::DevError, "Invalid log level #{hash[:level]}" unless @levels.index(hash[:level])
+ @levels.index(hash[:level]) >= @loglevel ? Puppet::Util::Log.new(hash) : nil
+ end
+
+ def Log.destinations
+ @destinations
+ end
+
+ # Yield each valid level in turn
+ def Log.eachlevel
+ @levels.each { |level| yield level }
+ end
+
+ # Return the current log level.
+ def Log.level
+ @levels[@loglevel]
+ end
+
+ # Set the current log level.
+ def Log.level=(level)
+ level = level.intern unless level.is_a?(Symbol)
+
+ raise Puppet::DevError, "Invalid loglevel #{level}" unless @levels.include?(level)
+
+ @loglevel = @levels.index(level)
+ end
+
+ def Log.levels
+ @levels.dup
+ end
+
+ # Create a new log destination.
+ def Log.newdestination(dest)
+ # Each destination can only occur once.
+ if @destinations.find { |name, obj| obj.name == dest }
+ return
end
- def Log.levels
- @levels.dup
+ name, type = @desttypes.find do |name, klass|
+ klass.match?(dest)
end
- # Create a new log destination.
- def Log.newdestination(dest)
- # Each destination can only occur once.
- if @destinations.find { |name, obj| obj.name == dest }
- return
- end
-
- name, type = @desttypes.find do |name, klass|
- klass.match?(dest)
- end
-
- raise Puppet::DevError, "Unknown destination type #{dest}" unless type
-
- begin
- if type.instance_method(:initialize).arity == 1
- @destinations[dest] = type.new(dest)
- else
- @destinations[dest] = type.new
- end
- flushqueue
- @destinations[dest]
- rescue => detail
- puts detail.backtrace if Puppet[:debug]
-
- # If this was our only destination, then add the console back in.
- newdestination(:console) if @destinations.empty? and (dest != :console and dest != "console")
- end
+ raise Puppet::DevError, "Unknown destination type #{dest}" unless type
+
+ begin
+ if type.instance_method(:initialize).arity == 1
+ @destinations[dest] = type.new(dest)
+ else
+ @destinations[dest] = type.new
+ end
+ flushqueue
+ @destinations[dest]
+ rescue => detail
+ puts detail.backtrace if Puppet[:debug]
+
+ # If this was our only destination, then add the console back in.
+ newdestination(:console) if @destinations.empty? and (dest != :console and dest != "console")
end
+ end
- # Route the actual message. FIXME There are lots of things this method
- # should do, like caching and a bit more. It's worth noting that there's
- # a potential for a loop here, if the machine somehow gets the destination set as
- # itself.
- def Log.newmessage(msg)
- return if @levels.index(msg.level) < @loglevel
+ # Route the actual message. FIXME There are lots of things this method
+ # should do, like caching and a bit more. It's worth noting that there's
+ # a potential for a loop here, if the machine somehow gets the destination set as
+ # itself.
+ def Log.newmessage(msg)
+ return if @levels.index(msg.level) < @loglevel
- queuemessage(msg) if @destinations.length == 0
-
- @destinations.each do |name, dest|
- threadlock(dest) do
- dest.handle(msg)
- end
- end
- end
-
- def Log.queuemessage(msg)
- @queued.push(msg)
- end
+ queuemessage(msg) if @destinations.length == 0
- def Log.flushqueue
- return unless @destinations.size >= 1
- @queued.each do |msg|
- Log.newmessage(msg)
- end
- @queued.clear
+ @destinations.each do |name, dest|
+ threadlock(dest) do
+ dest.handle(msg)
+ end
end
+ end
- def Log.sendlevel?(level)
- @levels.index(level) >= @loglevel
- end
+ def Log.queuemessage(msg)
+ @queued.push(msg)
+ end
- # Reopen all of our logs.
- def Log.reopen
- Puppet.notice "Reopening log files"
- types = @destinations.keys
- @destinations.each { |type, dest|
- dest.close if dest.respond_to?(:close)
- }
- @destinations.clear
- # We need to make sure we always end up with some kind of destination
- begin
- types.each { |type|
- Log.newdestination(type)
- }
- rescue => detail
- if @destinations.empty?
- Log.newdestination(:syslog)
- Puppet.err detail.to_s
- end
- end
+ def Log.flushqueue
+ return unless @destinations.size >= 1
+ @queued.each do |msg|
+ Log.newmessage(msg)
end
-
- # Is the passed level a valid log level?
- def self.validlevel?(level)
- @levels.include?(level)
+ @queued.clear
+ end
+
+ def Log.sendlevel?(level)
+ @levels.index(level) >= @loglevel
+ end
+
+ # Reopen all of our logs.
+ def Log.reopen
+ Puppet.notice "Reopening log files"
+ types = @destinations.keys
+ @destinations.each { |type, dest|
+ dest.close if dest.respond_to?(:close)
+ }
+ @destinations.clear
+ # We need to make sure we always end up with some kind of destination
+ begin
+ types.each { |type|
+ Log.newdestination(type)
+ }
+ rescue => detail
+ if @destinations.empty?
+ Log.newdestination(:syslog)
+ Puppet.err detail.to_s
+ end
end
+ end
- attr_accessor :time, :remote, :file, :line, :version, :source
- attr_reader :level, :message
-
- def initialize(args)
- self.level = args[:level]
- self.message = args[:message]
- self.source = args[:source] || "Puppet"
-
- @time = Time.now
+ # Is the passed level a valid log level?
+ def self.validlevel?(level)
+ @levels.include?(level)
+ end
- if tags = args[:tags]
- tags.each { |t| self.tag(t) }
- end
+ attr_accessor :time, :remote, :file, :line, :version, :source
+ attr_reader :level, :message
- [:file, :line, :version].each do |attr|
- next unless value = args[attr]
- send(attr.to_s + "=", value)
- end
+ def initialize(args)
+ self.level = args[:level]
+ self.message = args[:message]
+ self.source = args[:source] || "Puppet"
- Log.newmessage(self)
- end
+ @time = Time.now
- def message=(msg)
- raise ArgumentError, "Puppet::Util::Log requires a message" unless msg
- @message = msg.to_s
+ if tags = args[:tags]
+ tags.each { |t| self.tag(t) }
end
- def level=(level)
- raise ArgumentError, "Puppet::Util::Log requires a log level" unless level
- @level = level.to_sym
- raise ArgumentError, "Invalid log level #{@level}" unless self.class.validlevel?(@level)
-
- # Tag myself with my log level
- tag(level)
+ [:file, :line, :version].each do |attr|
+ next unless value = args[attr]
+ send(attr.to_s + "=", value)
end
- # If they pass a source in to us, we make sure it is a string, and
- # we retrieve any tags we can.
- def source=(source)
- if source.respond_to?(:source_descriptors)
- descriptors = source.source_descriptors
- @source = descriptors[:path]
-
- descriptors[:tags].each { |t| tag(t) }
-
- [:file, :line, :version].each do |param|
- next unless descriptors[param]
- send(param.to_s + "=", descriptors[param])
- end
- else
- @source = source.to_s
- end
+ Log.newmessage(self)
+ end
+
+ def message=(msg)
+ raise ArgumentError, "Puppet::Util::Log requires a message" unless msg
+ @message = msg.to_s
+ end
+
+ def level=(level)
+ raise ArgumentError, "Puppet::Util::Log requires a log level" unless level
+ @level = level.to_sym
+ raise ArgumentError, "Invalid log level #{@level}" unless self.class.validlevel?(@level)
+
+ # Tag myself with my log level
+ tag(level)
+ end
+
+ # If they pass a source in to us, we make sure it is a string, and
+ # we retrieve any tags we can.
+ def source=(source)
+ if source.respond_to?(:source_descriptors)
+ descriptors = source.source_descriptors
+ @source = descriptors[:path]
+
+ descriptors[:tags].each { |t| tag(t) }
+
+ [:file, :line, :version].each do |param|
+ next unless descriptors[param]
+ send(param.to_s + "=", descriptors[param])
+ end
+ else
+ @source = source.to_s
end
+ end
- def to_report
- "#{time} #{source} (#{level}): #{to_s}"
- end
+ def to_report
+ "#{time} #{source} (#{level}): #{to_s}"
+ end
- def to_s
- message
- end
+ def to_s
+ message
+ end
end
# This is for backward compatibility from when we changed the constant to Puppet::Util::Log
diff --git a/lib/puppet/util/log/destination.rb b/lib/puppet/util/log/destination.rb
index 35565b4a8..11ebd7d05 100644
--- a/lib/puppet/util/log/destination.rb
+++ b/lib/puppet/util/log/destination.rb
@@ -1,49 +1,49 @@
# A type of log destination.
class Puppet::Util::Log::Destination
- class << self
- attr_accessor :name
+ class << self
+ attr_accessor :name
+ end
+
+ def self.initvars
+ @matches = []
+ end
+
+ # Mark the things we're supposed to match.
+ def self.match(obj)
+ @matches ||= []
+ @matches << obj
+ end
+
+ # See whether we match a given thing.
+ def self.match?(obj)
+ # Convert single-word strings into symbols like :console and :syslog
+ if obj.is_a? String and obj =~ /^\w+$/
+ obj = obj.downcase.intern
end
- def self.initvars
- @matches = []
+ @matches.each do |thing|
+ # Search for direct matches or class matches
+ return true if thing === obj or thing == obj.class.to_s
end
-
- # Mark the things we're supposed to match.
- def self.match(obj)
- @matches ||= []
- @matches << obj
- end
-
- # See whether we match a given thing.
- def self.match?(obj)
- # Convert single-word strings into symbols like :console and :syslog
- if obj.is_a? String and obj =~ /^\w+$/
- obj = obj.downcase.intern
- end
-
- @matches.each do |thing|
- # Search for direct matches or class matches
- return true if thing === obj or thing == obj.class.to_s
- end
- false
+ false
+ end
+
+ def name
+ if defined?(@name)
+ return @name
+ else
+ return self.class.name
end
+ end
- def name
- if defined?(@name)
- return @name
- else
- return self.class.name
- end
- end
+ # Set how to handle a message.
+ def self.sethandler(&block)
+ define_method(:handle, &block)
+ end
- # Set how to handle a message.
- def self.sethandler(&block)
- define_method(:handle, &block)
- end
-
- # Mark how to initialize our object.
- def self.setinit(&block)
- define_method(:initialize, &block)
- end
+ # Mark how to initialize our object.
+ def self.setinit(&block)
+ define_method(:initialize, &block)
+ end
end
diff --git a/lib/puppet/util/log/destinations.rb b/lib/puppet/util/log/destinations.rb
index 515568c93..22b3dedb2 100644
--- a/lib/puppet/util/log/destinations.rb
+++ b/lib/puppet/util/log/destinations.rb
@@ -1,217 +1,217 @@
Puppet::Util::Log.newdesttype :syslog do
- def close
- Syslog.close
- end
-
- def initialize
- Syslog.close if Syslog.opened?
- name = Puppet[:name]
- name = "puppet-#{name}" unless name =~ /puppet/
-
- options = Syslog::LOG_PID | Syslog::LOG_NDELAY
-
- # XXX This should really be configurable.
- str = Puppet[:syslogfacility]
- begin
- facility = Syslog.const_get("LOG_#{str.upcase}")
- rescue NameError
- raise Puppet::Error, "Invalid syslog facility #{str}"
- end
-
- @syslog = Syslog.open(name, options, facility)
- end
-
- def handle(msg)
- # XXX Syslog currently has a bug that makes it so you
- # cannot log a message with a '%' in it. So, we get rid
- # of them.
- if msg.source == "Puppet"
- @syslog.send(msg.level, msg.to_s.gsub("%", '%%'))
- else
- @syslog.send(msg.level, "(%s) %s" % [msg.source.to_s.gsub("%", ""),
- msg.to_s.gsub("%", '%%')
- ]
- )
- end
- end
+ def close
+ Syslog.close
+ end
+
+ def initialize
+ Syslog.close if Syslog.opened?
+ name = Puppet[:name]
+ name = "puppet-#{name}" unless name =~ /puppet/
+
+ options = Syslog::LOG_PID | Syslog::LOG_NDELAY
+
+ # XXX This should really be configurable.
+ str = Puppet[:syslogfacility]
+ begin
+ facility = Syslog.const_get("LOG_#{str.upcase}")
+ rescue NameError
+ raise Puppet::Error, "Invalid syslog facility #{str}"
+ end
+
+ @syslog = Syslog.open(name, options, facility)
+ end
+
+ def handle(msg)
+ # XXX Syslog currently has a bug that makes it so you
+ # cannot log a message with a '%' in it. So, we get rid
+ # of them.
+ if msg.source == "Puppet"
+ @syslog.send(msg.level, msg.to_s.gsub("%", '%%'))
+ else
+ @syslog.send(msg.level, "(%s) %s" % [msg.source.to_s.gsub("%", ""),
+ msg.to_s.gsub("%", '%%')
+ ]
+ )
+ end
+ end
end
Puppet::Util::Log.newdesttype :file do
- match(/^\//)
+ match(/^\//)
- def close
- if defined?(@file)
- @file.close
- @file = nil
- end
+ def close
+ if defined?(@file)
+ @file.close
+ @file = nil
end
+ end
- def flush
- @file.flush if defined?(@file)
- end
+ def flush
+ @file.flush if defined?(@file)
+ end
- def initialize(path)
- @name = path
- # first make sure the directory exists
- # We can't just use 'Config.use' here, because they've
- # specified a "special" destination.
- unless FileTest.exist?(File.dirname(path))
- Puppet.recmkdir(File.dirname(path))
- Puppet.info "Creating log directory #{File.dirname(path)}"
- end
+ def initialize(path)
+ @name = path
+ # first make sure the directory exists
+ # We can't just use 'Config.use' here, because they've
+ # specified a "special" destination.
+ unless FileTest.exist?(File.dirname(path))
+ Puppet.recmkdir(File.dirname(path))
+ Puppet.info "Creating log directory #{File.dirname(path)}"
+ end
- # create the log file, if it doesn't already exist
- file = File.open(path, File::WRONLY|File::CREAT|File::APPEND)
+ # create the log file, if it doesn't already exist
+ file = File.open(path, File::WRONLY|File::CREAT|File::APPEND)
- @file = file
+ @file = file
- @autoflush = Puppet[:autoflush]
- end
+ @autoflush = Puppet[:autoflush]
+ end
- def handle(msg)
- @file.puts("#{msg.time} #{msg.source} (#{msg.level}): #{msg}")
+ def handle(msg)
+ @file.puts("#{msg.time} #{msg.source} (#{msg.level}): #{msg}")
- @file.flush if @autoflush
- end
+ @file.flush if @autoflush
+ end
end
Puppet::Util::Log.newdesttype :console do
- RED = {:console => "", :html => "FFA0A0"}
- GREEN = {:console => "", :html => "00CD00"}
- YELLOW = {:console => "", :html => "FFFF60"}
- BLUE = {:console => "", :html => "80A0FF"}
- PURPLE = {:console => "", :html => "FFA500"}
- CYAN = {:console => "", :html => "40FFFF"}
- WHITE = {:console => "", :html => "FFFFFF"}
- HRED = {:console => "", :html => "FFA0A0"}
- HGREEN = {:console => "", :html => "00CD00"}
- HYELLOW = {:console => "", :html => "FFFF60"}
- HBLUE = {:console => "", :html => "80A0FF"}
- HPURPLE = {:console => "", :html => "FFA500"}
- HCYAN = {:console => "", :html => "40FFFF"}
- HWHITE = {:console => "", :html => "FFFFFF"}
- RESET = {:console => "", :html => "" }
-
- @@colormap = {
- :debug => WHITE,
- :info => GREEN,
- :notice => CYAN,
- :warning => YELLOW,
- :err => HPURPLE,
- :alert => RED,
- :emerg => HRED,
- :crit => HRED
- }
-
- def colorize(level, str)
- case Puppet[:color]
- when true, :ansi, "ansi", "yes"; console_color(level, str)
- when :html, "html"; html_color(level, str)
- else
- str
- end
- end
-
- def console_color(level, str)
- @@colormap[level][:console] + str + RESET[:console]
- end
-
- def html_color(level, str)
- %{<span style="color: %s">%s</span>} % [@@colormap[level][:html], str]
- end
-
- def initialize
- # Flush output immediately.
- $stdout.sync = true
- end
-
- def handle(msg)
- if msg.source == "Puppet"
- puts colorize(msg.level, "#{msg.level}: #{msg}")
- else
- puts colorize(msg.level, "#{msg.level}: #{msg.source}: #{msg}")
- end
- end
+ RED = {:console => "", :html => "FFA0A0"}
+ GREEN = {:console => "", :html => "00CD00"}
+ YELLOW = {:console => "", :html => "FFFF60"}
+ BLUE = {:console => "", :html => "80A0FF"}
+ PURPLE = {:console => "", :html => "FFA500"}
+ CYAN = {:console => "", :html => "40FFFF"}
+ WHITE = {:console => "", :html => "FFFFFF"}
+ HRED = {:console => "", :html => "FFA0A0"}
+ HGREEN = {:console => "", :html => "00CD00"}
+ HYELLOW = {:console => "", :html => "FFFF60"}
+ HBLUE = {:console => "", :html => "80A0FF"}
+ HPURPLE = {:console => "", :html => "FFA500"}
+ HCYAN = {:console => "", :html => "40FFFF"}
+ HWHITE = {:console => "", :html => "FFFFFF"}
+ RESET = {:console => "", :html => "" }
+
+ @@colormap = {
+ :debug => WHITE,
+ :info => GREEN,
+ :notice => CYAN,
+ :warning => YELLOW,
+ :err => HPURPLE,
+ :alert => RED,
+ :emerg => HRED,
+ :crit => HRED
+ }
+
+ def colorize(level, str)
+ case Puppet[:color]
+ when true, :ansi, "ansi", "yes"; console_color(level, str)
+ when :html, "html"; html_color(level, str)
+ else
+ str
+ end
+ end
+
+ def console_color(level, str)
+ @@colormap[level][:console] + str + RESET[:console]
+ end
+
+ def html_color(level, str)
+ %{<span style="color: %s">%s</span>} % [@@colormap[level][:html], str]
+ end
+
+ def initialize
+ # Flush output immediately.
+ $stdout.sync = true
+ end
+
+ def handle(msg)
+ if msg.source == "Puppet"
+ puts colorize(msg.level, "#{msg.level}: #{msg}")
+ else
+ puts colorize(msg.level, "#{msg.level}: #{msg.source}: #{msg}")
+ end
+ end
end
Puppet::Util::Log.newdesttype :host do
- def initialize(host)
- Puppet.info "Treating #{host} as a hostname"
- args = {}
- if host =~ /:(\d+)/
- args[:Port] = $1
- args[:Server] = host.sub(/:\d+/, '')
- else
- args[:Server] = host
- end
-
- @name = host
-
- @driver = Puppet::Network::Client::LogClient.new(args)
- end
-
- def handle(msg)
- unless msg.is_a?(String) or msg.remote
- @hostname ||= Facter["hostname"].value
- unless defined?(@domain)
- @domain = Facter["domain"].value
- @hostname += ".#{@domain}" if @domain
- end
- if msg.source =~ /^\//
- msg.source = @hostname + ":#{msg.source}"
- elsif msg.source == "Puppet"
- msg.source = @hostname + " #{msg.source}"
- else
- msg.source = @hostname + " #{msg.source}"
- end
- begin
- #puts "would have sent #{msg}"
- #puts "would have sent %s" %
- # CGI.escape(YAML.dump(msg))
- begin
- tmp = CGI.escape(YAML.dump(msg))
- rescue => detail
- puts "Could not dump: #{detail}"
- return
- end
- # Add the hostname to the source
- @driver.addlog(tmp)
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err detail
- Puppet::Util::Log.close(self)
- end
+ def initialize(host)
+ Puppet.info "Treating #{host} as a hostname"
+ args = {}
+ if host =~ /:(\d+)/
+ args[:Port] = $1
+ args[:Server] = host.sub(/:\d+/, '')
+ else
+ args[:Server] = host
+ end
+
+ @name = host
+
+ @driver = Puppet::Network::Client::LogClient.new(args)
+ end
+
+ def handle(msg)
+ unless msg.is_a?(String) or msg.remote
+ @hostname ||= Facter["hostname"].value
+ unless defined?(@domain)
+ @domain = Facter["domain"].value
+ @hostname += ".#{@domain}" if @domain
+ end
+ if msg.source =~ /^\//
+ msg.source = @hostname + ":#{msg.source}"
+ elsif msg.source == "Puppet"
+ msg.source = @hostname + " #{msg.source}"
+ else
+ msg.source = @hostname + " #{msg.source}"
+ end
+ begin
+ #puts "would have sent #{msg}"
+ #puts "would have sent %s" %
+ # CGI.escape(YAML.dump(msg))
+ begin
+ tmp = CGI.escape(YAML.dump(msg))
+ rescue => detail
+ puts "Could not dump: #{detail}"
+ return
end
- end
+ # Add the hostname to the source
+ @driver.addlog(tmp)
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err detail
+ Puppet::Util::Log.close(self)
+ end
+ end
+ end
end
# Log to a transaction report.
Puppet::Util::Log.newdesttype :report do
- attr_reader :report
+ attr_reader :report
- match "Puppet::Transaction::Report"
+ match "Puppet::Transaction::Report"
- def initialize(report)
- @report = report
- end
+ def initialize(report)
+ @report = report
+ end
- def handle(msg)
- @report << msg
- end
+ def handle(msg)
+ @report << msg
+ end
end
# Log to an array, just for testing.
Puppet::Util::Log.newdesttype :array do
- match "Array"
+ match "Array"
- def initialize(messages)
- @messages = messages
- end
+ def initialize(messages)
+ @messages = messages
+ end
- def handle(msg)
- @messages << msg
- end
+ def handle(msg)
+ @messages << msg
+ end
end
diff --git a/lib/puppet/util/log_paths.rb b/lib/puppet/util/log_paths.rb
index e09ceb7fa..f59197ed1 100644
--- a/lib/puppet/util/log_paths.rb
+++ b/lib/puppet/util/log_paths.rb
@@ -2,26 +2,26 @@
# Copyright (c) 2007. All rights reserved.
module Puppet::Util::LogPaths
- # return the full path to us, for logging and rollback
- # some classes (e.g., FileTypeRecords) will have to override this
- def path
- @path ||= pathbuilder
+ # return the full path to us, for logging and rollback
+ # some classes (e.g., FileTypeRecords) will have to override this
+ def path
+ @path ||= pathbuilder
- "/" + @path.join("/")
- end
-
- def source_descriptors
- descriptors = {}
+ "/" + @path.join("/")
+ end
- descriptors[:tags] = tags
+ def source_descriptors
+ descriptors = {}
- [:path, :file, :line, :version].each do |param|
- next unless value = send(param)
- descriptors[param] = value
- end
+ descriptors[:tags] = tags
- descriptors
+ [:path, :file, :line, :version].each do |param|
+ next unless value = send(param)
+ descriptors[param] = value
end
+ descriptors
+ end
+
end
diff --git a/lib/puppet/util/logging.rb b/lib/puppet/util/logging.rb
index b4a531bfc..f20444a3b 100644
--- a/lib/puppet/util/logging.rb
+++ b/lib/puppet/util/logging.rb
@@ -3,38 +3,38 @@ require 'puppet/util/log'
module Puppet::Util::Logging
- def send_log(level, message)
- Puppet::Util::Log.create({:level => level, :source => log_source, :message => message}.merge(log_metadata))
+ def send_log(level, message)
+ Puppet::Util::Log.create({:level => level, :source => log_source, :message => message}.merge(log_metadata))
+ end
+
+ # Create a method for each log level.
+ Puppet::Util::Log.eachlevel do |level|
+ define_method(level) do |args|
+ args = args.join(" ") if args.is_a?(Array)
+ send_log(level, args)
end
+ end
- # Create a method for each log level.
- Puppet::Util::Log.eachlevel do |level|
- define_method(level) do |args|
- args = args.join(" ") if args.is_a?(Array)
- send_log(level, args)
- end
- end
+ private
- private
+ def is_resource?
+ defined?(Puppet::Type) && is_a?(Puppet::Type)
+ end
- def is_resource?
- defined?(Puppet::Type) && is_a?(Puppet::Type)
- end
+ def is_resource_parameter?
+ defined?(Puppet::Parameter) && is_a?(Puppet::Parameter)
+ end
- def is_resource_parameter?
- defined?(Puppet::Parameter) && is_a?(Puppet::Parameter)
+ def log_metadata
+ [:file, :line, :version, :tags].inject({}) do |result, attr|
+ result[attr] = send(attr) if respond_to?(attr)
+ result
end
+ end
- def log_metadata
- [:file, :line, :version, :tags].inject({}) do |result, attr|
- result[attr] = send(attr) if respond_to?(attr)
- result
- end
- end
-
- def log_source
- # We need to guard the existence of the constants, since this module is used by the base Puppet module.
- (is_resource? or is_resource_parameter?) and respond_to?(:path) and return path.to_s
- to_s
- end
+ def log_source
+ # We need to guard the existence of the constants, since this module is used by the base Puppet module.
+ (is_resource? or is_resource_parameter?) and respond_to?(:path) and return path.to_s
+ to_s
+ end
end
diff --git a/lib/puppet/util/metaid.rb b/lib/puppet/util/metaid.rb
index 076775c76..4092e4fda 100644
--- a/lib/puppet/util/metaid.rb
+++ b/lib/puppet/util/metaid.rb
@@ -1,21 +1,21 @@
class Object
- # The hidden singleton lurks behind everyone
- def singleton_class; class << self; self; end; end
- def meta_eval(&blk); singleton_class.instance_eval(&blk); end
+ # The hidden singleton lurks behind everyone
+ def singleton_class; class << self; self; end; end
+ def meta_eval(&blk); singleton_class.instance_eval(&blk); end
- # Adds methods to a singleton_class
- def meta_def(name, &blk)
- meta_eval { define_method name, &blk }
- end
+ # Adds methods to a singleton_class
+ def meta_def(name, &blk)
+ meta_eval { define_method name, &blk }
+ end
- # Remove singleton_class methods.
- def meta_undef(name, &blk)
- meta_eval { remove_method name }
- end
+ # Remove singleton_class methods.
+ def meta_undef(name, &blk)
+ meta_eval { remove_method name }
+ end
- # Defines an instance method within a class
- def class_def(name, &blk)
- class_eval { define_method name, &blk }
- end
+ # Defines an instance method within a class
+ def class_def(name, &blk)
+ class_eval { define_method name, &blk }
+ end
end
diff --git a/lib/puppet/util/methodhelper.rb b/lib/puppet/util/methodhelper.rb
index f8dc2cedc..2dd3afd79 100644
--- a/lib/puppet/util/methodhelper.rb
+++ b/lib/puppet/util/methodhelper.rb
@@ -1,32 +1,32 @@
# Where we store helper methods related to, um, methods.
module Puppet::Util::MethodHelper
- def requiredopts(*names)
- names.each do |name|
- devfail("#{name} is a required option for #{self.class}") if self.send(name).nil?
- end
+ def requiredopts(*names)
+ names.each do |name|
+ devfail("#{name} is a required option for #{self.class}") if self.send(name).nil?
end
+ end
- # Iterate over a hash, treating each member as an attribute.
- def set_options(options)
- options.each do |param,value|
- method = param.to_s + "="
- if respond_to? method
- self.send(method, value)
- else
- raise ArgumentError, "Invalid parameter #{param} to object class #{self.class}"
- end
- end
+ # Iterate over a hash, treating each member as an attribute.
+ def set_options(options)
+ options.each do |param,value|
+ method = param.to_s + "="
+ if respond_to? method
+ self.send(method, value)
+ else
+ raise ArgumentError, "Invalid parameter #{param} to object class #{self.class}"
+ end
end
+ end
- # Take a hash and convert all of the keys to symbols if possible.
- def symbolize_options(options)
- options.inject({}) do |hash, opts|
- if opts[0].respond_to? :intern
- hash[opts[0].intern] = opts[1]
- else
- hash[opts[0]] = opts[1]
- end
- hash
- end
+ # Take a hash and convert all of the keys to symbols if possible.
+ def symbolize_options(options)
+ options.inject({}) do |hash, opts|
+ if opts[0].respond_to? :intern
+ hash[opts[0].intern] = opts[1]
+ else
+ hash[opts[0]] = opts[1]
+ end
+ hash
end
+ end
end
diff --git a/lib/puppet/util/metric.rb b/lib/puppet/util/metric.rb
index eb25d7746..7e14a5fec 100644
--- a/lib/puppet/util/metric.rb
+++ b/lib/puppet/util/metric.rb
@@ -4,152 +4,152 @@ require 'puppet'
# A class for handling metrics. This is currently ridiculously hackish.
class Puppet::Util::Metric
- attr_accessor :type, :name, :value, :label
- attr_writer :values
-
- attr_writer :basedir
-
- # Return a specific value
- def [](name)
- if value = @values.find { |v| v[0] == name }
- return value[2]
- else
- return 0
- end
+ attr_accessor :type, :name, :value, :label
+ attr_writer :values
+
+ attr_writer :basedir
+
+ # Return a specific value
+ def [](name)
+ if value = @values.find { |v| v[0] == name }
+ return value[2]
+ else
+ return 0
end
+ end
- def basedir
- if defined?(@basedir)
- @basedir
- else
- Puppet[:rrddir]
- end
+ def basedir
+ if defined?(@basedir)
+ @basedir
+ else
+ Puppet[:rrddir]
end
+ end
- def create(start = nil)
- Puppet.settings.use(:main, :metrics)
+ def create(start = nil)
+ Puppet.settings.use(:main, :metrics)
- start ||= Time.now.to_i - 5
+ start ||= Time.now.to_i - 5
- @rrd = RRDtool.new(self.path)
- args = []
+ @rrd = RRDtool.new(self.path)
+ args = []
- values.each { |value|
- # the 7200 is the heartbeat -- this means that any data that isn't
- # more frequently than every two hours gets thrown away
- args.push "DS:#{value[0]}:GAUGE:7200:U:U"
- }
- args.push "RRA:AVERAGE:0.5:1:300"
+ values.each { |value|
+ # the 7200 is the heartbeat -- this means that any data that isn't
+ # more frequently than every two hours gets thrown away
+ args.push "DS:#{value[0]}:GAUGE:7200:U:U"
+ }
+ args.push "RRA:AVERAGE:0.5:1:300"
- begin
- @rrd.create( Puppet[:rrdinterval].to_i, start, args)
- rescue => detail
- raise "Could not create RRD file #{path}: #{detail}"
- end
+ begin
+ @rrd.create( Puppet[:rrdinterval].to_i, start, args)
+ rescue => detail
+ raise "Could not create RRD file #{path}: #{detail}"
end
+ end
+
+ def dump
+ puts @rrd.info
+ end
- def dump
- puts @rrd.info
+ def graph(range = nil)
+ unless Puppet.features.rrd?
+ Puppet.warning "RRD library is missing; cannot graph metrics"
+ return
end
- def graph(range = nil)
- unless Puppet.features.rrd?
- Puppet.warning "RRD library is missing; cannot graph metrics"
- return
- end
-
- unit = 60 * 60 * 24
- colorstack = %w{#00ff00 #ff0000 #0000ff #ffff00 #ff99ff #ff9966 #66ffff #990000 #099000 #000990 #f00990 #0f0f0f #555555 #333333 #ffffff}
-
- {:daily => unit, :weekly => unit * 7, :monthly => unit * 30, :yearly => unit * 365}.each do |name, time|
- file = self.path.sub(/\.rrd$/, "-#{name}.png")
- args = [file]
-
- args.push("--title",self.label)
- args.push("--imgformat","PNG")
- args.push("--interlace")
- i = 0
- defs = []
- lines = []
- #p @values.collect { |s,l| s }
- values.zip(colorstack).each { |value,color|
- next if value.nil?
- # this actually uses the data label
- defs.push("DEF:#{value[0]}=#{self.path}:#{value[0]}:AVERAGE")
- lines.push("LINE2:#{value[0]}#{color}:#{value[1]}")
- }
- args << defs
- args << lines
- args.flatten!
- if range
- args.push("--start",range[0],"--end",range[1])
- else
- args.push("--start", Time.now.to_i - time, "--end", Time.now.to_i)
- end
-
- begin
- #Puppet.warning "args = #{args}"
- RRDtool.graph( args )
- rescue => detail
- Puppet.err "Failed to graph #{self.name}: #{detail}"
- end
- end
+ unit = 60 * 60 * 24
+ colorstack = %w{#00ff00 #ff0000 #0000ff #ffff00 #ff99ff #ff9966 #66ffff #990000 #099000 #000990 #f00990 #0f0f0f #555555 #333333 #ffffff}
+
+ {:daily => unit, :weekly => unit * 7, :monthly => unit * 30, :yearly => unit * 365}.each do |name, time|
+ file = self.path.sub(/\.rrd$/, "-#{name}.png")
+ args = [file]
+
+ args.push("--title",self.label)
+ args.push("--imgformat","PNG")
+ args.push("--interlace")
+ i = 0
+ defs = []
+ lines = []
+ #p @values.collect { |s,l| s }
+ values.zip(colorstack).each { |value,color|
+ next if value.nil?
+ # this actually uses the data label
+ defs.push("DEF:#{value[0]}=#{self.path}:#{value[0]}:AVERAGE")
+ lines.push("LINE2:#{value[0]}#{color}:#{value[1]}")
+ }
+ args << defs
+ args << lines
+ args.flatten!
+ if range
+ args.push("--start",range[0],"--end",range[1])
+ else
+ args.push("--start", Time.now.to_i - time, "--end", Time.now.to_i)
+ end
+
+ begin
+ #Puppet.warning "args = #{args}"
+ RRDtool.graph( args )
+ rescue => detail
+ Puppet.err "Failed to graph #{self.name}: #{detail}"
+ end
end
+ end
- def initialize(name,label = nil)
- @name = name.to_s
+ def initialize(name,label = nil)
+ @name = name.to_s
- @label = label || labelize(name)
+ @label = label || labelize(name)
- @values = []
- end
+ @values = []
+ end
- def path
- File.join(self.basedir, @name + ".rrd")
- end
+ def path
+ File.join(self.basedir, @name + ".rrd")
+ end
- def newvalue(name,value,label = nil)
- label ||= labelize(name)
- @values.push [name,label,value]
- end
+ def newvalue(name,value,label = nil)
+ label ||= labelize(name)
+ @values.push [name,label,value]
+ end
- def store(time)
- unless Puppet.features.rrd?
- Puppet.warning "RRD library is missing; cannot store metrics"
- return
- end
- self.create(time - 5) unless FileTest.exists?(self.path)
-
- @rrd ||= RRDtool.new(self.path)
-
- # XXX this is not terribly error-resistant
- args = [time]
- temps = []
- values.each { |value|
- #Puppet.warning "value[0]: #{value[0]}; value[1]: #{value[1]}; value[2]: #{value[2]}; "
- args.push value[2]
- temps.push value[0]
- }
- arg = args.join(":")
- template = temps.join(":")
- begin
- @rrd.update( template, [ arg ] )
- #system("rrdtool updatev #{self.path} '#{arg}'")
- rescue => detail
- raise Puppet::Error, "Failed to update #{self.name}: #{detail}"
- end
+ def store(time)
+ unless Puppet.features.rrd?
+ Puppet.warning "RRD library is missing; cannot store metrics"
+ return
end
-
- def values
- @values.sort { |a, b| a[1] <=> b[1] }
+ self.create(time - 5) unless FileTest.exists?(self.path)
+
+ @rrd ||= RRDtool.new(self.path)
+
+ # XXX this is not terribly error-resistant
+ args = [time]
+ temps = []
+ values.each { |value|
+ #Puppet.warning "value[0]: #{value[0]}; value[1]: #{value[1]}; value[2]: #{value[2]}; "
+ args.push value[2]
+ temps.push value[0]
+ }
+ arg = args.join(":")
+ template = temps.join(":")
+ begin
+ @rrd.update( template, [ arg ] )
+ #system("rrdtool updatev #{self.path} '#{arg}'")
+ rescue => detail
+ raise Puppet::Error, "Failed to update #{self.name}: #{detail}"
end
+ end
- private
+ def values
+ @values.sort { |a, b| a[1] <=> b[1] }
+ end
- # Convert a name into a label.
- def labelize(name)
- name.to_s.capitalize.gsub("_", " ")
- end
+ private
+
+ # Convert a name into a label.
+ def labelize(name)
+ name.to_s.capitalize.gsub("_", " ")
+ end
end
# This is necessary because we changed the class path in early 2007,
diff --git a/lib/puppet/util/monkey_patches.rb b/lib/puppet/util/monkey_patches.rb
index e5e835ef0..e035afd9f 100644
--- a/lib/puppet/util/monkey_patches.rb
+++ b/lib/puppet/util/monkey_patches.rb
@@ -1,12 +1,12 @@
Process.maxgroups = 1024
module RDoc
- def self.caller(skip=nil)
- in_gem_wrapper = false
- Kernel.caller.reject { |call|
- in_gem_wrapper ||= call =~ /#{Regexp.escape $0}:\d+:in `load'/
- }
- end
+ def self.caller(skip=nil)
+ in_gem_wrapper = false
+ Kernel.caller.reject { |call|
+ in_gem_wrapper ||= call =~ /#{Regexp.escape $0}:\d+:in `load'/
+ }
+ end
end
@@ -14,22 +14,22 @@ require "yaml"
require "puppet/util/zaml.rb"
class Symbol
- def to_zaml(z)
- z.emit("!ruby/sym ")
- to_s.to_zaml(z)
- end
+ def to_zaml(z)
+ z.emit("!ruby/sym ")
+ to_s.to_zaml(z)
+ end
end
[Object, Exception, Integer, Struct, Date, Time, Range, Regexp, Hash, Array, Float, String, FalseClass, TrueClass, Symbol, NilClass, Class].each { |cls|
- cls.class_eval do
- def to_yaml
- ZAML.dump(self)
- end
+ cls.class_eval do
+ def to_yaml
+ ZAML.dump(self)
end
+ end
}
def YAML.dump(*args)
- ZAML.dump(*args)
+ ZAML.dump(*args)
end
#
@@ -38,10 +38,10 @@ end
# for details
#
if RUBY_VERSION == '1.8.7'
- class NilClass
- def closed?
- true
- end
+ class NilClass
+ def closed?
+ true
end
+ end
end
diff --git a/lib/puppet/util/nagios_maker.rb b/lib/puppet/util/nagios_maker.rb
index e824b1de2..59ed820f9 100644
--- a/lib/puppet/util/nagios_maker.rb
+++ b/lib/puppet/util/nagios_maker.rb
@@ -3,59 +3,59 @@ require 'puppet/external/nagios/base'
require 'puppet/provider/naginator'
module Puppet::Util::NagiosMaker
- # Create a new nagios type, using all of the parameters
- # from the parser.
- def self.create_nagios_type(name)
- name = name.to_sym
- full_name = ("nagios_#{name}").to_sym
+ # Create a new nagios type, using all of the parameters
+ # from the parser.
+ def self.create_nagios_type(name)
+ name = name.to_sym
+ full_name = ("nagios_#{name}").to_sym
- raise(Puppet::DevError, "No nagios type for #{name}") unless nagtype = Nagios::Base.type(name)
+ raise(Puppet::DevError, "No nagios type for #{name}") unless nagtype = Nagios::Base.type(name)
- type = Puppet::Type.newtype(full_name) {}
+ type = Puppet::Type.newtype(full_name) {}
- type.ensurable
+ type.ensurable
- type.newparam(nagtype.namevar, :namevar => true) do
- desc "The name parameter for Nagios type #{nagtype.name}"
- end
+ type.newparam(nagtype.namevar, :namevar => true) do
+ desc "The name parameter for Nagios type #{nagtype.name}"
+ end
- # We deduplicate the parameters because it makes sense to allow Naginator to have dupes.
- nagtype.parameters.uniq.each do |param|
- next if param == nagtype.namevar
+ # We deduplicate the parameters because it makes sense to allow Naginator to have dupes.
+ nagtype.parameters.uniq.each do |param|
+ next if param == nagtype.namevar
- # We can't turn these parameter names into constants, so at least for now they aren't
- # supported.
- next if param.to_s =~ /^[0-9]/
+ # We can't turn these parameter names into constants, so at least for now they aren't
+ # supported.
+ next if param.to_s =~ /^[0-9]/
- type.newproperty(param) do
- desc "Nagios configuration file parameter."
- end
- end
+ type.newproperty(param) do
+ desc "Nagios configuration file parameter."
+ end
+ end
- type.newproperty(:target) do
- desc 'target'
+ type.newproperty(:target) do
+ desc 'target'
- defaultto do
- resource.class.defaultprovider.default_target
- end
- end
+ defaultto do
+ resource.class.defaultprovider.default_target
+ end
+ end
- target = "/etc/nagios/#{full_name.to_s}.cfg"
- provider = type.provide(:naginator, :parent => Puppet::Provider::Naginator, :default_target => target) {}
- provider.nagios_type
+ target = "/etc/nagios/#{full_name.to_s}.cfg"
+ provider = type.provide(:naginator, :parent => Puppet::Provider::Naginator, :default_target => target) {}
+ provider.nagios_type
- type.desc "The Nagios type #{name.to_s}. This resource type is autogenerated using the
- model developed in Naginator_, and all of the Nagios types are generated using the
- same code and the same library.
+ type.desc "The Nagios type #{name.to_s}. This resource type is autogenerated using the
+ model developed in Naginator_, and all of the Nagios types are generated using the
+ same code and the same library.
- This type generates Nagios configuration statements in Nagios-parseable configuration
- files. By default, the statements will be added to ``#{target}``, but
- you can send them to a different file by setting their ``target`` attribute.
+ This type generates Nagios configuration statements in Nagios-parseable configuration
+ files. By default, the statements will be added to ``#{target}``, but
+ you can send them to a different file by setting their ``target`` attribute.
- You can purge Nagios resources using the ``resources`` type, but *only*
- in the default file locations. This is an architectural limitation.
+ You can purge Nagios resources using the ``resources`` type, but *only*
+ in the default file locations. This is an architectural limitation.
- .. _naginator: http://projects.reductivelabs.com/projects/naginator
- "
- end
+ .. _naginator: http://projects.reductivelabs.com/projects/naginator
+ "
+ end
end
diff --git a/lib/puppet/util/package.rb b/lib/puppet/util/package.rb
index ecac77806..5f1fc7465 100644
--- a/lib/puppet/util/package.rb
+++ b/lib/puppet/util/package.rb
@@ -1,31 +1,31 @@
module Puppet::Util::Package
- def versioncmp(version_a, version_b)
- vre = /[-.]|\d+|[^-.\d]+/
- ax = version_a.scan(vre)
- bx = version_b.scan(vre)
+ def versioncmp(version_a, version_b)
+ vre = /[-.]|\d+|[^-.\d]+/
+ ax = version_a.scan(vre)
+ bx = version_b.scan(vre)
- while (ax.length>0 && bx.length>0)
- a = ax.shift
- b = bx.shift
+ while (ax.length>0 && bx.length>0)
+ a = ax.shift
+ b = bx.shift
- if( a == b ) then next
- elsif (a == '-' && b == '-') then next
- elsif (a == '-') then return -1
- elsif (b == '-') then return 1
- elsif (a == '.' && b == '.') then next
- elsif (a == '.' ) then return -1
- elsif (b == '.' ) then return 1
- elsif (a =~ /^\d+$/ && b =~ /^\d+$/) then
- if( a =~ /^0/ or b =~ /^0/ ) then
- return a.to_s.upcase <=> b.to_s.upcase
- end
- return a.to_i <=> b.to_i
- else
- return a.upcase <=> b.upcase
- end
+ if( a == b ) then next
+ elsif (a == '-' && b == '-') then next
+ elsif (a == '-') then return -1
+ elsif (b == '-') then return 1
+ elsif (a == '.' && b == '.') then next
+ elsif (a == '.' ) then return -1
+ elsif (b == '.' ) then return 1
+ elsif (a =~ /^\d+$/ && b =~ /^\d+$/) then
+ if( a =~ /^0/ or b =~ /^0/ ) then
+ return a.to_s.upcase <=> b.to_s.upcase
end
- version_a <=> version_b;
+ return a.to_i <=> b.to_i
+ else
+ return a.upcase <=> b.upcase
+ end
end
+ version_a <=> version_b;
+ end
- module_function :versioncmp
+ module_function :versioncmp
end
diff --git a/lib/puppet/util/pidlock.rb b/lib/puppet/util/pidlock.rb
index d24b8378e..05e1459d0 100644
--- a/lib/puppet/util/pidlock.rb
+++ b/lib/puppet/util/pidlock.rb
@@ -1,68 +1,68 @@
require 'fileutils'
class Puppet::Util::Pidlock
- attr_reader :lockfile
+ attr_reader :lockfile
- def initialize(lockfile)
- @lockfile = lockfile
- end
+ def initialize(lockfile)
+ @lockfile = lockfile
+ end
- def locked?
- clear_if_stale
- File.exists? @lockfile
- end
+ def locked?
+ clear_if_stale
+ File.exists? @lockfile
+ end
- def mine?
- Process.pid == lock_pid
- end
+ def mine?
+ Process.pid == lock_pid
+ end
- def anonymous?
- return false unless File.exists?(@lockfile)
- File.read(@lockfile) == ""
- end
+ def anonymous?
+ return false unless File.exists?(@lockfile)
+ File.read(@lockfile) == ""
+ end
- def lock(opts = {})
- opts = {:anonymous => false}.merge(opts)
+ def lock(opts = {})
+ opts = {:anonymous => false}.merge(opts)
- if locked?
- mine?
- else
- if opts[:anonymous]
- File.open(@lockfile, 'w') { |fd| true }
- else
- File.open(@lockfile, "w") { |fd| fd.write(Process.pid) }
- end
- true
- end
+ if locked?
+ mine?
+ else
+ if opts[:anonymous]
+ File.open(@lockfile, 'w') { |fd| true }
+ else
+ File.open(@lockfile, "w") { |fd| fd.write(Process.pid) }
+ end
+ true
end
+ end
- def unlock(opts = {})
- opts = {:anonymous => false}.merge(opts)
+ def unlock(opts = {})
+ opts = {:anonymous => false}.merge(opts)
- if mine? or (opts[:anonymous] and anonymous?)
- File.unlink(@lockfile)
- true
- else
- false
- end
+ if mine? or (opts[:anonymous] and anonymous?)
+ File.unlink(@lockfile)
+ true
+ else
+ false
end
+ end
- private
- def lock_pid
- if File.exists? @lockfile
- File.read(@lockfile).to_i
- else
- nil
- end
+ private
+ def lock_pid
+ if File.exists? @lockfile
+ File.read(@lockfile).to_i
+ else
+ nil
end
+ end
- def clear_if_stale
- return if lock_pid.nil?
+ def clear_if_stale
+ return if lock_pid.nil?
- begin
- Process.kill(0, lock_pid)
- rescue Errno::ESRCH
- File.unlink(@lockfile)
- end
+ begin
+ Process.kill(0, lock_pid)
+ rescue Errno::ESRCH
+ File.unlink(@lockfile)
end
+ end
end
diff --git a/lib/puppet/util/posix.rb b/lib/puppet/util/posix.rb
index 6bb94b01f..4cabe24af 100755
--- a/lib/puppet/util/posix.rb
+++ b/lib/puppet/util/posix.rb
@@ -1,137 +1,137 @@
# Utility methods for interacting with POSIX objects; mostly user and group
module Puppet::Util::POSIX
- # Retrieve a field from a POSIX Etc object. The id can be either an integer
- # or a name. This only works for users and groups. It's also broken on
- # some platforms, unfortunately, which is why we fall back to the other
- # method search_posix_field in the gid and uid methods if a sanity check
- # fails
- def get_posix_field(space, field, id)
- raise Puppet::DevError, "Did not get id from caller" unless id
+ # Retrieve a field from a POSIX Etc object. The id can be either an integer
+ # or a name. This only works for users and groups. It's also broken on
+ # some platforms, unfortunately, which is why we fall back to the other
+ # method search_posix_field in the gid and uid methods if a sanity check
+ # fails
+ def get_posix_field(space, field, id)
+ raise Puppet::DevError, "Did not get id from caller" unless id
- if id.is_a?(Integer)
- if id > Puppet[:maximum_uid].to_i
- Puppet.err "Tried to get #{field} field for silly id #{id}"
- return nil
- end
- method = methodbyid(space)
- else
- method = methodbyname(space)
- end
+ if id.is_a?(Integer)
+ if id > Puppet[:maximum_uid].to_i
+ Puppet.err "Tried to get #{field} field for silly id #{id}"
+ return nil
+ end
+ method = methodbyid(space)
+ else
+ method = methodbyname(space)
+ end
- begin
- return Etc.send(method, id).send(field)
- rescue ArgumentError => detail
- # ignore it; we couldn't find the object
- return nil
- end
+ begin
+ return Etc.send(method, id).send(field)
+ rescue ArgumentError => detail
+ # ignore it; we couldn't find the object
+ return nil
end
+ end
- # A degenerate method of retrieving name/id mappings. The job of this method is
- # to retrieve all objects of a certain type, search for a specific entry
- # and then return a given field from that entry.
- def search_posix_field(type, field, id)
- idmethod = idfield(type)
- integer = false
- if id.is_a?(Integer)
- integer = true
- if id > Puppet[:maximum_uid].to_i
- Puppet.err "Tried to get #{field} field for silly id #{id}"
- return nil
- end
- end
+ # A degenerate method of retrieving name/id mappings. The job of this method is
+ # to retrieve all objects of a certain type, search for a specific entry
+ # and then return a given field from that entry.
+ def search_posix_field(type, field, id)
+ idmethod = idfield(type)
+ integer = false
+ if id.is_a?(Integer)
+ integer = true
+ if id > Puppet[:maximum_uid].to_i
+ Puppet.err "Tried to get #{field} field for silly id #{id}"
+ return nil
+ end
+ end
- Etc.send(type) do |object|
- if integer and object.send(idmethod) == id
- return object.send(field)
- elsif object.name == id
- return object.send(field)
- end
- end
+ Etc.send(type) do |object|
+ if integer and object.send(idmethod) == id
+ return object.send(field)
+ elsif object.name == id
+ return object.send(field)
+ end
+ end
- # Apparently the group/passwd methods need to get reset; if we skip
- # this call, then new users aren't found.
- case type
- when :passwd; Etc.send(:endpwent)
- when :group; Etc.send(:endgrent)
- end
- nil
+ # Apparently the group/passwd methods need to get reset; if we skip
+ # this call, then new users aren't found.
+ case type
+ when :passwd; Etc.send(:endpwent)
+ when :group; Etc.send(:endgrent)
end
+ nil
+ end
- # Determine what the field name is for users and groups.
- def idfield(space)
- case Puppet::Util.symbolize(space)
- when :gr, :group; return :gid
- when :pw, :user, :passwd; return :uid
- else
- raise ArgumentError.new("Can only handle users and groups")
- end
+ # Determine what the field name is for users and groups.
+ def idfield(space)
+ case Puppet::Util.symbolize(space)
+ when :gr, :group; return :gid
+ when :pw, :user, :passwd; return :uid
+ else
+ raise ArgumentError.new("Can only handle users and groups")
end
+ end
- # Determine what the method is to get users and groups by id
- def methodbyid(space)
- case Puppet::Util.symbolize(space)
- when :gr, :group; return :getgrgid
- when :pw, :user, :passwd; return :getpwuid
- else
- raise ArgumentError.new("Can only handle users and groups")
- end
+ # Determine what the method is to get users and groups by id
+ def methodbyid(space)
+ case Puppet::Util.symbolize(space)
+ when :gr, :group; return :getgrgid
+ when :pw, :user, :passwd; return :getpwuid
+ else
+ raise ArgumentError.new("Can only handle users and groups")
end
+ end
- # Determine what the method is to get users and groups by name
- def methodbyname(space)
- case Puppet::Util.symbolize(space)
- when :gr, :group; return :getgrnam
- when :pw, :user, :passwd; return :getpwnam
- else
- raise ArgumentError.new("Can only handle users and groups")
- end
+ # Determine what the method is to get users and groups by name
+ def methodbyname(space)
+ case Puppet::Util.symbolize(space)
+ when :gr, :group; return :getgrnam
+ when :pw, :user, :passwd; return :getpwnam
+ else
+ raise ArgumentError.new("Can only handle users and groups")
end
+ end
- # Get the GID of a given group, provided either a GID or a name
- def gid(group)
- begin
- group = Integer(group)
- rescue ArgumentError
- # pass
- end
- if group.is_a?(Integer)
- return nil unless name = get_posix_field(:group, :name, group)
- gid = get_posix_field(:group, :gid, name)
- check_value = gid
- else
- return nil unless gid = get_posix_field(:group, :gid, group)
- name = get_posix_field(:group, :name, gid)
- check_value = name
- end
- if check_value != group
- return search_posix_field(:group, :gid, group)
- else
- return gid
- end
+ # Get the GID of a given group, provided either a GID or a name
+ def gid(group)
+ begin
+ group = Integer(group)
+ rescue ArgumentError
+ # pass
+ end
+ if group.is_a?(Integer)
+ return nil unless name = get_posix_field(:group, :name, group)
+ gid = get_posix_field(:group, :gid, name)
+ check_value = gid
+ else
+ return nil unless gid = get_posix_field(:group, :gid, group)
+ name = get_posix_field(:group, :name, gid)
+ check_value = name
end
+ if check_value != group
+ return search_posix_field(:group, :gid, group)
+ else
+ return gid
+ end
+ end
- # Get the UID of a given user, whether a UID or name is provided
- def uid(user)
- begin
- user = Integer(user)
- rescue ArgumentError
- # pass
- end
- if user.is_a?(Integer)
- return nil unless name = get_posix_field(:passwd, :name, user)
- uid = get_posix_field(:passwd, :uid, name)
- check_value = uid
- else
- return nil unless uid = get_posix_field(:passwd, :uid, user)
- name = get_posix_field(:passwd, :name, uid)
- check_value = name
- end
- if check_value != user
- return search_posix_field(:passwd, :uid, user)
- else
- return uid
- end
+ # Get the UID of a given user, whether a UID or name is provided
+ def uid(user)
+ begin
+ user = Integer(user)
+ rescue ArgumentError
+ # pass
+ end
+ if user.is_a?(Integer)
+ return nil unless name = get_posix_field(:passwd, :name, user)
+ uid = get_posix_field(:passwd, :uid, name)
+ check_value = uid
+ else
+ return nil unless uid = get_posix_field(:passwd, :uid, user)
+ name = get_posix_field(:passwd, :name, uid)
+ check_value = name
+ end
+ if check_value != user
+ return search_posix_field(:passwd, :uid, user)
+ else
+ return uid
end
+ end
end
diff --git a/lib/puppet/util/provider_features.rb b/lib/puppet/util/provider_features.rb
index e0f90aebe..ac294d20d 100644
--- a/lib/puppet/util/provider_features.rb
+++ b/lib/puppet/util/provider_features.rb
@@ -3,167 +3,167 @@ require 'puppet/util/methodhelper'
require 'puppet/util/docs'
require 'puppet/util'
module Puppet::Util::ProviderFeatures
+ include Puppet::Util::Docs
+ # The class that models the features and handles checking whether the features
+ # are present.
+ class ProviderFeature
+ include Puppet::Util
+ include Puppet::Util::MethodHelper
include Puppet::Util::Docs
- # The class that models the features and handles checking whether the features
- # are present.
- class ProviderFeature
- include Puppet::Util
- include Puppet::Util::MethodHelper
- include Puppet::Util::Docs
- attr_accessor :name, :docs, :methods
-
- # Are all of the requirements met?
- def available?(obj)
- if self.methods
- return !!methods_available?(obj)
- else
- # In this case, the provider has to declare support for this
- # feature, and that's been checked before we ever get to the
- # method checks.
- return false
- end
- end
-
- def initialize(name, docs, hash)
- self.name = symbolize(name)
- self.docs = docs
- hash = symbolize_options(hash)
- set_options(hash)
- end
-
- private
-
- # Are all of the required methods available?
- def methods_available?(obj)
- methods.each do |m|
- if obj.is_a?(Class)
- return false unless obj.public_method_defined?(m)
- else
- return false unless obj.respond_to?(m)
- end
- end
- true
- end
+ attr_accessor :name, :docs, :methods
+
+ # Are all of the requirements met?
+ def available?(obj)
+ if self.methods
+ return !!methods_available?(obj)
+ else
+ # In this case, the provider has to declare support for this
+ # feature, and that's been checked before we ever get to the
+ # method checks.
+ return false
+ end
end
- # Define one or more features. At a minimum, features require a name
- # and docs, and at this point they should also specify a list of methods
- # required to determine if the feature is present.
- def feature(name, docs, hash = {})
- @features ||= {}
- raise(Puppet::DevError, "Feature #{name} is already defined") if @features.include?(name)
- begin
- obj = ProviderFeature.new(name, docs, hash)
- @features[obj.name] = obj
- rescue ArgumentError => detail
- error = ArgumentError.new(
- "Could not create feature #{name}: #{detail}"
- )
- error.set_backtrace(detail.backtrace)
- raise error
- end
+ def initialize(name, docs, hash)
+ self.name = symbolize(name)
+ self.docs = docs
+ hash = symbolize_options(hash)
+ set_options(hash)
end
- # Return a hash of all feature documentation.
- def featuredocs
- str = ""
- @features ||= {}
- return nil if @features.empty?
- names = @features.keys.sort { |a,b| a.to_s <=> b.to_s }
- names.each do |name|
- doc = @features[name].docs.gsub(/\n\s+/, " ")
- str += "- **#{name}**: #{doc}\n"
- end
+ private
- if providers.length > 0
- headers = ["Provider", names].flatten
- data = {}
- providers.each do |provname|
- data[provname] = []
- prov = provider(provname)
- names.each do |name|
- if prov.feature?(name)
- data[provname] << "**X**"
- else
- data[provname] << ""
- end
- end
- end
- str += doctable(headers, data)
+ # Are all of the required methods available?
+ def methods_available?(obj)
+ methods.each do |m|
+ if obj.is_a?(Class)
+ return false unless obj.public_method_defined?(m)
+ else
+ return false unless obj.respond_to?(m)
end
- str
+ end
+ true
+ end
+ end
+
+ # Define one or more features. At a minimum, features require a name
+ # and docs, and at this point they should also specify a list of methods
+ # required to determine if the feature is present.
+ def feature(name, docs, hash = {})
+ @features ||= {}
+ raise(Puppet::DevError, "Feature #{name} is already defined") if @features.include?(name)
+ begin
+ obj = ProviderFeature.new(name, docs, hash)
+ @features[obj.name] = obj
+ rescue ArgumentError => detail
+ error = ArgumentError.new(
+ "Could not create feature #{name}: #{detail}"
+ )
+ error.set_backtrace(detail.backtrace)
+ raise error
+ end
+ end
+
+ # Return a hash of all feature documentation.
+ def featuredocs
+ str = ""
+ @features ||= {}
+ return nil if @features.empty?
+ names = @features.keys.sort { |a,b| a.to_s <=> b.to_s }
+ names.each do |name|
+ doc = @features[name].docs.gsub(/\n\s+/, " ")
+ str += "- **#{name}**: #{doc}\n"
end
- # Return a list of features.
- def features
- @features ||= {}
- @features.keys
+ if providers.length > 0
+ headers = ["Provider", names].flatten
+ data = {}
+ providers.each do |provname|
+ data[provname] = []
+ prov = provider(provname)
+ names.each do |name|
+ if prov.feature?(name)
+ data[provname] << "**X**"
+ else
+ data[provname] << ""
+ end
+ end
+ end
+ str += doctable(headers, data)
end
+ str
+ end
+
+ # Return a list of features.
+ def features
+ @features ||= {}
+ @features.keys
+ end
+
+ # Generate a module that sets up the boolean methods to test for given
+ # features.
+ def feature_module
+ unless defined?(@feature_module)
+ @features ||= {}
+ @feature_module = ::Module.new
+ const_set("FeatureModule", @feature_module)
+ features = @features
+ # Create a feature? method that can be passed a feature name and
+ # determine if the feature is present.
+ @feature_module.send(:define_method, :feature?) do |name|
+ method = name.to_s + "?"
+ return !!(respond_to?(method) and send(method))
+ end
+
+ # Create a method that will list all functional features.
+ @feature_module.send(:define_method, :features) do
+ return false unless defined?(features)
+ features.keys.find_all { |n| feature?(n) }.sort { |a,b|
+ a.to_s <=> b.to_s
+ }
+ end
+
+ # Create a method that will determine if a provided list of
+ # features are satisfied by the curred provider.
+ @feature_module.send(:define_method, :satisfies?) do |*needed|
+ ret = true
+ needed.flatten.each do |feature|
+ unless feature?(feature)
+ ret = false
+ break
+ end
+ end
+ ret
+ end
+
+ # Create a boolean method for each feature so you can test them
+ # individually as you might need.
+ @features.each do |name, feature|
+ method = name.to_s + "?"
+ @feature_module.send(:define_method, method) do
+ (is_a?(Class) ? declared_feature?(name) : self.class.declared_feature?(name)) or feature.available?(self)
+ end
+ end
- # Generate a module that sets up the boolean methods to test for given
- # features.
- def feature_module
- unless defined?(@feature_module)
- @features ||= {}
- @feature_module = ::Module.new
- const_set("FeatureModule", @feature_module)
- features = @features
- # Create a feature? method that can be passed a feature name and
- # determine if the feature is present.
- @feature_module.send(:define_method, :feature?) do |name|
- method = name.to_s + "?"
- return !!(respond_to?(method) and send(method))
- end
-
- # Create a method that will list all functional features.
- @feature_module.send(:define_method, :features) do
- return false unless defined?(features)
- features.keys.find_all { |n| feature?(n) }.sort { |a,b|
- a.to_s <=> b.to_s
- }
- end
-
- # Create a method that will determine if a provided list of
- # features are satisfied by the curred provider.
- @feature_module.send(:define_method, :satisfies?) do |*needed|
- ret = true
- needed.flatten.each do |feature|
- unless feature?(feature)
- ret = false
- break
- end
- end
- ret
- end
-
- # Create a boolean method for each feature so you can test them
- # individually as you might need.
- @features.each do |name, feature|
- method = name.to_s + "?"
- @feature_module.send(:define_method, method) do
- (is_a?(Class) ? declared_feature?(name) : self.class.declared_feature?(name)) or feature.available?(self)
- end
- end
-
- # Allow the provider to declare that it has a given feature.
- @feature_module.send(:define_method, :has_features) do |*names|
- @declared_features ||= []
- names.each do |name|
- name = symbolize(name)
- @declared_features << name
- end
- end
- # Aaah, grammatical correctness
- @feature_module.send(:alias_method, :has_feature, :has_features)
+ # Allow the provider to declare that it has a given feature.
+ @feature_module.send(:define_method, :has_features) do |*names|
+ @declared_features ||= []
+ names.each do |name|
+ name = symbolize(name)
+ @declared_features << name
end
- @feature_module
+ end
+ # Aaah, grammatical correctness
+ @feature_module.send(:alias_method, :has_feature, :has_features)
end
+ @feature_module
+ end
- # Return the actual provider feature instance. Really only used for testing.
- def provider_feature(name)
- return nil unless defined?(@features)
+ # Return the actual provider feature instance. Really only used for testing.
+ def provider_feature(name)
+ return nil unless defined?(@features)
- @features[name]
- end
+ @features[name]
+ end
end
diff --git a/lib/puppet/util/pson.rb b/lib/puppet/util/pson.rb
index 87afbe0c5..1441069c0 100644
--- a/lib/puppet/util/pson.rb
+++ b/lib/puppet/util/pson.rb
@@ -6,8 +6,8 @@
# figure out what class we're working on, we don't need that, and we don't want
# our consumers and producers to need to know anything about our internals.
module Puppet::Util::Pson
- def pson_create(pson)
- raise ArgumentError, "No data provided in pson data" unless pson['data']
- from_pson(pson['data'])
- end
+ def pson_create(pson)
+ raise ArgumentError, "No data provided in pson data" unless pson['data']
+ from_pson(pson['data'])
+ end
end
diff --git a/lib/puppet/util/queue.rb b/lib/puppet/util/queue.rb
index d09d32cec..02357742a 100644
--- a/lib/puppet/util/queue.rb
+++ b/lib/puppet/util/queue.rb
@@ -34,63 +34,63 @@ require 'puppet/util/instance_loader'
# * <tt>subscribe(queue)</tt> _block_ subscribes to _queue_ and executes _block_ upon receiving a message.
# * _queue_ names are simple names independent of the message broker or client library. No "/queue/" prefixes like in Stomp::Client.
module Puppet::Util::Queue
- extend Puppet::Util::InstanceLoader
- instance_load :queue_clients, 'puppet/util/queue'
+ extend Puppet::Util::InstanceLoader
+ instance_load :queue_clients, 'puppet/util/queue'
- # Adds a new class/queue-type pair to the registry. The _type_ argument is optional; if not provided,
- # _type_ defaults to a lowercased, underscored symbol programmatically derived from the rightmost
- # namespace of <em>klass.name</em>.
- #
- # # register with default name +:you+
- # register_queue_type(Foo::You)
- #
- # # register with explicit queue type name +:myself+
- # register_queue_type(Foo::Me, :myself)
- #
- # If the type is already registered, an exception is thrown. No checking is performed of _klass_,
- # however; a given class could be registered any number of times, as long as the _type_ differs with
- # each registration.
- def self.register_queue_type(klass, type = nil)
- type ||= queue_type_from_class(klass)
- raise Puppet::Error, "Queue type #{type} is already registered" if instance_hash(:queue_clients).include?(type)
- instance_hash(:queue_clients)[type] = klass
- end
+ # Adds a new class/queue-type pair to the registry. The _type_ argument is optional; if not provided,
+ # _type_ defaults to a lowercased, underscored symbol programmatically derived from the rightmost
+ # namespace of <em>klass.name</em>.
+ #
+ # # register with default name +:you+
+ # register_queue_type(Foo::You)
+ #
+ # # register with explicit queue type name +:myself+
+ # register_queue_type(Foo::Me, :myself)
+ #
+ # If the type is already registered, an exception is thrown. No checking is performed of _klass_,
+ # however; a given class could be registered any number of times, as long as the _type_ differs with
+ # each registration.
+ def self.register_queue_type(klass, type = nil)
+ type ||= queue_type_from_class(klass)
+ raise Puppet::Error, "Queue type #{type} is already registered" if instance_hash(:queue_clients).include?(type)
+ instance_hash(:queue_clients)[type] = klass
+ end
- # Given a queue type symbol, returns the associated +Class+ object. If the queue type is unknown
- # (meaning it hasn't been registered with this module), an exception is thrown.
- def self.queue_type_to_class(type)
- c = loaded_instance :queue_clients, type
- raise Puppet::Error, "Queue type #{type} is unknown." unless c
- c
- end
+ # Given a queue type symbol, returns the associated +Class+ object. If the queue type is unknown
+ # (meaning it hasn't been registered with this module), an exception is thrown.
+ def self.queue_type_to_class(type)
+ c = loaded_instance :queue_clients, type
+ raise Puppet::Error, "Queue type #{type} is unknown." unless c
+ c
+ end
- # Given a class object _klass_, returns the programmatic default queue type name symbol for _klass_.
- # The algorithm is as shown in earlier examples; the last namespace segment of _klass.name_ is taken
- # and converted from mixed case to underscore-separated lowercase, and interned.
- # queue_type_from_class(Foo) -> :foo
- # queue_type_from_class(Foo::Too) -> :too
- # queue_type_from_class(Foo::ForYouTwo) -> :for_you_too
- #
- # The implicit assumption here, consistent with Puppet's approach to plugins in general,
- # is that all your client modules live in the same namespace, such that reduction to
- # a flat namespace of symbols is reasonably safe.
- def self.queue_type_from_class(klass)
- # convert last segment of classname from studly caps to lower case with underscores, and symbolize
- klass.name.split('::').pop.sub(/^[A-Z]/) {|c| c.downcase}.gsub(/[A-Z]/) {|c| '_' + c.downcase }.intern
- end
+ # Given a class object _klass_, returns the programmatic default queue type name symbol for _klass_.
+ # The algorithm is as shown in earlier examples; the last namespace segment of _klass.name_ is taken
+ # and converted from mixed case to underscore-separated lowercase, and interned.
+ # queue_type_from_class(Foo) -> :foo
+ # queue_type_from_class(Foo::Too) -> :too
+ # queue_type_from_class(Foo::ForYouTwo) -> :for_you_too
+ #
+ # The implicit assumption here, consistent with Puppet's approach to plugins in general,
+ # is that all your client modules live in the same namespace, such that reduction to
+ # a flat namespace of symbols is reasonably safe.
+ def self.queue_type_from_class(klass)
+ # convert last segment of classname from studly caps to lower case with underscores, and symbolize
+ klass.name.split('::').pop.sub(/^[A-Z]/) {|c| c.downcase}.gsub(/[A-Z]/) {|c| '_' + c.downcase }.intern
+ end
- # The class object for the client to be used, determined by queue configuration
- # settings.
- # Looks to the <tt>:queue_type</tt> configuration entry in the running application for
- # the default queue type to use.
- def client_class
- Puppet::Util::Queue.queue_type_to_class(Puppet[:queue_type])
- end
+ # The class object for the client to be used, determined by queue configuration
+ # settings.
+ # Looks to the <tt>:queue_type</tt> configuration entry in the running application for
+ # the default queue type to use.
+ def client_class
+ Puppet::Util::Queue.queue_type_to_class(Puppet[:queue_type])
+ end
- # Returns (instantiating as necessary) the singleton queue client instance, according to the
- # client_class. No arguments go to the client class constructor, meaning its up to the client class
- # to know how to determine its queue message source (presumably through Puppet configuration data).
- def client
- @client ||= client_class.new
- end
+ # Returns (instantiating as necessary) the singleton queue client instance, according to the
+ # client_class. No arguments go to the client class constructor, meaning its up to the client class
+ # to know how to determine its queue message source (presumably through Puppet configuration data).
+ def client
+ @client ||= client_class.new
+ end
end
diff --git a/lib/puppet/util/queue/stomp.rb b/lib/puppet/util/queue/stomp.rb
index ffe745ff7..c18edae6a 100644
--- a/lib/puppet/util/queue/stomp.rb
+++ b/lib/puppet/util/queue/stomp.rb
@@ -9,39 +9,39 @@ require 'uri'
# consequently, for this client to work, <tt>Puppet[:queue_source]</tt> must use the Stomp::Client URL-like
# syntax for identifying the Stomp message broker: <em>login:pass@host.port</em>
class Puppet::Util::Queue::Stomp
- attr_accessor :stomp_client
+ attr_accessor :stomp_client
- def initialize
- begin
- uri = URI.parse(Puppet[:queue_source])
- rescue => detail
- raise ArgumentError, "Could not create Stomp client instance - queue source #{Puppet[:queue_source]} is invalid: #{detail}"
- end
- unless uri.scheme == "stomp"
- raise ArgumentError, "Could not create Stomp client instance - queue source #{Puppet[:queue_source]} is not a Stomp URL: #{detail}"
- end
-
- begin
- self.stomp_client = Stomp::Client.new(uri.user, uri.password, uri.host, uri.port, true)
- rescue => detail
- raise ArgumentError, "Could not create Stomp client instance with queue source #{Puppet[:queue_source]}: got internal Stomp client error #{detail}"
- end
+ def initialize
+ begin
+ uri = URI.parse(Puppet[:queue_source])
+ rescue => detail
+ raise ArgumentError, "Could not create Stomp client instance - queue source #{Puppet[:queue_source]} is invalid: #{detail}"
end
-
- def send_message(target, msg)
- stomp_client.send(stompify_target(target), msg, :persistent => true)
+ unless uri.scheme == "stomp"
+ raise ArgumentError, "Could not create Stomp client instance - queue source #{Puppet[:queue_source]} is not a Stomp URL: #{detail}"
end
- def subscribe(target)
- stomp_client.subscribe(stompify_target(target), :ack => :client) do |stomp_message|
- yield(stomp_message.body)
- stomp_client.acknowledge(stomp_message)
- end
+ begin
+ self.stomp_client = Stomp::Client.new(uri.user, uri.password, uri.host, uri.port, true)
+ rescue => detail
+ raise ArgumentError, "Could not create Stomp client instance with queue source #{Puppet[:queue_source]}: got internal Stomp client error #{detail}"
end
+ end
- def stompify_target(target)
- '/queue/' + target.to_s
+ def send_message(target, msg)
+ stomp_client.send(stompify_target(target), msg, :persistent => true)
+ end
+
+ def subscribe(target)
+ stomp_client.subscribe(stompify_target(target), :ack => :client) do |stomp_message|
+ yield(stomp_message.body)
+ stomp_client.acknowledge(stomp_message)
end
+ end
+
+ def stompify_target(target)
+ '/queue/' + target.to_s
+ end
- Puppet::Util::Queue.register_queue_type(self, :stomp)
+ Puppet::Util::Queue.register_queue_type(self, :stomp)
end
diff --git a/lib/puppet/util/rails/cache_accumulator.rb b/lib/puppet/util/rails/cache_accumulator.rb
index 7c59a5d3f..4b3717f79 100644
--- a/lib/puppet/util/rails/cache_accumulator.rb
+++ b/lib/puppet/util/rails/cache_accumulator.rb
@@ -1,65 +1,65 @@
require 'puppet/util'
module Puppet::Util::CacheAccumulator
- def self.included(klass)
- klass.extend ClassMethods
- end
+ def self.included(klass)
+ klass.extend ClassMethods
+ end
- class Base
- attr_reader :klass, :attribute
+ class Base
+ attr_reader :klass, :attribute
- def initialize(klass, attribute)
- @klass = klass
- @attribute = attribute
- @find_or_create = "find_or_create_by_#{@attribute.to_s}".intern
- end
+ def initialize(klass, attribute)
+ @klass = klass
+ @attribute = attribute
+ @find_or_create = "find_or_create_by_#{@attribute.to_s}".intern
+ end
- def store
- @store || reset
- end
+ def store
+ @store || reset
+ end
- def reset
- @store = {}
- end
+ def reset
+ @store = {}
+ end
- def find(*keys)
- result = nil
- if keys.length == 1
- result = store[keys[0]] ||= @klass.send(@find_or_create, *keys)
- else
- found, missing = keys.partition {|k| store.include? k}
- result = found.length
- result += do_multi_find(missing) if missing.length > 0
- end
- result
- end
+ def find(*keys)
+ result = nil
+ if keys.length == 1
+ result = store[keys[0]] ||= @klass.send(@find_or_create, *keys)
+ else
+ found, missing = keys.partition {|k| store.include? k}
+ result = found.length
+ result += do_multi_find(missing) if missing.length > 0
+ end
+ result
+ end
- def do_multi_find(keys)
- result = 0
- @klass.find(:all, :conditions => {@attribute => keys}).each do |obj|
- store[obj.send(@attribute)] = obj
- result += 1
- end
- result
- end
+ def do_multi_find(keys)
+ result = 0
+ @klass.find(:all, :conditions => {@attribute => keys}).each do |obj|
+ store[obj.send(@attribute)] = obj
+ result += 1
+ end
+ result
end
+ end
- module ClassMethods
- def accumulates(*attributes)
- attributes.each {|attrib| install_accumulator(attrib)}
- end
+ module ClassMethods
+ def accumulates(*attributes)
+ attributes.each {|attrib| install_accumulator(attrib)}
+ end
- def accumulators
- @accumulators ||= {}
- end
+ def accumulators
+ @accumulators ||= {}
+ end
- def install_accumulator(attribute)
- self.accumulators[attribute] = Base.new(self, attribute)
- module_eval %{
- def self.accumulate_by_#{attribute.to_s}(*keys)
- accumulators[:#{attribute.to_s}].find(*keys)
- end
- }
+ def install_accumulator(attribute)
+ self.accumulators[attribute] = Base.new(self, attribute)
+ module_eval %{
+ def self.accumulate_by_#{attribute.to_s}(*keys)
+ accumulators[:#{attribute.to_s}].find(*keys)
end
+ }
end
+ end
end
diff --git a/lib/puppet/util/rails/collection_merger.rb b/lib/puppet/util/rails/collection_merger.rb
index 3a28bb304..f95d3d3bd 100644
--- a/lib/puppet/util/rails/collection_merger.rb
+++ b/lib/puppet/util/rails/collection_merger.rb
@@ -1,17 +1,17 @@
module Puppet::Util::CollectionMerger
- def ar_hash_merge(db_hash, mem_hash, args)
- (db_hash.keys | mem_hash.keys).each do |key|
- if (db_hash[key] && mem_hash[key])
- # in both, update value
- args[:modify].call(db_hash[key], mem_hash[key])
- elsif (db_hash[key])
- # in db, not memory, delete from database
- args[:delete].call(db_hash[key])
- else
- # in mem, not in db, insert into the database
- args[:create].call(key, mem_hash[key])
- end
- end
+ def ar_hash_merge(db_hash, mem_hash, args)
+ (db_hash.keys | mem_hash.keys).each do |key|
+ if (db_hash[key] && mem_hash[key])
+ # in both, update value
+ args[:modify].call(db_hash[key], mem_hash[key])
+ elsif (db_hash[key])
+ # in db, not memory, delete from database
+ args[:delete].call(db_hash[key])
+ else
+ # in mem, not in db, insert into the database
+ args[:create].call(key, mem_hash[key])
+ end
end
+ end
end
diff --git a/lib/puppet/util/rails/reference_serializer.rb b/lib/puppet/util/rails/reference_serializer.rb
index a23f2cbea..9beeb0048 100644
--- a/lib/puppet/util/rails/reference_serializer.rb
+++ b/lib/puppet/util/rails/reference_serializer.rb
@@ -1,32 +1,32 @@
module Puppet::Util::ReferenceSerializer
- def unserialize_value(val)
- case val
- when /^--- /
- YAML.load(val)
- when "true"
- true
- when "false"
- false
- else
- val
- end
+ def unserialize_value(val)
+ case val
+ when /^--- /
+ YAML.load(val)
+ when "true"
+ true
+ when "false"
+ false
+ else
+ val
end
+ end
- def serialize_value(val)
- case val
- when Puppet::Resource
- YAML.dump(val)
- when true, false
- # The database does this for us, but I prefer the
- # methods be their exact inverses.
- # Note that this means quoted booleans get returned
- # as actual booleans, but there doesn't appear to be
- # a way to fix that while keeping the ability to
- # search for parameters set to true.
- val.to_s
- else
- val
- end
+ def serialize_value(val)
+ case val
+ when Puppet::Resource
+ YAML.dump(val)
+ when true, false
+ # The database does this for us, but I prefer the
+ # methods be their exact inverses.
+ # Note that this means quoted booleans get returned
+ # as actual booleans, but there doesn't appear to be
+ # a way to fix that while keeping the ability to
+ # search for parameters set to true.
+ val.to_s
+ else
+ val
end
+ end
end
diff --git a/lib/puppet/util/rdoc.rb b/lib/puppet/util/rdoc.rb
index ef208caff..4a80b069b 100644
--- a/lib/puppet/util/rdoc.rb
+++ b/lib/puppet/util/rdoc.rb
@@ -1,91 +1,91 @@
module Puppet::Util::RDoc
- module_function
-
- # launch a rdoc documenation process
- # with the files/dir passed in +files+
- def rdoc(outputdir, files, charset = nil)
- Puppet[:ignoreimport] = true
-
- # then rdoc
- require 'rdoc/rdoc'
-
- # load our parser
- require 'puppet/util/rdoc/parser'
-
- r = RDoc::RDoc.new
-
- RDoc::RDoc::GENERATORS["puppet"] = RDoc::RDoc::Generator.new(
- "puppet/util/rdoc/generators/puppet_generator.rb",
- "PuppetGenerator".intern,
-
- "puppet")
- # specify our own format & where to output
- options = [ "--fmt", "puppet",
- "--quiet",
- "--force-update",
- "--exclude", "/modules/[^/]*/files/.*\.pp$",
- "--op", outputdir ]
-
- options += [ "--charset", charset] if charset
- options += files
-
- # launch the documentation process
- r.document(options)
- rescue RDoc::RDocError => e
- raise Puppet::ParseError.new("RDoc error #{e}")
+ module_function
+
+ # launch a rdoc documenation process
+ # with the files/dir passed in +files+
+ def rdoc(outputdir, files, charset = nil)
+ Puppet[:ignoreimport] = true
+
+ # then rdoc
+ require 'rdoc/rdoc'
+
+ # load our parser
+ require 'puppet/util/rdoc/parser'
+
+ r = RDoc::RDoc.new
+
+ RDoc::RDoc::GENERATORS["puppet"] = RDoc::RDoc::Generator.new(
+ "puppet/util/rdoc/generators/puppet_generator.rb",
+ "PuppetGenerator".intern,
+
+ "puppet")
+ # specify our own format & where to output
+ options = [ "--fmt", "puppet",
+ "--quiet",
+ "--force-update",
+ "--exclude", "/modules/[^/]*/files/.*\.pp$",
+ "--op", outputdir ]
+
+ options += [ "--charset", charset] if charset
+ options += files
+
+ # launch the documentation process
+ r.document(options)
+ rescue RDoc::RDocError => e
+ raise Puppet::ParseError.new("RDoc error #{e}")
+ end
+
+ # launch a output to console manifest doc
+ def manifestdoc(files)
+ Puppet[:ignoreimport] = true
+ files.select { |f| FileTest.file?(f) }.each do |f|
+ parser = Puppet::Parser::Parser.new(:environment => Puppet[:environment])
+ parser.file = f
+ ast = parser.parse
+ output(f, ast)
end
-
- # launch a output to console manifest doc
- def manifestdoc(files)
- Puppet[:ignoreimport] = true
- files.select { |f| FileTest.file?(f) }.each do |f|
- parser = Puppet::Parser::Parser.new(:environment => Puppet[:environment])
- parser.file = f
- ast = parser.parse
- output(f, ast)
- end
+ end
+
+ # Ouputs to the console the documentation
+ # of a manifest
+ def output(file, ast)
+ astobj = []
+ ast.nodes.each do |name, k|
+ astobj << k if k.file == file
end
- # Ouputs to the console the documentation
- # of a manifest
- def output(file, ast)
- astobj = []
- ast.nodes.each do |name, k|
- astobj << k if k.file == file
- end
-
- ast.hostclasses.each do |name,k|
- astobj << k if k.file == file
- end
-
- ast.definitions.each do |name, k|
- astobj << k if k.file == file
- end
- astobj.sort! {|a,b| a.line <=> b.line }.each do |k|
- output_astnode_doc(k)
- end
+ ast.hostclasses.each do |name,k|
+ astobj << k if k.file == file
end
- def output_astnode_doc(ast)
- puts ast.doc if !ast.doc.nil? and !ast.doc.empty?
- if Puppet.settings[:document_all]
- # scan each underlying resources to produce documentation
- code = ast.code.children if ast.code.is_a?(Puppet::Parser::AST::ASTArray)
- code ||= ast.code
- output_resource_doc(code) unless code.nil?
- end
+ ast.definitions.each do |name, k|
+ astobj << k if k.file == file
+ end
+ astobj.sort! {|a,b| a.line <=> b.line }.each do |k|
+ output_astnode_doc(k)
+ end
+ end
+
+ def output_astnode_doc(ast)
+ puts ast.doc if !ast.doc.nil? and !ast.doc.empty?
+ if Puppet.settings[:document_all]
+ # scan each underlying resources to produce documentation
+ code = ast.code.children if ast.code.is_a?(Puppet::Parser::AST::ASTArray)
+ code ||= ast.code
+ output_resource_doc(code) unless code.nil?
end
+ end
- def output_resource_doc(code)
- code.sort { |a,b| a.line <=> b.line }.each do |stmt|
- output_resource_doc(stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
+ def output_resource_doc(code)
+ code.sort { |a,b| a.line <=> b.line }.each do |stmt|
+ output_resource_doc(stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
- if stmt.is_a?(Puppet::Parser::AST::Resource)
- puts stmt.doc if !stmt.doc.nil? and !stmt.doc.empty?
- end
- end
+ if stmt.is_a?(Puppet::Parser::AST::Resource)
+ puts stmt.doc if !stmt.doc.nil? and !stmt.doc.empty?
+ end
end
+ end
end \ No newline at end of file
diff --git a/lib/puppet/util/rdoc/code_objects.rb b/lib/puppet/util/rdoc/code_objects.rb
index 9ee26f47d..3854fbc01 100644
--- a/lib/puppet/util/rdoc/code_objects.rb
+++ b/lib/puppet/util/rdoc/code_objects.rb
@@ -2,240 +2,240 @@ require 'rdoc/code_objects'
module RDoc
- # This modules contains various class that are used to hold information
- # about the various Puppet language structures we found while parsing.
- #
- # Those will be mapped to their html counterparts which are defined in
- # PuppetGenerator.
-
- # PuppetTopLevel is a top level (usually a .pp/.rb file)
- class PuppetTopLevel < TopLevel
- attr_accessor :module_name, :global
-
- # will contain all plugins
- @@all_plugins = {}
-
- # contains all cutoms facts
- @@all_facts = {}
-
- def initialize(toplevel)
- super(toplevel.file_relative_name)
- end
-
- def self.all_plugins
- @@all_plugins.values
- end
-
- def self.all_facts
- @@all_facts.values
- end
- end
-
- # PuppetModule holds a Puppet Module
- # This is mapped to an HTMLPuppetModule
- # it leverage the RDoc (ruby) module infrastructure
- class PuppetModule < NormalModule
- attr_accessor :facts, :plugins
-
- def initialize(name,superclass=nil)
- @facts = []
- @plugins = []
- super(name,superclass)
- end
-
- def initialize_classes_and_modules
- super
- @nodes = {}
- end
-
- def add_plugin(plugin)
- add_to(@plugins, plugin)
- end
-
- def add_fact(fact)
- add_to(@facts, fact)
- end
-
- def add_node(name,superclass)
- cls = @nodes[name]
- unless cls
- cls = PuppetNode.new(name, superclass)
- @nodes[name] = cls if !@done_documenting
- cls.parent = self
- cls.section = @current_section
- end
- cls
- end
-
- def each_fact
- @facts.each {|c| yield c}
- end
-
- def each_plugin
- @plugins.each {|c| yield c}
- end
-
- def each_node
- @nodes.each {|c| yield c}
- end
-
- def nodes
- @nodes.values
- end
- end
-
- # PuppetClass holds a puppet class
- # It is mapped to a HTMLPuppetClass for display
- # It leverages RDoc (ruby) Class
- class PuppetClass < ClassModule
- attr_accessor :resource_list, :requires, :childs, :realizes
-
- def initialize(name, superclass)
- super(name,superclass)
- @resource_list = []
- @requires = []
- @realizes = []
- @childs = []
- end
-
- def add_resource(resource)
- add_to(@resource_list, resource)
- end
-
- def is_module?
- false
- end
-
- def superclass=(superclass)
- @superclass = superclass
- end
-
- # we're (ab)using the RDoc require system here.
- # we're adding a required Puppet class, overriding
- # the RDoc add_require method which sees ruby required files.
- def add_require(required)
- add_to(@requires, required)
- end
-
- def add_realize(realized)
- add_to(@realizes, realized)
- end
-
- def add_child(child)
- @childs << child
- end
- end
-
- # PuppetNode holds a puppet node
- # It is mapped to a HTMLPuppetNode for display
- # A node is just a variation of a class
- class PuppetNode < PuppetClass
- def initialize(name, superclass)
- super(name,superclass)
- end
-
- def is_module?
- false
- end
- end
-
- # Plugin holds a native puppet plugin (function,type...)
- # It is mapped to a HTMLPuppetPlugin for display
- class Plugin < Context
- attr_accessor :name, :type
-
- def initialize(name, type)
- super()
- @name = name
- @type = type
- @comment = ""
- end
-
- def <=>(other)
- @name <=> other.name
- end
-
- def full_name
- @name
- end
-
- def http_url(prefix)
- path = full_name.split("::")
- File.join(prefix, *path) + ".html"
- end
-
- def is_fact?
- false
- end
-
- def to_s
- res = self.class.name + ": #{@name} (#{@type})\n"
- res << @comment.to_s
- res
- end
- end
-
- # Fact holds a custom fact
- # It is mapped to a HTMLPuppetPlugin for display
- class Fact < Context
- attr_accessor :name, :confine
-
- def initialize(name, confine)
- super()
- @name = name
- @confine = confine
- @comment = ""
- end
-
- def <=>(other)
- @name <=> other.name
- end
-
- def is_fact?
- true
- end
-
- def full_name
- @name
- end
-
- def to_s
- res = self.class.name + ": #{@name}\n"
- res << @comment.to_s
- res
- end
- end
-
- # PuppetResource holds a puppet resource
- # It is mapped to a HTMLPuppetResource for display
- # A resource is defined by its "normal" form Type[title]
- class PuppetResource < CodeObject
- attr_accessor :type, :title, :params
-
- def initialize(type, title, comment, params)
- super()
- @type = type
- @title = title
- @comment = comment
- @params = params
- end
-
- def <=>(other)
- full_name <=> other.full_name
- end
-
- def full_name
- @type + "[#{@title}]"
- end
-
- def name
- full_name
- end
-
- def to_s
- res = @type + "[#{@title}]\n"
- res << @comment.to_s
- res
- end
+ # This modules contains various class that are used to hold information
+ # about the various Puppet language structures we found while parsing.
+ #
+ # Those will be mapped to their html counterparts which are defined in
+ # PuppetGenerator.
+
+ # PuppetTopLevel is a top level (usually a .pp/.rb file)
+ class PuppetTopLevel < TopLevel
+ attr_accessor :module_name, :global
+
+ # will contain all plugins
+ @@all_plugins = {}
+
+ # contains all cutoms facts
+ @@all_facts = {}
+
+ def initialize(toplevel)
+ super(toplevel.file_relative_name)
+ end
+
+ def self.all_plugins
+ @@all_plugins.values
+ end
+
+ def self.all_facts
+ @@all_facts.values
+ end
+ end
+
+ # PuppetModule holds a Puppet Module
+ # This is mapped to an HTMLPuppetModule
+ # it leverage the RDoc (ruby) module infrastructure
+ class PuppetModule < NormalModule
+ attr_accessor :facts, :plugins
+
+ def initialize(name,superclass=nil)
+ @facts = []
+ @plugins = []
+ super(name,superclass)
+ end
+
+ def initialize_classes_and_modules
+ super
+ @nodes = {}
+ end
+
+ def add_plugin(plugin)
+ add_to(@plugins, plugin)
+ end
+
+ def add_fact(fact)
+ add_to(@facts, fact)
+ end
+
+ def add_node(name,superclass)
+ cls = @nodes[name]
+ unless cls
+ cls = PuppetNode.new(name, superclass)
+ @nodes[name] = cls if !@done_documenting
+ cls.parent = self
+ cls.section = @current_section
+ end
+ cls
+ end
+
+ def each_fact
+ @facts.each {|c| yield c}
+ end
+
+ def each_plugin
+ @plugins.each {|c| yield c}
+ end
+
+ def each_node
+ @nodes.each {|c| yield c}
+ end
+
+ def nodes
+ @nodes.values
+ end
+ end
+
+ # PuppetClass holds a puppet class
+ # It is mapped to a HTMLPuppetClass for display
+ # It leverages RDoc (ruby) Class
+ class PuppetClass < ClassModule
+ attr_accessor :resource_list, :requires, :childs, :realizes
+
+ def initialize(name, superclass)
+ super(name,superclass)
+ @resource_list = []
+ @requires = []
+ @realizes = []
+ @childs = []
+ end
+
+ def add_resource(resource)
+ add_to(@resource_list, resource)
+ end
+
+ def is_module?
+ false
+ end
+
+ def superclass=(superclass)
+ @superclass = superclass
+ end
+
+ # we're (ab)using the RDoc require system here.
+ # we're adding a required Puppet class, overriding
+ # the RDoc add_require method which sees ruby required files.
+ def add_require(required)
+ add_to(@requires, required)
+ end
+
+ def add_realize(realized)
+ add_to(@realizes, realized)
+ end
+
+ def add_child(child)
+ @childs << child
+ end
+ end
+
+ # PuppetNode holds a puppet node
+ # It is mapped to a HTMLPuppetNode for display
+ # A node is just a variation of a class
+ class PuppetNode < PuppetClass
+ def initialize(name, superclass)
+ super(name,superclass)
+ end
+
+ def is_module?
+ false
+ end
+ end
+
+ # Plugin holds a native puppet plugin (function,type...)
+ # It is mapped to a HTMLPuppetPlugin for display
+ class Plugin < Context
+ attr_accessor :name, :type
+
+ def initialize(name, type)
+ super()
+ @name = name
+ @type = type
+ @comment = ""
+ end
+
+ def <=>(other)
+ @name <=> other.name
+ end
+
+ def full_name
+ @name
+ end
+
+ def http_url(prefix)
+ path = full_name.split("::")
+ File.join(prefix, *path) + ".html"
+ end
+
+ def is_fact?
+ false
+ end
+
+ def to_s
+ res = self.class.name + ": #{@name} (#{@type})\n"
+ res << @comment.to_s
+ res
+ end
+ end
+
+ # Fact holds a custom fact
+ # It is mapped to a HTMLPuppetPlugin for display
+ class Fact < Context
+ attr_accessor :name, :confine
+
+ def initialize(name, confine)
+ super()
+ @name = name
+ @confine = confine
+ @comment = ""
+ end
+
+ def <=>(other)
+ @name <=> other.name
+ end
+
+ def is_fact?
+ true
+ end
+
+ def full_name
+ @name
+ end
+
+ def to_s
+ res = self.class.name + ": #{@name}\n"
+ res << @comment.to_s
+ res
+ end
+ end
+
+ # PuppetResource holds a puppet resource
+ # It is mapped to a HTMLPuppetResource for display
+ # A resource is defined by its "normal" form Type[title]
+ class PuppetResource < CodeObject
+ attr_accessor :type, :title, :params
+
+ def initialize(type, title, comment, params)
+ super()
+ @type = type
+ @title = title
+ @comment = comment
+ @params = params
+ end
+
+ def <=>(other)
+ full_name <=> other.full_name
+ end
+
+ def full_name
+ @type + "[#{@title}]"
+ end
+
+ def name
+ full_name
+ end
+
+ def to_s
+ res = @type + "[#{@title}]\n"
+ res << @comment.to_s
+ res
end
+ end
end
diff --git a/lib/puppet/util/rdoc/generators/puppet_generator.rb b/lib/puppet/util/rdoc/generators/puppet_generator.rb
index 24579d6d9..9caeacd5e 100644
--- a/lib/puppet/util/rdoc/generators/puppet_generator.rb
+++ b/lib/puppet/util/rdoc/generators/puppet_generator.rb
@@ -4,884 +4,884 @@ require 'digest/md5'
module Generators
- # This module holds all the classes needed to generate the HTML documentation
- # of a bunch of puppet manifests.
- #
- # It works by traversing all the code objects defined by the Puppet RDoc::Parser
- # and produces HTML counterparts objects that in turns are used by RDoc template engine
- # to produce the final HTML.
- #
- # It is also responsible of creating the whole directory hierarchy, and various index
- # files.
- #
- # It is to be noted that the whole system is built on top of ruby RDoc. As such there
- # is an implicit mapping of puppet entities to ruby entitites:
- #
- # Puppet => Ruby
- # ------------------------
- # Module Module
- # Class Class
- # Definition Method
- # Resource
- # Node
- # Plugin
- # Fact
-
- MODULE_DIR = "modules"
- NODE_DIR = "nodes"
- PLUGIN_DIR = "plugins"
-
- # This is a specialized HTMLGenerator tailored to Puppet manifests
- class PuppetGenerator < HTMLGenerator
-
- def PuppetGenerator.for(options)
- AllReferences::reset
- HtmlMethod::reset
-
- if options.all_one_file
- PuppetGeneratorInOne.new(options)
- else
- PuppetGenerator.new(options)
- end
- end
+ # This module holds all the classes needed to generate the HTML documentation
+ # of a bunch of puppet manifests.
+ #
+ # It works by traversing all the code objects defined by the Puppet RDoc::Parser
+ # and produces HTML counterparts objects that in turns are used by RDoc template engine
+ # to produce the final HTML.
+ #
+ # It is also responsible of creating the whole directory hierarchy, and various index
+ # files.
+ #
+ # It is to be noted that the whole system is built on top of ruby RDoc. As such there
+ # is an implicit mapping of puppet entities to ruby entitites:
+ #
+ # Puppet => Ruby
+ # ------------------------
+ # Module Module
+ # Class Class
+ # Definition Method
+ # Resource
+ # Node
+ # Plugin
+ # Fact
+
+ MODULE_DIR = "modules"
+ NODE_DIR = "nodes"
+ PLUGIN_DIR = "plugins"
+
+ # This is a specialized HTMLGenerator tailored to Puppet manifests
+ class PuppetGenerator < HTMLGenerator
+
+ def PuppetGenerator.for(options)
+ AllReferences::reset
+ HtmlMethod::reset
+
+ if options.all_one_file
+ PuppetGeneratorInOne.new(options)
+ else
+ PuppetGenerator.new(options)
+ end
+ end
- def initialize(options) #:not-new:
- @options = options
- load_html_template
- end
+ def initialize(options) #:not-new:
+ @options = options
+ load_html_template
+ end
- # loads our own html template file
- def load_html_template
- require 'puppet/util/rdoc/generators/template/puppet/puppet'
- extend RDoc::Page
- rescue LoadError
- $stderr.puts "Could not find Puppet template '#{template}'"
- exit 99
- end
+ # loads our own html template file
+ def load_html_template
+ require 'puppet/util/rdoc/generators/template/puppet/puppet'
+ extend RDoc::Page
+ rescue LoadError
+ $stderr.puts "Could not find Puppet template '#{template}'"
+ exit 99
+ end
- def gen_method_index
- # we don't generate an all define index
- # as the presentation is per module/per class
- end
+ def gen_method_index
+ # we don't generate an all define index
+ # as the presentation is per module/per class
+ end
- # This is the central method, it generates the whole structures
- # along with all the indices.
- def generate_html
- super
- gen_into(@nodes)
- gen_into(@plugins)
- end
+ # This is the central method, it generates the whole structures
+ # along with all the indices.
+ def generate_html
+ super
+ gen_into(@nodes)
+ gen_into(@plugins)
+ end
- ##
- # Generate:
- # the list of modules
- # the list of classes and definitions of a specific module
- # the list of all classes
- # the list of nodes
- # the list of resources
- def build_indices
- @allfiles = []
- @nodes = []
- @plugins = []
-
- # contains all the seen modules
- @modules = {}
- @allclasses = {}
-
- # build the modules, classes and per modules classes and define list
- @toplevels.each do |toplevel|
- next unless toplevel.document_self
- file = HtmlFile.new(toplevel, @options, FILE_DIR)
- classes = []
- methods = []
- modules = []
- nodes = []
-
- # find all classes of this toplevel
- # store modules if we find one
- toplevel.each_classmodule do |k|
- generate_class_list(classes, modules, k, toplevel, CLASS_DIR)
- end
-
- # find all defines belonging to this toplevel
- HtmlMethod.all_methods.each do |m|
- # find parent module, check this method is not already
- # defined.
- if m.context.parent.toplevel === toplevel
- methods << m
- end
- end
-
- classes.each do |k|
- @allclasses[k.index_name] = k if !@allclasses.has_key?(k.index_name)
- end
-
- # generate nodes and plugins found
- classes.each do |k|
- if k.context.is_module?
- k.context.each_node do |name,node|
- nodes << HTMLPuppetNode.new(node, toplevel, NODE_DIR, @options)
- @nodes << nodes.last
- end
- k.context.each_plugin do |plugin|
- @plugins << HTMLPuppetPlugin.new(plugin, toplevel, PLUGIN_DIR, @options)
- end
- k.context.each_fact do |fact|
- @plugins << HTMLPuppetPlugin.new(fact, toplevel, PLUGIN_DIR, @options)
- end
- end
- end
-
- @files << file
- @allfiles << { "file" => file, "modules" => modules, "classes" => classes, "methods" => methods, "nodes" => nodes }
- end
+ ##
+ # Generate:
+ # the list of modules
+ # the list of classes and definitions of a specific module
+ # the list of all classes
+ # the list of nodes
+ # the list of resources
+ def build_indices
+ @allfiles = []
+ @nodes = []
+ @plugins = []
- # scan all classes to create the childs references
- @allclasses.values.each do |klass|
- if superklass = klass.context.superclass
- if superklass = AllReferences[superklass] and (superklass.is_a?(HTMLPuppetClass) or superklass.is_a?(HTMLPuppetNode))
- superklass.context.add_child(klass.context)
- end
- end
- end
+ # contains all the seen modules
+ @modules = {}
+ @allclasses = {}
- @classes = @allclasses.values
- end
+ # build the modules, classes and per modules classes and define list
+ @toplevels.each do |toplevel|
+ next unless toplevel.document_self
+ file = HtmlFile.new(toplevel, @options, FILE_DIR)
+ classes = []
+ methods = []
+ modules = []
+ nodes = []
- # produce a class/module list of HTMLPuppetModule/HTMLPuppetClass
- # based on the code object traversal.
- def generate_class_list(classes, modules, from, html_file, class_dir)
- if from.is_module? and !@modules.has_key?(from.name)
- k = HTMLPuppetModule.new(from, html_file, class_dir, @options)
- classes << k
- @modules[from.name] = k
- modules << @modules[from.name]
- elsif from.is_module?
- modules << @modules[from.name]
- elsif !from.is_module?
- k = HTMLPuppetClass.new(from, html_file, class_dir, @options)
- classes << k
- end
- from.each_classmodule do |mod|
- generate_class_list(classes, modules, mod, html_file, class_dir)
- end
+ # find all classes of this toplevel
+ # store modules if we find one
+ toplevel.each_classmodule do |k|
+ generate_class_list(classes, modules, k, toplevel, CLASS_DIR)
end
- # generate all the subdirectories, modules, classes and files
- def gen_sub_directories
- super
- File.makedirs(MODULE_DIR)
- File.makedirs(NODE_DIR)
- File.makedirs(PLUGIN_DIR)
- rescue
- $stderr.puts $ERROR_INFO.message
- exit 1
+ # find all defines belonging to this toplevel
+ HtmlMethod.all_methods.each do |m|
+ # find parent module, check this method is not already
+ # defined.
+ if m.context.parent.toplevel === toplevel
+ methods << m
+ end
end
- # generate the index of modules
- def gen_file_index
- gen_top_index(@modules.values, 'All Modules', RDoc::Page::TOP_INDEX, "fr_modules_index.html")
+ classes.each do |k|
+ @allclasses[k.index_name] = k if !@allclasses.has_key?(k.index_name)
end
- # generate a top index
- def gen_top_index(collection, title, template, filename)
- template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template)
- res = []
- collection.sort.each do |f|
- if f.document_self
- res << { "classlist" => CGI.escapeHTML("#{MODULE_DIR}/fr_#{f.index_name}.html"), "module" => CGI.escapeHTML("#{CLASS_DIR}/#{f.index_name}.html"),"name" => CGI.escapeHTML(f.index_name) }
- end
+ # generate nodes and plugins found
+ classes.each do |k|
+ if k.context.is_module?
+ k.context.each_node do |name,node|
+ nodes << HTMLPuppetNode.new(node, toplevel, NODE_DIR, @options)
+ @nodes << nodes.last
end
-
- values = {
- "entries" => res,
- 'list_title' => CGI.escapeHTML(title),
- 'index_url' => main_url,
- 'charset' => @options.charset,
- 'style_url' => style_url('', @options.css),
- }
-
- File.open(filename, "w") do |f|
- template.write_html_on(f, values)
+ k.context.each_plugin do |plugin|
+ @plugins << HTMLPuppetPlugin.new(plugin, toplevel, PLUGIN_DIR, @options)
end
- end
-
- # generate the all classes index file and the combo index
- def gen_class_index
- gen_an_index(@classes, 'All Classes', RDoc::Page::CLASS_INDEX, "fr_class_index.html")
- @allfiles.each do |file|
- unless file['file'].context.file_relative_name =~ /\.rb$/
-
- gen_composite_index(
- file,
- RDoc::Page::COMBO_INDEX,
-
- "#{MODULE_DIR}/fr_#{file["file"].context.module_name}.html")
- end
+ k.context.each_fact do |fact|
+ @plugins << HTMLPuppetPlugin.new(fact, toplevel, PLUGIN_DIR, @options)
end
+ end
end
- def gen_composite_index(collection, template, filename)\
- return if FileTest.exists?(filename)
+ @files << file
+ @allfiles << { "file" => file, "modules" => modules, "classes" => classes, "methods" => methods, "nodes" => nodes }
+ end
- template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template)
- res1 = []
- collection['classes'].sort.each do |f|
- if f.document_self
- res1 << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.index_name) } unless f.context.is_module?
- end
- end
-
- res2 = []
- collection['methods'].sort.each do |f|
- res2 << { "href" => "../#{f.path}", "name" => f.index_name.sub(/\(.*\)$/,'') } if f.document_self
- end
+ # scan all classes to create the childs references
+ @allclasses.values.each do |klass|
+ if superklass = klass.context.superclass
+ if superklass = AllReferences[superklass] and (superklass.is_a?(HTMLPuppetClass) or superklass.is_a?(HTMLPuppetNode))
+ superklass.context.add_child(klass.context)
+ end
+ end
+ end
- module_name = []
- res3 = []
- res4 = []
- collection['modules'].sort.each do |f|
- module_name << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.index_name) }
- unless f.facts.nil?
- f.facts.each do |fact|
- res3 << {"href" => "../"+CGI.escapeHTML(AllReferences["PLUGIN(#{fact.name})"].path), "name" => CGI.escapeHTML(fact.name)}
- end
- end
- unless f.plugins.nil?
- f.plugins.each do |plugin|
- res4 << {"href" => "../"+CGI.escapeHTML(AllReferences["PLUGIN(#{plugin.name})"].path), "name" => CGI.escapeHTML(plugin.name)}
- end
- end
- end
+ @classes = @allclasses.values
+ end
- res5 = []
- collection['nodes'].sort.each do |f|
- res5 << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.name) } if f.document_self
- end
+ # produce a class/module list of HTMLPuppetModule/HTMLPuppetClass
+ # based on the code object traversal.
+ def generate_class_list(classes, modules, from, html_file, class_dir)
+ if from.is_module? and !@modules.has_key?(from.name)
+ k = HTMLPuppetModule.new(from, html_file, class_dir, @options)
+ classes << k
+ @modules[from.name] = k
+ modules << @modules[from.name]
+ elsif from.is_module?
+ modules << @modules[from.name]
+ elsif !from.is_module?
+ k = HTMLPuppetClass.new(from, html_file, class_dir, @options)
+ classes << k
+ end
+ from.each_classmodule do |mod|
+ generate_class_list(classes, modules, mod, html_file, class_dir)
+ end
+ end
- values = {
- "module" => module_name,
- "classes" => res1,
- 'classes_title' => CGI.escapeHTML("Classes"),
- 'defines_title' => CGI.escapeHTML("Defines"),
- 'facts_title' => CGI.escapeHTML("Custom Facts"),
- 'plugins_title' => CGI.escapeHTML("Plugins"),
- 'nodes_title' => CGI.escapeHTML("Nodes"),
- 'index_url' => main_url,
- 'charset' => @options.charset,
- 'style_url' => style_url('', @options.css),
- }
-
- values["defines"] = res2 if res2.size>0
- values["facts"] = res3 if res3.size>0
- values["plugins"] = res4 if res4.size>0
- values["nodes"] = res5 if res5.size>0
-
- File.open(filename, "w") do |f|
- template.write_html_on(f, values)
- end
- end
+ # generate all the subdirectories, modules, classes and files
+ def gen_sub_directories
+ super
+ File.makedirs(MODULE_DIR)
+ File.makedirs(NODE_DIR)
+ File.makedirs(PLUGIN_DIR)
+ rescue
+ $stderr.puts $ERROR_INFO.message
+ exit 1
+ end
- # returns the initial_page url
- def main_url
- main_page = @options.main_page
- ref = nil
- if main_page
- ref = AllReferences[main_page]
- if ref
- ref = ref.path
- else
- $stderr.puts "Could not find main page #{main_page}"
- end
- end
+ # generate the index of modules
+ def gen_file_index
+ gen_top_index(@modules.values, 'All Modules', RDoc::Page::TOP_INDEX, "fr_modules_index.html")
+ end
- unless ref
- for file in @files
- if file.document_self and file.context.global
- ref = CGI.escapeHTML("#{CLASS_DIR}/#{file.context.module_name}.html")
- break
- end
- end
- end
+ # generate a top index
+ def gen_top_index(collection, title, template, filename)
+ template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template)
+ res = []
+ collection.sort.each do |f|
+ if f.document_self
+ res << { "classlist" => CGI.escapeHTML("#{MODULE_DIR}/fr_#{f.index_name}.html"), "module" => CGI.escapeHTML("#{CLASS_DIR}/#{f.index_name}.html"),"name" => CGI.escapeHTML(f.index_name) }
+ end
+ end
+
+ values = {
+ "entries" => res,
+ 'list_title' => CGI.escapeHTML(title),
+ 'index_url' => main_url,
+ 'charset' => @options.charset,
+ 'style_url' => style_url('', @options.css),
+ }
+
+ File.open(filename, "w") do |f|
+ template.write_html_on(f, values)
+ end
+ end
- unless ref
- for file in @files
- if file.document_self and !file.context.global
- ref = CGI.escapeHTML("#{CLASS_DIR}/#{file.context.module_name}.html")
- break
- end
- end
- end
+ # generate the all classes index file and the combo index
+ def gen_class_index
+ gen_an_index(@classes, 'All Classes', RDoc::Page::CLASS_INDEX, "fr_class_index.html")
+ @allfiles.each do |file|
+ unless file['file'].context.file_relative_name =~ /\.rb$/
- unless ref
- $stderr.puts "Couldn't find anything to document"
- $stderr.puts "Perhaps you've used :stopdoc: in all classes"
- exit(1)
- end
+ gen_composite_index(
+ file,
+ RDoc::Page::COMBO_INDEX,
- ref
+ "#{MODULE_DIR}/fr_#{file["file"].context.module_name}.html")
end
-
+ end
end
- # This module is used to generate a referenced full name list of ContextUser
- module ReferencedListBuilder
- def build_referenced_list(list)
- res = []
- list.each do |i|
- ref = AllReferences[i.name] || @context.find_symbol(i.name)
- ref = ref.viewer if ref and ref.respond_to?(:viewer)
- name = i.respond_to?(:full_name) ? i.full_name : i.name
- h_name = CGI.escapeHTML(name)
- if ref and ref.document_self
- path = url(ref.path)
- res << { "name" => h_name, "aref" => path }
- else
- res << { "name" => h_name }
- end
- end
- res
- end
+ def gen_composite_index(collection, template, filename)\
+ return if FileTest.exists?(filename)
+
+ template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template)
+ res1 = []
+ collection['classes'].sort.each do |f|
+ if f.document_self
+ res1 << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.index_name) } unless f.context.is_module?
+ end
+ end
+
+ res2 = []
+ collection['methods'].sort.each do |f|
+ res2 << { "href" => "../#{f.path}", "name" => f.index_name.sub(/\(.*\)$/,'') } if f.document_self
+ end
+
+ module_name = []
+ res3 = []
+ res4 = []
+ collection['modules'].sort.each do |f|
+ module_name << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.index_name) }
+ unless f.facts.nil?
+ f.facts.each do |fact|
+ res3 << {"href" => "../"+CGI.escapeHTML(AllReferences["PLUGIN(#{fact.name})"].path), "name" => CGI.escapeHTML(fact.name)}
+ end
+ end
+ unless f.plugins.nil?
+ f.plugins.each do |plugin|
+ res4 << {"href" => "../"+CGI.escapeHTML(AllReferences["PLUGIN(#{plugin.name})"].path), "name" => CGI.escapeHTML(plugin.name)}
+ end
+ end
+ end
+
+ res5 = []
+ collection['nodes'].sort.each do |f|
+ res5 << { "href" => "../"+CGI.escapeHTML(f.path), "name" => CGI.escapeHTML(f.name) } if f.document_self
+ end
+
+ values = {
+ "module" => module_name,
+ "classes" => res1,
+ 'classes_title' => CGI.escapeHTML("Classes"),
+ 'defines_title' => CGI.escapeHTML("Defines"),
+ 'facts_title' => CGI.escapeHTML("Custom Facts"),
+ 'plugins_title' => CGI.escapeHTML("Plugins"),
+ 'nodes_title' => CGI.escapeHTML("Nodes"),
+ 'index_url' => main_url,
+ 'charset' => @options.charset,
+ 'style_url' => style_url('', @options.css),
+ }
+
+ values["defines"] = res2 if res2.size>0
+ values["facts"] = res3 if res3.size>0
+ values["plugins"] = res4 if res4.size>0
+ values["nodes"] = res5 if res5.size>0
+
+ File.open(filename, "w") do |f|
+ template.write_html_on(f, values)
+ end
end
- # This module is used to hold/generate a list of puppet resources
- # this is used in HTMLPuppetClass and HTMLPuppetNode
- module ResourceContainer
- def collect_resources
- list = @context.resource_list
- @resources = list.collect {|m| HTMLPuppetResource.new(m, self, @options) }
- end
-
- def build_resource_summary_list(path_prefix='')
- collect_resources unless @resources
- resources = @resources.sort
- res = []
- resources.each do |r|
- res << {
- "name" => CGI.escapeHTML(r.name),
- "aref" => CGI.escape(path_prefix)+"\#"+CGI.escape(r.aref)
- }
- end
- res
- end
+ # returns the initial_page url
+ def main_url
+ main_page = @options.main_page
+ ref = nil
+ if main_page
+ ref = AllReferences[main_page]
+ if ref
+ ref = ref.path
+ else
+ $stderr.puts "Could not find main page #{main_page}"
+ end
+ end
+
+ unless ref
+ for file in @files
+ if file.document_self and file.context.global
+ ref = CGI.escapeHTML("#{CLASS_DIR}/#{file.context.module_name}.html")
+ break
+ end
+ end
+ end
+
+ unless ref
+ for file in @files
+ if file.document_self and !file.context.global
+ ref = CGI.escapeHTML("#{CLASS_DIR}/#{file.context.module_name}.html")
+ break
+ end
+ end
+ end
+
+ unless ref
+ $stderr.puts "Couldn't find anything to document"
+ $stderr.puts "Perhaps you've used :stopdoc: in all classes"
+ exit(1)
+ end
+
+ ref
+ end
- def build_resource_detail_list(section)
- outer = []
- resources = @resources.sort
- resources.each do |r|
- row = {}
- if r.section == section and r.document_self
- row["name"] = CGI.escapeHTML(r.name)
- desc = r.description.strip
- row["m_desc"] = desc unless desc.empty?
- row["aref"] = r.aref
- row["params"] = r.params
- outer << row
- end
- end
- outer
- end
+ end
+
+ # This module is used to generate a referenced full name list of ContextUser
+ module ReferencedListBuilder
+ def build_referenced_list(list)
+ res = []
+ list.each do |i|
+ ref = AllReferences[i.name] || @context.find_symbol(i.name)
+ ref = ref.viewer if ref and ref.respond_to?(:viewer)
+ name = i.respond_to?(:full_name) ? i.full_name : i.name
+ h_name = CGI.escapeHTML(name)
+ if ref and ref.document_self
+ path = url(ref.path)
+ res << { "name" => h_name, "aref" => path }
+ else
+ res << { "name" => h_name }
+ end
+ end
+ res
+ end
+ end
+
+ # This module is used to hold/generate a list of puppet resources
+ # this is used in HTMLPuppetClass and HTMLPuppetNode
+ module ResourceContainer
+ def collect_resources
+ list = @context.resource_list
+ @resources = list.collect {|m| HTMLPuppetResource.new(m, self, @options) }
end
- class HTMLPuppetClass < HtmlClass
- include ResourceContainer, ReferencedListBuilder
+ def build_resource_summary_list(path_prefix='')
+ collect_resources unless @resources
+ resources = @resources.sort
+ res = []
+ resources.each do |r|
+ res << {
+ "name" => CGI.escapeHTML(r.name),
+ "aref" => CGI.escape(path_prefix)+"\#"+CGI.escape(r.aref)
+ }
+ end
+ res
+ end
- def value_hash
- super
- rl = build_resource_summary_list
- @values["resources"] = rl unless rl.empty?
+ def build_resource_detail_list(section)
+ outer = []
+ resources = @resources.sort
+ resources.each do |r|
+ row = {}
+ if r.section == section and r.document_self
+ row["name"] = CGI.escapeHTML(r.name)
+ desc = r.description.strip
+ row["m_desc"] = desc unless desc.empty?
+ row["aref"] = r.aref
+ row["params"] = r.params
+ outer << row
+ end
+ end
+ outer
+ end
+ end
- @context.sections.each do |section|
- secdata = @values["sections"].select { |secdata| secdata["secsequence"] == section.sequence }
- if secdata.size == 1
- secdata = secdata[0]
+ class HTMLPuppetClass < HtmlClass
+ include ResourceContainer, ReferencedListBuilder
- rdl = build_resource_detail_list(section)
- secdata["resource_list"] = rdl unless rdl.empty?
- end
- end
+ def value_hash
+ super
+ rl = build_resource_summary_list
+ @values["resources"] = rl unless rl.empty?
- rl = build_require_list(@context)
- @values["requires"] = rl unless rl.empty?
+ @context.sections.each do |section|
+ secdata = @values["sections"].select { |secdata| secdata["secsequence"] == section.sequence }
+ if secdata.size == 1
+ secdata = secdata[0]
- rl = build_realize_list(@context)
- @values["realizes"] = rl unless rl.empty?
+ rdl = build_resource_detail_list(section)
+ secdata["resource_list"] = rdl unless rdl.empty?
+ end
+ end
- cl = build_child_list(@context)
- @values["childs"] = cl unless cl.empty?
+ rl = build_require_list(@context)
+ @values["requires"] = rl unless rl.empty?
- @values
- end
+ rl = build_realize_list(@context)
+ @values["realizes"] = rl unless rl.empty?
- def build_require_list(context)
- build_referenced_list(context.requires)
- end
+ cl = build_child_list(@context)
+ @values["childs"] = cl unless cl.empty?
- def build_realize_list(context)
- build_referenced_list(context.realizes)
- end
+ @values
+ end
- def build_child_list(context)
- build_referenced_list(context.childs)
- end
+ def build_require_list(context)
+ build_referenced_list(context.requires)
end
- class HTMLPuppetNode < ContextUser
- include ResourceContainer, ReferencedListBuilder
+ def build_realize_list(context)
+ build_referenced_list(context.realizes)
+ end
- attr_reader :path
+ def build_child_list(context)
+ build_referenced_list(context.childs)
+ end
+ end
- def initialize(context, html_file, prefix, options)
- super(context, options)
+ class HTMLPuppetNode < ContextUser
+ include ResourceContainer, ReferencedListBuilder
- @html_file = html_file
- @is_module = context.is_module?
- @values = {}
+ attr_reader :path
- context.viewer = self
+ def initialize(context, html_file, prefix, options)
+ super(context, options)
- if options.all_one_file
- @path = context.full_name
- else
- @path = http_url(context.full_name, prefix)
- end
+ @html_file = html_file
+ @is_module = context.is_module?
+ @values = {}
- AllReferences.add("NODE(#{@context.full_name})", self)
- end
+ context.viewer = self
- def name
- @context.name
- end
+ if options.all_one_file
+ @path = context.full_name
+ else
+ @path = http_url(context.full_name, prefix)
+ end
- # return the relative file name to store this class in,
- # which is also its url
- def http_url(full_name, prefix)
- path = full_name.dup
- path.gsub!(/<<\s*(\w*)/) { "from-#$1" } if path['<<']
- File.join(prefix, path.split("::").collect { |p| Digest::MD5.hexdigest(p) }) + ".html"
- end
+ AllReferences.add("NODE(#{@context.full_name})", self)
+ end
- def parent_name
- @context.parent.full_name
- end
+ def name
+ @context.name
+ end
- def index_name
- name
- end
+ # return the relative file name to store this class in,
+ # which is also its url
+ def http_url(full_name, prefix)
+ path = full_name.dup
+ path.gsub!(/<<\s*(\w*)/) { "from-#$1" } if path['<<']
+ File.join(prefix, path.split("::").collect { |p| Digest::MD5.hexdigest(p) }) + ".html"
+ end
- def write_on(f)
- value_hash
+ def parent_name
+ @context.parent.full_name
+ end
- template = TemplatePage.new(
- RDoc::Page::BODYINC,
- RDoc::Page::NODE_PAGE,
+ def index_name
+ name
+ end
- RDoc::Page::METHOD_LIST)
- template.write_html_on(f, @values)
- end
+ def write_on(f)
+ value_hash
- def value_hash
- class_attribute_values
- add_table_of_sections
+ template = TemplatePage.new(
+ RDoc::Page::BODYINC,
+ RDoc::Page::NODE_PAGE,
- @values["charset"] = @options.charset
- @values["style_url"] = style_url(path, @options.css)
+ RDoc::Page::METHOD_LIST)
+ template.write_html_on(f, @values)
+ end
- d = markup(@context.comment)
- @values["description"] = d unless d.empty?
+ def value_hash
+ class_attribute_values
+ add_table_of_sections
- ml = build_method_summary_list
- @values["methods"] = ml unless ml.empty?
+ @values["charset"] = @options.charset
+ @values["style_url"] = style_url(path, @options.css)
- rl = build_resource_summary_list
- @values["resources"] = rl unless rl.empty?
+ d = markup(@context.comment)
+ @values["description"] = d unless d.empty?
- il = build_include_list(@context)
- @values["includes"] = il unless il.empty?
+ ml = build_method_summary_list
+ @values["methods"] = ml unless ml.empty?
- rl = build_require_list(@context)
- @values["requires"] = rl unless rl.empty?
+ rl = build_resource_summary_list
+ @values["resources"] = rl unless rl.empty?
- rl = build_realize_list(@context)
- @values["realizes"] = rl unless rl.empty?
+ il = build_include_list(@context)
+ @values["includes"] = il unless il.empty?
- cl = build_child_list(@context)
- @values["childs"] = cl unless cl.empty?
+ rl = build_require_list(@context)
+ @values["requires"] = rl unless rl.empty?
- @values["sections"] = @context.sections.map do |section|
+ rl = build_realize_list(@context)
+ @values["realizes"] = rl unless rl.empty?
- secdata = {
- "sectitle" => section.title,
- "secsequence" => section.sequence,
- "seccomment" => markup(section.comment)
- }
+ cl = build_child_list(@context)
+ @values["childs"] = cl unless cl.empty?
- al = build_alias_summary_list(section)
- secdata["aliases"] = al unless al.empty?
+ @values["sections"] = @context.sections.map do |section|
- co = build_constants_summary_list(section)
- secdata["constants"] = co unless co.empty?
+ secdata = {
+ "sectitle" => section.title,
+ "secsequence" => section.sequence,
+ "seccomment" => markup(section.comment)
+ }
- al = build_attribute_list(section)
- secdata["attributes"] = al unless al.empty?
+ al = build_alias_summary_list(section)
+ secdata["aliases"] = al unless al.empty?
- cl = build_class_list(0, @context, section)
- secdata["classlist"] = cl unless cl.empty?
+ co = build_constants_summary_list(section)
+ secdata["constants"] = co unless co.empty?
- mdl = build_method_detail_list(section)
- secdata["method_list"] = mdl unless mdl.empty?
+ al = build_attribute_list(section)
+ secdata["attributes"] = al unless al.empty?
- rdl = build_resource_detail_list(section)
- secdata["resource_list"] = rdl unless rdl.empty?
+ cl = build_class_list(0, @context, section)
+ secdata["classlist"] = cl unless cl.empty?
- secdata
- end
+ mdl = build_method_detail_list(section)
+ secdata["method_list"] = mdl unless mdl.empty?
- @values
- end
+ rdl = build_resource_detail_list(section)
+ secdata["resource_list"] = rdl unless rdl.empty?
- def build_attribute_list(section)
- atts = @context.attributes.sort
- res = []
- atts.each do |att|
- next unless att.section == section
- if att.visibility == :public || att.visibility == :protected || @options.show_all
- entry = {
- "name" => CGI.escapeHTML(att.name),
- "rw" => att.rw,
- "a_desc" => markup(att.comment, true)
- }
- unless att.visibility == :public || att.visibility == :protected
- entry["rw"] << "-"
- end
- res << entry
- end
- end
- res
- end
+ secdata
+ end
- def class_attribute_values
- h_name = CGI.escapeHTML(name)
+ @values
+ end
- @values["classmod"] = "Node"
- @values["title"] = CGI.escapeHTML("#{@values['classmod']}: #{h_name}")
+ def build_attribute_list(section)
+ atts = @context.attributes.sort
+ res = []
+ atts.each do |att|
+ next unless att.section == section
+ if att.visibility == :public || att.visibility == :protected || @options.show_all
+ entry = {
+ "name" => CGI.escapeHTML(att.name),
+ "rw" => att.rw,
+ "a_desc" => markup(att.comment, true)
+ }
+ unless att.visibility == :public || att.visibility == :protected
+ entry["rw"] << "-"
+ end
+ res << entry
+ end
+ end
+ res
+ end
- c = @context
- c = c.parent while c and !c.diagram
+ def class_attribute_values
+ h_name = CGI.escapeHTML(name)
- @values["diagram"] = diagram_reference(c.diagram) if c && c.diagram
+ @values["classmod"] = "Node"
+ @values["title"] = CGI.escapeHTML("#{@values['classmod']}: #{h_name}")
- @values["full_name"] = h_name
+ c = @context
+ c = c.parent while c and !c.diagram
- parent_class = @context.superclass
+ @values["diagram"] = diagram_reference(c.diagram) if c && c.diagram
- if parent_class
- @values["parent"] = CGI.escapeHTML(parent_class)
+ @values["full_name"] = h_name
- if parent_name
- lookup = parent_name + "::#{parent_class}"
- else
- lookup = parent_class
- end
- lookup = "NODE(#{lookup})"
- parent_url = AllReferences[lookup] || AllReferences[parent_class]
- @values["par_url"] = aref_to(parent_url.path) if parent_url and parent_url.document_self
- end
+ parent_class = @context.superclass
- files = []
- @context.in_files.each do |f|
- res = {}
- full_path = CGI.escapeHTML(f.file_absolute_name)
+ if parent_class
+ @values["parent"] = CGI.escapeHTML(parent_class)
- res["full_path"] = full_path
- res["full_path_url"] = aref_to(f.viewer.path) if f.document_self
+ if parent_name
+ lookup = parent_name + "::#{parent_class}"
+ else
+ lookup = parent_class
+ end
+ lookup = "NODE(#{lookup})"
+ parent_url = AllReferences[lookup] || AllReferences[parent_class]
+ @values["par_url"] = aref_to(parent_url.path) if parent_url and parent_url.document_self
+ end
- res["cvsurl"] = cvs_url( @options.webcvs, full_path ) if @options.webcvs
+ files = []
+ @context.in_files.each do |f|
+ res = {}
+ full_path = CGI.escapeHTML(f.file_absolute_name)
- files << res
- end
+ res["full_path"] = full_path
+ res["full_path_url"] = aref_to(f.viewer.path) if f.document_self
- @values['infiles'] = files
- end
+ res["cvsurl"] = cvs_url( @options.webcvs, full_path ) if @options.webcvs
- def build_require_list(context)
- build_referenced_list(context.requires)
- end
+ files << res
+ end
- def build_realize_list(context)
- build_referenced_list(context.realizes)
- end
+ @values['infiles'] = files
+ end
- def build_child_list(context)
- build_referenced_list(context.childs)
- end
+ def build_require_list(context)
+ build_referenced_list(context.requires)
+ end
- def <=>(other)
- self.name <=> other.name
- end
+ def build_realize_list(context)
+ build_referenced_list(context.realizes)
end
- class HTMLPuppetModule < HtmlClass
+ def build_child_list(context)
+ build_referenced_list(context.childs)
+ end
- def initialize(context, html_file, prefix, options)
- super(context, html_file, prefix, options)
- end
+ def <=>(other)
+ self.name <=> other.name
+ end
+ end
- def value_hash
- @values = super
+ class HTMLPuppetModule < HtmlClass
- fl = build_facts_summary_list
- @values["facts"] = fl unless fl.empty?
+ def initialize(context, html_file, prefix, options)
+ super(context, html_file, prefix, options)
+ end
- pl = build_plugins_summary_list
- @values["plugins"] = pl unless pl.empty?
+ def value_hash
+ @values = super
- nl = build_nodes_list(0, @context)
- @values["nodelist"] = nl unless nl.empty?
+ fl = build_facts_summary_list
+ @values["facts"] = fl unless fl.empty?
- @values
- end
+ pl = build_plugins_summary_list
+ @values["plugins"] = pl unless pl.empty?
- def build_nodes_list(level, context)
- res = ""
- prefix = "&nbsp;&nbsp;::" * level;
-
- context.nodes.sort.each do |node|
- if node.document_self
- res <<
- prefix <<
- "Node " <<
- href(url(node.viewer.path), "link", node.full_name) <<
- "<br />\n"
- end
- end
- res
- end
+ nl = build_nodes_list(0, @context)
+ @values["nodelist"] = nl unless nl.empty?
- def build_facts_summary_list
- potentially_referenced_list(context.facts) {|fn| ["PLUGIN(#{fn})"] }
- end
+ @values
+ end
- def build_plugins_summary_list
- potentially_referenced_list(context.plugins) {|fn| ["PLUGIN(#{fn})"] }
- end
+ def build_nodes_list(level, context)
+ res = ""
+ prefix = "&nbsp;&nbsp;::" * level;
- def facts
- @context.facts
+ context.nodes.sort.each do |node|
+ if node.document_self
+ res <<
+ prefix <<
+ "Node " <<
+ href(url(node.viewer.path), "link", node.full_name) <<
+ "<br />\n"
end
+ end
+ res
+ end
- def plugins
- @context.plugins
- end
+ def build_facts_summary_list
+ potentially_referenced_list(context.facts) {|fn| ["PLUGIN(#{fn})"] }
+ end
+ def build_plugins_summary_list
+ potentially_referenced_list(context.plugins) {|fn| ["PLUGIN(#{fn})"] }
end
- class HTMLPuppetPlugin < ContextUser
- attr_reader :path
+ def facts
+ @context.facts
+ end
- def initialize(context, html_file, prefix, options)
- super(context, options)
+ def plugins
+ @context.plugins
+ end
- @html_file = html_file
- @is_module = false
- @values = {}
+ end
- context.viewer = self
+ class HTMLPuppetPlugin < ContextUser
+ attr_reader :path
- if options.all_one_file
- @path = context.full_name
- else
- @path = http_url(context.full_name, prefix)
- end
+ def initialize(context, html_file, prefix, options)
+ super(context, options)
- AllReferences.add("PLUGIN(#{@context.full_name})", self)
- end
+ @html_file = html_file
+ @is_module = false
+ @values = {}
- def name
- @context.name
- end
+ context.viewer = self
- # return the relative file name to store this class in,
- # which is also its url
- def http_url(full_name, prefix)
- path = full_name.dup
- path.gsub!(/<<\s*(\w*)/) { "from-#$1" } if path['<<']
- File.join(prefix, path.split("::")) + ".html"
- end
+ if options.all_one_file
+ @path = context.full_name
+ else
+ @path = http_url(context.full_name, prefix)
+ end
- def parent_name
- @context.parent.full_name
- end
+ AllReferences.add("PLUGIN(#{@context.full_name})", self)
+ end
- def index_name
- name
- end
+ def name
+ @context.name
+ end
- def write_on(f)
- value_hash
+ # return the relative file name to store this class in,
+ # which is also its url
+ def http_url(full_name, prefix)
+ path = full_name.dup
+ path.gsub!(/<<\s*(\w*)/) { "from-#$1" } if path['<<']
+ File.join(prefix, path.split("::")) + ".html"
+ end
- template = TemplatePage.new(
- RDoc::Page::BODYINC,
- RDoc::Page::PLUGIN_PAGE,
+ def parent_name
+ @context.parent.full_name
+ end
- RDoc::Page::PLUGIN_LIST)
- template.write_html_on(f, @values)
- end
+ def index_name
+ name
+ end
- def value_hash
- attribute_values
- add_table_of_sections
-
- @values["charset"] = @options.charset
- @values["style_url"] = style_url(path, @options.css)
-
- d = markup(@context.comment)
- @values["description"] = d unless d.empty?
-
- if context.is_fact?
- unless context.confine.empty?
- res = {}
- res["type"] = context.confine[:type]
- res["value"] = context.confine[:value]
- @values["confine"] = [res]
- end
- else
- @values["type"] = context.type
- end
+ def write_on(f)
+ value_hash
- @values["sections"] = @context.sections.map do |section|
- secdata = {
- "sectitle" => section.title,
- "secsequence" => section.sequence,
- "seccomment" => markup(section.comment)
- }
- secdata
- end
+ template = TemplatePage.new(
+ RDoc::Page::BODYINC,
+ RDoc::Page::PLUGIN_PAGE,
- @values
- end
+ RDoc::Page::PLUGIN_LIST)
+ template.write_html_on(f, @values)
+ end
- def attribute_values
- h_name = CGI.escapeHTML(name)
+ def value_hash
+ attribute_values
+ add_table_of_sections
+
+ @values["charset"] = @options.charset
+ @values["style_url"] = style_url(path, @options.css)
+
+ d = markup(@context.comment)
+ @values["description"] = d unless d.empty?
+
+ if context.is_fact?
+ unless context.confine.empty?
+ res = {}
+ res["type"] = context.confine[:type]
+ res["value"] = context.confine[:value]
+ @values["confine"] = [res]
+ end
+ else
+ @values["type"] = context.type
+ end
+
+ @values["sections"] = @context.sections.map do |section|
+ secdata = {
+ "sectitle" => section.title,
+ "secsequence" => section.sequence,
+ "seccomment" => markup(section.comment)
+ }
+ secdata
+ end
+
+ @values
+ end
- if @context.is_fact?
- @values["classmod"] = "Fact"
- else
- @values["classmod"] = "Plugin"
- end
- @values["title"] = "#{@values['classmod']}: #{h_name}"
+ def attribute_values
+ h_name = CGI.escapeHTML(name)
- c = @context
- @values["full_name"] = h_name
+ if @context.is_fact?
+ @values["classmod"] = "Fact"
+ else
+ @values["classmod"] = "Plugin"
+ end
+ @values["title"] = "#{@values['classmod']}: #{h_name}"
- files = []
- @context.in_files.each do |f|
- res = {}
- full_path = CGI.escapeHTML(f.file_absolute_name)
+ c = @context
+ @values["full_name"] = h_name
- res["full_path"] = full_path
- res["full_path_url"] = aref_to(f.viewer.path) if f.document_self
+ files = []
+ @context.in_files.each do |f|
+ res = {}
+ full_path = CGI.escapeHTML(f.file_absolute_name)
- res["cvsurl"] = cvs_url( @options.webcvs, full_path ) if @options.webcvs
+ res["full_path"] = full_path
+ res["full_path_url"] = aref_to(f.viewer.path) if f.document_self
- files << res
- end
+ res["cvsurl"] = cvs_url( @options.webcvs, full_path ) if @options.webcvs
- @values['infiles'] = files
- end
+ files << res
+ end
- def <=>(other)
- self.name <=> other.name
- end
+ @values['infiles'] = files
+ end
+ def <=>(other)
+ self.name <=> other.name
end
- class HTMLPuppetResource
- include MarkUp
+ end
- attr_reader :context
+ class HTMLPuppetResource
+ include MarkUp
- @@seq = "R000000"
+ attr_reader :context
- def initialize(context, html_class, options)
- @context = context
- @html_class = html_class
- @options = options
- @@seq = @@seq.succ
- @seq = @@seq
+ @@seq = "R000000"
- context.viewer = self
+ def initialize(context, html_class, options)
+ @context = context
+ @html_class = html_class
+ @options = options
+ @@seq = @@seq.succ
+ @seq = @@seq
- AllReferences.add(name, self)
- end
+ context.viewer = self
- def as_href(from_path)
- if @options.all_one_file
- "##{path}"
- else
- HTMLGenerator.gen_url(from_path, path)
- end
- end
+ AllReferences.add(name, self)
+ end
- def name
- @context.name
- end
+ def as_href(from_path)
+ if @options.all_one_file
+ "##{path}"
+ else
+ HTMLGenerator.gen_url(from_path, path)
+ end
+ end
- def section
- @context.section
- end
+ def name
+ @context.name
+ end
- def index_name
- "#{@context.name}"
- end
+ def section
+ @context.section
+ end
- def params
- @context.params
- end
+ def index_name
+ "#{@context.name}"
+ end
- def parent_name
- if @context.parent.parent
- @context.parent.parent.full_name
- else
- nil
- end
- end
+ def params
+ @context.params
+ end
- def aref
- @seq
- end
+ def parent_name
+ if @context.parent.parent
+ @context.parent.parent.full_name
+ else
+ nil
+ end
+ end
- def path
- if @options.all_one_file
- aref
- else
- @html_class.path + "##{aref}"
- end
- end
+ def aref
+ @seq
+ end
- def description
- markup(@context.comment)
- end
+ def path
+ if @options.all_one_file
+ aref
+ else
+ @html_class.path + "##{aref}"
+ end
+ end
- def <=>(other)
- @context <=> other.context
- end
+ def description
+ markup(@context.comment)
+ end
- def document_self
- @context.document_self
- end
+ def <=>(other)
+ @context <=> other.context
+ end
- def find_symbol(symbol, method=nil)
- res = @context.parent.find_symbol(symbol, method)
- res &&= res.viewer
- end
+ def document_self
+ @context.document_self
+ end
+ def find_symbol(symbol, method=nil)
+ res = @context.parent.find_symbol(symbol, method)
+ res &&= res.viewer
end
- class PuppetGeneratorInOne < HTMLGeneratorInOne
- def gen_method_index
- gen_an_index(HtmlMethod.all_methods, 'Defines')
- end
+ end
+
+ class PuppetGeneratorInOne < HTMLGeneratorInOne
+ def gen_method_index
+ gen_an_index(HtmlMethod.all_methods, 'Defines')
end
+ end
end
diff --git a/lib/puppet/util/rdoc/parser.rb b/lib/puppet/util/rdoc/parser.rb
index b0ff98834..573d1766f 100644
--- a/lib/puppet/util/rdoc/parser.rb
+++ b/lib/puppet/util/rdoc/parser.rb
@@ -13,463 +13,463 @@ require "rdoc/parsers/parserfactory"
module RDoc
class Parser
- extend ParserFactory
-
- attr_accessor :ast, :input_file_name, :top_level
-
- # parser registration into RDoc
- parse_files_matching(/\.(rb|pp)$/)
-
- # called with the top level file
- def initialize(top_level, file_name, content, options, stats)
- @options = options
- @stats = stats
- @input_file_name = file_name
- @top_level = PuppetTopLevel.new(top_level)
- @progress = $stderr unless options.quiet
+ extend ParserFactory
+
+ attr_accessor :ast, :input_file_name, :top_level
+
+ # parser registration into RDoc
+ parse_files_matching(/\.(rb|pp)$/)
+
+ # called with the top level file
+ def initialize(top_level, file_name, content, options, stats)
+ @options = options
+ @stats = stats
+ @input_file_name = file_name
+ @top_level = PuppetTopLevel.new(top_level)
+ @progress = $stderr unless options.quiet
+ end
+
+ # main entry point
+ def scan
+ Puppet.info "rdoc: scanning #{@input_file_name}"
+ if @input_file_name =~ /\.pp$/
+ @parser = Puppet::Parser::Parser.new(Puppet[:environment])
+ @parser.file = @input_file_name
+ @ast = @parser.parse
end
-
- # main entry point
- def scan
- Puppet.info "rdoc: scanning #{@input_file_name}"
- if @input_file_name =~ /\.pp$/
- @parser = Puppet::Parser::Parser.new(Puppet[:environment])
- @parser.file = @input_file_name
- @ast = @parser.parse
- end
- scan_top_level(@top_level)
- @top_level
+ scan_top_level(@top_level)
+ @top_level
+ end
+
+ # Due to a bug in RDoc, we need to roll our own find_module_named
+ # The issue is that RDoc tries harder by asking the parent for a class/module
+ # of the name. But by doing so, it can mistakenly use a module of same name
+ # but from which we are not descendant.
+ def find_object_named(container, name)
+ return container if container.name == name
+ container.each_classmodule do |m|
+ return m if m.name == name
end
+ nil
+ end
- # Due to a bug in RDoc, we need to roll our own find_module_named
- # The issue is that RDoc tries harder by asking the parent for a class/module
- # of the name. But by doing so, it can mistakenly use a module of same name
- # but from which we are not descendant.
- def find_object_named(container, name)
- return container if container.name == name
- container.each_classmodule do |m|
- return m if m.name == name
- end
- nil
- end
-
- # walk down the namespace and lookup/create container as needed
- def get_class_or_module(container, name)
+ # walk down the namespace and lookup/create container as needed
+ def get_class_or_module(container, name)
- # class ::A -> A is in the top level
- if name =~ /^::/
- container = @top_level
- end
+ # class ::A -> A is in the top level
+ if name =~ /^::/
+ container = @top_level
+ end
- names = name.split('::')
+ names = name.split('::')
- final_name = names.pop
- names.each do |name|
- prev_container = container
- container = find_object_named(container, name)
- container ||= prev_container.add_class(PuppetClass, name, nil)
- end
- [container, final_name]
+ final_name = names.pop
+ names.each do |name|
+ prev_container = container
+ container = find_object_named(container, name)
+ container ||= prev_container.add_class(PuppetClass, name, nil)
end
-
- # split_module tries to find if +path+ belongs to the module path
- # if it does, it returns the module name, otherwise if we are sure
- # it is part of the global manifest path, "<site>" is returned.
- # And finally if this path couldn't be mapped anywhere, nil is returned.
- def split_module(path)
- # find a module
- fullpath = File.expand_path(path)
- Puppet.debug "rdoc: testing #{fullpath}"
- if fullpath =~ /(.*)\/([^\/]+)\/(?:manifests|plugins|lib)\/.+\.(pp|rb)$/
- modpath = $1
- name = $2
- Puppet.debug "rdoc: module #{name} into #{modpath} ?"
- Puppet::Module.modulepath.each do |mp|
- if File.identical?(modpath,mp)
- Puppet.debug "rdoc: found module #{name}"
- return name
- end
- end
- end
- if fullpath =~ /\.(pp|rb)$/
- # there can be paths we don't want to scan under modules
- # imagine a ruby or manifest that would be distributed as part as a module
- # but we don't want those to be hosted under <site>
- Puppet::Module.modulepath.each do |mp|
- # check that fullpath is a descendant of mp
- dirname = fullpath
- while (dirname = File.dirname(dirname)) != '/'
- return nil if File.identical?(dirname,mp)
- end
- end
+ [container, final_name]
+ end
+
+ # split_module tries to find if +path+ belongs to the module path
+ # if it does, it returns the module name, otherwise if we are sure
+ # it is part of the global manifest path, "<site>" is returned.
+ # And finally if this path couldn't be mapped anywhere, nil is returned.
+ def split_module(path)
+ # find a module
+ fullpath = File.expand_path(path)
+ Puppet.debug "rdoc: testing #{fullpath}"
+ if fullpath =~ /(.*)\/([^\/]+)\/(?:manifests|plugins|lib)\/.+\.(pp|rb)$/
+ modpath = $1
+ name = $2
+ Puppet.debug "rdoc: module #{name} into #{modpath} ?"
+ Puppet::Module.modulepath.each do |mp|
+ if File.identical?(modpath,mp)
+ Puppet.debug "rdoc: found module #{name}"
+ return name
end
- # we are under a global manifests
- Puppet.debug "rdoc: global manifests"
- "<site>"
+ end
end
-
- # create documentation for the top level +container+
- def scan_top_level(container)
- # use the module README as documentation for the module
- comment = ""
- readme = File.join(File.dirname(File.dirname(@input_file_name)), "README")
- comment = File.open(readme,"r") { |f| f.read } if FileTest.readable?(readme)
- look_for_directives_in(container, comment) unless comment.empty?
-
- # infer module name from directory
- name = split_module(@input_file_name)
- if name.nil?
- # skip .pp files that are not in manifests directories as we can't guarantee they're part
- # of a module or the global configuration.
- container.document_self = false
- return
+ if fullpath =~ /\.(pp|rb)$/
+ # there can be paths we don't want to scan under modules
+ # imagine a ruby or manifest that would be distributed as part as a module
+ # but we don't want those to be hosted under <site>
+ Puppet::Module.modulepath.each do |mp|
+ # check that fullpath is a descendant of mp
+ dirname = fullpath
+ while (dirname = File.dirname(dirname)) != '/'
+ return nil if File.identical?(dirname,mp)
end
+ end
+ end
+ # we are under a global manifests
+ Puppet.debug "rdoc: global manifests"
+ "<site>"
+ end
+
+ # create documentation for the top level +container+
+ def scan_top_level(container)
+ # use the module README as documentation for the module
+ comment = ""
+ readme = File.join(File.dirname(File.dirname(@input_file_name)), "README")
+ comment = File.open(readme,"r") { |f| f.read } if FileTest.readable?(readme)
+ look_for_directives_in(container, comment) unless comment.empty?
+
+ # infer module name from directory
+ name = split_module(@input_file_name)
+ if name.nil?
+ # skip .pp files that are not in manifests directories as we can't guarantee they're part
+ # of a module or the global configuration.
+ container.document_self = false
+ return
+ end
- Puppet.debug "rdoc: scanning for #{name}"
+ Puppet.debug "rdoc: scanning for #{name}"
- container.module_name = name
- container.global=true if name == "<site>"
+ container.module_name = name
+ container.global=true if name == "<site>"
- @stats.num_modules += 1
- container, name = get_class_or_module(container,name)
- mod = container.add_module(PuppetModule, name)
- mod.record_location(@top_level)
- mod.comment = comment
+ @stats.num_modules += 1
+ container, name = get_class_or_module(container,name)
+ mod = container.add_module(PuppetModule, name)
+ mod.record_location(@top_level)
+ mod.comment = comment
- if @input_file_name =~ /\.pp$/
- parse_elements(mod)
- elsif @input_file_name =~ /\.rb$/
- parse_plugins(mod)
- end
+ if @input_file_name =~ /\.pp$/
+ parse_elements(mod)
+ elsif @input_file_name =~ /\.rb$/
+ parse_plugins(mod)
end
-
- # create documentation for include statements we can find in +code+
- # and associate it with +container+
- def scan_for_include_or_require(container, code)
- code = [code] unless code.is_a?(Array)
- code.each do |stmt|
- scan_for_include_or_require(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
-
- if stmt.is_a?(Puppet::Parser::AST::Function) and ['include','require'].include?(stmt.name)
- stmt.arguments.each do |included|
- Puppet.debug "found #{stmt.name}: #{included.value}"
- container.send("add_#{stmt.name}",Include.new(included.value, stmt.doc))
- end
- end
+ end
+
+ # create documentation for include statements we can find in +code+
+ # and associate it with +container+
+ def scan_for_include_or_require(container, code)
+ code = [code] unless code.is_a?(Array)
+ code.each do |stmt|
+ scan_for_include_or_require(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
+
+ if stmt.is_a?(Puppet::Parser::AST::Function) and ['include','require'].include?(stmt.name)
+ stmt.arguments.each do |included|
+ Puppet.debug "found #{stmt.name}: #{included.value}"
+ container.send("add_#{stmt.name}",Include.new(included.value, stmt.doc))
end
+ end
end
-
- # create documentation for realize statements we can find in +code+
- # and associate it with +container+
- def scan_for_realize(container, code)
- code = [code] unless code.is_a?(Array)
- code.each do |stmt|
- scan_for_realize(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
-
- if stmt.is_a?(Puppet::Parser::AST::Function) and stmt.name == 'realize'
- stmt.arguments.each do |realized|
- Puppet.debug "found #{stmt.name}: #{realized}"
- container.add_realize(Include.new(realized.to_s, stmt.doc))
- end
- end
+ end
+
+ # create documentation for realize statements we can find in +code+
+ # and associate it with +container+
+ def scan_for_realize(container, code)
+ code = [code] unless code.is_a?(Array)
+ code.each do |stmt|
+ scan_for_realize(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
+
+ if stmt.is_a?(Puppet::Parser::AST::Function) and stmt.name == 'realize'
+ stmt.arguments.each do |realized|
+ Puppet.debug "found #{stmt.name}: #{realized}"
+ container.add_realize(Include.new(realized.to_s, stmt.doc))
end
+ end
end
-
- # create documentation for global variables assignements we can find in +code+
- # and associate it with +container+
- def scan_for_vardef(container, code)
- code = [code] unless code.is_a?(Array)
- code.each do |stmt|
- scan_for_vardef(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
-
- if stmt.is_a?(Puppet::Parser::AST::VarDef)
- Puppet.debug "rdoc: found constant: #{stmt.name} = #{stmt.value}"
- container.add_constant(Constant.new(stmt.name.to_s, stmt.value.to_s, stmt.doc))
- end
- end
+ end
+
+ # create documentation for global variables assignements we can find in +code+
+ # and associate it with +container+
+ def scan_for_vardef(container, code)
+ code = [code] unless code.is_a?(Array)
+ code.each do |stmt|
+ scan_for_vardef(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
+
+ if stmt.is_a?(Puppet::Parser::AST::VarDef)
+ Puppet.debug "rdoc: found constant: #{stmt.name} = #{stmt.value}"
+ container.add_constant(Constant.new(stmt.name.to_s, stmt.value.to_s, stmt.doc))
+ end
end
-
- # create documentation for resources we can find in +code+
- # and associate it with +container+
- def scan_for_resource(container, code)
- code = [code] unless code.is_a?(Array)
- code.each do |stmt|
- scan_for_resource(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
-
- if stmt.is_a?(Puppet::Parser::AST::Resource) and !stmt.type.nil?
- begin
- type = stmt.type.split("::").collect { |s| s.capitalize }.join("::")
- title = stmt.title.is_a?(Puppet::Parser::AST::ASTArray) ? stmt.title.to_s.gsub(/\[(.*)\]/,'\1') : stmt.title.to_s
- Puppet.debug "rdoc: found resource: #{type}[#{title}]"
-
- param = []
- stmt.params.children.each do |p|
- res = {}
- res["name"] = p.param
- res["value"] = "#{p.value.to_s}" unless p.value.nil?
-
- param << res
- end
-
- container.add_resource(PuppetResource.new(type, title, stmt.doc, param))
- rescue => detail
- raise Puppet::ParseError, "impossible to parse resource in #{stmt.file} at line #{stmt.line}: #{detail}"
- end
- end
+ end
+
+ # create documentation for resources we can find in +code+
+ # and associate it with +container+
+ def scan_for_resource(container, code)
+ code = [code] unless code.is_a?(Array)
+ code.each do |stmt|
+ scan_for_resource(container,stmt.children) if stmt.is_a?(Puppet::Parser::AST::ASTArray)
+
+ if stmt.is_a?(Puppet::Parser::AST::Resource) and !stmt.type.nil?
+ begin
+ type = stmt.type.split("::").collect { |s| s.capitalize }.join("::")
+ title = stmt.title.is_a?(Puppet::Parser::AST::ASTArray) ? stmt.title.to_s.gsub(/\[(.*)\]/,'\1') : stmt.title.to_s
+ Puppet.debug "rdoc: found resource: #{type}[#{title}]"
+
+ param = []
+ stmt.params.children.each do |p|
+ res = {}
+ res["name"] = p.param
+ res["value"] = "#{p.value.to_s}" unless p.value.nil?
+
+ param << res
+ end
+
+ container.add_resource(PuppetResource.new(type, title, stmt.doc, param))
+ rescue => detail
+ raise Puppet::ParseError, "impossible to parse resource in #{stmt.file} at line #{stmt.line}: #{detail}"
end
+ end
end
+ end
- def resource_stmt_to_ref(stmt)
- type = stmt.type.split("::").collect { |s| s.capitalize }.join("::")
- title = stmt.title.is_a?(Puppet::Parser::AST::ASTArray) ? stmt.title.to_s.gsub(/\[(.*)\]/,'\1') : stmt.title.to_s
+ def resource_stmt_to_ref(stmt)
+ type = stmt.type.split("::").collect { |s| s.capitalize }.join("::")
+ title = stmt.title.is_a?(Puppet::Parser::AST::ASTArray) ? stmt.title.to_s.gsub(/\[(.*)\]/,'\1') : stmt.title.to_s
- param = stmt.params.children.collect do |p|
- {"name" => p.param, "value" => p.value.to_s}
- end
- PuppetResource.new(type, title, stmt.doc, param)
+ param = stmt.params.children.collect do |p|
+ {"name" => p.param, "value" => p.value.to_s}
end
-
- # create documentation for a class named +name+
- def document_class(name, klass, container)
- Puppet.debug "rdoc: found new class #{name}"
- container, name = get_class_or_module(container, name)
-
- superclass = klass.parent
- superclass = "" if superclass.nil? or superclass.empty?
-
- @stats.num_classes += 1
- comment = klass.doc
- look_for_directives_in(container, comment) unless comment.empty?
- cls = container.add_class(PuppetClass, name, superclass)
- # it is possible we already encountered this class, while parsing some namespaces
- # from other classes of other files. But at that time we couldn't know this class superclass
- # so, now we know it and force it.
- cls.superclass = superclass
- cls.record_location(@top_level)
-
- # scan class code for include
- code = klass.code.children if klass.code.is_a?(Puppet::Parser::AST::ASTArray)
- code ||= klass.code
- unless code.nil?
- scan_for_include_or_require(cls, code)
- scan_for_realize(cls, code)
- scan_for_resource(cls, code) if Puppet.settings[:document_all]
- end
-
- cls.comment = comment
- rescue => detail
- raise Puppet::ParseError, "impossible to parse class '#{name}' in #{klass.file} at line #{klass.line}: #{detail}"
+ PuppetResource.new(type, title, stmt.doc, param)
+ end
+
+ # create documentation for a class named +name+
+ def document_class(name, klass, container)
+ Puppet.debug "rdoc: found new class #{name}"
+ container, name = get_class_or_module(container, name)
+
+ superclass = klass.parent
+ superclass = "" if superclass.nil? or superclass.empty?
+
+ @stats.num_classes += 1
+ comment = klass.doc
+ look_for_directives_in(container, comment) unless comment.empty?
+ cls = container.add_class(PuppetClass, name, superclass)
+ # it is possible we already encountered this class, while parsing some namespaces
+ # from other classes of other files. But at that time we couldn't know this class superclass
+ # so, now we know it and force it.
+ cls.superclass = superclass
+ cls.record_location(@top_level)
+
+ # scan class code for include
+ code = klass.code.children if klass.code.is_a?(Puppet::Parser::AST::ASTArray)
+ code ||= klass.code
+ unless code.nil?
+ scan_for_include_or_require(cls, code)
+ scan_for_realize(cls, code)
+ scan_for_resource(cls, code) if Puppet.settings[:document_all]
end
- # create documentation for a node
- def document_node(name, node, container)
- Puppet.debug "rdoc: found new node #{name}"
- superclass = node.parent
- superclass = "" if superclass.nil? or superclass.empty?
-
- comment = node.doc
- look_for_directives_in(container, comment) unless comment.empty?
- n = container.add_node(name, superclass)
- n.record_location(@top_level)
-
- code = node.code.children if node.code.is_a?(Puppet::Parser::AST::ASTArray)
- code ||= node.code
- unless code.nil?
- scan_for_include_or_require(n, code)
- scan_for_realize(n, code)
- scan_for_vardef(n, code)
- scan_for_resource(n, code) if Puppet.settings[:document_all]
- end
-
- n.comment = comment
- rescue => detail
- raise Puppet::ParseError, "impossible to parse node '#{name}' in #{node.file} at line #{node.line}: #{detail}"
+ cls.comment = comment
+ rescue => detail
+ raise Puppet::ParseError, "impossible to parse class '#{name}' in #{klass.file} at line #{klass.line}: #{detail}"
+ end
+
+ # create documentation for a node
+ def document_node(name, node, container)
+ Puppet.debug "rdoc: found new node #{name}"
+ superclass = node.parent
+ superclass = "" if superclass.nil? or superclass.empty?
+
+ comment = node.doc
+ look_for_directives_in(container, comment) unless comment.empty?
+ n = container.add_node(name, superclass)
+ n.record_location(@top_level)
+
+ code = node.code.children if node.code.is_a?(Puppet::Parser::AST::ASTArray)
+ code ||= node.code
+ unless code.nil?
+ scan_for_include_or_require(n, code)
+ scan_for_realize(n, code)
+ scan_for_vardef(n, code)
+ scan_for_resource(n, code) if Puppet.settings[:document_all]
end
- # create documentation for a define
- def document_define(name, define, container)
- Puppet.debug "rdoc: found new definition #{name}"
- # find superclas if any
- @stats.num_methods += 1
-
- # find the parent
- # split define name by :: to find the complete module hierarchy
- container, name = get_class_or_module(container,name)
-
- # build up declaration
- declaration = ""
- define.arguments.each do |arg,value|
- declaration << "\$#{arg}"
- unless value.nil?
- declaration << " => "
- case value
- when Puppet::Parser::AST::Leaf
- declaration << "'#{value.value}'"
- when Puppet::Parser::AST::ASTArray
- declaration << "[#{value.children.collect { |v| "'#{v}'" }.join(", ")}]"
- else
- declaration << "#{value.to_s}"
- end
- end
- declaration << ", "
+ n.comment = comment
+ rescue => detail
+ raise Puppet::ParseError, "impossible to parse node '#{name}' in #{node.file} at line #{node.line}: #{detail}"
+ end
+
+ # create documentation for a define
+ def document_define(name, define, container)
+ Puppet.debug "rdoc: found new definition #{name}"
+ # find superclas if any
+ @stats.num_methods += 1
+
+ # find the parent
+ # split define name by :: to find the complete module hierarchy
+ container, name = get_class_or_module(container,name)
+
+ # build up declaration
+ declaration = ""
+ define.arguments.each do |arg,value|
+ declaration << "\$#{arg}"
+ unless value.nil?
+ declaration << " => "
+ case value
+ when Puppet::Parser::AST::Leaf
+ declaration << "'#{value.value}'"
+ when Puppet::Parser::AST::ASTArray
+ declaration << "[#{value.children.collect { |v| "'#{v}'" }.join(", ")}]"
+ else
+ declaration << "#{value.to_s}"
end
- declaration.chop!.chop! if declaration.size > 1
-
- # register method into the container
- meth = AnyMethod.new(declaration, name)
- meth.comment = define.doc
- container.add_method(meth)
- look_for_directives_in(container, meth.comment) unless meth.comment.empty?
- meth.params = "( #{declaration} )"
- meth.visibility = :public
- meth.document_self = true
- meth.singleton = false
- rescue => detail
- raise Puppet::ParseError, "impossible to parse definition '#{name}' in #{define.file} at line #{define.line}: #{detail}"
+ end
+ declaration << ", "
end
-
- # Traverse the AST tree and produce code-objects node
- # that contains the documentation
- def parse_elements(container)
- Puppet.debug "rdoc: scanning manifest"
- @ast.hostclasses.values.sort { |a,b| a.name <=> b.name }.each do |klass|
- name = klass.name
- if klass.file == @input_file_name
- unless name.empty?
- document_class(name,klass,container)
- else # on main class document vardefs
- code = klass.code.children if klass.code.is_a?(Puppet::Parser::AST::ASTArray)
- code ||= klass.code
- scan_for_vardef(container, code) unless code.nil?
- end
- end
- end
-
- @ast.definitions.each do |name, define|
- if define.file == @input_file_name
- document_define(name,define,container)
- end
- end
-
- @ast.nodes.each do |name, node|
- if node.file == @input_file_name
- document_node(name.to_s,node,container)
- end
+ declaration.chop!.chop! if declaration.size > 1
+
+ # register method into the container
+ meth = AnyMethod.new(declaration, name)
+ meth.comment = define.doc
+ container.add_method(meth)
+ look_for_directives_in(container, meth.comment) unless meth.comment.empty?
+ meth.params = "( #{declaration} )"
+ meth.visibility = :public
+ meth.document_self = true
+ meth.singleton = false
+ rescue => detail
+ raise Puppet::ParseError, "impossible to parse definition '#{name}' in #{define.file} at line #{define.line}: #{detail}"
+ end
+
+ # Traverse the AST tree and produce code-objects node
+ # that contains the documentation
+ def parse_elements(container)
+ Puppet.debug "rdoc: scanning manifest"
+ @ast.hostclasses.values.sort { |a,b| a.name <=> b.name }.each do |klass|
+ name = klass.name
+ if klass.file == @input_file_name
+ unless name.empty?
+ document_class(name,klass,container)
+ else # on main class document vardefs
+ code = klass.code.children if klass.code.is_a?(Puppet::Parser::AST::ASTArray)
+ code ||= klass.code
+ scan_for_vardef(container, code) unless code.nil?
end
+ end
end
- # create documentation for plugins
- def parse_plugins(container)
- Puppet.debug "rdoc: scanning plugin or fact"
- if @input_file_name =~ /\/facter\/[^\/]+\.rb$/
- parse_fact(container)
- else
- parse_puppet_plugin(container)
- end
+ @ast.definitions.each do |name, define|
+ if define.file == @input_file_name
+ document_define(name,define,container)
+ end
end
- # this is a poor man custom fact parser :-)
- def parse_fact(container)
- comments = ""
- current_fact = nil
- File.open(@input_file_name) do |of|
- of.each do |line|
- # fetch comments
- if line =~ /^[ \t]*# ?(.*)$/
- comments += $1 + "\n"
- elsif line =~ /^[ \t]*Facter.add\(['"](.*?)['"]\)/
- current_fact = Fact.new($1,{})
- look_for_directives_in(container, comments) unless comments.empty?
- current_fact.comment = comments
- container.add_fact(current_fact)
- current_fact.record_location(@top_level)
- comments = ""
- Puppet.debug "rdoc: found custom fact #{current_fact.name}"
- elsif line =~ /^[ \t]*confine[ \t]*:(.*?)[ \t]*=>[ \t]*(.*)$/
- current_fact.confine = { :type => $1, :value => $2 } unless current_fact.nil?
- else # unknown line type
- comments =""
- end
- end
- end
+ @ast.nodes.each do |name, node|
+ if node.file == @input_file_name
+ document_node(name.to_s,node,container)
+ end
end
-
- # this is a poor man puppet plugin parser :-)
- # it doesn't extract doc nor desc :-(
- def parse_puppet_plugin(container)
- comments = ""
- current_plugin = nil
-
- File.open(@input_file_name) do |of|
- of.each do |line|
- # fetch comments
- if line =~ /^[ \t]*# ?(.*)$/
- comments += $1 + "\n"
- elsif line =~ /^[ \t]*newfunction[ \t]*\([ \t]*:(.*?)[ \t]*,[ \t]*:type[ \t]*=>[ \t]*(:rvalue|:lvalue)\)/
- current_plugin = Plugin.new($1, "function")
- container.add_plugin(current_plugin)
- look_for_directives_in(container, comments) unless comments.empty?
- current_plugin.comment = comments
- current_plugin.record_location(@top_level)
- comments = ""
- Puppet.debug "rdoc: found new function plugins #{current_plugin.name}"
- elsif line =~ /^[ \t]*Puppet::Type.newtype[ \t]*\([ \t]*:(.*?)\)/
- current_plugin = Plugin.new($1, "type")
- container.add_plugin(current_plugin)
- look_for_directives_in(container, comments) unless comments.empty?
- current_plugin.comment = comments
- current_plugin.record_location(@top_level)
- comments = ""
- Puppet.debug "rdoc: found new type plugins #{current_plugin.name}"
- elsif line =~ /module Puppet::Parser::Functions/
- # skip
- else # unknown line type
- comments =""
- end
- end
+ end
+
+ # create documentation for plugins
+ def parse_plugins(container)
+ Puppet.debug "rdoc: scanning plugin or fact"
+ if @input_file_name =~ /\/facter\/[^\/]+\.rb$/
+ parse_fact(container)
+ else
+ parse_puppet_plugin(container)
+ end
+ end
+
+ # this is a poor man custom fact parser :-)
+ def parse_fact(container)
+ comments = ""
+ current_fact = nil
+ File.open(@input_file_name) do |of|
+ of.each do |line|
+ # fetch comments
+ if line =~ /^[ \t]*# ?(.*)$/
+ comments += $1 + "\n"
+ elsif line =~ /^[ \t]*Facter.add\(['"](.*?)['"]\)/
+ current_fact = Fact.new($1,{})
+ look_for_directives_in(container, comments) unless comments.empty?
+ current_fact.comment = comments
+ container.add_fact(current_fact)
+ current_fact.record_location(@top_level)
+ comments = ""
+ Puppet.debug "rdoc: found custom fact #{current_fact.name}"
+ elsif line =~ /^[ \t]*confine[ \t]*:(.*?)[ \t]*=>[ \t]*(.*)$/
+ current_fact.confine = { :type => $1, :value => $2 } unless current_fact.nil?
+ else # unknown line type
+ comments =""
end
+ end
end
-
- # look_for_directives_in scans the current +comment+ for RDoc directives
- def look_for_directives_in(context, comment)
- preprocess = SM::PreProcess.new(@input_file_name, @options.rdoc_include)
-
- preprocess.handle(comment) do |directive, param|
- case directive
- when "stopdoc"
- context.stop_doc
- ""
- when "startdoc"
- context.start_doc
- context.force_documentation = true
- ""
- when "enddoc"
- #context.done_documenting = true
- #""
- throw :enddoc
- when "main"
- options = Options.instance
- options.main_page = param
- ""
- when "title"
- options = Options.instance
- options.title = param
- ""
- when "section"
- context.set_current_section(param, comment)
- comment.replace("") # 1.8 doesn't support #clear
- break
- else
- warn "Unrecognized directive '#{directive}'"
- break
- end
+ end
+
+ # this is a poor man puppet plugin parser :-)
+ # it doesn't extract doc nor desc :-(
+ def parse_puppet_plugin(container)
+ comments = ""
+ current_plugin = nil
+
+ File.open(@input_file_name) do |of|
+ of.each do |line|
+ # fetch comments
+ if line =~ /^[ \t]*# ?(.*)$/
+ comments += $1 + "\n"
+ elsif line =~ /^[ \t]*newfunction[ \t]*\([ \t]*:(.*?)[ \t]*,[ \t]*:type[ \t]*=>[ \t]*(:rvalue|:lvalue)\)/
+ current_plugin = Plugin.new($1, "function")
+ container.add_plugin(current_plugin)
+ look_for_directives_in(container, comments) unless comments.empty?
+ current_plugin.comment = comments
+ current_plugin.record_location(@top_level)
+ comments = ""
+ Puppet.debug "rdoc: found new function plugins #{current_plugin.name}"
+ elsif line =~ /^[ \t]*Puppet::Type.newtype[ \t]*\([ \t]*:(.*?)\)/
+ current_plugin = Plugin.new($1, "type")
+ container.add_plugin(current_plugin)
+ look_for_directives_in(container, comments) unless comments.empty?
+ current_plugin.comment = comments
+ current_plugin.record_location(@top_level)
+ comments = ""
+ Puppet.debug "rdoc: found new type plugins #{current_plugin.name}"
+ elsif line =~ /module Puppet::Parser::Functions/
+ # skip
+ else # unknown line type
+ comments =""
end
- remove_private_comments(comment)
+ end
end
-
- def remove_private_comments(comment)
- comment.gsub!(/^#--.*?^#\+\+/m, '')
- comment.sub!(/^#--.*/m, '')
+ end
+
+ # look_for_directives_in scans the current +comment+ for RDoc directives
+ def look_for_directives_in(context, comment)
+ preprocess = SM::PreProcess.new(@input_file_name, @options.rdoc_include)
+
+ preprocess.handle(comment) do |directive, param|
+ case directive
+ when "stopdoc"
+ context.stop_doc
+ ""
+ when "startdoc"
+ context.start_doc
+ context.force_documentation = true
+ ""
+ when "enddoc"
+ #context.done_documenting = true
+ #""
+ throw :enddoc
+ when "main"
+ options = Options.instance
+ options.main_page = param
+ ""
+ when "title"
+ options = Options.instance
+ options.title = param
+ ""
+ when "section"
+ context.set_current_section(param, comment)
+ comment.replace("") # 1.8 doesn't support #clear
+ break
+ else
+ warn "Unrecognized directive '#{directive}'"
+ break
+ end
end
+ remove_private_comments(comment)
+ end
+
+ def remove_private_comments(comment)
+ comment.gsub!(/^#--.*?^#\+\+/m, '')
+ comment.sub!(/^#--.*/m, '')
+ end
end
end
diff --git a/lib/puppet/util/reference.rb b/lib/puppet/util/reference.rb
index 78304217c..62bab643e 100644
--- a/lib/puppet/util/reference.rb
+++ b/lib/puppet/util/reference.rb
@@ -3,205 +3,205 @@ require 'fileutils'
# Manage Reference Documentation.
class Puppet::Util::Reference
- include Puppet::Util
- include Puppet::Util::Docs
-
- extend Puppet::Util::InstanceLoader
-
- instance_load(:reference, 'puppet/reference')
-
- def self.footer
- "\n\n----------------\n\n*This page autogenerated on #{Time.now}*\n"
- end
-
- def self.modes
- %w{pdf trac text markdown}
- end
+ include Puppet::Util
+ include Puppet::Util::Docs
- def self.newreference(name, options = {}, &block)
- ref = self.new(name, options, &block)
- instance_hash(:reference)[symbolize(name)] = ref
+ extend Puppet::Util::InstanceLoader
- ref
- end
+ instance_load(:reference, 'puppet/reference')
- def self.page(*sections)
- depth = 4
- # Use the minimum depth
- sections.each do |name|
- section = reference(name) or raise "Could not find section #{name}"
- depth = section.depth if section.depth < depth
- end
- text = ".. contents:: :depth: 2\n\n"
- end
+ def self.footer
+ "\n\n----------------\n\n*This page autogenerated on #{Time.now}*\n"
+ end
+
+ def self.modes
+ %w{pdf trac text markdown}
+ end
- def self.pdf(text)
- puts "creating pdf"
- Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f|
- f.puts text
- end
- rst2latex = %x{which rst2latex}
- if $CHILD_STATUS != 0 or rst2latex =~ /no /
- rst2latex = %x{which rst2latex.py}
- end
- if $CHILD_STATUS != 0 or rst2latex =~ /no /
- raise "Could not find rst2latex"
- end
- rst2latex.chomp!
- cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex}
- Puppet::Util.secure_open("/tmp/puppetdoc.tex","w") do |f|
- # If we get here without an error, /tmp/puppetdoc.tex isn't a tricky cracker's symlink
- end
- output = %x{#{cmd}}
- unless $CHILD_STATUS == 0
- $stderr.puts "rst2latex failed"
- $stderr.puts output
- exit(1)
- end
- $stderr.puts output
+ def self.newreference(name, options = {}, &block)
+ ref = self.new(name, options, &block)
+ instance_hash(:reference)[symbolize(name)] = ref
- # Now convert to pdf
- Dir.chdir("/tmp") do
- %x{texi2pdf puppetdoc.tex >/dev/null 2>/dev/null}
- end
+ ref
+ end
+ def self.page(*sections)
+ depth = 4
+ # Use the minimum depth
+ sections.each do |name|
+ section = reference(name) or raise "Could not find section #{name}"
+ depth = section.depth if section.depth < depth
end
+ text = ".. contents:: :depth: 2\n\n"
+ end
- def self.markdown(name, text)
- puts "Creating markdown for #{name} reference."
- dir = "/tmp/#{Puppet::PUPPETVERSION}"
- FileUtils.mkdir(dir) unless File.directory?(dir)
- Puppet::Util.secure_open(dir + "/#{name}.rst", "w") do |f|
- f.puts text
- end
- pandoc = %x{which pandoc}
- if $CHILD_STATUS != 0 or pandoc =~ /no /
- pandoc = %x{which pandoc}
- end
- if $CHILD_STATUS != 0 or pandoc =~ /no /
- raise "Could not find pandoc"
- end
- pandoc.chomp!
- cmd = %{#{pandoc} -s -r rst -w markdown #{dir}/#{name}.rst -o #{dir}/#{name}.mdwn}
- output = %x{#{cmd}}
- unless $CHILD_STATUS == 0
- $stderr.puts "Pandoc failed to create #{name} reference."
- $stderr.puts output
- exit(1)
- end
+ def self.pdf(text)
+ puts "creating pdf"
+ Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f|
+ f.puts text
+ end
+ rst2latex = %x{which rst2latex}
+ if $CHILD_STATUS != 0 or rst2latex =~ /no /
+ rst2latex = %x{which rst2latex.py}
+ end
+ if $CHILD_STATUS != 0 or rst2latex =~ /no /
+ raise "Could not find rst2latex"
+ end
+ rst2latex.chomp!
+ cmd = %{#{rst2latex} /tmp/puppetdoc.txt > /tmp/puppetdoc.tex}
+ Puppet::Util.secure_open("/tmp/puppetdoc.tex","w") do |f|
+ # If we get here without an error, /tmp/puppetdoc.tex isn't a tricky cracker's symlink
+ end
+ output = %x{#{cmd}}
+ unless $CHILD_STATUS == 0
+ $stderr.puts "rst2latex failed"
+ $stderr.puts output
+ exit(1)
+ end
+ $stderr.puts output
- File.unlink(dir + "/#{name}.rst")
+ # Now convert to pdf
+ Dir.chdir("/tmp") do
+ %x{texi2pdf puppetdoc.tex >/dev/null 2>/dev/null}
end
- def self.references
- instance_loader(:reference).loadall
- loaded_instances(:reference).sort { |a,b| a.to_s <=> b.to_s }
+ end
+
+ def self.markdown(name, text)
+ puts "Creating markdown for #{name} reference."
+ dir = "/tmp/#{Puppet::PUPPETVERSION}"
+ FileUtils.mkdir(dir) unless File.directory?(dir)
+ Puppet::Util.secure_open(dir + "/#{name}.rst", "w") do |f|
+ f.puts text
+ end
+ pandoc = %x{which pandoc}
+ if $CHILD_STATUS != 0 or pandoc =~ /no /
+ pandoc = %x{which pandoc}
+ end
+ if $CHILD_STATUS != 0 or pandoc =~ /no /
+ raise "Could not find pandoc"
+ end
+ pandoc.chomp!
+ cmd = %{#{pandoc} -s -r rst -w markdown #{dir}/#{name}.rst -o #{dir}/#{name}.mdwn}
+ output = %x{#{cmd}}
+ unless $CHILD_STATUS == 0
+ $stderr.puts "Pandoc failed to create #{name} reference."
+ $stderr.puts output
+ exit(1)
end
- HEADER_LEVELS = [nil, "=", "-", "+", "'", "~"]
+ File.unlink(dir + "/#{name}.rst")
+ end
- attr_accessor :page, :depth, :header, :title, :dynamic
- attr_writer :doc
+ def self.references
+ instance_loader(:reference).loadall
+ loaded_instances(:reference).sort { |a,b| a.to_s <=> b.to_s }
+ end
- def doc
- if defined?(@doc)
- return "#{@name} - #{@doc}"
- else
- return @title
- end
- end
+ HEADER_LEVELS = [nil, "=", "-", "+", "'", "~"]
- def dynamic?
- self.dynamic
- end
+ attr_accessor :page, :depth, :header, :title, :dynamic
+ attr_writer :doc
- def h(name, level)
- "#{name}\n#{HEADER_LEVELS[level] * name.to_s.length}\n\n"
+ def doc
+ if defined?(@doc)
+ return "#{@name} - #{@doc}"
+ else
+ return @title
end
+ end
- def initialize(name, options = {}, &block)
- @name = name
- options.each do |option, value|
- send(option.to_s + "=", value)
- end
+ def dynamic?
+ self.dynamic
+ end
- meta_def(:generate, &block)
+ def h(name, level)
+ "#{name}\n#{HEADER_LEVELS[level] * name.to_s.length}\n\n"
+ end
- # Now handle the defaults
- @title ||= "#{@name.to_s.capitalize} Reference"
- @page ||= @title.gsub(/\s+/, '')
- @depth ||= 2
- @header ||= ""
+ def initialize(name, options = {}, &block)
+ @name = name
+ options.each do |option, value|
+ send(option.to_s + "=", value)
end
- # Indent every line in the chunk except those which begin with '..'.
- def indent(text, tab)
- text.gsub(/(^|\A)/, tab).gsub(/^ +\.\./, "..")
- end
+ meta_def(:generate, &block)
- def option(name, value)
- ":#{name.to_s.capitalize}: #{value}\n"
- end
+ # Now handle the defaults
+ @title ||= "#{@name.to_s.capitalize} Reference"
+ @page ||= @title.gsub(/\s+/, '')
+ @depth ||= 2
+ @header ||= ""
+ end
- def paramwrap(name, text, options = {})
- options[:level] ||= 5
- #str = "#{name} : "
- str = h(name, options[:level])
- str += "- **namevar**\n\n" if options[:namevar]
- str += text
- #str += text.gsub(/\n/, "\n ")
+ # Indent every line in the chunk except those which begin with '..'.
+ def indent(text, tab)
+ text.gsub(/(^|\A)/, tab).gsub(/^ +\.\./, "..")
+ end
- str += "\n\n"
- end
+ def option(name, value)
+ ":#{name.to_s.capitalize}: #{value}\n"
+ end
- # Remove all trac links.
- def strip_trac(text)
- text.gsub(/`\w+\s+([^`]+)`:trac:/) { |m| $1 }
- end
+ def paramwrap(name, text, options = {})
+ options[:level] ||= 5
+ #str = "#{name} : "
+ str = h(name, options[:level])
+ str += "- **namevar**\n\n" if options[:namevar]
+ str += text
+ #str += text.gsub(/\n/, "\n ")
- def text
- puts output
- end
+ str += "\n\n"
+ end
- def to_rest(withcontents = true)
- # First the header
- text = h(@title, 1)
- text += "\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on #{Time.now.to_s})*\n\n"
- text += ".. contents:: :depth: #{@depth}\n\n" if withcontents
+ # Remove all trac links.
+ def strip_trac(text)
+ text.gsub(/`\w+\s+([^`]+)`:trac:/) { |m| $1 }
+ end
- text += @header
+ def text
+ puts output
+ end
- text += generate
+ def to_rest(withcontents = true)
+ # First the header
+ text = h(@title, 1)
+ text += "\n\n**This page is autogenerated; any changes will get overwritten** *(last generated on #{Time.now.to_s})*\n\n"
+ text += ".. contents:: :depth: #{@depth}\n\n" if withcontents
- text += self.class.footer if withcontents
+ text += @header
- text
- end
+ text += generate
- def to_text(withcontents = true)
- strip_trac(to_rest(withcontents))
- end
+ text += self.class.footer if withcontents
- def to_trac(with_contents = true)
- "{{{\n#!rst\n#{self.to_rest(with_contents)}\n}}}"
- end
+ text
+ end
+
+ def to_text(withcontents = true)
+ strip_trac(to_rest(withcontents))
+ end
- def trac
- Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f|
- f.puts self.to_trac
- end
+ def to_trac(with_contents = true)
+ "{{{\n#!rst\n#{self.to_rest(with_contents)}\n}}}"
+ end
- puts "Writing #{@name} reference to trac as #{@page}"
- cmd = %{sudo trac-admin /opt/rl/trac/puppet wiki import %s /tmp/puppetdoc.txt} % self.page
- output = %x{#{cmd}}
- unless $CHILD_STATUS == 0
- $stderr.puts "trac-admin failed"
- $stderr.puts output
- exit(1)
- end
- unless output =~ /^\s+/
- $stderr.puts output
- end
+ def trac
+ Puppet::Util.secure_open("/tmp/puppetdoc.txt", "w") do |f|
+ f.puts self.to_trac
+ end
+
+ puts "Writing #{@name} reference to trac as #{@page}"
+ cmd = %{sudo trac-admin /opt/rl/trac/puppet wiki import %s /tmp/puppetdoc.txt} % self.page
+ output = %x{#{cmd}}
+ unless $CHILD_STATUS == 0
+ $stderr.puts "trac-admin failed"
+ $stderr.puts output
+ exit(1)
+ end
+ unless output =~ /^\s+/
+ $stderr.puts output
end
+ end
end
diff --git a/lib/puppet/util/resource_template.rb b/lib/puppet/util/resource_template.rb
index ceb9ea389..b12b125b5 100644
--- a/lib/puppet/util/resource_template.rb
+++ b/lib/puppet/util/resource_template.rb
@@ -36,26 +36,26 @@ require 'erb'
# parameters, which is generally most useful, since it allows you to configure
# the generated resource via the generating resource.
class Puppet::Util::ResourceTemplate
- include Puppet::Util::Logging
+ include Puppet::Util::Logging
- def evaluate
- set_resource_variables
- ERB.new(File.read(@file), 0, "-").result(binding)
- end
+ def evaluate
+ set_resource_variables
+ ERB.new(File.read(@file), 0, "-").result(binding)
+ end
- def initialize(file, resource)
- raise ArgumentError, "Template #{file} does not exist" unless FileTest.exist?(file)
- @file = file
- @resource = resource
- end
+ def initialize(file, resource)
+ raise ArgumentError, "Template #{file} does not exist" unless FileTest.exist?(file)
+ @file = file
+ @resource = resource
+ end
- private
+ private
- def set_resource_variables
- @resource.to_hash.each do |param, value|
- var = "@#{param.to_s}"
- instance_variable_set(var, value)
- end
+ def set_resource_variables
+ @resource.to_hash.each do |param, value|
+ var = "@#{param.to_s}"
+ instance_variable_set(var, value)
end
+ end
end
diff --git a/lib/puppet/util/run_mode.rb b/lib/puppet/util/run_mode.rb
index bf745743f..eb9c511dc 100644
--- a/lib/puppet/util/run_mode.rb
+++ b/lib/puppet/util/run_mode.rb
@@ -1,81 +1,81 @@
module Puppet
- module Util
- class RunMode
- def initialize(name)
- @name = name.to_sym
- end
+ module Util
+ class RunMode
+ def initialize(name)
+ @name = name.to_sym
+ end
- @@run_modes = Hash.new {|h, k| h[k] = RunMode.new(k)}
+ @@run_modes = Hash.new {|h, k| h[k] = RunMode.new(k)}
- attr :name
+ attr :name
- def self.[](name)
- @@run_modes[name]
- end
+ def self.[](name)
+ @@run_modes[name]
+ end
- def master?
- name == :master
- end
+ def master?
+ name == :master
+ end
- def agent?
- name == :agent
- end
+ def agent?
+ name == :agent
+ end
- def user?
- name == :user
- end
+ def user?
+ name == :user
+ end
- def conf_dir
- which_dir(
- (Puppet.features.microsoft_windows? ? File.join(Dir::WINDOWS, "puppet", "etc") : "/etc/puppet"),
- "~/.puppet"
- )
- end
+ def conf_dir
+ which_dir(
+ (Puppet.features.microsoft_windows? ? File.join(Dir::WINDOWS, "puppet", "etc") : "/etc/puppet"),
+ "~/.puppet"
+ )
+ end
- def var_dir
- which_dir(
- (Puppet.features.microsoft_windows? ? File.join(Dir::WINDOWS, "puppet", "var") : "/var/lib/puppet"),
- "~/.puppet/var"
- )
- end
+ def var_dir
+ which_dir(
+ (Puppet.features.microsoft_windows? ? File.join(Dir::WINDOWS, "puppet", "var") : "/var/lib/puppet"),
+ "~/.puppet/var"
+ )
+ end
- def run_dir
- which_dir("/var/run/puppet", "~/.puppet/var")
- end
+ def run_dir
+ which_dir("/var/run/puppet", "~/.puppet/var")
+ end
- def logopts
- if name == :master
- {
- :default => "$vardir/log",
- :mode => 0750,
- :owner => "service",
- :group => "service",
- :desc => "The Puppet log directory."
- }
- else
- ["$vardir/log", "The Puppet log directory."]
- end
- end
+ def logopts
+ if name == :master
+ {
+ :default => "$vardir/log",
+ :mode => 0750,
+ :owner => "service",
+ :group => "service",
+ :desc => "The Puppet log directory."
+ }
+ else
+ ["$vardir/log", "The Puppet log directory."]
+ end
+ end
- private
+ private
- def which_dir( global, user )
- #FIXME: we should test if we're user "puppet"
- # there's a comment that suggests that we do that
- # and we currently don't.
- expand_path case
- when name == :master; global
- when Puppet.features.root?; global
- else user
- end
- end
+ def which_dir( global, user )
+ #FIXME: we should test if we're user "puppet"
+ # there's a comment that suggests that we do that
+ # and we currently don't.
+ expand_path case
+ when name == :master; global
+ when Puppet.features.root?; global
+ else user
+ end
+ end
- def expand_path( dir )
- require 'etc'
- ENV["HOME"] ||= Etc.getpwuid(Process.uid).dir
- File.expand_path(dir)
- end
+ def expand_path( dir )
+ require 'etc'
+ ENV["HOME"] ||= Etc.getpwuid(Process.uid).dir
+ File.expand_path(dir)
+ end
- end
end
+ end
end
diff --git a/lib/puppet/util/selinux.rb b/lib/puppet/util/selinux.rb
index 5aafd9c02..9d0e0a715 100644
--- a/lib/puppet/util/selinux.rb
+++ b/lib/puppet/util/selinux.rb
@@ -13,204 +13,204 @@ require 'pathname'
module Puppet::Util::SELinux
- def selinux_support?
- return false unless defined?(Selinux)
- if Selinux.is_selinux_enabled == 1
- return true
- end
- false
+ def selinux_support?
+ return false unless defined?(Selinux)
+ if Selinux.is_selinux_enabled == 1
+ return true
end
-
- # Retrieve and return the full context of the file. If we don't have
- # SELinux support or if the SELinux call fails then return nil.
- def get_selinux_current_context(file)
- return nil unless selinux_support?
- retval = Selinux.lgetfilecon(file)
- if retval == -1
- return nil
- end
- retval[1]
+ false
+ end
+
+ # Retrieve and return the full context of the file. If we don't have
+ # SELinux support or if the SELinux call fails then return nil.
+ def get_selinux_current_context(file)
+ return nil unless selinux_support?
+ retval = Selinux.lgetfilecon(file)
+ if retval == -1
+ return nil
end
-
- # Retrieve and return the default context of the file. If we don't have
- # SELinux support or if the SELinux call fails to file a default then return nil.
- def get_selinux_default_context(file)
- return nil unless selinux_support?
- # If the filesystem has no support for SELinux labels, return a default of nil
- # instead of what matchpathcon would return
- return nil unless selinux_label_support?(file)
- # If the file exists we should pass the mode to matchpathcon for the most specific
- # matching. If not, we can pass a mode of 0.
- begin
- filestat = File.lstat(file)
- mode = filestat.mode
- rescue Errno::ENOENT
- mode = 0
- end
- retval = Selinux.matchpathcon(file, mode)
- if retval == -1
- return nil
- end
- retval[1]
+ retval[1]
+ end
+
+ # Retrieve and return the default context of the file. If we don't have
+ # SELinux support or if the SELinux call fails to file a default then return nil.
+ def get_selinux_default_context(file)
+ return nil unless selinux_support?
+ # If the filesystem has no support for SELinux labels, return a default of nil
+ # instead of what matchpathcon would return
+ return nil unless selinux_label_support?(file)
+ # If the file exists we should pass the mode to matchpathcon for the most specific
+ # matching. If not, we can pass a mode of 0.
+ begin
+ filestat = File.lstat(file)
+ mode = filestat.mode
+ rescue Errno::ENOENT
+ mode = 0
end
-
- # Take the full SELinux context returned from the tools and parse it
- # out to the three (or four) component parts. Supports :seluser, :selrole,
- # :seltype, and on systems with range support, :selrange.
- def parse_selinux_context(component, context)
- if context.nil? or context == "unlabeled"
- return nil
- end
- unless context =~ /^([a-z0-9_]+):([a-z0-9_]+):([a-zA-Z0-9_]+)(?::([a-zA-Z0-9:,._-]+))?/
- raise Puppet::Error, "Invalid context to parse: #{context}"
- end
- ret = {
- :seluser => $1,
- :selrole => $2,
- :seltype => $3,
- :selrange => $4,
- }
- ret[component]
+ retval = Selinux.matchpathcon(file, mode)
+ if retval == -1
+ return nil
end
-
- # This updates the actual SELinux label on the file. You can update
- # only a single component or update the entire context.
- # The caveat is that since setting a partial context makes no sense the
- # file has to already exist. Puppet (via the File resource) will always
- # just try to set components, even if all values are specified by the manifest.
- # I believe that the OS should always provide at least a fall-through context
- # though on any well-running system.
- def set_selinux_context(file, value, component = false)
- return nil unless selinux_support? && selinux_label_support?(file)
-
- if component
- # Must first get existing context to replace a single component
- context = Selinux.lgetfilecon(file)[1]
- if context == -1
- # We can't set partial context components when no context exists
- # unless/until we can find a way to make Puppet call this method
- # once for all selinux file label attributes.
- Puppet.warning "Can't set SELinux context on file unless the file already has some kind of context"
- return nil
- end
- context = context.split(':')
- case component
- when :seluser
- context[0] = value
- when :selrole
- context[1] = value
- when :seltype
- context[2] = value
- when :selrange
- context[3] = value
- else
- raise ArguementError, "set_selinux_context component must be one of :seluser, :selrole, :seltype, or :selrange"
- end
- context = context.join(':')
- else
- context = value
- end
-
- retval = Selinux.lsetfilecon(file, context)
- if retval == 0
- return true
+ retval[1]
+ end
+
+ # Take the full SELinux context returned from the tools and parse it
+ # out to the three (or four) component parts. Supports :seluser, :selrole,
+ # :seltype, and on systems with range support, :selrange.
+ def parse_selinux_context(component, context)
+ if context.nil? or context == "unlabeled"
+ return nil
+ end
+ unless context =~ /^([a-z0-9_]+):([a-z0-9_]+):([a-zA-Z0-9_]+)(?::([a-zA-Z0-9:,._-]+))?/
+ raise Puppet::Error, "Invalid context to parse: #{context}"
+ end
+ ret = {
+ :seluser => $1,
+ :selrole => $2,
+ :seltype => $3,
+ :selrange => $4,
+ }
+ ret[component]
+ end
+
+ # This updates the actual SELinux label on the file. You can update
+ # only a single component or update the entire context.
+ # The caveat is that since setting a partial context makes no sense the
+ # file has to already exist. Puppet (via the File resource) will always
+ # just try to set components, even if all values are specified by the manifest.
+ # I believe that the OS should always provide at least a fall-through context
+ # though on any well-running system.
+ def set_selinux_context(file, value, component = false)
+ return nil unless selinux_support? && selinux_label_support?(file)
+
+ if component
+ # Must first get existing context to replace a single component
+ context = Selinux.lgetfilecon(file)[1]
+ if context == -1
+ # We can't set partial context components when no context exists
+ # unless/until we can find a way to make Puppet call this method
+ # once for all selinux file label attributes.
+ Puppet.warning "Can't set SELinux context on file unless the file already has some kind of context"
+ return nil
+ end
+ context = context.split(':')
+ case component
+ when :seluser
+ context[0] = value
+ when :selrole
+ context[1] = value
+ when :seltype
+ context[2] = value
+ when :selrange
+ context[3] = value
else
- Puppet.warning "Failed to set SELinux context #{context} on #{file}"
- return false
- end
+ raise ArguementError, "set_selinux_context component must be one of :seluser, :selrole, :seltype, or :selrange"
+ end
+ context = context.join(':')
+ else
+ context = value
end
- # Since this call relies on get_selinux_default_context it also needs a
- # full non-relative path to the file. Fortunately, that seems to be all
- # Puppet uses. This will set the file's SELinux context to the policy's
- # default context (if any) if it differs from the context currently on
- # the file.
- def set_selinux_default_context(file)
- new_context = get_selinux_default_context(file)
- return nil unless new_context
- cur_context = get_selinux_current_context(file)
- if new_context != cur_context
- set_selinux_context(file, new_context)
- return new_context
- end
- nil
+ retval = Selinux.lsetfilecon(file, context)
+ if retval == 0
+ return true
+ else
+ Puppet.warning "Failed to set SELinux context #{context} on #{file}"
+ return false
end
-
- # Internal helper function to read and parse /proc/mounts
- def read_mounts
- mounts = ""
- begin
- if File.instance_methods.include? "read_nonblock"
- # If possible we use read_nonblock in a loop rather than read to work-
- # a linux kernel bug. See ticket #1963 for details.
- mountfh = File.open("/proc/mounts")
- mounts += mountfh.read_nonblock(1024) while true
- else
- # Otherwise we shell out and let cat do it for us
- mountfh = IO.popen("/bin/cat /proc/mounts")
- mounts = mountfh.read
- end
- rescue EOFError
- # that's expected
- rescue
- return nil
- ensure
- mountfh.close if mountfh
- end
-
- mntpoint = {}
-
- # Read all entries in /proc/mounts. The second column is the
- # mountpoint and the third column is the filesystem type.
- # We skip rootfs because it is always mounted at /
- mounts.collect do |line|
- params = line.split(' ')
- next if params[2] == 'rootfs'
- mntpoint[params[1]] = params[2]
- end
- mntpoint
+ end
+
+ # Since this call relies on get_selinux_default_context it also needs a
+ # full non-relative path to the file. Fortunately, that seems to be all
+ # Puppet uses. This will set the file's SELinux context to the policy's
+ # default context (if any) if it differs from the context currently on
+ # the file.
+ def set_selinux_default_context(file)
+ new_context = get_selinux_default_context(file)
+ return nil unless new_context
+ cur_context = get_selinux_current_context(file)
+ if new_context != cur_context
+ set_selinux_context(file, new_context)
+ return new_context
end
-
- def realpath(path)
- path, rest = Pathname.new(path), []
- path, rest = path.dirname, [path.basename] + rest while ! path.exist?
- File.join( path.realpath, *rest )
+ nil
+ end
+
+ # Internal helper function to read and parse /proc/mounts
+ def read_mounts
+ mounts = ""
+ begin
+ if File.instance_methods.include? "read_nonblock"
+ # If possible we use read_nonblock in a loop rather than read to work-
+ # a linux kernel bug. See ticket #1963 for details.
+ mountfh = File.open("/proc/mounts")
+ mounts += mountfh.read_nonblock(1024) while true
+ else
+ # Otherwise we shell out and let cat do it for us
+ mountfh = IO.popen("/bin/cat /proc/mounts")
+ mounts = mountfh.read
+ end
+ rescue EOFError
+ # that's expected
+ rescue
+ return nil
+ ensure
+ mountfh.close if mountfh
end
- def parent_directory(path)
- Pathname.new(path).dirname.to_s
- end
+ mntpoint = {}
- # Internal helper function to return which type of filesystem a
- # given file path resides on
- def find_fs(path)
- unless mnts = read_mounts
- return nil
- end
-
- # For a given file:
- # Check if the filename is in the data structure;
- # return the fstype if it is.
- # Just in case: return something if you're down to "/" or ""
- # Remove the last slash and everything after it,
- # and repeat with that as the file for the next loop through.
- path = realpath(path)
- while not path.empty?
- return mnts[path] if mnts.has_key?(path)
- path = parent_directory(path)
- end
- mnts['/']
+ # Read all entries in /proc/mounts. The second column is the
+ # mountpoint and the third column is the filesystem type.
+ # We skip rootfs because it is always mounted at /
+ mounts.collect do |line|
+ params = line.split(' ')
+ next if params[2] == 'rootfs'
+ mntpoint[params[1]] = params[2]
+ end
+ mntpoint
+ end
+
+ def realpath(path)
+ path, rest = Pathname.new(path), []
+ path, rest = path.dirname, [path.basename] + rest while ! path.exist?
+ File.join( path.realpath, *rest )
+ end
+
+ def parent_directory(path)
+ Pathname.new(path).dirname.to_s
+ end
+
+ # Internal helper function to return which type of filesystem a
+ # given file path resides on
+ def find_fs(path)
+ unless mnts = read_mounts
+ return nil
end
- # Check filesystem a path resides on for SELinux support against
- # whitelist of known-good filesystems.
- # Returns true if the filesystem can support SELinux labels and
- # false if not.
- def selinux_label_support?(file)
- fstype = find_fs(file)
- return false if fstype.nil?
- filesystems = ['ext2', 'ext3', 'ext4', 'gfs', 'gfs2', 'xfs', 'jfs']
- filesystems.include?(fstype)
+ # For a given file:
+ # Check if the filename is in the data structure;
+ # return the fstype if it is.
+ # Just in case: return something if you're down to "/" or ""
+ # Remove the last slash and everything after it,
+ # and repeat with that as the file for the next loop through.
+ path = realpath(path)
+ while not path.empty?
+ return mnts[path] if mnts.has_key?(path)
+ path = parent_directory(path)
end
+ mnts['/']
+ end
+
+ # Check filesystem a path resides on for SELinux support against
+ # whitelist of known-good filesystems.
+ # Returns true if the filesystem can support SELinux labels and
+ # false if not.
+ def selinux_label_support?(file)
+ fstype = find_fs(file)
+ return false if fstype.nil?
+ filesystems = ['ext2', 'ext3', 'ext4', 'gfs', 'gfs2', 'xfs', 'jfs']
+ filesystems.include?(fstype)
+ end
end
diff --git a/lib/puppet/util/settings.rb b/lib/puppet/util/settings.rb
index 5573145b5..cbb12a816 100644
--- a/lib/puppet/util/settings.rb
+++ b/lib/puppet/util/settings.rb
@@ -7,581 +7,581 @@ require 'puppet/util/loadedfile'
# The class for handling configuration files.
class Puppet::Util::Settings
- include Enumerable
- include Puppet::Util::Cacher
-
- require 'puppet/util/settings/setting'
- require 'puppet/util/settings/file_setting'
- require 'puppet/util/settings/boolean_setting'
-
- attr_accessor :file
- attr_reader :timer
-
- ReadOnly = [:run_mode, :name]
-
- # Retrieve a config value
- def [](param)
- value(param)
- end
-
- # Set a config value. This doesn't set the defaults, it sets the value itself.
- def []=(param, value)
- set_value(param, value, :memory)
- end
-
- # Generate the list of valid arguments, in a format that GetoptLong can
- # understand, and add them to the passed option list.
- def addargs(options)
- # Add all of the config parameters as valid options.
- self.each { |name, setting|
- setting.getopt_args.each { |args| options << args }
- }
-
- options
- end
-
- # Generate the list of valid arguments, in a format that OptionParser can
- # understand, and add them to the passed option list.
- def optparse_addargs(options)
- # Add all of the config parameters as valid options.
- self.each { |name, setting|
- options << setting.optparse_args
- }
-
- options
- end
-
- # Is our parameter a boolean parameter?
- def boolean?(param)
- param = param.to_sym
- !!(@config.include?(param) and @config[param].kind_of? BooleanSetting)
- end
-
- # Remove all set values, potentially skipping cli values.
- def clear(exceptcli = false)
- @sync.synchronize do
- unsafe_clear(exceptcli)
- end
- end
-
- # Remove all set values, potentially skipping cli values.
- def unsafe_clear(exceptcli = false)
- @values.each do |name, values|
- @values.delete(name) unless exceptcli and name == :cli
- end
-
- # Don't clear the 'used' in this case, since it's a config file reparse,
- # and we want to retain this info.
- @used = [] unless exceptcli
-
- @cache.clear
- end
-
- # This is mostly just used for testing.
- def clearused
- @cache.clear
- @used = []
- end
-
- # Do variable interpolation on the value.
- def convert(value, environment = nil)
- return value unless value
- return value unless value.is_a? String
- newval = value.gsub(/\$(\w+)|\$\{(\w+)\}/) do |value|
- varname = $2 || $1
- if varname == "environment" and environment
- environment
- elsif pval = self.value(varname)
- pval
- else
- raise Puppet::DevError, "Could not find value for #{value}"
- end
- end
-
- newval
- end
-
- # Return a value's description.
- def description(name)
- if obj = @config[name.to_sym]
- obj.desc
- else
- nil
- end
- end
-
- def each
- @config.each { |name, object|
- yield name, object
- }
- end
-
- # Iterate over each section name.
- def eachsection
- yielded = []
- @config.each do |name, object|
- section = object.section
- unless yielded.include? section
- yield section
- yielded << section
- end
- end
- end
-
- # Return an object by name.
- def setting(param)
- param = param.to_sym
- @config[param]
- end
-
- # Handle a command-line argument.
- def handlearg(opt, value = nil)
- @cache.clear
- value &&= munge_value(value)
- str = opt.sub(/^--/,'')
-
- bool = true
- newstr = str.sub(/^no-/, '')
- if newstr != str
- str = newstr
- bool = false
- end
- str = str.intern
-
- if @config[str].is_a?(Puppet::Util::Settings::BooleanSetting)
- if value == "" or value.nil?
- value = bool
- end
- end
-
- set_value(str, value, :cli)
- end
-
- def without_noop
- old_noop = value(:noop,:cli) and set_value(:noop, false, :cli) if valid?(:noop)
- yield
- ensure
- set_value(:noop, old_noop, :cli) if valid?(:noop)
- end
-
- def include?(name)
- name = name.intern if name.is_a? String
- @config.include?(name)
- end
-
- # check to see if a short name is already defined
- def shortinclude?(short)
- short = short.intern if name.is_a? String
- @shortnames.include?(short)
- end
-
- # Create a new collection of config settings.
- def initialize
- @config = {}
- @shortnames = {}
-
- @created = []
- @searchpath = nil
-
- # Mutex-like thing to protect @values
- @sync = Sync.new
-
- # Keep track of set values.
- @values = Hash.new { |hash, key| hash[key] = {} }
-
- # And keep a per-environment cache
- @cache = Hash.new { |hash, key| hash[key] = {} }
-
- # The list of sections we've used.
- @used = []
- end
-
- # NOTE: ACS ahh the util classes. . .sigh
- # as part of a fix for 1183, I pulled the logic for the following 5 methods out of the executables and puppet.rb
- # They probably deserve their own class, but I don't want to do that until I can refactor environments
- # its a little better than where they were
-
- # Prints the contents of a config file with the available config settings, or it
- # prints a single value of a config setting.
- def print_config_options
- env = value(:environment)
- val = value(:configprint)
- if val == "all"
- hash = {}
- each do |name, obj|
- val = value(name,env)
- val = val.inspect if val == ""
- hash[name] = val
- end
- hash.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, val|
- puts "#{name} = #{val}"
- end
- else
- val.split(/\s*,\s*/).sort.each do |v|
- if include?(v)
- #if there is only one value, just print it for back compatibility
- if v == val
- puts value(val,env)
- break
- end
- puts "#{v} = #{value(v,env)}"
- else
- puts "invalid parameter: #{v}"
- return false
- end
- end
- end
- true
- end
-
- def generate_config
- puts to_config
- true
- end
-
- def generate_manifest
- puts to_manifest
- true
- end
-
- def print_configs
- return print_config_options if value(:configprint) != ""
- return generate_config if value(:genconfig)
- generate_manifest if value(:genmanifest)
- end
-
- def print_configs?
- (value(:configprint) != "" || value(:genconfig) || value(:genmanifest)) && true
- end
-
- # Return a given object's file metadata.
- def metadata(param)
- if obj = @config[param.to_sym] and obj.is_a?(FileSetting)
- return [:owner, :group, :mode].inject({}) do |meta, p|
- if v = obj.send(p)
- meta[p] = v
- end
- meta
- end
- else
- nil
- end
- end
-
- # Make a directory with the appropriate user, group, and mode
- def mkdir(default)
- obj = get_config_file_default(default)
-
- Puppet::Util::SUIDManager.asuser(obj.owner, obj.group) do
- mode = obj.mode || 0750
- Dir.mkdir(obj.value, mode)
- end
- end
-
- # Figure out the section name for the run_mode.
- def run_mode
- Puppet.run_mode.name
- end
-
- # Return all of the parameters associated with a given section.
- def params(section = nil)
- if section
- section = section.intern if section.is_a? String
- @config.find_all { |name, obj|
- obj.section == section
- }.collect { |name, obj|
- name
- }
- else
- @config.keys
- end
- end
-
- # Parse the configuration file. Just provides
- # thread safety.
- def parse
- raise "No :config setting defined; cannot parse unknown config file" unless self[:config]
-
- @sync.synchronize do
- unsafe_parse(self[:config])
- end
-
- # Create a timer so that this file will get checked automatically
- # and reparsed if necessary.
- set_filetimeout_timer
- end
-
- # Unsafely parse the file -- this isn't thread-safe and causes plenty of problems if used directly.
- def unsafe_parse(file)
- return unless FileTest.exist?(file)
- begin
- data = parse_file(file)
- rescue => details
- puts details.backtrace if Puppet[:trace]
- Puppet.err "Could not parse #{file}: #{details}"
- return
- end
-
- unsafe_clear(true)
-
- metas = {}
- data.each do |area, values|
- metas[area] = values.delete(:_meta)
- values.each do |key,value|
- set_value(key, value, area, :dont_trigger_handles => true, :ignore_bad_settings => true )
- end
- end
-
- # Determine our environment, if we have one.
- if @config[:environment]
- env = self.value(:environment).to_sym
- else
- env = "none"
- end
-
- # Call any hooks we should be calling.
- settings_with_hooks.each do |setting|
- each_source(env) do |source|
- if value = @values[source][setting.name]
- # We still have to use value to retrieve the value, since
- # we want the fully interpolated value, not $vardir/lib or whatever.
- # This results in extra work, but so few of the settings
- # will have associated hooks that it ends up being less work this
- # way overall.
- setting.handle(self.value(setting.name, env))
- break
- end
- end
- end
-
- # We have to do it in the reverse of the search path,
- # because multiple sections could set the same value
- # and I'm too lazy to only set the metadata once.
- searchpath.reverse.each do |source|
- source = run_mode if source == :run_mode
- source = @name if (@name && source == :name)
- if meta = metas[source]
- set_metadata(meta)
- end
- end
- end
-
- # Create a new setting. The value is passed in because it's used to determine
- # what kind of setting we're creating, but the value itself might be either
- # a default or a value, so we can't actually assign it.
- def newsetting(hash)
- klass = nil
- hash[:section] = hash[:section].to_sym if hash[:section]
- if type = hash[:type]
- unless klass = {:setting => Setting, :file => FileSetting, :boolean => BooleanSetting}[type]
- raise ArgumentError, "Invalid setting type '#{type}'"
- end
- hash.delete(:type)
- else
- case hash[:default]
- when true, false, "true", "false"
- klass = BooleanSetting
- when /^\$\w+\//, /^\//, /^\w:\//
- klass = FileSetting
- when String, Integer, Float # nothing
- klass = Setting
- else
- raise ArgumentError, "Invalid value '#{hash[:default].inspect}' for #{hash[:name]}"
- end
- end
- hash[:settings] = self
- setting = klass.new(hash)
-
- setting
- end
-
- # This has to be private, because it doesn't add the settings to @config
- private :newsetting
-
- # Iterate across all of the objects in a given section.
- def persection(section)
- section = section.to_sym
- self.each { |name, obj|
- if obj.section == section
- yield obj
- end
- }
- end
-
- # Cache this in an easily clearable way, since we were
- # having trouble cleaning it up after tests.
- cached_attr(:file) do
- if path = self[:config] and FileTest.exist?(path)
- Puppet::Util::LoadedFile.new(path)
- end
- end
-
- # Reparse our config file, if necessary.
- def reparse
- if file and file.changed?
- Puppet.notice "Reparsing #{file.file}"
- parse
- reuse
- end
- end
-
- def reuse
- return unless defined?(@used)
- @sync.synchronize do # yay, thread-safe
- new = @used
- @used = []
- self.use(*new)
- end
- end
-
- # The order in which to search for values.
- def searchpath(environment = nil)
- if environment
- [:cli, :memory, environment, :run_mode, :main, :mutable_defaults]
+ include Enumerable
+ include Puppet::Util::Cacher
+
+ require 'puppet/util/settings/setting'
+ require 'puppet/util/settings/file_setting'
+ require 'puppet/util/settings/boolean_setting'
+
+ attr_accessor :file
+ attr_reader :timer
+
+ ReadOnly = [:run_mode, :name]
+
+ # Retrieve a config value
+ def [](param)
+ value(param)
+ end
+
+ # Set a config value. This doesn't set the defaults, it sets the value itself.
+ def []=(param, value)
+ set_value(param, value, :memory)
+ end
+
+ # Generate the list of valid arguments, in a format that GetoptLong can
+ # understand, and add them to the passed option list.
+ def addargs(options)
+ # Add all of the config parameters as valid options.
+ self.each { |name, setting|
+ setting.getopt_args.each { |args| options << args }
+ }
+
+ options
+ end
+
+ # Generate the list of valid arguments, in a format that OptionParser can
+ # understand, and add them to the passed option list.
+ def optparse_addargs(options)
+ # Add all of the config parameters as valid options.
+ self.each { |name, setting|
+ options << setting.optparse_args
+ }
+
+ options
+ end
+
+ # Is our parameter a boolean parameter?
+ def boolean?(param)
+ param = param.to_sym
+ !!(@config.include?(param) and @config[param].kind_of? BooleanSetting)
+ end
+
+ # Remove all set values, potentially skipping cli values.
+ def clear(exceptcli = false)
+ @sync.synchronize do
+ unsafe_clear(exceptcli)
+ end
+ end
+
+ # Remove all set values, potentially skipping cli values.
+ def unsafe_clear(exceptcli = false)
+ @values.each do |name, values|
+ @values.delete(name) unless exceptcli and name == :cli
+ end
+
+ # Don't clear the 'used' in this case, since it's a config file reparse,
+ # and we want to retain this info.
+ @used = [] unless exceptcli
+
+ @cache.clear
+ end
+
+ # This is mostly just used for testing.
+ def clearused
+ @cache.clear
+ @used = []
+ end
+
+ # Do variable interpolation on the value.
+ def convert(value, environment = nil)
+ return value unless value
+ return value unless value.is_a? String
+ newval = value.gsub(/\$(\w+)|\$\{(\w+)\}/) do |value|
+ varname = $2 || $1
+ if varname == "environment" and environment
+ environment
+ elsif pval = self.value(varname)
+ pval
+ else
+ raise Puppet::DevError, "Could not find value for #{value}"
+ end
+ end
+
+ newval
+ end
+
+ # Return a value's description.
+ def description(name)
+ if obj = @config[name.to_sym]
+ obj.desc
+ else
+ nil
+ end
+ end
+
+ def each
+ @config.each { |name, object|
+ yield name, object
+ }
+ end
+
+ # Iterate over each section name.
+ def eachsection
+ yielded = []
+ @config.each do |name, object|
+ section = object.section
+ unless yielded.include? section
+ yield section
+ yielded << section
+ end
+ end
+ end
+
+ # Return an object by name.
+ def setting(param)
+ param = param.to_sym
+ @config[param]
+ end
+
+ # Handle a command-line argument.
+ def handlearg(opt, value = nil)
+ @cache.clear
+ value &&= munge_value(value)
+ str = opt.sub(/^--/,'')
+
+ bool = true
+ newstr = str.sub(/^no-/, '')
+ if newstr != str
+ str = newstr
+ bool = false
+ end
+ str = str.intern
+
+ if @config[str].is_a?(Puppet::Util::Settings::BooleanSetting)
+ if value == "" or value.nil?
+ value = bool
+ end
+ end
+
+ set_value(str, value, :cli)
+ end
+
+ def without_noop
+ old_noop = value(:noop,:cli) and set_value(:noop, false, :cli) if valid?(:noop)
+ yield
+ ensure
+ set_value(:noop, old_noop, :cli) if valid?(:noop)
+ end
+
+ def include?(name)
+ name = name.intern if name.is_a? String
+ @config.include?(name)
+ end
+
+ # check to see if a short name is already defined
+ def shortinclude?(short)
+ short = short.intern if name.is_a? String
+ @shortnames.include?(short)
+ end
+
+ # Create a new collection of config settings.
+ def initialize
+ @config = {}
+ @shortnames = {}
+
+ @created = []
+ @searchpath = nil
+
+ # Mutex-like thing to protect @values
+ @sync = Sync.new
+
+ # Keep track of set values.
+ @values = Hash.new { |hash, key| hash[key] = {} }
+
+ # And keep a per-environment cache
+ @cache = Hash.new { |hash, key| hash[key] = {} }
+
+ # The list of sections we've used.
+ @used = []
+ end
+
+ # NOTE: ACS ahh the util classes. . .sigh
+ # as part of a fix for 1183, I pulled the logic for the following 5 methods out of the executables and puppet.rb
+ # They probably deserve their own class, but I don't want to do that until I can refactor environments
+ # its a little better than where they were
+
+ # Prints the contents of a config file with the available config settings, or it
+ # prints a single value of a config setting.
+ def print_config_options
+ env = value(:environment)
+ val = value(:configprint)
+ if val == "all"
+ hash = {}
+ each do |name, obj|
+ val = value(name,env)
+ val = val.inspect if val == ""
+ hash[name] = val
+ end
+ hash.sort { |a,b| a[0].to_s <=> b[0].to_s }.each do |name, val|
+ puts "#{name} = #{val}"
+ end
+ else
+ val.split(/\s*,\s*/).sort.each do |v|
+ if include?(v)
+ #if there is only one value, just print it for back compatibility
+ if v == val
+ puts value(val,env)
+ break
+ end
+ puts "#{v} = #{value(v,env)}"
else
- [:cli, :memory, :run_mode, :main, :mutable_defaults]
- end
- end
-
- # Get a list of objects per section
- def sectionlist
- sectionlist = []
- self.each { |name, obj|
- section = obj.section || "puppet"
- sections[section] ||= []
- sectionlist << section unless sectionlist.include?(section)
- sections[section] << obj
- }
-
- return sectionlist, sections
- end
-
- def service_user_available?
- return @service_user_available if defined?(@service_user_available)
-
- return @service_user_available = false unless user_name = self[:user]
-
- user = Puppet::Type.type(:user).new :name => self[:user], :audit => :ensure
-
- @service_user_available = user.exists?
- end
-
- def legacy_to_mode(type, param)
- if not defined?(@app_names)
- require 'puppet/util/command_line'
- command_line = Puppet::Util::CommandLine.new
- @app_names = Puppet::Util::CommandLine::LegacyName.inject({}) do |hash, pair|
- app, legacy = pair
- command_line.require_application app
- hash[legacy.to_sym] = Puppet::Application.find(app).run_mode.name
- hash
- end
- end
- if new_type = @app_names[type]
- Puppet.warning "You have configuration parameter $#{param} specified in [#{type}], which is a deprecated section. I'm assuming you meant [#{new_type}]"
- return new_type
- end
- type
- end
-
- def set_value(param, value, type, options = {})
- param = param.to_sym
- unless setting = @config[param]
- if options[:ignore_bad_settings]
- return
- else
- raise ArgumentError,
- "Attempt to assign a value to unknown configuration parameter #{param.inspect}"
- end
- end
- value = setting.munge(value) if setting.respond_to?(:munge)
- setting.handle(value) if setting.respond_to?(:handle) and not options[:dont_trigger_handles]
- if ReadOnly.include? param and type != :mutable_defaults
- raise ArgumentError,
- "You're attempting to set configuration parameter $#{param}, which is read-only."
- end
- type = legacy_to_mode(type, param)
- @sync.synchronize do # yay, thread-safe
- @values[type][param] = value
- @cache.clear
-
- clearused
-
- # Clear the list of environments, because they cache, at least, the module path.
- # We *could* preferentially just clear them if the modulepath is changed,
- # but we don't really know if, say, the vardir is changed and the modulepath
- # is defined relative to it. We need the defined?(stuff) because of loading
- # order issues.
- Puppet::Node::Environment.clear if defined?(Puppet::Node) and defined?(Puppet::Node::Environment)
- end
-
- value
- end
-
- # Set a bunch of defaults in a given section. The sections are actually pretty
- # pointless, but they help break things up a bit, anyway.
- def setdefaults(section, defs)
- section = section.to_sym
- call = []
- defs.each { |name, hash|
- if hash.is_a? Array
- unless hash.length == 2
- raise ArgumentError, "Defaults specified as an array must contain only the default value and the decription"
- end
- tmp = hash
- hash = {}
- [:default, :desc].zip(tmp).each { |p,v| hash[p] = v }
- end
- name = name.to_sym
- hash[:name] = name
- hash[:section] = section
- raise ArgumentError, "Parameter #{name} is already defined" if @config.include?(name)
- tryconfig = newsetting(hash)
- if short = tryconfig.short
- if other = @shortnames[short]
- raise ArgumentError, "Parameter #{other.name} is already using short name '#{short}'"
- end
- @shortnames[short] = tryconfig
- end
- @config[name] = tryconfig
-
- # Collect the settings that need to have their hooks called immediately.
- # We have to collect them so that we can be sure we're fully initialized before
- # the hook is called.
- call << tryconfig if tryconfig.call_on_define
- }
-
- call.each { |setting| setting.handle(self.value(setting.name)) }
- end
-
- # Create a timer to check whether the file should be reparsed.
- def set_filetimeout_timer
- return unless timeout = self[:filetimeout] and timeout = Integer(timeout) and timeout > 0
- timer = EventLoop::Timer.new(:interval => timeout, :tolerance => 1, :start? => true) { self.reparse }
- end
-
- # Convert the settings we manage into a catalog full of resources that model those settings.
- def to_catalog(*sections)
- sections = nil if sections.empty?
-
- catalog = Puppet::Resource::Catalog.new("Settings")
-
- @config.values.find_all { |value| value.is_a?(FileSetting) }.each do |file|
- next unless (sections.nil? or sections.include?(file.section))
- next unless resource = file.to_resource
- next if catalog.resource(resource.ref)
-
- catalog.add_resource(resource)
- end
-
- add_user_resources(catalog, sections)
-
- catalog
- end
-
- # Convert our list of config settings into a configuration file.
- def to_config
- str = %{The configuration file for #{Puppet[:name]}. Note that this file
+ puts "invalid parameter: #{v}"
+ return false
+ end
+ end
+ end
+ true
+ end
+
+ def generate_config
+ puts to_config
+ true
+ end
+
+ def generate_manifest
+ puts to_manifest
+ true
+ end
+
+ def print_configs
+ return print_config_options if value(:configprint) != ""
+ return generate_config if value(:genconfig)
+ generate_manifest if value(:genmanifest)
+ end
+
+ def print_configs?
+ (value(:configprint) != "" || value(:genconfig) || value(:genmanifest)) && true
+ end
+
+ # Return a given object's file metadata.
+ def metadata(param)
+ if obj = @config[param.to_sym] and obj.is_a?(FileSetting)
+ return [:owner, :group, :mode].inject({}) do |meta, p|
+ if v = obj.send(p)
+ meta[p] = v
+ end
+ meta
+ end
+ else
+ nil
+ end
+ end
+
+ # Make a directory with the appropriate user, group, and mode
+ def mkdir(default)
+ obj = get_config_file_default(default)
+
+ Puppet::Util::SUIDManager.asuser(obj.owner, obj.group) do
+ mode = obj.mode || 0750
+ Dir.mkdir(obj.value, mode)
+ end
+ end
+
+ # Figure out the section name for the run_mode.
+ def run_mode
+ Puppet.run_mode.name
+ end
+
+ # Return all of the parameters associated with a given section.
+ def params(section = nil)
+ if section
+ section = section.intern if section.is_a? String
+ @config.find_all { |name, obj|
+ obj.section == section
+ }.collect { |name, obj|
+ name
+ }
+ else
+ @config.keys
+ end
+ end
+
+ # Parse the configuration file. Just provides
+ # thread safety.
+ def parse
+ raise "No :config setting defined; cannot parse unknown config file" unless self[:config]
+
+ @sync.synchronize do
+ unsafe_parse(self[:config])
+ end
+
+ # Create a timer so that this file will get checked automatically
+ # and reparsed if necessary.
+ set_filetimeout_timer
+ end
+
+ # Unsafely parse the file -- this isn't thread-safe and causes plenty of problems if used directly.
+ def unsafe_parse(file)
+ return unless FileTest.exist?(file)
+ begin
+ data = parse_file(file)
+ rescue => details
+ puts details.backtrace if Puppet[:trace]
+ Puppet.err "Could not parse #{file}: #{details}"
+ return
+ end
+
+ unsafe_clear(true)
+
+ metas = {}
+ data.each do |area, values|
+ metas[area] = values.delete(:_meta)
+ values.each do |key,value|
+ set_value(key, value, area, :dont_trigger_handles => true, :ignore_bad_settings => true )
+ end
+ end
+
+ # Determine our environment, if we have one.
+ if @config[:environment]
+ env = self.value(:environment).to_sym
+ else
+ env = "none"
+ end
+
+ # Call any hooks we should be calling.
+ settings_with_hooks.each do |setting|
+ each_source(env) do |source|
+ if value = @values[source][setting.name]
+ # We still have to use value to retrieve the value, since
+ # we want the fully interpolated value, not $vardir/lib or whatever.
+ # This results in extra work, but so few of the settings
+ # will have associated hooks that it ends up being less work this
+ # way overall.
+ setting.handle(self.value(setting.name, env))
+ break
+ end
+ end
+ end
+
+ # We have to do it in the reverse of the search path,
+ # because multiple sections could set the same value
+ # and I'm too lazy to only set the metadata once.
+ searchpath.reverse.each do |source|
+ source = run_mode if source == :run_mode
+ source = @name if (@name && source == :name)
+ if meta = metas[source]
+ set_metadata(meta)
+ end
+ end
+ end
+
+ # Create a new setting. The value is passed in because it's used to determine
+ # what kind of setting we're creating, but the value itself might be either
+ # a default or a value, so we can't actually assign it.
+ def newsetting(hash)
+ klass = nil
+ hash[:section] = hash[:section].to_sym if hash[:section]
+ if type = hash[:type]
+ unless klass = {:setting => Setting, :file => FileSetting, :boolean => BooleanSetting}[type]
+ raise ArgumentError, "Invalid setting type '#{type}'"
+ end
+ hash.delete(:type)
+ else
+ case hash[:default]
+ when true, false, "true", "false"
+ klass = BooleanSetting
+ when /^\$\w+\//, /^\//, /^\w:\//
+ klass = FileSetting
+ when String, Integer, Float # nothing
+ klass = Setting
+ else
+ raise ArgumentError, "Invalid value '#{hash[:default].inspect}' for #{hash[:name]}"
+ end
+ end
+ hash[:settings] = self
+ setting = klass.new(hash)
+
+ setting
+ end
+
+ # This has to be private, because it doesn't add the settings to @config
+ private :newsetting
+
+ # Iterate across all of the objects in a given section.
+ def persection(section)
+ section = section.to_sym
+ self.each { |name, obj|
+ if obj.section == section
+ yield obj
+ end
+ }
+ end
+
+ # Cache this in an easily clearable way, since we were
+ # having trouble cleaning it up after tests.
+ cached_attr(:file) do
+ if path = self[:config] and FileTest.exist?(path)
+ Puppet::Util::LoadedFile.new(path)
+ end
+ end
+
+ # Reparse our config file, if necessary.
+ def reparse
+ if file and file.changed?
+ Puppet.notice "Reparsing #{file.file}"
+ parse
+ reuse
+ end
+ end
+
+ def reuse
+ return unless defined?(@used)
+ @sync.synchronize do # yay, thread-safe
+ new = @used
+ @used = []
+ self.use(*new)
+ end
+ end
+
+ # The order in which to search for values.
+ def searchpath(environment = nil)
+ if environment
+ [:cli, :memory, environment, :run_mode, :main, :mutable_defaults]
+ else
+ [:cli, :memory, :run_mode, :main, :mutable_defaults]
+ end
+ end
+
+ # Get a list of objects per section
+ def sectionlist
+ sectionlist = []
+ self.each { |name, obj|
+ section = obj.section || "puppet"
+ sections[section] ||= []
+ sectionlist << section unless sectionlist.include?(section)
+ sections[section] << obj
+ }
+
+ return sectionlist, sections
+ end
+
+ def service_user_available?
+ return @service_user_available if defined?(@service_user_available)
+
+ return @service_user_available = false unless user_name = self[:user]
+
+ user = Puppet::Type.type(:user).new :name => self[:user], :audit => :ensure
+
+ @service_user_available = user.exists?
+ end
+
+ def legacy_to_mode(type, param)
+ if not defined?(@app_names)
+ require 'puppet/util/command_line'
+ command_line = Puppet::Util::CommandLine.new
+ @app_names = Puppet::Util::CommandLine::LegacyName.inject({}) do |hash, pair|
+ app, legacy = pair
+ command_line.require_application app
+ hash[legacy.to_sym] = Puppet::Application.find(app).run_mode.name
+ hash
+ end
+ end
+ if new_type = @app_names[type]
+ Puppet.warning "You have configuration parameter $#{param} specified in [#{type}], which is a deprecated section. I'm assuming you meant [#{new_type}]"
+ return new_type
+ end
+ type
+ end
+
+ def set_value(param, value, type, options = {})
+ param = param.to_sym
+ unless setting = @config[param]
+ if options[:ignore_bad_settings]
+ return
+ else
+ raise ArgumentError,
+ "Attempt to assign a value to unknown configuration parameter #{param.inspect}"
+ end
+ end
+ value = setting.munge(value) if setting.respond_to?(:munge)
+ setting.handle(value) if setting.respond_to?(:handle) and not options[:dont_trigger_handles]
+ if ReadOnly.include? param and type != :mutable_defaults
+ raise ArgumentError,
+ "You're attempting to set configuration parameter $#{param}, which is read-only."
+ end
+ type = legacy_to_mode(type, param)
+ @sync.synchronize do # yay, thread-safe
+ @values[type][param] = value
+ @cache.clear
+
+ clearused
+
+ # Clear the list of environments, because they cache, at least, the module path.
+ # We *could* preferentially just clear them if the modulepath is changed,
+ # but we don't really know if, say, the vardir is changed and the modulepath
+ # is defined relative to it. We need the defined?(stuff) because of loading
+ # order issues.
+ Puppet::Node::Environment.clear if defined?(Puppet::Node) and defined?(Puppet::Node::Environment)
+ end
+
+ value
+ end
+
+ # Set a bunch of defaults in a given section. The sections are actually pretty
+ # pointless, but they help break things up a bit, anyway.
+ def setdefaults(section, defs)
+ section = section.to_sym
+ call = []
+ defs.each { |name, hash|
+ if hash.is_a? Array
+ unless hash.length == 2
+ raise ArgumentError, "Defaults specified as an array must contain only the default value and the decription"
+ end
+ tmp = hash
+ hash = {}
+ [:default, :desc].zip(tmp).each { |p,v| hash[p] = v }
+ end
+ name = name.to_sym
+ hash[:name] = name
+ hash[:section] = section
+ raise ArgumentError, "Parameter #{name} is already defined" if @config.include?(name)
+ tryconfig = newsetting(hash)
+ if short = tryconfig.short
+ if other = @shortnames[short]
+ raise ArgumentError, "Parameter #{other.name} is already using short name '#{short}'"
+ end
+ @shortnames[short] = tryconfig
+ end
+ @config[name] = tryconfig
+
+ # Collect the settings that need to have their hooks called immediately.
+ # We have to collect them so that we can be sure we're fully initialized before
+ # the hook is called.
+ call << tryconfig if tryconfig.call_on_define
+ }
+
+ call.each { |setting| setting.handle(self.value(setting.name)) }
+ end
+
+ # Create a timer to check whether the file should be reparsed.
+ def set_filetimeout_timer
+ return unless timeout = self[:filetimeout] and timeout = Integer(timeout) and timeout > 0
+ timer = EventLoop::Timer.new(:interval => timeout, :tolerance => 1, :start? => true) { self.reparse }
+ end
+
+ # Convert the settings we manage into a catalog full of resources that model those settings.
+ def to_catalog(*sections)
+ sections = nil if sections.empty?
+
+ catalog = Puppet::Resource::Catalog.new("Settings")
+
+ @config.values.find_all { |value| value.is_a?(FileSetting) }.each do |file|
+ next unless (sections.nil? or sections.include?(file.section))
+ next unless resource = file.to_resource
+ next if catalog.resource(resource.ref)
+
+ catalog.add_resource(resource)
+ end
+
+ add_user_resources(catalog, sections)
+
+ catalog
+ end
+
+ # Convert our list of config settings into a configuration file.
+ def to_config
+ str = %{The configuration file for #{Puppet[:name]}. Note that this file
is likely to have unused configuration parameters in it; any parameter that's
valid anywhere in Puppet can be in any config file, even if it's not used.
@@ -596,346 +596,346 @@ Generated on #{Time.now}.
# Add a section heading that matches our name.
if @config.include?(:run_mode)
- str += "[#{self[:run_mode]}]\n"
- end
- eachsection do |section|
- persection(section) do |obj|
- str += obj.to_config + "\n" unless ReadOnly.include? obj.name
- end
- end
-
- return str
- end
-
- # Convert to a parseable manifest
- def to_manifest
- catalog = to_catalog
- catalog.resource_refs.collect do |ref|
- catalog.resource(ref).to_manifest
- end.join("\n\n")
- end
-
- # Create the necessary objects to use a section. This is idempotent;
- # you can 'use' a section as many times as you want.
- def use(*sections)
- sections = sections.collect { |s| s.to_sym }
- @sync.synchronize do # yay, thread-safe
- sections = sections.reject { |s| @used.include?(s) }
-
- return if sections.empty?
-
- begin
- catalog = to_catalog(*sections).to_ral
- rescue => detail
- puts detail.backtrace if Puppet[:trace]
- Puppet.err "Could not create resources for managing Puppet's files and directories in sections #{sections.inspect}: #{detail}"
-
- # We need some way to get rid of any resources created during the catalog creation
- # but not cleaned up.
- return
- end
-
- without_noop do
- catalog.host_config = false
- catalog.apply do |transaction|
- if transaction.any_failed?
- report = transaction.report
- failures = report.logs.find_all { |log| log.level == :err }
- raise "Got #{failures.length} failure(s) while initializing: #{failures.collect { |l| l.to_s }.join("; ")}"
- end
- end
- end
-
- sections.each { |s| @used << s }
- @used.uniq!
- end
- end
-
- def valid?(param)
- param = param.to_sym
- @config.has_key?(param)
- end
-
- def uninterpolated_value(param, environment = nil)
- param = param.to_sym
- environment &&= environment.to_sym
-
- # See if we can find it within our searchable list of values
- val = catch :foundval do
- each_source(environment) do |source|
- # Look for the value. We have to test the hash for whether
- # it exists, because the value might be false.
- @sync.synchronize do
- throw :foundval, @values[source][param] if @values[source].include?(param)
- end
- end
- throw :foundval, nil
+ str += "[#{self[:run_mode]}]\n"
+ end
+ eachsection do |section|
+ persection(section) do |obj|
+ str += obj.to_config + "\n" unless ReadOnly.include? obj.name
+ end
+ end
+
+ return str
+ end
+
+ # Convert to a parseable manifest
+ def to_manifest
+ catalog = to_catalog
+ catalog.resource_refs.collect do |ref|
+ catalog.resource(ref).to_manifest
+ end.join("\n\n")
+ end
+
+ # Create the necessary objects to use a section. This is idempotent;
+ # you can 'use' a section as many times as you want.
+ def use(*sections)
+ sections = sections.collect { |s| s.to_sym }
+ @sync.synchronize do # yay, thread-safe
+ sections = sections.reject { |s| @used.include?(s) }
+
+ return if sections.empty?
+
+ begin
+ catalog = to_catalog(*sections).to_ral
+ rescue => detail
+ puts detail.backtrace if Puppet[:trace]
+ Puppet.err "Could not create resources for managing Puppet's files and directories in sections #{sections.inspect}: #{detail}"
+
+ # We need some way to get rid of any resources created during the catalog creation
+ # but not cleaned up.
+ return
+ end
+
+ without_noop do
+ catalog.host_config = false
+ catalog.apply do |transaction|
+ if transaction.any_failed?
+ report = transaction.report
+ failures = report.logs.find_all { |log| log.level == :err }
+ raise "Got #{failures.length} failure(s) while initializing: #{failures.collect { |l| l.to_s }.join("; ")}"
+ end
+ end
+ end
+
+ sections.each { |s| @used << s }
+ @used.uniq!
+ end
+ end
+
+ def valid?(param)
+ param = param.to_sym
+ @config.has_key?(param)
+ end
+
+ def uninterpolated_value(param, environment = nil)
+ param = param.to_sym
+ environment &&= environment.to_sym
+
+ # See if we can find it within our searchable list of values
+ val = catch :foundval do
+ each_source(environment) do |source|
+ # Look for the value. We have to test the hash for whether
+ # it exists, because the value might be false.
+ @sync.synchronize do
+ throw :foundval, @values[source][param] if @values[source].include?(param)
end
-
- # If we didn't get a value, use the default
- val = @config[param].default if val.nil?
-
- val
+ end
+ throw :foundval, nil
end
- # Find the correct value using our search path. Optionally accept an environment
- # in which to search before the other configuration sections.
- def value(param, environment = nil)
- param = param.to_sym
- environment &&= environment.to_sym
-
- # Short circuit to nil for undefined parameters.
- return nil unless @config.include?(param)
+ # If we didn't get a value, use the default
+ val = @config[param].default if val.nil?
- # Yay, recursion.
- #self.reparse unless [:config, :filetimeout].include?(param)
+ val
+ end
- # Check the cache first. It needs to be a per-environment
- # cache so that we don't spread values from one env
- # to another.
- if cached = @cache[environment||"none"][param]
- return cached
- end
-
- val = uninterpolated_value(param, environment)
+ # Find the correct value using our search path. Optionally accept an environment
+ # in which to search before the other configuration sections.
+ def value(param, environment = nil)
+ param = param.to_sym
+ environment &&= environment.to_sym
- if param == :code
- # if we interpolate code, all hell breaks loose.
- return val
- end
+ # Short circuit to nil for undefined parameters.
+ return nil unless @config.include?(param)
- # Convert it if necessary
- val = convert(val, environment)
+ # Yay, recursion.
+ #self.reparse unless [:config, :filetimeout].include?(param)
- # And cache it
- @cache[environment||"none"][param] = val
- val
+ # Check the cache first. It needs to be a per-environment
+ # cache so that we don't spread values from one env
+ # to another.
+ if cached = @cache[environment||"none"][param]
+ return cached
end
- # Open a file with the appropriate user, group, and mode
- def write(default, *args, &bloc)
- obj = get_config_file_default(default)
- writesub(default, value(obj.name), *args, &bloc)
- end
+ val = uninterpolated_value(param, environment)
- # Open a non-default file under a default dir with the appropriate user,
- # group, and mode
- def writesub(default, file, *args, &bloc)
- obj = get_config_file_default(default)
- chown = nil
- if Puppet.features.root?
- chown = [obj.owner, obj.group]
- else
- chown = [nil, nil]
- end
-
- Puppet::Util::SUIDManager.asuser(*chown) do
- mode = obj.mode || 0640
- args << "w" if args.empty?
-
- args << mode
-
- # Update the umask to make non-executable files
- Puppet::Util.withumask(File.umask ^ 0111) do
- File.open(file, *args) do |file|
- yield file
- end
- end
- end
- end
-
- def readwritelock(default, *args, &bloc)
- file = value(get_config_file_default(default).name)
- tmpfile = file + ".tmp"
- sync = Sync.new
- raise Puppet::DevError, "Cannot create #{file}; directory #{File.dirname(file)} does not exist" unless FileTest.directory?(File.dirname(tmpfile))
-
- sync.synchronize(Sync::EX) do
- File.open(file, ::File::CREAT|::File::RDWR, 0600) do |rf|
- rf.lock_exclusive do
- if File.exist?(tmpfile)
- raise Puppet::Error, ".tmp file already exists for #{file}; Aborting locked write. Check the .tmp file and delete if appropriate"
- end
-
- # If there's a failure, remove our tmpfile
- begin
- writesub(default, tmpfile, *args, &bloc)
- rescue
- File.unlink(tmpfile) if FileTest.exist?(tmpfile)
- raise
- end
-
- begin
- File.rename(tmpfile, file)
- rescue => detail
- Puppet.err "Could not rename #{file} to #{tmpfile}: #{detail}"
- File.unlink(tmpfile) if FileTest.exist?(tmpfile)
- end
- end
- end
- end
+ if param == :code
+ # if we interpolate code, all hell breaks loose.
+ return val
end
- private
+ # Convert it if necessary
+ val = convert(val, environment)
- def get_config_file_default(default)
- obj = nil
- unless obj = @config[default]
- raise ArgumentError, "Unknown default #{default}"
- end
+ # And cache it
+ @cache[environment||"none"][param] = val
+ val
+ end
- raise ArgumentError, "Default #{default} is not a file" unless obj.is_a? FileSetting
+ # Open a file with the appropriate user, group, and mode
+ def write(default, *args, &bloc)
+ obj = get_config_file_default(default)
+ writesub(default, value(obj.name), *args, &bloc)
+ end
- obj
+ # Open a non-default file under a default dir with the appropriate user,
+ # group, and mode
+ def writesub(default, file, *args, &bloc)
+ obj = get_config_file_default(default)
+ chown = nil
+ if Puppet.features.root?
+ chown = [obj.owner, obj.group]
+ else
+ chown = [nil, nil]
end
- # Create the transportable objects for users and groups.
- def add_user_resources(catalog, sections)
- return unless Puppet.features.root?
- return unless self[:mkusers]
-
- @config.each do |name, setting|
- next unless setting.respond_to?(:owner)
- next unless sections.nil? or sections.include?(setting.section)
+ Puppet::Util::SUIDManager.asuser(*chown) do
+ mode = obj.mode || 0640
+ args << "w" if args.empty?
- if user = setting.owner and user != "root" and catalog.resource(:user, user).nil?
- resource = Puppet::Resource.new(:user, user, :parameters => {:ensure => :present})
- resource[:gid] = self[:group] if self[:group]
- catalog.add_resource resource
- end
- if group = setting.group and ! %w{root wheel}.include?(group) and catalog.resource(:group, group).nil?
- catalog.add_resource Puppet::Resource.new(:group, group, :parameters => {:ensure => :present})
- end
- end
- end
+ args << mode
- # Yield each search source in turn.
- def each_source(environment)
- searchpath(environment).each do |source|
- # Modify the source as necessary.
- source = self.run_mode if source == :run_mode
- yield source
- end
- end
-
- # Return all settings that have associated hooks; this is so
- # we can call them after parsing the configuration file.
- def settings_with_hooks
- @config.values.find_all { |setting| setting.respond_to?(:handle) }
- end
-
- # Extract extra setting information for files.
- def extract_fileinfo(string)
- result = {}
- value = string.sub(/\{\s*([^}]+)\s*\}/) do
- params = $1
- params.split(/\s*,\s*/).each do |str|
- if str =~ /^\s*(\w+)\s*=\s*([\w\d]+)\s*$/
- param, value = $1.intern, $2
- result[param] = value
- raise ArgumentError, "Invalid file option '#{param}'" unless [:owner, :mode, :group].include?(param)
-
- if param == :mode and value !~ /^\d+$/
- raise ArgumentError, "File modes must be numbers"
- end
- else
- raise ArgumentError, "Could not parse '#{string}'"
- end
- end
- ''
- end
- result[:value] = value.sub(/\s*$/, '')
- result
- end
-
- # Convert arguments into booleans, integers, or whatever.
- def munge_value(value)
- # Handle different data types correctly
- return case value
- when /^false$/i; false
- when /^true$/i; true
- when /^\d+$/i; Integer(value)
- when true; true
- when false; false
- else
- value.gsub(/^["']|["']$/,'').sub(/\s+$/, '')
+ # Update the umask to make non-executable files
+ Puppet::Util.withumask(File.umask ^ 0111) do
+ File.open(file, *args) do |file|
+ yield file
+ end
+ end
+ end
+ end
+
+ def readwritelock(default, *args, &bloc)
+ file = value(get_config_file_default(default).name)
+ tmpfile = file + ".tmp"
+ sync = Sync.new
+ raise Puppet::DevError, "Cannot create #{file}; directory #{File.dirname(file)} does not exist" unless FileTest.directory?(File.dirname(tmpfile))
+
+ sync.synchronize(Sync::EX) do
+ File.open(file, ::File::CREAT|::File::RDWR, 0600) do |rf|
+ rf.lock_exclusive do
+ if File.exist?(tmpfile)
+ raise Puppet::Error, ".tmp file already exists for #{file}; Aborting locked write. Check the .tmp file and delete if appropriate"
+ end
+
+ # If there's a failure, remove our tmpfile
+ begin
+ writesub(default, tmpfile, *args, &bloc)
+ rescue
+ File.unlink(tmpfile) if FileTest.exist?(tmpfile)
+ raise
+ end
+
+ begin
+ File.rename(tmpfile, file)
+ rescue => detail
+ Puppet.err "Could not rename #{file} to #{tmpfile}: #{detail}"
+ File.unlink(tmpfile) if FileTest.exist?(tmpfile)
+ end
+ end
+ end
+ end
+ end
+
+ private
+
+ def get_config_file_default(default)
+ obj = nil
+ unless obj = @config[default]
+ raise ArgumentError, "Unknown default #{default}"
+ end
+
+ raise ArgumentError, "Default #{default} is not a file" unless obj.is_a? FileSetting
+
+ obj
+ end
+
+ # Create the transportable objects for users and groups.
+ def add_user_resources(catalog, sections)
+ return unless Puppet.features.root?
+ return unless self[:mkusers]
+
+ @config.each do |name, setting|
+ next unless setting.respond_to?(:owner)
+ next unless sections.nil? or sections.include?(setting.section)
+
+ if user = setting.owner and user != "root" and catalog.resource(:user, user).nil?
+ resource = Puppet::Resource.new(:user, user, :parameters => {:ensure => :present})
+ resource[:gid] = self[:group] if self[:group]
+ catalog.add_resource resource
+ end
+ if group = setting.group and ! %w{root wheel}.include?(group) and catalog.resource(:group, group).nil?
+ catalog.add_resource Puppet::Resource.new(:group, group, :parameters => {:ensure => :present})
+ end
+ end
+ end
+
+ # Yield each search source in turn.
+ def each_source(environment)
+ searchpath(environment).each do |source|
+ # Modify the source as necessary.
+ source = self.run_mode if source == :run_mode
+ yield source
+ end
+ end
+
+ # Return all settings that have associated hooks; this is so
+ # we can call them after parsing the configuration file.
+ def settings_with_hooks
+ @config.values.find_all { |setting| setting.respond_to?(:handle) }
+ end
+
+ # Extract extra setting information for files.
+ def extract_fileinfo(string)
+ result = {}
+ value = string.sub(/\{\s*([^}]+)\s*\}/) do
+ params = $1
+ params.split(/\s*,\s*/).each do |str|
+ if str =~ /^\s*(\w+)\s*=\s*([\w\d]+)\s*$/
+ param, value = $1.intern, $2
+ result[param] = value
+ raise ArgumentError, "Invalid file option '#{param}'" unless [:owner, :mode, :group].include?(param)
+
+ if param == :mode and value !~ /^\d+$/
+ raise ArgumentError, "File modes must be numbers"
+ end
+ else
+ raise ArgumentError, "Could not parse '#{string}'"
+ end
+ end
+ ''
+ end
+ result[:value] = value.sub(/\s*$/, '')
+ result
+ end
+
+ # Convert arguments into booleans, integers, or whatever.
+ def munge_value(value)
+ # Handle different data types correctly
+ return case value
+ when /^false$/i; false
+ when /^true$/i; true
+ when /^\d+$/i; Integer(value)
+ when true; true
+ when false; false
+ else
+ value.gsub(/^["']|["']$/,'').sub(/\s+$/, '')
+ end
+ end
+
+ # This method just turns a file in to a hash of hashes.
+ def parse_file(file)
+ text = read_file(file)
+
+ result = Hash.new { |names, name|
+ names[name] = {}
+ }
+
+ count = 0
+
+ # Default to 'main' for the section.
+ section = :main
+ result[section][:_meta] = {}
+ text.split(/\n/).each { |line|
+ count += 1
+ case line
+ when /^\s*\[(\w+)\]\s*$/
+ section = $1.intern # Section names
+ # Add a meta section
+ result[section][:_meta] ||= {}
+ when /^\s*#/; next # Skip comments
+ when /^\s*$/; next # Skip blanks
+ when /^\s*(\w+)\s*=\s*(.*?)\s*$/ # settings
+ var = $1.intern
+
+ # We don't want to munge modes, because they're specified in octal, so we'll
+ # just leave them as a String, since Puppet handles that case correctly.
+ if var == :mode
+ value = $2
+ else
+ value = munge_value($2)
end
- end
- # This method just turns a file in to a hash of hashes.
- def parse_file(file)
- text = read_file(file)
-
- result = Hash.new { |names, name|
- names[name] = {}
- }
-
- count = 0
-
- # Default to 'main' for the section.
- section = :main
- result[section][:_meta] = {}
- text.split(/\n/).each { |line|
- count += 1
- case line
- when /^\s*\[(\w+)\]\s*$/
- section = $1.intern # Section names
- # Add a meta section
- result[section][:_meta] ||= {}
- when /^\s*#/; next # Skip comments
- when /^\s*$/; next # Skip blanks
- when /^\s*(\w+)\s*=\s*(.*?)\s*$/ # settings
- var = $1.intern
-
- # We don't want to munge modes, because they're specified in octal, so we'll
- # just leave them as a String, since Puppet handles that case correctly.
- if var == :mode
- value = $2
- else
- value = munge_value($2)
- end
-
- # Check to see if this is a file argument and it has extra options
- begin
- if value.is_a?(String) and options = extract_fileinfo(value)
- value = options[:value]
- options.delete(:value)
- result[section][:_meta][var] = options
- end
- result[section][var] = value
- rescue Puppet::Error => detail
- detail.file = file
- detail.line = line
- raise
- end
- else
- error = Puppet::Error.new("Could not match line #{line}")
- error.file = file
- error.line = line
- raise error
- end
- }
-
- result
- end
-
- # Read the file in.
- def read_file(file)
+ # Check to see if this is a file argument and it has extra options
begin
- return File.read(file)
- rescue Errno::ENOENT
- raise ArgumentError, "No such file #{file}"
- rescue Errno::EACCES
- raise ArgumentError, "Permission denied to file #{file}"
- end
- end
-
- # Set file metadata.
- def set_metadata(meta)
- meta.each do |var, values|
- values.each do |param, value|
- @config[var].send(param.to_s + "=", value)
- end
- end
- end
+ if value.is_a?(String) and options = extract_fileinfo(value)
+ value = options[:value]
+ options.delete(:value)
+ result[section][:_meta][var] = options
+ end
+ result[section][var] = value
+ rescue Puppet::Error => detail
+ detail.file = file
+ detail.line = line
+ raise
+ end
+ else
+ error = Puppet::Error.new("Could not match line #{line}")
+ error.file = file
+ error.line = line
+ raise error
+ end
+ }
+
+ result
+ end
+
+ # Read the file in.
+ def read_file(file)
+ begin
+ return File.read(file)
+ rescue Errno::ENOENT
+ raise ArgumentError, "No such file #{file}"
+ rescue Errno::EACCES
+ raise ArgumentError, "Permission denied to file #{file}"
+ end
+ end
+
+ # Set file metadata.
+ def set_metadata(meta)
+ meta.each do |var, values|
+ values.each do |param, value|
+ @config[var].send(param.to_s + "=", value)
+ end
+ end
+ end
end
diff --git a/lib/puppet/util/settings/boolean_setting.rb b/lib/puppet/util/settings/boolean_setting.rb
index 67fce9ae3..e4678c9b4 100644
--- a/lib/puppet/util/settings/boolean_setting.rb
+++ b/lib/puppet/util/settings/boolean_setting.rb
@@ -2,29 +2,29 @@ require 'puppet/util/settings/setting'
# A simple boolean.
class Puppet::Util::Settings::BooleanSetting < Puppet::Util::Settings::Setting
- # get the arguments in getopt format
- def getopt_args
- if short
- [["--#{name}", "-#{short}", GetoptLong::NO_ARGUMENT], ["--no-#{name}", GetoptLong::NO_ARGUMENT]]
- else
- [["--#{name}", GetoptLong::NO_ARGUMENT], ["--no-#{name}", GetoptLong::NO_ARGUMENT]]
- end
+ # get the arguments in getopt format
+ def getopt_args
+ if short
+ [["--#{name}", "-#{short}", GetoptLong::NO_ARGUMENT], ["--no-#{name}", GetoptLong::NO_ARGUMENT]]
+ else
+ [["--#{name}", GetoptLong::NO_ARGUMENT], ["--no-#{name}", GetoptLong::NO_ARGUMENT]]
end
+ end
- def optparse_args
- if short
- ["--[no-]#{name}", "-#{short}", desc, :NONE ]
- else
- ["--[no-]#{name}", desc, :NONE]
- end
+ def optparse_args
+ if short
+ ["--[no-]#{name}", "-#{short}", desc, :NONE ]
+ else
+ ["--[no-]#{name}", desc, :NONE]
end
+ end
- def munge(value)
- case value
- when true, "true"; return true
- when false, "false"; return false
- else
- raise ArgumentError, "Invalid value '#{value.inspect}' for #{@name}"
- end
+ def munge(value)
+ case value
+ when true, "true"; return true
+ when false, "false"; return false
+ else
+ raise ArgumentError, "Invalid value '#{value.inspect}' for #{@name}"
end
+ end
end
diff --git a/lib/puppet/util/settings/file_setting.rb b/lib/puppet/util/settings/file_setting.rb
index ee17d7ddc..edbab1d0c 100644
--- a/lib/puppet/util/settings/file_setting.rb
+++ b/lib/puppet/util/settings/file_setting.rb
@@ -2,122 +2,122 @@ require 'puppet/util/settings/setting'
# A file.
class Puppet::Util::Settings::FileSetting < Puppet::Util::Settings::Setting
- AllowedOwners = %w{root service}
- AllowedGroups = %w{root service}
+ AllowedOwners = %w{root service}
+ AllowedGroups = %w{root service}
- class SettingError < StandardError; end
+ class SettingError < StandardError; end
- attr_accessor :mode, :create
+ attr_accessor :mode, :create
- # Should we create files, rather than just directories?
- def create_files?
- create
- end
+ # Should we create files, rather than just directories?
+ def create_files?
+ create
+ end
- def group=(value)
- unless AllowedGroups.include?(value)
- identifying_fields = [desc,name,default].compact.join(': ')
- raise SettingError, "Internal error: The :group setting for #{identifying_fields} must be 'service', not '#{value}'"
- end
- @group = value
+ def group=(value)
+ unless AllowedGroups.include?(value)
+ identifying_fields = [desc,name,default].compact.join(': ')
+ raise SettingError, "Internal error: The :group setting for #{identifying_fields} must be 'service', not '#{value}'"
end
-
- def group
- return unless @group
- @settings[:group]
+ @group = value
+ end
+
+ def group
+ return unless @group
+ @settings[:group]
+ end
+
+ def owner=(value)
+ unless AllowedOwners.include?(value)
+ identifying_fields = [desc,name,default].compact.join(': ')
+ raise SettingError, "Internal error: The :owner setting for #{identifying_fields} must be either 'root' or 'service', not '#{value}'"
end
-
- def owner=(value)
- unless AllowedOwners.include?(value)
- identifying_fields = [desc,name,default].compact.join(': ')
- raise SettingError, "Internal error: The :owner setting for #{identifying_fields} must be either 'root' or 'service', not '#{value}'"
- end
- @owner = value
+ @owner = value
+ end
+
+ def owner
+ return unless @owner
+ return "root" if @owner == "root" or ! use_service_user?
+ @settings[:user]
+ end
+
+ def use_service_user?
+ @settings[:mkusers] or @settings.service_user_available?
+ end
+
+ # Set the type appropriately. Yep, a hack. This supports either naming
+ # the variable 'dir', or adding a slash at the end.
+ def munge(value)
+ # If it's not a fully qualified path...
+ if value.is_a?(String) and value !~ /^\$/ and value != 'false'
+ # Make it one
+ value = File.expand_path(value)
end
-
- def owner
- return unless @owner
- return "root" if @owner == "root" or ! use_service_user?
- @settings[:user]
+ if value.to_s =~ /\/$/
+ @type = :directory
+ return value.sub(/\/$/, '')
end
-
- def use_service_user?
- @settings[:mkusers] or @settings.service_user_available?
+ value
+ end
+
+ # Return the appropriate type.
+ def type
+ value = @settings.value(self.name)
+ if @name.to_s =~ /dir/
+ return :directory
+ elsif value.to_s =~ /\/$/
+ return :directory
+ elsif value.is_a? String
+ return :file
+ else
+ return nil
end
+ end
- # Set the type appropriately. Yep, a hack. This supports either naming
- # the variable 'dir', or adding a slash at the end.
- def munge(value)
- # If it's not a fully qualified path...
- if value.is_a?(String) and value !~ /^\$/ and value != 'false'
- # Make it one
- value = File.expand_path(value)
- end
- if value.to_s =~ /\/$/
- @type = :directory
- return value.sub(/\/$/, '')
- end
- value
- end
+ # Turn our setting thing into a Puppet::Resource instance.
+ def to_resource
+ return nil unless type = self.type
- # Return the appropriate type.
- def type
- value = @settings.value(self.name)
- if @name.to_s =~ /dir/
- return :directory
- elsif value.to_s =~ /\/$/
- return :directory
- elsif value.is_a? String
- return :file
- else
- return nil
- end
- end
+ path = self.value
- # Turn our setting thing into a Puppet::Resource instance.
- def to_resource
- return nil unless type = self.type
+ return nil unless path.is_a?(String)
- path = self.value
+ # Make sure the paths are fully qualified.
+ path = File.expand_path(path)
- return nil unless path.is_a?(String)
+ return nil unless type == :directory or create_files? or File.exist?(path)
+ return nil if path =~ /^\/dev/
- # Make sure the paths are fully qualified.
- path = File.expand_path(path)
+ resource = Puppet::Resource.new(:file, path)
- return nil unless type == :directory or create_files? or File.exist?(path)
- return nil if path =~ /^\/dev/
+ if Puppet[:manage_internal_file_permissions]
+ resource[:mode] = self.mode if self.mode
- resource = Puppet::Resource.new(:file, path)
-
- if Puppet[:manage_internal_file_permissions]
- resource[:mode] = self.mode if self.mode
-
- if Puppet.features.root?
- resource[:owner] = self.owner if self.owner
- resource[:group] = self.group if self.group
- end
- end
-
- resource[:ensure] = type
- resource[:loglevel] = :debug
- resource[:backup] = false
-
- resource.tag(self.section, self.name, "settings")
-
- resource
+ if Puppet.features.root?
+ resource[:owner] = self.owner if self.owner
+ resource[:group] = self.group if self.group
+ end
end
- # Make sure any provided variables look up to something.
- def validate(value)
- return true unless value.is_a? String
- value.scan(/\$(\w+)/) { |name|
- name = $1
- unless @settings.include?(name)
- raise ArgumentError,
- "Settings parameter '#{name}' is undefined"
- end
- }
- end
+ resource[:ensure] = type
+ resource[:loglevel] = :debug
+ resource[:backup] = false
+
+ resource.tag(self.section, self.name, "settings")
+
+ resource
+ end
+
+ # Make sure any provided variables look up to something.
+ def validate(value)
+ return true unless value.is_a? String
+ value.scan(/\$(\w+)/) { |name|
+ name = $1
+ unless @settings.include?(name)
+ raise ArgumentError,
+ "Settings parameter '#{name}' is undefined"
+ end
+ }
+ end
end
diff --git a/lib/puppet/util/settings/setting.rb b/lib/puppet/util/settings/setting.rb
index a14dcf050..07409eefe 100644
--- a/lib/puppet/util/settings/setting.rb
+++ b/lib/puppet/util/settings/setting.rb
@@ -1,94 +1,94 @@
# The base element type.
class Puppet::Util::Settings::Setting
- attr_accessor :name, :section, :default, :setbycli, :call_on_define
- attr_reader :desc, :short
-
- def desc=(value)
- @desc = value.gsub(/^\s*/, '')
+ attr_accessor :name, :section, :default, :setbycli, :call_on_define
+ attr_reader :desc, :short
+
+ def desc=(value)
+ @desc = value.gsub(/^\s*/, '')
+ end
+
+ # get the arguments in getopt format
+ def getopt_args
+ if short
+ [["--#{name}", "-#{short}", GetoptLong::REQUIRED_ARGUMENT]]
+ else
+ [["--#{name}", GetoptLong::REQUIRED_ARGUMENT]]
end
-
- # get the arguments in getopt format
- def getopt_args
- if short
- [["--#{name}", "-#{short}", GetoptLong::REQUIRED_ARGUMENT]]
- else
- [["--#{name}", GetoptLong::REQUIRED_ARGUMENT]]
- end
+ end
+
+ # get the arguments in OptionParser format
+ def optparse_args
+ if short
+ ["--#{name}", "-#{short}", desc, :REQUIRED]
+ else
+ ["--#{name}", desc, :REQUIRED]
end
+ end
- # get the arguments in OptionParser format
- def optparse_args
- if short
- ["--#{name}", "-#{short}", desc, :REQUIRED]
- else
- ["--#{name}", desc, :REQUIRED]
- end
- end
+ def hook=(block)
+ meta_def :handle, &block
+ end
- def hook=(block)
- meta_def :handle, &block
+ # Create the new element. Pretty much just sets the name.
+ def initialize(args = {})
+ unless @settings = args.delete(:settings)
+ raise ArgumentError.new("You must refer to a settings object")
end
- # Create the new element. Pretty much just sets the name.
- def initialize(args = {})
- unless @settings = args.delete(:settings)
- raise ArgumentError.new("You must refer to a settings object")
- end
-
- args.each do |param, value|
- method = param.to_s + "="
- raise ArgumentError, "#{self.class} does not accept #{param}" unless self.respond_to? method
+ args.each do |param, value|
+ method = param.to_s + "="
+ raise ArgumentError, "#{self.class} does not accept #{param}" unless self.respond_to? method
- self.send(method, value)
- end
-
- raise ArgumentError, "You must provide a description for the #{self.name} config option" unless self.desc
+ self.send(method, value)
end
- def iscreated
- @iscreated = true
- end
+ raise ArgumentError, "You must provide a description for the #{self.name} config option" unless self.desc
+ end
- def iscreated?
- @iscreated
- end
+ def iscreated
+ @iscreated = true
+ end
- def set?
- !!(!@value.nil?)
- end
-
- # short name for the celement
- def short=(value)
- raise ArgumentError, "Short names can only be one character." if value.to_s.length != 1
- @short = value.to_s
- end
+ def iscreated?
+ @iscreated
+ end
- # Convert the object to a config statement.
- def to_config
- str = @desc.gsub(/^/, "# ") + "\n"
+ def set?
+ !!(!@value.nil?)
+ end
- # Add in a statement about the default.
- str += "# The default value is '#{@default}'.\n" if @default
+ # short name for the celement
+ def short=(value)
+ raise ArgumentError, "Short names can only be one character." if value.to_s.length != 1
+ @short = value.to_s
+ end
- # If the value has not been overridden, then print it out commented
- # and unconverted, so it's clear that that's the default and how it
- # works.
- value = @settings.value(self.name)
+ # Convert the object to a config statement.
+ def to_config
+ str = @desc.gsub(/^/, "# ") + "\n"
- if value != @default
- line = "#{@name} = #{value}"
- else
- line = "# #{@name} = #{@default}"
- end
+ # Add in a statement about the default.
+ str += "# The default value is '#{@default}'.\n" if @default
- str += line + "\n"
+ # If the value has not been overridden, then print it out commented
+ # and unconverted, so it's clear that that's the default and how it
+ # works.
+ value = @settings.value(self.name)
- str.gsub(/^/, " ")
+ if value != @default
+ line = "#{@name} = #{value}"
+ else
+ line = "# #{@name} = #{@default}"
end
- # Retrieves the value, or if it's not set, retrieves the default.
- def value
- @settings.value(self.name)
- end
+ str += line + "\n"
+
+ str.gsub(/^/, " ")
+ end
+
+ # Retrieves the value, or if it's not set, retrieves the default.
+ def value
+ @settings.value(self.name)
+ end
end
diff --git a/lib/puppet/util/storage.rb b/lib/puppet/util/storage.rb
index 6927092de..abc0bbcde 100644
--- a/lib/puppet/util/storage.rb
+++ b/lib/puppet/util/storage.rb
@@ -5,92 +5,92 @@ require 'puppet/util/file_locking'
# a class for storing state
class Puppet::Util::Storage
- include Singleton
- include Puppet::Util
-
- def self.state
- @@state
+ include Singleton
+ include Puppet::Util
+
+ def self.state
+ @@state
+ end
+
+ def initialize
+ self.class.load
+ end
+
+ # Return a hash that will be stored to disk. It's worth noting
+ # here that we use the object's full path, not just the name/type
+ # combination. At the least, this is useful for those non-isomorphic
+ # types like exec, but it also means that if an object changes locations
+ # in the configuration it will lose its cache.
+ def self.cache(object)
+ if object.is_a?(Symbol)
+ name = object
+ else
+ name = object.to_s
end
- def initialize
- self.class.load
- end
+ @@state[name] ||= {}
+ end
- # Return a hash that will be stored to disk. It's worth noting
- # here that we use the object's full path, not just the name/type
- # combination. At the least, this is useful for those non-isomorphic
- # types like exec, but it also means that if an object changes locations
- # in the configuration it will lose its cache.
- def self.cache(object)
- if object.is_a?(Symbol)
- name = object
- else
- name = object.to_s
- end
-
- @@state[name] ||= {}
- end
-
- def self.clear
- @@state.clear
- Storage.init
- end
-
- def self.init
- @@state = {}
- @@splitchar = "\t"
- end
+ def self.clear
+ @@state.clear
+ Storage.init
+ end
- self.init
+ def self.init
+ @@state = {}
+ @@splitchar = "\t"
+ end
- def self.load
- Puppet.settings.use(:main) unless FileTest.directory?(Puppet[:statedir])
+ self.init
- unless File.exists?(Puppet[:statefile])
- self.init unless !@@state.nil?
- return
- end
- unless File.file?(Puppet[:statefile])
- Puppet.warning("Checksumfile #{Puppet[:statefile]} is not a file, ignoring")
- return
- end
- Puppet::Util.benchmark(:debug, "Loaded state") do
- Puppet::Util::FileLocking.readlock(Puppet[:statefile]) do |file|
- begin
- @@state = YAML.load(file)
- rescue => detail
- Puppet.err "Checksumfile #{Puppet[:statefile]} is corrupt (#{detail}); replacing"
- begin
- File.rename(Puppet[:statefile], Puppet[:statefile] + ".bad")
- rescue
- raise Puppet::Error,
- "Could not rename corrupt #{Puppet[:statefile]}; remove manually"
- end
- end
- end
- end
+ def self.load
+ Puppet.settings.use(:main) unless FileTest.directory?(Puppet[:statedir])
- unless @@state.is_a?(Hash)
- Puppet.err "State got corrupted"
- self.init
+ unless File.exists?(Puppet[:statefile])
+ self.init unless !@@state.nil?
+ return
+ end
+ unless File.file?(Puppet[:statefile])
+ Puppet.warning("Checksumfile #{Puppet[:statefile]} is not a file, ignoring")
+ return
+ end
+ Puppet::Util.benchmark(:debug, "Loaded state") do
+ Puppet::Util::FileLocking.readlock(Puppet[:statefile]) do |file|
+ begin
+ @@state = YAML.load(file)
+ rescue => detail
+ Puppet.err "Checksumfile #{Puppet[:statefile]} is corrupt (#{detail}); replacing"
+ begin
+ File.rename(Puppet[:statefile], Puppet[:statefile] + ".bad")
+ rescue
+ raise Puppet::Error,
+ "Could not rename corrupt #{Puppet[:statefile]}; remove manually"
+ end
end
-
- #Puppet.debug "Loaded state is #{@@state.inspect}"
+ end
end
- def self.stateinspect
- @@state.inspect
+ unless @@state.is_a?(Hash)
+ Puppet.err "State got corrupted"
+ self.init
end
- def self.store
- Puppet.debug "Storing state"
+ #Puppet.debug "Loaded state is #{@@state.inspect}"
+ end
- Puppet.info "Creating state file #{Puppet[:statefile]}" unless FileTest.exist?(Puppet[:statefile])
+ def self.stateinspect
+ @@state.inspect
+ end
- Puppet::Util.benchmark(:debug, "Stored state") do
- Puppet::Util::FileLocking.writelock(Puppet[:statefile], 0660) do |file|
- file.print YAML.dump(@@state)
- end
- end
+ def self.store
+ Puppet.debug "Storing state"
+
+ Puppet.info "Creating state file #{Puppet[:statefile]}" unless FileTest.exist?(Puppet[:statefile])
+
+ Puppet::Util.benchmark(:debug, "Stored state") do
+ Puppet::Util::FileLocking.writelock(Puppet[:statefile], 0660) do |file|
+ file.print YAML.dump(@@state)
+ end
end
+ end
end
diff --git a/lib/puppet/util/subclass_loader.rb b/lib/puppet/util/subclass_loader.rb
index ee6b68b15..3fb048835 100644
--- a/lib/puppet/util/subclass_loader.rb
+++ b/lib/puppet/util/subclass_loader.rb
@@ -4,79 +4,79 @@
#
# This module is currently used by network handlers and clients.
module Puppet::Util::SubclassLoader
- attr_accessor :loader, :classloader
+ attr_accessor :loader, :classloader
- # Iterate over each of the subclasses.
- def each
- @subclasses ||= []
- @subclasses.each { |c| yield c }
- end
+ # Iterate over each of the subclasses.
+ def each
+ @subclasses ||= []
+ @subclasses.each { |c| yield c }
+ end
- # The hook method that sets up subclass loading. We need the name
- # of the method to create and the path in which to look for them.
- def handle_subclasses(name, path)
- raise ArgumentError, "Must be a class to use SubclassLoader" unless self.is_a?(Class)
- @subclasses = []
+ # The hook method that sets up subclass loading. We need the name
+ # of the method to create and the path in which to look for them.
+ def handle_subclasses(name, path)
+ raise ArgumentError, "Must be a class to use SubclassLoader" unless self.is_a?(Class)
+ @subclasses = []
- @loader = Puppet::Util::Autoload.new(
- self,
+ @loader = Puppet::Util::Autoload.new(
+ self,
- path, :wrap => false
- )
+ path, :wrap => false
+ )
- @subclassname = name
+ @subclassname = name
- @classloader = self
+ @classloader = self
- # Now create a method for retrieving these subclasses by name. Note
- # that we're defining a class method here, not an instance.
- meta_def(name) do |subname|
- subname = subname.to_s.downcase
+ # Now create a method for retrieving these subclasses by name. Note
+ # that we're defining a class method here, not an instance.
+ meta_def(name) do |subname|
+ subname = subname.to_s.downcase
- unless c = @subclasses.find { |c| c.name.to_s.downcase == subname }
- loader.load(subname)
- c = @subclasses.find { |c| c.name.to_s.downcase == subname }
+ unless c = @subclasses.find { |c| c.name.to_s.downcase == subname }
+ loader.load(subname)
+ c = @subclasses.find { |c| c.name.to_s.downcase == subname }
- # Now make the method that returns this subclass. This way we
- # normally avoid the method_missing method.
- define_method(subname) { c } if c and ! respond_to?(subname)
- end
- return c
- end
+ # Now make the method that returns this subclass. This way we
+ # normally avoid the method_missing method.
+ define_method(subname) { c } if c and ! respond_to?(subname)
+ end
+ return c
end
+ end
- # Add a new class to our list. Note that this has to handle subclasses of
- # subclasses, thus the reason we're keeping track of the @@classloader.
- def inherited(sub)
- @subclasses ||= []
- sub.classloader = self.classloader
- if self.classloader == self
- @subclasses << sub
- else
- @classloader.inherited(sub)
- end
+ # Add a new class to our list. Note that this has to handle subclasses of
+ # subclasses, thus the reason we're keeping track of the @@classloader.
+ def inherited(sub)
+ @subclasses ||= []
+ sub.classloader = self.classloader
+ if self.classloader == self
+ @subclasses << sub
+ else
+ @classloader.inherited(sub)
end
+ end
- # See if we can load a class.
- def method_missing(method, *args)
- unless self == self.classloader
- super
- end
- return nil unless defined?(@subclassname)
- self.send(@subclassname, method) || nil
+ # See if we can load a class.
+ def method_missing(method, *args)
+ unless self == self.classloader
+ super
end
+ return nil unless defined?(@subclassname)
+ self.send(@subclassname, method) || nil
+ end
- # Retrieve or calculate a name.
- def name(dummy_argument=:work_arround_for_ruby_GC_bug)
- @name ||= self.to_s.sub(/.+::/, '').intern
+ # Retrieve or calculate a name.
+ def name(dummy_argument=:work_arround_for_ruby_GC_bug)
+ @name ||= self.to_s.sub(/.+::/, '').intern
- @name
- end
+ @name
+ end
- # Provide a list of all subclasses.
- def subclasses
- @loader.loadall
- @subclasses.collect { |klass| klass.name }
- end
+ # Provide a list of all subclasses.
+ def subclasses
+ @loader.loadall
+ @subclasses.collect { |klass| klass.name }
+ end
end
diff --git a/lib/puppet/util/suidmanager.rb b/lib/puppet/util/suidmanager.rb
index 981564646..4d2c32217 100644
--- a/lib/puppet/util/suidmanager.rb
+++ b/lib/puppet/util/suidmanager.rb
@@ -2,105 +2,105 @@ require 'puppet/util/warnings'
require 'forwardable'
module Puppet::Util::SUIDManager
- include Puppet::Util::Warnings
- extend Forwardable
-
- # Note groups= is handled specially due to a bug in OS X 10.6
- to_delegate_to_process = [ :euid=, :euid, :egid=, :egid, :uid=, :uid, :gid=, :gid, :groups ]
-
- to_delegate_to_process.each do |method|
- def_delegator Process, method
- module_function method
- end
-
- def osx_maj_ver
- return @osx_maj_ver unless @osx_maj_ver.nil?
- require 'facter'
- # 'kernel' is available without explicitly loading all facts
- if Facter.value('kernel') != 'Darwin'
- @osx_maj_ver = false
- return @osx_maj_ver
- end
- # But 'macosx_productversion_major' requires it.
- Facter.loadfacts
- @osx_maj_ver = Facter.value('macosx_productversion_major')
- end
- module_function :osx_maj_ver
-
- def groups=(grouplist)
- if osx_maj_ver == '10.6'
- return true
- else
- return Process.groups = grouplist
- end
- end
- module_function :groups=
-
- if Facter['kernel'].value == 'Darwin'
- # Cannot change real UID on Darwin so we set euid
- alias :uid :euid
- alias :gid :egid
+ include Puppet::Util::Warnings
+ extend Forwardable
+
+ # Note groups= is handled specially due to a bug in OS X 10.6
+ to_delegate_to_process = [ :euid=, :euid, :egid=, :egid, :uid=, :uid, :gid=, :gid, :groups ]
+
+ to_delegate_to_process.each do |method|
+ def_delegator Process, method
+ module_function method
+ end
+
+ def osx_maj_ver
+ return @osx_maj_ver unless @osx_maj_ver.nil?
+ require 'facter'
+ # 'kernel' is available without explicitly loading all facts
+ if Facter.value('kernel') != 'Darwin'
+ @osx_maj_ver = false
+ return @osx_maj_ver
end
-
- def self.root?
- Process.uid == 0
- end
-
- # Runs block setting uid and gid if provided then restoring original ids
- def asuser(new_uid=nil, new_gid=nil)
- return yield if Puppet.features.microsoft_windows? or !root?
-
- # We set both because some programs like to drop privs, i.e. bash.
- old_uid, old_gid = self.uid, self.gid
- old_euid, old_egid = self.euid, self.egid
- old_groups = self.groups
- begin
- self.egid = convert_xid :gid, new_gid if new_gid
- self.initgroups(convert_xid(:uid, new_uid)) if new_uid
- self.euid = convert_xid :uid, new_uid if new_uid
-
- yield
- ensure
- self.euid, self.egid = old_euid, old_egid
- self.groups = old_groups
- end
+ # But 'macosx_productversion_major' requires it.
+ Facter.loadfacts
+ @osx_maj_ver = Facter.value('macosx_productversion_major')
+ end
+ module_function :osx_maj_ver
+
+ def groups=(grouplist)
+ if osx_maj_ver == '10.6'
+ return true
+ else
+ return Process.groups = grouplist
end
- module_function :asuser
-
- # Make sure the passed argument is a number.
- def convert_xid(type, id)
- map = {:gid => :group, :uid => :user}
- raise ArgumentError, "Invalid id type #{type}" unless map.include?(type)
- ret = Puppet::Util.send(type, id)
- if ret == nil
- raise Puppet::Error, "Invalid #{map[type]}: #{id}"
- end
- ret
+ end
+ module_function :groups=
+
+ if Facter['kernel'].value == 'Darwin'
+ # Cannot change real UID on Darwin so we set euid
+ alias :uid :euid
+ alias :gid :egid
+ end
+
+ def self.root?
+ Process.uid == 0
+ end
+
+ # Runs block setting uid and gid if provided then restoring original ids
+ def asuser(new_uid=nil, new_gid=nil)
+ return yield if Puppet.features.microsoft_windows? or !root?
+
+ # We set both because some programs like to drop privs, i.e. bash.
+ old_uid, old_gid = self.uid, self.gid
+ old_euid, old_egid = self.euid, self.egid
+ old_groups = self.groups
+ begin
+ self.egid = convert_xid :gid, new_gid if new_gid
+ self.initgroups(convert_xid(:uid, new_uid)) if new_uid
+ self.euid = convert_xid :uid, new_uid if new_uid
+
+ yield
+ ensure
+ self.euid, self.egid = old_euid, old_egid
+ self.groups = old_groups
end
- module_function :convert_xid
-
- # Initialize supplementary groups
- def initgroups(user)
- require 'etc'
- Process.initgroups(Etc.getpwuid(user).name, Process.gid)
- end
-
- module_function :initgroups
-
- def run_and_capture(command, new_uid=nil, new_gid=nil)
- output = Puppet::Util.execute(command, :failonfail => false, :uid => new_uid, :gid => new_gid)
- [output, $CHILD_STATUS.dup]
+ end
+ module_function :asuser
+
+ # Make sure the passed argument is a number.
+ def convert_xid(type, id)
+ map = {:gid => :group, :uid => :user}
+ raise ArgumentError, "Invalid id type #{type}" unless map.include?(type)
+ ret = Puppet::Util.send(type, id)
+ if ret == nil
+ raise Puppet::Error, "Invalid #{map[type]}: #{id}"
end
- module_function :run_and_capture
-
- def system(command, new_uid=nil, new_gid=nil)
- status = nil
- asuser(new_uid, new_gid) do
- Kernel.system(command)
- status = $CHILD_STATUS.dup
- end
- status
+ ret
+ end
+ module_function :convert_xid
+
+ # Initialize supplementary groups
+ def initgroups(user)
+ require 'etc'
+ Process.initgroups(Etc.getpwuid(user).name, Process.gid)
+ end
+
+ module_function :initgroups
+
+ def run_and_capture(command, new_uid=nil, new_gid=nil)
+ output = Puppet::Util.execute(command, :failonfail => false, :uid => new_uid, :gid => new_gid)
+ [output, $CHILD_STATUS.dup]
+ end
+ module_function :run_and_capture
+
+ def system(command, new_uid=nil, new_gid=nil)
+ status = nil
+ asuser(new_uid, new_gid) do
+ Kernel.system(command)
+ status = $CHILD_STATUS.dup
end
- module_function :system
+ status
+ end
+ module_function :system
end
diff --git a/lib/puppet/util/tagging.rb b/lib/puppet/util/tagging.rb
index 1f185e42c..6323ee08c 100644
--- a/lib/puppet/util/tagging.rb
+++ b/lib/puppet/util/tagging.rb
@@ -3,54 +3,54 @@
# A common module to handle tagging.
module Puppet::Util::Tagging
- # Add a tag to our current list. These tags will be added to all
- # of the objects contained in this scope.
- def tag(*ary)
- @tags ||= []
+ # Add a tag to our current list. These tags will be added to all
+ # of the objects contained in this scope.
+ def tag(*ary)
+ @tags ||= []
- qualified = []
+ qualified = []
- ary.collect { |tag| tag.to_s.downcase }.each do |tag|
- fail(Puppet::ParseError, "Invalid tag #{tag.inspect}") unless valid_tag?(tag)
- qualified << tag if tag.include?("::")
- @tags << tag unless @tags.include?(tag)
- end
-
- handle_qualified_tags( qualified )
+ ary.collect { |tag| tag.to_s.downcase }.each do |tag|
+ fail(Puppet::ParseError, "Invalid tag #{tag.inspect}") unless valid_tag?(tag)
+ qualified << tag if tag.include?("::")
+ @tags << tag unless @tags.include?(tag)
end
- # Are we tagged with the provided tag?
- def tagged?(*tags)
- not ( self.tags & tags.flatten.collect { |t| t.to_s } ).empty?
- end
+ handle_qualified_tags( qualified )
+ end
- # Return a copy of the tag list, so someone can't ask for our tags
- # and then modify them.
- def tags
- @tags ||= []
- @tags.dup
- end
+ # Are we tagged with the provided tag?
+ def tagged?(*tags)
+ not ( self.tags & tags.flatten.collect { |t| t.to_s } ).empty?
+ end
- def tags=(tags)
- @tags = []
+ # Return a copy of the tag list, so someone can't ask for our tags
+ # and then modify them.
+ def tags
+ @tags ||= []
+ @tags.dup
+ end
- return if tags.nil? or tags == ""
+ def tags=(tags)
+ @tags = []
- tags = tags.strip.split(/\s*,\s*/) if tags.is_a?(String)
+ return if tags.nil? or tags == ""
- tags.each do |t|
- tag(t)
- end
+ tags = tags.strip.split(/\s*,\s*/) if tags.is_a?(String)
+
+ tags.each do |t|
+ tag(t)
end
+ end
- private
+ private
- def handle_qualified_tags( qualified )
- # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
- qualified.collect { |name| x = name.split("::") }.flatten.each { |tag| @tags << tag unless @tags.include?(tag) }
- end
+ def handle_qualified_tags( qualified )
+ # LAK:NOTE See http://snurl.com/21zf8 [groups_google_com]
+ qualified.collect { |name| x = name.split("::") }.flatten.each { |tag| @tags << tag unless @tags.include?(tag) }
+ end
- def valid_tag?(tag)
- tag =~ /^\w[-\w:.]*$/
- end
+ def valid_tag?(tag)
+ tag =~ /^\w[-\w:.]*$/
+ end
end
diff --git a/lib/puppet/util/user_attr.rb b/lib/puppet/util/user_attr.rb
index c26c4911a..9b190580b 100644
--- a/lib/puppet/util/user_attr.rb
+++ b/lib/puppet/util/user_attr.rb
@@ -1,21 +1,21 @@
class UserAttr
- def self.get_attributes_by_name(name)
- attributes = nil
+ def self.get_attributes_by_name(name)
+ attributes = nil
- File.readlines('/etc/user_attr').each do |line|
- next if line =~ /^#/
+ File.readlines('/etc/user_attr').each do |line|
+ next if line =~ /^#/
- token = line.split(':')
+ token = line.split(':')
- if token[0] == name
- attributes = {:name => name}
- token[4].split(';').each do |attr|
- key_value = attr.split('=')
- attributes[key_value[0].intern] = key_value[1].strip
- end
- break
- end
+ if token[0] == name
+ attributes = {:name => name}
+ token[4].split(';').each do |attr|
+ key_value = attr.split('=')
+ attributes[key_value[0].intern] = key_value[1].strip
end
- attributes
+ break
+ end
end
+ attributes
+ end
end
diff --git a/lib/puppet/util/warnings.rb b/lib/puppet/util/warnings.rb
index 355010842..7e26feaa0 100644
--- a/lib/puppet/util/warnings.rb
+++ b/lib/puppet/util/warnings.rb
@@ -1,29 +1,29 @@
# Methods to help with handling warnings.
module Puppet::Util::Warnings
- module_function
+ module_function
- def notice_once(msg)
- Puppet::Util::Warnings.maybe_log(msg, self.class) { Puppet.notice msg }
- end
+ def notice_once(msg)
+ Puppet::Util::Warnings.maybe_log(msg, self.class) { Puppet.notice msg }
+ end
- def warnonce(msg)
- Puppet::Util::Warnings.maybe_log(msg, self.class) { Puppet.warning msg }
- end
+ def warnonce(msg)
+ Puppet::Util::Warnings.maybe_log(msg, self.class) { Puppet.warning msg }
+ end
- def clear_warnings
- @stampwarnings = {}
- nil
- end
+ def clear_warnings
+ @stampwarnings = {}
+ nil
+ end
- protected
+ protected
- def self.maybe_log(message, klass)
- @stampwarnings ||= {}
- @stampwarnings[klass] ||= []
- return nil if @stampwarnings[klass].include? message
- yield
- @stampwarnings[klass] << message
- nil
- end
+ def self.maybe_log(message, klass)
+ @stampwarnings ||= {}
+ @stampwarnings[klass] ||= []
+ return nil if @stampwarnings[klass].include? message
+ yield
+ @stampwarnings[klass] << message
+ nil
+ end
end
diff --git a/lib/puppet/util/zaml.rb b/lib/puppet/util/zaml.rb
index aff837077..8ecc2c8bd 100644
--- a/lib/puppet/util/zaml.rb
+++ b/lib/puppet/util/zaml.rb
@@ -13,101 +13,101 @@
require 'yaml'
class ZAML
- VERSION = "0.1.1"
+ VERSION = "0.1.1"
+ #
+ # Class Methods
+ #
+ def self.dump(stuff, where='')
+ z = new
+ stuff.to_zaml(z)
+ where << z.to_s
+ end
+ #
+ # Instance Methods
+ #
+ def initialize
+ @result = []
+ @indent = nil
+ @structured_key_prefix = nil
+ Label.counter_reset
+ emit('--- ')
+ end
+ def nested(tail=' ')
+ old_indent = @indent
+ @indent = "#{@indent || "\n"}#{tail}"
+ yield
+ @indent = old_indent
+ end
+ class Label
#
- # Class Methods
+ # YAML only wants objects in the datastream once; if the same object
+ # occurs more than once, we need to emit a label ("&idxxx") on the
+ # first occurrence and then emit a back reference (*idxxx") on any
+ # subsequent occurrence(s).
#
- def self.dump(stuff, where='')
- z = new
- stuff.to_zaml(z)
- where << z.to_s
- end
- #
- # Instance Methods
+ # To accomplish this we keeps a hash (by object id) of the labels of
+ # the things we serialize as we begin to serialize them. The labels
+ # initially serialize as an empty string (since most objects are only
+ # going to be be encountered once), but can be changed to a valid
+ # (by assigning it a number) the first time it is subsequently used,
+ # if it ever is. Note that we need to do the label setup BEFORE we
+ # start to serialize the object so that circular structures (in
+ # which we will encounter a reference to the object as we serialize
+ # it can be handled).
#
- def initialize
- @result = []
- @indent = nil
- @structured_key_prefix = nil
- Label.counter_reset
- emit('--- ')
- end
- def nested(tail=' ')
- old_indent = @indent
- @indent = "#{@indent || "\n"}#{tail}"
- yield
- @indent = old_indent
- end
- class Label
- #
- # YAML only wants objects in the datastream once; if the same object
- # occurs more than once, we need to emit a label ("&idxxx") on the
- # first occurrence and then emit a back reference (*idxxx") on any
- # subsequent occurrence(s).
- #
- # To accomplish this we keeps a hash (by object id) of the labels of
- # the things we serialize as we begin to serialize them. The labels
- # initially serialize as an empty string (since most objects are only
- # going to be be encountered once), but can be changed to a valid
- # (by assigning it a number) the first time it is subsequently used,
- # if it ever is. Note that we need to do the label setup BEFORE we
- # start to serialize the object so that circular structures (in
- # which we will encounter a reference to the object as we serialize
- # it can be handled).
- #
- def self.counter_reset
- @@previously_emitted_object = {}
- @@next_free_label_number = 0
- end
- def initialize(obj,indent)
- @indent = indent
- @this_label_number = nil
- @@previously_emitted_object[obj.object_id] = self
- end
- def to_s
- @this_label_number ? ('&id%03d%s' % [@this_label_number, @indent]) : ''
- end
- def reference
- @this_label_number ||= (@@next_free_label_number += 1)
- @reference ||= '*id%03d' % @this_label_number
- end
- def self.for(obj)
- @@previously_emitted_object[obj.object_id]
- end
- end
- def new_label_for(obj)
- Label.new(obj,(Hash === obj || Array === obj) ? "#{@indent || "\n"} " : ' ')
+ def self.counter_reset
+ @@previously_emitted_object = {}
+ @@next_free_label_number = 0
end
- def first_time_only(obj)
- if label = Label.for(obj)
- emit(label.reference)
- else
- if @structured_key_prefix and not obj.is_a? String
- emit(@structured_key_prefix)
- @structured_key_prefix = nil
- end
- emit(new_label_for(obj))
- yield
- end
+ def initialize(obj,indent)
+ @indent = indent
+ @this_label_number = nil
+ @@previously_emitted_object[obj.object_id] = self
end
- def emit(s)
- @result << s
- @recent_nl = false unless s.kind_of?(Label)
+ def to_s
+ @this_label_number ? ('&id%03d%s' % [@this_label_number, @indent]) : ''
end
- def nl(s='')
- emit(@indent || "\n") unless @recent_nl
- emit(s)
- @recent_nl = true
+ def reference
+ @this_label_number ||= (@@next_free_label_number += 1)
+ @reference ||= '*id%03d' % @this_label_number
end
- def to_s
- @result.join
+ def self.for(obj)
+ @@previously_emitted_object[obj.object_id]
end
- def prefix_structured_keys(x)
- @structured_key_prefix = x
- yield
- nl unless @structured_key_prefix
+ end
+ def new_label_for(obj)
+ Label.new(obj,(Hash === obj || Array === obj) ? "#{@indent || "\n"} " : ' ')
+ end
+ def first_time_only(obj)
+ if label = Label.for(obj)
+ emit(label.reference)
+ else
+ if @structured_key_prefix and not obj.is_a? String
+ emit(@structured_key_prefix)
@structured_key_prefix = nil
+ end
+ emit(new_label_for(obj))
+ yield
end
+ end
+ def emit(s)
+ @result << s
+ @recent_nl = false unless s.kind_of?(Label)
+ end
+ def nl(s='')
+ emit(@indent || "\n") unless @recent_nl
+ emit(s)
+ @recent_nl = true
+ end
+ def to_s
+ @result.join
+ end
+ def prefix_structured_keys(x)
+ @structured_key_prefix = x
+ yield
+ nl unless @structured_key_prefix
+ @structured_key_prefix = nil
+ end
end
################################################################
@@ -117,31 +117,31 @@ end
################################################################
class Object
- def to_yaml_properties
- instance_variables.sort # Default YAML behavior
- end
- def zamlized_class_name(root)
- cls = self.class
- "!ruby/#{root.name.downcase}#{cls == root ? '' : ":#{cls.respond_to?(:name) ? cls.name : cls}"}"
- end
- def to_zaml(z)
- z.first_time_only(self) {
- z.emit(zamlized_class_name(Object))
- z.nested {
- instance_variables = to_yaml_properties
- if instance_variables.empty?
- z.emit(" {}")
- else
- instance_variables.each { |v|
- z.nl
- v[1..-1].to_zaml(z) # Remove leading '@'
- z.emit(': ')
- instance_variable_get(v).to_zaml(z)
- }
- end
- }
- }
- end
+ def to_yaml_properties
+ instance_variables.sort # Default YAML behavior
+ end
+ def zamlized_class_name(root)
+ cls = self.class
+ "!ruby/#{root.name.downcase}#{cls == root ? '' : ":#{cls.respond_to?(:name) ? cls.name : cls}"}"
+ end
+ def to_zaml(z)
+ z.first_time_only(self) {
+ z.emit(zamlized_class_name(Object))
+ z.nested {
+ instance_variables = to_yaml_properties
+ if instance_variables.empty?
+ z.emit(" {}")
+ else
+ instance_variables.each { |v|
+ z.nl
+ v[1..-1].to_zaml(z) # Remove leading '@'
+ z.emit(': ')
+ instance_variable_get(v).to_zaml(z)
+ }
+ end
+ }
+ }
+ end
end
################################################################
@@ -151,169 +151,169 @@ end
################################################################
class NilClass
- def to_zaml(z)
- z.emit('') # NOTE: blank turns into nil in YAML.load
- end
+ def to_zaml(z)
+ z.emit('') # NOTE: blank turns into nil in YAML.load
+ end
end
class Symbol
- def to_zaml(z)
- z.emit(self.inspect)
- end
+ def to_zaml(z)
+ z.emit(self.inspect)
+ end
end
class TrueClass
- def to_zaml(z)
- z.emit('true')
- end
+ def to_zaml(z)
+ z.emit('true')
+ end
end
class FalseClass
- def to_zaml(z)
- z.emit('false')
- end
+ def to_zaml(z)
+ z.emit('false')
+ end
end
class Numeric
- def to_zaml(z)
- z.emit(self)
- end
+ def to_zaml(z)
+ z.emit(self)
+ end
end
class Regexp
- def to_zaml(z)
- z.first_time_only(self) { z.emit("#{zamlized_class_name(Regexp)} #{inspect}") }
- end
+ def to_zaml(z)
+ z.first_time_only(self) { z.emit("#{zamlized_class_name(Regexp)} #{inspect}") }
+ end
end
class Exception
- def to_zaml(z)
- z.emit(zamlized_class_name(Exception))
- z.nested {
- z.nl("message: ")
- message.to_zaml(z)
- }
- end
- #
- # Monkey patch for buggy Exception restore in YAML
- #
- # This makes it work for now but is not very future-proof; if things
- # change we'll most likely want to remove this. To mitigate the risks
- # as much as possible, we test for the bug before appling the patch.
- #
- if respond_to? :yaml_new and yaml_new(self, :tag, "message" => "blurp").message != "blurp"
- def self.yaml_new( klass, tag, val )
- o = YAML.object_maker( klass, {} ).exception(val.delete( 'message'))
- val.each_pair do |k,v|
- o.instance_variable_set("@#{k}", v)
- end
- o
- end
+ def to_zaml(z)
+ z.emit(zamlized_class_name(Exception))
+ z.nested {
+ z.nl("message: ")
+ message.to_zaml(z)
+ }
+ end
+ #
+ # Monkey patch for buggy Exception restore in YAML
+ #
+ # This makes it work for now but is not very future-proof; if things
+ # change we'll most likely want to remove this. To mitigate the risks
+ # as much as possible, we test for the bug before appling the patch.
+ #
+ if respond_to? :yaml_new and yaml_new(self, :tag, "message" => "blurp").message != "blurp"
+ def self.yaml_new( klass, tag, val )
+ o = YAML.object_maker( klass, {} ).exception(val.delete( 'message'))
+ val.each_pair do |k,v|
+ o.instance_variable_set("@#{k}", v)
+ end
+ o
end
+ end
end
class String
- ZAML_ESCAPES = %w{\x00 \x01 \x02 \x03 \x04 \x05 \x06 \a \x08 \t \n \v \f \r \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 \x1a \e \x1c \x1d \x1e \x1f }
- def escaped_for_zaml
- gsub( /\x5C/, "\\\\\\" ). # Demi-kludge for Maglev/rubinius; the regexp should be /\\/ but parsetree chokes on that.
- gsub( /"/, "\\\"" ).
- gsub( /([\x00-\x1F])/ ) { |x| ZAML_ESCAPES[ x.unpack("C")[0] ] }.
- gsub( /([\x80-\xFF])/ ) { |x| "\\x#{x.unpack("C")[0].to_s(16)}" }
- end
- def to_zaml(z)
- z.first_time_only(self) {
- num = '[-+]?(0x)?\d+\.?\d*'
- case
- when self == ''
- z.emit('""')
- # when self =~ /[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/
- # z.emit("!binary |\n")
- # z.emit([self].pack("m*"))
- when (
- (self =~ /\A(true|false|yes|no|on|null|off|#{num}(:#{num})*|!|=|~)$/i) or
- (self =~ /\A\n* /) or
- (self =~ /[\s:]$/) or
- (self =~ /^[>|][-+\d]*\s/i) or
- (self[-1..-1] =~ /\s/) or
- (self =~ /[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/) or
- (self =~ /[,\[\]\{\}\r\t]|:\s|\s#/) or
- (self =~ /\A([-:?!#&*'"]|<<|%.+:.)/)
- )
- z.emit("\"#{escaped_for_zaml}\"")
- when self =~ /\n/
- if self[-1..-1] == "\n" then z.emit('|+') else z.emit('|-') end
- z.nested { split("\n",-1).each { |line| z.nl; z.emit(line.chomp("\n")) } }
- z.nl
- else
- z.emit(self)
- end
- }
- end
+ ZAML_ESCAPES = %w{\x00 \x01 \x02 \x03 \x04 \x05 \x06 \a \x08 \t \n \v \f \r \x0e \x0f \x10 \x11 \x12 \x13 \x14 \x15 \x16 \x17 \x18 \x19 \x1a \e \x1c \x1d \x1e \x1f }
+ def escaped_for_zaml
+ gsub( /\x5C/, "\\\\\\" ). # Demi-kludge for Maglev/rubinius; the regexp should be /\\/ but parsetree chokes on that.
+ gsub( /"/, "\\\"" ).
+ gsub( /([\x00-\x1F])/ ) { |x| ZAML_ESCAPES[ x.unpack("C")[0] ] }.
+ gsub( /([\x80-\xFF])/ ) { |x| "\\x#{x.unpack("C")[0].to_s(16)}" }
+ end
+ def to_zaml(z)
+ z.first_time_only(self) {
+ num = '[-+]?(0x)?\d+\.?\d*'
+ case
+ when self == ''
+ z.emit('""')
+ # when self =~ /[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/
+ # z.emit("!binary |\n")
+ # z.emit([self].pack("m*"))
+ when (
+ (self =~ /\A(true|false|yes|no|on|null|off|#{num}(:#{num})*|!|=|~)$/i) or
+ (self =~ /\A\n* /) or
+ (self =~ /[\s:]$/) or
+ (self =~ /^[>|][-+\d]*\s/i) or
+ (self[-1..-1] =~ /\s/) or
+ (self =~ /[\x00-\x08\x0B\x0C\x0E-\x1F\x80-\xFF]/) or
+ (self =~ /[,\[\]\{\}\r\t]|:\s|\s#/) or
+ (self =~ /\A([-:?!#&*'"]|<<|%.+:.)/)
+ )
+ z.emit("\"#{escaped_for_zaml}\"")
+ when self =~ /\n/
+ if self[-1..-1] == "\n" then z.emit('|+') else z.emit('|-') end
+ z.nested { split("\n",-1).each { |line| z.nl; z.emit(line.chomp("\n")) } }
+ z.nl
+ else
+ z.emit(self)
+ end
+ }
+ end
end
class Hash
- def to_zaml(z)
- z.first_time_only(self) {
- z.nested {
- if empty?
- z.emit('{}')
- else
- each_pair { |k, v|
- z.nl
- z.prefix_structured_keys('? ') { k.to_zaml(z) }
- z.emit(': ')
- v.to_zaml(z)
- }
- end
- }
- }
- end
+ def to_zaml(z)
+ z.first_time_only(self) {
+ z.nested {
+ if empty?
+ z.emit('{}')
+ else
+ each_pair { |k, v|
+ z.nl
+ z.prefix_structured_keys('? ') { k.to_zaml(z) }
+ z.emit(': ')
+ v.to_zaml(z)
+ }
+ end
+ }
+ }
+ end
end
class Array
- def to_zaml(z)
- z.first_time_only(self) {
- z.nested {
- if empty?
- z.emit('[]')
- else
- each { |v| z.nl('- '); v.to_zaml(z) }
- end
- }
- }
- end
+ def to_zaml(z)
+ z.first_time_only(self) {
+ z.nested {
+ if empty?
+ z.emit('[]')
+ else
+ each { |v| z.nl('- '); v.to_zaml(z) }
+ end
+ }
+ }
+ end
end
class Time
- def to_zaml(z)
- # 2008-12-06 10:06:51.373758 -07:00
- ms = ("%0.6f" % (usec * 1e-6)).sub(/^\d+\./,'')
- offset = "%+0.2i:%0.2i" % [utc_offset / 3600, (utc_offset / 60) % 60]
- z.emit(self.strftime("%Y-%m-%d %H:%M:%S.#{ms} #{offset}"))
- end
+ def to_zaml(z)
+ # 2008-12-06 10:06:51.373758 -07:00
+ ms = ("%0.6f" % (usec * 1e-6)).sub(/^\d+\./,'')
+ offset = "%+0.2i:%0.2i" % [utc_offset / 3600, (utc_offset / 60) % 60]
+ z.emit(self.strftime("%Y-%m-%d %H:%M:%S.#{ms} #{offset}"))
+ end
end
class Date
- def to_zaml(z)
- z.emit(strftime('%Y-%m-%d'))
- end
+ def to_zaml(z)
+ z.emit(strftime('%Y-%m-%d'))
+ end
end
class Range
- def to_zaml(z)
- z.first_time_only(self) {
- z.emit(zamlized_class_name(Range))
- z.nested {
- z.nl
- z.emit('begin: ')
- z.emit(first)
- z.nl
- z.emit('end: ')
- z.emit(last)
- z.nl
- z.emit('excl: ')
- z.emit(exclude_end?)
- }
- }
- end
+ def to_zaml(z)
+ z.first_time_only(self) {
+ z.emit(zamlized_class_name(Range))
+ z.nested {
+ z.nl
+ z.emit('begin: ')
+ z.emit(first)
+ z.nl
+ z.emit('end: ')
+ z.emit(last)
+ z.nl
+ z.emit('excl: ')
+ z.emit(exclude_end?)
+ }
+ }
+ end
end