diff options
| author | Stig Sandbeck Mathisen <ssm@debian.org> | 2013-02-05 10:44:00 +0100 |
|---|---|---|
| committer | Stig Sandbeck Mathisen <ssm@debian.org> | 2013-02-05 10:44:00 +0100 |
| commit | 107e8d1a41d447403883a6f6faa1cc40fb904720 (patch) | |
| tree | aaaeca9cb6289b3db94a105e6cb1b1270292337c | |
| parent | 7a3cd3a80c8d57462509c7e193dfcc11fc61a191 (diff) | |
| parent | 480379d1f61d88e732bd10d6773845a788351ed3 (diff) | |
| download | puppet-upstream/3.1.0.tar.gz | |
Imported Upstream version 3.1.0upstream/3.1.0
337 files changed, 6686 insertions, 3251 deletions
diff --git a/COMMITTERS.md b/COMMITTERS.md new file mode 100644 index 000000000..1c61d0761 --- /dev/null +++ b/COMMITTERS.md @@ -0,0 +1,185 @@ +Committing changes to Puppet +==== + +We would like to make it easier for community members to contribute to Puppet +using pull requests, even if it makes the task of reviewing and committing +these changes a little harder. Pull requests are only ever based on a single +branch, however, we maintain more than one active branch. As a result +contributors should target their changes at the master branch. This makes the +process of contributing a little easier for the contributor since they don't +need to concern themselves with the question, "What branch do I base my changes +on?" This is already called out in the [CONTRIBUTING.md](http://goo.gl/XRH2J). + +Therefore, it is the responsibility of the committer to re-base the change set +on the appropriate branch which should receive the contribution. + +The rest of this document addresses the concerns of the committer. This +document will help guide the committer decide which branch to base, or re-base +a contribution on top of. This document also describes our branch management +strategy, which is closely related to the decision of what branch to commit +changes into. + +Terminology +==== + +Many of these terms have more than one meaning. For the purposes of this +document, the following terms refer to specific things. + +**contributor** - A person who makes a change to Puppet and submits a change +set in the form of a pull request. + +**change set** - A set of discrete patches which combined together form a +contribution. A change set takes the form of Git commits and is submitted to +Puppet in the form of a pull request. + +**committer** - A person responsible for reviewing a pull request and then +making the decision what base branch to merge the change set into. + +**base branch** - A branch in Git that contains an active history of changes +and will eventually be released using semantic version guidelines. The branch +named master will always exist as a base branch. All other base branches will +be associated with a specific released version of Puppet, e.g. 2.7.x and 3.0.x. + +Committer Guide +==== + +This section provides a guide to follow while committing change sets to Puppet +base branches. + +How to decide what release(s) should be patched +--- + +This section provides a guide to help a committer decide the specific base +branch that a change set should be merged into. + +The latest minor release of a major release is the only base branch that should +be patched. Older minor releases in a major release do not get patched. Before +the switch to [semantic versions](http://semver.org/) committers did not have +to think about the difference between minor and major releases. Committing to +the latest minor release of a major release is a policy intended to limit the +number of active base branches that must be managed. + +Security patches are handled as a special case. Security patches may be +applied to earlier minor releases of a major release. + +How to commit a change set to multiple base branches +--- + +A change set may apply to multiple releases. In this situation the change set +needs to be committed to multiple base branches. This section provides a guide +for how to merge patches across releases, e.g. 2.7 is patched, how should the +changes be applied to 3.0? + +First, merge the change set into the lowest numbered base branch, e.g. 2.7. +Next, merge the changed base branch up through all later base branches by using +the `--no-ff --log` git merge options. We commonly refer to this as our "merge +up process" because we merge in once, then merge up multiple times. + +When a new minor release branch is created (e.g. 3.1.x) then the previous one +is deleted (e.g. 3.0.x). Any security or urgent fixes that might have to be +applied to the older code line is done by creating an ad-hoc branch from the +tag of the last patch release of the old minor line. + +Code review checklist +--- + +This section aims to provide a checklist of things to look for when reviewing a +pull request and determining if the change set should be merged into a base +branch: + + * All tests pass + * Are there any platform gotchas? (Does a change make an assumption about + platform specific behavior that is incompatible with other platforms? e.g. + Windows paths vs. POSIX paths.) + * Is the change backwards compatible? (It should be) + * Are there YARD docs for API changes? + * Does the change set also require documentation changes? If so is the + documentation being kept up to date? + * Does the change set include clean code? (software code that is formatted + correctly and in an organized manner so that another coder can easily read + or modify it.) HINT: `git diff master --check` + * Does the change set conform to the contributing guide? + + +Commit citizen guidelines: +--- + +This section aims to provide guidelines for being a good commit citizen by +paying attention to our automated build tools. + + * Don’t push on a broken build. (A broken build is defined as a failing job + in the [Puppet FOSS](https://jenkins.puppetlabs.com/view/Puppet%20FOSS/) + page.) + * Watch the build until your changes have gone through green + * Update the ticket status and target version. The target version field in + our issue tracker should be updated to be the next release of Puppet. For + example, if the most recent release of Puppet is 3.1.1 and you merge a + backwards compatible change set into master, then the target version should + be 3.2.0 in the issue tracker.) + * Ensure the pull request is closed (Hint: amend your merge commit to contain + the string `closes: #123` where 123 is the pull request number. + +Example Procedure +==== + +This section helps a committer rebase a contribution onto an earlier base +branch, then merge into the base branch and up through all active base +branches. + +Suppose a contributor submits a pull request based on master. The change set +fixes a bug reported against Puppet 3.1.1 which is the most recently released +version of Puppet. + +In this example the committer should rebase the change set onto the 3.1.x +branch since this is a bug rather than new functionality. + +First, the committer pulls down the branch using the `hub` gem. This tool +automates the process of adding the remote repository and creating a local +branch to track the remote branch. + + $ hub checkout https://github.com/puppetlabs/puppet/pull/1234 + Branch jeffmccune-fix_foo_error set up to track remote branch fix_foo_error from jeffmccune. + Switched to a new branch 'jeffmccune-fix_foo_error' + +At this point the topic branch is a descendant of master, but we want it to +descend from 3.1.x. The committer creates a new branch then re-bases the +change set: + + $ git branch bug/3.1.x/fix_foo_error + $ git rebase --onto 3.1.x master bug/3.1.x/fix_foo_error + First, rewinding head to replay your work on top of it... + Applying: (#23456) Fix FooError that always bites users in 3.1.1 + +The `git rebase` command may be interpreted as, "First, check out the branch +named `bug/3.1.x/fix_foo_error`, then take the changes that were previously +based on `master` and re-base them onto `3.1.x`. + +Now that we have a topic branch containing the change set based on the correct +release branch, the committer merges in: + + $ git checkout 3.1.x + Switched to branch '3.1.x' + $ git merge --no-ff --log bug/3.1.x/fix_foo_error + Merge made by the 'recursive' strategy. + foo | 0 + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 foo + +Once merged into the first base branch, the committer merges up: + + $ git checkout master + Switched to branch 'master' + $ git merge --no-ff --log 3.1.x + Merge made by the 'recursive' strategy. + foo | 0 + 1 file changed, 0 insertions(+), 0 deletions(-) + create mode 100644 foo + +Once the change set has been merged "in and up." the committer pushes. (Note, +the checklist should be complete at this point.) Note that both the 3.1.x and +master branches are being pushed at the same time. + + $ git push puppetlabs master:master 3.1.x:3.1.x + +That's it! The committer then updates the pull request, updates the issue in +our issue tracker, and keeps an eye on the build status. @@ -1,13 +1,10 @@ source :rubygems -# This is a fake version just to make bundler happy during development -FAKE_VERSION = '9999.0.0' - def location_for(place) if place =~ /^(git:[^#]*)#(.*)/ [{ :git => $1, :branch => $2, :require => false }] elsif place =~ /^file:\/\/(.*)/ - [FAKE_VERSION, { :path => File.expand_path($1), :require => false }] + ['>= 0', { :path => File.expand_path($1), :require => false }] else [place, { :require => false }] end @@ -15,17 +12,22 @@ end group(:development, :test) do gem "puppet", *location_for('file://.') - gem "facter", *location_for(ENV['FACTER_LOCATION'] || '~> 1.6.4') - gem "hiera", *location_for(ENV['HIERA_LOCATION'] || '~> 1.0.0') - gem "rack", "~> 1.4.1", :require => false - gem "rake", "~> 0.9.2", :require => false - gem "rspec", "~> 2.10.0", :require => false + gem "facter", *location_for(ENV['FACTER_LOCATION'] || '~> 1.6') + gem "hiera", *location_for(ENV['HIERA_LOCATION'] || '~> 1.0') + gem "rack", "~> 1.4", :require => false + gem "rake", :require => false + gem "rspec", "~> 2.11.0", :require => false gem "mocha", "~> 0.10.5", :require => false + gem "activerecord", *location_for('~> 3.0.7') + gem "couchrest", *location_for('~> 1.0') + gem "net-ssh", *location_for('~> 2.1') + gem "puppetlabs_spec_helper" + gem "sqlite3" + gem "stomp" + gem "tzinfo" end platforms :mswin, :mingw do - # See http://jenkins.puppetlabs.com/ for current Gem listings for the Windows - # CI Jobs. gem "sys-admin", "~> 1.5.6", :require => false gem "win32-api", "~> 1.4.8", :require => false gem "win32-dir", "~> 0.3.7", :require => false @@ -1,7 +1,9 @@ Puppet ====== -Puppet, an automated administrative engine for your Linux and Unix systems, performs +[](https://travis-ci.org/puppetlabs/puppet) + +Puppet, an automated administrative engine for your Linux, Unix, and Windows systems, performs administrative tasks (such as adding users, installing packages, and updating server configurations) based on a centralized specification. @@ -14,11 +16,7 @@ Installation Generally, you need the following things installed: -* A supported Ruby version. Ruby 1.8.5, 1.8.7, and 1.9.2 are fully supported - (with a handful of known issues under 1.9.2); Ruby 1.8.1 is supported on a - best-effort basis for agent use only. Other versions of Ruby are used at your - own risk, and Ruby 1.8.6, 1.9.0, and 1.9.1 are not recommended for - compatibility reasons. +* A supported Ruby version. Ruby 1.8.7, and 1.9.3 are fully supported. * The Ruby OpenSSL library. For some reason, this often isn't included in the main ruby distributions. You can test for it by running @@ -48,4 +46,8 @@ See LICENSE file. Support ------- -Please log tickets and issues at our [Projects site](http://projects.puppetlabs.com) +Please log tickets and issues at our [Projects +site](http://projects.puppetlabs.com). A [mailing +list](https://groups.google.com/forum/?fromgroups#!forum/puppet-users) is +available for asking questions and getting help from others. In addition there +is an active #puppet channel on Freenode. diff --git a/README_DEVELOPER.md b/README_DEVELOPER.md index 48a9965eb..fa5455b93 100644 --- a/README_DEVELOPER.md +++ b/README_DEVELOPER.md @@ -3,36 +3,13 @@ This file is intended to provide a place for developers and contributors to document what other developers need to know about changes made to Puppet. -# Use of RVM considered dangerous # +# Internal Structures -Use of RVM in production situations, e.g. running CI tests against this -repository, is considered dangerous. The reason we consider RVM to be -dangerous is because the default behavior of RVM is to hijack the builtin -behavior of the shell, causing Gemfile files to be loaded and evaluated when -the shell changes directories into the project root. - -This behavior causes the CI Job execution environment that runs with `set -e` -to be incompatible with RVM. - -We work around this issue by disabling the per-project RC file parsing using - - if ! grep -qx rvm_project_rvmrc=0 ~/.rvmrc; then - echo rvm_project_rvmrc=0 >> ~/.rvmrc - fi - -When we setup CI nodes, but this is not standard or expected behavior. - -Please consider rbenv instead of rvm. The default behavior of rvm is difficult -to maintain with `set -e` shell environments. - -# Two Types of Catalog +## Two Types of Catalog When working on subsystems of Puppet that deal with the catalog it is important -to be aware of the two different types of Catalog. I often ran into this when -working in Professional Services when I built a small tool to diff two catalogs -to determine if an upgrade in Puppet produces the same configuration catalogs. -As a developer I've run into this difference while working on spec tests for -the static compiler and working on spec tests for types and providers. +to be aware of the two different types of Catalog. Developers will often find +this difference while working on the static compiler and types and providers. The two different types of catalog becomes relevant when writing spec tests because we frequently need to wire up a fake catalog so that we can exercise @@ -48,7 +25,7 @@ is used to apply the configuration model to the system. Resource dependency information is most easily obtained from a RAL catalog by walking the graph instance produced by the `relationship_graph` method. -## Resource Catalog +### Resource Catalog If you're writing spec tests for something that deals with a catalog "server side," a new catalog terminus for example, then you'll be dealing with a @@ -73,7 +50,7 @@ Resource dependencies are not easily walked using a resource catalog however. To walk the dependency tree convert the catalog to a RAL catalog as described in -## RAL Catalog +### RAL Catalog The resource catalog may be converted to a RAL catalog using `catalog.to_ral`. The RAL catalog contains `Puppet::Type` instances instead of `Puppet::Resource` @@ -403,7 +380,7 @@ This special filebucket resource named "puppet" will cause the agent to fetch file contents specified by checksum from the remote filebucket instead of the default clientbucket. -## Quick start +## Trying out the Static Compiler Create a module that recursively downloads something. The jeffmccune-filetest module will recursively copy the rubygems source tree. @@ -434,4 +411,18 @@ checksum representing the content. When managing an out of sync file resource, the real contents should be fetched from the server instead of the clientbucket. +Package Maintainers +===== + +Software Version API +----- + +Please see the public API regarding the software version as described in +`lib/puppet/version.rb`. Puppet provides the means to easily specify the exact +version of the software packaged using the VERSION file, for example: + + $ git describe --match "3.0.*" > lib/puppet/VERSION + $ ruby -r puppet/version -e 'puts Puppet.version' + 3.0.1-260-g9ca4e54 + EOF diff --git a/README_HIERA.md b/README_HIERA.md deleted file mode 100644 index e778b2c53..000000000 --- a/README_HIERA.md +++ /dev/null @@ -1,148 +0,0 @@ -What? -===== - -A data backend for Hiera that can query the internal Puppet -scope for data. The data structure and approach is heavily -based on work by Nigel Kersten but made more configurable and -with full hierarchy. - -It also includes a Puppet function that works like extlookup() -but uses the Hiera backends. - -Usage? -====== - -Hiera supports the concept of chaining backends together in order, -using this we can create a very solid module author/module user -experience. - -Module Author -------------- - -A module author wants to create a configurable module that has sane -defaults but want to retain the ability for users to configure it. - -We'll use a simple NTP config class as an example. - -<pre> -class ntp::config($ntpservers = hiera("ntpservers")) { - file{"/etc/ntp.conf": - content => template("ntp.conf.erb") - } -} -</pre> - -We create a class that takes as parameters a list of NTP servers. - -The module author wants to create a works-out-of-the-box experience -so creates a data class for the NTP module: - -<pre> -class ntp::data { - $ntpservers = ["1.pool.ntp.org", "2.pool.ntp.org"] -} -</pre> - -Together this creates a default sane setup. - -Module User ------------ - -The module user has a complex multi data center setup, he wants to use -the NTP module from the forge and configure it for his needs. - -The user creates a set of default data for his organization, he can do -this in data files or in Puppet. We'll show a Puppet example. - -<pre> -class data::common { - $ntpservers = ["ntp1.example.com", "ntp2.example.com"] -} -</pre> - -Being part of the actual code this data is subject to strict change -control. This is needed as its data that can potentially affect all -machines in all locations. - -The user has a fact called _location_ that contains, for example, a name -of the data center. - -He decides to create JSON based data for the data centers, being just data -that applies to one data center this data is not subject to as strict -change controls and so does not live with the code: - -He creates _/var/lib/hiera/dc1.json_ with the following: - -<pre> -{"ntpservers" : ["ntp1.dc1.example.com", "ntp2.dc1.example.com"]} -</pre> - -Machines in dc1 will now use specific NTP servers while all the rest will -use the data in _data::common_ - -The module user can now just declare the class on his nodes: - -<pre> -node "web1" { - include ntp::config -} -</pre> - -For true one-off changes, the user can use the full paramterized class approach -that will completely disable the Hiera handling of this data item. He could -also use an ENC to supply this data. - -<pre> -node "web2" { - class{"ntp::config": ntpservers => ["another.example.com"]} -} -</pre> - -This behavior is thanks to Hiera's ability to search through multiple backends -for data picking the first match. We can have the JSON searched before the internal -Puppet data. - -To achieve this setup the module user needs to configure Hiera in _/etc/puppet/hiera.yaml_: - -<pre> ---- -:backends: - - json - - puppet - -:hierarchy: - - "%{location}" - - common - -:json: - :datadir: /var/lib/hiera - -:puppet: - :datasource: data -</pre> - -Converting from extlookup? -========================== - -A simple converter is included called _extlookup2hiera_ and it can convert from CSV to JSON or YAML: - -<pre> -$ extlookup2hiera --in common.csv --out common.json --json -</pre> - -Installation? -============= - -It's not 100% ready for prime time, shortly a simple _gem install hiera-puppet_ on your master will do it. - -For the moment the Gem install will place the Puppet Parser Function where Puppet cannot find it, you should -copy it out and distribute it to your master using Pluginsync or something similar - -License -======= - -See LICENSE file. - -Support -======= -Please log tickets and issues at our [Projects site](http://projects.puppetlabs.com) diff --git a/bin/extlookup2hiera b/bin/extlookup2hiera index 7a095a37b..7a095a37b 100644..100755 --- a/bin/extlookup2hiera +++ b/bin/extlookup2hiera diff --git a/conf/auth.conf b/conf/auth.conf index 56a87ca61..07e5a34b6 100644 --- a/conf/auth.conf +++ b/conf/auth.conf @@ -1,15 +1,19 @@ -# This is an example auth.conf file, which implements the -# defaults used by the puppet master. +# This is the default auth.conf file, which implements the default rules +# used by the puppet master. (That is, the rules below will still apply +# even if this file is deleted.) # -# The ACLs are evaluated in top-down order. More general -# stanzas should be towards the bottom of the file and more -# specific ones at the top, otherwise the general rules -# take precedence and later rules will not be evaluated. +# The ACLs are evaluated in top-down order. More specific stanzas should +# be towards the top of the file and more general ones at the bottom; +# otherwise, the general rules may "steal" requests that should be +# governed by the specific rules. +# +# See http://docs.puppetlabs.com/guides/rest_auth_conf.html for a more complete +# description of auth.conf's behavior. # # Supported syntax: -# Each stanza in auth.conf starts with a path to mach, followed +# Each stanza in auth.conf starts with a path to match, followed # by optional modifiers, and finally, a series of allow or deny -# directives. +# directives. # # Example Stanza # --------------------------------- @@ -18,25 +22,33 @@ # [environment envlist] # [method methodlist] # [auth[enthicated] {yes|no|on|off|any}] -# allow [host|backreference|*] -# deny [host|backreference|*] +# allow [host|backreference|*|regex] +# deny [host|backreference|*|regex] # allow_ip [ip|cidr|ip_wildcard|*] # deny_ip [ip|cidr|ip_wildcard|*] # -# The path match can either be a simple prefix match or a regular +# The path match can either be a simple prefix match or a regular # expression. `path /file` would match both `/file_metadata` and # `/file_content`. Regex matches allow the use of backreferences # in the allow/deny directives. -# +# # The regex syntax is the same as for Ruby regex, and captures backreferences # for use in the `allow` and `deny` lines of that stanza # # Examples: -# path ~ ^/path/to/resource # equivalent to `path /path/to/resource` -# allow * # -# path ~ ^/catalog/([^/]+)$ # permit access only for the -# allow $1 # node whose cert matches the path +# path ~ ^/path/to/resource # Equivalent to `path /path/to/resource`. +# allow * # Allow all authenticated nodes (since auth +# # defaults to `yes`). +# +# path ~ ^/catalog/([^/]+)$ # Permit nodes to access their own catalog (by +# allow $1 # certname), but not any other node's catalog. +# +# path ~ ^/file_(metadata|content)/extra_files/ # Only allow certain nodes to +# auth yes # access the "extra_files" +# allow /^(.+)\.example\.com$/ # mount point; note this must +# allow_ip 192.168.100.0/24 # go ABOVE the "/file" rule, +# # since it is more specific. # # environment:: restrict an ACL to a comma-separated list of environments # method:: restrict an ACL to a comma-separated list of HTTP methods @@ -45,7 +57,7 @@ # (ie exactly as if auth yes was present). # -### Authenticated paths - these apply only when the client +### Authenticated ACLs - these rules apply only when the client ### has a valid certificate and is thus authenticated # allow nodes to retrieve their own catalog @@ -68,33 +80,37 @@ path /report method save allow * -# unconditionally allow access to all file services -# which means in practice that fileserver.conf will -# still be used +# Allow all nodes to access all file services; this is necessary for +# pluginsync, file serving from modules, and file serving from custom +# mount points (see fileserver.conf). Note that the `/file` prefix matches +# requests to both the file_metadata and file_content paths. See "Examples" +# above if you need more granular access control for custom mount points. path /file allow * -### Unauthenticated ACL, for clients for which the current master doesn't -### have a valid certificate; we allow authenticated users, too, because -### there isn't a great harm in letting that request through. +### Unauthenticated ACLs, for clients without valid certificates; authenticated +### clients can also access these paths, though they rarely need to. -# allow access to the master CA +# allow access to the CA certificate; unauthenticated nodes need this +# in order to validate the puppet master's certificate path /certificate/ca auth any method find allow * +# allow nodes to retrieve the certificate they requested earlier path /certificate/ auth any method find allow * +# allow nodes to request a new certificate path /certificate_request auth any method find, save allow * -# this one is not stricly necessary, but it has the merit -# of showing the default policy, which is deny everything else +# deny everything else; this ACL is not strictly necessary, but +# illustrates the default policy. path / auth any diff --git a/conf/epm.list b/conf/epm.list deleted file mode 100644 index d7d7b40e5..000000000 --- a/conf/epm.list +++ /dev/null @@ -1,8 +0,0 @@ -%product Puppet -%copyright 2004-2005 by Reductive Labs, All Rights Reserved -%vendor Reductive Labs -%license COPYING -%readme README -%description System Automation and Configuration Management Software -%version 0.15.0 -%requires facter 1.1 diff --git a/conf/fileserver.conf b/conf/fileserver.conf new file mode 100644 index 000000000..62598c4e3 --- /dev/null +++ b/conf/fileserver.conf @@ -0,0 +1,41 @@ +# fileserver.conf + +# Puppet automatically serves PLUGINS and FILES FROM MODULES: anything in +# <module name>/files/<file name> is available to authenticated nodes at +# puppet:///modules/<module name>/<file name>. You do not need to edit this +# file to enable this. + +# MOUNT POINTS + +# If you need to serve files from a directory that is NOT in a module, +# you must create a static mount point in this file: +# +# [extra_files] +# path /etc/puppet/files +# allow * +# +# In the example above, anything in /etc/puppet/files/<file name> would be +# available to authenticated nodes at puppet:///extra_files/<file name>. +# +# Mount points may also use three placeholders as part of their path: +# +# %H - The node's certname. +# %h - The portion of the node's certname before the first dot. (Usually the +# node's short hostname.) +# %d - The portion of the node's certname after the first dot. (Usually the +# node's domain name.) + +# PERMISSIONS + +# Every static mount point should have an `allow *` line; setting more +# granular permissions in this file is deprecated. Instead, you can +# control file access in auth.conf by controlling the +# /file_metadata/<mount point> and /file_content/<mount point> paths: +# +# path ~ ^/file_(metadata|content)/extra_files/ +# auth yes +# allow /^(.+)\.example\.com$/ +# allow_ip 192.168.100.0/24 +# +# If added to auth.conf BEFORE the "path /file" rule, the rule above +# will add stricter restrictions to the extra_files mount point. diff --git a/conf/namespaceauth.conf b/conf/namespaceauth.conf deleted file mode 100644 index 837235769..000000000 --- a/conf/namespaceauth.conf +++ /dev/null @@ -1,20 +0,0 @@ -# This is an example namespaceauth.conf file, -# which you'll need if you want to start a client -# in --listen mode. -[fileserver] - allow *.domain.com - -[puppetmaster] - allow *.domain.com - -[puppetrunner] - allow culain.domain.com - -[puppetbucket] - allow *.domain.com - -[puppetreports] - allow *.domain.com - -[resource] - allow server.domain.com diff --git a/conf/puppet-queue.conf b/conf/puppet-queue.conf deleted file mode 100644 index fef22f8ca..000000000 --- a/conf/puppet-queue.conf +++ /dev/null @@ -1,10 +0,0 @@ -:daemon: true -:working_dir: /tmp/stompserver -:storage: .queue -:queue: file -:auth: false -:debug: false -:group: -:user: -:host: 127.0.0.1 -:port: 61613 diff --git a/conf/tagmail.conf b/conf/tagmail.conf new file mode 100644 index 000000000..3d324469e --- /dev/null +++ b/conf/tagmail.conf @@ -0,0 +1,16 @@ +# tagmail.conf + +# This file configures the `tagmail` report, which can be enabled by including +# tagmail in the puppet master's `reports` setting. (`reports = https, tagmail`) + +# Each line in this file should consist of a comma-separated list of tags and/or +# negated tags (`!tag`), a colon, and a comma-separated list of email addresses. +# The `all` psuedo-tag will email all log events. +# See http://docs.puppetlabs.com/guides/configuring.html#tagmailconf for +# a complete description of this file. + +# Example: + +# all: log-archive@example.com +# webserver, !mailserver: httpadmins@example.com +# emerg, crit: james@example.com, zach@example.com, ben@example.com diff --git a/examples/allatonce b/examples/allatonce deleted file mode 100644 index 8912ec4e7..000000000 --- a/examples/allatonce +++ /dev/null @@ -1,13 +0,0 @@ -# $Id$ - -define thingie { - file { "/tmp/classtest": ensure => file, mode => 755 } - #testing {} -} - -class testing { - thingie { "componentname": } -} - -#component {} -testing { "testingname": } diff --git a/examples/assignments b/examples/assignments deleted file mode 100644 index 3edcef84e..000000000 --- a/examples/assignments +++ /dev/null @@ -1,11 +0,0 @@ -# $Id$ - -$goodness = sunos - -$subvariable = $goodness - -$yayness = "this is a string of text" - -#$sleeper = service { sleeper: -# running => "1" -#} diff --git a/examples/components b/examples/components deleted file mode 100644 index 3da43c571..000000000 --- a/examples/components +++ /dev/null @@ -1,73 +0,0 @@ -# $Id$ - -# i still have no 'require'-like functionality, and i should also -# have 'recommend'-like functionality... -define apache(php,docroot,user,group) { - package { apache: - version => "2.0.53" - } - service { apache: - running => true - } - - - # this definitely won't parse - #if $php == "true" { - # # this needs to do two things: - # # - mark a dependency - # # - cause this apache component to receive refresh events generated by php - # #require("php") - # $var = value - #} - - #file { "../examples/root/etc/configfile": - # owner => $user - #} -} - -define sudo() { - package { sudo: - version => "1.6.8p7" - } - file { "/etc/sudoers": - owner => root, - group => root, - mode => "440" - } -} - -define ssh { - package { ssh: - version => "3.4.4.4" - } - service { "sshd": - running => true - } -} - -define sleeper(path,mode) { - Service { - path => "../examples/root/etc/init.d" - } - - service { sleeper: - running => true, - path => "../examples/root/etc/init.d" - } - file { $path: - mode => $mode - } - $files = ["/tmp/testness","/tmp/funtest"] - file { $files: - ensure => file - } -} - -#apache { "test": -# php => false, -# docroot => "/export/html", -# user => "www-data", -# group => "www-data" -#} - -#ssh { "yucko":} diff --git a/examples/etc/init.d/sleeper b/examples/etc/init.d/sleeper deleted file mode 100755 index c60a5555c..000000000 --- a/examples/etc/init.d/sleeper +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash - -script=$0 -path=`echo $script | sed 's/etc..*/bin/'` - -PATH=$PATH:$path - -ps=`facter ps` - -if [ -z "$ps" ]; then - ps="ps -ef" -fi - -function start -{ - cd $path - ./sleeper -} - -function stop -{ - #if [ -n `which pgrep` ]; then - # pid=`pgrep sleeper` - #else - pid=`$ps | grep -v grep | grep sleeper | grep ruby | awk '{print $2}'` - #fi - if [ -n "$pid" ]; then - kill $pid - fi -} - -function restart -{ - stop - start -} - -function status -{ - #if [ -n `which pgrep` ]; then - # cmd="pgrep sleeper" - #else - #cmd="$ps | grep -v grep | grep sleeper | grep ruby | awk '{print $2}'" - #fi - #$cmd - $ps | grep -v grep | grep sleeper | grep ruby -} - -case "$1" in - start) - start - ;; - stop) - stop - ;; - restart) - stop; start - ;; - status) - output=`status` - #status - exit $? - ;; - *) - echo "Usage: $N {start|stop|restart|force-reload}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/examples/etc/otherfile b/examples/etc/otherfile deleted file mode 100644 index e69de29bb..000000000 --- a/examples/etc/otherfile +++ /dev/null diff --git a/examples/etc/puppet/fileserver.conf b/examples/etc/puppet/fileserver.conf deleted file mode 100644 index 163ce1220..000000000 --- a/examples/etc/puppet/fileserver.conf +++ /dev/null @@ -1,13 +0,0 @@ -# $Id$ - -[dist] - path /dist - allow *.puppetlabs.com - -[plugins] - path /var/lib/puppet/plugins - allow *.puppetlabs.com - -[facts] - path /var/lib/puppet/facts - allow *.puppetlabs.com diff --git a/examples/etc/puppet/namespaceauth.conf b/examples/etc/puppet/namespaceauth.conf deleted file mode 100644 index fb08d428b..000000000 --- a/examples/etc/puppet/namespaceauth.conf +++ /dev/null @@ -1,20 +0,0 @@ -# This file is only necessary if your clients listen. -# Note that it affects all puppet daemons, including puppetmasterd, -# which is why puppetmaster is in there. -[fileserver] - allow *.madstop.com - -[puppetmaster] - allow *.madstop.com - -[pelementserver] - allow puppet.madstop.com - -[puppetrunner] - allow culain.madstop.com - -[puppetbucket] - allow *.madstop.com - -[puppetreports] - allow *.madstop.com diff --git a/examples/etc/puppet/puppet.conf b/examples/etc/puppet/puppet.conf deleted file mode 100644 index 151364ebd..000000000 --- a/examples/etc/puppet/puppet.conf +++ /dev/null @@ -1,10 +0,0 @@ -[puppetd] -report = true -factsync = true -pluginsync = true - -[puppetmasterd] -reports = store,rrdgraph,tagmail,log -node_terminus = ldap -ldapserver = culain.madstop.com -ldapbase = dc=madstop,dc=com diff --git a/examples/etc/puppet/tagmail.conf b/examples/etc/puppet/tagmail.conf deleted file mode 100644 index 31c77f4bc..000000000 --- a/examples/etc/puppet/tagmail.conf +++ /dev/null @@ -1 +0,0 @@ -all: user@domain.com diff --git a/examples/execs b/examples/execs deleted file mode 100644 index 44f133098..000000000 --- a/examples/execs +++ /dev/null @@ -1,16 +0,0 @@ -$path = "/usr/bin:/bin" - -exec { "mkdir -p /tmp/fakedir": - path => $path -} - -exec { "rm -rf /tmp/fakedir": - path => $path -} - -exec { "touch /this/directory/does/not/exist": - path => $path, - returns => 1 -} - - diff --git a/examples/file.bl b/examples/file.bl deleted file mode 100644 index ef46ba223..000000000 --- a/examples/file.bl +++ /dev/null @@ -1,11 +0,0 @@ -# $Id$ - -file { - "/tmp/atest": ensure => file, mode => 755; - "/tmp/btest": ensure => file, mode => 755 -} - -file { - "/tmp/ctest": ensure => file; - "/tmp/dtest": ensure => file; -} diff --git a/examples/filedefaults b/examples/filedefaults deleted file mode 100644 index 56cf76a9a..000000000 --- a/examples/filedefaults +++ /dev/null @@ -1,10 +0,0 @@ -# $Id$ - -File { - mode => 755, - recurse => true -} - -file { "/tmp/filedefaultstest": - ensure => file -} diff --git a/examples/fileparsing b/examples/fileparsing deleted file mode 100644 index f9766b9f6..000000000 --- a/examples/fileparsing +++ /dev/null @@ -1,116 +0,0 @@ -# $Id$ - -# this will eventually parse different config files - -# this creates the 'passwd' type, but it does not create any instances -filetype { "passwd": - linesplit => "\n", - escapednewlines => false -} - - -# this creates the 'PasswdUser' type, but again, no instances -filerecord { "user": - filetype => passwd, - fields => [name, password, uid, gid, gcos, home, shell], - namevar => name, - splitchar => ":" - -} - -filetype { ini: - linesplit => "\n\n" -} - -# ini files are different because we don't really care about validating fields -# or at least, we can't do it for most files... -filerecord { "initrecord": - filetype => ini, - fields => [name, password, uid, gid, gcos, home, shell], - namevar => name, - splitchar => ":" - -} - -# this won't work for multiple record types, will it? -# or at least, it requires that we specify multiple times -# ah, and it doesn't specify which of the available record types -# it works for... -passwd { user: - complete => true, # manage the whole file - path => "/etc/passwd" -} - -user { yaytest: - password => x, - uid => 10000, - gid => 10000, - home => "/home/yaytest", - gcos => "The Yaytest", - shell => "/bin/sh" -} - # there seems to be an intrinsic problem here -- i've got subtypes that only - # make sense when an instance of the super type already exists, and i need - # to associate the instances of the subtype with the instances of the supertype - # even if i created the parsers manually, I'd have the same problem - -# this is the crux of it -- i want to be able to say 'user' here without having -# to specify the file, which leaves two options: -# 1) associate the record type with a filetype instance (BAD) -# 2) once the filetype and record type are created, have another command -# that specifically creates a filetype instance and gives names for instances -# of its record types - -define syslog { - - # create a new type, with all defaults - filetype { "syslog": - escapednewlines => true - } - - filerecord { "log": - filetype => syslog, - regex => "^([^#\s]+)\s+(\S+)$", - joinchar => "\t", - fields => [logs, dest] - } - - # these two should just be supported within the filetypes - filerecord { "comment": - filetype => syslog, - regex => "^(#.*)$", - joinchar => "s", - fields => [comment] - } - - filerecord { "blank": - filetype => syslog, - regex => "^(\s*)$", - joinchar => "s", - fields => blank - } -} - -define cron { - filetype { "usercrontab": - } - - # this won't actually work, of course - filerecord { "cronjob": - filetype => crontab, - regex => "^([^#\s]+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$", - joinchar => " ", - fields => [minute, hour, day, month, weekday, command], - defaults => ["*", "*", "*", "*", "*", nil], - optional => [minute, hour, day, month, weekday] - } - - crontab { "luke": - } -} - -# XXX this doesn't work in the slightest -define crontab(name,path) { - usercrontab { "${path}/${name}": - } -} diff --git a/examples/filerecursion b/examples/filerecursion deleted file mode 100644 index b7d8278c2..000000000 --- a/examples/filerecursion +++ /dev/null @@ -1,15 +0,0 @@ -# $Id$ - -file { "/tmp/dirtest/b/a": - mode => 755, -} - -file { "/tmp/dirtest": - mode => 755, - recurse => true, -} - -file { "/tmp/dirtest/b/b": - mode => 644, -} - diff --git a/examples/functions b/examples/functions deleted file mode 100644 index 8e95c3a72..000000000 --- a/examples/functions +++ /dev/null @@ -1,3 +0,0 @@ -# $Id$ - -$yaytest = fact("operatingsystem") diff --git a/examples/groups b/examples/groups deleted file mode 100644 index 35505a2eb..000000000 --- a/examples/groups +++ /dev/null @@ -1,7 +0,0 @@ -# $Id$ - -# there need to be two forms of adding to groups: -# add the current host to a group, and add a list of hosts to a -# group by name - -$group = "crap" diff --git a/examples/head b/examples/head deleted file mode 100644 index 59cbb6593..000000000 --- a/examples/head +++ /dev/null @@ -1,30 +0,0 @@ -# $Id$ - -# this file is responsible for importing all of the files we want to actually test - -# these are all of the simple tests -import "simpletests" -import "assignments" -import "selectors" -#import "iftest" -import "importing" -import "execs" -import "filedefaults" - -# facts are now imported into the top of the namespace -#import "facts" - -# obsoleted -#import "functions" - -# files we no longer need to import directly, or at all in some cases -#import "one" -#import "classing" -#import "components" -#import "file.bl" -#import "fileparsing.disabled" -#import "groups" - -# this imports the more complex files -import "allatonce" # imports classing and components -import "nodes" # imports classing and components diff --git a/examples/hiera/modules/data/manifests/common.pp b/examples/hiera/modules/data/manifests/common.pp index 13071a477..9e0b532e1 100644 --- a/examples/hiera/modules/data/manifests/common.pp +++ b/examples/hiera/modules/data/manifests/common.pp @@ -1,3 +1,4 @@ +# sets the common (across all puppet conf) ntp servers. class data::common { - $ntpservers = ["ntp1.example.com", "ntp2.example.com"] + $ntpservers = ['ntp1.example.com', 'ntp2.example.com'] } diff --git a/examples/hiera/modules/ntp/manifests/config.pp b/examples/hiera/modules/ntp/manifests/config.pp index ff11dfb1f..0638ad1d8 100644 --- a/examples/hiera/modules/ntp/manifests/config.pp +++ b/examples/hiera/modules/ntp/manifests/config.pp @@ -1,5 +1,6 @@ -class ntp::config($ntpservers = hiera("ntpservers")) { - file{"/tmp/ntp.conf": - content => template("ntp/ntp.conf.erb") +# lookup ntpservers from hiera, or allow user of class to provide other value +class ntp::config($ntpservers = hiera('ntpservers')) { + file{'/tmp/ntp.conf': + content => template('ntp/ntp.conf.erb') } } diff --git a/examples/hiera/modules/ntp/manifests/data.pp b/examples/hiera/modules/ntp/manifests/data.pp index 21db54f5b..b300c5fff 100644 --- a/examples/hiera/modules/ntp/manifests/data.pp +++ b/examples/hiera/modules/ntp/manifests/data.pp @@ -1,3 +1,4 @@ +# this class will be loaded using hiera's 'puppet' backend class ntp::data { - $ntpservers = ["1.pool.ntp.org", "2.pool.ntp.org"] + $ntpservers = ['1.pool.ntp.org', '2.pool.ntp.org'] } diff --git a/examples/hiera/modules/users/manifests/common.pp b/examples/hiera/modules/users/manifests/common.pp index b8c0aad1f..18f7195e8 100644 --- a/examples/hiera/modules/users/manifests/common.pp +++ b/examples/hiera/modules/users/manifests/common.pp @@ -1,3 +1,4 @@ +# notifies class users::common { - notify{"Adding users::common": } + notify{'Adding users::common': } } diff --git a/examples/hiera/modules/users/manifests/dc1.pp b/examples/hiera/modules/users/manifests/dc1.pp index 743c0028d..c9f246f4e 100644 --- a/examples/hiera/modules/users/manifests/dc1.pp +++ b/examples/hiera/modules/users/manifests/dc1.pp @@ -1,3 +1,4 @@ +# notifies class users::dc1 { - notify{"Adding users::dc1": } + notify{'Adding users::dc1': } } diff --git a/examples/hiera/modules/users/manifests/development.pp b/examples/hiera/modules/users/manifests/development.pp index 89110a478..93282e9ba 100644 --- a/examples/hiera/modules/users/manifests/development.pp +++ b/examples/hiera/modules/users/manifests/development.pp @@ -1,3 +1,4 @@ +# notifies class users::development { - notify{"Adding users::development": } + notify{'Adding users::development': } } diff --git a/examples/hiera/site.pp b/examples/hiera/site.pp index 7ff69440b..beaa9be3f 100644 --- a/examples/hiera/site.pp +++ b/examples/hiera/site.pp @@ -1,3 +1,3 @@ node default { - hiera_include("classes") + hiera_include('classes') } diff --git a/examples/importing b/examples/importing deleted file mode 100644 index f02604109..000000000 --- a/examples/importing +++ /dev/null @@ -1,8 +0,0 @@ -# $Id$ - -#import "groups" -# testing import loops -import "importing" - -$name = "value" -$system = $operatingsystem diff --git a/examples/mac_dscl.pp b/examples/mac_dscl.pp deleted file mode 100755 index d04f97d58..000000000 --- a/examples/mac_dscl.pp +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env puppet --debug --verbose --trace -# -# Jeff McCune: I use this for developing and testing the directory service -# provider. - -User { provider => "directoryservice" } -Group { provider => "directoryservice" } - -user { - "testgone": - ensure => absent, - uid => 550; - "testhere": - ensure => present, - password => "foobar", - shell => "/bin/bash", - uid => 551; -} - -group { - "testgone": - ensure => absent, - gid => 550; - "testhere": - ensure => present, - gid => 551; - -} diff --git a/examples/mac_dscl_revert.pp b/examples/mac_dscl_revert.pp deleted file mode 100755 index 7c348b33b..000000000 --- a/examples/mac_dscl_revert.pp +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env puppet --debug --verbose --trace -# -# Jeff McCune: I use this for developing and testing the directory service -# provider. - -User { provider => "directoryservice" } -Group { provider => "directoryservice" } - -user { - "testgone": - ensure => absent, - uid => 550; - "testhere": - ensure => absent, - uid => 551; -} - -group { - "testgone": - ensure => absent, - gid => 550; - "testhere": - ensure => absent, - gid => 551; - -} diff --git a/examples/mac_pkgdmg.pp b/examples/mac_pkgdmg.pp deleted file mode 100755 index a2499e815..000000000 --- a/examples/mac_pkgdmg.pp +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env puppet -# - -package -{ - "Foobar.pkg.dmg": ensure => present, provider => pkgdmg; -} diff --git a/examples/modules/sample_module.pp b/examples/modules/sample_module.pp deleted file mode 100644 index 404bf09e8..000000000 --- a/examples/modules/sample_module.pp +++ /dev/null @@ -1,10 +0,0 @@ -# Jeff McCune <jeff.mccune@northstarlabs.net> -# 2007-08-14 -# -# Use: -# puppet --verbose --debug --modulepath=`pwd` ./sample-module.pp -# -# sample-module demonstrates the use of a custom language function -# included within the module bundle. - -include sample_module diff --git a/examples/modules/sample_module/lib/puppet/parser/functions/hostname_to_dn.rb b/examples/modules/sample_module/lib/puppet/parser/functions/hostname_to_dn.rb deleted file mode 100644 index fe4e54992..000000000 --- a/examples/modules/sample_module/lib/puppet/parser/functions/hostname_to_dn.rb +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (C) David Schmitt <david@schmitt.edv-bus.at> -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions -# are met: -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# 3. Neither the name of the Author nor the names of its contributors -# may be used to endorse or promote products derived from this software -# without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE -# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -# SUCH DAMAGE. - -# Jeff McCune <jeff.mccune@northstarlabs.net> -# 2007-08-14 -# See: http://docs.puppetlabs.com/guides/custom_functions.html - -module Puppet::Parser::Functions - newfunction(:hostname_to_dn, :type => :rvalue, :doc => "Given 'foo.bar.com', return 'dc=foo,dc=bar,dc=com'.") do |args| - args[0].split(/\./).map do |s| "dc=#{s}" end.join(",") - end -end diff --git a/examples/modules/sample_module/manifests/init.pp b/examples/modules/sample_module/manifests/init.pp deleted file mode 100644 index e89ba9294..000000000 --- a/examples/modules/sample_module/manifests/init.pp +++ /dev/null @@ -1,12 +0,0 @@ -# Jeff McCune <jeff.mccune@northstarlabs.net> -# -# Demonstration of a custom parser function and erb template within -# a module, working in concert. - -class sample_module { - $fqdn_to_dn = hostname_to_dn($domain) - $sample_template = template("sample-module/sample.erb") - - notice("hostname_to_dn module function returned: [$fqdn_to_dn]") - info("sample.erb looks like:\n$sample_template") -} diff --git a/examples/modules/sample_module/templates/sample.erb b/examples/modules/sample_module/templates/sample.erb deleted file mode 100644 index b13561b45..000000000 --- a/examples/modules/sample_module/templates/sample.erb +++ /dev/null @@ -1,5 +0,0 @@ - -## Jeff McCune <jeff.mccune@northstarlabs.net> -fqdn: <%= fqdn %> -basedn: <%= fqdn_to_dn %> -## end sample.erb ## diff --git a/examples/nodes b/examples/nodes deleted file mode 100644 index 42488e689..000000000 --- a/examples/nodes +++ /dev/null @@ -1,20 +0,0 @@ -# $Id$ - -# define nodes - -#service.setpath("../examples/root/etc/init.d") - -Service { - path => "../examples/root/etc/init.d" -} - -import "classing" - -sleepserver { - path => $operatingsystem ? { - sunos => "../examples/root/etc/configfile", - hpux => "../examples/other/etc/configfile", - default => "../examples/root/etc/configfile" - }, - schedule => true -} diff --git a/examples/one b/examples/one deleted file mode 100644 index 452d32f3e..000000000 --- a/examples/one +++ /dev/null @@ -1,8 +0,0 @@ -# $Id$ - -# this service doesn't actually exist, so we noop it -# and this way, we can test noop :) -service { "funtest": - running => "0", - noop => true -} diff --git a/examples/relationships b/examples/relationships deleted file mode 100644 index e361dc852..000000000 --- a/examples/relationships +++ /dev/null @@ -1,34 +0,0 @@ -# $Id$ - -#service.setpath("../examples/root/etc/init.d") -#puppet.statefile("/tmp/puppetstate") -$path = "../examples/root/etc/configfile" - path => "../examples/root/etc/init.d" - - -define files { - file { "/tmp/yaytest": - ensure => file, - mode => 755 - } - file { "/tmp/exists": - checksum => md5 - } -} - -define sleeper { - file { $path: - mode => 755 - } - service { sleeper: - path => "../examples/root/etc/init.d", - running => 1 - } -} - -files { } - -sleeper { - require => files["yay"], - schedule => true -} diff --git a/examples/selectors b/examples/selectors deleted file mode 100644 index a70399bc7..000000000 --- a/examples/selectors +++ /dev/null @@ -1,28 +0,0 @@ -# $Id$ -# - -$platform = SunOS - -$funtest = $platform ? { - SunOS => yayness, - AIX => goodness, - default => badness -} - -# this is a comment - -$filename = "/tmp/yayness" - -$sleeper = file { $filename: - mode => $platform ? { - SunOS => 644, - default => 755 - }, - create => $platform ? "SunOS" => true -} - -# i guess it has to be solved this way... - -#$platform ? sunos => file { $filename: -# mode => 644 -#} diff --git a/examples/simpletests b/examples/simpletests deleted file mode 100644 index b4fd3234e..000000000 --- a/examples/simpletests +++ /dev/null @@ -1,11 +0,0 @@ -# $Id$ - -file { - "/tmp/atest": ensure => file; - "/tmp/btest": ensure => file -} - -file { - "/tmp/ctest": ensure => file; - "/tmp/dtest": ensure => file; -} diff --git a/examples/svncommit b/examples/svncommit deleted file mode 100644 index 350cd8580..000000000 --- a/examples/svncommit +++ /dev/null @@ -1,13 +0,0 @@ -$path = "/usr/bin:/bin" - -file { "/tmp/svntests": - recurse => true, - checksum => md5 -} - -exec { "echo 'files have been updated'": - cwd => "/tmp/svntests", - refreshonly => true, - require => file["/tmp/svntests"], - path => $path -} diff --git a/ext/debian/changelog b/ext/debian/changelog index 8463e43b1..2e5fd2ac7 100644 --- a/ext/debian/changelog +++ b/ext/debian/changelog @@ -1,8 +1,14 @@ -puppet (3.0.2-1puppetlabs1) hardy lucid natty oneiric unstable sid squeeze wheezy precise; urgency=low +puppet (3.1.0-1puppetlabs1) hardy lucid natty oneiric unstable sid squeeze wheezy precise; urgency=low - * Update to version 3.0.2-1puppetlabs1 + * Update to version 3.1.0-1puppetlabs1 - -- Puppet Labs Release <info@puppetlabs.com> Wed, 26 Dec 2012 15:28:21 -0800 + -- Puppet Labs Release <info@puppetlabs.com> Mon, 04 Feb 2013 10:56:11 -0800 + +puppet (3.1.0-0.1rc1puppetlabs1) lucid natty oneiric precise unstable sid squeeze wheezy precise; urgency=low + + * Add extlookup2hiera manpage to puppet-common.manpages + + -- Matthaus Owens <matthaus@puppetlabs.com> Fri, 25 Jan 2013 14:45:14 +0000 puppet (2.7.19-1puppetlabs2) hardy jaunty karmic lucid maverick natty oneiric unstable lenny sid squeeze wheezy precise; urgency=low diff --git a/ext/debian/fileserver.conf b/ext/debian/fileserver.conf index c72e3c4b8..62598c4e3 100644 --- a/ext/debian/fileserver.conf +++ b/ext/debian/fileserver.conf @@ -1,17 +1,41 @@ -# This file consists of arbitrarily named sections/modules -# defining where files are served from and to whom +# fileserver.conf -# Define a section 'files' -# Adapt the allow/deny settings to your needs. Order -# for allow/deny does not matter, allow always takes precedence -# over deny -#[files] -# path /etc/puppet/files -# allow *.example.com -# deny *.evil.example.com -# allow 192.168.0.0/24 +# Puppet automatically serves PLUGINS and FILES FROM MODULES: anything in +# <module name>/files/<file name> is available to authenticated nodes at +# puppet:///modules/<module name>/<file name>. You do not need to edit this +# file to enable this. -#[plugins] -# allow *.example.com -# deny *.evil.example.com -# allow 192.168.0.0/24 +# MOUNT POINTS + +# If you need to serve files from a directory that is NOT in a module, +# you must create a static mount point in this file: +# +# [extra_files] +# path /etc/puppet/files +# allow * +# +# In the example above, anything in /etc/puppet/files/<file name> would be +# available to authenticated nodes at puppet:///extra_files/<file name>. +# +# Mount points may also use three placeholders as part of their path: +# +# %H - The node's certname. +# %h - The portion of the node's certname before the first dot. (Usually the +# node's short hostname.) +# %d - The portion of the node's certname after the first dot. (Usually the +# node's domain name.) + +# PERMISSIONS + +# Every static mount point should have an `allow *` line; setting more +# granular permissions in this file is deprecated. Instead, you can +# control file access in auth.conf by controlling the +# /file_metadata/<mount point> and /file_content/<mount point> paths: +# +# path ~ ^/file_(metadata|content)/extra_files/ +# auth yes +# allow /^(.+)\.example\.com$/ +# allow_ip 192.168.100.0/24 +# +# If added to auth.conf BEFORE the "path /file" rule, the rule above +# will add stricter restrictions to the extra_files mount point. diff --git a/ext/debian/puppet-common.manpages b/ext/debian/puppet-common.manpages index 49271a764..233d716cd 100644 --- a/ext/debian/puppet-common.manpages +++ b/ext/debian/puppet-common.manpages @@ -1,2 +1,3 @@ man/man5/puppet.conf.5 man/man8/puppet.8 +man/man8/extlookup2hiera.8 diff --git a/ext/debian/puppet.default b/ext/debian/puppet.default index 4bc02a0c2..535f61c3a 100644 --- a/ext/debian/puppet.default +++ b/ext/debian/puppet.default @@ -1,6 +1,8 @@ # Defaults for puppet - sourced by /etc/init.d/puppet -# Start puppet on boot? +# Enable puppet agent service? +# Setting this to "yes" allows the puppet agent service to run. +# Setting this to "no" keeps the puppet agent service from running. START=no # Startup options diff --git a/ext/debian/puppetmaster.default b/ext/debian/puppetmaster.default index df50d3864..be2817a03 100644 --- a/ext/debian/puppetmaster.default +++ b/ext/debian/puppetmaster.default @@ -1,11 +1,14 @@ # Defaults for puppetmaster - sourced by /etc/init.d/puppetmaster -# Start puppetmaster on boot? If you are using passenger, you should -# have this set to "no" +# Enable puppetmaster service? +# Setting this to "yes" allows the puppet master service to run. +# Setting this to "no" keeps the puppet master service from running. +# +# If you are using Passenger, you should have this set to "no." START=yes # Startup options DAEMON_OPTS="" -# What port should the puppetmaster listen on (default: 8140). +# On what port should the puppet master listen? (default: 8140) PORT=8140 diff --git a/ext/envpuppet b/ext/envpuppet index 1635bead5..daea7c526 100755 --- a/ext/envpuppet +++ b/ext/envpuppet @@ -67,6 +67,7 @@ EO_HELP fi if test -d puppet -o -d facter; then + ( echo " WARNING!" echo " Strange things happen if puppet or facter are in the" echo " current working directory" @@ -77,6 +78,7 @@ if test -d puppet -o -d facter; then echo "" echo "Sleeping 2 seconds." echo "" + ) 1>&2 sleep 2 fi diff --git a/ext/gentoo/puppet/fileserver.conf b/ext/gentoo/puppet/fileserver.conf index f38aed7dd..62598c4e3 100644 --- a/ext/gentoo/puppet/fileserver.conf +++ b/ext/gentoo/puppet/fileserver.conf @@ -1,12 +1,41 @@ -# This file consists of arbitrarily named sections/modules -# defining where files are served from and to whom - -# Define a section 'files' -# Adapt the allow/deny settings to your needs. Order -# for allow/deny does not matter, allow always takes precedence -# over deny -[files] - path /var/lib/puppet/files -# allow *.example.com -# deny *.evil.example.com -# allow 192.168.0.0/24 +# fileserver.conf + +# Puppet automatically serves PLUGINS and FILES FROM MODULES: anything in +# <module name>/files/<file name> is available to authenticated nodes at +# puppet:///modules/<module name>/<file name>. You do not need to edit this +# file to enable this. + +# MOUNT POINTS + +# If you need to serve files from a directory that is NOT in a module, +# you must create a static mount point in this file: +# +# [extra_files] +# path /etc/puppet/files +# allow * +# +# In the example above, anything in /etc/puppet/files/<file name> would be +# available to authenticated nodes at puppet:///extra_files/<file name>. +# +# Mount points may also use three placeholders as part of their path: +# +# %H - The node's certname. +# %h - The portion of the node's certname before the first dot. (Usually the +# node's short hostname.) +# %d - The portion of the node's certname after the first dot. (Usually the +# node's domain name.) + +# PERMISSIONS + +# Every static mount point should have an `allow *` line; setting more +# granular permissions in this file is deprecated. Instead, you can +# control file access in auth.conf by controlling the +# /file_metadata/<mount point> and /file_content/<mount point> paths: +# +# path ~ ^/file_(metadata|content)/extra_files/ +# auth yes +# allow /^(.+)\.example\.com$/ +# allow_ip 192.168.100.0/24 +# +# If added to auth.conf BEFORE the "path /file" rule, the rule above +# will add stricter restrictions to the extra_files mount point. diff --git a/ext/ips/puppet-agent b/ext/ips/puppet-agent index 41e90df47..2e6890d6a 100644 --- a/ext/ips/puppet-agent +++ b/ext/ips/puppet-agent @@ -1,7 +1,4 @@ #!/sbin/sh -# It needs the smf property puppet-agent/server to be set to where the server is. -# svccfg -s svc:/network/puppet/agent setprop server/name=asstring:localhost - . /lib/svc/share/smf_include.sh @@ -11,12 +8,10 @@ typeset -r CONF_FILE=/etc/puppet/puppet.conf [[ ! -f "${CONF_FILE}" ]] && exit $SMF_EXIT_ERR_CONFIG typeset -r PUPPET=/usr/bin/puppet -typeset -r PUPPET_SERVER=$(svcprop -p server/name $SMF_FMRI) -[[ -z "${PUPPET_SERVER}" ]] && exit $SMF_EXIT_ERR_CONFIG case "$1" in start) - exec $PUPPET agent --daemonize --server $PUPPET_SERVER + exec $PUPPET agent ;; stop) diff --git a/ext/ips/puppet.p5m b/ext/ips/puppet.p5m index e6c8f8bda..0feecd5f6 100644 --- a/ext/ips/puppet.p5m +++ b/ext/ips/puppet.p5m @@ -1,6 +1,6 @@ -set name=pkg.fmri value=pkg://puppetlabs.com/system/management/puppet@3.0.2,11.4.0-0 +set name=pkg.fmri value=pkg://puppetlabs.com/system/management/puppet@3.1.0,11.4.2-0 set name=pkg.summary value="Puppet, an automated configuration management tool" -set name=pkg.human-version value="3.0.2" +set name=pkg.human-version value="3.1.0" set name=pkg.description value="Puppet, an automated configuration management tool" set name=info.classification value="org.opensolaris.category.2008:System/Administration and Configuration" set name=org.opensolaris.consolidation value="puppet" diff --git a/ext/ips/puppetagent.xml b/ext/ips/puppetagent.xml index 89f5e5419..11d46c972 100644 --- a/ext/ips/puppetagent.xml +++ b/ext/ips/puppetagent.xml @@ -26,10 +26,6 @@ <exec_method type="method" name="stop" exec="/lib/svc/method/puppet-agent stop" timeout_seconds="60"/> - <property_group name='server' type='framework'> - <propval name='name' type='astring' value='puppet' /> - </property_group> - <stability value="Evolving"/> <template> diff --git a/ext/osx/postflight b/ext/osx/postflight new file mode 100644 index 000000000..2e36b25ef --- /dev/null +++ b/ext/osx/postflight @@ -0,0 +1,109 @@ +#!/bin/bash + +#by doing the below, we are ensuring we are modifying the target system the package is being installed on, +#not the OS running the installer +declare -x dest_vol="${3}" +declare -x dscl="${dest_vol}/usr/bin/dscl" +declare -x dspath="${dest_vol}/var/db/dslocal/nodes/Default/" +declare -x scripts_dir="${1}/Contents/Resources/" +declare -x awk="/usr/bin/awk" +declare -x last_user_id='-1' +declare -x last_group_id='-1' + +function idFree() { + declare -a idArray=("${!2}") + for inc in ${idArray[@]} + do + if [ $inc == $1 ] + then + return 1 + fi + done + + return 0 + +} + +function create_puser () { + "${dscl}" -f "${dspath}" localonly -create /Local/Target/Users/puppet + "${dscl}" -f "${dspath}" localonly -create /Local/Target/Users/puppet UniqueID $1 + "${dscl}" -f "${dspath}" localonly -create /Local/Target/Users/puppet PrimaryGroupID $2 +} + +function create_pgroup () { + "${dscl}" -f "${dspath}" localonly -create /Local/Target/Groups/puppet + "${dscl}" -f "${dspath}" localonly -create /Local/Target/Groups/puppet PrimaryGroupID $1 +} + +function scan_users () { + UniqueIDS=(`"${dscl}" -f "${dspath}" localonly list /Local/Target/Users UniqueID | $awk '{print $2}'`); + + #first just check for UID 52 + if idFree '52' UniqueIDS[@] + then + last_user_id='52' + else + for possibleUID in {450..495} + do + if idFree $possibleUID UniqueIDS[@] + then + last_user_id=$possibleUID + #echo $last_good_id + fi + done + fi +} + +function scan_groups () { + GroupIDS=(`"${dscl}" -f "${dspath}" localonly list /Local/Target/Groups PrimaryGroupID | $awk '{print $2}'`); + #check for 52 for group, if it's free, take it, don't bother doing the big search + if idFree '52' GroupIDS[@] + then + last_group_id='52' + else + for groupID in {450..495} + do + if idFree $groupID GroupIDS[@] + then + last_group_id=$groupID + fi + done + fi +} + +echo "looking for Puppet User" +"${dscl}" -f "${dspath}" localonly -read /Local/Target/Users/puppet +puser_exists=$? +echo "Looking for Puppet Group" +"${dscl}" -f "${dspath}" localonly -read /Local/Target/Groups/puppet +pgroup_exists=$? +# exit status 56 indicates user/group not found +# exit status 0 indicates user/group does exist + +if [ $pgroup_exists == '0' ] && [ $puser_exists == '0' ]; then + #Puppet user and group already exist + echo "Puppet User / Group already exist, not adding anything" + #storing the existing UID/GID to set permissions for /var/lib/puppet and /etc/puppet/puppet.conf + last_group_id=`"${dscl}" -f "${dspath}" localonly -read /Local/Target/Groups/puppet PrimaryGroupID | awk '{print $2}'` + last_user_id=`"${dscl}" -f "${dspath}" localonly -read /Local/Target/Users/puppet UniqueID | awk '{print $2}'` +elif [ $pgroup_exists == '0' ] && [ $puser_exists == '56' ]; then + #puppet group exists, but user does not + last_group_id=`"${dscl}" -f "${dspath}" localonly -read /Local/Target/Groups/puppet PrimaryGroupID | awk '{print $2}'` + scan_users + echo "Creating Puppet User (uid: $last_user_id) in existing Puppet Group (gid: $last_group_id)" + create_puser $last_user_id $last_group_id +elif [ $pgroup_exists == '56' ] && [ $puser_exists == '0' ]; then + #puppet user exists, but group does not + last_user_id=`"${dscl}" -f "${dspath}" localonly -read /Local/Target/Users/puppet UniqueID | awk '{print $2}'` + scan_groups + echo "Creating Puppet Group (gid: $last_group_id), Puppet User exists (uid: $last_user_id)" + create_pgroup $last_group_id +elif [ $pgroup_exists == '56' ] && [ $puser_exists == '56' ]; then + scan_users + scan_groups + echo "Creating Puppet User (uid: $last_user_id) in new Puppet Group (gid: $last_group_id)" + create_pgroup $last_group_id + create_puser $last_user_id $last_group_id +else + echo "Something went wrong and user creation will need to be done manually" +fi diff --git a/ext/osx/preflight b/ext/osx/preflight index f0239fd01..dcf2c2487 100644 --- a/ext/osx/preflight +++ b/ext/osx/preflight @@ -455,6 +455,8 @@ /bin/rm -Rf "${3}/puppet/indirector/node/store_configs.rb" +/bin/rm -Rf "${3}/puppet/indirector/node/write_only_yaml.rb" + /bin/rm -Rf "${3}/puppet/indirector/node/yaml.rb" /bin/rm -Rf "${3}/puppet/indirector/none.rb" @@ -1139,6 +1141,8 @@ /bin/rm -Rf "${3}/puppet/settings/boolean_setting.rb" +/bin/rm -Rf "${3}/puppet/settings/config_file.rb" + /bin/rm -Rf "${3}/puppet/settings/directory_setting.rb" /bin/rm -Rf "${3}/puppet/settings/duration_setting.rb" @@ -1153,6 +1157,8 @@ /bin/rm -Rf "${3}/puppet/settings/terminus_setting.rb" +/bin/rm -Rf "${3}/puppet/settings/value_translator.rb" + /bin/rm -Rf "${3}/puppet/settings.rb" /bin/rm -Rf "${3}/puppet/simple_graph.rb" @@ -1171,6 +1177,8 @@ /bin/rm -Rf "${3}/puppet/ssl/certificate_revocation_list.rb" +/bin/rm -Rf "${3}/puppet/ssl/certificate_signer.rb" + /bin/rm -Rf "${3}/puppet/ssl/configuration.rb" /bin/rm -Rf "${3}/puppet/ssl/digest.rb" diff --git a/ext/osx/prototype.plist b/ext/osx/prototype.plist index 48a0aaf94..dd452a1fc 100644 --- a/ext/osx/prototype.plist +++ b/ext/osx/prototype.plist @@ -5,7 +5,7 @@ <key>CFBundleIdentifier</key> <string></string> <key>CFBundleShortVersionString</key> - <string>3.0.2</string> + <string>3.1.0</string> <key>IFMajorVersion</key> <integer></integer> <key>IFMinorVersion</key> diff --git a/ext/project_data.yaml b/ext/project_data.yaml index 6e7f6691c..33f6b7444 100644 --- a/ext/project_data.yaml +++ b/ext/project_data.yaml @@ -15,8 +15,8 @@ gem_executables: 'puppet' gem_default_executables: 'puppet' gem_forge_project: 'puppet' gem_runtime_dependencies: - facter: '~> 1.6.11' - hiera: '~> 1.0.0' + facter: '~> 1.6' + hiera: '~> 1.0' gem_rdoc_options: - --title - "Puppet - Configuration Management" diff --git a/ext/redhat/fileserver.conf b/ext/redhat/fileserver.conf index 67e387ca0..62598c4e3 100644 --- a/ext/redhat/fileserver.conf +++ b/ext/redhat/fileserver.conf @@ -1,12 +1,41 @@ -# This file consists of arbitrarily named sections/modules -# defining where files are served from and to whom - -# Define a section 'files' -# Adapt the allow/deny settings to your needs. Order -# for allow/deny does not matter, allow always takes precedence -# over deny -# [files] -# path /var/lib/puppet/files -# allow *.example.com -# deny *.evil.example.com -# allow 192.168.0.0/24 +# fileserver.conf + +# Puppet automatically serves PLUGINS and FILES FROM MODULES: anything in +# <module name>/files/<file name> is available to authenticated nodes at +# puppet:///modules/<module name>/<file name>. You do not need to edit this +# file to enable this. + +# MOUNT POINTS + +# If you need to serve files from a directory that is NOT in a module, +# you must create a static mount point in this file: +# +# [extra_files] +# path /etc/puppet/files +# allow * +# +# In the example above, anything in /etc/puppet/files/<file name> would be +# available to authenticated nodes at puppet:///extra_files/<file name>. +# +# Mount points may also use three placeholders as part of their path: +# +# %H - The node's certname. +# %h - The portion of the node's certname before the first dot. (Usually the +# node's short hostname.) +# %d - The portion of the node's certname after the first dot. (Usually the +# node's domain name.) + +# PERMISSIONS + +# Every static mount point should have an `allow *` line; setting more +# granular permissions in this file is deprecated. Instead, you can +# control file access in auth.conf by controlling the +# /file_metadata/<mount point> and /file_content/<mount point> paths: +# +# path ~ ^/file_(metadata|content)/extra_files/ +# auth yes +# allow /^(.+)\.example\.com$/ +# allow_ip 192.168.100.0/24 +# +# If added to auth.conf BEFORE the "path /file" rule, the rule above +# will add stricter restrictions to the extra_files mount point. diff --git a/ext/redhat/puppet.spec b/ext/redhat/puppet.spec index e6683103b..4312fa544 100644 --- a/ext/redhat/puppet.spec +++ b/ext/redhat/puppet.spec @@ -16,8 +16,8 @@ %endif # VERSION is subbed out during rake srpm process -%global realversion 3.0.2 -%global rpmversion 3.0.2 +%global realversion 3.1.0 +%global rpmversion 3.1.0 %global confdir ext/redhat @@ -97,22 +97,11 @@ patch -s -p1 < ext/redhat/rundir-perms.patch %build -# Fix some rpmlint complaints -for f in mac_dscl.pp mac_dscl_revert.pp \ - mac_pkgdmg.pp ; do - sed -i -e'1d' examples/$f - chmod a-x examples/$f -done for f in external/nagios.rb relationship.rb; do sed -i -e '1d' lib/puppet/$f done -#chmod +x ext/puppetstoredconfigclean.rb - -find examples/ -type f -empty | xargs rm -find examples/ -type f | xargs chmod a-x -# puppet-queue.conf is more of an example, used for stompserver -mv conf/puppet-queue.conf examples/etc/puppet/ +find examples/ -type f | xargs --no-run-if-empty chmod a-x %install rm -rf %{buildroot} @@ -203,11 +192,7 @@ mkdir -p %{buildroot}%{_sysconfdir}/%{name}/modules %{_datadir}/emacs %{_datadir}/vim %{_datadir}/%{name} -# These need to be owned by puppet so the server can -# write to them -%attr(-, puppet, puppet) %{_localstatedir}/run/puppet -%attr(-, puppet, puppet) %{_localstatedir}/log/puppet -%attr(-, puppet, puppet) %{_localstatedir}/lib/puppet +# man pages %{_mandir}/man5/puppet.conf.5.gz %{_mandir}/man8/puppet.8.gz %{_mandir}/man8/puppet-agent.8.gz @@ -243,6 +228,15 @@ mkdir -p %{buildroot}%{_sysconfdir}/%{name}/modules %{_mandir}/man8/puppet-resource_type.8.gz %{_mandir}/man8/puppet-secret_agent.8.gz %{_mandir}/man8/puppet-status.8.gz +%{_mandir}/man8/extlookup2hiera.8.gz +# These need to be owned by puppet so the server can +# write to them. The separate %defattr's are required +# to work around RH Bugzilla 681540 +%defattr(-, puppet, puppet, 0755) +%{_localstatedir}/run/puppet +%defattr(-, puppet, puppet, 0750) +%{_localstatedir}/log/puppet +%{_localstatedir}/lib/puppet %files server %defattr(-, root, root, 0755) @@ -383,8 +377,20 @@ fi rm -rf %{buildroot} %changelog -* Wed Dec 26 2012 Puppet Labs Release <info@puppetlabs.com> - 3.0.2-1 -- Build for 3.0.2 +* Mon Feb 04 2013 Puppet Labs Release <info@puppetlabs.com> - 3.1.0-1 +- Build for 3.1.0 + +* Fri Jan 25 2013 Matthaus Owens <matthaus@puppetlabs.com> - 3.1.0-0.1rc1 +- Add extlookup2hiera.8.gz to the files list + +* Wed Jan 9 2013 Ryan Uber <ru@ryanuber.com> - 3.1.0-0.1rc1 +- Work-around for RH Bugzilla 681540 + +* Tue Dec 18 2012 Matthaus Owens <matthaus@puppetlabs.com> +- Remove for loop on examples/ code which no longer exists. Add --no-run-if-empty to xargs invocations. + +* Sat Dec 1 2012 Ryan Uber <ryuber@cisco.com> +- Fix for logdir perms regression (#17866) * Wed Aug 29 2012 Moses Mendoza <moses@puppetlabs.com> - 3.0.0-0.1rc5 - Update for 3.0.0 rc5 diff --git a/install.rb b/install.rb index 85c617655..9934526e8 100755 --- a/install.rb +++ b/install.rb @@ -179,8 +179,6 @@ def prepare_installation end - InstallOptions.tests = true - ARGV.options do |opts| opts.banner = "Usage: #{File.basename($0)} [options]" opts.separator "" @@ -190,8 +188,9 @@ def prepare_installation opts.on('--[no-]ri', 'Prevents the creation of RI output.', 'Default off on mswin32.') do |onri| InstallOptions.ri = onri end - opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default on.') do |ontest| + opts.on('--[no-]tests', 'Prevents the execution of unit tests.', 'Default off.') do |ontest| InstallOptions.tests = ontest + warn "The tests flag is no longer functional in Puppet and is deprecated as of Dec 19, 2012. It will be removed in a future version of Puppet." end opts.on('--[no-]configs', 'Prevents the installation of config files', 'Default off.') do |ontest| InstallOptions.configs = ontest @@ -217,13 +216,11 @@ def prepare_installation opts.on('--quick', 'Performs a quick installation. Only the', 'installation is done.') do |quick| InstallOptions.rdoc = false InstallOptions.ri = false - InstallOptions.tests = false InstallOptions.configs = true end opts.on('--full', 'Performs a full installation. All', 'optional installation steps are run.') do |full| InstallOptions.rdoc = true InstallOptions.ri = true - InstallOptions.tests = true InstallOptions.configs = true end opts.separator("") diff --git a/lib/puppet.rb b/lib/puppet.rb index 543096f88..817766206 100644 --- a/lib/puppet.rb +++ b/lib/puppet.rb @@ -9,6 +9,9 @@ require 'puppet/settings' require 'puppet/util/feature' require 'puppet/util/suidmanager' require 'puppet/util/run_mode' +require 'puppet/external/pson/common' +require 'puppet/external/pson/version' +require 'puppet/external/pson/pure' #------------------------------------------------------------ # the top-level module @@ -18,6 +21,9 @@ require 'puppet/util/run_mode' # # it's also a place to find top-level commands like 'debug' +# The main Puppet class. Everything is contained here. +# +# @api public module Puppet class << self include Puppet::Util @@ -46,7 +52,11 @@ module Puppet @@settings.define_settings(section, hash) end - # configuration parameter access and stuff + # Get the value for a setting + # + # @param [Symbol] param the setting to retrieve + # + # @api public def self.[](param) if param == :debug return Puppet::Util::Log.level == :debug @@ -102,31 +112,36 @@ module Puppet end # Parse the config file for this process. + # @deprecated Use {#initialize_settings} def self.parse_config() Puppet.deprecation_warning("Puppet.parse_config is deprecated; please use Faces API (which will handle settings and state management for you), or (less desirable) call Puppet.initialize_settings") Puppet.initialize_settings end - # Initialize puppet's settings. This is intended only for use by external tools that are not - # built off of the Faces API or the Puppet::Util::Application class. It may also be used + # Initialize puppet's settings. This is intended only for use by external tools that are not + # built off of the Faces API or the Puppet::Util::Application class. It may also be used # to initialize state so that a Face may be used programatically, rather than as a stand-alone # command-line tool. # - # Note that this API may be subject to change in the future. - def self.initialize_settings() - do_initialize_settings_for_run_mode(:user) + # @api public + # @param args [Array<String>] the command line arguments to use for initialization + # @return [void] + def self.initialize_settings(args = []) + do_initialize_settings_for_run_mode(:user, args) end - # Initialize puppet's settings for a specified run_mode. This + # Initialize puppet's settings for a specified run_mode. + # + # @deprecated Use {#initialize_settings} def self.initialize_settings_for_run_mode(run_mode) Puppet.deprecation_warning("initialize_settings_for_run_mode may be removed in a future release, as may run_mode itself") - do_initialize_settings_for_run_mode(run_mode) + do_initialize_settings_for_run_mode(run_mode, []) end # private helper method to provide the implementation details of initializing for a run mode, # but allowing us to control where the deprecation warning is issued - def self.do_initialize_settings_for_run_mode(run_mode) - Puppet.settings.initialize_global_settings + def self.do_initialize_settings_for_run_mode(run_mode, args) + Puppet.settings.initialize_global_settings(args) run_mode = Puppet::Util::RunMode[run_mode] Puppet.settings.initialize_app_defaults(Puppet::Settings.app_defaults_for_run_mode(run_mode)) end diff --git a/lib/puppet/application.rb b/lib/puppet/application.rb index a437da731..110ababae 100644 --- a/lib/puppet/application.rb +++ b/lib/puppet/application.rb @@ -1,8 +1,11 @@ require 'optparse' +require 'puppet/util/command_line' require 'puppet/util/plugins' require 'puppet/util/constant_inflector' require 'puppet/error' +module Puppet + # This class handles all the aspects of a Puppet application/executable # * setting up options # * setting up logs @@ -116,13 +119,14 @@ require 'puppet/error' # process_member(member) # end # end -module Puppet class Application require 'puppet/util' include Puppet::Util DOCPATTERN = ::File.expand_path(::File.dirname(__FILE__) + "/util/command_line/*" ) + CommandLineArgs = Struct.new(:subcommand_name, :args) + @loader = Puppet::Util::Autoload.new(self, 'puppet/application') class << self include Puppet::Util @@ -219,17 +223,32 @@ class Application @option_parser_commands end - def find(file_name) - # This should probably be using the autoloader, but due to concerns about the fact that - # the autoloader currently considers the modulepath when looking for things to load, - # we're delaying that for now. + # @return [Array<String>] the names of available applications + # @api public + def available_application_names + @loader.files_to_load.map do |fn| + ::File.basename(fn, '.rb') + end.uniq + end + + # Finds the class for a given application and loads the class. This does + # not create an instance of the application, it only gets a handle to the + # class. The code for the application is expected to live in a ruby file + # `puppet/application/#{name}.rb` that is available on the `$LOAD_PATH`. + # + # @param application_name [String] the name of the application to find (eg. "apply"). + # @return [Class] the Class instance of the application that was found. + # @raise [Puppet::Error] if the application class was not found. + # @raise [LoadError] if there was a problem loading the application file. + # @api public + def find(application_name) begin - require ::File.join('puppet', 'application', file_name.to_s.downcase) + require @loader.expand(application_name.to_s.downcase) rescue LoadError => e - Puppet.log_and_raise(e, "Unable to find application '#{file_name}'. #{e}") + Puppet.log_and_raise(e, "Unable to find application '#{application_name}'. #{e}") end - class_name = Puppet::Util::ConstantInflector.file2constant(file_name.to_s) + class_name = Puppet::Util::ConstantInflector.file2constant(application_name.to_s) clazz = try_load_class(class_name) @@ -239,7 +258,7 @@ class Application #### and then get rid of this stanza in a subsequent release. ################################################################ if (clazz.nil?) - class_name = file_name.capitalize + class_name = application_name.capitalize clazz = try_load_class(class_name) end ################################################################ @@ -247,7 +266,7 @@ class Application ################################################################ if clazz.nil? - raise Puppet::Error.new("Unable to load application class '#{class_name}' from file 'puppet/application/#{file_name}.rb'") + raise Puppet::Error.new("Unable to load application class '#{class_name}' from file 'puppet/application/#{application_name}.rb'") end return clazz @@ -315,15 +334,14 @@ class Application def preinit end - def initialize(command_line = nil) - - require 'puppet/util/command_line' - @command_line = command_line || Puppet::Util::CommandLine.new + def initialize(command_line = Puppet::Util::CommandLine.new) + @command_line = CommandLineArgs.new(command_line.subcommand_name, command_line.args.dup) @options = {} - end - # This is the main application entry point + # Execute the application. + # @api public + # @return [void] def run # I don't really like the names of these lifecycle phases. It would be nice to change them to some more meaningful diff --git a/lib/puppet/application/agent.rb b/lib/puppet/application/agent.rb index 37b5f7fce..e919242f7 100644 --- a/lib/puppet/application/agent.rb +++ b/lib/puppet/application/agent.rb @@ -241,10 +241,10 @@ configuration options can also be generated by running puppet agent with debugging or verbosity is enabled. * --no-client: - Do not create a config client. This will cause the daemon to run - without ever checking for its configuration automatically, and only - makes sense when puppet agent is being run with listen = true in puppet.conf - or was started with the `--listen` option. + Do not create a config client. This will cause the daemon to start + but not check configuration unless it is triggered with `puppet + kick`. This only makes sense when puppet agent is being run with + listen = true in puppet.conf or was started with the `--listen` option. * --noop: Use 'noop' mode where the daemon runs in a no-op or dry-run mode. This diff --git a/lib/puppet/application/master.rb b/lib/puppet/application/master.rb index e9eff973a..69909beb3 100644 --- a/lib/puppet/application/master.rb +++ b/lib/puppet/application/master.rb @@ -120,18 +120,27 @@ Luke Kanies COPYRIGHT --------- -Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License +Copyright (c) 2012 Puppet Labs, LLC Licensed under the Apache 2.0 License HELP end - def app_defaults() - super.merge :facts_terminus => 'yaml' + # Sets up the 'node_cache_terminus' default to use the Write Only Yaml terminus :write_only_yaml. + # If this is not wanted, the setting ´node_cache_terminus´ should be set to nil. + # @see Puppet::Node::WriteOnlyYaml + # @see #setup_node_cache + # @see puppet issue 16753 + # + def app_defaults + super.merge({ + :node_cache_terminus => :write_only_yaml, + :facts_terminus => 'yaml' + }) end def preinit Signal.trap(:INT) do - $stderr.puts "Cancelling startup" + $stderr.puts "Canceling startup" exit(0) end @@ -151,7 +160,6 @@ Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License 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.indirection.find(options[:node]) raise "Could not compile catalog for #{options[:node]}" @@ -241,6 +249,16 @@ Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License end end + # Sets up a special node cache "write only yaml" that collects and stores node data in yaml + # but never finds or reads anything (this since a real cache causes stale data to be served + # in circumstances when the cache can not be cleared). + # @see puppet issue 16753 + # @see Puppet::Node::WriteOnlyYaml + # @return [void] + def setup_node_cache + Puppet::Node.indirection.cache_class = Puppet[:node_cache_terminus] + end + def setup raise Puppet::Error.new("Puppet master is not supported on Microsoft Windows") if Puppet.features.microsoft_windows? @@ -252,6 +270,8 @@ Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2.0 License setup_terminuses + setup_node_cache + setup_ssl end end diff --git a/lib/puppet/defaults.rb b/lib/puppet/defaults.rb index 6e40ff341..a83fc4bcf 100644 --- a/lib/puppet/defaults.rb +++ b/lib/puppet/defaults.rb @@ -1,4 +1,6 @@ # The majority of Puppet's configuration settings are set in this file. + + module Puppet ############################################################################################ @@ -155,12 +157,6 @@ module Puppet "all files referenced with `import` statements to exist. This setting was primarily\n" + "designed for use with commit hooks for parse-checking.", }, - :authconfig => { - :default => "$confdir/namespaceauth.conf", - :desc => "The configuration file that defines the rights to the different\n" + - "namespaces and methods. This can be used as a coarse-grained\n" + - "authorization system for both `puppet agent` and `puppet master`.", - }, :environment => { :default => "production", :desc => "The environment Puppet is running in. For clients\n" + @@ -215,6 +211,13 @@ module Puppet :default => "plain", :desc => "Where to find information about nodes.", }, + :node_cache_terminus => { + :type => :terminus, + :default => nil, + :desc => "How to store cached nodes. + Valid values are (none), 'json', 'yaml' or write only yaml ('write_only_yaml'). + The master application defaults to 'write_only_yaml', all others to none.", + }, :data_binding_terminus => { :type => :terminus, :default => "hiera", @@ -676,11 +679,8 @@ EOT :ca_ttl => { :default => "5y", :type => :duration, - :desc => "The default TTL for new certificates. Can be specified as a duration." - }, - :ca_md => { - :default => "md5", - :desc => "The type of hash used in certificates.", + :desc => "The default TTL for new certificates. If this setting is set, ca_days is ignored. + Can be specified as a duration." }, :req_bits => { :default => 4096, @@ -1085,9 +1085,14 @@ EOT }, :dynamicfacts => { :default => "memorysize,memoryfree,swapsize,swapfree", - :desc => "Facts that are dynamic; these facts will be ignored when deciding whether + :desc => "(Deprecated) 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.", + :hook => proc { |value| + if value + Puppet.deprecation_warning "The dynamicfacts setting is deprecated and will be ignored." + end + } }, :splaylimit => { :default => "$runinterval", diff --git a/lib/puppet/error.rb b/lib/puppet/error.rb index 43a8df0f8..dceeea38e 100644 --- a/lib/puppet/error.rb +++ b/lib/puppet/error.rb @@ -1,4 +1,4 @@ -module Puppet # :nodoc: +module Puppet # The base class for all Puppet errors. It can wrap another exception class Error < RuntimeError attr_reader :original diff --git a/lib/puppet/face/help.rb b/lib/puppet/face/help.rb index f20df3a30..ef445f862 100644 --- a/lib/puppet/face/help.rb +++ b/lib/puppet/face/help.rb @@ -1,6 +1,5 @@ require 'puppet/face' require 'puppet/application/face_base' -require 'puppet/util/command_line' require 'puppet/util/constant_inflector' require 'pathname' require 'erb' @@ -123,7 +122,7 @@ Detail: "#{detail.message}" # Return a list of applications that are not simply just stubs for Faces. def legacy_applications - Puppet::Util::CommandLine.available_subcommands.reject do |appname| + Puppet::Application.available_application_names.reject do |appname| (is_face_app?(appname)) or (exclude_from_docs?(appname)) end.sort end @@ -134,7 +133,7 @@ Detail: "#{detail.message}" # element in the outer array is a pair whose first element is a String containing the application # name, and whose second element is a String containing the summary for that application. def all_application_summaries() - Puppet::Util::CommandLine.available_subcommands.sort.inject([]) do |result, appname| + Puppet::Application.available_application_names.sort.inject([]) do |result, appname| next result if exclude_from_docs?(appname) if (is_face_app?(appname)) @@ -152,7 +151,6 @@ Detail: "#{detail.message}" def horribly_extract_summary_from(appname) begin - require "puppet/application/#{appname}" help = Puppet::Application[appname].help.split("\n") # Now we find the line with our summary, extract it, and return it. This # depends on the implementation coincidence of how our pages are diff --git a/lib/puppet/face/man.rb b/lib/puppet/face/man.rb index c43ead3ec..8042da893 100644 --- a/lib/puppet/face/man.rb +++ b/lib/puppet/face/man.rb @@ -59,7 +59,13 @@ Puppet::Face.define(:man, '0.0.1') do # OK, if we have Ronn on the path we can delegate to it and override the # normal output process. Otherwise delegate to a pager on the raw text, # otherwise we finally just delegate to our parent. Oh, well. - ENV['LESS'] ||= 'FRSX' # emulate git... + + # These are the same options for less that git normally uses. + # -R : Pass through color control codes (allows display of colors) + # -X : Don't init/deinit terminal (leave display on screen on exit) + # -F : automatically exit if display fits entirely on one screen + # -S : don't wrap long lines + ENV['LESS'] ||= 'FRSX' ronn = Puppet::Util.which('ronn') pager = [ENV['MANPAGER'], ENV['PAGER'], 'less', 'most', 'more']. @@ -84,7 +90,7 @@ Puppet::Face.define(:man, '0.0.1') do def legacy_applications # The list of applications, less those that are duplicated as a face. - Puppet::Util::CommandLine.available_subcommands.reject do |appname| + Puppet::Application.available_application_names.reject do |appname| Puppet::Face.face? appname.to_sym, :current or # ...this is a nasty way to exclude non-applications. :( %w{face_base indirection_base}.include? appname diff --git a/lib/puppet/feature/pson.rb b/lib/puppet/feature/pson.rb index 0ebb2806f..64c15f16a 100644 --- a/lib/puppet/feature/pson.rb +++ b/lib/puppet/feature/pson.rb @@ -1,6 +1,4 @@ Puppet.features.add(:pson) do - require 'puppet/external/pson/common' - require 'puppet/external/pson/version' - require 'puppet/external/pson/pure' + Puppet.deprecation_warning "There is no need to check for pson support. It is always available." true end diff --git a/lib/puppet/indirector/catalog/active_record.rb b/lib/puppet/indirector/catalog/active_record.rb index 2af2430c4..8e0d96f41 100644 --- a/lib/puppet/indirector/catalog/active_record.rb +++ b/lib/puppet/indirector/catalog/active_record.rb @@ -5,6 +5,9 @@ require 'puppet/resource/catalog' class Puppet::Resource::Catalog::ActiveRecord < Puppet::Indirector::ActiveRecord use_ar_model Puppet::Rails::Host + desc "A component of ActiveRecord storeconfigs. ActiveRecord-based storeconfigs + and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" + def initialize Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" super diff --git a/lib/puppet/indirector/catalog/compiler.rb b/lib/puppet/indirector/catalog/compiler.rb index 09afedf9b..88ee07400 100644 --- a/lib/puppet/indirector/catalog/compiler.rb +++ b/lib/puppet/indirector/catalog/compiler.rb @@ -4,8 +4,7 @@ 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 "Compiles catalogs on demand using Puppet's compiler." include Puppet::Util diff --git a/lib/puppet/indirector/catalog/queue.rb b/lib/puppet/indirector/catalog/queue.rb index 581382e9e..51356526b 100644 --- a/lib/puppet/indirector/catalog/queue.rb +++ b/lib/puppet/indirector/catalog/queue.rb @@ -2,4 +2,8 @@ require 'puppet/resource/catalog' require 'puppet/indirector/queue' class Puppet::Resource::Catalog::Queue < Puppet::Indirector::Queue + + desc "Part of async storeconfigs, requiring the puppet queue daemon. ActiveRecord-based storeconfigs + and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" + end diff --git a/lib/puppet/indirector/catalog/static_compiler.rb b/lib/puppet/indirector/catalog/static_compiler.rb index add339200..86bf0eddd 100644 --- a/lib/puppet/indirector/catalog/static_compiler.rb +++ b/lib/puppet/indirector/catalog/static_compiler.rb @@ -3,6 +3,36 @@ require 'puppet/resource/catalog' require 'puppet/indirector/code' class Puppet::Resource::Catalog::StaticCompiler < Puppet::Indirector::Code + + desc %q{Compiles catalogs on demand using the optional static compiler. This + functions similarly to the normal compiler, but it replaces puppet:/// file + URLs with explicit metadata and file content hashes, expecting puppet agent + to fetch the exact specified content from the filebucket. This guarantees + that a given catalog will always result in the same file states. It also + decreases catalog application time and fileserver load, at the cost of + increased compilation time. + + This terminus works today, but cannot be used without additional + configuration. Specifically: + + You must create a `Filebucket['puppet']` resource in site.pp (or somewhere + else where it will be added to every node's catalog). The title of this + resource **MUST** be "puppet"; the static compiler treats this title as magical. + + # Note: the special $servername var always contains the master's FQDN, + # even if it was reached at a different name. + filebucket { puppet: + server => $servername, + path => false, + } + + You must set `catalog_terminus = static_compiler` in the puppet master's puppet.conf. + + If you are using multiple puppet masters, you must configure load balancer + affinity for agent nodes. This is because puppet masters other than the one + that compiled a given catalog may not have stored the required file contents + in their filebuckets.} + def compiler @compiler ||= indirection.terminus(:compiler) end diff --git a/lib/puppet/indirector/catalog/store_configs.rb b/lib/puppet/indirector/catalog/store_configs.rb index 2a6bdb5a9..e2921b20d 100644 --- a/lib/puppet/indirector/catalog/store_configs.rb +++ b/lib/puppet/indirector/catalog/store_configs.rb @@ -2,4 +2,7 @@ require 'puppet/indirector/store_configs' require 'puppet/resource/catalog' class Puppet::Resource::Catalog::StoreConfigs < Puppet::Indirector::StoreConfigs + + desc %q{Part of the "storeconfigs" feature. Should not be directly set by end users.} + end diff --git a/lib/puppet/indirector/certificate_request/rest.rb b/lib/puppet/indirector/certificate_request/rest.rb index 81810551f..a2004af45 100644 --- a/lib/puppet/indirector/certificate_request/rest.rb +++ b/lib/puppet/indirector/certificate_request/rest.rb @@ -6,4 +6,5 @@ class Puppet::SSL::CertificateRequest::Rest < Puppet::Indirector::REST use_server_setting(:ca_server) use_port_setting(:ca_port) + use_srv_service(:ca) end diff --git a/lib/puppet/indirector/certificate_revocation_list/rest.rb b/lib/puppet/indirector/certificate_revocation_list/rest.rb index 06cbb19f2..70dc1d4dd 100644 --- a/lib/puppet/indirector/certificate_revocation_list/rest.rb +++ b/lib/puppet/indirector/certificate_revocation_list/rest.rb @@ -6,4 +6,5 @@ class Puppet::SSL::CertificateRevocationList::Rest < Puppet::Indirector::REST use_server_setting(:ca_server) use_port_setting(:ca_port) + use_srv_service(:ca) end diff --git a/lib/puppet/indirector/certificate_status/file.rb b/lib/puppet/indirector/certificate_status/file.rb index 9061d9423..329a1bec2 100644 --- a/lib/puppet/indirector/certificate_status/file.rb +++ b/lib/puppet/indirector/certificate_status/file.rb @@ -7,6 +7,10 @@ require 'puppet/ssl/host' require 'puppet/ssl/key' class Puppet::Indirector::CertificateStatus::File < Puppet::Indirector::Code + + desc "Manipulate certificate status on the local filesystem. Only functional + on the CA." + def ca raise ArgumentError, "This process is not configured as a certificate authority" unless Puppet::SSL::CertificateAuthority.ca? Puppet::SSL::CertificateAuthority.new diff --git a/lib/puppet/indirector/certificate_status/rest.rb b/lib/puppet/indirector/certificate_status/rest.rb index c53b663b5..e2a492881 100644 --- a/lib/puppet/indirector/certificate_status/rest.rb +++ b/lib/puppet/indirector/certificate_status/rest.rb @@ -7,4 +7,5 @@ class Puppet::Indirector::CertificateStatus::Rest < Puppet::Indirector::REST use_server_setting(:ca_server) use_port_setting(:ca_port) + use_srv_service(:ca) end diff --git a/lib/puppet/indirector/facts/active_record.rb b/lib/puppet/indirector/facts/active_record.rb index e5fc798bf..88aa4efe4 100644 --- a/lib/puppet/indirector/facts/active_record.rb +++ b/lib/puppet/indirector/facts/active_record.rb @@ -6,6 +6,9 @@ require 'puppet/indirector/active_record' class Puppet::Node::Facts::ActiveRecord < Puppet::Indirector::ActiveRecord use_ar_model Puppet::Rails::Host + desc "A component of ActiveRecord storeconfigs and inventory. ActiveRecord-based storeconfigs + and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" + def initialize Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" super diff --git a/lib/puppet/indirector/facts/couch.rb b/lib/puppet/indirector/facts/couch.rb index fda2b9191..54980eb14 100644 --- a/lib/puppet/indirector/facts/couch.rb +++ b/lib/puppet/indirector/facts/couch.rb @@ -2,6 +2,9 @@ require 'puppet/node/facts' require 'puppet/indirector/couch' class Puppet::Node::Facts::Couch < Puppet::Indirector::Couch + desc "Store facts in CouchDB. This should not be used with the inventory service; + it is for more obscure custom integrations. If you are wondering whether you + should use it, you shouldn't; use PuppetDB instead." # Return the facts object or nil if there is no document def find(request) doc = super diff --git a/lib/puppet/indirector/facts/inventory_active_record.rb b/lib/puppet/indirector/facts/inventory_active_record.rb index 97765d6d5..4add7f2be 100644 --- a/lib/puppet/indirector/facts/inventory_active_record.rb +++ b/lib/puppet/indirector/facts/inventory_active_record.rb @@ -6,6 +6,10 @@ require 'puppet/util/retryaction' class Puppet::Node::Facts::InventoryActiveRecord < Puppet::Indirector::ActiveRecord + desc "Medium-performance fact storage suitable for the inventory service. + Most users should use PuppetDB instead. Note: ActiveRecord-based storeconfigs + and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" + def initialize Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" super diff --git a/lib/puppet/indirector/facts/store_configs.rb b/lib/puppet/indirector/facts/store_configs.rb index 5a6804c35..247898f0b 100644 --- a/lib/puppet/indirector/facts/store_configs.rb +++ b/lib/puppet/indirector/facts/store_configs.rb @@ -2,4 +2,7 @@ require 'puppet/node/facts' require 'puppet/indirector/store_configs' class Puppet::Node::Facts::StoreConfigs < Puppet::Indirector::StoreConfigs + + desc %q{Part of the "storeconfigs" feature. Should not be directly set by end users.} + end diff --git a/lib/puppet/indirector/file_metadata/rest.rb b/lib/puppet/indirector/file_metadata/rest.rb index 31de2698b..b59b452ef 100644 --- a/lib/puppet/indirector/file_metadata/rest.rb +++ b/lib/puppet/indirector/file_metadata/rest.rb @@ -4,4 +4,6 @@ require 'puppet/indirector/rest' class Puppet::Indirector::FileMetadata::Rest < Puppet::Indirector::REST desc "Retrieve file metadata via a REST HTTP interface." + + use_srv_service(:fileserver) end diff --git a/lib/puppet/indirector/instrumentation_data/local.rb b/lib/puppet/indirector/instrumentation_data/local.rb index 6510d7f2d..7504a7d57 100644 --- a/lib/puppet/indirector/instrumentation_data/local.rb +++ b/lib/puppet/indirector/instrumentation_data/local.rb @@ -1,6 +1,9 @@ require 'puppet/indirector/instrumentation_data' class Puppet::Indirector::InstrumentationData::Local < Puppet::Indirector::Code + + desc "Undocumented." + def find(request) model.new(request.key) end diff --git a/lib/puppet/indirector/instrumentation_data/rest.rb b/lib/puppet/indirector/instrumentation_data/rest.rb index 28b211781..f926d7ddf 100644 --- a/lib/puppet/indirector/instrumentation_data/rest.rb +++ b/lib/puppet/indirector/instrumentation_data/rest.rb @@ -2,4 +2,7 @@ require 'puppet/indirector/rest' require 'puppet/indirector/instrumentation_data' class Puppet::Indirector::InstrumentationData::Rest < Puppet::Indirector::REST + + desc "Undocumented." + end diff --git a/lib/puppet/indirector/instrumentation_listener/local.rb b/lib/puppet/indirector/instrumentation_listener/local.rb index 72578014c..947d62717 100644 --- a/lib/puppet/indirector/instrumentation_listener/local.rb +++ b/lib/puppet/indirector/instrumentation_listener/local.rb @@ -1,6 +1,9 @@ require 'puppet/indirector/instrumentation_listener' class Puppet::Indirector::InstrumentationListener::Local < Puppet::Indirector::Code + + desc "Undocumented." + def find(request) Puppet::Util::Instrumentation[request.key] end diff --git a/lib/puppet/indirector/instrumentation_listener/rest.rb b/lib/puppet/indirector/instrumentation_listener/rest.rb index 0bc8122ea..c99ec9803 100644 --- a/lib/puppet/indirector/instrumentation_listener/rest.rb +++ b/lib/puppet/indirector/instrumentation_listener/rest.rb @@ -2,4 +2,7 @@ require 'puppet/indirector/instrumentation_listener' require 'puppet/indirector/rest' class Puppet::Indirector::InstrumentationListener::Rest < Puppet::Indirector::REST + + desc "Undocumented." + end diff --git a/lib/puppet/indirector/instrumentation_probe/local.rb b/lib/puppet/indirector/instrumentation_probe/local.rb index dd0a3f707..8f6711555 100644 --- a/lib/puppet/indirector/instrumentation_probe/local.rb +++ b/lib/puppet/indirector/instrumentation_probe/local.rb @@ -3,6 +3,9 @@ require 'puppet/indirector/code' require 'puppet/util/instrumentation/indirection_probe' class Puppet::Indirector::InstrumentationProbe::Local < Puppet::Indirector::Code + + desc "Undocumented." + def find(request) end diff --git a/lib/puppet/indirector/instrumentation_probe/rest.rb b/lib/puppet/indirector/instrumentation_probe/rest.rb index 57e6fcf3d..ba5d5e437 100644 --- a/lib/puppet/indirector/instrumentation_probe/rest.rb +++ b/lib/puppet/indirector/instrumentation_probe/rest.rb @@ -2,4 +2,7 @@ require 'puppet/indirector/rest' require 'puppet/indirector/instrumentation_probe' class Puppet::Indirector::InstrumentationProbe::Rest < Puppet::Indirector::REST + + desc "Undocumented." + end diff --git a/lib/puppet/indirector/node/active_record.rb b/lib/puppet/indirector/node/active_record.rb index 1274cbab6..0741906c6 100644 --- a/lib/puppet/indirector/node/active_record.rb +++ b/lib/puppet/indirector/node/active_record.rb @@ -5,6 +5,9 @@ require 'puppet/node' class Puppet::Node::ActiveRecord < Puppet::Indirector::ActiveRecord use_ar_model Puppet::Rails::Host + desc "A component of ActiveRecord storeconfigs. ActiveRecord-based storeconfigs + and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" + def initialize Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" super diff --git a/lib/puppet/indirector/node/rest.rb b/lib/puppet/indirector/node/rest.rb index 6aa8025a6..565c19013 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 "Get a node via REST. Puppet agent uses this to allow the puppet master + to override its environment." end diff --git a/lib/puppet/indirector/node/store_configs.rb b/lib/puppet/indirector/node/store_configs.rb index 192254e41..62651db97 100644 --- a/lib/puppet/indirector/node/store_configs.rb +++ b/lib/puppet/indirector/node/store_configs.rb @@ -2,4 +2,7 @@ require 'puppet/indirector/store_configs' require 'puppet/node' class Puppet::Node::StoreConfigs < Puppet::Indirector::StoreConfigs + + desc %q{Part of the "storeconfigs" feature. Should not be directly set by end users.} + end diff --git a/lib/puppet/indirector/node/write_only_yaml.rb b/lib/puppet/indirector/node/write_only_yaml.rb new file mode 100644 index 000000000..b30bdc1db --- /dev/null +++ b/lib/puppet/indirector/node/write_only_yaml.rb @@ -0,0 +1,32 @@ +require 'puppet/node' +require 'puppet/indirector/yaml' + +# This is a WriteOnlyYaml terminus that exists only for the purpose of being able to write +# node cache data that later can be read by the YAML terminus. +# The use case this supports is to make it possible to search among the "current nodes" +# when Puppet DB (recommended) or other central storage of information is not available. +# +# @see puppet issue 16753 +# @see Puppet::Application::Master#setup_node_cache +# @api private +# +class Puppet::Node::WriteOnlyYaml < Puppet::Indirector::Yaml + desc "Store node information as flat files, serialized using YAML, + does not deserialize (write only)." + + # Overridden to always return nil. This is a write only terminus. + # @param [Object] request Ignored. + # @return [nil] This implementation always return nil' + # @api + def find(request) + nil + end + + # Overridden to always return nil. This is a write only terminus. + # @param [Object] request Ignored. + # @return [nil] This implementation always return nil + # @api + def search(request) + nil + end +end diff --git a/lib/puppet/indirector/queue.rb b/lib/puppet/indirector/queue.rb index 299032bcb..8b9d8ab61 100644 --- a/lib/puppet/indirector/queue.rb +++ b/lib/puppet/indirector/queue.rb @@ -24,7 +24,6 @@ class Puppet::Indirector::Queue < Puppet::Indirector::Terminus def initialize(*args) super - raise ArgumentError, "Queueing requires pson support" unless Puppet.features.pson? end # Queue has no idiomatic "find" diff --git a/lib/puppet/indirector/request.rb b/lib/puppet/indirector/request.rb index 60222e2fe..06db55f61 100644 --- a/lib/puppet/indirector/request.rb +++ b/lib/puppet/indirector/request.rb @@ -16,8 +16,7 @@ class Puppet::Indirector::Request OPTION_ATTRIBUTES = [:ip, :node, :authenticated, :ignore_terminus, :ignore_cache, :instance, :environment] - # Load json before trying to register. - Puppet.features.pson? and ::PSON.register_document_type('IndirectorRequest',self) + ::PSON.register_document_type('IndirectorRequest',self) def self.from_pson(json) raise ArgumentError, "No indirection name provided in json data" unless indirection_name = json['type'] diff --git a/lib/puppet/indirector/resource/active_record.rb b/lib/puppet/indirector/resource/active_record.rb index 9192a4aad..caadc2450 100644 --- a/lib/puppet/indirector/resource/active_record.rb +++ b/lib/puppet/indirector/resource/active_record.rb @@ -1,6 +1,10 @@ require 'puppet/indirector/active_record' class Puppet::Resource::ActiveRecord < Puppet::Indirector::ActiveRecord + + desc "A component of ActiveRecord storeconfigs. ActiveRecord-based storeconfigs + and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" + def initialize Puppet.deprecation_warning "ActiveRecord-based storeconfigs and inventory are deprecated. See http://links.puppetlabs.com/activerecord-deprecation" super diff --git a/lib/puppet/indirector/resource/ral.rb b/lib/puppet/indirector/resource/ral.rb index b7f827a7c..59ddc36eb 100644 --- a/lib/puppet/indirector/resource/ral.rb +++ b/lib/puppet/indirector/resource/ral.rb @@ -1,4 +1,7 @@ class Puppet::Resource::Ral < Puppet::Indirector::Code + + desc "Manipulate resources with the resource abstraction layer. Only used internally." + def find( request ) # find by name res = type(request).instances.find { |o| o.name == resource_name(request) } diff --git a/lib/puppet/indirector/resource/rest.rb b/lib/puppet/indirector/resource/rest.rb index 7848ae65e..abb684246 100644 --- a/lib/puppet/indirector/resource/rest.rb +++ b/lib/puppet/indirector/resource/rest.rb @@ -2,4 +2,7 @@ require 'puppet/indirector/status' require 'puppet/indirector/rest' class Puppet::Resource::Rest < Puppet::Indirector::REST + + desc "Maniuplate resources remotely? Undocumented." + end diff --git a/lib/puppet/indirector/resource/store_configs.rb b/lib/puppet/indirector/resource/store_configs.rb index 69b57c0c0..685922061 100644 --- a/lib/puppet/indirector/resource/store_configs.rb +++ b/lib/puppet/indirector/resource/store_configs.rb @@ -1,3 +1,6 @@ require 'puppet/indirector/store_configs' class Puppet::Resource::StoreConfigs < Puppet::Indirector::StoreConfigs + + desc %q{Part of the "storeconfigs" feature. Should not be directly set by end users.} + end diff --git a/lib/puppet/indirector/run/local.rb b/lib/puppet/indirector/run/local.rb index 8cf65d179..10ada0e53 100644 --- a/lib/puppet/indirector/run/local.rb +++ b/lib/puppet/indirector/run/local.rb @@ -2,6 +2,9 @@ require 'puppet/run' require 'puppet/indirector/code' class Puppet::Run::Local < Puppet::Indirector::Code + + desc "Trigger a Puppet run locally. Only used internally." + def save( request ) request.instance.run end diff --git a/lib/puppet/indirector/ssl_file.rb b/lib/puppet/indirector/ssl_file.rb index 45104999a..df72ab4f5 100644 --- a/lib/puppet/indirector/ssl_file.rb +++ b/lib/puppet/indirector/ssl_file.rb @@ -82,13 +82,9 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus # 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) + filename = rename_files_with_uppercase(path(request.key)) - result = model.new(request.key) - result.read(path) - result + filename ? create_model(request.key, filename) : nil end # Save our file to disk. @@ -106,16 +102,20 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus # 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 + Dir.entries(dir). + select { |file| file =~ /\.pem$/ }. + collect { |file| create_model(file.sub(/\.pem$/, ''), File.join(dir, file)) }. + compact end private + def create_model(name, path) + result = model.new(name) + result.read(path) + result + end + # Demeterish pointers to class info. def collection_directory self.class.collection_directory @@ -135,6 +135,8 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus # 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) + return file if FileTest.exist?(file) + dir, short = File.split(file) return nil unless FileTest.exist?(dir) @@ -147,10 +149,10 @@ class Puppet::Indirector::SslFile < Puppet::Indirector::Terminus full_file = File.join(dir, real_file) - Puppet.notice "Fixing case in #{full_file}; renaming to #{file}" + Puppet.deprecation_warning "Automatic downcasing and renaming of ssl files is deprecated; please request the file using its correct case: #{full_file}" File.rename(full_file, file) - true + file end # Yield a filehandle set up appropriately, either with our settings doing diff --git a/lib/puppet/indirector/status/local.rb b/lib/puppet/indirector/status/local.rb index 9951f7e22..e64c3ddb0 100644 --- a/lib/puppet/indirector/status/local.rb +++ b/lib/puppet/indirector/status/local.rb @@ -1,6 +1,9 @@ require 'puppet/indirector/status' class Puppet::Indirector::Status::Local < Puppet::Indirector::Code + + desc "Get status locally. Only used internally." + def find( *anything ) model.new end diff --git a/lib/puppet/indirector/status/rest.rb b/lib/puppet/indirector/status/rest.rb index 22e70429b..4fd99437b 100644 --- a/lib/puppet/indirector/status/rest.rb +++ b/lib/puppet/indirector/status/rest.rb @@ -2,4 +2,8 @@ require 'puppet/indirector/status' require 'puppet/indirector/rest' class Puppet::Indirector::Status::Rest < Puppet::Indirector::REST + + desc "Get puppet master's status via REST. Useful because it tests the health + of both the web server and the indirector." + end diff --git a/lib/puppet/interface.rb b/lib/puppet/interface.rb index e9e2e4a99..ec77b09f7 100644 --- a/lib/puppet/interface.rb +++ b/lib/puppet/interface.rb @@ -4,6 +4,7 @@ require 'puppet/interface/documentation' require 'prettyprint' require 'semver' +# @api public class Puppet::Interface include FullDocs @@ -22,19 +23,38 @@ class Puppet::Interface class << self # This is just so we can search for actions. We only use its # list of directories to search. - # Can't we utilize an external autoloader, or simply use the $LOAD_PATH? -pvb + + # @api private + # @deprecated def autoloader + Puppet.deprecation_warning("Puppet::Interface.autoloader is deprecated; please use Puppet::Interface#loader instead") @autoloader ||= Puppet::Util::Autoload.new(:application, "puppet/face") end + # Lists all loaded faces + # @return [Array<Symbol>] The names of the loaded faces def faces Puppet::Interface::FaceCollection.faces end + # Register a face + # @param instance [Puppet::Interface] The face + # @return [void] + # @api private def register(instance) Puppet::Interface::FaceCollection.register(instance) end + # Defines a new Face. + # @todo Talk about using Faces DSL inside the block + # + # @param name [Symbol] the name of the face + # @param version [String] the version of the face (this should + # conform to {http://semver.org/ Semantic Versioning}) + # @overload define(name, version, {|| ... }) + # @return [Puppet::Interface] The created face + # @api public + # @dsl Faces def define(name, version, &block) face = Puppet::Interface::FaceCollection[name, version] if face.nil? then @@ -50,12 +70,30 @@ class Puppet::Interface return face end + # Retrieves a face by name and version. Use `:current` for the + # version to get the most recent available version. + # + # @param name [Symbol] the name of the face + # @param version [String, :current] the version of the face + # + # @return [Puppet::Interface] the face + # + # @api public def face?(name, version) Puppet::Interface::FaceCollection[name, version] end + # Retrieves a face by name and version + # + # @param name [Symbol] the name of the face + # @param version [String] the version of the face + # + # @return [Puppet::Interface] the face + # + # @api public def [](name, version) unless face = Puppet::Interface::FaceCollection[name, version] + # REVISIT (#18042) no sense in rechecking if version == :current -- josh if current = Puppet::Interface::FaceCollection[name, :current] raise Puppet::Error, "Could not find version #{version} of #{name}" else @@ -66,6 +104,11 @@ class Puppet::Interface face end + # Retrieves an action for a face + # @param name [Symbol] The face + # @param action [Symbol] The action name + # @param version [String, :current] The version of the face + # @return [Puppet::Interface::Action] The action def find_action(name, action, version = :current) Puppet::Interface::FaceCollection.get_action_for_face(name, action, version) end @@ -76,15 +119,35 @@ class Puppet::Interface # the same instance between build-time and the runtime instance. When that # splits out this should merge into a module that both the action and face # include. --daniel 2011-04-17 + + + # Returns the synopsis for the face. This shows basic usage and global + # options. + # @return [String] usage synopsis + # @api private def synopsis build_synopsis self.name, '<action>' end ######################################################################## - attr_reader :name, :version, :loader + + # The name of the face + # @return [Symbol] + # @api private + attr_reader :name + + # The version of the face + # @return [SemVer] + attr_reader :version + + # The autoloader instance for the face + # @return [Puppet::Util::Autoload] + # @api private + attr_reader :loader private :loader + # @api private def initialize(name, version, &block) unless SemVer.valid?(version) raise ArgumentError, "Cannot create face #{name.inspect} with invalid version number '#{version}'!" @@ -103,11 +166,16 @@ class Puppet::Interface instance_eval(&block) if block_given? end - # Try to find actions defined in other files. + # Loads all actions defined in other files. + # + # @return [void] + # @api private def load_actions loader.loadall end + # Returns a string representation with the face's name and version + # @return [String] def to_s "Puppet::Face[#{name.inspect}, #{version.inspect}]" end @@ -123,6 +191,8 @@ class Puppet::Interface # all this away, replace it with something nice, and work out if we should # be making this visible to the outside world... --daniel 2011-04-14 private + # @return [void] + # @api private def __invoke_decorations(type, action, passed_args = [], passed_options = {}) [:before, :after].member?(type) or fail "unknown decoration type #{type}" @@ -142,10 +212,15 @@ class Puppet::Interface end end + # @return [void] + # @api private def __add_method(name, proc) meta_def(name, &proc) method(name).unbind end + + # @return [void] + # @api private def self.__add_method(name, proc) define_method(name, proc) instance_method(name) diff --git a/lib/puppet/interface/action.rb b/lib/puppet/interface/action.rb index f191bfcb6..344de2a3b 100644 --- a/lib/puppet/interface/action.rb +++ b/lib/puppet/interface/action.rb @@ -3,11 +3,17 @@ require 'puppet/interface/documentation' require 'puppet/util/methodhelper' require 'prettyprint' +# This represents an action that is attached to a face. Actions should +# be constructed by calling {Puppet::Interface::ActionManager#action}, +# which is available on {Puppet::Interface}, and then calling methods of +# {Puppet::Interface::ActionBuilder} in the supplied block. +# @api private class Puppet::Interface::Action include Puppet::Util::MethodHelper extend Puppet::Interface::DocGen include Puppet::Interface::FullDocs + # @api private def initialize(face, name, attrs = {}) raise "#{name.inspect} is an invalid action name" unless name.to_s =~ /^[a-z]\w*$/ @face = face @@ -32,6 +38,9 @@ class Puppet::Interface::Action # This is not nice, but it is the easiest way to make us behave like the # Ruby Method object rather than UnboundMethod. Duplication is vaguely # annoying, but at least we are a shallow clone. --daniel 2011-04-12 + + # @return [void] + # @api private def __dup_and_rebind_to(to) bound_version = self.dup bound_version.instance_variable_set(:@face, to) @@ -40,8 +49,17 @@ class Puppet::Interface::Action def to_s() "#{@face}##{@name}" end + # The name of this action + # @return [Symbol] attr_reader :name + + # The face this action is attached to + # @return [Puppet::Interface] attr_reader :face + + # Whether this is the default action for the face + # @return [Boolean] + # @api private attr_accessor :default def default? !!@default @@ -57,6 +75,9 @@ class Puppet::Interface::Action ######################################################################## # Support for rendering formats and all. + + + # @api private def when_rendering(type) unless type.is_a? Symbol raise ArgumentError, "The rendering format must be a symbol, not #{type.class.name}" @@ -71,6 +92,8 @@ class Puppet::Interface::Action # Guess not, nothing to run. return nil end + + # @api private def set_rendering_method_for(type, proc) unless proc.is_a? Proc msg = "The second argument to set_rendering_method_for must be a Proc" @@ -103,12 +126,16 @@ class Puppet::Interface::Action @face.__send__( :__add_method, __render_method_name_for(type), proc) end + # @return [void] + # @api private def __render_method_name_for(type) :"#{name}_when_rendering_#{type}" end private :__render_method_name_for + # @api private + # @return [Symbol] attr_accessor :render_as def render_as=(value) @render_as = value.to_sym @@ -169,7 +196,14 @@ class Puppet::Interface::Action # this stuff work, because it would have been cleaner. Which gives you an # idea how motivated we were to make this cleaner. Sorry. # --daniel 2011-03-31 + + + # The arity of the action + # @return [Integer] attr_reader :positional_arg_count + + # The block that is executed when the action is invoked + # @return [block] attr_accessor :when_invoked def when_invoked=(block) @@ -249,7 +283,7 @@ WRAPPER def options @face.options + @options end - + def add_display_global_options(*args) @display_global_options ||= [] [args].flatten.each do |refopt| @@ -259,12 +293,12 @@ WRAPPER @display_global_options.uniq! @display_global_options end - + def display_global_options(*args) args ? add_display_global_options(args) : @display_global_options + @face.display_global_options end alias :display_global_option :display_global_options - + def get_option(name, with_inherited_options = true) option = @options_hash[name.to_sym] if option.nil? and with_inherited_options @@ -334,6 +368,8 @@ WRAPPER # Support code for action decoration; see puppet/interface.rb for the gory # details of why this is hidden away behind private. --daniel 2011-04-15 private + # @return [void] + # @api private def __add_method(name, proc) @face.__send__ :__add_method, name, proc end diff --git a/lib/puppet/interface/action_builder.rb b/lib/puppet/interface/action_builder.rb index 7198e9015..b667887bd 100644 --- a/lib/puppet/interface/action_builder.rb +++ b/lib/puppet/interface/action_builder.rb @@ -1,9 +1,20 @@ require 'puppet/interface' require 'puppet/interface/action' +# This class is used to build {Puppet::Interface::Action actions}. +# When an action is defined with +# {Puppet::Interface::ActionManager#action} the block is evaluated +# within the context of a new instance of this class. +# @api public class Puppet::Interface::ActionBuilder + # The action under construction + # @return [Puppet::Interface::Action] + # @api private attr_reader :action + # Builds a new action. + # @return [Puppet::Interface::Action] + # @api private def self.build(face, name, &block) raise "Action #{name.inspect} must specify a block" unless block new(face, name, &block).action @@ -12,10 +23,33 @@ class Puppet::Interface::ActionBuilder # Ideally the method we're defining here would be added to the action, and a # method on the face would defer to it, but we can't get scope correct, so # we stick with this. --daniel 2011-03-24 + + # Sets what the action does when it is invoked. This takes a block + # which will be called when the action is invoked. The action will + # accept arguments based on the arity of the block. It should always + # take at least one argument for options. Options will be the last + # argument. + # + # @overload when_invoked({|options| ... }) + # An action with no arguments + # @overload when_invoked({|arg1, arg2, options| ... }) + # An action with two arguments + # @return [void] + # @api public + # @dsl Faces def when_invoked(&block) @action.when_invoked = block end + # Sets a block to be run at the rendering stage, for a specific + # rendering type (eg JSON, YAML, console), after the block for + # when_invoked gets run. This manipulates the value returned by the + # action. It makes it possible to work around limitations in the + # underlying object returned, and should be avoided in favor of + # returning a more capable object. + # @api private + # @todo this needs more + # @dsl Faces def when_rendering(type = nil, &block) if type.nil? then # the default error message sucks --daniel 2011-04-18 raise ArgumentError, 'You must give a rendering format to when_rendering' @@ -26,20 +60,59 @@ class Puppet::Interface::ActionBuilder @action.set_rendering_method_for(type, block) end + # Declare that this action can take a specific option, and provide the + # code to do so. One or more strings are given, in the style of + # OptionParser (see example). These strings are parsed to derive a + # name for the option. Any `-` characters within the option name (ie + # excluding the intial `-` or `--` for an option) will be translated + # to `_`.The first long option will be used as the name, and the rest + # are retained as aliases. The original form of the option is used + # when invoking the face, the translated form is used internally. + # + # When the action is invoked the value of the option is available in + # a hash passed to the {Puppet::Interface::ActionBuilder#when_invoked + # when_invoked} block, using the option name in symbol form as the + # hash key. + # + # The block to this method is used to set attributes for the option + # (see {Puppet::Interface::OptionBuilder}). + # + # @param declaration [String] Option declarations, as described above + # and in the example. + # + # @example Say hi + # action :say_hi do + # option "-u USER", "--user-name USER" do + # summary "Who to say hi to" + # end + # + # when_invoked do |options| + # "Hi, #{options[:user_name]}" + # end + # end + # @api public + # @dsl Faces def option(*declaration, &block) option = Puppet::Interface::OptionBuilder.build(@action, *declaration, &block) @action.add_option(option) end + # Set this as the default action for the face. + # @api public + # @dsl Faces + # @return [void] def default(value = true) @action.default = !!value end - + + # @api private def display_global_options(*args) @action.add_display_global_options args end alias :display_global_option :display_global_options + # Sets the default rendering format + # @api private def render_as(value = nil) value.nil? and raise ArgumentError, "You must give a rendering format to render_as" diff --git a/lib/puppet/interface/action_manager.rb b/lib/puppet/interface/action_manager.rb index a275587b3..2be33516b 100644 --- a/lib/puppet/interface/action_manager.rb +++ b/lib/puppet/interface/action_manager.rb @@ -1,15 +1,30 @@ require 'puppet/interface/action' require 'puppet/interface/action_builder' +# This class is not actually public API, but the method +# {Puppet::Interface::ActionManager#action action} is public when used +# as part of the Faces DSL (i.e. from within a +# {Puppet::Interface.define define} block). +# @api public module Puppet::Interface::ActionManager # Declare that this app can take a specific action, and provide # the code to do so. + + # Defines a new action. This takes a block to build the action using + # the methods on {Puppet::Interface::ActionBuilder}. + # @param name [Symbol] The name that will be used to invoke the + # action + # @overload action(name, {|| block}) + # @return [void] + # @api public + # @dsl Faces def action(name, &block) @actions ||= {} Puppet.warning "Redefining action #{name} for #{self}" if action?(name) action = Puppet::Interface::ActionBuilder.build(self, name, &block) + # REVISIT: (#18042) doesn't this mean we can't redefine the default action? -- josh if action.default and current = get_default_action raise "Actions #{current.name} and #{name} cannot both be default" end @@ -17,14 +32,21 @@ module Puppet::Interface::ActionManager @actions[action.name] = action end - # This is the short-form of an action definition; it doesn't use the - # builder, just creates the action directly from the block. + # Defines an action without using ActionBuilder. The block given is + # the code that will be executed when the action is invoked. + # @api public + # @deprecated def script(name, &block) @actions ||= {} - raise "Action #{name} already defined for #{self}" if action?(name) + Puppet.warning "Redefining action #{name} for #{self}" if action?(name) + + # REVISIT: (#18048) it's possible to create multiple default actions @actions[name] = Puppet::Interface::Action.new(self, name, :when_invoked => block) end + # Returns the list of available actions for this face. + # @return [Array<Symbol>] The names of the actions for this face + # @api private def actions @actions ||= {} result = @actions.keys @@ -40,6 +62,10 @@ module Puppet::Interface::ActionManager result.uniq.sort end + # Retrieves a named action + # @param name [Symbol] The name of the action + # @return [Puppet::Interface::Action] The action object + # @api private def get_action(name) @actions ||= {} result = @actions[name.to_sym] @@ -60,6 +86,9 @@ module Puppet::Interface::ActionManager return result end + # Retrieves the default action for the face + # @return [Puppet::Interface::Action] + # @api private def get_default_action default = actions.map {|x| get_action(x) }.select {|x| x.default } if default.length > 1 @@ -68,6 +97,7 @@ module Puppet::Interface::ActionManager default.first end + # @api private def action?(name) actions.include?(name.to_sym) end diff --git a/lib/puppet/interface/documentation.rb b/lib/puppet/interface/documentation.rb index be4cc3b31..ef5c5a2b1 100644 --- a/lib/puppet/interface/documentation.rb +++ b/lib/puppet/interface/documentation.rb @@ -1,6 +1,7 @@ -# This isn't usable outside Puppet::Interface; don't load it alone. class Puppet::Interface + # @api private module DocGen + # @api private def self.strip_whitespace(text) text.gsub!(/[ \t\f]+$/, '') @@ -25,6 +26,8 @@ class Puppet::Interface # # This feels a bit like overkill, but at least the common code is common # now. --daniel 2011-04-29 + + # @api private def attr_doc(name, &validate) # Now, which form of the setter do we want, validated or not? get_arg = "value.to_s" @@ -51,17 +54,30 @@ class Puppet::Interface end end + # This module can be mixed in to provide a minimal set of + # documentation attributes. + # @api public module TinyDocs extend Puppet::Interface::DocGen + # @!method summary(summary) + # Sets a summary of this object. + # @api public + # @dsl Faces attr_doc :summary do |value| value =~ /\n/ and raise ArgumentError, "Face summary should be a single line; put the long text in 'description' instead." value end + # @!method description(description) + # Sets the long description of this object. + # @param description [String] The description of this object. + # @api public + # @dsl Faces attr_doc :description + # @api private def build_synopsis(face, action = nil, arguments = nil) output = PrettyPrint.format do |s| s.text("puppet #{face}") @@ -85,13 +101,13 @@ class Puppet::Interface s.breakable end - + display_global_options.sort.each do |option| wrap = %w{ [ ] } s.group(0, *wrap) do - desc = Puppet.settings.setting(option).desc - type = Puppet.settings.setting(option).default - type ||= Puppet.settings.setting(option).type.to_s.upcase + desc = Puppet.settings.setting(option).desc + type = Puppet.settings.setting(option).default + type ||= Puppet.settings.setting(option).type.to_s.upcase s.text "--#{option} #{type}" s.breakable end @@ -106,15 +122,68 @@ class Puppet::Interface end + # This module can be mixed in to provide a full set of documentation + # attributes. It is intended to be used for {Puppet::Interface}. + # @api public module FullDocs extend Puppet::Interface::DocGen include TinyDocs + # @!method examples + # @overload examples(text) + # Sets examples. + # @param text [String] Example text + # @api public + # @returns [void] + # @dsl Faces + # @overload examples + # Returns documentation of examples + # @returns [String] The examples + # @api private attr_doc :examples + + # @!method notes(text) + # @overload notes(text) + # Sets optional notes. + # @param text [String] The notes + # @api public + # @returns [void] + # @dsl Faces + # @overload notes + # Returns any optional notes + # @returns [String] The notes + # @api private attr_doc :notes + + # @!method license(text) + # @overload license(text) + # Sets the license text + # @param text [String] the license text + # @api public + # @returns [void] + # @dsl Faces + # @overload license + # Returns the license + # @returns [String] The license + # @api private attr_doc :license attr_doc :short_description + # @overload short_description(value) + # Sets a short description for this object. + # @param value [String, nil] A short description (about a paragraph) + # of this component. If `value` is `nil` the short_description + # will be set to the shorter of the first paragraph or the first + # five lines of {description}. + # @return [void] + # @api public + # @dsl Faces + # @overload short_description + # Get the short description for this object + # @return [String, nil] The short description of this object. If none is + # set it will be derived from {description}. Returns `nil` if + # {description} is `nil`. + # @api private def short_description(value = nil) self.short_description = value unless value.nil? if @short_description.nil? then @@ -128,6 +197,17 @@ class Puppet::Interface @short_description end + # @overload author(value) + # Adds an author to the documentation for this object. To set + # multiple authors, call this once for each author. + # @param value [String] the name of the author + # @api public + # @dsl Faces + # @overload author + # Returns a list of authors + # @return [String, nil] The names of all authors separated by + # newlines, or `nil` if no authors have been set. + # @api private def author(value = nil) unless value.nil? then unless value.is_a? String @@ -141,10 +221,18 @@ class Puppet::Interface end @authors.empty? ? nil : @authors.join("\n") end + + # Returns a list of authors. See {author}. + # @return [String] The list of authors, separated by newlines. + # @api private def authors @authors end + + # @api private def author=(value) + # I think it's a bug that this ends up being the exposed + # version of `author` on ActionBuilder if Array(value).any? {|x| x =~ /\n/ } then raise ArgumentError, 'author should be a single line; use multiple statements' end @@ -152,6 +240,18 @@ class Puppet::Interface end alias :authors= :author= + # Sets the copyright owner and year. This returns the copyright + # string, so it can be called with no arguments retrieve that string + # without side effects. + # @param owner [String, Array<String>] The copyright owner or an + # array of owners + # @param years [Integer, Range<Integer>, Array<Integer,Range<Integer>>] + # The copyright year or years. Years can be specified with integers, + # a range of integers, or an array of integers and ranges of + # integers. + # @return [String] A string describing the copyright on this object. + # @api public + # @dsl Faces def copyright(owner = nil, years = nil) if years.nil? and not owner.nil? then raise ArgumentError, 'copyright takes the owners names, then the years covered' @@ -166,6 +266,11 @@ class Puppet::Interface end end + # Sets the copyright owner + # @param value [String, Array<String>] The copyright owner or + # owners. + # @return [String] Comma-separated list of copyright owners + # @api private attr_accessor :copyright_owner def copyright_owner=(value) case value @@ -177,6 +282,11 @@ class Puppet::Interface @copyright_owner end + # Sets the copyright year + # @param value [Integer, Range<Integer>, Array<Integer, Range>] The + # copyright year or years. + # @return [String] + # @api private attr_accessor :copyright_years def copyright_years=(value) years = munge_copyright_year value @@ -192,6 +302,7 @@ class Puppet::Interface end.join(", ") end + # @api private def munge_copyright_year(input) case input when Range then input diff --git a/lib/puppet/interface/face_collection.rb b/lib/puppet/interface/face_collection.rb index d2e3dbe01..11056588c 100644 --- a/lib/puppet/interface/face_collection.rb +++ b/lib/puppet/interface/face_collection.rb @@ -3,14 +3,13 @@ require 'puppet/interface' module Puppet::Interface::FaceCollection @faces = Hash.new { |hash, key| hash[key] = {} } + @loader = Puppet::Util::Autoload.new(:application, 'puppet/face') + def self.faces unless @loaded @loaded = true - $LOAD_PATH.each do |dir| - Dir.glob("#{dir}/puppet/face/*.rb"). - collect {|f| File.basename(f, '.rb') }. - each {|name| self[name, :current] } - end + names = @loader.files_to_load.map {|fn| ::File.basename(fn, '.rb')}.uniq + names.each {|name| self[name, :current]} end @faces.keys.select {|name| @faces[name].length > 0 } end @@ -58,7 +57,7 @@ module Puppet::Interface::FaceCollection # other Ruby library that we might want to use. --daniel 2011-04-06 if safely_require name then # If we wanted :current, we need to index to find that; direct version - # requests just work™ as they go. --daniel 2011-04-06 + # requests just work as they go. --daniel 2011-04-06 if version == :current then # We need to find current out of this. This is the largest version # number that doesn't have a dedicated on-disk file present; those @@ -99,7 +98,7 @@ module Puppet::Interface::FaceCollection end def self.safely_require(name, version = nil) - path = File.join 'puppet' ,'face', version.to_s, name.to_s + path = @loader.expand(version ? ::File.join(version.to_s, name.to_s) : name) require path true diff --git a/lib/puppet/interface/option.rb b/lib/puppet/interface/option.rb index 3d0a9c329..d646dde14 100644 --- a/lib/puppet/interface/option.rb +++ b/lib/puppet/interface/option.rb @@ -1,8 +1,15 @@ require 'puppet/interface' +# This represents an option on an action or face (to be globally applied +# to its actions). Options should be constructed by calling +# {Puppet::Interface::OptionManager#option}, which is available on +# {Puppet::Interface}, and then calling methods of +# {Puppet::Interface::OptionBuilder} in the supplied block. +# @api public class Puppet::Interface::Option include Puppet::Interface::TinyDocs + # @api private def initialize(parent, *declaration, &block) @parent = parent @optparse = [] @@ -69,18 +76,20 @@ class Puppet::Interface::Option # to_s and optparse_to_name are roughly mirrored, because they are used to # transform options to name symbols, and vice-versa. This isn't a full # bidirectional transformation though. --daniel 2011-04-07 + def to_s @name.to_s.tr('_', '-') end + # @api private def optparse_to_optionname(declaration) unless found = declaration.match(/^-+(?:\[no-\])?([^ =]+)/) then raise ArgumentError, "Can't find a name in the declaration #{declaration.inspect}" end name = found.captures.first end - + # @api private def optparse_to_name(declaration) name = optparse_to_optionname(declaration).tr('-', '_') raise "#{name.inspect} is an invalid option name" unless name.to_s =~ /^[a-z]\w*$/ diff --git a/lib/puppet/interface/option_builder.rb b/lib/puppet/interface/option_builder.rb index c87adc2c0..4c7c6328b 100644 --- a/lib/puppet/interface/option_builder.rb +++ b/lib/puppet/interface/option_builder.rb @@ -1,13 +1,19 @@ require 'puppet/interface/option' +# @api public class Puppet::Interface::OptionBuilder + # The option under construction + # @return [Puppet::Interface::Option] + # @api private attr_reader :option + # Build an option + # @return [Puppet::Interface::Option] + # @api private def self.build(face, *declaration, &block) new(face, *declaration, &block).option end - private def initialize(face, *declaration, &block) @face = face @option = Puppet::Interface::Option.new(face, *declaration) @@ -26,6 +32,15 @@ class Puppet::Interface::OptionBuilder end # Override some methods that deal in blocks, not objects. + + # Sets a block to be executed when an action is invoked before the + # main action code. This is most commonly used to validate an option. + # @yieldparam action [Puppet::Interface::Action] The action being + # invoked + # @yieldparam args [Array] The arguments given to the action + # @yieldparam options [Hash<Symbol=>Object>] Any options set + # @api public + # @dsl Faces def before_action(&block) block or raise ArgumentError, "#{@option} before_action requires a block" if @option.before_action @@ -37,6 +52,10 @@ class Puppet::Interface::OptionBuilder @option.before_action = block end + # Sets a block to be executed after an action is invoked. + # !(see before_action) + # @api public + # @dsl Faces def after_action(&block) block or raise ArgumentError, "#{@option} after_action requires a block" if @option.after_action @@ -48,10 +67,19 @@ class Puppet::Interface::OptionBuilder @option.after_action = block end + # Sets whether the option is required. If no argument is given it + # defaults to setting it as a required option. + # @api public + # @dsl Faces def required(value = true) @option.required = value end + # Sets a block that will be used to compute the default value for this + # option. It will be evaluated when the action is invoked. The block + # should take no arguments. + # @api public + # @dsl Faces def default_to(&block) block or raise ArgumentError, "#{@option} default_to requires a block" if @option.has_default? diff --git a/lib/puppet/interface/option_manager.rb b/lib/puppet/interface/option_manager.rb index e9dec7ecd..224eb1dba 100644 --- a/lib/puppet/interface/option_manager.rb +++ b/lib/puppet/interface/option_manager.rb @@ -1,7 +1,13 @@ require 'puppet/interface/option_builder' +# This class is not actually public API, but the method +# {Puppet::Interface::OptionManager#option option} is public when used +# as part of the Faces DSL (i.e. from within a +# {Puppet::Interface.define define} block). +# @api public module Puppet::Interface::OptionManager - + + # @api private def display_global_options(*args) @display_global_options ||= [] [args].flatten.each do |refopt| @@ -12,11 +18,12 @@ module Puppet::Interface::OptionManager @display_global_options end alias :display_global_option :display_global_options - + def all_display_global_options walk_inheritance_tree(@display_global_options, :all_display_global_options) end - + + # @api private def walk_inheritance_tree(start, sym) result = (start ||= []) if self.is_a?(Class) and superclass.respond_to?(sym) @@ -26,13 +33,18 @@ module Puppet::Interface::OptionManager end return result end - - # Declare that this app can take a specific option, and provide - # the code to do so. + + # Declare that this app can take a specific option, and provide the + # code to do so. See {Puppet::Interface::ActionBuilder#option} for + # details. + # + # @api public + # @dsl Faces def option(*declaration, &block) add_option Puppet::Interface::OptionBuilder.build(self, *declaration, &block) end + # @api private def add_option(option) # @options collects the added options in the order they're declared. # @options_hash collects the options keyed by alias for quick lookups. @@ -61,10 +73,12 @@ module Puppet::Interface::OptionManager return option end + # @api private def options walk_inheritance_tree(@options, :options) end + # @api private def get_option(name, with_inherited_options = true) @options_hash ||= {} @@ -80,6 +94,7 @@ module Puppet::Interface::OptionManager return result end + # @api private def option?(name) options.include? name.to_sym end diff --git a/lib/puppet/metatype/manager.rb b/lib/puppet/metatype/manager.rb index 6555a0739..727b89034 100644 --- a/lib/puppet/metatype/manager.rb +++ b/lib/puppet/metatype/manager.rb @@ -2,20 +2,29 @@ require 'puppet' require 'puppet/util/classgen' require 'puppet/node/environment' -# Methods dealing with Type management. This module gets included into the -# Puppet::Type class, it's just split out here for clarity. +# This module defines methods dealing with Type management. +# This module gets included into the Puppet::Type class, it's just split out here for clarity. +# @api public +# module Puppet::MetaType module Manager include Puppet::Util::ClassGen - # remove all type instances; this is mostly only useful for testing + # An implementation specific method that removes all type instances during testing. + # @note Only use this method for testing purposes. + # @api private + # def allclear @types.each { |name, type| type.clear } end - # iterate across all of the subclasses of Type + # Iterates over all already loaded Type subclasses. + # @yield [t] a block receiving each type + # @yieldparam t [Puppet::Type] each defined type + # @yieldreturn [Object] the last returned object is also returned from this method + # @return [Object] the last returned value from the block. def eachtype @types.each do |name, type| # Only consider types that have names @@ -25,12 +34,32 @@ module Manager end end - # Load all types. Only currently used for documentation. + # Loads all types. + # @note Should only be used for purposes such as generating documentation as this is potentially a very + # expensive operation. + # @return [void] + # def loadall typeloader.loadall end - # Define a new type. + # Defines a new type or redefines an existing type with the given name. + # A convenience method on the form `new<name>` where name is the name of the type is also created. + # (If this generated method happens to clash with an existing method, a warning is issued and the original + # method is kept). + # + # @param name [String] the name of the type to create or redefine. + # @param options [Hash] options passed on to {Puppet::Util::ClassGen#genclass} as the option `:attributes` after + # first having removed any present `:parent` option. + # @option options [Puppet::Type] :parent the parent (super type) of this type. If nil, the default is + # Puppet::Type. This option is not passed on as an attribute to genclass. + # @yield [ ] a block evaluated in the context of the created class, thus allowing further detailing of + # that class. + # @return [Class<inherits Puppet::Type>] the created subclass + # @see Puppet::Util::ClassGen.genclass + # + # @dsl type + # @api public def newtype(name, options = {}, &block) # Handle backward compatibility unless options.is_a?(Hash) @@ -96,7 +125,9 @@ module Manager klass end - # Remove an existing defined type. Largely used for testing. + # Removes an existing type. + # @note Only use this for testing. + # @api private def rmtype(name) # Then create the class. @@ -105,7 +136,11 @@ module Manager singleton_class.send(:remove_method, "new#{name}") if respond_to?("new#{name}") end - # Return a Type instance by name. + # Returns a Type instance by name. + # This will load the type if not already defined. + # @param [String, Symbol] name of the wanted Type + # @return [Puppet::Type, nil] the type or nil if the type was not defined and could not be loaded + # def type(name) @types ||= {} @@ -129,7 +164,10 @@ module Manager return @types[name] end - # Create a loader for Puppet types. + # Creates a loader for Puppet types. + # Defaults to an instance of {Puppet::Util::Autoload} if no other auto loader has been set. + # @return [Puppet::Util::Autoload] the loader to use. + # @api private def typeloader unless defined?(@typeloader) @typeloader = Puppet::Util::Autoload.new(self, "puppet/type", :wrap => false) diff --git a/lib/puppet/module_tool.rb b/lib/puppet/module_tool.rb index 77feec4d3..4ff4207ec 100644 --- a/lib/puppet/module_tool.rb +++ b/lib/puppet/module_tool.rb @@ -4,7 +4,6 @@ require 'pathname' require 'fileutils' require 'puppet/util/colors' -# Define tool module Puppet module ModuleTool extend Puppet::Util::Colors @@ -105,20 +104,32 @@ module Puppet def self.set_option_defaults(options) sep = File::PATH_SEPARATOR - if options[:target_dir] - options[:target_dir] = File.expand_path(options[:target_dir]) - end - prepend_target_dir = !! options[:target_dir] + if options[:environment] + Puppet.settings[:environment] = options[:environment] + else + options[:environment] = Puppet.settings[:environment] + end - options[:modulepath] ||= Puppet.settings[:modulepath] - options[:environment] ||= Puppet.settings[:environment] - options[:modulepath] = "#{options[:target_dir]}#{sep}#{options[:modulepath]}" if prepend_target_dir - Puppet[:modulepath] = options[:modulepath] - Puppet[:environment] = options[:environment] + if options[:modulepath] + Puppet.settings[:modulepath] = options[:modulepath] + else + # (#14872) make sure the module path of the desired environment is used + # when determining the default value of the --target-dir option + Puppet.settings[:modulepath] = options[:modulepath] = + Puppet.settings.value(:modulepath, options[:environment]) + end - options[:target_dir] = options[:modulepath].split(sep).first - options[:target_dir] = File.expand_path(options[:target_dir]) + if options[:target_dir] + options[:target_dir] = File.expand_path(options[:target_dir]) + # prepend the target dir to the module path + Puppet.settings[:modulepath] = options[:modulepath] = + options[:target_dir] + sep + options[:modulepath] + else + # default to the first component of the module path + options[:target_dir] = + File.expand_path(options[:modulepath].split(sep).first) + end end end end diff --git a/lib/puppet/network/formats.rb b/lib/puppet/network/formats.rb index c5af28885..12bece89e 100644 --- a/lib/puppet/network/formats.rb +++ b/lib/puppet/network/formats.rb @@ -101,8 +101,6 @@ Puppet::Network::FormatHandler.create(:raw, :mime => "application/x-raw", :weigh end Puppet::Network::FormatHandler.create_serialized_formats(: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 @@ -150,7 +148,7 @@ Puppet::Network::FormatHandler.create(:console, # Simple hash to table if datum.is_a? Hash and datum.keys.all? { |x| x.is_a? String or x.is_a? Numeric } output = '' - column_a = datum.map do |k,v| k.to_s.length end.max + 2 + column_a = datum.empty? ? 2 : datum.map{ |k,v| k.to_s.length }.max + 2 column_b = 79 - column_a datum.sort_by { |k,v| k.to_s } .each do |key, value| output << key.to_s.ljust(column_a) diff --git a/lib/puppet/node.rb b/lib/puppet/node.rb index efccfe560..83395fba4 100644 --- a/lib/puppet/node.rb +++ b/lib/puppet/node.rb @@ -18,9 +18,8 @@ class Puppet::Node attr_accessor :name, :classes, :source, :ipaddress, :parameters attr_reader :time, :facts - # - # Load json before trying to register. - Puppet.features.pson? and ::PSON.register_document_type('Node',self) + + ::PSON.register_document_type('Node',self) def self.from_pson(pson) raise ArgumentError, "No name provided in pson data" unless name = pson['name'] diff --git a/lib/puppet/node/environment.rb b/lib/puppet/node/environment.rb index 9ec7020a8..25e429a64 100644 --- a/lib/puppet/node/environment.rb +++ b/lib/puppet/node/environment.rb @@ -88,6 +88,17 @@ class Puppet::Node::Environment } end + # Yields each modules' plugin directory. + # + # @yield [String] Yields the plugin directory from each module to the block. + # @api public + def each_plugin_directory(&block) + modules.map(&:plugin_directory).each do |lib| + lib = Puppet::Util::Autoload.cleanpath(lib) + yield lib if File.directory?(lib) + end + end + def module(name) modules.find {|mod| mod.name == name} end diff --git a/lib/puppet/parameter.rb b/lib/puppet/parameter.rb index 3969374cd..d515c5e24 100644 --- a/lib/puppet/parameter.rb +++ b/lib/puppet/parameter.rb @@ -3,6 +3,22 @@ require 'puppet/util/log_paths' require 'puppet/util/logging' require 'puppet/util/docs' +# The Parameter class is the implementation of a resource's attributes of _parameter_ kind. +# The Parameter class is also the base class for {Puppet::Property}, and is used to describe meta-parameters +# (parameters that apply to all resource types). +# A Parameter (in contrast to a Property) has a single value where a property has both a current and a wanted value. +# The Parameter class methods are used to configure and create an instance of Parameter that represents +# one particular attribute data type; its valid value(s), and conversion to/from internal form. +# +# The intention is that a new parameter is created by using the DSL method {Puppet::Type.newparam}, or +# {Puppet::Type.newmetaparam} if the parameter should be applicable to all resource types. +# +# A Parameter that does not specify and valid values (via {newvalues}) accepts any value. +# +# @see Puppet::Type +# @see Puppet::Property +# @api public +# class Puppet::Parameter include Puppet::Util include Puppet::Util::Errors @@ -15,12 +31,71 @@ class Puppet::Parameter class << self include Puppet::Util include Puppet::Util::Docs - attr_reader :validater, :munger, :name, :default, :required_features, :value_collection + # Unused? + # @todo The term "validater" only appears in this location in the Puppet code base. There is `validate` + # which seems to works fine without this attribute declaration. + # @api private + # + attr_reader :validater + + # Unused? + # @todo The term "munger" only appears in this location in the Puppet code base. There is munge and unmunge + # and they seem to work perfectly fine without this attribute declaration. + # @api private + # + attr_reader :munger + + # @return [Symbol] The parameter name as given when it was created. + attr_reader :name + + # @return [Object] The default value of the parameter as determined by the {defaultto} method, or nil if no + # default has been set. + attr_reader :default + + # @comment This somewhat odd documentation construct is because the getter and setter are not + # orthogonal; the setter uses varargs and this confuses yard. To overcome the problem both the + # getter and the setter are documented here. If this issues is fixed, a todo will be displayed + # for the setter method, and the setter documentation can be moved there. + # Since the attribute is actually RW it should perhaps instead just be implemented as a setter + # and a getter method (and no attr_xxx declaration). + # + # @!attribute [rw] required_features + # @return [Array<Symbol>] The names of the _provider features_ required for this parameter to work. + # the returned names are always all lower case symbols. + # @overload required_features + # Returns the required _provider features_ as an array of lower case symbols + # @overload required_features=(*args) + # @param *args [Symbol] one or more names of required provider features + # Sets the required_provider_features_ from one or more values, or array. The given arguments + # are flattened, and internalized. + # @api public + # @dsl type + # + attr_reader :required_features + + # @return [Puppet::Parameter::ValueCollection] The set of valid values (or an empty set that accepts any value). + # @api private + # + attr_reader :value_collection + + # @return [Boolean] Flag indicating whether this parameter is a meta-parameter or not. 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. + # Defines how the `default` value of a parameter is computed. + # The computation of the parameter's default value is defined by providing a value or a block. + # A default of `nil` can not be used. + # @overload defaultto(value) + # Defines the default value with a literal value + # @param value [Object] the literal value to use as the default value + # @overload defaultto({|| ... }) + # Defines that the default value is produced by the given block. The given block + # should produce the default value. + # @raise [Puppet::DevError] if value is nil, and no block is given. + # @return [void] + # @see Parameter.default + # @dsl type + # @api public + # def defaultto(value = nil, &block) if block define_method(:default, &block) @@ -33,8 +108,12 @@ class Puppet::Parameter end end - # Return a documentation string. If there are valid values, - # then tack them onto the string. + # Produces a documentation string. + # If an enumeration of _valid values_ has been defined, it is appended to the documentation + # for this parameter specified with the {desc} method. + # @return [String] Returns a documentation string. + # @api public + # def doc @doc ||= "" @@ -50,21 +129,49 @@ class Puppet::Parameter @doc end + # Removes the `default` method if defined. + # Has no effect if the default method is not defined. + # This method is intended to be used in a DSL scenario where a parameter inherits from a parameter + # with a default value that is not wanted in the derived parameter (otherwise, simply do not define + # a default value method). + # + # @return [void] + # @see desc + # @api public + # @dsl type + # def nodefault undef_method :default if public_method_defined? :default end - # Store documentation for this parameter. + # Sets the documentation for this parameter. + # @param str [String] The documentation string to set + # @return [String] the given `str` parameter + # @see doc + # @dsl type + # @api public + # def desc(str) @doc = str end + # Initializes the instance variables. + # Clears the internal value collection (set of allowed values). + # @return [void] + # @api private + # 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. + # @overload munge {|| ... } + # Defines an optional method used to convert the parameter value from DSL/string form to an internal form. + # If a munge method is not defined, the DSL/string value is used as is. + # @note This adds a method with the name `unsafe_munge` in the created parameter class. Later this method is + # called in a context where exceptions will be rescued and handled. + # @dsl type + # @api public + # 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 @@ -73,55 +180,105 @@ class Puppet::Parameter define_method(:unsafe_munge, &block) end - # Does the parameter support reverse munging? - # This will be called when something wants to access the parameter - # in a canonical form different to what the storage form is. + # @overload unmunge {|| ... } + # Defines an optional method used to convert the parameter value to DSL/string form from an internal form. + # If an `unmunge` method is not defined, the internal form is used. + # @see munge + # @note This adds a method with the name `unmunge` in the created parameter class. + # @dsl type + # @api public + # def unmunge(&block) define_method(:unmunge, &block) end - # Mark whether we're the namevar. + # Sets a marker indicating that this parameter is the _namevar_ (unique identifier) of the type + # where the parameter is contained. + # This also makes the parameter a required value. The marker can not be unset once it has been set. + # @return [void] + # @dsl type + # @api public + # def isnamevar @isnamevar = true @required = true end - # Is this parameter the namevar? Defaults to false. + # @return [Boolean] Returns whether this parameter is the _namevar_ or not. + # @api public + # def isnamevar? @isnamevar end - # This parameter is required. + # Sets a marker indicating that this parameter is required. + # Once set, it is not possible to make a parameter optional. + # @return [void] + # @dsl type + # @api public + # def isrequired @required = true end - # Specify features that are required for this parameter to work. + # @comment This method is not picked up by yard as it has a different signature than + # expected for an attribute (varargs). Instead, this method is documented as an overload + # of the attribute required_features. (Not ideal, but better than nothing). + # @todo If this text appears in documentation - see comment in source and makes corrections - it means + # that an issue in yardoc has been fixed. + # def required_features=(*args) @required_features = args.flatten.collect { |a| a.to_s.downcase.intern } end - # Is this parameter required? Defaults to false. + # Returns whether this parameter is required or not. + # A parameter is required if a call has been made to the DSL method {isrequired}. + # @return [Boolean] Returns whether this parameter is required or not. + # @api public + # def required? @required end - # Verify that we got a good value + # @overload validate {|| ... } + # Defines an optional method that is used to validate the parameter's value. + # Validation should raise appropriate exceptions, the return value of the given block is ignored. + # @return [void] + # @dsl type + # @api public + # def validate(&block) define_method(:unsafe_validate, &block) end - # Define a new value for our parameter. + # Defines valid values for the parameter (enumeration or regular expressions). + # The set of valid values for the parameter can be limited to a (mix of) literal values and + # regular expression patterns. + # @note Each call to this method adds to the set of valid values + # @param names [Symbol, Regexp] The set of valid literal values and/or patterns for the parameter. + # @return [void] + # @dsl type + # @api public + # def newvalues(*names) @value_collection.newvalues(*names) end + # Makes the given `name` an alias for the given `other` name. + # Or said differently, the valid value `other` can now also be referred to via the given `name`. + # Aliasing may affect how the parameter's value is serialized/stored (it may store the `other` value + # instead of the alias). + # @api public + # @dsl type + # def aliasvalue(name, other) @value_collection.aliasvalue(name, other) end end - # Just a simple method to proxy instance methods to class methods + # Creates instance (proxy) methods that delegates to a class method with the same name. + # @api private + # def self.proxymethods(*values) values.each { |val| define_method(val) do @@ -130,21 +287,45 @@ class Puppet::Parameter } end - # And then define one of these proxies for each method in our - # ParamHandler class. + # @!method required? + # (see required?) + # @!method isnamevar? + # (see isnamevar?) + # proxymethods("required?", "isnamevar?") + # @return [Puppet::Resource] A reference to the resource this parameter is an attribute of (the _associated resource_). attr_accessor :resource - # LAK 2007-05-09: Keep the @parent around for backward compatibility. + + # @comment LAK 2007-05-09: Keep the @parent around for backward compatibility. + # @return [Puppet::Parameter] A reference to the parameter's parent kept for backwards compatibility. + # @api private + # attr_accessor :parent + # @!method line() + # @return [Integer] Returns the result of calling the same method on the associated resource. + # @!method file + # @return [Integer] Returns the result of calling the same method on the associated resource. + # @!method version + # @return [Integer] Returns the result of calling the same method on the associated resource. + # [:line, :file, :version].each do |param| define_method(param) do resource.send(param) end end - # Basic parameter initialization. + # Initializes the parameter with a required resource reference and optional attribute settings. + # The option `:resource` must be specified or an exception is raised. Any additional options passed + # are used to initialize the attributes of this parameter by treating each key in the `options` hash as + # the name of the attribute to set, and the value as the value to set. + # @param options [Hash{Symbol => Object]] Options, where `resource` is required + # @option options [Puppet::Resource] :resource The resource this parameter holds a value for. Required. + # @raise [Puppet::DevError] If resource is not specified in the options hash. + # @api public + # @note A parameter should be created via the DSL method {Puppet::Type::newparam} + # def initialize(options = {}) options = symbolize_options(options) if resource = options[:resource] @@ -157,24 +338,35 @@ class Puppet::Parameter set_options(options) end + # Writes the given `msg` to the log with the loglevel indicated by the associated resource's + # `loglevel` parameter. + # @todo is loglevel a metaparameter? it is looked up with `resource[:loglevel]` + # @return [void] + # @api public def log(msg) send_log(resource[:loglevel], msg) end - # Is this parameter a metaparam? + # @return [Boolean] Returns whether this parameter is a meta-parameter or not. 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 + # @!attribute [r] name + # @return [Symbol] The parameter's name as given when it was created. + # @note Since a Parameter defines the name at the class level, each Parameter class must be + # unique within a type's inheritance chain. + # @comment 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 + # @return [Boolean] Returns true if this parameter, the associated resource, or overall puppet mode is `noop`. + # @todo How is noop mode set for a parameter? Is this of value in DSL to inhibit a parameter? + # def noop @noop ||= false tmp = @noop || self.resource.noop || Puppet[:noop] || false @@ -182,8 +374,11 @@ class Puppet::Parameter tmp end - # return the full path to us, for logging and rollback; not currently - # used + # @todo Original comment = _return the full path to us, for logging and rollback; not currently + # used_ This is difficult to figure out (if it is used or not as calls are certainly made to "pathbuilder" + # method is several places, not just sure if it is this implementation or not. + # + # @api private def pathbuilder if @resource return [@resource.pathbuilder, self.name] @@ -192,18 +387,31 @@ class Puppet::Parameter end end - # If the specified value is allowed, then munge appropriately. - # If the developer uses a 'munge' hook, this method will get overridden. + # This is the default implementation of `munge` that simply produces the value (if it is valid). + # The DSL method {munge} should be used to define an overriding method if munging is required. + # + # @api private + # def unsafe_munge(value) self.class.value_collection.munge(value) end - # no unmunge by default + # Unmunges the value by transforming it from internal form to DSL form. + # This is the default implementation of `unmunge` that simply returns the value without processing. + # The DSL method {unmunge} should be used to define an overriding method if required. + # @return [Object] the unmunged value + # def unmunge(value) value end - # A wrapper around our munging that makes sure we raise useful exceptions. + # Munges the value to internal form. + # This implementation of `munge` provides exception handling around the specified munging of this parameter. + # @note This method should not be overridden. Use the DSL method {munge} to define a munging method + # if required. + # @param value [Object] the DSL value to munge + # @return [Object] the munged (internal) value + # def munge(value) begin ret = unsafe_munge(value) @@ -216,13 +424,27 @@ class Puppet::Parameter ret end - # Verify that the passed value is valid. - # If the developer uses a 'validate' hook, this method will get overridden. + # This is the default implementation of `validate` that may be overridden by the DSL method {validate}. + # If no valid values have been defined, the given value is accepted, else it is validated against + # the literal values (enumerator) and/or patterns defined by calling {newvalues}. + # + # @param value [Object] the value to check for validity + # @raise [ArgumentError] if the value is not valid + # @return [void] + # @api private + # def unsafe_validate(value) self.class.value_collection.validate(value) end + # Performs validation of the given value against the rules defined by this parameter. + # @return [void] + # @todo Better description of when the various exceptions are raised.ArgumentError is rescued and + # changed into Puppet::Error. + # @raise [ArgumentError, TypeError, Puppet::DevError, Puppet::Error] under various conditions # A protected validation method that only ever raises useful exceptions. + # @api public + # def validate(value) begin unsafe_validate(value) @@ -235,30 +457,54 @@ class Puppet::Parameter end end + # Sets the associated resource to nil. + # @todo Why - what is the intent/purpose of this? + # @return [nil] + # def remove @resource = nil end + # @return [Object] Gets the value of this parameter after performing any specified unmunging. 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). + # Sets the given value as the value of this parameter. + # @todo This original comment _"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)."_ does not seem to be correct, the implementation + # calls both validate an munge on the given value, so no late binding. + # + # The given value is validated and then munged (if munging has been specified). The result is store + # as the value of this arameter. + # @return [Object] The given `value` after munging. + # @raise (see #validate) + # 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. + # @return [Puppet::Provider] Returns the provider of the associated resource. + # @todo The original comment says = _"Retrieve the resource's provider. + # Some types don't have providers, in which case we return the resource object itself."_ + # This does not seem to be true, the default implementation that sets this value may be + # {Puppet::Type.provider=} which always gets either the name of a provider or an instance of one. + # def provider @resource.provider end - # The properties need to return tags so that logs correctly collect them. + # @return [Array<Symbol>] Returns an array of the associated resource's symbolic tags (including the parameter itself). + # Returns an array of the associated resource's symbolic tags (including the parameter itself). + # At a minimun, the array contains the name of the parameter. If the associated resource + # has tags, these tags are also included in the array. + # @todo The original comment says = _"The properties need to return tags so that logs correctly + # collect them."_ what if anything of that is of interest to document. Should tags and their relationship + # to logs be described. This is a more general concept. + # def tags unless defined?(@tags) @tags = [] @@ -269,10 +515,29 @@ class Puppet::Parameter @tags end + # @return [String] The name of the parameter in string form. def to_s name.to_s end + # Produces a String with the value formatted for display to a human. + # When the parameter value is a: + # + # * **single valued parameter value** the result is produced on the + # form `'value'` where _value_ is the string form of the parameter's value. + # + # * **Array** the list of values is enclosed in `[]`, and + # each produced value is separated by a comma. + # + # * **Hash** value is output with keys in sorted order enclosed in `{}` with each entry formatted + # on the form `'k' => v` where + # `k` is the key in string form and _v_ is the value of the key. Entries are comma separated. + # + # For both Array and Hash this method is called recursively to format contained values. + # @note this method does not protect against infinite structures. + # + # @return [String] The formatted value in string form. + # def self.format_value_for_display(value) if value.is_a? Array formatted_values = value.collect {|value| format_value_for_display(value)}.join(', ') diff --git a/lib/puppet/parameter/package_options.rb b/lib/puppet/parameter/package_options.rb index 7482cb048..60b3c06c3 100644 --- a/lib/puppet/parameter/package_options.rb +++ b/lib/puppet/parameter/package_options.rb @@ -1,5 +1,9 @@ require 'puppet/parameter' +# This specialized {Puppet::Parameter} handles munging of package options. +# Package options are passed as an array of key value pairs. Special munging is +# required as the keys and values needs to be quoted in a safe way. +# class Puppet::Parameter::PackageOptions < Puppet::Parameter def unsafe_munge(values) values = [values] unless values.is_a? Array @@ -20,6 +24,7 @@ class Puppet::Parameter::PackageOptions < Puppet::Parameter end end + # @api private def quote(value) value.include?(' ') ? %Q["#{value.gsub(/"/, '\"')}"] : value end diff --git a/lib/puppet/parameter/path.rb b/lib/puppet/parameter/path.rb index 11d0969db..430aca1de 100644 --- a/lib/puppet/parameter/path.rb +++ b/lib/puppet/parameter/path.rb @@ -1,6 +1,13 @@ require 'puppet/parameter' +# This specialized {Puppet::Parameter} handles validation and munging of paths. +# By default, a single path is accepted, and by calling {accept_arrays} it is possible to +# allow an array of paths. +# class Puppet::Parameter::Path < Puppet::Parameter + # Specifies whether multiple paths are accepted or not. + # @dsl type + # def self.accept_arrays(bool = true) @accept_arrays = !!bool end @@ -8,6 +15,13 @@ class Puppet::Parameter::Path < Puppet::Parameter @accept_arrays end + # Performs validation of the given paths. + # If the concrete parameter defines a validation method, it may call this method to perform + # path validation. + # @raise [Puppet::Error] if this property is configured for single paths and an array is given + # @raise [Puppet::Error] if a path is not an absolute path + # @return [Array<String>] the given paths + # def validate_path(paths) if paths.is_a?(Array) and ! self.class.arrays? then fail "#{name} only accepts a single path, not an array of paths" @@ -18,13 +32,22 @@ class Puppet::Parameter::Path < Puppet::Parameter paths end - # This will be overridden if someone uses the validate option, which is why - # it just delegates to the other, useful, method. + # This is the default implementation of the `validate` method. + # It will be overridden if the validate option is used when defining the parameter. + # @return [void] + # def unsafe_validate(paths) validate_path(paths) end - # Likewise, this might be overridden, but by default... + # This is the default implementation of `munge`. + # If the concrete parameter defines a `munge` method, this default implementation will be overridden. + # This default implementation does not perform any munging, it just checks the one/many paths + # constraints. A derived implementation can perform this check as: + # `paths.is_a?(Array) and ! self.class.arrays?` and raise a {Puppet::Error}. + # @param [String, Array<String>] one of multiple paths + # @return [String, Array<String>] the given paths + # @raise [Puppet::Error] if the given paths does not comply with the on/many paths rule. def unsafe_munge(paths) if paths.is_a?(Array) and ! self.class.arrays? then fail "#{name} only accepts a single path, not an array of paths" diff --git a/lib/puppet/parameter/value.rb b/lib/puppet/parameter/value.rb index 12c389d2f..c45c40e5e 100644 --- a/lib/puppet/parameter/value.rb +++ b/lib/puppet/parameter/value.rb @@ -1,25 +1,42 @@ require 'puppet/parameter/value_collection' -# An individual Value class. +# Describes an acceptable value for a parameter or property. +# An acceptable value is either specified as a literal value or a regular expression. +# @note this class should be used via the api methods in {Puppet::Parameter} and {Puppet::Property} +# @api private +# class Puppet::Parameter::Value attr_reader :name, :options, :event attr_accessor :block, :call, :method, :required_features - # Add an alias for this value. + # Adds an alias for this value. + # Makes the given _name_ be an alias for this acceptable value. + # @param name [Symbol] the additonal alias this value should be known as + # @api private + # def alias(name) @aliases << convert(name) end - # Return all aliases. + # @return [Array<Symbol>] Returns all aliases (or an empty array). + # @api private + # def aliases @aliases.dup end - # Store the event that our value generates, if it does so. + # Stores the event that our value generates, if it does so. + # @api private + # def event=(value) @event = convert(value) end + # Initializes the instance with a literal accepted value, or a regular expression. + # If anything else is passed, it is turned into a String, and then made into a Symbol. + # @param [Symbol, Regexp, Object] the value to accept, Symbol, a regular expression, or object to convert. + # @api private + # def initialize(name) if name.is_a?(Regexp) @name = name @@ -34,7 +51,10 @@ class Puppet::Parameter::Value @call = :instead end - # Does a provided value match our value? + # Checks if the given value matches the acceptance rules (literal value, regular expression, or one + # of the aliases. + # @api private + # def match?(value) if regex? return true if name =~ value.to_s @@ -43,7 +63,9 @@ class Puppet::Parameter::Value end end - # Is our value a regex? + # @return [Boolean] whether the accepted value is a regular expression or not. + # @api private + # def regex? @name.is_a?(Regexp) end @@ -52,6 +74,8 @@ class Puppet::Parameter::Value # A standard way of converting all of our values, so we're always # comparing apples to apples. + # @api private + # def convert(value) case value when Symbol, '' # can't intern an empty string diff --git a/lib/puppet/parameter/value_collection.rb b/lib/puppet/parameter/value_collection.rb index 619e0731d..c048fbdaa 100644 --- a/lib/puppet/parameter/value_collection.rb +++ b/lib/puppet/parameter/value_collection.rb @@ -1,9 +1,21 @@ require 'puppet/parameter/value' -# A collection of values and regexes, used for specifying -# what values are allowed in a given parameter. +# A collection of values and regular expressions, used for specifying allowed values +# in a given parameter. +# @note This class is considered part of the internal implementation of {Puppet::Parameter}, and +# {Puppet::Property} and the functionality provided by this class should be used via their interfaces. +# @comment This class probably have several problems when trying to use it with a combination of +# regular expressions and aliases as it finds an acceptable value holder vi "name" which may be +# a regular expression... +# +# @api private +# class Puppet::Parameter::ValueCollection + # Aliases the given existing _other_ value with the additional given _name_. + # @return [void] + # @api private + # def aliasvalue(name, other) other = other.to_sym unless value = match?(other) @@ -13,7 +25,10 @@ class Puppet::Parameter::ValueCollection value.alias(name) end - # Return a doc string for all of the values in this parameter/property. + # Returns a doc string (enumerating the acceptable values) for all of the values in this parameter/property. + # @return [String] a documentation string. + # @api private + # def doc unless defined?(@doc) @doc = "" @@ -34,11 +49,15 @@ class Puppet::Parameter::ValueCollection @doc end - # Does this collection contain any value definitions? + # @return [Boolean] Returns whether the set of allowed values is empty or not. + # @api private + # def empty? @values.empty? end + # @api private + # def initialize # We often look values up by name, so a hash makes more sense. @values = {} @@ -49,7 +68,15 @@ class Puppet::Parameter::ValueCollection @strings = [] end - # Can we match a given value? + # Checks if the given value is acceptable (matches one of the literal values or patterns) and returns + # the "matcher" that matched. + # Literal string matchers are tested first, if both a literal and a regexp match would match, the literal + # match wins. + # + # @param test_value [Object] the value to test if it complies with the configured rules + # @return [Puppet::Parameter::Value, nil] The instance of Puppet::Parameter::Value that matched the given value, or nil if there was no match. + # @api private + # def match?(test_value) # First look for normal values if value = @strings.find { |v| v.match?(test_value) } @@ -60,7 +87,14 @@ class Puppet::Parameter::ValueCollection @regexes.find { |v| v.match?(test_value) } end - # If the specified value is allowed, then munge appropriately. + # Munges the value if it is valid, else produces the same value. + # @param value [Object] the value to munge + # @return [Object] the munged value, or the given value + # @todo This method does not seem to do any munging. It just returns the value if it matches the + # regexp, or the (most likely Symbolic) allowed value if it matches (which is more of a replacement + # of one instance with an equal one. Is the intent that this method should be specialized? + # @api private + # def munge(value) return value if empty? @@ -75,17 +109,25 @@ class Puppet::Parameter::ValueCollection 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. + # Defines a new valid value for a {Puppet::Property}. + # A valid value is specified as a literal (typically a Symbol), but can also be + # specified with a regexp. + # + # @param name [Symbol, Regexp] a valid literal value, or a regexp that matches a value + # @param options [Hash] a hash with options + # @option options [Symbol] :event The event that should be emitted when this value is set. + # @todo Option :event original comment says "event should be returned...", is "returned" the correct word + # to use? + # @option options [Symbol] :call When to call any associated block. The default value is `:instead` which + # means that the block should be called instead of the provider. In earlier versions (before 20081031) it + # was possible to specify a value of `:before` or `:after` for the purpose of calling + # both the block and the provider. Use of these deprecated options will now raise an exception later + # in the process when the _is_ value is set (see Puppet::Property#set). + # @option options [Object] _any_ Any other option is treated as a call to a setter having the given + # option name (e.g. `:required_features` calls `required_features=` with the option's value as an + # argument). + # @api private # - # 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 @@ -107,16 +149,27 @@ class Puppet::Parameter::ValueCollection value end - # Define one or more new values for our parameter. + # Defines one or more valid values (literal or regexp) for a parameter or property. + # @return [void] + # @dsl type + # @api private + # def newvalues(*names) names.each { |name| newvalue(name) } end + # @return [Array<String>] An array of the regular expressions in string form, configured as matching valid values. + # @api private + # def regexes @regexes.collect { |r| r.name.inspect } end - # Verify that the passed value is valid. + # Validates the given value against the set of valid literal values and regular expressions. + # @raise [ArgumentError] if the value is not accepted + # @return [void] + # @api private + # def validate(value) return if empty? @@ -131,12 +184,21 @@ class Puppet::Parameter::ValueCollection end end - # Return a single value instance. + # Returns a valid value matcher (a literal or regular expression) + # @todo This looks odd, asking for an instance that matches a symbol, or a instance that has + # a regexp. What is the intention here? Marking as api private... + # + # @return [Puppet::Parameter::Value] a valid valud matcher + # @api private + # def value(name) @values[name] end - # Return the list of valid values. + # @return [Array<Symbol>] Returns a list of valid literal values. + # @see regexes + # @api private + # def values @strings.collect { |s| s.name } end diff --git a/lib/puppet/parser.rb b/lib/puppet/parser.rb index 4d274b43c..e01ca1f9f 100644 --- a/lib/puppet/parser.rb +++ b/lib/puppet/parser.rb @@ -1,3 +1,6 @@ +# @api public +module Puppet::Parser; end + require 'puppet/parser/parser' require 'puppet/parser/compiler' require 'puppet/resource/type_collection' diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index a814c7980..484b4ea22 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -5,6 +5,8 @@ require 'monitor' # A module for managing parser functions. Each specified function # is added to a central module that then gets included into the Scope # class. +# +# @api public module Puppet::Parser::Functions Environment = Puppet::Node::Environment @@ -12,7 +14,9 @@ module Puppet::Parser::Functions include Puppet::Util end - # This is used by tests + # Reset the list of loaded functions. + # + # @api private def self.reset @functions = Hash.new { |h,k| h[k] = {} }.extend(MonitorMixin) @modules = Hash.new.extend(MonitorMixin) @@ -25,12 +29,19 @@ module Puppet::Parser::Functions end end + # Accessor for singleton autoloader + # + # @api private def self.autoloader @autoloader ||= Puppet::Util::Autoload.new( self, "puppet/parser/functions", :wrap => false ) end + # Get the module that functions are mixed into corresponding to an + # environment + # + # @api private def self.environment_module(env = nil) if env and ! env.is_a?(Puppet::Node::Environment) env = Puppet::Node::Environment.new(env) @@ -40,12 +51,79 @@ module Puppet::Parser::Functions } end - # Create a new function type. + # Create a new Puppet DSL function. + # + # **The {newfunction} method provides a public API.** + # + # This method is used both internally inside of Puppet to define parser + # functions. For example, template() is defined in + # {file:lib/puppet/parser/functions/template.rb template.rb} using the + # {newfunction} method. Third party Puppet modules such as + # [stdlib](https://forge.puppetlabs.com/puppetlabs/stdlib) use this method to + # extend the behavior and functionality of Puppet. + # + # See also [Docs: Custom + # Functions](http://docs.puppetlabs.com/guides/custom_functions.html) + # + # @example Define a new Puppet DSL Function + # >> Puppet::Parser::Functions.newfunction(:double, :arity => 1, + # :doc => "Doubles an object, typically a number or string.", + # :type => :rvalue) {|i| i[0]*2 } + # => {:arity=>1, :type=>:rvalue, + # :name=>"function_double", + # :doc=>"Doubles an object, typically a number or string."} + # + # @example Invoke the double function from irb as is done in RSpec examples: + # >> scope = Puppet::Parser::Scope.new_for_test_harness('example') + # => Scope() + # >> scope.function_double([2]) + # => 4 + # >> scope.function_double([4]) + # => 8 + # >> scope.function_double([]) + # ArgumentError: double(): Wrong number of arguments given (0 for 1) + # >> scope.function_double([4,8]) + # ArgumentError: double(): Wrong number of arguments given (2 for 1) + # >> scope.function_double(["hello"]) + # => "hellohello" + # + # @param [Symbol] name the name of the function represented as a ruby Symbol. + # The {newfunction} method will define a Ruby method based on this name on + # the parser scope instance. + # + # @param [Proc] block the block provided to the {newfunction} method will be + # executed when the Puppet DSL function is evaluated during catalog + # compilation. The arguments to the function will be passed as an array to + # the first argument of the block. The return value of the block will be + # the return value of the Puppet DSL function for `:rvalue` functions. + # + # @option options [:rvalue, :statement] :type (:statement) the type of function. + # Either `:rvalue` for functions that return a value, or `:statement` for + # functions that do not return a value. + # + # @option options [String] :doc ('') the documentation for the function. + # This string will be extracted by documentation generation tools. + # + # @option options [Integer] :arity (-1) the + # [arity](http://en.wikipedia.org/wiki/Arity) of the function. When + # specified as a positive integer the function is expected to receive + # _exactly_ the specified number of arguments. When specified as a + # negative number, the function is expected to receive _at least_ the + # absolute value of the specified number of arguments incremented by one. + # For example, a function with an arity of `-4` is expected to receive at + # minimum 3 arguments. A function with the default arity of `-1` accepts + # zero or more arguments. A function with an arity of 2 must be provided + # with exactly two arguments, no more and no less. Added in Puppet 3.1.0. + # + # @return [Hash] describing the function. + # + # @api public def self.newfunction(name, options = {}, &block) name = name.intern Puppet.warning "Overwriting previous definition for function #{name}" if get_function(name) + arity = options[:arity] || -1 ftype = options[:type] || :statement unless ftype == :statement or ftype == :rvalue @@ -60,22 +138,32 @@ module Puppet::Parser::Functions fname = "function_#{name}" environment_module.send(:define_method, fname) do |*args| if args[0].is_a? Array + if arity >= 0 and args[0].size != arity + raise ArgumentError, "#{name}(): Wrong number of arguments given (#{args[0].size} for #{arity})" + elsif arity < 0 and args[0].size < (arity+1).abs + raise ArgumentError, "#{name}(): Wrong number of arguments given (#{args[0].size} for minimum #{(arity+1).abs})" + end self.send(real_fname, args[0]) else raise ArgumentError, "custom functions must be called with a single array that contains the arguments. For example, function_example([1]) instead of function_example(1)" end end - # Someday we'll support specifying an arity, but for now, nope - #functions[name] = {:arity => arity, :type => ftype} - func = {:type => ftype, :name => fname} + func = {:arity => arity, :type => ftype, :name => fname} func[:doc] = options[:doc] if options[:doc] add_function(name, func) func end - # Determine if a given name is a function + # Determine if a function is defined + # + # @param [Symbol] name the function + # + # @return [Symbol, false] The name of the function if it's defined, + # otherwise false. + # + # @api public def self.function(name) name = name.intern @@ -113,12 +201,28 @@ module Puppet::Parser::Functions ret end - # Determine if a given function returns a value or not. + # Determine whether a given function returns a value. + # + # @param [Symbol] name the function + # + # @api public def self.rvalue?(name) func = get_function(name) func ? func[:type] == :rvalue : false end + # Return the number of arguments a function expects. + # + # @param [Symbol] name the function + # @return [Integer] The arity of the function. See {newfunction} for + # the meaning of negative values. + # + # @api public + def self.arity(name) + func = get_function(name) + func ? func[:arity] : -1 + end + class << self private diff --git a/lib/puppet/parser/functions/create_resources.rb b/lib/puppet/parser/functions/create_resources.rb index e8497c2f3..6c0f696a7 100644 --- a/lib/puppet/parser/functions/create_resources.rb +++ b/lib/puppet/parser/functions/create_resources.rb @@ -1,4 +1,4 @@ -Puppet::Parser::Functions::newfunction(:create_resources, :doc => <<-'ENDHEREDOC') do |args| +Puppet::Parser::Functions::newfunction(:create_resources, :arity => -3, :doc => <<-'ENDHEREDOC') do |args| Converts a hash into a set of resources and adds them to the catalog. This function takes two mandatory arguments: a resource type, and a hash describing @@ -31,12 +31,31 @@ Puppet::Parser::Functions::newfunction(:create_resources, :doc => <<-'ENDHEREDOC This function can be used to create defined resources and classes, as well as native resources. + + Virtual and Exported resources may be created by prefixing the type name + with @ or @@ respectively. For example, the $myusers hash may be exported + in the following manner: + + create_resources("@@user", $myusers) + + The $myusers may be declared as virtual resources using: + + create_resources("@user", $myusers) + ENDHEREDOC - raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2 or 3)") if args.length < 2 || args.length > 3 + raise ArgumentError, ("create_resources(): wrong number of arguments (#{args.length}; must be 2 or 3)") if args.length > 3 # figure out what kind of resource we are type_of_resource = nil type_name = args[0].downcase + type_exported, type_virtual = false + if type_name.start_with? '@@' + type_name = type_name[2..-1] + type_exported = true + elsif type_name.start_with? '@' + type_name = type_name[1..-1] + type_virtual = true + end if type_name == 'class' type_of_resource = :class else @@ -58,6 +77,8 @@ Puppet::Parser::Functions::newfunction(:create_resources, :doc => <<-'ENDHEREDOC # for a defined type. when :type, :define p_resource = Puppet::Parser::Resource.new(type_name, title, :scope => self, :source => resource) + p_resource.virtual = type_virtual + p_resource.exported = type_exported {:name => title}.merge(params).each do |k,v| p_resource.set_parameter(k,v) end diff --git a/lib/puppet/parser/functions/defined.rb b/lib/puppet/parser/functions/defined.rb index 2aeaa9ba0..314cc45a0 100644 --- a/lib/puppet/parser/functions/defined.rb +++ b/lib/puppet/parser/functions/defined.rb @@ -1,5 +1,5 @@ # Test whether a given class or definition is defined -Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :doc => "Determine whether +Puppet::Parser::Functions::newfunction(:defined, :type => :rvalue, :arity => -2, :doc => "Determine whether a given class or resource type is defined. This function can also determine whether a specific resource has been declared. Returns true or false. Accepts class names, type names, and resource references. diff --git a/lib/puppet/parser/functions/extlookup.rb b/lib/puppet/parser/functions/extlookup.rb index dbc319dde..d012bcd72 100644 --- a/lib/puppet/parser/functions/extlookup.rb +++ b/lib/puppet/parser/functions/extlookup.rb @@ -3,6 +3,7 @@ require 'csv' module Puppet::Parser::Functions newfunction(:extlookup, :type => :rvalue, + :arity => -2, :doc => "This is a parser function to read data from external files, this version uses CSV files but the concept can easily be adjust for databases, yaml or any other queryable data source. @@ -89,7 +90,7 @@ This is for back compatibility to interpolate variables with %. % interpolation default = args[1] datafile = args[2] - raise Puppet::ParseError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3 + raise ArgumentError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3 extlookup_datadir = undef_as('',self['::extlookup_datadir']) diff --git a/lib/puppet/parser/functions/fail.rb b/lib/puppet/parser/functions/fail.rb index 5bef6c7e3..34c99b638 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| +Puppet::Parser::Functions::newfunction(:fail, :arity => -1, :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 end diff --git a/lib/puppet/parser/functions/file.rb b/lib/puppet/parser/functions/file.rb index 2b9a709de..569266a3b 100644 --- a/lib/puppet/parser/functions/file.rb +++ b/lib/puppet/parser/functions/file.rb @@ -1,7 +1,7 @@ # Returns the contents of a file Puppet::Parser::Functions::newfunction( - :file, :type => :rvalue, + :file, :arity => -2, :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| diff --git a/lib/puppet/parser/functions/fqdn_rand.rb b/lib/puppet/parser/functions/fqdn_rand.rb index 916338e98..b39c0bb77 100644 --- a/lib/puppet/parser/functions/fqdn_rand.rb +++ b/lib/puppet/parser/functions/fqdn_rand.rb @@ -1,6 +1,6 @@ require 'digest/md5' -Puppet::Parser::Functions::newfunction(:fqdn_rand, :type => :rvalue, :doc => +Puppet::Parser::Functions::newfunction(:fqdn_rand, :arity => -2, :type => :rvalue, :doc => "Generates random numbers based on the node's fqdn. Generated random values will be a range from 0 up to and excluding n, where n is the first parameter. The second argument specifies a number to add to the seed and is optional, for example: diff --git a/lib/puppet/parser/functions/generate.rb b/lib/puppet/parser/functions/generate.rb index 1f8286c1c..71bd0b19f 100644 --- a/lib/puppet/parser/functions/generate.rb +++ b/lib/puppet/parser/functions/generate.rb @@ -1,5 +1,5 @@ # Runs an external command and returns the results -Puppet::Parser::Functions::newfunction(:generate, :type => :rvalue, +Puppet::Parser::Functions::newfunction(:generate, :arity => -2, :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, diff --git a/lib/puppet/parser/functions/hiera.rb b/lib/puppet/parser/functions/hiera.rb index 4c75b8ee5..9de4f70f1 100644 --- a/lib/puppet/parser/functions/hiera.rb +++ b/lib/puppet/parser/functions/hiera.rb @@ -1,5 +1,5 @@ module Puppet::Parser::Functions - newfunction(:hiera, :type => :rvalue) do |*args| + newfunction(:hiera, :type => :rvalue, :arity => -2) do |*args| require 'hiera_puppet' key, default, override = HieraPuppet.parse_args(args) HieraPuppet.lookup(key, default, self, override, :priority) diff --git a/lib/puppet/parser/functions/hiera_array.rb b/lib/puppet/parser/functions/hiera_array.rb index dc87b28fb..61ad5e6aa 100644 --- a/lib/puppet/parser/functions/hiera_array.rb +++ b/lib/puppet/parser/functions/hiera_array.rb @@ -1,5 +1,5 @@ module Puppet::Parser::Functions - newfunction(:hiera_array, :type => :rvalue) do |*args| + newfunction(:hiera_array, :type => :rvalue, :arity => -2) do |*args| require 'hiera_puppet' key, default, override = HieraPuppet.parse_args(args) HieraPuppet.lookup(key, default, self, override, :array) diff --git a/lib/puppet/parser/functions/hiera_hash.rb b/lib/puppet/parser/functions/hiera_hash.rb index baae15169..7f26a0924 100644 --- a/lib/puppet/parser/functions/hiera_hash.rb +++ b/lib/puppet/parser/functions/hiera_hash.rb @@ -1,5 +1,5 @@ module Puppet::Parser::Functions - newfunction(:hiera_hash, :type => :rvalue) do |*args| + newfunction(:hiera_hash, :type => :rvalue, :arity => -2) do |*args| require 'hiera_puppet' key, default, override = HieraPuppet.parse_args(args) HieraPuppet.lookup(key, default, self, override, :hash) diff --git a/lib/puppet/parser/functions/hiera_include.rb b/lib/puppet/parser/functions/hiera_include.rb index 6cf125d1e..bb77c151c 100644 --- a/lib/puppet/parser/functions/hiera_include.rb +++ b/lib/puppet/parser/functions/hiera_include.rb @@ -1,5 +1,5 @@ module Puppet::Parser::Functions - newfunction(:hiera_include) do |*args| + newfunction(:hiera_include, :arity => -2) do |*args| require 'hiera_puppet' key, default, override = HieraPuppet.parse_args(args) if answer = HieraPuppet.lookup(key, default, self, override, :array) diff --git a/lib/puppet/parser/functions/include.rb b/lib/puppet/parser/functions/include.rb index 5e24e4942..ca8819176 100644 --- a/lib/puppet/parser/functions/include.rb +++ b/lib/puppet/parser/functions/include.rb @@ -1,5 +1,5 @@ # Include the specified classes -Puppet::Parser::Functions::newfunction(:include, :doc => "Evaluate one or more classes.") do |vals| +Puppet::Parser::Functions::newfunction(:include, :arity => -2, :doc => "Evaluate one or more classes.") do |vals| if vals.is_a?(Array) # Protect against array inside array vals = vals.flatten diff --git a/lib/puppet/parser/functions/inline_template.rb b/lib/puppet/parser/functions/inline_template.rb index 9759ff6e1..d86024154 100644 --- a/lib/puppet/parser/functions/inline_template.rb +++ b/lib/puppet/parser/functions/inline_template.rb @@ -1,4 +1,4 @@ -Puppet::Parser::Functions::newfunction(:inline_template, :type => :rvalue, :doc => +Puppet::Parser::Functions::newfunction(:inline_template, :type => :rvalue, :arity => -2, :doc => "Evaluate a template string and return its value. See [the templating docs](http://docs.puppetlabs.com/guides/templating.html) for more information. Note that if multiple template strings are specified, their diff --git a/lib/puppet/parser/functions/md5.rb b/lib/puppet/parser/functions/md5.rb index d1e1efae2..d9e1ee802 100644 --- a/lib/puppet/parser/functions/md5.rb +++ b/lib/puppet/parser/functions/md5.rb @@ -1,5 +1,5 @@ require 'digest/md5' -Puppet::Parser::Functions::newfunction(:md5, :type => :rvalue, :doc => "Returns a MD5 hash value from a provided string.") do |args| +Puppet::Parser::Functions::newfunction(:md5, :type => :rvalue, :arity => 1, :doc => "Returns a MD5 hash value from a provided string.") do |args| Digest::MD5.hexdigest(args[0]) end diff --git a/lib/puppet/parser/functions/realize.rb b/lib/puppet/parser/functions/realize.rb index c21ccd14a..4d1567de1 100644 --- a/lib/puppet/parser/functions/realize.rb +++ b/lib/puppet/parser/functions/realize.rb @@ -1,7 +1,7 @@ # This is just syntactic sugar for a collection, although it will generally # be a good bit faster. -Puppet::Parser::Functions::newfunction(:realize, :doc => "Make a virtual object real. This is useful +Puppet::Parser::Functions::newfunction(:realize, :arity => -2, :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 diff --git a/lib/puppet/parser/functions/regsubst.rb b/lib/puppet/parser/functions/regsubst.rb index 397d2b2ee..a22dc53c9 100644 --- a/lib/puppet/parser/functions/regsubst.rb +++ b/lib/puppet/parser/functions/regsubst.rb @@ -24,10 +24,9 @@ # other dealings in this Software without prior written authorization # from Thomas Bellman. -module Puppet::Parser::Functions - - newfunction( +Puppet::Parser::Functions::newfunction( :regsubst, :type => :rvalue, + :arity => -4, :doc => " Perform regexp replacement on a string or array of strings. @@ -56,64 +55,62 @@ Get the third octet from the node's IP address: Put angle brackets around each octet in the node's IP address: $x = regsubst($ipaddress, '([0-9]+)', '<\\1>', 'G') -") \ - do |args| - unless args.length.between?(3, 5) +") do |args| + unless args.length.between?(3, 5) - raise( - Puppet::ParseError, + raise( + ArgumentError, - "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 + "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 - begin - re = Regexp.compile(regexp, reflags, lang) - rescue RegexpError, TypeError + end + begin + re = Regexp.compile(regexp, reflags, lang) + rescue RegexpError, TypeError - raise( - Puppet::ParseError, + 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 + "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 diff --git a/lib/puppet/parser/functions/require.rb b/lib/puppet/parser/functions/require.rb index 44aca854d..819b82619 100644 --- a/lib/puppet/parser/functions/require.rb +++ b/lib/puppet/parser/functions/require.rb @@ -2,6 +2,7 @@ Puppet::Parser::Functions::newfunction( :require, + :arity => -2, :doc =>"Evaluate one or more classes, adding the required class as a dependency. The relationship metaparameters work well for specifying relationships diff --git a/lib/puppet/parser/functions/search.rb b/lib/puppet/parser/functions/search.rb index 8a9c7c8be..04c7579d7 100644 --- a/lib/puppet/parser/functions/search.rb +++ b/lib/puppet/parser/functions/search.rb @@ -1,4 +1,4 @@ -Puppet::Parser::Functions::newfunction(:search, :doc => "Add another namespace for this class to search. +Puppet::Parser::Functions::newfunction(:search, :arity => -2, :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| diff --git a/lib/puppet/parser/functions/sha1.rb b/lib/puppet/parser/functions/sha1.rb index c52df4d28..7c565cf61 100644 --- a/lib/puppet/parser/functions/sha1.rb +++ b/lib/puppet/parser/functions/sha1.rb @@ -1,5 +1,5 @@ require 'digest/sha1' -Puppet::Parser::Functions::newfunction(:sha1, :type => :rvalue, :doc => "Returns a SHA1 hash value from a provided string.") do |args| +Puppet::Parser::Functions::newfunction(:sha1, :type => :rvalue, :arity => 1, :doc => "Returns a SHA1 hash value from a provided string.") do |args| Digest::SHA1.hexdigest(args[0]) end diff --git a/lib/puppet/parser/functions/shellquote.rb b/lib/puppet/parser/functions/shellquote.rb index e30df904c..1cf6b1b22 100644 --- a/lib/puppet/parser/functions/shellquote.rb +++ b/lib/puppet/parser/functions/shellquote.rb @@ -24,7 +24,7 @@ # other dealings in this Software without prior written authorization # from Thomas Bellman. -Puppet::Parser::Functions.newfunction(:shellquote, :type => :rvalue, :doc => "\ +Puppet::Parser::Functions.newfunction(:shellquote, :type => :rvalue, :arity => -1, :doc => "\ Quote and concatenate arguments for use in Bourne shell. Each argument is quoted separately, and then all are concatenated diff --git a/lib/puppet/parser/functions/split.rb b/lib/puppet/parser/functions/split.rb index ad027865b..0485a5ef5 100644 --- a/lib/puppet/parser/functions/split.rb +++ b/lib/puppet/parser/functions/split.rb @@ -2,6 +2,7 @@ module Puppet::Parser::Functions newfunction( :split, :type => :rvalue, + :arity => 2, :doc => "\ Split a string variable into an array using the specified split regexp. @@ -22,8 +23,6 @@ a regexp meta-character (.), which must be escaped. A simple way to do that for a single character is to enclose it in square brackets; a backslash will also escape a single character.") do |args| - 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 end diff --git a/lib/puppet/parser/functions/sprintf.rb b/lib/puppet/parser/functions/sprintf.rb index 118020412..09b57f57d 100644 --- a/lib/puppet/parser/functions/sprintf.rb +++ b/lib/puppet/parser/functions/sprintf.rb @@ -24,16 +24,13 @@ # other dealings in this Software without prior written authorization # from Thomas Bellman. -module Puppet::Parser::Functions - - newfunction( +Puppet::Parser::Functions::newfunction( :sprintf, :type => :rvalue, + :arity => -2, + :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| + fmt = args.shift + return sprintf(fmt, *args) end diff --git a/lib/puppet/parser/functions/tag.rb b/lib/puppet/parser/functions/tag.rb index 84df175eb..b4b1b6907 100644 --- a/lib/puppet/parser/functions/tag.rb +++ b/lib/puppet/parser/functions/tag.rb @@ -1,5 +1,5 @@ # Tag the current scope with each passed name -Puppet::Parser::Functions::newfunction(:tag, :doc => "Add the specified tags to the containing class +Puppet::Parser::Functions::newfunction(:tag, :arity => -2, :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) diff --git a/lib/puppet/parser/functions/tagged.rb b/lib/puppet/parser/functions/tagged.rb index aaa2adfad..72fb16ed7 100644 --- a/lib/puppet/parser/functions/tagged.rb +++ b/lib/puppet/parser/functions/tagged.rb @@ -1,5 +1,5 @@ # 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 +Puppet::Parser::Functions::newfunction(:tagged, :type => :rvalue, :arity => -2, :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| diff --git a/lib/puppet/parser/functions/template.rb b/lib/puppet/parser/functions/template.rb index 5e4b00e1e..d9b48408e 100644 --- a/lib/puppet/parser/functions/template.rb +++ b/lib/puppet/parser/functions/template.rb @@ -1,4 +1,4 @@ -Puppet::Parser::Functions::newfunction(:template, :type => :rvalue, :doc => +Puppet::Parser::Functions::newfunction(:template, :type => :rvalue, :arity => -2, :doc => "Evaluate a template and return its value. See [the templating docs](http://docs.puppetlabs.com/guides/templating.html) for more information. diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb index a7905a6d0..302250d4f 100644 --- a/lib/puppet/parser/functions/versioncmp.rb +++ b/lib/puppet/parser/functions/versioncmp.rb @@ -1,6 +1,6 @@ require 'puppet/util/package' -Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, :doc => +Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, :arity => 2, :doc => "Compares two version numbers. Prototype: @@ -26,9 +26,5 @@ This function uses the same version comparison algorithm used by Puppet's ") do |args| - unless args.length == 2 - raise Puppet::ParseError, "versioncmp should have 2 arguments" - end - return Puppet::Util::Package.versioncmp(args[0], args[1]) end diff --git a/lib/puppet/parser/lexer.rb b/lib/puppet/parser/lexer.rb index 302f9eed5..abb860ca6 100644 --- a/lib/puppet/parser/lexer.rb +++ b/lib/puppet/parser/lexer.rb @@ -25,6 +25,8 @@ class Puppet::Parser::Lexer end class Token + ALWAYS_ACCEPTABLE = Proc.new { |context| true } + include Puppet::Util::MethodHelper attr_accessor :regex, :name, :string, :skip, :incr_line, :skip_text, :accumulate @@ -40,6 +42,7 @@ class Puppet::Parser::Lexer end set_options(options) + @acceptable_when = ALWAYS_ACCEPTABLE end def to_s @@ -47,8 +50,15 @@ class Puppet::Parser::Lexer end def acceptable?(context={}) - # By default tokens are aceeptable in any context - true + @acceptable_when.call(context) + end + + # Define when the token is able to match. + # This provides context that cannot be expressed otherwise, such as feature flags. + # + # @param block [Proc] a proc that given a context returns a boolean + def acceptable_when(block) + @acceptable_when = block end end @@ -157,15 +167,40 @@ class Puppet::Parser::Lexer "<boolean>" => :BOOLEAN ) + module Contextual + QUOTE_TOKENS = [:DQPRE,:DQMID] + REGEX_INTRODUCING_TOKENS = [:NODE,:LBRACE,:RBRACE,:MATCH,:NOMATCH,:COMMA] + + NOT_INSIDE_QUOTES = Proc.new do |context| + !QUOTE_TOKENS.include? context[:after] + end + + INSIDE_QUOTES = Proc.new do |context| + QUOTE_TOKENS.include? context[:after] + end + + IN_REGEX_POSITION = Proc.new do |context| + REGEX_INTRODUCING_TOKENS.include? context[:after] + end + + IN_STRING_INTERPOLATION = Proc.new do |context| + context[:string_interpolation_depth] > 0 + end + + DASHED_VARIABLES_ALLOWED = Proc.new do |context| + Puppet[:allow_variables_with_dashes] + end + + VARIABLE_AND_DASHES_ALLOWED = Proc.new do |context| + Contextual::DASHED_VARIABLES_ALLOWED.call(context) and TOKENS[:VARIABLE].acceptable?(context) + end + end + # Numbers are treated separately from names, so that they may contain dots. 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[:NUMBER].acceptable_when Contextual::NOT_INSIDE_QUOTES TOKENS.add_token :NAME, %r{((::)?[a-z0-9][-\w]*)(::[a-z0-9][-\w]*)*} do |lexer, value| string_token = self @@ -179,13 +214,9 @@ class Puppet::Parser::Lexer end [string_token, value] end - [:NAME,:CLASSNAME,:CLASSREF].each { |name_token| - #:stopdoc: # Issue #4161 - def (TOKENS[name_token]).acceptable?(context={}) - ![:DQPRE,:DQMID].include? context[:after] - end - #:startdoc: - } + [:NAME, :CLASSREF].each do |name_token| + TOKENS[name_token].acceptable_when Contextual::NOT_INSIDE_QUOTES + end TOKENS.add_token :COMMENT, %r{#.*}, :accumulate => true, :skip => true do |lexer,value| value.sub!(/# ?/,'') @@ -208,12 +239,7 @@ class Puppet::Parser::Lexer 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[:REGEX].acceptable_when Contextual::IN_REGEX_POSITION TOKENS.add_token :RETURN, "\n", :skip => true, :incr_line => true, :skip_text => true @@ -231,20 +257,14 @@ class Puppet::Parser::Lexer 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[:DQCONT].acceptable_when Contextual::IN_STRING_INTERPOLATION TOKENS.add_token :DOLLAR_VAR_WITH_DASH, %r{\$(?:::)?(?:[-\w]+::)*[-\w]+} do |lexer, value| lexer.warn_if_variable_has_hyphen(value) [TOKENS[:VARIABLE], value[1..-1]] end - def (TOKENS[:DOLLAR_VAR_WITH_DASH]).acceptable?(context = {}) - Puppet[:allow_variables_with_dashes] - end + TOKENS[:DOLLAR_VAR_WITH_DASH].acceptable_when Contextual::DASHED_VARIABLES_ALLOWED TOKENS.add_token :DOLLAR_VAR, %r{\$(::)?(\w+::)*\w+} do |lexer, value| [TOKENS[:VARIABLE],value[1..-1]] @@ -255,19 +275,10 @@ class Puppet::Parser::Lexer [TOKENS[:VARIABLE], value] end - #:stopdoc: # Issue #4161 - def (TOKENS[:VARIABLE_WITH_DASH]).acceptable?(context={}) - Puppet[:allow_variables_with_dashes] and TOKENS[:VARIABLE].acceptable?(context) - end - #:startdoc: + TOKENS[:VARIABLE_WITH_DASH].acceptable_when Contextual::VARIABLE_AND_DASHES_ALLOWED TOKENS.add_token :VARIABLE, %r{(::)?(\w+::)*\w+} - #:stopdoc: # Issue #4161 - def (TOKENS[:VARIABLE]).acceptable?(context={}) - [:DQPRE,:DQMID].include? context[:after] - end - #:startdoc: - + TOKENS[:VARIABLE].acceptable_when Contextual::INSIDE_QUOTES TOKENS.sort_tokens diff --git a/lib/puppet/parser/parser_support.rb b/lib/puppet/parser/parser_support.rb index 8503d88a7..c7c0057d2 100644 --- a/lib/puppet/parser/parser_support.rb +++ b/lib/puppet/parser/parser_support.rb @@ -158,6 +158,8 @@ class Puppet::Parser::Parser end def parse_ruby_file + Puppet.deprecation_warning("Use of the Ruby DSL is deprecated.") + # Execute the contents of the file inside its own "main" object so # that it can call methods in the resource type API. main_object = Puppet::DSL::ResourceTypeAPI.new diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 5664062c7..1a05b1202 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -8,6 +8,11 @@ require 'puppet/parser/templatewrapper' require 'puppet/resource/type_collection_helper' require 'puppet/util/methodhelper' +# This class is part of the internal parser/evaluator/compiler functionality of Puppet. +# It is passed between the various classes that participate in evaluation. +# None of its methods are API except those that are clearly marked as such. +# +# @api public class Puppet::Parser::Scope extend Forwardable include Puppet::Util::MethodHelper @@ -56,6 +61,9 @@ class Puppet::Parser::Scope # Initialize a new scope suitable for parser function testing. This method # should be considered a public API for external modules. A shared spec # helper should consume this API method. + # + # @api protected + # def self.new_for_test_harness(node_name) node = Puppet::Node.new(node_name) compiler = Puppet::Parser::Compiler.new(node) @@ -235,6 +243,15 @@ class Puppet::Parser::Scope end end + # Lookup a variable within this scope using the Puppet language's + # scoping rules. Variables can be qualified using just as in a + # manifest. + # + # @param [String] name the variable name to lookup + # + # @return Object the value of the variable, or nil if it's not found + # + # @api public def lookupvar(name, options = {}) unless name.is_a? String raise Puppet::DevError, "Scope variable name is a #{name.class}, not a string" @@ -263,7 +280,20 @@ class Puppet::Parser::Scope nil end end - alias [] lookupvar + + # Retrieves the variable value assigned to the name given as an argument. The name must be a String, + # and namespace can be qualified with '::'. The value is looked up in this scope, its parent scopes, + # or in a specific visible named scope. + # + # @param varname [String] the name of the variable (may be a qualified name using `(ns'::')*varname` + # @param options [Hash] Additional options, not part of api. + # @return [Object] the value assigned to the given varname + # @see #[]= + # @api public + # + def [](varname, options={}) + lookupvar(varname, options) + end def qualified_scope(classname) raise "class #{classname} could not be found" unless klass = find_hostclass(classname) @@ -353,7 +383,21 @@ class Puppet::Parser::Scope table[name] = value end end - alias []= setvar + + # Sets the variable value of the name given as an argument to the given value. The value is + # set in the current scope and may shadow a variable with the same name in a visible outer scope. + # It is illegal to re-assign a variable in the same scope. It is illegal to set a variable in some other + # scope/namespace than the scope passed to a method. + # + # @param varname [String] The variable name to which the value is assigned. Must not contain `::` + # @param value [String] The value to assign to the given variable name. + # @param options [Hash] Additional options, not part of api. + # + # @api public + # + def []=(varname, value, options = {}) + setvar(varname, value, options = {}) + end def append_value(bound_value, new_value) case new_value diff --git a/lib/puppet/property.rb b/lib/puppet/property.rb index 52e46fa27..083d68a9d 100644 --- a/lib/puppet/property.rb +++ b/lib/puppet/property.rb @@ -4,27 +4,98 @@ require 'puppet' require 'puppet/parameter' +# The Property class is the implementation of a resource's attributes of _property_ kind. +# A Property is a specialized Resource Type Parameter that has both an 'is' (current) state, and +# a 'should' (wanted state). However, even if this is conceptually true, the current _is_ value is +# obtained by asking the associated provider for the value, and hence it is not actually part of a +# property's state, and only available when a provider has been selected and can obtain the value (i.e. when +# running on an agent). +# +# A Property (also in contrast to a parameter) is intended to describe a managed attribute of +# some system entity, such as the name or mode of a file. +# +# The current value _(is)_ is read and written with the methods {#retrieve} and {#set}, and the wanted +# value _(should)_ is read and written with the methods {#value} and {#value=} which delegate to +# {#should} and {#should=}, i.e. when a property is used like any other parameter, it is the _should_ value +# that is operated on. +# +# All resource type properties in the puppet system are derived from this class. +# +# The intention is that new parameters are created by using the DSL method {Puppet::Type.newproperty}. +# +# @abstract +# @note Properties of Types are expressed using subclasses of this class. Such a class describes one +# named property of a particular Type (as opposed to describing a type of property in general). This +# limits the use of one (concrete) property class instance to occur only once for a given type's inheritance +# chain. An instance of a Property class is the value holder of one instance of the resource type (e.g. the +# mode of a file resource instance). +# A Property class may server as the superclass _(parent)_ of another; e.g. a Size property that describes +# handling of measurements such as kb, mb, gb. If a type requires two different size measurements it requires +# one concrete class per such measure; e.g. MinSize (:parent => Size), and MaxSize (:parent => Size). +# +# @todo Describe meta-parameter shadowing. This concept can not be understood by just looking at the descriptions +# of the methods involved. +# +# @see Puppet::Type +# @see Puppet::Parameter +# +# @api public +# 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. + # Returns the original wanted value(s) _(should)_ unprocessed by munging/unmunging. + # The original values are set by {#value=} or {#should=}. + # @return (see #should) + # attr_reader :shouldorig + # The noop mode for this property. + # By setting a property's noop mode to `true`, any management of this property is inhibited. Calculation + # and reporting still takes place, but if a change of the underlying managed entity's state + # should take place it will not be carried out. This noop + # setting overrides the overall `Puppet[:noop]` mode as well as the noop mode in the _associated resource_ + # attr_writer :noop class << self + # @todo Figure out what this is used for. Can not find any logic in the puppet code base that + # reads or writes this attribute. + # ??? Probably Unused attr_accessor :unmanaged + + # @return [Symbol] The name of the property as given when the property was created. + # attr_reader :name - # Return array matching info, defaulting to just matching - # the first value. + # @!attribute [rw] array_matching + # @comment note that $#46; is a period - char code require to not terminate sentence. + # The `is` vs. `should` array matching mode; `:first`, or `:all`. + # + # @comment there are two blank chars after the symbols to cause a break - do not remove these. + # * `:first` + # This is primarily used for single value properties. When matched against an array of values + # a match is true if the `is` value matches any of the values in the `should` array. When the `is` value + # is also an array, the matching is performed against the entire array as the `is` value. + # * `:all` + # : This is primarily used for multi-valued properties. When matched against an array of + # `should` values, the size of `is` and `should` must be the same, and all values in `is` must match + # a value in `should`. + # + # @note The semantics of these modes are implemented by the method {#insync?}. That method is the default + # implementation and it has a backwards compatible behavior that imposes additional constraints + # on what constitutes a positive match. A derived property may override that method. + # @return [Symbol] (:first) the mode in which matching is performed + # @see #insync? + # @dsl type + # @api public + # def array_matching @array_matching ||= :first end - # Set whether properties should match all values or just the first one. + # @comment This is documented as an attribute - see the {array_matching} method. + # 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) @@ -32,33 +103,56 @@ class Puppet::Property < Puppet::Parameter end end - # Look up a value's name, so we can find options and such. + # Looks up a value's name among valid values, to enable option lookup with result as a key. + # @param name [Object] the parameter value to match against valid values (names). + # @return {Symbol, Regexp} a value matching predicate + # @api private + # def self.value_name(name) if value = value_collection.match?(name) value.name end end - # Retrieve an option set when a value was defined. + # Returns the value of the given option (set when a valid value with the given "name" was defined). + # @param name [Symbol, Regexp] the valid value predicate as returned by {value_name} + # @param option [Symbol] the name of the wanted option + # @return [Object] value of the option + # @raise [NoMethodError] if the option is not supported + # @todo Guessing on result of passing a non supported option (it performs send(option)). + # @api private + # 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. + # Defines a new valid value for this property. + # A valid value is specified as a literal (typically a Symbol), but can also be + # specified with a Regexp. # - # 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). + # @param name [Symbol, Regexp] a valid literal value, or a regexp that matches a value + # @param options [Hash] a hash with options + # @option options [Symbol] :event The event that should be emitted when this value is set. + # @todo Option :event original comment says "event should be returned...", is "returned" the correct word + # to use? + # @option options [Symbol] :call When to call any associated block. The default value is `:instead` which + # means that the block should be called instead of the provider. In earlier versions (before 20081031) it + # was possible to specify a value of `:before` or `:after` for the purpose of calling + # both the block and the provider. Use of these deprecated options will now raise an exception later + # in the process when the _is_ value is set (see #set). + # @option options [Object] any Any other option is treated as a call to a setter having the given + # option name (e.g. `:required_features` calls `required_features=` with the option's value as an + # argument). + # @todo The original documentation states that the option `:method` will set the name of the generated + # setter method, but this is not implemented. Is the documentatin or the implementation in error? + # (The implementation is in Puppet::Parameter::ValueCollection#new_value). + # @todo verify that the use of :before and :after have been deprecated (or rather - never worked, and + # was never in use. (This means, that the option :call could be removed since calls are always :instead). + # + # @dsl type + # @api public def self.newvalue(name, options = {}, &block) value = value_collection.newvalue(name, options, &block) @@ -66,7 +160,12 @@ class Puppet::Property < Puppet::Parameter value end - # Call the provider method. + # Calls the provider setter method for this property with the given value as argument. + # @return [Object] what the provider returns when calling a setter for this property's name + # @raise [Puppet::Error] when the provider can not handle this property. + # @see #set + # @api private + # def call_provider(value) method = self.class.name.to_s + "=" unless provider.respond_to? method @@ -75,8 +174,19 @@ class Puppet::Property < Puppet::Parameter provider.send(method, value) end - # Call the dynamically-created method associated with our value, if - # there is one. + # Sets the value of this property to the given value by calling the dynamically created setter method associated with the "valid value" referenced by the given name. + # @param name [Symbol, Regexp] a valid value "name" as returned by {value_name} + # @param value [Object] the value to set as the value of the property + # @raise [Puppet::DevError] if there was no method to call + # @raise [Puppet::Error] if there were problems setting the value + # @raise [Puppet::ResourceError] if there was a problem setting the value and it was not raised + # as a Puppet::Error. The original exception is wrapped and logged. + # @todo The check for a valid value option called `:method` does not seem to be fully supported + # as it seems that this option is never consulted when the method is dynamically created. Needs to + # be investigated. (Bug, or documentation needs to be changed). + # @see #set + # @api private + # def call_valuemethod(name, value) if method = self.class.value_option(name, :method) and self.respond_to?(method) begin @@ -98,7 +208,11 @@ class Puppet::Property < Puppet::Parameter end end - # How should a property change be printed as a string? + # Formats a message for a property change from the given `current_value` to the given `newvalue`. + # @return [String] a message describing the property change. + # @note If called with equal values, this is reported as a change. + # @raise [Puppet::DevError] if there were issues formatting the message + # def change_to_s(current_value, newvalue) begin if current_value == :absent @@ -117,7 +231,12 @@ class Puppet::Property < Puppet::Parameter end end - # Figure out which event to return. + # Produces the name of the event to use to describe a change of this property's value. + # The produced event name is either the event name configured for this property, or a generic + # event based on the name of the property with suffix `_changed`, or if the property is + # `:ensure`, the name of the resource type and one of the suffixes `_created`, `_removed`, or `_changed`. + # @return [String] the name of the event that describes the change + # def event_name value = self.should @@ -133,14 +252,35 @@ class Puppet::Property < Puppet::Parameter end).to_sym end - # Return a modified form of the resource event. + # Produces an event describing a change of this property. + # In addition to the event attributes set by the resource type, this method adds: + # + # * `:name` - the event_name + # * `:desired_value` - a.k.a _should_ or _wanted value_ + # * `:property` - reference to this property + # * `:source_description` - the _path_ (?? See todo) + # + # @todo What is the intent of this method? What is the meaning of the :source_description passed in the + # options to the created event? + # @return [Puppet::Transaction::Event] the created event + # @see Puppet::Type#event def event resource.event :name => event_name, :desired_value => should, :property => self, :source_description => path end + # @todo What is this? + # What is this used for? attr_reader :shadow - # initialize our property + # Initializes a Property the same way as a Parameter and handles the special case when a property is shadowing a meta-parameter. + # @todo There is some special initialization when a property is not a metaparameter but + # Puppet::Type.metaparamclass(for this class's name) is not nil - if that is the case a + # setup_shadow is performed for that class. + # + # @param hash [Hash] options passed to the super initializer {Puppet::Parameter#initialize} + # @note New properties of a type should be created via the DSL method {Puppet::Type.newproperty}. + # @see Puppet::Parameter#initialize description of Parameter initialize options. + # @api private def initialize(hash = {}) super @@ -149,14 +289,14 @@ class Puppet::Property < Puppet::Parameter 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. + # Determines whether the property is in-sync or not in a way that is protected against missing value. + # @note If the wanted value _(should)_ is not defined or is set to a non-true value then this is + # a state that can not be fixed and the property is reported to be in sync. + # @return [Boolean] the protected result of `true` or the result of calling {#insync?}. + # + # @api private + # @note Do not override this method. # - # Don't override this method. def safe_insync?(is) # If there is no @should value, consider the property to be in sync. return true unless @should @@ -165,15 +305,34 @@ class Puppet::Property < Puppet::Parameter insync?(is) end + # Protects against override of the {#safe_insync?} method. + # @raise [RuntimeError] if the added method is `:safe_insync?` + # @api private + # def self.method_added(sym) raise "Puppet::Property#safe_insync? shouldn't be overridden; please override insync? instead" if sym == :safe_insync? end - # This method may be overridden by derived classes if necessary - # to provide extra logic to determine whether the property is in - # sync. In most cases, however, only `property_matches?` needs to be - # overridden to give the correct outcome - without reproducing all the array - # matching logic, etc, found here. + # Checks if the current _(is)_ value is in sync with the wanted _(should)_ value. + # The check if the two values are in sync is controlled by the result of {#match_all?} which + # specifies a match of `:first` or `:all`). The matching of the _is_ value against the entire _should_ value + # or each of the _should_ values (as controlled by {#match_all?} is performed by {#property_matches?}. + # + # A derived property typically only needs to override the {#property_matches?} method, but may also + # override this method if there is a need to have more control over the array matching logic. + # + # @note The array matching logic in this method contains backwards compatible logic that performs the + # comparison in `:all` mode by checking equality and equality of _is_ against _should_ converted to array of String, + # and that the lengths are equal, and in `:first` mode by checking if one of the _should_ values + # is included in the _is_ values. This means that the _is_ value needs to be carefully arranged to + # match the _should_. + # @todo The implementation should really do return is.zip(@should).all? {|a, b| property_matches?(a, b) } + # instead of using equality check and then check against an array with converted strings. + # @param is [Object] The current _(is)_ value to check if it is in sync with the wanted _(should)_ value(s) + # @return [Boolean] whether the values are in sync or not. + # @raise [Puppet::DevError] if wanted value _(should)_ is not an array. + # @api public + # def insync?(is) self.devfail "#{self.class.name}'s should is not array" unless @should.is_a?(Array) @@ -211,10 +370,16 @@ class Puppet::Property < Puppet::Parameter end end - # Compare the current and desired value of a property in a property-specific - # way. Invoked by `insync?`; this should be overridden if your property - # has a different comparison type but does not actually differentiate the - # overall insync? logic. + # Checks if the given current and desired values are equal. + # This default implementation performs this check in a backwards compatible way where + # the equality of the two values is checked, and then the equality of current with desired + # converted to a string. + # + # A derived implementation may override this method to perform a property specific equality check. + # + # The intent of this method is to provide an equality check suitable for checking if the property + # value is in sync or not. It is typically called from {#insync?}. + # def property_matches?(current, desired) # This preserves the older Puppet behaviour of doing raw and string # equality comparisons for all equality. I am not clear this is globally @@ -222,15 +387,20 @@ class Puppet::Property < Puppet::Parameter current == desired or current == desired.to_s 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 + # Produces a pretty printing string for the given value. + # This default implementation simply returns the given argument. A derived implementation + # may perform property specific pretty printing when the _is_ and _should_ values are not + # already in suitable form. + # @return [String] a pretty printing string def is_to_s(currentvalue) currentvalue end - # Send a log message. + # Emits a log message at the log level specified for the associated resource. + # The log entry is associated with this property. + # @param msg [String] the message to log + # @return [void] + # def log(msg) Puppet::Util::Log.create( :level => resource[:loglevel], @@ -239,27 +409,36 @@ class Puppet::Property < Puppet::Parameter ) end - # Should we match all values, or just the first? + # @return [Boolean] whether the {array_matching} mode is set to `:all` or not def match_all? self.class.array_matching == :all end - # Execute our shadow's munge code, too, if we have one. + # (see Puppet::Parameter#munge) + # If this property is a meta-parameter shadow, the shadow's munge is also called. + # @todo Incomprehensible ! The concept of "meta-parameter-shadowing" needs to be explained. + # 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 + # @return [Symbol] the name of the property as stated when the property was created. + # @note A property class (just like a parameter class) describes one specific property and + # can only be used once within one type's inheritance chain. def name self.class.name end - # for testing whether we should actually do anything + # @return [Boolean] whether this property is in noop mode or not. + # Returns whether this property is in noop mode or not; if a difference between the + # _is_ and _should_ values should be acted on or not. + # The noop mode is a transitive setting. The mode is checked in this property, then in + # the _associated resource_ and finally in Puppet[:noop]. + # @todo This logic is different than Parameter#noop in that the resource noop mode overrides + # the property's mode - in parameter it is the other way around. Bug or feature? + # def noop # This is only here to make testing easier. if @resource.respond_to?(:noop?) @@ -273,14 +452,33 @@ class Puppet::Property < Puppet::Parameter 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. + # Retrieves the current value _(is)_ of this property from the provider. + # This implementation performs this operation by calling a provider method with the + # same name as this property (i.e. if the property name is 'gid', a call to the + # 'provider.gid' is expected to return the current value. + # @return [Object] what the provider returns as the current value of the property + # def retrieve provider.send(self.class.name) end - # Set our value, using the provider, an associated block, or both. + # Sets the current _(is)_ value of this property. + # The value is set using the provider's setter method for this property ({#call_provider}) if nothing + # else has been specified. If the _valid value_ for the given value defines a `:call` option with the + # value `:instead`, the + # value is set with {#call_valuemethod} which invokes a block specified for the valid value. + # + # @note In older versions (before 20081031) it was possible to specify the call types `:before` and `:after` + # which had the effect that both the provider method and the _valid value_ block were called. + # This is no longer supported. + # + # @param value [Object] the value to set as the value of this property + # @return [Object] returns what {#call_valuemethod} or {#call_provider} returns + # @raise [Puppet::Error] when the provider setter should be used but there is no provider set in the _associated + # resource_ + # @raise [Puppet::DevError] when a deprecated call form was specified (e.g. `:before` or `:after`). + # @api public + # def set(value) # Set a name for looking up associated options like the event. name = self.class.value_name(value) @@ -305,15 +503,29 @@ class Puppet::Property < Puppet::Parameter end 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. + # Sets up a shadow property for a shadowing meta-parameter. + # This construct allows the creation of a property with the + # same name as a meta-parameter. The metaparam will only be stored as a shadow. + # @param klass [Class<inherits Puppet::Parameter>] the class of the shadowed meta-parameter + # @return [Puppet::Parameter] an instance of the given class (a parameter or property) + # def setup_shadow(klass) @shadow = klass.new(:resource => self.resource) end - # Only return the first value + # Returns the wanted _(should)_ value of this property. + # If the _array matching mode_ {#match_all?} is true, an array of the wanted values in unmunged format + # is returned, else the first value in the array of wanted values in unmunged format is returned. + # @return [Array<Object>, Object, nil] Array of values if {#match_all?} else a single value, or nil if there are no + # wanted values. + # @raise [Puppet::DevError] if the wanted value is non nil and not an array + # + # @note This method will potentially return different values than the original values as they are + # converted via munging/unmunging. If the original values are wanted, call {#shouldorig}. + # + # @see #shouldorig + # @api public + # def should return nil unless defined?(@should) @@ -326,7 +538,14 @@ class Puppet::Property < Puppet::Parameter end end - # Set the should value. + # Sets the wanted _(should)_ value of this property. + # If the given value is not already an Array, it will be wrapped in one before being set. + # This method also sets the cached original _should_ values returned by {#shouldorig}. + # + # @param values [Array<Object>, Object] the value(s) to set as the wanted value(s) + # @raise [StandardError] when validation of a value fails (see {#validate}). + # @api public + # def should=(values) values = [values] unless values.is_a?(Array) @@ -336,23 +555,39 @@ class Puppet::Property < Puppet::Parameter @should = values.collect { |val| self.munge(val) } end + # Formats the given newvalue (following _should_ type conventions) for inclusion in a string describing a change. + # @return [String] Returns the given newvalue in string form with space separated entries if it is an array. + # @see #change_to_s + # def should_to_s(newvalue) [newvalue].flatten.join(" ") end + # Synchronizes the current value _(is)_ and the wanted value _(should)_ by calling {#set}. + # @raise [Puppet::DevError] if {#should} is nil + # @todo The implementation of this method is somewhat inefficient as it computes the should + # array twice. def sync devfail "Got a nil value for should" unless should set(should) end - # Verify that the passed value is valid. + # Asserts that the given value is valid. # If the developer uses a 'validate' hook, this method will get overridden. + # @raise [Exception] if the value is invalid, or value can not be handled. + # @return [void] + # @api private + # 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. + # Asserts that all required provider features are present for the given property value. + # @raise [ArgumentError] if a required feature is not present + # @return [void] + # @api private + # def validate_features_per_value(value) if features = self.class.value_option(self.class.value_name(value), :required_features) features = Array(features) @@ -361,13 +596,12 @@ class Puppet::Property < Puppet::Parameter end end - # Just return any should value we might have. + # @return [Object, nil] Returns the wanted _(should)_ value of this property. 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. + # (see #should=) def value=(value) self.should = value end diff --git a/lib/puppet/property/ensure.rb b/lib/puppet/property/ensure.rb index 8b97ddeab..3c9f98d85 100644 --- a/lib/puppet/property/ensure.rb +++ b/lib/puppet/property/ensure.rb @@ -1,7 +1,12 @@ require 'puppet/property' -# This property will get automatically added to any type that responds +# This property is automatically added to any {Puppet::Type} that responds # to the methods 'exists?', 'create', and 'destroy'. +# +# Ensure defaults to having the wanted _(should)_ value `:present`. +# +# @api public +# class Puppet::Property::Ensure < Puppet::Property @name = :ensure @@ -58,6 +63,14 @@ class Puppet::Property::Ensure < Puppet::Property end end + # Retrieves the _is_ value for the ensure property. + # The existence of the resource is checked by first consulting the provider (if it responds to + # `:exists`), and secondly the resource. A a value of `:present` or `:absent` is returned + # depending on if the managed entity exists or not. + # + # @return [Symbol] a value of `:present` or `:absent` depending on if it exists or not + # @raise [Puppet::DevError] if neither the provider nor the resource responds to `:exists` + # 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 diff --git a/lib/puppet/property/keyvalue.rb b/lib/puppet/property/keyvalue.rb index 57d0ea2d9..8184b77b3 100644 --- a/lib/puppet/property/keyvalue.rb +++ b/lib/puppet/property/keyvalue.rb @@ -1,15 +1,16 @@ -#This subclass of property manages string key value pairs. - -#In order to use this property: -# - the @should value must be an array of keyvalue pairs separated by the 'separator' -# - the retrieve method should return a hash with the keys as symbols -# IMPORTANT NOTE: In order for this property to work there must also be a 'membership' parameter -# The class that inherits from property should override that method with the symbol for the membership - require 'puppet/property' module Puppet class Property + # This subclass of {Puppet::Property} manages string key value pairs. + # In order to use this property: + # + # * the _should_ value must be an array of key-value pairs separated by the 'separator' + # * the retrieve method should return a hash with the keys as symbols + # @note **IMPORTANT**: In order for this property to work there must also be a 'membership' parameter + # The class that inherits from property should override that method with the symbol for the membership + # @todo The node with an important message is not very clear. + # class KeyValue < Property def hash_to_key_value_s(hash) @@ -59,14 +60,19 @@ module Puppet current.merge(members) end + # @return [String] Returns a default separator of "=" def separator "=" end + # @return [String] Returns a default delimiter of ";" def delimiter ";" end + # Retrieves the key-hash from the provider by invoking it's method named the same as this property. + # @return [Hash] the hash from the provider, or `:absent` + # 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 @@ -76,6 +82,9 @@ module Puppet end end + # Returns true if there is no _is_ value, else returns if _is_ is equal to _should_ using == as comparison. + # @return [Boolean] whether the property is in sync or not. + # def insync?(is) return true unless is diff --git a/lib/puppet/property/list.rb b/lib/puppet/property/list.rb index b86dc87f2..ed0566bdd 100644 --- a/lib/puppet/property/list.rb +++ b/lib/puppet/property/list.rb @@ -2,6 +2,9 @@ require 'puppet/property' module Puppet class Property + # This subclass of {Puppet::Property} manages an unordered list of values. + # For an ordered list see {Puppet::Property::OrderedList}. + # class List < Property def should_to_s(should_value) diff --git a/lib/puppet/property/ordered_list.rb b/lib/puppet/property/ordered_list.rb index 7408b3019..65cd16953 100644 --- a/lib/puppet/property/ordered_list.rb +++ b/lib/puppet/property/ordered_list.rb @@ -2,6 +2,13 @@ require 'puppet/property/list' module Puppet class Property + # This subclass of {Puppet::Property} manages an ordered list of values. + # The maintained order is the order defined by the 'current' set of values (i.e. the + # original order is not disrupted). Any additions are added after the current values + # in their given order). + # + # For an unordered list see {Puppet::Property::List}. + # class OrderedList < List def add_should_with_current(should, current) diff --git a/lib/puppet/provider.rb b/lib/puppet/provider.rb index a8d2d3f90..5edebb53e 100644 --- a/lib/puppet/provider.rb +++ b/lib/puppet/provider.rb @@ -1,4 +1,40 @@ -# The container class for implementations. +# A Provider is an implementation of the actions that manage resources (of some type) on a system. +# This class is the base class for all implementation of a Puppet Provider. +# +# Concepts: +#-- +# * **Confinement** - confinement restricts providers to only be applicable under certain conditions. +# It is possible to confine a provider several different ways: +# * the included {#confine} method which provides filtering on fact, feature, existence of files, or a free form +# predicate. +# * the {commands} method that filters on the availability of given system commands. +# * **Property hash** - the important instance variable `@property_hash` contains all current state values +# for properties (it is lazily built). It is important that these values are managed appropriately in the +# methods {instances}, {prefetch}, and in methods that alters the current state (those that change the +# lifecycle (creates, destroys), or alters some value reflected backed by a property). +# * **Flush** - is a hook that is called once per resource when everything has been applied. The intent is +# that an implementation may defer modification of the current state typically done in property setters +# and instead record information that allows flush to perform the changes more efficiently. +# * **Execution Methods** - The execution methods provides access to execution of arbitrary commands. +# As a convenience execution methods are available on both the instance and the class of a provider since a +# lot of provider logic switch between these contexts fairly freely. +# * **System Entity/Resource** - this documentation uses the term "system entity" for system resources to make +# it clear if talking about a resource on the system being managed (e.g. a file in the file system) +# or about a description of such a resource (e.g. a Puppet Resource). +# * **Resource Type** - this is an instance of Type that describes a classification of instances of Resource (e.g. +# the `File` resource type describes all instances of `file` resources). +# (The term is used to contrast with "type" in general, and specifically to contrast with the implementation +# class of Resource or a specific Type). +# +# @note An instance of a Provider is associated with one resource. +# +# @note Class level methods are only called once to configure the provider (when the type is created), and not +# for each resource the provider is operating on. +# The instance methods are however called for each resource. +# +# +# @api public +# class Puppet::Provider include Puppet::Util include Puppet::Util::Errors @@ -16,53 +52,105 @@ class Puppet::Provider # Include the util module so we have access to things like 'which' include Puppet::Util, Puppet::Util::Docs include Puppet::Util::Logging + + # @return [String] The name of the provider 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. + # + # @todo Original = _"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."_ This seems to be a package type specific attribute. Is this really + # used? + # + # @return [???] The source is WHAT? attr_writer :source - # LAK 2007-05-09: Keep the model stuff around for backward compatibility + # @todo Original = _"LAK 2007-05-09: Keep the model stuff around for backward compatibility"_ + # Is this really needed? The comment about backwards compatibility was made in 2007. + # + # @return [???] A model kept for backwards compatibility. + # @api private + # @deprecated This attribute is available for backwards compatibility reasons. attr_reader :model + + # @todo What is this type? A reference to a Puppet::Type ? + # @return [Puppet::Type] the resource type (that this provider is ... WHAT?) + # attr_accessor :resource_type + + # @!attribute [r] doc + # The (full) documentation for this provider class. The documentation for the provider class itself + # should be set with the DSL method {desc=}. Setting the documentation with with {doc=} has the same effect + # as setting it with {desc=} (only the class documentation part is set). In essence this means that + # there is no getter for the class documentation part (since the getter returns the full + # documentation when there are additional contributors). + # + # @return [String] Returns the full documentation for the provider. + # @see Puppet::Utils::Docs + # @comment This is puzzling ... a write only doc attribute??? The generated setter never seems to be + # used, instead the instance variable @doc is set in the `desc` method. This seems wrong. It is instead + # documented as a read only attribute (to get the full documentation). Also see doc below for + # desc. + # @!attribute [w] desc + # Sets the documentation of this provider class. (The full documentation is read via the + # {doc} attribute). + # + # @dsl type + # + # attr_writer :doc + end - # LAK 2007-05-09: Keep the model stuff around for backward compatibility + # @todo original = _"LAK 2007-05-09: Keep the model stuff around for backward compatibility"_, why is it + # both here (instance) and at class level? Is this a different model? + # @return [???] model is WHAT? attr_reader :model + + # @return [???] This resource is what? Is an instance of a provider attached to one particular Puppet::Resource? + # attr_accessor :resource - # Provide access to execution of arbitrary commands in providers. Execution methods are - # available on both the instance and the class of a provider because it seems that a lot of - # providers switch between these contexts fairly freely. - # - # @see Puppet::Util::Execution for how to use these methods + # Convenience methods - see class method with the same name. + # @see execute + # @return (see execute) def execute(*args) Puppet::Util::Execution.execute(*args) end + # (see Puppet::Util::Execution.execute) def self.execute(*args) Puppet::Util::Execution.execute(*args) end + # Convenience methods - see class method with the same name. + # @see execpipe + # @return (see execpipe) def execpipe(*args, &block) Puppet::Util::Execution.execpipe(*args, &block) end + # (see Puppet::Util::Execution.execpipe) def self.execpipe(*args, &block) Puppet::Util::Execution.execpipe(*args, &block) end + # Convenience methods - see class method with the same name. + # @see execfail + # @return (see execfail) def execfail(*args) Puppet::Util::Execution.execfail(*args) end + # (see Puppet::Util::Execution.execfail) def self.execfail(*args) Puppet::Util::Execution.execfail(*args) end - ######### + # Returns the absolute path to the executable for the command referenced by the given name. + # @raise [Puppet::DevError] if the name does not reference an existing command. + # @return [String] the absolute path to the found executable for the command + # @see which def self.command(name) name = name.intern @@ -77,22 +165,33 @@ class Puppet::Provider which(command) end - # Define commands that are not optional. + # Confines this provider to be suitable only on hosts where the given commands are present. + # Also see {Puppet::Provider::Confiner#confine} for other types of confinement of a provider by use of other types of + # predicates. + # + # @note It is preferred if the commands are not entered with absolute paths as this allows puppet + # to search for them using the PATH variable. # - # @param [Hash{String => String}] command_specs Named commands that the provider will + # @param command_specs [Hash{String => String}] Map of name to command that the provider will # be executing on the system. Each command is specified with a name and the path of the executable. - # (@see #has_command) + # @return [void] + # @see optional_commands + # def self.commands(command_specs) command_specs.each do |name, path| has_command(name, path) end end - # Define commands that are optional. - # + # Defines optional commands. + # Since Puppet 2.7.8 this is typically not needed as evaluation of provider suitability + # is lazy (when a resource is evaluated) and the absence of commands + # that will be present after other resources have been applied no longer needs to be specified as + # optional. # @param [Hash{String => String}] command_specs Named commands that the provider will # be executing on the system. Each command is specified with a name and the path of the executable. # (@see #has_command) + # @see commands def self.optional_commands(hash) hash.each do |name, target| has_command(name, target) do @@ -101,27 +200,31 @@ class Puppet::Provider end end - # Define a single command - # - # A method will be generated on the provider that allows easy execution of the command. The generated - # method can take arguments that will be passed through to the executable as the command line arguments - # when it is run. + # Creates a convenience method for invocation of a command. # - # has_command(:echo, "/bin/echo") - # def some_method - # echo("arg 1", "arg 2") - # end + # This generates a Provider method that allows easy execution of the command. The generated + # method may take arguments that will be passed through to the executable as the command line arguments + # when it is invoked. # - # # or + # @example Use it like this: + # has_command(:echo, "/bin/echo") + # def some_method + # echo("arg 1", "arg 2") + # end + # @comment the . . . below is intentional to avoid the three dots to become an illegible ellipsis char. + # @example . . . or like this + # has_command(:echo, "/bin/echo") do + # is_optional + # environment :HOME => "/var/tmp", :PWD => "/tmp" + # end # - # has_command(:echo, "/bin/echo") do - # is_optional - # environment :HOME => "/var/tmp", :PWD => "/tmp" - # end + # @param name [Symbol] The name of the command (will become the name of the generated method that executes the command) + # @param path [String] The path to the executable for the command + # @yield [ ] A block that configures the command (see {Puppet::Provider::Command}) + # @comment a yield [ ] produces {|| ...} in the signature, do not remove the space. + # @note the name ´has_command´ looks odd in an API context, but makes more sense when seen in the internal + # DSL context where a Provider is declaratively defined. # - # @param [Symbol] name Name of the command (will be the name of the generated method to call the command) - # @param [String] path The path to the executable for the command - # @yield A block that configures the command (@see Puppet::Provider::Command) def self.has_command(name, path, &block) name = name.intern command = CommandDefiner.define(name, path, self, &block) @@ -134,6 +237,8 @@ class Puppet::Provider end end + # Internal helper class when creating commands - undocumented. + # @api private class CommandDefiner private_class_method :new @@ -168,13 +273,15 @@ class Puppet::Provider end end - # Is the provided feature a declared feature? + # @return [Boolean] Return whether the given feature has been declared or not. 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. + # @return [Boolean] Returns whether this implementation satisfies all of the default requirements or not. + # Returns false If defaults are empty. + # @see Provider.defaultfor + # def self.default? return false if @defaults.empty? if @defaults.find do |fact, values| @@ -198,31 +305,79 @@ class Puppet::Provider end end - # Store how to determine defaults. + # Sets a facts filter that determine which of several suitable providers should be picked by default. + # This selection only kicks in if there is more than one suitable provider. + # To filter on multiple facts the given hash may contain more than one fact name/value entry. + # The filter picks the provider if all the fact/value entries match the current set of facts. (In case + # there are still more than one provider after this filtering, the first found is picked). + # @param hash [Hash<{String => Object}>] hash of fact name to fact value. + # @return [void] + # def self.defaultfor(hash) hash.each do |d,v| @defaults[d] = v end end + # @return [Integer] Returns a numeric specificity for this provider based on how many requirements it has + # and number of _ancestors_. The higher the number the more specific the provider. + # The number of requirements is based on the number of defaults set up with {Provider.defaultfor}. + # + # The _ancestors_ is the Ruby Module::ancestors method and the number of classes returned is used + # to boost the score. The intent is that if two providers are equal, but one is more "derived" than the other + # (i.e. includes more classes), it should win because it is more specific). + # @note Because of how this value is + # calculated there could be surprising side effects if a provider included an excessive amount of classes. + # def self.specificity + # This strange piece of logic attempts to figure out how many parent providers there + # are to increase the score. What is will actually do is count all classes that Ruby Module::ancestors + # returns (which can be other classes than those the parent chain) - in a way, an odd measure of the + # complexity of a provider). (@defaults.length * 100) + ancestors.select { |a| a.is_a? Class }.length end + # Initializes defaults and commands (i.e. clears them). + # @return [void] 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. + # Returns a list of system resources (entities) this provider may/can manage. + # This is a query mechanism that lists entities that the provider may manage on a given system. It is + # is directly used in query services, but is also the foundation for other services; prefetching, and + # purging. + # + # As an example, a package provider lists all installed packages. (In contrast, the File provider does + # not list all files on the file-system as that would make execution incredibly slow). An implementation + # of this method should be made if it is possible to quickly (with a single system call) provide all + # instances. + # + # An implementation of this method should only cache the values of properties + # if they are discovered as part of the process for finding existing resources. + # Resource properties that require additional commands (than those used to determine existence/identity) + # should be implemented in their respective getter method. (This is important from a performance perspective; + # it may be expensive to compute, as well as wasteful as all discovered resources may perhaps not be managed). + # + # An implementation may return an empty list (naturally with the effect that it is not possible to query + # for manageable entities). + # + # By implementing this method, it is possible to use the `resources´ resource type to specify purging + # of all non managed entities. + # + # @note The returned instances are instance of some subclass of Provider, not resources. + # @return [Array<Puppet::Provider>] a list of providers referencing the system entities + # @abstract this method must be implemented by a subclass and this super method should never be called as it raises an exception. + # @raise [Puppet::DevError] Error indicating that the method should have been implemented by subclass. + # @see prefetch def self.instances raise Puppet::DevError, "Provider #{self.name} has not defined the 'instances' class method" end - # Create the methods for a given command. - # - # @deprecated Use {#commands}, {#optional_commands}, or {#has_command} instead. This was not meant to be part of a public API + # Creates the methods for a given command. + # @api private + # @deprecated Use {commands}, {optional_commands}, or {has_command} instead. This was not meant to be part of a public API def self.make_command_methods(name) Puppet.deprecation_warning "Provider.make_command_methods is deprecated; use Provider.commands or Provider.optional_commands instead for creating command methods" @@ -245,9 +400,19 @@ class Puppet::Provider 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. + # Creates getter- and setter- methods for each property supported by the resource type. + # Call this method to generate simple accessors for all properties supported by the + # resource type. These simple accessors lookup and sets values in the property hash. + # The generated methods may be overridden by more advanced implementations if something + # else than a straight forward getter/setter pair of methods is required. + # (i.e. define such overriding methods after this method has been called) + # + # An implementor of a provider that makes use of `prefetch` and `flush` can use this method since it uses + # the internal `@property_hash` variable to store values. An implementation would then update the system + # state on a call to `flush` based on the current values in the `@property_hash`. + # + # @return [void] + # def self.mk_resource_methods [resource_type.validproperties, resource_type.parameters].flatten.each do |attr| attr = attr.intern @@ -264,6 +429,10 @@ class Puppet::Provider self.initvars + # This method is used to generate a method for a command. + # @return [void] + # @api private + # def self.create_class_and_instance_method(name, &block) unless singleton_class.method_defined?(name) meta_def(name, &block) @@ -277,12 +446,20 @@ class Puppet::Provider end private_class_method :create_class_and_instance_method - # Retrieve the data source. Defaults to the provider name. + # @return [String] Returns the data source, which is the provider name if no other source has been set. + # @todo Unclear what "the source" is used for? def self.source @source ||= self.name end - # Does this provider support the specified parameter? + # Returns true if the given attribute/parameter is supported by the provider. + # The check is made that the parameter is a valid parameter for the resource type, and then + # if all its required features (if any) are supported by the provider. + # + # @param param [Class, Puppet::Parameter] the parameter class, or a parameter instance + # @return [Boolean] Returns whether this provider supports the given parameter or not. + # @raise [Puppet::DevError] if the given parameter is not valid for the resource type + # def self.supports_parameter?(param) if param.is_a?(Class) klass = param @@ -331,22 +508,34 @@ class Puppet::Provider end end - # Remove the reference to the resource, so GC can clean up. + # Clears this provider instance to allow GC to clean up. def clear @resource = nil @model = nil end - # Retrieve a named command. + # (see command) def command(name) self.class.command(name) end - # Get a parameter value. + # Returns the value of a parameter value, or `:absent` if it is not defined. + # @param param [Puppet::Parameter] the parameter to obtain the value of + # @return [Object] the value of the parameter or `:absent` if not defined. + # def get(param) @property_hash[param.intern] || :absent end + # Creates a new provider that is optionally initialized from a resource or a hash of properties. + # If no argument is specified, a new non specific provider is initialized. If a resource is given + # it is remembered for further operations. If a hash is used it becomes the internal `@property_hash` + # structure of the provider - this hash holds the current state property values of system entities + # as they are being discovered by querying or other operations (typically getters). + # + # @todo The use of a hash as a parameter needs a better exaplanation; why is this done? What is the intent? + # @param resource [Puppet::Resource, Hash] optional resource or hash + # def initialize(resource = nil) if resource.is_a?(Hash) # We don't use a duplicate here, because some providers (ParsedFile, at least) @@ -362,6 +551,10 @@ class Puppet::Provider end end + # Returns the name of the resource this provider is operating on. + # @return [String] the name of the resource instance (e.g. the file path of a File). + # @raise [Puppet::DevError] if no resource is set, or no name defined. + # def name if n = @property_hash[:name] return n @@ -372,24 +565,53 @@ class Puppet::Provider end end - # Set passed params as the current values. + # Sets the given parameters values as the current values for those parameters. + # Other parameters are unchanged. + # @param [Array<Puppet::Parameter] the parameters with values that should be set + # @return [void] + # def set(params) params.each do |param, value| @property_hash[param.intern] = value end end + # @return [String] Returns a human readable string with information about the resource and the provider. def to_s "#{@resource}(provider=#{self.class.name})" end - # Make providers comparable. + # Makes providers comparable. include Comparable + # Compares this provider against another provider. + # Comparison is only possible with another provider (no other class). + # The ordering is based on the class name of the two providers. + # + # @return [-1,0,+1, nil] A comparison result -1, 0, +1 if this is before other, equal or after other. Returns + # nil oif not comparable to other. + # @see Comparable def <=>(other) # We can only have ordering against other providers. return nil unless other.is_a? Puppet::Provider # Otherwise, order by the providers class name. return self.class.name <=> other.class.name end + + # @comment Document prefetch here as it does not exist anywhere else (called from transaction if implemented) + # @!method self.prefetch(resource_hash) + # @abstract A subclass may implement this - it is not implemented in the Provider class + # This method may be implemented by a provider in order to pre-fetch resource properties. + # If implemented it should set the provider instance of the managed resources to a provider with the + # fetched state (i.e. what is returned from the {instances} method). + # @param resources_hash [Hash<{String => Puppet::Resource}>] map from name to resource of resources to prefetch + # @return [void] + + # @comment Document flush here as it does not exist anywhere (called from transaction if implemented) + # @!method flush() + # @abstract A subclass may implement this - it is not implemented in the Provider class + # This method may be implemented by a provider in order to flush properties that has not been individually + # applied to the managed entity's current state. + # @return [void] + end diff --git a/lib/puppet/provider/augeas/augeas.rb b/lib/puppet/provider/augeas/augeas.rb index a301c8cd7..bf73ee683 100644 --- a/lib/puppet/provider/augeas/augeas.rb +++ b/lib/puppet/provider/augeas/augeas.rb @@ -38,6 +38,7 @@ Puppet::Type.type(:augeas).provide(:augeas) do "setm" => [ :path, :string, :string ], "rm" => [ :path ], "clear" => [ :path ], + "clearm" => [ :path, :string ], "mv" => [ :path, :path ], "insert" => [ :string, :string, :path ], "get" => [ :path, :comparator, :string ], @@ -431,9 +432,13 @@ Puppet::Type.type(:augeas).provide(:augeas) do rv = aug.set(cmd_array[0], cmd_array[1]) fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) when "setm" - debug("sending command '#{command}' with params #{cmd_array.inspect}") - rv = aug.setm(cmd_array[0], cmd_array[1], cmd_array[2]) - fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) + if aug.respond_to?(command) + debug("sending command '#{command}' with params #{cmd_array.inspect}") + rv = aug.setm(cmd_array[0], cmd_array[1], cmd_array[2]) + fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (rv == -1) + else + fail("command '#{command}' not supported in installed version of ruby-augeas") + end when "rm", "remove" debug("sending command '#{command}' with params #{cmd_array.inspect}") rv = aug.rm(cmd_array[0]) @@ -442,6 +447,15 @@ Puppet::Type.type(:augeas).provide(:augeas) do 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 "clearm" + # Check command exists ... doesn't currently in ruby-augeas 0.4.1 + if aug.respond_to?(command) + debug("sending command '#{command}' with params #{cmd_array.inspect}") + rv = aug.clearm(cmd_array[0], cmd_array[1]) + fail("Error sending command '#{command}' with params #{cmd_array.inspect}") if (!rv) + else + fail("command '#{command}' not supported in installed version of ruby-augeas") + end when "insert", "ins" label = cmd_array[0] where = cmd_array[1] diff --git a/lib/puppet/provider/confiner.rb b/lib/puppet/provider/confiner.rb index 6e1fb23ab..63499e78c 100644 --- a/lib/puppet/provider/confiner.rb +++ b/lib/puppet/provider/confiner.rb @@ -1,15 +1,44 @@ require 'puppet/provider/confine_collection' +# The Confiner module contains methods for managing a Provider's confinement (suitability under given +# conditions). The intent is to include this module in an object where confinement management is wanted. +# It lazily adds an instance variable `@confine_collection` to the object where it is included. +# module Puppet::Provider::Confiner + # Confines a provider to be suitable only under the given conditions. + # The hash describes a confine using mapping from symbols to values or predicate code. + # + # * _fact_name_ => value of fact (or array of facts) + # * `:exists` => the path to an existing file + # * `:true` => a predicate code block returning true + # * `:false` => a predicate code block returning false + # * `:feature` => name of system feature that must be present + # + # @example + # confine :operatingsystem => [:redhat, :fedora] + # confine :true { ... } + # + # @param hash [Hash<{Symbol => Object}>] hash of confines + # @return [void] + # @api public + # def confine(hash) confine_collection.confine(hash) end + # @return [Puppet::Provider::ConfineCollection] the collection of confines + # @api private + # def confine_collection @confine_collection ||= Puppet::Provider::ConfineCollection.new(self.to_s) end - # Check whether this implementation is suitable for our platform. + # Checks whether this implementation is suitable for the current platform (or returns a summary + # of all confines if short == false). + # @return [Boolean. Hash] Returns whether the confines are all valid (if short == true), or a hash of all confines + # if short == false. + # @api public + # def suitable?(short = true) return(short ? confine_collection.valid? : confine_collection.summary) end diff --git a/lib/puppet/provider/group/pw.rb b/lib/puppet/provider/group/pw.rb index b6c74f766..4dd516880 100644 --- a/lib/puppet/provider/group/pw.rb +++ b/lib/puppet/provider/group/pw.rb @@ -1,12 +1,12 @@ require 'puppet/provider/nameservice/pw' Puppet::Type.type(:group).provide :pw, :parent => Puppet::Provider::NameService::PW do - desc "Group management via `pw` on FreeBSD." + desc "Group management via `pw` on FreeBSD and DragonFly BSD." commands :pw => "pw" has_features :manages_members - defaultfor :operatingsystem => :freebsd + defaultfor :operatingsystem => [:freebsd, :dragonfly] options :members, :flag => "-M", :method => :mem diff --git a/lib/puppet/provider/package/openbsd.rb b/lib/puppet/provider/package/openbsd.rb index 285edf36a..ab2b610a2 100755 --- a/lib/puppet/provider/package/openbsd.rb +++ b/lib/puppet/provider/package/openbsd.rb @@ -56,8 +56,22 @@ Puppet::Type.type(:package).provide :openbsd, :parent => Puppet::Provider::Packa should = @resource.should(:ensure) unless @resource[:source] - raise Puppet::Error, - "You must specify a package source for BSD packages" + if File.exist?("/etc/pkg.conf") + File.open("/etc/pkg.conf", "rb").readlines.each do |line| + if matchdata = line.match(/^installpath\s*=\s*(.+)\s*$/i) + @resource[:source] = matchdata[1] + break + end + end + + unless @resource[:source] + raise Puppet::Error, + "No valid installpath found in /etc/pkg.conf and no source was set" + end + else + raise Puppet::Error, + "You must specify a package source or configure an installpath in /etc/pkg.conf" + end end if @resource[:source][-1,1] == ::File::SEPARATOR diff --git a/lib/puppet/provider/package/pip.rb b/lib/puppet/provider/package/pip.rb index b6b608928..22762c293 100644 --- a/lib/puppet/provider/package/pip.rb +++ b/lib/puppet/provider/package/pip.rb @@ -25,7 +25,7 @@ Puppet::Type.type(:package).provide :pip, # that's managed by `pip` or an empty array if `pip` is not available. def self.instances packages = [] - pip_cmd = which('pip') or return [] + pip_cmd = which(cmd) or return [] execpipe "#{pip_cmd} freeze" do |process| process.collect do |line| next unless options = parse(line) @@ -35,6 +35,15 @@ Puppet::Type.type(:package).provide :pip, packages end + def self.cmd + case Facter.value(:osfamily) + when "RedHat" + "pip-python" + else + "pip" + end + end + # Return structured information about a particular package or `nil` if # it is not installed or `pip` itself is not available. def query @@ -64,7 +73,6 @@ Puppet::Type.type(:package).provide :pip, def install args = %w{install -q} if @resource[:source] - args << "-e" if String === @resource[:ensure] args << "#{@resource[:source]}@#{@resource[:ensure]}#egg=#{ @resource[:name]}" @@ -101,7 +109,7 @@ Puppet::Type.type(:package).provide :pip, def lazy_pip(*args) pip *args rescue NoMethodError => e - if pathname = which('pip') + if pathname = which(self.class.cmd) self.class.commands :pip => pathname pip *args else diff --git a/lib/puppet/provider/package/pkgin.rb b/lib/puppet/provider/package/pkgin.rb index 62cb8dadd..5061cd3c9 100644 --- a/lib/puppet/provider/package/pkgin.rb +++ b/lib/puppet/provider/package/pkgin.rb @@ -5,6 +5,8 @@ Puppet::Type.type(:package).provide :pkgin, :parent => Puppet::Provider::Package commands :pkgin => "pkgin" + defaultfor :operatingsystem => :dragonfly + has_feature :installable, :uninstallable def self.parse_pkgin_line(package, force_status=nil) diff --git a/lib/puppet/provider/package/portage.rb b/lib/puppet/provider/package/portage.rb index 8f9fb896a..b1fb5df84 100644 --- a/lib/puppet/provider/package/portage.rb +++ b/lib/puppet/provider/package/portage.rb @@ -13,19 +13,17 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa 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] - - version_format = "{last}<version>{}" - search_format = "<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>\n" + result_format = self.eix_result_format + result_fields = self.eix_result_fields + version_format = self.eix_version_format begin eix_file = File.directory?("/var/cache/eix") ? "/var/cache/eix/portage.eix" : "/var/cache/eix" update_eix if !FileUtils.uptodate?(eix_file, %w{/usr/bin/eix /usr/portage/metadata/timestamp}) search_output = nil Puppet::Util.withenv :LASTVERSION => version_format do - search_output = eix "--nocolor", "--pure-packages", "--stable", "--installed", "--format", search_format + search_output = eix *(self.eix_search_arguments + ["--installed"]) end packages = [] @@ -72,12 +70,10 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa 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" + result_format = self.class.eix_result_format + result_fields = self.class.eix_result_fields + version_format = self.class.eix_version_format search_field = package_name.count('/') > 0 ? "--category-name" : "--name" search_value = package_name @@ -87,7 +83,7 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa search_output = nil Puppet::Util.withenv :LASTVERSION => version_format do - search_output = eix "--nocolor", "--pure-packages", "--stable", "--format", search_format, "--exact", search_field, search_value + search_output = eix *(self.class.eix_search_arguments + ["--exact",search_field,search_value]) end packages = [] @@ -121,4 +117,25 @@ Puppet::Type.type(:package).provide :portage, :parent => Puppet::Provider::Packa def latest self.query[:version_available] end + + private + def self.eix_search_format + "'<category> <name> [<installedversions:LASTVERSION>] [<bestversion:LASTVERSION>] <homepage> <description>'" + end + + def self.eix_result_format + /^(\S+)\s+(\S+)\s+\[(\S*)\]\s+\[(\S*)\]\s+(\S+)\s+(.*)$/ + end + + def self.eix_result_fields + [:category, :name, :ensure, :version_available, :vendor, :description] + end + + def self.eix_version_format + "{last}<version>{}" + end + + def self.eix_search_arguments + ["--nocolor", "--pure-packages", "--format",self.eix_search_format] + end end diff --git a/lib/puppet/provider/service/bsd.rb b/lib/puppet/provider/service/bsd.rb index 5b73dfc64..85e7824fa 100644 --- a/lib/puppet/provider/service/bsd.rb +++ b/lib/puppet/provider/service/bsd.rb @@ -7,7 +7,7 @@ Puppet::Type.type(:service).provide :bsd, :parent => :init do EOT - confine :operatingsystem => [:freebsd, :netbsd, :openbsd] + confine :operatingsystem => [:freebsd, :netbsd, :openbsd, :dragonfly] def rcconf_dir '/etc/rc.conf.d' diff --git a/lib/puppet/provider/service/freebsd.rb b/lib/puppet/provider/service/freebsd.rb index 80a76eb12..43e0af646 100644 --- a/lib/puppet/provider/service/freebsd.rb +++ b/lib/puppet/provider/service/freebsd.rb @@ -1,9 +1,9 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do - desc "Provider for FreeBSD. Uses the `rcvar` argument of init scripts and parses/edits rc files." + desc "Provider for FreeBSD and DragonFly BSD. Uses the `rcvar` argument of init scripts and parses/edits rc files." - confine :operatingsystem => [:freebsd] - defaultfor :operatingsystem => [:freebsd] + confine :operatingsystem => [:freebsd, :dragonfly] + defaultfor :operatingsystem => [:freebsd, :dragonfly] def rcconf() '/etc/rc.conf' end def rcconf_local() '/etc/rc.conf.local' end @@ -13,6 +13,10 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do superclass.defpath end + def error(msg) + raise Puppet::Error, msg + end + # Executing an init script with the 'rcvar' argument returns # the service name, rcvar name and whether it's enabled/disabled def rcvar @@ -37,7 +41,7 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do def rcvar_name name = self.rcvar[1] self.error("No rcvar name found in rcvar") if name.nil? - name = name.gsub!(/(.*)_enable=(.*)/, '\1') + name = name.gsub!(/(.*)(_enable)?=(.*)/, '\1') self.error("rcvar name is empty") if name.nil? self.debug("rcvar name is #{name}") name @@ -47,7 +51,7 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do def rcvar_value value = self.rcvar[1] self.error("No rcvar value found in rcvar") if value.nil? - value = value.gsub!(/(.*)_enable="?(\w+)"?/, '\2') + value = value.gsub!(/(.*)(_enable)?="?(\w+)"?/, '\3') self.error("rcvar value is empty") if value.nil? self.debug("rcvar value is #{value}") value @@ -69,7 +73,7 @@ Puppet::Type.type(:service).provide :freebsd, :parent => :init do [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}\"") + if s.gsub!(/(#{rcvar}(_enable)?)=\"?(YES|NO)\"?/, "\\1=\"#{yesno}\"") File.open(filename, File::WRONLY) { |f| f << s } self.debug("Replaced in #{filename}") success = true diff --git a/lib/puppet/provider/service/init.rb b/lib/puppet/provider/service/init.rb index b7e2498d3..372ab20cd 100755 --- a/lib/puppet/provider/service/init.rb +++ b/lib/puppet/provider/service/init.rb @@ -5,7 +5,7 @@ Puppet::Type.type(:service).provide :init, :parent => :base do def self.defpath case Facter.value(:operatingsystem) - when "FreeBSD" + when "FreeBSD", "DragonFly" ["/etc/rc.d", "/usr/local/etc/rc.d"] when "HP-UX" "/sbin/init.d" diff --git a/lib/puppet/provider/service/launchd.rb b/lib/puppet/provider/service/launchd.rb index 9c3768489..5f3726a9c 100644 --- a/lib/puppet/provider/service/launchd.rb +++ b/lib/puppet/provider/service/launchd.rb @@ -49,11 +49,14 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do confine :operatingsystem => :darwin has_feature :enableable + has_feature :refreshable mk_resource_methods # These are the paths in OS X where a launchd service plist could # exist. This is a helper method, versus a constant, for easy testing # and mocking + # + # @api private def self.launchd_paths [ "/Library/LaunchAgents", @@ -62,14 +65,14 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do "/System/Library/LaunchDaemons" ] end - private_class_method :launchd_paths - # This is the path to the overrides plist file where service enabling - # behavior is defined in 10.6 and greater + # Defines the path to the overrides plist file where service enabling + # behavior is defined in 10.6 and greater. + # + # @api private def self.launchd_overrides "/var/db/launchd.db/com.apple.launchd/overrides.plist" end - private_class_method :launchd_overrides # Caching is enabled through the following three methods. Self.prefetch will # call self.instances to create an instance for each service. Self.flush will @@ -108,7 +111,6 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do end array_of_files.compact end - private_class_method :return_globbed_list_of_file_paths # Sets a class instance variable with a hash of all launchd plist files that # are found on the system. The key of the hash is the job id and the value @@ -271,13 +273,20 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do self.enable if did_disable_job and resource[:enable] == :true end + def restart + Puppet.debug("A restart has been triggered for the #{resource[:name]} service") + Puppet.debug("Stopping the #{resource[:name]} service") + self.stop + Puppet.debug("Starting the #{resource[:name]} service") + self.start + 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. - # Starting 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. + # Starting 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 @@ -303,11 +312,10 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do :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. - # Starting in 10.6 we need to write out a disabled key to the global + # Starting 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 has_macosx_plist_overrides? @@ -323,7 +331,6 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do end end - def disable if has_macosx_plist_overrides? overrides = self.class.read_plist(self.class.launchd_overrides) @@ -335,6 +342,4 @@ Puppet::Type.type(:service).provide :launchd, :parent => :base do Plist::Emit.save_plist(job_plist, job_path) end end - - end diff --git a/lib/puppet/provider/service/service.rb b/lib/puppet/provider/service/service.rb index ec2372f93..27f9b6373 100644 --- a/lib/puppet/provider/service/service.rb +++ b/lib/puppet/provider/service/service.rb @@ -23,7 +23,7 @@ Puppet::Type.type(:service).provide :service do def texecute(type, command, fof = true) begin # #565: Services generally produce no output, so squelch them. - execute(command, :failonfail => fof, :squelch => true) + execute(command, :failonfail => fof, :override_locale => false, :squelch => true) rescue Puppet::ExecutionFailure => detail @resource.fail "Could not #{type} #{@resource.ref}: #{detail}" end diff --git a/lib/puppet/provider/service/upstart.rb b/lib/puppet/provider/service/upstart.rb index 20eaebc1c..221d970d6 100755 --- a/lib/puppet/provider/service/upstart.rb +++ b/lib/puppet/provider/service/upstart.rb @@ -64,7 +64,7 @@ Puppet::Type.type(:service).provide :upstart, :parent => :debian do end def upstart_version - @@upstart_version ||= initctl("--version").match(/initctl \(upstart ([^\)]*)\)/)[1] + @upstart_version ||= initctl("--version").match(/initctl \(upstart ([^\)]*)\)/)[1] end # Where is our override script? diff --git a/lib/puppet/provider/user/hpux.rb b/lib/puppet/provider/user/hpux.rb index f0c8f7e8f..c38879a1c 100644 --- a/lib/puppet/provider/user/hpux.rb +++ b/lib/puppet/provider/user/hpux.rb @@ -6,7 +6,7 @@ Puppet::Type.type(:user).provide :hpuxuseradd, :parent => :useradd do 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" + commands :modify => "/usr/sam/lbin/usermod.sam", :delete => "/usr/sam/lbin/userdel.sam", :add => "/usr/sam/lbin/useradd.sam" options :comment, :method => :gecos options :groups, :flag => "-G" options :home, :flag => "-d", :method => :dir @@ -19,7 +19,7 @@ Puppet::Type.type(:user).provide :hpuxuseradd, :parent => :useradd do value !~ /\s/ end - has_features :manages_homedir, :allows_duplicates + has_features :manages_homedir, :allows_duplicates, :manages_passwords def deletecmd super.insert(1,"-F") @@ -28,4 +28,39 @@ Puppet::Type.type(:user).provide :hpuxuseradd, :parent => :useradd do def modifycmd(param,value) super.insert(1,"-F") end + + def password + # Password management routine for trusted and non-trusted systems + #temp="" + while ent = Etc.getpwent() do + if ent.name == resource.name + temp=ent.name + break + end + end + Etc.endpwent() + if !temp + return nil + end + + ent = Etc.getpwnam(resource.name) + if ent.passwd == "*" + # Either no password or trusted password, check trusted + file_name="/tcb/files/auth/#{resource.name.chars.first}/#{resource.name}" + if File.file?(file_name) + # Found the tcb user for the specific user, now get passwd + File.open(file_name).each do |line| + if ( line =~ /u_pwd/ ) + temp_passwd=line.split(":")[1].split("=")[1] + ent.passwd = temp_passwd + return ent.passwd + end + end + else + debug "No trusted computing user file #{file_name} found." + end + else + return ent.passwd + end + end end diff --git a/lib/puppet/provider/user/pw.rb b/lib/puppet/provider/user/pw.rb index cdf0e891d..87ad00adc 100644 --- a/lib/puppet/provider/user/pw.rb +++ b/lib/puppet/provider/user/pw.rb @@ -2,12 +2,12 @@ require 'puppet/provider/nameservice/pw' require 'open3' Puppet::Type.type(:user).provide :pw, :parent => Puppet::Provider::NameService::PW do - desc "User management via `pw` on FreeBSD." + desc "User management via `pw` on FreeBSD and DragonFly BSD." commands :pw => "pw" has_features :manages_homedir, :allows_duplicates, :manages_passwords, :manages_expiry - defaultfor :operatingsystem => :freebsd + defaultfor :operatingsystem => [:freebsd, :dragonfly] options :home, :flag => "-d", :method => :dir options :comment, :method => :gecos diff --git a/lib/puppet/provider/user/useradd.rb b/lib/puppet/provider/user/useradd.rb index 8ce053711..351e749e8 100644 --- a/lib/puppet/provider/user/useradd.rb +++ b/lib/puppet/provider/user/useradd.rb @@ -34,7 +34,7 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ cmd = [] if @resource.managehome? cmd << "-m" - elsif %w{Fedora RedHat CentOS OEL OVS}.include?(Facter.value(:operatingsystem)) + elsif Facter.value(:osfamily) == 'RedHat' cmd << "-M" end cmd @@ -80,7 +80,7 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ cmd += check_system_users cmd << @resource[:name] end - + def deletecmd cmd = [command(:delete)] cmd += @resource.managehome? ? ['-r'] : [] @@ -124,4 +124,3 @@ Puppet::Type.type(:user).provide :useradd, :parent => Puppet::Provider::NameServ :absent end end - diff --git a/lib/puppet/reference/configuration.rb b/lib/puppet/reference/configuration.rb index 19e09dee2..e7f495403 100644 --- a/lib/puppet/reference/configuration.rb +++ b/lib/puppet/reference/configuration.rb @@ -53,6 +53,12 @@ config.header = <<EOT * Multiple values should be specified as comma-separated lists; multiple directories should be separated with the system path separator (usually a colon). +* Settings that represent time intervals should be specified in duration format: + an integer immediately followed by one of the units 'y' (years of 365 days), + 'd' (days), 'h' (hours), 'm' (minutes), or 's' (seconds). The unit cannot be + combined with other units, and defaults to seconds when omitted. Examples are + '3600' which is equivalent to '1h' (one hour), and '1825d' which is equivalent + to '5y' (5 years). * Settings that take a single file or directory can optionally set the owner, group, and mode for their value: `rundir = $vardir/run { owner = puppet, group = puppet, mode = 644 }` diff --git a/lib/puppet/reports.rb b/lib/puppet/reports.rb index 69a3196e8..bf89ad510 100755 --- a/lib/puppet/reports.rb +++ b/lib/puppet/reports.rb @@ -1,6 +1,32 @@ require 'puppet/util/instance_loader' -# A simple mechanism for loading and returning reports. +# This class is an implementation of a simple mechanism for loading and returning reports. +# The intent is that a user registers a report by calling {register_report} and providing a code +# block that performs setup, and defines a method called `process`. The setup, and the `process` method +# are called in the context where `self` is an instance of {Puppet::Transaction::Report} which provides the actual +# data for the report via its methods. +# +# @example Minimal scaffolding for a report... +# Puppet::Reports::.register_report(:myreport) do +# # do setup here +# def process +# if self.status == 'failed' +# msg = "failed puppet run for #{self.host} #{self.status}" +# . . . +# else +# . . . +# end +# end +# end +# +# Required configuration: +# -- +# * A .rb file that defines a new report should be placed in the master's directory `lib/puppet/reports` +# * The `puppet.conf` file must have `report = true` in the `[agent]` section +# +# @see Puppet::Transaction::Report +# @api public +# class Puppet::Reports extend Puppet::Util::ClassGen extend Puppet::Util::InstanceLoader @@ -9,10 +35,22 @@ class Puppet::Reports instance_load :report, 'puppet/reports' class << self + # @api private attr_reader :hooks end - # Add a new report type. + # Adds a new report type. + # The block should contain setup, and define a method with the name `process`. The `process` method is + # called when the report is executed; the `process` method has access to report data via methods available + # in its context where `self` is an instance of {Puppet::Transaction::Report}. + # + # For an example, see the overview of this class. + # + # @param name [Symbol] the name of the report (do not use whitespace in the name). + # @param options [Hash] a hash of options + # @option options [Boolean] :useyaml whether yaml should be used or not + # @todo Uncertain what the options :useyaml really does; "whether yaml should be used or not", used where/how? + # def self.register_report(name, options = {}, &block) name = name.intern @@ -25,7 +63,8 @@ class Puppet::Reports end end - # Collect the docs for all of our reports. + # Collects the docs for all reports. + # @api private def self.reportdocs docs = "" @@ -41,7 +80,8 @@ class Puppet::Reports docs end - # List each of the reports. + # Lists each of the reports. + # @api private def self.reports instance_loader(:report).loadall loaded_instances(:report) diff --git a/lib/puppet/reports/tagmail.rb b/lib/puppet/reports/tagmail.rb index d4320d63f..c55089015 100644 --- a/lib/puppet/reports/tagmail.rb +++ b/lib/puppet/reports/tagmail.rb @@ -35,7 +35,7 @@ Puppet::Reports.register_report(:tagmail) do If you are using anti-spam controls such as grey-listing on your mail server, you should whitelist the sending email address (controlled by - `reportform` configuration option) to ensure your email is not discarded as spam. + `reportfrom` configuration option) to ensure your email is not discarded as spam. " # Find all matching messages. diff --git a/lib/puppet/settings.rb b/lib/puppet/settings.rb index 38dbf1d73..291e26ee1 100644 --- a/lib/puppet/settings.rb +++ b/lib/puppet/settings.rb @@ -11,6 +11,8 @@ require 'puppet/settings/path_setting' require 'puppet/settings/boolean_setting' require 'puppet/settings/terminus_setting' require 'puppet/settings/duration_setting' +require 'puppet/settings/config_file' +require 'puppet/settings/value_translator' # The class for handling configuration files. class Puppet::Settings @@ -46,7 +48,7 @@ class Puppet::Settings else fqdn = hostname end - fqdn.gsub(/\.$/, '') + fqdn.to_s.gsub(/\.$/, '') end def self.hostname_fact() @@ -61,6 +63,35 @@ class Puppet::Settings "puppet.conf" 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] = {} } + + # Hold parsed metadata until run_mode is known + @metas = {} + + # And keep a per-environment cache + @cache = Hash.new { |hash, key| hash[key] = {} } + + # The list of sections we've used. + @used = [] + + @hooks_to_call_on_application_initialization = [] + + @translate = Puppet::Settings::ValueTranslator.new + @config_file_parser = Puppet::Settings::ConfigFile.new(@translate) + end + # Retrieve a config value def [](param) value(param) @@ -208,7 +239,6 @@ class Puppet::Settings end def initialize_app_defaults(app_defaults) - raise Puppet::DevError, "Attempting to initialize application default settings more than once!" if app_defaults_initialized? REQUIRED_APP_SETTINGS.each do |key| raise SettingsError, "missing required app default setting '#{key}'" unless app_defaults.has_key?(key) end @@ -220,6 +250,7 @@ class Puppet::Settings set_value(key, value, :application_defaults) end end + apply_metadata call_hooks_deferred_to_application_initialization @app_defaults_initialized = true @@ -301,7 +332,7 @@ class Puppet::Settings value = "true" end - value &&= munge_value(value) + value &&= @translate[value] str = opt.sub(/^--/,'') bool = true @@ -332,29 +363,6 @@ class Puppet::Settings @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 = [] - - @hooks_to_call_on_application_initialization = [] - end - # 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 @@ -465,19 +473,8 @@ class Puppet::Settings # Parse the configuration file. Just provides thread safety. def parse_config_files - # we are able to support multiple config files; the "main" config file will - # be the one located in /etc/puppet (or overridden $confdir)... but we can - # also look for a config file in the user's home directory. We only load - # one configuration file in order to present a simple and consistent - # configuration model to the end user. It should also be noted we decided - # to merge in the user puppet.conf with the system puppet.conf for a time - # (e.g. load two configuration files) as a small part of #7749 but then - # decided to reverse this decision in #15337 to return to a disjoint - # configuration file model. - config_files = [which_configuration_file] - @sync.synchronize do - unsafe_parse(config_files) + unsafe_parse(which_configuration_file) end call_hooks_deferred_to_application_initialization :ignore_interpolation_dependency_errors => true @@ -518,13 +515,10 @@ class Puppet::Settings private :config_file_name # Unsafely parse the file -- this isn't thread-safe and causes plenty of problems if used directly. - def unsafe_parse(files) - raise Puppet::DevError unless files.length > 0 - + def unsafe_parse(file) # build up a single data structure that contains the values from all of the parsed files. data = {} - files.each do |file| - next unless FileTest.exist?(file) + if FileTest.exist?(file) begin file_data = parse_file(file) @@ -537,7 +531,6 @@ class Puppet::Settings data[key] = file_data[key] end end - rescue => detail Puppet.log_exception(detail, "Could not parse #{file}: #{detail}") return @@ -552,9 +545,8 @@ class Puppet::Settings unsafe_clear(false, false) # And now we can repopulate with the values from our last parsing of the config files. - metas = {} data.each do |area, values| - metas[area] = values.delete(:_meta) + @metas[area] = values.delete(:_meta) values.each do |key,value| set_value(key, value, area, :dont_trigger_handles => true, :ignore_bad_settings => true ) end @@ -582,19 +574,24 @@ class Puppet::Settings end end + # Take a best guess at metadata based on uninitialized run_mode + apply_metadata + end + private :unsafe_parse + + def apply_metadata # 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 = preferred_run_mode if source == :run_mode source = @name if (@name && source == :name) - if meta = metas[source] + if meta = @metas[source] set_metadata(meta) end end end - private :unsafe_parse - + private :apply_metadata # 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 @@ -710,11 +707,25 @@ class Puppet::Settings def service_user_available? return @service_user_available if defined?(@service_user_available) - return @service_user_available = false unless user_name = self[:user] + if self[:user] + user = Puppet::Type.type(:user).new :name => self[:user], :audit => :ensure + + @service_user_available = user.exists? + else + @service_user_available = false + end + end - user = Puppet::Type.type(:user).new :name => self[:user], :audit => :ensure + def service_group_available? + return @service_group_available if defined?(@service_group_available) - @service_user_available = user.exists? + if self[:group] + group = Puppet::Type.type(:group).new :name => self[:group], :audit => :ensure + + @service_group_available = group.exists? + else + @service_group_available = false + end end # Allow later inspection to determine if the setting was set on the @@ -1098,98 +1109,9 @@ Generated on #{Time.now}. @config.values.find_all { |setting| setting.has_hook? } 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 do |line| - count += 1 - case line - when /^\s*\[(\w+)\]\s*$/ - section = $1.intern # Section names - #disallow application_defaults in config file - if section == :application_defaults - raise Puppet::Error, "Illegal section 'application_defaults' in config file #{file} at line #{line}" - end - # 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 - raise ParseError.new(detail.message, file, line, detail) - end - else - raise ParseError.new("Could not match line #{line}", file, line) - end - end - - result + @config_file_parser.parse_file(file, read_file(file)) end # Read the file in. @@ -1207,7 +1129,9 @@ Generated on #{Time.now}. def set_metadata(meta) meta.each do |var, values| values.each do |param, value| - @config[var].send(param.to_s + "=", value) + @sync.synchronize do # yay, thread-safe + @config[var].send(param.to_s + "=", value) + end end end end diff --git a/lib/puppet/settings/config_file.rb b/lib/puppet/settings/config_file.rb new file mode 100644 index 000000000..88f45f4f5 --- /dev/null +++ b/lib/puppet/settings/config_file.rb @@ -0,0 +1,99 @@ +require 'puppet/settings/errors' + +## +# @api private +# +# Parses puppet configuration files +# +class Puppet::Settings::ConfigFile + + ## + # @param value_converter [Proc] a function that will convert strings into ruby types + # + def initialize(value_converter) + @value_converter = value_converter + end + + def parse_file(file, text) + result = {} + count = 0 + + # Default to 'main' for the section. + section_name = :main + result[section_name] = empty_section + text.split(/\n/).each do |line| + count += 1 + case line + when /^\s*\[(\w+)\]\s*$/ + section_name = $1.intern + fail_when_illegal_section_name(section_name, file, line) + if result[section_name].nil? + result[section_name] = empty_section + end + 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 = @value_converter[$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_name][:_meta][var] = options + end + result[section_name][var] = value + rescue Puppet::Error => detail + raise Puppet::Settings::ParseError.new(detail.message, file, line, detail) + end + else + raise Puppet::Settings::ParseError.new("Could not match line #{line}", file, line) + end + end + + result + end + +private + + def empty_section + { :_meta => {} } + end + + def fail_when_illegal_section_name(section, file, line) + if section == :application_defaults or section == :global_defaults + raise Puppet::Error, "Illegal section '#{section}' in config file #{file} at line #{line}" + end + end + + 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 +end diff --git a/lib/puppet/settings/file_setting.rb b/lib/puppet/settings/file_setting.rb index 56805e0b5..36275852c 100644 --- a/lib/puppet/settings/file_setting.rb +++ b/lib/puppet/settings/file_setting.rb @@ -2,47 +2,110 @@ require 'puppet/settings/string_setting' # A file. class Puppet::Settings::FileSetting < Puppet::Settings::StringSetting - AllowedOwners = %w{root service} - AllowedGroups = %w{root service} - class SettingError < StandardError; end + # An unspecified user or group + # + # @api private + class Unspecified + def value + nil + end + end + + # A "root" user or group + # + # @api private + class Root + def value + "root" + end + end + + # A "service" user or group that picks up values from settings when the + # referenced user or group is safe to use (it exists or will be created), and + # uses the given fallback value when not safe. + # + # @api private + class Service + # @param name [Symbol] the name of the setting to use as the service value + # @param fallback [String, nil] the value to use when the service value cannot be used + # @param settings [Puppet::Settings] the puppet settings object + # @param available_method [Symbol] the name of the method to call on + # settings to determine if the value in settings is available on the system + # + def initialize(name, fallback, settings, available_method) + @settings = settings + @available_method = available_method + @name = name + @fallback = fallback + end + + def value + if safe_to_use_settings_value? + @settings[@name] + else + @fallback + end + end + + private + def safe_to_use_settings_value? + @settings[:mkusers] or @settings.send(@available_method) + end + end + attr_accessor :mode, :create + def initialize(args) + @group = Unspecified.new + @owner = Unspecified.new + super(args) + end + # Should we create files, rather than just directories? def create_files? create end + # @param value [String] the group to use on the created file (can only be "root" or "service") + # @api public 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 - end - - def group - return unless @group - @settings[:group] + @group = case value + when "root" + Root.new + when "service" + # Group falls back to `nil` because we cannot assume that a "root" group exists. + # Some systems have root group, others have wheel, others have something else. + Service.new(:group, nil, @settings, :service_group_available?) + else + unknown_value(':group', value) + end end + # @param value [String] the owner to use on the created file (can only be "root" or "service") + # @api public 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 = case value + when "root" + Root.new + when "service" + Service.new(:user, "root", @settings, :service_user_available?) + else + unknown_value(':owner', value) + end end - def owner - return unless @owner - return "root" if @owner == "root" or ! use_service_user? - @settings[:user] + # @return [String, nil] the name of the group to use for the file or nil if the group should not be managed + # @api public + def group + @group.value end - def use_service_user? - @settings[:mkusers] or @settings.service_user_available? + # @return [String, nil] the name of the user to use for the file or nil if the user should not be managed + # @api public + def owner + @owner.value end def munge(value) @@ -116,4 +179,9 @@ class Puppet::Settings::FileSetting < Puppet::Settings::StringSetting end } end + +private + def unknown_value(parameter, value) + raise SettingError, "The #{parameter} parameter for the setting '#{name}' must be either 'root' or 'service', not '#{value}'" + end end diff --git a/lib/puppet/settings/value_translator.rb b/lib/puppet/settings/value_translator.rb new file mode 100644 index 000000000..58a3e278a --- /dev/null +++ b/lib/puppet/settings/value_translator.rb @@ -0,0 +1,15 @@ +# Convert arguments into booleans, integers, or whatever. +class Puppet::Settings::ValueTranslator + def [](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 +end diff --git a/lib/puppet/ssl/certificate_authority.rb b/lib/puppet/ssl/certificate_authority.rb index bd9e13d9a..6229a2d16 100644 --- a/lib/puppet/ssl/certificate_authority.rb +++ b/lib/puppet/ssl/certificate_authority.rb @@ -1,6 +1,7 @@ require 'monitor' require 'puppet/ssl/host' require 'puppet/ssl/certificate_request' +require 'puppet/ssl/certificate_signer' require 'puppet/util' # The class that knows how to sign certificates. It creates @@ -277,7 +278,9 @@ class Puppet::SSL::CertificateAuthority cert = Puppet::SSL::Certificate.new(hostname) cert.content = Puppet::SSL::CertificateFactory. build(cert_type, csr, issuer, next_serial) - cert.content.sign(host.key.content, OpenSSL::Digest::SHA256.new) + + signer = Puppet::SSL::CertificateSigner.new + signer.sign(cert.content, host.key.content) Puppet.notice "Signed certificate request for #{hostname}" diff --git a/lib/puppet/ssl/certificate_authority/interface.rb b/lib/puppet/ssl/certificate_authority/interface.rb index caeb2b609..4e7a14ac8 100644 --- a/lib/puppet/ssl/certificate_authority/interface.rb +++ b/lib/puppet/ssl/certificate_authority/interface.rb @@ -1,8 +1,8 @@ -# This class is basically a hidden class that knows how to act on the -# CA. Its job is to provide a CLI-like interface to the CA class. module Puppet module SSL class CertificateAuthority + # This class is basically a hidden class that knows how to act on the + # CA. Its job is to provide a CLI-like interface to the CA class. class Interface INTERFACE_METHODS = [:destroy, :list, :revoke, :generate, :sign, :print, :verify, :fingerprint] diff --git a/lib/puppet/ssl/certificate_request.rb b/lib/puppet/ssl/certificate_request.rb index 4e1cc1a06..0d90e5a4f 100644 --- a/lib/puppet/ssl/certificate_request.rb +++ b/lib/puppet/ssl/certificate_request.rb @@ -1,4 +1,5 @@ require 'puppet/ssl/base' +require 'puppet/ssl/certificate_signer' # Manage certificate requests. class Puppet::SSL::CertificateRequest < Puppet::SSL::Base @@ -59,7 +60,8 @@ class Puppet::SSL::CertificateRequest < Puppet::SSL::Base csr.add_attribute(OpenSSL::X509::Attribute.new("extReq", extReq)) end - csr.sign(key, OpenSSL::Digest::SHA256.new) + signer = Puppet::SSL::CertificateSigner.new + signer.sign(csr, key) 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) diff --git a/lib/puppet/ssl/certificate_signer.rb b/lib/puppet/ssl/certificate_signer.rb new file mode 100644 index 000000000..acaff012b --- /dev/null +++ b/lib/puppet/ssl/certificate_signer.rb @@ -0,0 +1,22 @@ +# Take care of signing a certificate in a FIPS 140-2 compliant manner. +# +# @see http://projects.puppetlabs.com/issues/17295 +# +# @api private +class Puppet::SSL::CertificateSigner + def initialize + if OpenSSL::Digest.const_defined?('SHA256') + @digest = OpenSSL::Digest::SHA256 + elsif OpenSSL::Digest.const_defined?('SHA1') + @digest = OpenSSL::Digest::SHA1 + else + raise Puppet::Error, + "No FIPS 140-2 compliant digest algorithm in OpenSSL::Digest" + end + @digest + end + + def sign(content, key) + content.sign(key, @digest.new) + end +end diff --git a/lib/puppet/test/test_helper.rb b/lib/puppet/test/test_helper.rb index 6db4ab937..cc57bd359 100644 --- a/lib/puppet/test/test_helper.rb +++ b/lib/puppet/test/test_helper.rb @@ -27,6 +27,13 @@ module Puppet::Test # other features such as "around_test", but we didn't see a compelling # reason to deal with that right now. class TestHelper + # Call this method once, as early as possible, such as before loading tests + # that call Puppet. + # @return nil + def self.initialize() + initialize_settings_before_each + end + # Call this method once, when beginning a test run--prior to running # any individual tests. # @return nil @@ -146,9 +153,7 @@ module Puppet::Test def self.initialize_settings_before_each() Puppet.settings.preferred_run_mode = "user" # Initialize "app defaults" settings to a good set of test values - app_defaults_for_tests.each do |key, value| - Puppet.settings.set_value(key, value, :application_defaults) - end + Puppet.settings.initialize_app_defaults(app_defaults_for_tests) # Avoid opening ports to the outside world Puppet.settings[:bindaddress] = "127.0.0.1" diff --git a/lib/puppet/transaction.rb b/lib/puppet/transaction.rb index bc588c8c7..60d880b98 100644 --- a/lib/puppet/transaction.rb +++ b/lib/puppet/transaction.rb @@ -12,8 +12,7 @@ class Puppet::Transaction require 'puppet/transaction/resource_harness' require 'puppet/resource/status' - attr_accessor :component, :catalog, :ignoreschedules, :for_network_device - attr_accessor :configurator + attr_accessor :catalog, :ignoreschedules, :for_network_device # The report, once generated. attr_reader :report diff --git a/lib/puppet/transaction/report.rb b/lib/puppet/transaction/report.rb index 4fe5062da..260a068b2 100644 --- a/lib/puppet/transaction/report.rb +++ b/lib/puppet/transaction/report.rb @@ -1,34 +1,119 @@ require 'puppet' require 'puppet/indirector' -# A class for reporting what happens on each client. Reports consist of -# two types of data: Logs and Metrics. Logs are the output that each -# change produces, and Metrics are all of the numerical data involved -# in the transaction. +# This class is used to report what happens on a client. +# There are two types of data in a report; _Logs_ and _Metrics_. +# +# * **Logs** - are the output that each change produces. +# * **Metrics** - are all of the numerical data involved in the transaction. +# +# Use {Puppet::Reports} class to create a new custom report type. This class is indirectly used +# as a source of data to report in such a registered report. +# +# ##Metrics +# There are three types of metrics in each report, and each type of metric has one or more values. +# +# * Time: Keeps track of how long things took. +# * Total: Total time for the configuration run +# * File: +# * Exec: +# * User: +# * Group: +# * Config Retrieval: How long the configuration took to retrieve +# * Service: +# * Package: +# * Resources: Keeps track of the following stats: +# * Total: The total number of resources being managed +# * Skipped: How many resources were skipped, because of either tagging or scheduling restrictions +# * Scheduled: How many resources met any scheduling restrictions +# * Out of Sync: How many resources were out of sync +# * Applied: How many resources were attempted to be fixed +# * Failed: How many resources were not successfully fixed +# * Restarted: How many resources were restarted because their dependencies changed +# * Failed Restarts: How many resources could not be restarted +# * Changes: The total number of changes in the transaction. +# +# @api public class Puppet::Transaction::Report extend Puppet::Indirector indirects :report, :terminus_class => :processor - attr_accessor :configuration_version, :host, :environment - attr_reader :resource_statuses, :logs, :metrics, :time, :kind, :status, - :puppet_version, :report_format - - # This is necessary since Marshall doesn't know how to - # dump hash with default proc (see below @records) + # The version of the configuration + # @todo Uncertain what this is? + # @return [???] the configuration version + attr_accessor :configuration_version + + # The host name for which the report is generated + # @return [String] the host name + attr_accessor :host + + # The name of the environment the host is in + # @return [String] the environment name + attr_accessor :environment + + # A hash with a map from resource to status + # @return [Hash<{String => String}>] Resource name to status string. + # @todo Uncertain if the types in the hash are correct... + attr_reader :resource_statuses + + # A list of log messages. + # @return [Array<String>] logged messages + attr_reader :logs + + # A hash of metric name to metric value. + # @return [Hash<{String => Object}>] A map of metric name to value. + # @todo Uncertain if all values are numbers - now marked as Object. + # + attr_reader :metrics + + # The time when the report data was generated. + # @return [Time] A time object indicating when the report data was generated + # + attr_reader :time + + # The 'kind' of report is the name of operation that triggered the report to be produced. + # Typically "apply". + # @return [String] the kind of operation that triggered the generation of the report. + # + attr_reader :kind + + # The status of the client run is an enumeration: 'failed', 'changed' or 'unchanged' + # @return [String] the status of the run - one of the values 'failed', 'changed', or 'unchanged' + # + attr_reader :status + + # @return [String] The Puppet version in String form. + # @see Puppet::version() + # + attr_reader :puppet_version + + # @return [Integer] (3) a report format version number + # @todo Unclear what this is - a version? + # + attr_reader :report_format + + # This is necessary since Marshal doesn't know how to + # dump hash with default proc (see below "@records") ? + # @todo there is no "@records" to see below, uncertain what this is for. + # @api private + # def self.default_format :yaml end + # @api private def <<(msg) @logs << msg self end + # @api private def add_times(name, value) @external_times[name] = value end + # @api private def add_metric(name, hash) metric = Puppet::Util::Metric.new(name) @@ -40,10 +125,12 @@ class Puppet::Transaction::Report metric end + # @api private def add_resource_status(status) @resource_statuses[status.resource] = status end + # @api private def compute_status(resource_metrics, change_metric) if (resource_metrics["failed"] || 0) > 0 'failed' @@ -54,10 +141,12 @@ class Puppet::Transaction::Report end end + # @api private def prune_internal_data resource_statuses.delete_if {|name,res| res.resource_type == 'Whit'} end + # @api private def finalize_report prune_internal_data @@ -69,6 +158,7 @@ class Puppet::Transaction::Report @status = compute_status(resource_metrics, change_metric) end + # @api private def initialize(kind, configuration_version=nil, environment=nil) @metrics = {} @logs = [] @@ -84,11 +174,18 @@ class Puppet::Transaction::Report @status = 'failed' # assume failed until the report is finalized end + # @return [String] the host name + # @api public + # def name host end # Provide a human readable textual summary of this report. + # @note This is intended for debugging purposes + # @return [String] A string with a textual summary of this report. + # @api public + # def summary report = raw_summary @@ -115,7 +212,10 @@ class Puppet::Transaction::Report ret end - # Provide a raw hash summary of this report. + # Provides a raw hash summary of this report. + # @return [Hash<{String => Object}>] A hash with metrics key to value map + # @api public + # def raw_summary report = { "version" => { "config" => configuration_version, "puppet" => Puppet.version } } @@ -131,9 +231,16 @@ class Puppet::Transaction::Report report 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 + # Computes a single number that represents the report's status. + # The computation is based on the contents of this report's metrics. + # The resulting number is a bitmask where # individual bits represent the presence of different metrics. + # + # * 0x2 set if there are changes + # * 0x4 set if there are failures + # @return [Integer] A bitmask where 0x2 is set if there are changes, and 0x4 is set of there are failures. + # @api public + # def exit_status status = 0 status |= 2 if @metrics["changes"]["total"] > 0 @@ -141,6 +248,8 @@ class Puppet::Transaction::Report status end + # @api private + # def to_yaml_properties instance_variables - [:@external_times] end diff --git a/lib/puppet/type.rb b/lib/puppet/type.rb index 405473dfd..e5328d8db 100644 --- a/lib/puppet/type.rb +++ b/lib/puppet/type.rb @@ -13,7 +13,67 @@ require 'puppet/util/tagging' # see the bottom of the file for the rest of the inclusions + module Puppet +# The base class for all Puppet types. +# +# A type describes: +#-- +# * **Attributes** - properties, parameters, and meta-parameters are different types of attributes of a type. +# * **Properties** - these are the properties of the managed resource (attributes of the entity being managed; like +# a file's owner, group and mode). A property describes two states; the 'is' (current state) and the 'should' (wanted +# state). +# * **Ensurable** - a set of traits that control the lifecycle (create, remove, etc.) of a managed entity. +# There is a default set of operations associated with being _ensurable_, but this can be changed. +# * **Name/Identity** - one property is the name/identity of a resource, the _namevar_ that uniquely identifies +# one instance of a type from all others. +# * **Parameters** - additional attributes of the type (that does not directly related to an instance of the managed +# resource; if an operation is recursive or not, where to look for things, etc.). A Parameter (in contrast to Property) +# has one current value where a Property has two (current-state and wanted-state). +# * **Meta-Parameters** - parameters that are available across all types. A meta-parameter typically has +# additional semantics; like the `require` meta-parameter. A new type typically does not add new meta-parameters, +# but you need to be aware of their existence so you do not inadvertently shadow an existing meta-parameters. +# * **Parent** - a type can have a super type (that it inherits from). +# * **Validation** - If not just a basic data type, or an enumeration of symbolic values, it is possible to provide +# validation logic for a type, properties and parameters. +# * **Munging** - munging/unmunging is the process of turning a value in external representation (as used +# by a provider) into an internal representation and vice versa. A Type supports adding custom logic for these. +# * **Auto Requirements** - a type can specify automatic relationships to resources to ensure that if they are being +# managed, they will be processed before this type. +# * **Providers** - a provider is an implementation of a type's behavior - the management of a resource in the +# system being managed. A provider is often platform specific and is selected at runtime based on +# criteria/predicates specified in the configured providers. See {Puppet::Provider} for details. +# * **Device Support** - A type has some support for being applied to a device; i.e. something that is managed +# by running logic external to the device itself. There are several methods that deals with type +# applicability for these special cases such as {apply_to_device}. +# +# Additional Concepts: +# -- +# * **Resource-type** - A _resource type_ is a term used to denote the type of a resource; internally a resource +# is really an instance of a Ruby class i.e. {Puppet::Resource} which defines its behavior as "resource data". +# Conceptually however, a resource is an instance of a subclass of Type (e.g. File), where such a class describes +# its interface (what can be said/what is known about a resource of this type), +# * **Managed Entity** - This is not a term in general use, but is used here when there is a need to make +# a distinction between a resource (a description of what/how something should be managed), and what it is +# managing (a file in the file system). The term _managed entity_ is a reference to the "file in the file system" +# * **Isomorphism** - the quality of being _isomorphic_ means that two resource instances with the same name +# refers to the same managed entity. Or put differently; _an isomorphic name is the identity of a resource_. +# As an example, `exec` resources (that executes some command) have the command (i.e. the command line string) as +# their name, and these resources are said to be non-isomorphic. +# +# @note The Type class deals with multiple concerns; some methods provide an internal DSL for convenient definition +# of types, other methods deal with various aspects while running; wiring up a resource (expressed in Puppet DSL +# or Ruby DSL) with its _resource type_ (i.e. an instance of Type) to enable validation, transformation of values +# (munge/unmunge), etc. Lastly, Type is also responsible for dealing with Providers; the concrete implementations +# of the behavior that constitutes how a particular Type behaves on a particular type of system (e.g. how +# commands are executed on a flavor of Linux, on Windows, etc.). This means that as you are reading through the +# documentation of this class, you will be switching between these concepts, as well as switching between +# the conceptual level "a resource is an instance of a resource-type" and the actual implementation classes +# (Type, Resource, Provider, and various utility and helper classes). +# +# @api public +# +# class Type include Puppet::Util include Puppet::Util::Errors @@ -21,9 +81,15 @@ class Type include Puppet::Util::Logging include Puppet::Util::Tagging - ############################### # Comparing type instances. include Comparable + + # Compares this type against the given _other_ (type) and returns -1, 0, or +1 depending on the order. + # @param other [Object] the object to compare against (produces nil, if not kind of Type} + # @return [-1, 0, +1, nil] produces -1 if this type is before the given _other_ type, 0 if equals, and 1 if after. + # Returns nil, if the given _other_ is not a kind of Type. + # @see Comparable + # def <=>(other) # We only order against other types, not arbitrary objects. return nil unless other.is_a? Puppet::Type @@ -32,22 +98,30 @@ class Type self.ref <=> other.ref end - ############################### # Code related to resource type attributes. class << self include Puppet::Util::ClassGen include Puppet::Util::Warnings + + # @return [Array<Puppet::Property>] The list of declared properties for the resource type. + # The returned lists contains instances if Puppet::Property or its subclasses. attr_reader :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. + # Returns all the attribute names of the type in the appropriate order. + # The {key_attributes} come first, then the {provider}, then the {properties}, and finally + # the {parameters} and {metaparams}, + # all in the order they were specified in the respective files. + # @return [Array<String>] all type attribute names in a defined order. + # def self.allattrs key_attributes | (parameters & [:provider]) | properties.collect { |property| property.name } | parameters | metaparams end - # Find the class associated with any given attribute. + # Returns the class associated with the given attribute name. + # @param name [String] the name of the attribute to obtain the class for + # @return [Class, nil] the class for the given attribute, or nil if the name does not refer to an existing attribute + # def self.attrclass(name) @attrclasses ||= {} @@ -63,8 +137,11 @@ class Type @attrclasses[name] end - # What type of parameter are we dealing with? Cache the results, because - # this method gets called so many times. + # Returns the attribute type (`:property`, `;param`, `:meta`). + # @comment What type of parameter are we dealing with? Cache the results, because + # this method gets called so many times. + # @return [Symbol] a symbol describing the type of attribute (`:property`, `;param`, `:meta`) + # def self.attrtype(attr) @attrtypes ||= {} unless @attrtypes.include?(attr) @@ -77,13 +154,35 @@ class Type @attrtypes[attr] end - + + # Provides iteration over meta-parameters. + # @yieldparam p [Puppet::Parameter] each meta parameter + # @return [void] + # 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. + # Creates a new `ensure` property with configured default values or with configuration by an optional block. + # This method is a convenience method for creating a property `ensure` with default accepted values. + # If no block is specified, the new `ensure` property will accept the default symbolic + # values `:present`, and `:absent` - see {Puppet::Property::Ensure}. + # If something else is wanted, pass a block and make calls to {Puppet::Property.newvalue} from this block + # to define each possible value. If a block is passed, the defaults are not automatically added to the set of + # valid values. + # + # @note This method will be automatically called without a block if the type implements the methods + # specified by {ensurable?}. It is recommended to always call this method and not rely on this automatic + # specification to clearly state that the type is ensurable. + # + # @overload ensurable() + # @overload ensurable({|| ... }) + # @yield [ ] A block evaluated in scope of the new Parameter + # @yieldreturn [void] + # @return [void] + # @dsl type + # @api public + # def self.ensurable(&block) if block_given? self.newproperty(:ensure, :parent => Puppet::Property::Ensure, &block) @@ -94,7 +193,12 @@ class Type end end - # Should we add the 'ensure' property to this class? + # Returns true if the type implements the default behavior expected by being _ensurable_ "by default". + # A type is _ensurable_ by default if it responds to `:exists`, `:create`, and `:destroy`. + # If a type implements these methods and have not already specified that it is _ensurable_, it will be + # made so with the defaults specified in {ensurable}. + # @return [Boolean] whether the type is _ensurable_ or not. + # def self.ensurable? # If the class has all three of these methods defined, then it's # ensurable. @@ -103,34 +207,60 @@ class Type } end - # These `apply_to` methods are horrible. They should really be implemented - # as part of the usual system of constraints that apply to a type and - # provider pair, but were implemented as a separate shadow system. + # @comment These `apply_to` methods are horrible. They should really be implemented + # as part of the usual system of constraints that apply to a type and + # provider pair, but were implemented as a separate shadow system. + # + # @comment We should rip them out in favour of a real constraint pattern around the + # target device - whatever that looks like - and not have this additional + # magic here. --daniel 2012-03-08 + # + # Makes this type applicable to `:device`. + # @return [Symbol] Returns `:device` + # @api private # - # We should rip them out in favour of a real constraint pattern around the - # target device - whatever that looks like - and not have this additional - # magic here. --daniel 2012-03-08 def self.apply_to_device @apply_to = :device end + # Makes this type applicable to `:host`. + # @return [Symbol] Returns `:host` + # @api private + # def self.apply_to_host @apply_to = :host end + # Makes this type applicable to `:both` (i.e. `:host` and `:device`). + # @return [Symbol] Returns `:both` + # @api private + # def self.apply_to_all @apply_to = :both end + # Makes this type apply to `:host` if not already applied to something else. + # @return [Symbol] a `:device`, `:host`, or `:both` enumeration + # @api private def self.apply_to @apply_to ||= :host end + # Returns true if this type is applicable to the given target. + # @param target [Symbol] should be :device, :host or :target, if anything else, :host is enforced + # @return [Boolean] true + # @api private + # def self.can_apply_to(target) [ target == :device ? :device : :host, :both ].include?(apply_to) end - # Deal with any options passed into parameters. + # Processes the options for a named parameter. + # @param name [String] the name of a parameter + # @param options [Hash] a hash of options + # @option options [Boolean] :boolean if option set to true, an access method on the form _name_? is added for the param + # @return [void] + # def self.handle_param_options(name, options) # If it's a boolean parameter, create a method to test the value easily if options[:boolean] @@ -143,28 +273,59 @@ class Type end end - # Is the parameter in question a meta-parameter? + # Is the given parameter a meta-parameter? + # @return [Boolean] true if the given parameter is a meta-parameter. + # def self.metaparam?(param) @@metaparamhash.include?(param.intern) end - # Find the metaparameter class associated with a given metaparameter name. - # Must accept a `nil` name, and return nil. + # Returns the meta-parameter class associated with the given meta-parameter name. + # Accepts a `nil` name, and return nil. + # @param name [String, nil] the name of a meta-parameter + # @return [Class,nil] the class for the given meta-parameter, or `nil` if no such meta-parameter exists, (or if + # the given meta-parameter name is `nil`. + # def self.metaparamclass(name) return nil if name.nil? @@metaparamhash[name.intern] end + # Returns all meta-parameter names. + # @return [Array<String>] all meta-parameter names + # def self.metaparams @@metaparams.collect { |param| param.name } end + # Returns the documentation for a given meta-parameter of this type. + # @todo the type for the param metaparam + # @param metaparam [??? Puppet::Parameter] the meta-parameter to get documentation for. + # @return [String] the documentation associated with the given meta-parameter, or nil of not such documentation + # exists. + # @raises [?] if the given metaparam is not a meta-parameter in this type + # 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. + # Creates a new meta-parameter. + # This creates a new meta-parameter that is added to all types. + # @param name [Symbol] the name of the parameter + # @param options [Hash] a hash with options. + # @option options [Class<inherits Puppet::Parameter>] :parent (Puppet::Parameter) the super class of this parameter + # @option options [Hash{String => Object}] :attributes a hash that is applied to the generated class + # by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given + # block is evaluated. + # @option options [Boolean] :boolean (false) specifies if this is a boolean parameter + # @option options [Boolean] :namevar (false) specifies if this parameter is the namevar + # @option options [Symbol, Array<Symbol>] :required_features specifies required provider features by name + # @return [Class<inherits Puppet::Parameter>] the created parameter + # @yield [ ] a required block that is evaluated in the scope of the new meta-parameter + # @api public + # @dsl type + # @todo Verify that this description is ok + # def self.newmetaparam(name, options = {}, &block) @@metaparams ||= [] @@metaparamhash ||= {} @@ -190,6 +351,11 @@ class Type param end + # Returns parameters that act as a key. + # All parameters that return true from #isnamevar? or is named `:name` are included in the returned result. + # @todo would like a better explanation + # @return Array<??? Puppet::Parameter> + # def self.key_attribute_parameters @key_attribute_parameters ||= ( params = @parameters.find_all { |param| @@ -198,11 +364,43 @@ class Type ) end + # Returns cached {key_attribute_parameters} names + # @todo what is a 'key_attribute' ? + # @return [Array<String>] cached key_attribute names + # def self.key_attributes # This is a cache miss around 0.05 percent of the time. --daniel 2012-07-17 @key_attributes_cache ||= key_attribute_parameters.collect { |p| p.name } end + # Returns a mapping from the title string to setting of attribute value(s). + # This default implementation provides a mapping of title to the one and only _namevar_ present + # in the type's definition. + # @note Advanced: some logic requires this mapping to be done differently, using a different + # validation/pattern, breaking up the title + # into several parts assigning each to an individual attribute, or even use a composite identity where + # all namevars are seen as part of the unique identity (such computation is done by the {#uniqueness} method. + # These advanced options are rarely used (only one of the built in puppet types use this, and then only + # a small part of the available functionality), and the support for these advanced mappings is not + # implemented in a straight forward way. For these reasons, this method has been marked as private). + # + # @raise [Puppet::DevError] if there is no title pattern and there are two or more key attributes + # @return [Array<Array<Regexp, Array<Array <Symbol, Proc>>>>, nil] a structure with a regexp and the first key_attribute ??? + # @comment This wonderful piece of logic creates a structure used by Resource.parse_title which + # has the capability to assign parts of the title to one or more attributes; It looks like an implementation + # of a composite identity key (all parts of the key_attributes array are in the key). This can also + # be seen in the method uniqueness_key. + # The implementation in this method simply assigns the title to the one and only namevar (which is name + # or a variable marked as namevar). + # If there are multiple namevars (any in addition to :name?) then this method MUST be implemented + # as it raises an exception if there is more than 1. Note that in puppet, it is only File that uses this + # to create a different pattern for assigning to the :path attribute + # This requires further digging. + # The entire construct is somewhat strange, since resource checks if the method "title_patterns" is + # implemented (it seems it always is) - why take this more expensive regexp mathching route for all + # other types? + # @api private + # def self.title_patterns case key_attributes.length when 0; [] @@ -213,12 +411,29 @@ class Type end end + # Produces a _uniqueness_key_ + # @todo Explain what a uniqueness_key is + # @return [Object] an object that is a _uniqueness_key_ for this object + # def uniqueness_key self.class.key_attributes.sort_by { |attribute_name| attribute_name.to_s }.map{ |attribute_name| self[attribute_name] } end - # Create a new parameter. Requires a block and a name, stores it in the - # @parameters array, and does some basic checking on it. + # Creates a new parameter. + # @param name [Symbol] the name of the parameter + # @param options [Hash] a hash with options. + # @option options [Class<inherits Puppet::Parameter>] :parent (Puppet::Parameter) the super class of this parameter + # @option options [Hash{String => Object}] :attributes a hash that is applied to the generated class + # by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given + # block is evaluated. + # @option options [Boolean] :boolean (false) specifies if this is a boolean parameter + # @option options [Boolean] :namevar (false) specifies if this parameter is the namevar + # @option options [Symbol, Array<Symbol>] :required_features specifies required provider features by name + # @return [Class<inherits Puppet::Parameter>] the created parameter + # @yield [ ] a required block that is evaluated in the scope of the new parameter + # @api public + # @dsl type + # def self.newparam(name, options = {}, &block) options[:attributes] ||= {} @@ -242,12 +457,24 @@ class Type param 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. + # Creates a new property. + # @param name [Symbol] the name of the property + # @param options [Hash] a hash with options. + # @option options [Symbol] :array_matching (:first) specifies how the current state is matched against + # the wanted state. Use `:first` if the property is single valued, and (`:all`) otherwise. + # @option options [Class<inherits Puppet::Property>] :parent (Puppet::Property) the super class of this property + # @option options [Hash{String => Object}] :attributes a hash that is applied to the generated class + # by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given + # block is evaluated. + # @option options [Boolean] :boolean (false) specifies if this is a boolean parameter + # @option options [Symbol] :retrieve the method to call on the provider (or `parent` if `provider` is not set) + # to retrieve the current value of this property. + # @option options [Symbol, Array<Symbol>] :required_features specifies required provider features by name + # @return [Class<inherits Puppet::Property>] the created property + # @yield [ ] a required block that is evaluated in the scope of the new property + # @api public + # @dsl type + # def self.newproperty(name, options = {}, &block) name = name.intern @@ -295,22 +522,25 @@ class Type @paramhash[param].doc end - # Return the parameter names + # @return [Array<String>] Returns 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. + # @return [Puppet::Parameter] Returns the parameter class associated with the given parameter name. def self.paramclass(name) @paramhash[name] end - # Return the property class associated with a name + # @return [Puppet::Property] Returns the property class ??? associated with the given property name def self.propertybyname(name) @validproperties[name] end + # Returns whether or not the given name is the name of a property, parameter or meta-parameter + # @return [Boolean] true if the given attribute name is the name of an existing property, parameter or meta-parameter + # def self.validattr?(name) name = name.intern return true if name == :name @@ -323,37 +553,43 @@ class Type @validattrs[name] end - # does the name reflect a valid property? + # @return [Boolean] Returns true if the given name is the name of an existing property def self.validproperty?(name) name = name.intern @validproperties.include?(name) && @validproperties[name] end - # Return the list of validproperties + # @return [Array<Symbol>, {}] Returns a list of valid property names, or an empty hash if there are none. + # @todo An empty hash is returned if there are no defined parameters (not an empty array). This looks like + # a bug. + # def self.validproperties return {} unless defined?(@parameters) @validproperties.keys end - # does the name reflect a valid parameter? + # @return [Boolean] Returns true if the given name is the name of an existing 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. + # (see validattr?) + # @note see comment in code - how should this be documented? Are some of the other query methods deprecated? + # (or should be). + # @comment 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 - # Are we deleting this resource? + # @return [Boolean] Returns true if the wanted state of the resoure is that it should be absent (i.e. to be deleted). 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 + # Creates a new property value holder for the resource if it is valid and does not already exist + # @return [Boolean] 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) @@ -362,20 +598,24 @@ class Type false end - # - # The name_var is the key_attribute in the case that there is only one. - # + # @return [Symbol, Boolean] Returns the name of the namevar if there is only one or false otherwise. + # @comment This is really convoluted and part of the support for multiple namevars (?). + # If there is only one namevar, the produced value is naturally this namevar, but if there are several? + # The logic caches the name of the namevar if it is a single name, but otherwise always + # calls key_attributes, and then caches the first if there was only one, otherwise it returns + # false and caches this (which is then subsequently returned as a cache hit). + # def name_var return @name_var_cache unless @name_var_cache.nil? key_attributes = self.class.key_attributes @name_var_cache = (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)'. + # Gets the 'should' (wanted state) value of a parameter or property by name. + # To explicitly get the 'is' (current state) value use `o.is(:name)`, and to explicitly get the 'should' value + # use `o.should(:name)` + # @param name [String] the name of the attribute to obtain the 'should' value for. + # @return [Object] 'should'/wanted value of the given attribute def [](name) name = name.intern fail("Invalid parameter #{name}(#{name.inspect})") unless self.class.validattr?(name) @@ -393,9 +633,9 @@ class Type 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. + # Sets the 'should' (wanted state) value of a property, or the value of a parameter. + # @return + # @raise [Puppet::Error] if the setting of the value fails, or if the given name is nil. def []=(name,value) name = name.intern @@ -422,8 +662,16 @@ class Type nil end - # remove a property from the object; useful in testing or in cleanup + # Removes a property from the object; useful in testing or in cleanup # when an error has been encountered + # @todo Incomprehensible - the comment says "Remove a property", the code refers to @parameters, and + # the method parameter is called "attr" - What is it, property, parameter, both (i.e an attribute) or what? + # @todo Don't know what the attr is (name or Property/Parameter?). Guessing it is a String name... + # @todo Is it possible to delete a meta-parameter? + # @todo What does delete mean? Is it deleted from the type or is its value state 'is'/'should' deleted? + # @param attr [String] the attribute to delete from this object. WHAT IS THE TYPE? + # @raise [Puppet::DecError] when an attempt is made to delete an attribute that does not exists. + # def delete(attr) attr = attr.intern if @parameters.has_key?(attr) @@ -433,7 +681,11 @@ class Type end end - # iterate across the existing properties + # Iterates over the existing properties. + # @todo what does this mean? As opposed to iterating over the "non existing properties" ??? Is it an + # iteration over those properties that have state? CONFUSING. + # @yieldparam property [Puppet::Property] each property + # @return [void] def eachproperty # properties is a private method properties.each { |property| @@ -441,21 +693,38 @@ class Type } end - # Create a transaction event. Called by Transaction or by - # a property. + # Creates a transaction event. + # Called by Transaction or by a property. + # Merges the given options with the options `:resource`, `:file`, `:line`, and `:tags`, initialized from + # values in this object. For possible options to pass (if any ????) see {Puppet::Transaction::Event}. + # @todo Needs a better explanation "Why should I care who is calling this method?", What do I need to know + # about events and how they work? Where can I read about them? + # @param options [Hash] options merged with a fixed set of options defined by this method, passed on to {Puppet::Transaction::Event}. + # @return [Puppet::Transaction::Event] the created event def event(options = {}) Puppet::Transaction::Event.new({:resource => self, :file => file, :line => line, :tags => tags}.merge(options)) end - # retrieve the 'should' value for a specified property + # @return [Object, nil] Returns the 'should' (wanted state) value for a specified property, or nil if the + # given attribute name is not a property (i.e. if it is a parameter, meta-parameter, or does not exist). def should(name) name = name.intern (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 + # Creates an instance to represent/manage the given attribute. + # Requires either the attribute name or class as the first argument, then an optional hash of # attributes to set during initialization. + # @todo The original comment is just wrong - the method does not accept a hash of options + # @todo Detective work required; this method interacts with provider to ask if it supports a parameter of + # the given class. it then returns the parameter if it exists, otherwise creates a parameter + # with its :resource => self. + # @overload newattr(name) + # @param name [String] Unclear what name is (probably a symbol) - Needs investigation. + # @overload newattr(klass) + # @param klass [Class] a class supported as an attribute class - Needs clarification what that means. + # @return [???] Probably returns a new instance of the class - Needs investigation. + # def newattr(name) if name.is_a?(Class) klass = name @@ -477,31 +746,46 @@ class Type @parameters[name] = klass.new(:resource => self) end - # return the value of a parameter + # Returns the value of this object's parameter given by name + # @param name [String] the name of the parameter + # @return [Object] the value def parameter(name) @parameters[name.to_sym] end + # Returns a shallow copy of this object's hash of parameters. + # @todo Add that this is not only "parameters", but also "properties" and "meta-parameters" ? + # Changes to the contained parameters will have an effect on the parameters of this type, but changes to + # the returned hash does not. + # @return [Hash{String => Puppet:???Parameter}] a new hash being a shallow copy of the parameters map name to parameter def parameters @parameters.dup end - # Is the named property defined? + # @return [Boolean] Returns whether the property given by name is defined or not. + # @todo what does it mean to be 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. + # Returns a {Puppet::Property} instance by name. + # To return the value, use 'resource[param]' + # @todo LAK:NOTE(20081028) Since the 'parameter' method is now a superset of this method, + # this one should probably go away at some point. - Does this mean it should be deprecated ? + # @return [Puppet::Property] the property with the given name, or nil if not a property or does not exist. def property(name) (obj = @parameters[name.intern] 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. + # @todo comment says "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." + # @todo Needs a better explanation, and investigation about the claim an array can be passed (it is passed + # to self.class.attrclass to produce a class on which a check is made if it has a method class :default (does + # not seem to support an array... + # @return [void] + # def set_default(attr) return unless klass = self.class.attrclass(attr) return unless klass.method_defined?(:default) @@ -516,7 +800,14 @@ class Type end end - # Convert our object to a hash. This just includes properties. + # @todo the comment says: "Convert our object to a hash. This just includes properties." + # @todo this is confused, again it is the @parameters instance variable that is consulted, and + # each value is copied - does it contain "properties" and "parameters" or both? Does it contain + # meta-parameters? + # + # @return [Hash{ ??? => ??? }] a hash of WHAT?. The hash is a shallow copy, any changes to the + # objects returned in this hash will be reflected in the original resource having these attributes. + # def to_hash rethash = {} @@ -527,31 +818,47 @@ class Type rethash end + # @return [String] the name of this object's class + # @todo Would that be "file" for the "File" resource type? of "File" or something else? + # def type self.class.name end - # Return a specific value for an attribute. + # @todo Comment says "Return a specific value for an attribute.", as opposed to what "An upspecific value"??? + # @todo is this the 'is' or the 'should' value? + # @todo why is the return restricted to things that respond to :value? (Only non structural basic data types + # supported? + # + # @return [Object, nil] the value of the attribute having the given name, or nil if the given name is not + # an attribute, or the referenced attribute does not respond to `:value`. def value(name) name = name.intern (obj = @parameters[name] and obj.respond_to?(:value)) ? obj.value : nil end + # @todo What is this used for? Needs a better explanation. + # @return [???] the version of the catalog or 0 if there is no catalog. def version return 0 unless catalog catalog.version end - # Return all of the property objects, in the order specified in the - # class. + # @return [Array<Puppet::Property>] Returns all of the property objects, in the order specified in the + # class. + # @todo "what does the 'order specified in the class' mean? The order the properties where added in the + # ruby file adding a new type with new properties? + # 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? + # Returns true if the type's notion of name is the identity of a resource. + # See the overview of this class for a longer explanation of the concept _isomorphism_. # Defaults to true. + # + # @return [Boolan] true, if this type's name is isomorphic with the object def self.isomorphic? if defined?(@isomorphic) return @isomorphic @@ -560,14 +867,18 @@ class Type end end + # @todo check that this gets documentation (it is at the class level as well as instance). + # (see isomorphic?) 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 + # Returns true if the instance is 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. + # @note An object that is managed always stays managed, but an object that is not managed + # may become managed later in its lifecycle. + # @return [Boolean] true if the object is managed 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, @@ -590,12 +901,25 @@ class Type ############################### # Code related to the container behaviour. + + # Returns true if the search should be done in depth-first order. + # This implementation always returns false. + # @todo What is this used for? + # + # @return [Boolean] true if the search should be done in depth first order. + # def depthfirst? false end - # Remove an object. The argument determines whether the object's - # subscriptions get eliminated, too. + # Removes this object (FROM WHERE?) + # @todo removes if from where? + # @overload remove(rmdeps) + # @deprecated Use remove() + # @param rmdeps [Boolean] intended to indicate that all subscriptions should also be removed, ignored. + # @overload remove() + # @return [void] + # def remove(rmdeps = true) # This is hackish (mmm, cut and paste), but it works for now, and it's # better than warnings. @@ -616,19 +940,32 @@ class Type ############################### # Code related to evaluating the resources. + + # Returns the ancestors - WHAT? + # This implementation always returns an empty list. + # @todo WHAT IS THIS ? + # @return [Array<???>] returns a list of ancestors. def ancestors [] end - # Flush the provider, if it supports it. This is called by the - # transaction. + # Flushes the provider if supported by the provider, else no action. + # This is called by the transaction. + # @todo What does Flushing the provider mean? Why is it interesting to know that this is + # called by the transaction? (It is not explained anywhere what a transaction is). + # + # @return [???, nil] WHAT DOES IT RETURN? GUESS IS VOID 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 + # Returns true if all contained objects are in sync. + # @todo "contained in what?" in the given "in" parameter? + # + # @todo deal with the comment _"FIXME I don't think this is used on the type instances any more, + # it's really only used for testing"_ + # @return [Boolean] true if in sync, false otherwise. + # def insync?(is) insync = true @@ -662,7 +999,12 @@ class Type insync end - # retrieve the current value of all contained properties + # Retrieves the current value of all contained properties. + # Parameters and meta-parameters are not included in the result. + # @todo As oposed to all non contained properties? How is this different than any of the other + # methods that also "gets" properties/parameters/etc. ? + # @return [Array<Object>] array of all property values (mix of types) + # @raise [fail???] if there is a provider and it is not suitable for the host this is evaluated for. def retrieve fail "Provider #{provider.class.name} is not functional on this host" if self.provider.is_a?(Puppet::Provider) and ! provider.class.suitable? @@ -689,15 +1031,22 @@ class Type result end + # ??? + # @todo what does this do? It seems to create a new Resource based on the result of calling #retrieve + # and if that is a Hash, else this method produces nil. + # @return [Puppet::Resource, nil] a new Resource, or nil, if this object did not produce a Hash as the + # result from #retrieve + # 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. + # Returns a hash of the current properties and their values. + # If a resource is absent, it's value is the symbol `:absent` + # @return [Hash{Puppet::Property => Object}] mapping of property instance to its 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' @@ -719,7 +1068,8 @@ class Type end end - # Are we running in noop mode? + # Returns the `noop` run mode status of this. + # @return [Boolean] true if running in noop mode. def noop? # If we're not a host_config, we're almost certainly part of # Settings, and we want to ignore 'noop' @@ -732,11 +1082,15 @@ class Type end end + # (see #noop?) def noop noop? end - # Retrieve all known instances. Either requires providers or must be overridden. + # Retrieves all known instances. + # @todo Retrieves them from where? Known to whom? + # Either requires providers or must be overridden. + # @raise [Puppet::DevError] when there are no providers and the implementation has not overridded this method. def self.instances raise Puppet::DevError, "#{self.name} has no providers and has not overridden 'instances'" if provider_hash.empty? @@ -766,7 +1120,10 @@ class Type end.flatten.compact end - # Return a list of one suitable provider per source, with the default provider first. + # Returns a list of one suitable provider per source, with the default provider first. + # @todo Needs better explanation; what does "source" mean in this context? + # @return [Array<Puppet::Provider>] list of providers + # def self.providers_by_source # Put the default provider first (can be nil), then the rest of the suitable providers. sources = [] @@ -779,7 +1136,11 @@ class Type end.compact end - # Convert a simple hash into a Resource instance. + # Converts a simple hash into a Resource instance. + # @todo as opposed to a complex hash? Other raised exceptions? + # @param [Hash{Symbol, String => Object}] resource attribute to value map to initialize the created resource from + # @return [Puppet::Resource] the resource created from the hash + # @raise [Puppet::Error] if a title is missing in the given hash def self.hash2resource(hash) hash = hash.inject({}) { |result, ary| result[ary[0].to_sym] = ary[1]; result } @@ -804,7 +1165,10 @@ class Type resource end - # Create the path for logging and such. + # Creates the path for logging and such. + # @todo "and such?", what? + # @api private + # def pathbuilder if p = parent [p.pathbuilder, self.ref].flatten @@ -814,7 +1178,7 @@ class Type end ############################### - # Add all of the meta parameters. + # Add all of the meta-parameters. newmetaparam(:noop) do desc "Boolean flag indicating whether work should actually be done." @@ -1009,6 +1373,10 @@ class Type end end + # RelationshipMetaparam is an implementation supporting the meta-parameters `:require`, `:subscribe`, + # `:notify`, and `:before`. + # + # class RelationshipMetaparam < Puppet::Parameter class << self attr_accessor :direction, :events, :callback, :subclasses @@ -1020,6 +1388,7 @@ class Type @subclasses << sub end + # @return [Array<Puppet::Resource>] turns attribute value(s) into list of resources def munge(references) references = [references] unless references.is_a?(Array) references.collect do |ref| @@ -1031,6 +1400,10 @@ class Type end end + # Checks each reference to assert that what it references exists in the catalog. + # + # @raise [???fail] if the referenced resource can not be found + # @return [void] def validate_relationship @value.each do |ref| unless @resource.catalog.resource(ref.to_s) @@ -1040,14 +1413,19 @@ class Type 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 + # Creates edges for all relationships. + # The `:in` relationships are specified by the event-receivers, and `:out` + # relationships are specified by the event generator. + # @todo references to "event-receivers" and "event generator" means in this context - are those just + # the resources at the two ends of the relationship? + # This way 'source' and 'target' are consistent terms in both edges + # and events, i.e. 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. + # @return [Array<Puppet::Relationship>] + # @raise [???fail] when a reference can not be resolved + # def to_edges @value.collect do |reference| reference.catalog = resource.catalog @@ -1086,6 +1464,8 @@ class Type end end + # @todo document this, have no clue what this does... it retuns "RelationshipMetaparam.subclasses" + # def self.relationship_params RelationshipMetaparam.subclasses end @@ -1236,15 +1616,33 @@ class Type # Add the feature handling module. extend Puppet::Util::ProviderFeatures + # The provider that has been selected for the instance of the resource type. + # @return [Puppet::Provider,nil] the selected provider or nil, if none has been selected + # attr_reader :provider # the Type class attribute accessors class << self + # The loader of providers to use when loading providers from disk. + # Although it looks like this attribute provides a way to operate with different loaders of + # providers that is not the case; the attribute is written when a new type is created, + # and should not be changed thereafter. + # @api private + # attr_accessor :providerloader + + # @todo Don't know if this is a name, or a reference to a Provider instance (now marked up as an instance + # of Provider. + # @return [Puppet::Provider, nil] The default provider for this type, or nil if non is defines + # attr_writer :defaultprovider end - # Find the default provider. + # The default provider, or the most suitable provider if no default provider was set. + # @note a warning will be issued if no default provider has been configured and a search for the most + # suitable provider returns more than one equally suitable provider. + # @return [Puppet::Provider, nil] the default or most suitable provider, or nil if no provider was found + # def self.defaultprovider return @defaultprovider if @defaultprovider @@ -1267,16 +1665,26 @@ class Type @defaultprovider = defaults.shift unless defaults.empty? end + # @return [Hash{??? => Puppet::Provider}] Returns a hash of WHAT EXACTLY for the given type + # @todo what goes into this hash? def self.provider_hash_by_type(type) @provider_hashes ||= {} @provider_hashes[type] ||= {} end + # @return [Hash{ ??? => Puppet::Provider}] Returns a hash of WHAT EXACTLY for this type. + # @see provider_hash_by_type method to get the same for some other type def self.provider_hash Puppet::Type.provider_hash_by_type(self.name) end - # Retrieve a provider by name. + # Returns the provider having the given name. + # This will load a provider if it is not already loaded. The returned provider is the first found provider + # having the given name, where "first found" semantics is defined by the {providerloader} in use. + # + # @param name [String] the name of the provider to get + # @return [Puppet::Provider, nil] the found provider, or nil if no provider of the given name was found + # def self.provider(name) name = name.intern @@ -1285,19 +1693,41 @@ class Type provider_hash[name] end - # Just list all of the providers. + # Returns a list of loaded providers by name. + # This method will not load/search for available providers. + # @return [Array<String>] list of loaded provider names + # def self.providers provider_hash.keys end + # Returns true if the given name is a reference to a provider and if this is a suitable provider for + # this type. + # @todo How does the provider know if it is suitable for the type? Is it just suitable for the platform/ + # environment where this method is executing? + # @param name [String] the name of the provider for which validity is checked + # @return [Boolean] true if the given name references a provider that is suitable + # def self.validprovider?(name) name = name.intern (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. + # Creates a new provider of a type. + # This method must be called directly on the type that it's implementing. + # @todo Fix Confusing Explanations! + # Is this a new provider of a Type (metatype), or a provider of an instance of Type (a resource), or + # a Provider (the implementation of a Type's behavior). CONFUSED. It calls magically named methods like + # "providify" ... + # @param name [String, Symbol] the name of the WHAT? provider? type? + # @param options [Hash{Symbol => Object}] a hash of options, used by this method, and passed on to {#genclass}, (see + # it for additional options to pass). + # @option options [Puppet::Provider] :parent the parent provider (what is this?) + # @option options [Puppet::Type] :resource_type the resource type, defaults to this type if unspecified + # @return [Puppet::Provider] a provider ??? + # @raise [Puppet::DevError] when the parent provider could not be found. + # def self.provide(name, options = {}, &block) name = name.intern @@ -1339,8 +1769,9 @@ class Type provider end - # Make sure we have a :provider parameter defined. Only gets called if there - # are providers. + # Ensures there is a `:provider` parameter defined. + # Should only be called if there are providers. + # @return [void] def self.providify return if @paramhash.has_key? :provider @@ -1358,10 +1789,14 @@ class Type # This is so we can refer back to the type to get a list of # providers for documentation. class << self + # The reference to a parent type for the parameter `:provider` used to get a list of + # providers for documentation purposes. + # attr_accessor :parenttype end - # We need to add documentation for each provider. + # Provides the ability to add documentation to a provider. + # def self.doc # Since we're mixing @doc with text from other sources, we must normalize # its indentation with scrub. But we don't need to manually scrub the @@ -1373,6 +1808,8 @@ class Type }.join end + # @todo this does what? where and how? + # @returns [String] the name of the provider defaultto { prov = @resource.class.defaultprovider prov.name if prov @@ -1401,6 +1838,9 @@ class Type end.parenttype = self end + # @todo this needs a better explanation + # Removes the implementation class of a given provider. + # @return [Object] returns what {Puppet::Util::ClassGen#rmclass} returns def self.unprovide(name) if @defaultprovider and @defaultprovider.name == name @defaultprovider = nil @@ -1409,7 +1849,12 @@ class Type rmclass(name, :hash => provider_hash, :prefix => "Provider") end - # Return an array of all of the suitable providers. + # Returns a list of suitable providers for the given type. + # A call to this method will load all providers if not already loaded and ask each if it is + # suitable - those that are are included in the result. + # @note This method also does some special processing which rejects a provider named `:fake` (for testing purposes). + # @return [Array<Puppet::Provider>] Returns an array of all suitable providers. + # def self.suitableprovider providerloader.loadall if provider_hash.empty? provider_hash.find_all { |name, provider| @@ -1419,6 +1864,9 @@ class Type }.reject { |p| p.name == :fake } # For testing end + # @return [Boolean] Returns true if this is something else than a `:provider`, or if it + # is a provider and it is suitable, or if there is a default provider. Otherwise, false is returned. + # def suitable? # If we don't use providers, then we consider it suitable. return true unless self.class.paramclass(:provider) @@ -1437,6 +1885,16 @@ class Type false end + # Sets the provider to the given provider/name. + # @overload provider=(name) + # Sets the provider to the result of resolving the name to an instance of Provider. + # @param name [String] the name of the provider + # @overload provider=(provider) + # Sets the provider to the given instances of Provider. + # @param provider [Puppet::Provider] the provider to set + # @return [Puppet::Provider] the provider set + # @raise [ArgumentError] if the provider could not be found/resolved. + # def provider=(name) if name.is_a?(Puppet::Provider) @provider = name @@ -1451,15 +1909,30 @@ class Type ############################### # 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. + + # Adds a block producing a single name (or list of names) of the given resource type name to autorequire. + # @example Autorequire the files File['foo', 'bar'] + # autorequire( 'file', {|| ['foo', 'bar'] }) + # + # @todo original = _"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."_ + # @param name [String] the name of a type of which one or several resources should be autorequired e.g. "file" + # @yield [ ] a block returning list of names of given type to auto require + # @yieldreturn [String, Array<String>] one or several resource names for the named type + # @return [void] + # @dsl type + # @api public + # def self.autorequire(name, &block) @autorequires ||= {} @autorequires[name] = block end - # Yield each of those autorequires in turn, yo. + # Provides iteration over added auto-requirements (see {autorequire}). + # @yieldparam type [String] the name of the type to autoriquire an instance of + # @yieldparam block [Proc] a block producing one or several dependencies to auto require (see {autorequire}). + # @yieldreturn [void] + # @return [void] def self.eachautorequire @autorequires ||= {} @autorequires.each { |type, block| @@ -1467,8 +1940,13 @@ class Type } end - # Figure out of there are any objects we can automatically add as - # dependencies. + # Adds dependencies to the catalog from added autorequirements. + # See {autorequire} for how to add an auto-requirement. + # @todo needs details - see the param rel_catalog, and type of this param + # @param rel_catalog [Puppet::Catalog, nil] the catalog to add dependencies to. Defaults to the + # catalog (TODO: what is the type of the catalog). + # @raise [Puppet::DevError] if there is no catalog + # def autorequire(rel_catalog = nil) rel_catalog ||= catalog raise(Puppet::DevError, "You cannot add relationships without a catalog") unless rel_catalog @@ -1499,7 +1977,12 @@ class Type reqs end - # Build the dependencies associated with an individual object. + # Builds the dependencies associated with an individual object. + # @todo Which object is the "individual object", as opposed to "object as a group?" or should it simply + # be "this object" as in "this resource" ? + # @todo Does this method "build dependencies" or "build what it depends on" ... CONFUSING + # + # @return [Array<???>] list of WHAT? resources? edges? def builddepends # Handle the requires self.class.relationship_params.collect do |klass| @@ -1509,21 +1992,40 @@ class Type end.flatten.reject { |r| r.nil? } end - # Define the initial list of tags. + # Sets the initial list of tags... + # @todo The initial list of tags, that ... that what? + # @return [void] ??? 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. + # @comment - these two comments were floating around here, and turned up as documentation + # for the attribute "title", much to my surprise and amusement. Clearly these comments + # are orphaned ... I think they can just be removed as what they say should be covered + # by the now added yardoc. <irony>(Yo! to quote some of the other actual awsome specific comments applicable + # to objects called from elsewhere, or not. ;-)</irony> + # + # @comment 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. + + # @comment 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. + + + # The title attribute of WHAT ??? + # @todo Figure out what this is the title attribute of (it appears on line 1926 currently). + # @return [String] the title attr_writer :title + + # The noop attribute of WHAT ??? does WHAT??? + # @todo Figure out what this is the noop attribute of (it appears on line 1931 currently). + # @return [???] the noop WHAT ??? (mode? if so of what, or noop for an instance of the type, or for all + # instances of a type, or for what??? + # attr_writer :noop include Enumerable @@ -1532,9 +2034,14 @@ class Type public - # the Type class attribute accessors + # The Type class attribute accessors class << self + # @return [String] the name of the resource type; e.g., "File" + # attr_reader :name + + # @return [Boolean] true if the type should send itself a refresh event on change. + # attr_accessor :self_refresh include Enumerable, Puppet::Util::ClassGen include Puppet::MetaType::Manager @@ -1543,7 +2050,9 @@ class Type include Puppet::Util::Logging end - # all of the variables that must be initialized for each subclass + # Initializes all of the variables that must be initialized for each subclass. + # @todo Does the explanation make sense? + # @return [void] def self.initvars # all of the instances of this class @objects = Hash.new @@ -1571,6 +2080,11 @@ class Type end + # Returns the name of this type (if specified) or the parent type #to_s. + # The returned name is on the form "Puppet::Type::<name>", where the first letter of name is + # capitalized. + # @return [String] the fully qualified name Puppet::Type::<name> where the first letter of name is captialized + # def self.to_s if defined?(@name) "Puppet::Type::#{@name.to_s.capitalize}" @@ -1579,26 +2093,42 @@ class Type end end - # Create a block to validate that our object is set up entirely. This will - # be run before the object is operated on. + # Creates a `validate` method that is used to validate a resource before it is operated on. + # The validation should raise exceptions if the validation finds errors. (It is not recommended to + # issue warnings as this typically just ends up in a logfile - you should fail if a validation fails). + # The easiest way to raise an appropriate exception is to call the method {Puppet::Util::Errors.fail} with + # the message as an argument. + # + # @yield [ ] a required block called with self set to the instance of a Type class representing a resource. + # @return [void] + # @dsl type + # @api public + # def self.validate(&block) define_method(:validate, &block) #@validate = block end - # Origin information. - attr_accessor :file, :line + # @return [String] The file from which this type originates from + attr_accessor :file + + # @return [Integer] The line in {#file} from which this type originates from + attr_accessor :line - # The catalog that this resource is stored in. + # @todo what does this mean "this resource" (sounds like this if for an instance of the type, not the meta Type), + # but not sure if this is about the catalog where the meta Type is included) + # @return [??? TODO] The catalog that this resource is stored in. attr_accessor :catalog - # is the resource exported + # @return [Boolean] Flag indicating if this type is exported attr_accessor :exported - # is the resource virtual (it should not :-)) + # @return [Boolean] Flag indicating if the type is virtual (it should not be). attr_accessor :virtual - # create a log at specified level + # Creates a log entry with the given message at the log level specified by the parameter `loglevel` + # @return [void] + # def log(msg) Puppet::Util::Log.create( @@ -1616,9 +2146,24 @@ class Type public + # @return [Hash] hash of parameters originally defined + # @api private attr_reader :original_parameters - # initialize the type instance + # Creates an instance of Type from a hash or a {Puppet::Resource}. + # @todo Unclear if this is a new Type or a new instance of a given type (the initialization ends + # with calling validate - which seems like validation of an instance of a given type, not a new + # meta type. + # + # @todo Explain what the Hash and Resource are. There seems to be two different types of + # resources; one that causes the title to be set to resource.title, and one that + # causes the title to be resource.ref ("for components") - what is a component? + # + # @overaload initialize(hsh) + # @param hsh [Hash] + # @overload initialize(resource) + # @param resource [Puppet:Resource] + # def initialize(resource) resource = self.class.hash2resource(resource) unless resource.is_a?(Puppet::Resource) @@ -1655,12 +2200,32 @@ class Type private - # Set our resource's name. + # Sets the name of the resource from a hash containing a mapping of `name_var` to value. + # Sets the value of the property/parameter appointed by the `name_var` (if it is defined). The value set is + # given by the corresponding entry in the given hash - e.g. if name_var appoints the name `:path` the value + # of `:path` is set to the value at the key `:path` in the given hash. As a side effect this key/value is then + # removed from the given hash. + # + # @note This method mutates the given hash by removing the entry with a key equal to the value + # returned from name_var! + # @param hash [Hash] a hash of what + # @return [void] 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. + # Sets parameters from the given hash. + # Values are set in _attribute order_ i.e. higher priority attributes before others, otherwise in + # the order they were specified (as opposed to just setting them in the order they happen to appear in + # when iterating over the given hash). + # + # Attributes that are not included in the given hash are set to their default value. + # + # @todo Is this description accurate? Is "ensure" an example of such a higher priority attribute? + # @return [void] + # @raise [Puppet::DevError] when impossible to set the value due to some problem + # @raise [ArgumentError, TypeError, Puppet::Error] when faulty arguments have been passed + # def set_parameters(hash) # Use the order provided by allattrs, but add in any # extra attributes from the resource so we get failures @@ -1691,7 +2256,14 @@ class Type public - # Set up all of our autorequires. + # Finishes any outstanding processing. + # This method should be called as a final step in setup, + # to allow the parameters that have associated auto-require needs to be processed. + # + # @todo what is the expected sequence here - who is responsible for calling this? When? + # Is the returned type correct? + # @return [Array<Puppet::Parameter>] the validated list/set of attributes + # def finish # Make sure all of our relationships are valid. Again, must be done # when the entire catalog is instantiated. @@ -1702,13 +2274,22 @@ class Type 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. + # @comment For now, leave the 'name' method functioning like it used to. Once 'title' + # works everywhere, I'll switch it. + # Returns the resource's name + # @todo There is a comment in source that this is not quite the same as ':title' and that a switch should + # be made... + # @return [String] the name of a resource def name self[:name] end - # Look up our parent in the catalog, if we have one. + # Returns the parent of this in the catalog. + # In case of an erroneous catalog where multiple parents have been produced, the first found (non deterministic) + # parent is returned. + # @return [???, nil] WHAT (which types can be the parent of a resource in a catalog?), or nil if there + # is no catalog. + # def parent return nil unless catalog @@ -1724,24 +2305,36 @@ class Type @parent end - # Return the "type[name]" style reference. + # Returns a reference to this as a string in "Type[name]" format. + # @return [String] a reference to this object on the form 'Type[name]' + # def ref # memoizing this is worthwhile ~ 3 percent of calls are the "first time # around" in an average run of Puppet. --daniel 2012-07-17 @ref ||= "#{self.class.name.to_s.capitalize}[#{self.title}]" end + # (see self_refresh) + # @todo check that meaningful yardoc is produced - this method delegates to "self.class.self_refresh" + # @return [Boolean] - ??? returns true when ... what? + # def self_refresh? self.class.self_refresh end - # Mark that we're purging. + # Marks the object as "being purged". + # This method is used by transactions to forbid deletion when there are dependencies. + # @todo what does this mean; "mark that we are purging" (purging what from where). How to use/when? + # Is this internal API in transactions? + # @see purging? def purging @purging = true end - # Is this resource being purged? Used by transactions to forbid - # deletion when there are dependencies. + # Returns whether this resource is being purged or not. + # This method is used by transactions to forbid deletion when there are dependencies. + # @return [Boolean] the current "purging" state + # def purging? if defined?(@purging) @purging @@ -1750,8 +2343,15 @@ class Type end end - # Retrieve the title of an object. If no title was set separately, - # then use the object's name. + # Returns the title of this object, or it's name if title was not explicetly set. + # If the title is not already set, it will be computed by looking up the {#name_var} and using + # that value as the title. + # @todo it is somewhat confusing that if the name_var is a valid parameter, it is assumed to + # be the name_var called :name, but if it is a property, it uses the name_var. + # It is further confusing as Type in some respects supports multiple namevars. + # + # @return [String] Returns the title of this object, or it's name if title was not explicetly set. + # @raise [??? devfail] if title is not set, and name_var can not be found. def title unless @title if self.class.validparameter?(name_var) @@ -1766,11 +2366,16 @@ class Type @title end - # convert to a string + # Produces a reference to this in reference format. + # @see #ref + # def to_s self.ref end + # @todo What to resource? Which one of the resource forms is prroduced? returned here? + # @return [??? Resource] a resource that WHAT??? + # def to_resource resource = self.retrieve_resource resource.tag(*self.tags) @@ -1787,13 +2392,21 @@ class Type resource end + # @return [Boolean] Returns whether the resource is virtual or not def virtual?; !!@virtual; end + # @return [Boolean] Returns whether the resource is exported or not def exported?; !!@exported; end + # @return [Boolean] Returns whether the resource is applicable to `:device` + # @todo Explain what this means + # @api private def appliable_to_device? self.class.can_apply_to(:device) end + # @return [Boolean] Returns whether the resource is applicable to `:host` + # @todo Explain what this means + # @api private def appliable_to_host? self.class.can_apply_to(:host) end diff --git a/lib/puppet/type/augeas.rb b/lib/puppet/type/augeas.rb index ce2163874..75c8142f2 100644 --- a/lib/puppet/type/augeas.rb +++ b/lib/puppet/type/augeas.rb @@ -116,6 +116,10 @@ Puppet::Type.newtype(:augeas) do : Sets the node at `PATH` to `NULL`, creating it if needed + `clearm <PATH> <SUB>` + : Sets multiple nodes (matching `SUB` relative to `PATH`) to `NULL` + + `ins <LABEL> (before|after) <PATH>` : Inserts an empty node `LABEL` either before or after `PATH`. diff --git a/lib/puppet/type/file/ensure.rb b/lib/puppet/type/file/ensure.rb index c68c0669c..e8a9150b0 100755 --- a/lib/puppet/type/file/ensure.rb +++ b/lib/puppet/type/file/ensure.rb @@ -68,7 +68,7 @@ module Puppet end if mode Puppet::Util.withumask(000) do - Dir.mkdir(@resource[:path], symbolic_mode_to_int(mode, 755, true)) + Dir.mkdir(@resource[:path], symbolic_mode_to_int(mode, 0755, true)) end else Dir.mkdir(@resource[:path]) diff --git a/lib/puppet/type/file/group.rb b/lib/puppet/type/file/group.rb index a90499605..a1ae66518 100755 --- a/lib/puppet/type/file/group.rb +++ b/lib/puppet/type/file/group.rb @@ -1,7 +1,7 @@ require 'puppet/util/posix' -# Manage file group ownership. module Puppet + # Manage file group ownership. Puppet::Type.type(:file).newproperty(:group) do desc <<-EOT Which group should own the file. Argument can be either a group diff --git a/lib/puppet/type/file/mode.rb b/lib/puppet/type/file/mode.rb index 9e4ad8eec..7c9f23150 100755 --- a/lib/puppet/type/file/mode.rb +++ b/lib/puppet/type/file/mode.rb @@ -1,6 +1,8 @@ # Manage file modes. This state should support different formats # 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 'puppet/util/symbolic_file_mode' diff --git a/lib/puppet/type/file/selcontext.rb b/lib/puppet/type/file/selcontext.rb index 03ee5b9e2..580dbbf28 100644 --- a/lib/puppet/type/file/selcontext.rb +++ b/lib/puppet/type/file/selcontext.rb @@ -19,6 +19,7 @@ # # See http://www.nsa.gov/selinux/ for complete docs on SELinux. + module Puppet require 'puppet/util/selinux' diff --git a/lib/puppet/type/group.rb b/lib/puppet/type/group.rb index 819c6dcc5..19a0b2daf 100755 --- a/lib/puppet/type/group.rb +++ b/lib/puppet/type/group.rb @@ -145,5 +145,17 @@ module Puppet defaultto false end + + # This method has been exposed for puppet to manage users and groups of + # files in its settings and should not be considered available outside of + # puppet. + # + # (see Puppet::Settings#service_group_available?) + # + # @returns [Boolean] if the group exists on the system + # @api private + def exists? + provider.exists? + end end end diff --git a/lib/puppet/type/mount.rb b/lib/puppet/type/mount.rb index 8a6edb93f..b3598965d 100755 --- a/lib/puppet/type/mount.rb +++ b/lib/puppet/type/mount.rb @@ -15,7 +15,7 @@ module Puppet # 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 + `unmounted` 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 @@ -207,7 +207,7 @@ module Puppet newvalues(:true, :false) defaultto do case Facter.value(:operatingsystem) - when "FreeBSD", "Darwin", "AIX" + when "FreeBSD", "Darwin", "AIX", "DragonFly" false else true diff --git a/lib/puppet/type/notify.rb b/lib/puppet/type/notify.rb index 98da694d7..606df84cf 100644 --- a/lib/puppet/type/notify.rb +++ b/lib/puppet/type/notify.rb @@ -1,6 +1,6 @@ # # Simple module for logging messages on the client-side -# + module Puppet newtype(:notify) do diff --git a/lib/puppet/type/router.rb b/lib/puppet/type/router.rb index 6cd267b2d..06be96054 100644 --- a/lib/puppet/type/router.rb +++ b/lib/puppet/type/router.rb @@ -1,6 +1,6 @@ # # Manage a router abstraction -# + module Puppet newtype(:router) do diff --git a/lib/puppet/type/service.rb b/lib/puppet/type/service.rb index 6e32ed5b9..f15cf14cf 100644 --- a/lib/puppet/type/service.rb +++ b/lib/puppet/type/service.rb @@ -4,6 +4,7 @@ # can only be managed through the interface of an init script # which is why they have a search path for initscripts and such + module Puppet newtype(:service) do diff --git a/lib/puppet/type/ssh_authorized_key.rb b/lib/puppet/type/ssh_authorized_key.rb index 24ca62ad2..a761bc03b 100644 --- a/lib/puppet/type/ssh_authorized_key.rb +++ b/lib/puppet/type/ssh_authorized_key.rb @@ -27,7 +27,9 @@ module Puppet end newproperty(:key) do - desc "The key itself; generally a long string of hex digits." + desc "The public key itself; generally a long string of hex characters. The key attribute + may not contain whitespace: Omit key headers (e.g. 'ssh-rsa') and key identifiers + (e.g. 'joe@joescomputer.local') found in the public key file." validate do |value| raise Puppet::Error, "Key must not contain whitespace: #{value}" if value =~ /\s/ diff --git a/lib/puppet/type/user.rb b/lib/puppet/type/user.rb index 4e79971b7..509b0deb4 100755 --- a/lib/puppet/type/user.rb +++ b/lib/puppet/type/user.rb @@ -355,7 +355,14 @@ module Puppet autos end - # Provide an external hook. Yay breaking out of APIs. + # This method has been exposed for puppet to manage users and groups of + # files in its settings and should not be considered available outside of + # puppet. + # + # (see Puppet::Settings#service_user_available?) + # + # @returns [Boolean] if the user exists on the system + # @api private def exists? provider.exists? end diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index ce0f335b6..ef32e60d4 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -185,6 +185,13 @@ module Util end end + # Resolve a path for an executable to the absolute path. This tries to behave + # in the same manner as the unix `which` command and uses the `PATH` + # environment variable. + # + # @api public + # @param bin [String] the name of the executable to find. + # @return [String] the absolute path to the found executable. def which(bin) if absolute_path?(bin) return bin if FileTest.file? bin and FileTest.executable? bin @@ -489,6 +496,7 @@ module Util # Executes a block of code, wrapped with some special exception handling. Causes the ruby interpreter to # exit if the block throws an exception. # + # @api public # @param [String] message a message to log if the block fails # @param [Integer] code the exit code that the ruby interpreter should return if the block fails # @yield diff --git a/lib/puppet/util/autoload.rb b/lib/puppet/util/autoload.rb index d85030281..059202190 100644 --- a/lib/puppet/util/autoload.rb +++ b/lib/puppet/util/autoload.rb @@ -19,13 +19,6 @@ class Puppet::Util::Autoload @gem_source ||= Puppet::Util::RubyGems::Source.new end - # List all loaded files. - def list_loaded - loaded.keys.sort { |a,b| a[0] <=> b[0] }.collect do |path, hash| - "#{path}: #{hash[:file]}" - end - 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 @@ -205,7 +198,7 @@ class Puppet::Util::Autoload end def load(name, env=nil) - self.class.load_file(File.join(@path, name.to_s), env) + self.class.load_file(expand(name), env) end # Load all instances that we can. This uses require, rather than load, @@ -215,14 +208,18 @@ class Puppet::Util::Autoload end def loaded?(name) - self.class.loaded?(File.join(@path, name.to_s)) + self.class.loaded?(expand(name)) end def changed?(name) - self.class.changed?(File.join(@path, name.to_s)) + self.class.changed?(expand(name)) end def files_to_load self.class.files_to_load(@path) end + + def expand(name) + ::File.join(@path, name.to_s) + end end diff --git a/lib/puppet/util/classgen.rb b/lib/puppet/util/classgen.rb index 7993e695b..e03bf2ab7 100644 --- a/lib/puppet/util/classgen.rb +++ b/lib/puppet/util/classgen.rb @@ -3,51 +3,66 @@ module Puppet class SubclassAlreadyDefined < Error; end end +# This is a utility module for generating classes. +# @api public +# 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. + # Create a new class. + # @param name [String] the name of the generated class + # @param options [Hash] a hash of options + # @option options [Array<Class>] :array if specified, the generated class is appended to this array + # @option options [Hash<{String => Object}>] :attributes a hash that is applied to the generated class + # by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given + # block is evaluated. + # @option options [Proc] :block a block to evaluate in the context of the class (this block can be provided + # this way, or as a normal yield block). + # @option options [String] :constant (name with first letter capitalized) what to set the constant that references + # the generated class to. + # @option options [Hash] :hash a hash of existing classes that this class is appended to (name => class). + # This hash must be specified if the `:overwrite` option is set to `true`. + # @option options [Boolean] :overwrite whether an overwrite of an existing class should be allowed (requires also + # defining the `:hash` with existing classes as the test is based on the content of this hash). + # @option options [Class] :parent (self) the parent class of the generated class. + # @option options [String] ('') :prefix the constant prefix to prepend to the constant name referencing the + # generated class. + # @return [Class] the generated class + # 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, + # Creates a new module. + # @param name [String] the name of the generated module + # @param optinos [Hash] hash with options + # @option options [Array<Class>] :array if specified, the generated class is appended to this array + # @option options [Hash<{String => Object}>] :attributes a hash that is applied to the generated class + # by calling setter methods corresponding to this hash's keys/value pairs. This is done before the given + # block is evaluated. + # @option options [Proc] :block a block to evaluate in the context of the class (this block can be provided + # this way, or as a normal yield block). + # @option options [String] :constant (name with first letter capitalized) what to set the constant that references + # the generated class to. + # @option options [Hash] :hash a hash of existing classes that this class is appended to (name => class). + # This hash must be specified if the `:overwrite` option is set to `true`. + # @option options [Boolean] :overwrite whether an overwrite of an existing class should be allowed (requires also + # defining the `:hash` with existing classes as the test is based on the content of this hash). # the capitalized name is appended and the result is set as the constant. + # @option options [String] ('') :prefix the constant prefix to prepend to the constant name referencing the + # generated class. + # @return [Module] the generated Module def genmodule(name, options = {}, &block) genthing(name, Module, options, block) end - # Remove an existing class + # Removes an existing class. + # @param name [String] the name of the class to remove + # @param options [Hash] options + # @option options [Hash] :hash a hash of existing classes from which the class to be removed is also removed + # @return [Boolean] whether the class was removed or not + # def rmclass(name, options) options = symbolize_options(options) const = genconst_string(name, options) @@ -68,7 +83,8 @@ module Puppet::Util::ClassGen private - # Generate the constant to create or remove. + # Generates the constant to create or remove. + # @api private def genconst_string(name, options) unless const = options[:constant] prefix = options[:prefix] || "" @@ -80,6 +96,7 @@ module Puppet::Util::ClassGen # This does the actual work of creating our class or module. It's just a # slightly abstract version of genclass. + # @api private def genthing(name, type, options, block) options = symbolize_options(options) @@ -128,6 +145,8 @@ module Puppet::Util::ClassGen # of which class hierarchy it polls for nested namespaces # # See http://redmine.ruby-lang.org/issues/show/1915 + # @api private + # def is_constant_defined?(const) if ::RUBY_VERSION =~ /1.9/ const_defined?(const, false) @@ -137,6 +156,8 @@ module Puppet::Util::ClassGen end # Handle the setting and/or removing of the associated constant. + # @api private + # def handleclassconst(klass, name, options) const = genconst_string(name, options) @@ -155,6 +176,8 @@ module Puppet::Util::ClassGen end # Perform the initializations on the class. + # @api private + # def initclass(klass, options) klass.initvars if klass.respond_to? :initvars @@ -178,11 +201,13 @@ module Puppet::Util::ClassGen end # Convert our name to a constant. + # @api private def name2const(name) name.to_s.capitalize end # Store the class in the appropriate places. + # @api private def storeclass(klass, klassname, options) if hash = options[:hash] if hash.include? klassname and ! options[:overwrite] diff --git a/lib/puppet/util/command_line.rb b/lib/puppet/util/command_line.rb index 92f6eb1bb..1612691e8 100644 --- a/lib/puppet/util/command_line.rb +++ b/lib/puppet/util/command_line.rb @@ -10,125 +10,168 @@ if not defined? ::Bundler end require 'puppet' +require 'puppet/util' require "puppet/util/plugins" require "puppet/util/rubygems" module Puppet module Util + # This is the main entry point for all puppet applications / faces; it + # is basically where the bootstrapping process / lifecycle of an app + # begins. class CommandLine + OPTION_OR_MANIFEST_FILE = /^-|\.pp$|\.rb$/ + # @param zero [String] the name of the executable + # @param argv [Array<String>] the arguments passed on the command line + # @param stdin [IO] (unused) def initialize(zero = $0, argv = ARGV, stdin = STDIN) - @zero = zero - @argv = argv.dup - @stdin = stdin - - @subcommand_name, @args = subcommand_and_args(@zero, @argv, @stdin) + @command = File.basename(zero, '.rb') + @argv = argv Puppet::Plugins.on_commandline_initialization(:command_line_object => self) end - attr :subcommand_name - attr :args + # @return [String] name of the subcommand is being executed + # @api public + def subcommand_name + return @command if @command != 'puppet' - def appdir - File.join('puppet', 'application') + if @argv.first =~ OPTION_OR_MANIFEST_FILE + nil + else + @argv.first + end end + # @return [Array<String>] the command line arguments being passed to the subcommand + # @api public + def args + return @argv if @command != 'puppet' + + if subcommand_name.nil? + @argv + else + @argv[1..-1] + end + end + + # @api private + # @deprecated def self.available_subcommands - # Eventually we probably want to replace this with a call to the - # autoloader. however, at the moment the autoloader considers the - # module path when loading, and we don't want to allow apps / faces to - # load from there. Once that is resolved, this should be replaced. - # --cprice 2012-03-06 - # - # But we do want to load from rubygems --hightower - search_path = Puppet::Util::RubyGems::Source.new.directories + $LOAD_PATH - absolute_appdirs = search_path.uniq.collect do |x| - File.join(x,'puppet','application') - end.select{ |x| File.directory?(x) } - absolute_appdirs.inject([]) do |commands, dir| - commands + Dir[File.join(dir, '*.rb')].map{|fn| File.basename(fn, '.rb')} - end.uniq + Puppet.deprecation_warning('Puppet::Util::CommandLine.available_subcommands is deprecated; please use Puppet::Application.available_application_names instead.') + Puppet::Application.available_application_names end + # available_subcommands was previously an instance method, not a class # method, and we have an unknown number of user-implemented applications # that depend on that behaviour. Forwarding allows us to preserve a # backward compatible API. --daniel 2011-04-11 + # @api private + # @deprecated def available_subcommands - self.class.available_subcommands - end - - def require_application(application) - require File.join(appdir, application) + Puppet.deprecation_warning('Puppet::Util::CommandLine#available_subcommands is deprecated; please use Puppet::Application.available_application_names instead.') + Puppet::Application.available_application_names end - # This is the main entry point for all puppet applications / faces; it - # is basically where the bootstrapping process / lifecycle of an app - # begins. + # Run the puppet subcommand. If the subcommand is determined to be an + # external executable, this method will never return and the current + # process will be replaced via {Kernel#exec}. + # + # @return [void] def execute - # Build up our settings - we don't need that until after version check. Puppet::Util.exit_on_fail("intialize global default settings") do - Puppet.settings.initialize_global_settings(args) + Puppet.initialize_settings(args) end - # OK, now that we've processed the command line options and the config - # files, we should be able to say that we definitively know where the - # libdir is... which means that we can now look for our available - # applications / subcommands / faces. + find_subcommand.run + end - if subcommand_name and available_subcommands.include?(subcommand_name) then - require_application subcommand_name - # This will need to be cleaned up to do something that is not so - # application-specific (i.e.. so that we can load faces). - # Longer-term, use the autoloader. See comments in - # #available_subcommands method above. --cprice 2012-03-06 - app = Puppet::Application.find(subcommand_name).new(self) - Puppet::Plugins.on_application_initialization(:application_object => self) + # @api private + def external_subcommand + Puppet::Util.which("puppet-#{subcommand_name}") + end - app.run - elsif ! execute_external_subcommand then - unless subcommand_name.nil? then - puts "Error: Unknown Puppet subcommand '#{subcommand_name}'" - end + private - # If the user is just checking the version, print that and exit - if @argv.include? "--version" or @argv.include? "-V" - puts Puppet.version - else - puts "See 'puppet help' for help on available puppet subcommands" - end + def find_subcommand + if subcommand_name.nil? + NilSubcommand.new(self) + elsif Puppet::Application.available_application_names.include?(subcommand_name) + ApplicationSubcommand.new(subcommand_name, self) + elsif path_to_subcommand = external_subcommand + ExternalSubcommand.new(path_to_subcommand, self) + else + UnknownSubcommand.new(subcommand_name, self) end end - def execute_external_subcommand - external_command = "puppet-#{subcommand_name}" + # @api private + class ApplicationSubcommand + def initialize(subcommand_name, command_line) + @subcommand_name = subcommand_name + @command_line = command_line + end + + def run + # For most applications, we want to be able to load code from the modulepath, + # such as apply, describe, resource, and faces. + # For agent, we only want to load pluginsync'ed code from libdir. + # For master, we shouldn't ever be loading per-enviroment code into the master's + # ruby process, but that requires fixing (#17210, #12173, #8750). So for now + # we try to restrict to only code that can be autoloaded from the node's + # environment. + if @subcommand_name != 'master' and @subcommand_name != 'agent' + Puppet::Node::Environment.new.each_plugin_directory do |dir| + $LOAD_PATH << dir unless $LOAD_PATH.include?(dir) + end + end - require 'puppet/util' - path_to_subcommand = Puppet::Util.which(external_command) - return false unless path_to_subcommand + app = Puppet::Application.find(@subcommand_name).new(@command_line) + Puppet::Plugins.on_application_initialization(:application_object => @command_line) - exec(path_to_subcommand, *args) + app.run + end end - private + # @api private + class ExternalSubcommand + def initialize(path_to_subcommand, command_line) + @path_to_subcommand = path_to_subcommand + @command_line = command_line + end + + def run + Kernel.exec(@path_to_subcommand, *@command_line.args) + end + end - def subcommand_and_args(zero, argv, stdin) - zero = File.basename(zero, '.rb') - - if zero == 'puppet' - case argv.first - # if they didn't pass a command, or passed a help flag, we will - # fall back to showing a usage message. we no longer default to - # 'apply' - when nil, "--help", "-h", /^-|\.pp$|\.rb$/ - [nil, argv] - else - [argv.first, argv[1..-1]] + # @api private + class NilSubcommand + def initialize(command_line) + @command_line = command_line + end + + def run + if @command_line.args.include? "--version" or @command_line.args.include? "-V" + puts Puppet.version + else + puts "See 'puppet help' for help on available puppet subcommands" end - else - [zero, argv] end end + # @api private + class UnknownSubcommand < NilSubcommand + def initialize(subcommand_name, command_line) + @subcommand_name = subcommand_name + super(command_line) + end + + def run + puts "Error: Unknown Puppet subcommand '#{@subcommand_name}'" + super + end + end end end end diff --git a/lib/puppet/util/constant_inflector.rb b/lib/puppet/util/constant_inflector.rb index ddc797a79..ff440ba34 100644 --- a/lib/puppet/util/constant_inflector.rb +++ b/lib/puppet/util/constant_inflector.rb @@ -5,6 +5,8 @@ # A common module for converting between constants and # file names. + + module Puppet module Util module ConstantInflector diff --git a/lib/puppet/util/execution.rb b/lib/puppet/util/execution.rb index c0baec0f3..5f0089303 100644 --- a/lib/puppet/util/execution.rb +++ b/lib/puppet/util/execution.rb @@ -6,16 +6,31 @@ module Puppet class ExecutionFailure < Puppet::Error end +# This module defines methods for execution of system commands. It is intented for inclusion +# in classes that needs to execute system commands. +# @api public module Util::Execution - # Execute the provided command with STDIN connected to a pipe, yielding the - # pipe object. That allows data to be fed to that subprocess. + # Executes the provided command with STDIN connected to a pipe, yielding the + # pipe object. + # This allows data to be fed to the subprocess. # # The command can be a simple string, which is executed as-is, or an Array, - # which is treated as a set of command arguments to pass through.# + # which is treated as a set of command arguments to pass through. # # In all cases this is passed directly to the shell, and STDOUT and STDERR # are connected together during execution. + # @param command [String, Array<String>] the command to execute as one string, or as parts in an array. + # the parts of the array are joined with one separating space between each entry when converting to + # the command line string to execute. + # @param failonfail [Boolean] (true) if the execution should fail with Exception on failure or not. + # @yield [pipe] to a block executing a subprocess + # @yieldparam pipe [IO] the opened pipe + # @yieldreturn [String] the output to return + # @raise [ExecutionFailure] if the executed chiled process did not exit with status == 0 and `failonfail` is + # `true`. + # @return [String] a string with the output from the subprocess executed by the given block + # def self.execpipe(command, failonfail = true) if respond_to? :debug debug "Executing '#{command}'" @@ -44,6 +59,9 @@ module Util::Execution output end + # Wraps execution of {execute} with mapping of exception to given exception (and output as argument). + # @raise [exception] under same conditions as {execute}, but raises the given `exception` with the output as argument + # @return (see execute) def self.execfail(command, exception) output = execute(command) return output @@ -51,35 +69,37 @@ module Util::Execution raise exception, output end + # Default empty options for {execute} + NoOptionsSpecified = {} - # Execute the desired command, and return the status and output. + # Executes the desired command, and return the status and output. # def execute(command, options) - # [command] an Array or String representing the command to execute. If it is + # @param command [Array<String>, String] the command to execute. If it is # an Array the first element should be the executable and the rest of the # elements should be the individual arguments to that executable. - # [options] a Hash optionally containing any of the following keys: - # :failonfail (see below) -- if this value is set to true, then this method will raise an error if the - # command is not executed successfully. - # :uid (default nil) -- the user id of the user that the process should be run as - # :gid (default nil) -- the group id of the group that the process should be run as - # :combine (see below) -- sets whether or not to combine stdout/stderr in the output - # :stdinfile (default nil) -- sets a file that can be used for stdin. Passing a string for stdin is not currently - # supported. - # :squelch (default false) -- if true, ignore stdout / stderr completely - # :override_locale (default true) -- by default (and if this option is set to true), we will temporarily override - # the user/system locale to "C" (via environment variables LANG and LC_*) while we are executing the command. - # This ensures that the output of the command will be formatted consistently, making it predictable for parsing. - # Passing in a value of false for this option will allow the command to be executed using the user/system locale. - # :custom_environment (default {}) -- a hash of key/value pairs to set as environment variables for the duration - # of the command + # @param options [Hash] a Hash of options + # @option options [Boolean] :failonfail if this value is set to true, then this method will raise an error if the + # command is not executed successfully. + # @option options [?] :uid (nil) the user id of the user that the process should be run as + # @option options [?] :gid (nil) the group id of the group that the process should be run as + # @option options [Boolean] :combine sets whether or not to combine stdout/stderr in the output + # @option options [String] :stdinfile (nil) sets a file that can be used for stdin. Passing a string for stdin is not currently + # supported. + # @option options [Boolean] :squelch (true) if true, ignore stdout / stderr completely. + # @option options [Boolean] :override_locale (true) by default (and if this option is set to true), we will temporarily override + # the user/system locale to "C" (via environment variables LANG and LC_*) while we are executing the command. + # This ensures that the output of the command will be formatted consistently, making it predictable for parsing. + # Passing in a value of false for this option will allow the command to be executed using the user/system locale. + # @option options [Hash<{String => String}>] :custom_environment ({}) a hash of key/value pairs to set as environment variables for the duration + # of the command. + # @return [String] output as specified by options + # @note Unfortunately, the default behavior for failonfail and combine (since + # 0.22.4 and 0.24.7, respectively) depend on whether options are specified + # or not. If specified, then failonfail and combine default to false (even + # when the options specified are neither failonfail nor combine). If no + # options are specified, then failonfail and combine default to true. + # @comment See commits efe9a833c and d32d7f30 # - # Unfortunately, the default behavior for failonfail and combine (since - # 0.22.4 and 0.24.7, respectively) depend on whether options are specified - # or not. If specified, then failonfail and combine default to false (even - # when the options specified are neither failonfail nor combine). If no - # options are specified, then failonfail and combine default to true. See - # commits efe9a833c and d32d7f30 - NoOptionsSpecified = {} def self.execute(command, options = NoOptionsSpecified) # specifying these here rather than in the method signature to allow callers to pass in a partial # set of overrides without affecting the default values for options that they don't pass in @@ -147,9 +167,10 @@ module Util::Execution output end - # get the path to the ruby executable (available via Config object, even if - # it's not in the PATH... so this is slightly safer than just using - # Puppet::Util.which) + # Returns the path to the ruby executable (available via Config object, even if + # it's not in the PATH... so this is slightly safer than just using Puppet::Util.which) + # @return [String] the path to the Ruby executable + # def self.ruby_path() File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'] + RbConfig::CONFIG['EXEEXT']). @@ -162,7 +183,10 @@ module Util::Execution end - # this is private method, see call to private_class_method after method definition + # This is private method. + # @comment see call to private_class_method after method definition + # @api private + # def self.execute_posix(command, options, stdin, stdout, stderr) child_pid = Puppet::Util.safe_posix_fork(stdin, stdout, stderr) do @@ -208,7 +232,10 @@ module Util::Execution private_class_method :execute_posix - # this is private method, see call to private_class_method after method definition + # This is private method. + # @comment see call to private_class_method after method definition + # @api private + # def self.execute_windows(command, options, stdin, stdout, stderr) command = command.map do |part| part.include?(' ') ? %Q["#{part.gsub(/"/, '\"')}"] : part @@ -222,7 +249,10 @@ module Util::Execution private_class_method :execute_windows - # this is private method, see call to private_class_method after method definition + # This is private method. + # @comment see call to private_class_method after method definition + # @api private + # def self.wait_for_output(stdout) # Make sure the file's actually been written. This is basically a race # condition, and is probably a horrible way to handle it, but, well, oh diff --git a/lib/puppet/util/filetype.rb b/lib/puppet/util/filetype.rb index 81453e7c0..ac91d4c42 100755 --- a/lib/puppet/util/filetype.rb +++ b/lib/puppet/util/filetype.rb @@ -181,7 +181,7 @@ class Puppet::Util::FileType # Remove a specific @path's cron tab. def remove - if %w{Darwin FreeBSD}.include?(Facter.value("operatingsystem")) + if %w{Darwin FreeBSD DragonFly}.include?(Facter.value("operatingsystem")) %x{/bin/echo yes | #{cmdbase} -r 2>/dev/null} else %x{#{cmdbase} -r 2>/dev/null} diff --git a/lib/puppet/util/monkey_patches.rb b/lib/puppet/util/monkey_patches.rb index ef9e5a41c..820cb376f 100644 --- a/lib/puppet/util/monkey_patches.rb +++ b/lib/puppet/util/monkey_patches.rb @@ -310,3 +310,49 @@ if RUBY_VERSION == '1.8.5' module_function :move end end + +# Ruby 1.8.6 doesn't have it either +# From https://github.com/puppetlabs/hiera/pull/47/files: +# In ruby 1.8.5 Dir does not have mktmpdir defined, so this monkey patches +# Dir to include the 1.8.7 definition of that method if it isn't already defined. +# Method definition borrowed from ruby-1.8.7-p357/lib/ruby/1.8/tmpdir.rb +unless Dir.respond_to?(:mktmpdir) + def Dir.mktmpdir(prefix_suffix=nil, tmpdir=nil) + case prefix_suffix + when nil + prefix = "d" + suffix = "" + when String + prefix = prefix_suffix + suffix = "" + when Array + prefix = prefix_suffix[0] + suffix = prefix_suffix[1] + else + raise ArgumentError, "unexpected prefix_suffix: #{prefix_suffix.inspect}" + end + tmpdir ||= Dir.tmpdir + t = Time.now.strftime("%Y%m%d") + n = nil + begin + path = "#{tmpdir}/#{prefix}#{t}-#{$$}-#{rand(0x100000000).to_s(36)}" + path << "-#{n}" if n + path << suffix + Dir.mkdir(path, 0700) + rescue Errno::EEXIST + n ||= 0 + n += 1 + retry + end + + if block_given? + begin + yield path + ensure + FileUtils.remove_entry_secure path + end + else + path + end + end +end diff --git a/lib/puppet/util/plugins.rb b/lib/puppet/util/plugins.rb index 105fdcd75..5a559cb97 100644 --- a/lib/puppet/util/plugins.rb +++ b/lib/puppet/util/plugins.rb @@ -25,8 +25,8 @@ # Note that the instance variables are local to this Puppet::Plugin (and so may be used # for maintaining state, etc.) but the plugin system does not provide any thread safety # assurances, so they may not be adequate for some complex use cases. -# -# + + module Puppet class Plugins Paths = [] # Where we might find plugin initialization code diff --git a/lib/puppet/util/provider_features.rb b/lib/puppet/util/provider_features.rb index 7d61ae55c..f2f7a1028 100644 --- a/lib/puppet/util/provider_features.rb +++ b/lib/puppet/util/provider_features.rb @@ -2,10 +2,15 @@ require 'puppet/util/methodhelper' require 'puppet/util/docs' require 'puppet/util' +# This module models provider features and handles checking whether the features +# are present. +# @todo Unclear what is api and what is private in this module. +# module Puppet::Util::ProviderFeatures include Puppet::Util::Docs - # The class that models the features and handles checking whether the features + # This class models provider features and handles checking whether the features # are present. + # @todo Unclear what is api and what is private in this class class ProviderFeature include Puppet::Util include Puppet::Util::MethodHelper @@ -13,6 +18,9 @@ module Puppet::Util::ProviderFeatures attr_accessor :name, :docs, :methods # Are all of the requirements met? + # Requirements are checked by checking if feature predicate methods have been generated - see {#methods_available?}. + # @param obj [Object, Class] the object or class to check if requirements are met + # @return [Boolean] whether all requirements for this feature are met or not. def available?(obj) if self.methods return !!methods_available?(obj) @@ -33,7 +41,9 @@ module Puppet::Util::ProviderFeatures private - # Are all of the required methods available? + # Checks whether all feature predicate methods are available. + # @param obj [Object, Class] the object or class to check if feature predicates are available or not. + # @return [Boolean] Returns whether all of the required methods are available or not in the given object. def methods_available?(obj) methods.each do |m| if obj.is_a?(Class) @@ -46,9 +56,11 @@ module Puppet::Util::ProviderFeatures end end - # Define one or more features. At a minimum, features require a name + # Defines one feature. + # At a minimum, a feature requires a name # and docs, and at this point they should also specify a list of methods # required to determine if the feature is present. + # @todo How methods that determine if the feature is present are specified. def feature(name, docs, hash = {}) @features ||= {} raise(Puppet::DevError, "Feature #{name} is already defined") if @features.include?(name) @@ -64,7 +76,7 @@ module Puppet::Util::ProviderFeatures end end - # Return a hash of all feature documentation. + # @return [String] Returns a string with documentation covering all features. def featuredocs str = "" @features ||= {} @@ -94,14 +106,14 @@ module Puppet::Util::ProviderFeatures str end - # Return a list of features. + # @return [Array<String>] Returns a list of features. def features @features ||= {} @features.keys end - # Generate a module that sets up the boolean methods to test for given - # features. + # Generates a module that sets up the boolean predicate methods to test for given features. + # def feature_module unless defined?(@feature_module) @features ||= {} @@ -158,7 +170,11 @@ module Puppet::Util::ProviderFeatures @feature_module end - # Return the actual provider feature instance. Really only used for testing. + # @return [ProviderFeature] Returns a provider feature instance by name. + # @param name [String] the name of the feature to return + # @note Should only be used for testing. + # @api private + # def provider_feature(name) return nil unless defined?(@features) diff --git a/lib/puppet/util/rubygems.rb b/lib/puppet/util/rubygems.rb index 60b6b1429..dab47bf5c 100644 --- a/lib/puppet/util/rubygems.rb +++ b/lib/puppet/util/rubygems.rb @@ -2,9 +2,12 @@ require 'puppet/util' module Puppet::Util::RubyGems - #Base/factory class for rubygems source + # Base/factory class for rubygems source. These classes introspec into + # rubygems to in order to list where the rubygems system will look for files + # to load. class Source class << self + # @api private def has_rubygems? # Gems are not actually available when Bundler is loaded, even # though the Gem constant is defined. This is because Bundler @@ -15,6 +18,7 @@ module Puppet::Util::RubyGems defined? ::Gem and not defined? ::Bundler end + # @api private def source if has_rubygems? Gem::Specification.respond_to?(:latest_specs) ? Gems18Source : OldGemsSource @@ -32,21 +36,26 @@ module Puppet::Util::RubyGems end # For RubyGems >= 1.8.0 + # @api private class Gems18Source < Source def directories - Gem::Specification.latest_specs.collect do |spec| + # `require 'mygem'` will consider and potentally load + # prerelease gems, so we need to match that behavior. + Gem::Specification.latest_specs(true).collect do |spec| File.join(spec.full_gem_path, 'lib') end end end # RubyGems < 1.8.0 + # @api private class OldGemsSource < Source def directories @paths ||= Gem.latest_load_paths end end + # @api private class NoGemsSource < Source def directories [] diff --git a/lib/puppet/util/selinux.rb b/lib/puppet/util/selinux.rb index 53ab664f0..0b712be0d 100644 --- a/lib/puppet/util/selinux.rb +++ b/lib/puppet/util/selinux.rb @@ -43,13 +43,8 @@ module Puppet::Util::SELinux # matching. If not, we can pass a mode of 0. begin filestat = file_lstat(file) - rescue Errno::EACCES, Errno::ENOENT => detail - warning "Could not stat; #{detail}" - end - - if filestat mode = filestat.mode - else + rescue Errno::EACCES, Errno::ENOENT mode = 0 end diff --git a/lib/puppet/util/zaml.rb b/lib/puppet/util/zaml.rb index 3476df977..1915d1468 100644 --- a/lib/puppet/util/zaml.rb +++ b/lib/puppet/util/zaml.rb @@ -376,7 +376,7 @@ class Time def to_zaml(z) # 2008-12-06 10:06:51.373758 -07:00 ms = ("%0.6f" % (usec * 1e-6))[2..-1] - offset = "%+0.2i:%0.2i" % [utc_offset / 3600, (utc_offset / 60) % 60] + offset = "%+0.2i:%0.2i" % [utc_offset / 3600.0, (utc_offset / 60) % 60] z.emit(self.strftime("%Y-%m-%d %H:%M:%S.#{ms} #{offset}")) end end diff --git a/lib/puppet/version.rb b/lib/puppet/version.rb index 12e496772..89f742c68 100644 --- a/lib/puppet/version.rb +++ b/lib/puppet/version.rb @@ -4,15 +4,86 @@ # # The version is programatically settable because we want to allow the # Raketasks and such to set the version based on the output of `git describe` -# + + module Puppet - PUPPETVERSION = '3.0.2' + PUPPETVERSION = '3.1.0' + ## + # version is a public API method intended to always provide a fast and + # lightweight way to determine the version of Puppet. + # + # The intent is that software external to Puppet be able to determine the + # Puppet version with no side-effects. The expected use is: + # + # require 'puppet/version' + # version = Puppet.version + # + # This function has the following ordering precedence. This precedence list + # is designed to facilitate automated packaging tasks by simply writing to + # the VERSION file in the same directory as this source file. + # + # 1. If a version has been explicitly assigned using the Puppet.version= + # method, return that version. + # 2. If there is a VERSION file, read the contents, trim any + # trailing whitespace, and return that version string. + # 3. Return the value of the Puppet::PUPPETVERSION constant hard-coded into + # the source code. + # + # If there is no VERSION file, the method must return the version string of + # the nearest parent version that is an officially released version. That is + # to say, if a branch named 3.1.x contains 25 patches on top of the most + # recent official release of 3.1.1, then the version method must return the + # string "3.1.1" if no "VERSION" file is present. + # + # By design the version identifier is _not_ intended to vary during the life + # a process. There is no guarantee provided that writing to the VERSION file + # while a Puppet process is running will cause the version string to be + # updated. On the contrary, the contents of the VERSION are cached to reduce + # filesystem accesses. + # + # The VERSION file is intended to be used by package maintainers who may be + # applying patches or otherwise changing the software version in a manner + # that warrants a different software version identifier. The VERSION file is + # intended to be managed and owned by the release process and packaging + # related tasks, and as such should not reside in version control. The + # PUPPETVERSION constant is intended to be version controlled in history. + # + # Ideally, this behavior will allow package maintainers to precisely specify + # the version of the software they're packaging as in the following example: + # + # $ git describe --match "3.0.*" > lib/puppet/VERSION + # $ ruby -r puppet -e 'puts Puppet.version' + # 3.0.1-260-g9ca4e54 + # + # @api public + # + # @return [String] containing the puppet version, e.g. "3.0.1" def self.version - @puppet_version || PUPPETVERSION + version_file = File.join(File.dirname(__FILE__), 'VERSION') + return @puppet_version if @puppet_version + if version = read_version_file(version_file) + @puppet_version = version + end + @puppet_version ||= PUPPETVERSION end def self.version=(version) @puppet_version = version end + + ## + # read_version_file reads the content of the "VERSION" file that lives in the + # same directory as this source code file. + # + # @api private + # + # @return [String] for example: "1.6.14-6-gea42046" or nil if the VERSION + # file does not exist. + def self.read_version_file(path) + if File.exists?(path) + File.read(path).chomp + end + end + private_class_method :read_version_file end diff --git a/man/man5/puppet.conf.5 b/man/man5/puppet.conf.5 index aa31f5a7b..27d5d12bf 100644 --- a/man/man5/puppet.conf.5 +++ b/man/man5/puppet.conf.5 @@ -1,8 +1,8 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPETCONF" "5" "May 2012" "Puppet Labs, LLC" "Puppet manual" -\fBThis page is autogenerated; any changes will get overwritten\fR \fI(last generated on Thu May 17 14:19:16 \-0700 2012)\fR +.TH "PUPPETCONF" "5" "January 2013" "Puppet Labs, LLC" "Puppet manual" +\fBThis page is autogenerated; any changes will get overwritten\fR \fI(last generated on Tue Jan 15 12:33:09 \-0800 2013)\fR . .SH "Configuration Settings" . @@ -19,6 +19,9 @@ Settings can be interpolated as \fB$variables\fR in other settings; \fB$environm Multiple values should be specified as comma\-separated lists; multiple directories should be separated with the system path separator (usually a colon)\. . .IP "\(bu" 4 +Settings that represent time intervals should be specified in duration format: an integer immediately followed by one of the units \'y\' (years of 365 days), \'d\' (days), \'h\' (hours), \'m\' (minutes), or \'s\' (seconds)\. The unit cannot be combined with other units, and defaults to seconds when omitted\. Examples are \'3600\' which is equivalent to \'1h\' (one hour), and \'1825d\' which is equivalent to \'5y\' (5 years)\. +. +.IP "\(bu" 4 Settings that take a single file or directory can optionally set the owner, group, and mode for their value: \fBrundir = $vardir/run { owner = puppet, group = puppet, mode = 644 }\fR . .IP "\(bu" 4 @@ -29,6 +32,14 @@ The Puppet executables will ignore any setting that isn\'t relevant to their fun .P See the configuration guide \fIhttp://docs\.puppetlabs\.com/guides/configuring\.html\fR for more details\. . +.SS "agent_catalog_run_lockfile" +A lock file to indicate that a puppet agent catalog run is currently in progress\. The file contains the pid of the process that holds the lock on the catalog run\. +. +.IP "\(bu" 4 +\fIDefault\fR: $statedir/agent_catalog_run\.lock +. +.IP "" 0 +. .SS "agent_disabled_lockfile" A lock file to indicate that puppet agent runs have been administratively disabled\. File contains a JSON object with state information\. . @@ -37,16 +48,16 @@ A lock file to indicate that puppet agent runs have been administratively disabl . .IP "" 0 . -.SS "agent_pidfile" -A lock file to indicate that a puppet agent run is currently in progress\. File contains the pid of the running process\. +.SS "allow_duplicate_certs" +Whether to allow a new certificate request to overwrite an existing certificate\. . .IP "\(bu" 4 -\fIDefault\fR: $statedir/agent\.pid +\fIDefault\fR: false . .IP "" 0 . -.SS "allow_duplicate_certs" -Whether to allow a new certificate request to overwrite an existing certificate\. +.SS "allow_variables_with_dashes" +Permit hyphens (\fB\-\fR) in variable names and issue deprecation warnings about them\. This setting \fBshould always be \fBfalse\fR;\fR setting it to \fBtrue\fR will cause subtle and wide\-ranging bugs\. It will be removed in a future version\. Hyphenated variables caused major problems in the language, but were allowed between Puppet 2\.7\.3 and 2\.7\.14\. If you used them during this window, we apologize for the inconvenience \-\-\- you can temporarily set this to \fBtrue\fR in order to upgrade, and can rename your variables at your leisure\. Please revert it to \fBfalse\fR after you have renamed all affected variables\. . .IP "\(bu" 4 \fIDefault\fR: false @@ -70,21 +81,13 @@ During an inspect run, whether to archive files whose contents are audited to a .IP "" 0 . .SS "async_storeconfigs" -Whether to use a queueing system to provide asynchronous database integration\. Requires that \fBpuppet queue\fR be running and that \'PSON\' support for ruby be installed\. +Whether to use a queueing system to provide asynchronous database integration\. Requires that \fBpuppet queue\fR be running\. . .IP "\(bu" 4 \fIDefault\fR: false . .IP "" 0 . -.SS "authconfig" -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 \fBpuppet agent\fR and \fBpuppet master\fR\. -. -.IP "\(bu" 4 -\fIDefault\fR: $confdir/namespaceauth\.conf -. -.IP "" 0 -. .SS "autoflush" Whether log files should always flush to disk\. . @@ -102,7 +105,12 @@ Whether to enable autosign\. Valid values are true (which autosigns any key requ .IP "" 0 . .SS "bindaddress" -The address a listening server should bind to\. WEBrick defaults to 0\.0\.0\.0\. +The address a listening server should bind to\. +. +.IP "\(bu" 4 +\fIDefault\fR: 0\.0\.0\.0 +. +.IP "" 0 . .SS "bucketdir" Where FileBucket files are stored\. @@ -120,17 +128,6 @@ Whether the master should function as a certificate authority\. . .IP "" 0 . -.SS "ca_days" -How long a certificate should be valid, in days\. This setting is deprecated; use \fBca_ttl\fR instead -. -.SS "ca_md" -The type of hash used in certificates\. -. -.IP "\(bu" 4 -\fIDefault\fR: md5 -. -.IP "" 0 -. .SS "ca_name" The name to use the Certificate Authority certificate\. . @@ -156,7 +153,7 @@ The server to use for certificate authority requests\. It\'s a separate server b .IP "" 0 . .SS "ca_ttl" -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 setting is set, ca_days is ignored\. Examples are \'3600\' (one hour) and \'1825d\', which is the same as \'5y\' (5 years) +The default TTL for new certificates\. If this setting is set, ca_days is ignored\. Can be specified as a duration\. . .IP "\(bu" 4 \fIDefault\fR: 5y @@ -219,6 +216,13 @@ The CA public key\. . .IP "" 0 . +.SS "catalog_cache_terminus" +How to store cached catalogs\. Valid values are \'json\' and \'yaml\'\. The agent application defaults to \'json\'\. +. +.TP +\fIDefault\fR: + +. .SS "catalog_format" (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\. . @@ -249,6 +253,14 @@ The certificate directory\. .SS "certdnsnames" The \fBcertdnsnames\fR setting is no longer functional, after CVE\-2011\-3872\. We ignore the value completely\. For your own certificate request you can set \fBdns_alt_names\fR in the configuration and it will apply locally\. There is no configuration option to set DNS alt names, or any other \fBsubjectAltName\fR value, for another nodes certificate\. Alternately you can use the \fB\-\-dns_alt_names\fR command line option to set the labels added while generating your own CSR\. . +.SS "certificate_expire_warning" +The window of time leading up to a certificate\'s expiration that a notification will be logged\. This applies to CA, master, and agent certificates\. Can be specified as a duration\. +. +.IP "\(bu" 4 +\fIDefault\fR: 60d +. +.IP "" 0 +. .SS "certificate_revocation" 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\. . @@ -261,7 +273,7 @@ Whether certificate revocation should be supported by downloading a Certificate The name to use when handling certificates\. Defaults to the fully qualified domain name\. . .IP "\(bu" 4 -\fIDefault\fR: wyclef\.puppetlabs\.lan +\fIDefault\fR: sirrus\.puppetlabs\.lan . .IP "" 0 . @@ -339,10 +351,10 @@ How to determine the configuration version\. By default, it will be the time tha Print the value of a specific configuration setting\. If the name of a setting is provided for this, then the value is printed and puppet exits\. Comma\-separate multiple values\. For a list of all values, specify \'all\'\. . .SS "configtimeout" -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\. +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\. Can be specified as a duration\. . .IP "\(bu" 4 -\fIDefault\fR: 120 +\fIDefault\fR: 2m . .IP "" 0 . @@ -494,16 +506,8 @@ Document all resources . .IP "" 0 . -.SS "downcasefacts" -Whether facts should be made all lowercase when sent to the server\. -. -.IP "\(bu" 4 -\fIDefault\fR: false -. -.IP "" 0 -. .SS "dynamicfacts" -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\. +(Deprecated) 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\. . .IP "\(bu" 4 \fIDefault\fR: memorysize,memoryfree,swapsize,swapfree @@ -559,10 +563,10 @@ Where the fileserver configuration is stored\. .IP "" 0 . .SS "filetimeout" -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\. +The minimum time to wait 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\. Can be specified as a duration\. . .IP "\(bu" 4 -\fIDefault\fR: 15 +\fIDefault\fR: 15s . .IP "" 0 . @@ -785,14 +789,6 @@ The LDAP attributes to use to define Puppet classes\. Values should be comma\-se . .IP "" 0 . -.SS "ldapnodes" -Whether to search for node configurations in LDAP\. See http://projects\.puppetlabs\.com/projects/puppet/wiki/LDAP_Nodes for more information\. -. -.IP "\(bu" 4 -\fIDefault\fR: false -. -.IP "" 0 -. .SS "ldapparentattr" The attribute to use to define the parent node\. . @@ -805,7 +801,7 @@ The attribute to use to define the parent node\. The password to use to connect to LDAP\. . .SS "ldapport" -The LDAP port\. Only used if \fBldapnodes\fR is enabled\. +The LDAP port\. Only used if \fBnode_terminus\fR is set to \fBldap\fR\. . .IP "\(bu" 4 \fIDefault\fR: 389 @@ -813,7 +809,7 @@ The LDAP port\. Only used if \fBldapnodes\fR is enabled\. .IP "" 0 . .SS "ldapserver" -The LDAP server\. Only used if \fBldapnodes\fR is enabled\. +The LDAP server\. Only used if \fBnode_terminus\fR is set to \fBldap\fR\. . .IP "\(bu" 4 \fIDefault\fR: ldap @@ -855,14 +851,6 @@ Whether TLS should be used when searching for nodes\. Defaults to false because .SS "ldapuser" The user to use to connect to LDAP\. Must be specified as a full DN\. . -.SS "lexical" -Whether to use lexical scoping (vs\. dynamic)\. -. -.IP "\(bu" 4 -\fIDefault\fR: false -. -.IP "" 0 -. .SS "libdir" 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 . @@ -970,7 +958,7 @@ Whether to create the necessary user and group that puppet agent will run as\. The module repository . .IP "\(bu" 4 -\fIDefault\fR: http://forge\.puppetlabs\.com +\fIDefault\fR: https://forge\.puppetlabs\.com . .IP "" 0 . @@ -997,6 +985,13 @@ The name of the application, if we are running as one\. The default is essential \fIDefault\fR: . +.SS "node_cache_terminus" +How to store cached nodes\. Valid values are (none), \'json\', \'yaml\' or write only yaml (\'write_only_yaml\')\. The master application defaults to \'write_only_yaml\', all others to none\. +. +.TP +\fIDefault\fR: + +. .SS "node_name" How the puppet master 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) . @@ -1057,7 +1052,7 @@ The shell search path\. Defaults to whatever is inherited from the parent proces .IP "" 0 . .SS "pidfile" -The pid file +The file containing the PID of a running process\. This file is intended to be used by service management frameworks and monitoring systems to determine if a puppet process is still in the process table\. . .IP "\(bu" 4 \fIDefault\fR: $rundir/${run_mode}\.pid @@ -1218,7 +1213,7 @@ The directory in which to store reports received from the client\. Each client g The \'from\' email address for the reports\. . .IP "\(bu" 4 -\fIDefault\fR: report@wyclef\.puppetlabs\.lan +\fIDefault\fR: report@sirrus\.puppetlabs\.lan . .IP "" 0 . @@ -1230,14 +1225,6 @@ The list of reports to generate\. All reports are looked for in \fBpuppet/report . .IP "" 0 . -.SS "reportserver" -(Deprecated for \'report_server\') The server to which to send transaction reports\. -. -.IP "\(bu" 4 -\fIDefault\fR: $server -. -.IP "" 0 -. .SS "reporturl" The URL used by the http reports processor to send reports . @@ -1295,20 +1282,13 @@ The directory where RRD database files are stored\. Directories for each reporti .IP "" 0 . .SS "rrdinterval" -How often RRD should expect data\. This should match how often the hosts report back to the server\. +How often RRD should expect data\. This should match how often the hosts report back to the server\. Can be specified as a duration\. . .IP "\(bu" 4 \fIDefault\fR: $runinterval . .IP "" 0 . -.SS "run_mode" -The effective \'run mode\' of the application: master, agent, or user\. -. -.TP -\fIDefault\fR: - -. .SS "rundir" Where Puppet PID files are kept\. . @@ -1317,10 +1297,10 @@ Where Puppet PID files are kept\. . .SS "runinterval" -How often puppet agent applies the client configuration; in seconds\. Note that a runinterval of 0 means "run continuously" rather than "never run\." If you want puppet agent to never run, you should start it with the \fB\-\-no\-client\fR option\. +How often puppet agent applies the client configuration; in seconds\. Note that a runinterval of 0 means "run continuously" rather than "never run\." If you want puppet agent to never run, you should start it with the \fB\-\-no\-client\fR option\. Can be specified as a duration\. . .IP "\(bu" 4 -\fIDefault\fR: 1800 +\fIDefault\fR: 30m . .IP "" 0 . @@ -1356,14 +1336,6 @@ The directory in which serialized data is stored, usually in a subdirectory\. . .IP "" 0 . -.SS "servertype" -The type of server to use\. Currently supported option is webrick\. -. -.IP "\(bu" 4 -\fIDefault\fR: webrick -. -.IP "" 0 -. .SS "show_diff" Whether to log and report a contextual diff when files are being replaced\. This causes partial file contents to pass through Puppet\'s normal logging and reporting system, so this setting should be used with caution if you are sending Puppet\'s reports to an insecure destination\. This feature currently requires the \fBdiff/lcs\fR Ruby library\. . @@ -1397,7 +1369,7 @@ Whether to sleep for a pseudo\-random (but consistent) amount of time before a r .IP "" 0 . .SS "splaylimit" -The maximum time to delay before runs\. Defaults to being the same as the run interval\. +The maximum time to delay before runs\. Defaults to being the same as the run interval\. Can be specified as a duration\. . .IP "\(bu" 4 \fIDefault\fR: $runinterval @@ -1412,6 +1384,13 @@ The domain which will be queried to find the SRV records of servers to use\. . .IP "" 0 . +.SS "ssl_client_ca_auth" +Certificate authorities who issue server certificates\. SSL servers will not be considered authentic unless they posses a certificate issued by an authority listed in this file\. If this setting has no value then the Puppet master\'s CA certificate (localcacert) will be used\. +. +.TP +\fIDefault\fR: + +. .SS "ssl_client_header" The header containing an authenticated client\'s SSL DN\. This header must be set by the proxy to the authenticated client\'s SSL DN (e\.g\., \fB/CN=puppet\.puppetlabs\.com\fR)\. . @@ -1428,6 +1407,13 @@ The header containing the status message of the client verification\. This heade . .IP "" 0 . +.SS "ssl_server_ca_auth" +Certificate authorities who issue client certificates\. SSL clients will not be considered authentic unless they posses a certificate issued by an authority listed in this file\. If this setting has no value then the Puppet master\'s CA certificate (localcacert) will be used\. +. +.TP +\fIDefault\fR: + +. .SS "ssldir" Where SSL certificates are kept\. . @@ -1512,7 +1498,7 @@ Where Puppet looks for template files\. Can be a list of colon\-separated direct .IP "" 0 . .SS "thin_storeconfigs" -Boolean; whether 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 +Boolean; whether Puppet should store only facts and exported resources in the storeconfigs database\. This will improve the performance of exported resources with the older \fBactive_record\fR backend, but will disable external tools that search the storeconfigs database\. Thinning catalogs is generally unnecessary when using PuppetDB to store catalogs\. . .IP "\(bu" 4 \fIDefault\fR: false @@ -1568,10 +1554,10 @@ Where Puppet stores dynamic and growing data\. The default for this setting is c .IP "" 0 . .SS "waitforcert" -The time interval, specified in seconds, \'puppet agent\' should connect to the server and ask it to sign a certificate request\. This is useful for the initial setup of a puppet client\. You can turn off waiting for certificates by specifying a time of 0\. +The time interval \'puppet agent\' should connect to the server and ask it to sign a certificate request\. This is useful for the initial setup of a puppet client\. You can turn off waiting for certificates by specifying a time of 0\. Can be specified as a duration\. . .IP "\(bu" 4 -\fIDefault\fR: 120 +\fIDefault\fR: 2m . .IP "" 0 . @@ -1592,4 +1578,4 @@ Boolean; whether to use the zlib library .IP "" 0 . .P -\fIThis page autogenerated on Thu May 17 14:19:16 \-0700 2012\fR +\fIThis page autogenerated on Tue Jan 15 12:33:09 \-0800 2013\fR diff --git a/man/man8/extlookup2hiera.8 b/man/man8/extlookup2hiera.8 new file mode 100644 index 000000000..3a97591f3 --- /dev/null +++ b/man/man8/extlookup2hiera.8 @@ -0,0 +1,23 @@ +.\" generated with Ronn/v0.7.3 +.\" http://github.com/rtomayko/ronn/tree/0.7.3 +. +.TH "EXTLOOKUP2HIERA" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" +. +.SH "NAME" +\fBextlookup2hiera\fR +. +.P +Converter for extlookup CSV files into Hiera JSON and YAML files +. +.IP "" 4 +. +.nf + +\-i, \-\-in FILE Input CSV file +\-o, \-\-out FILE Output Hiera file +\-j, \-\-json Create JSON format file +. +.fi +. +.IP "" 0 + diff --git a/man/man8/puppet-agent.8 b/man/man8/puppet-agent.8 index edef1bfde..e32ff49fe 100644 --- a/man/man8/puppet-agent.8 +++ b/man/man8/puppet-agent.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-AGENT" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-AGENT" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-agent\fR \- The puppet agent daemon @@ -61,7 +61,7 @@ Provide transaction information via exit codes\. If this is enabled, an exit cod . .TP \-\-digest -Change the certificate fingerprinting digest algorithm\. The default is MD5\. Valid values depends on the version of OpenSSL installed, but should always at least contain MD5, MD2, SHA1 and SHA256\. +Change the certificate fingerprinting digest algorithm\. The default is SHA256\. Valid values depends on the version of OpenSSL installed, but will likely contain MD5, MD2, SHA1 and SHA256\. . .TP \-\-disable @@ -97,7 +97,7 @@ Where to send messages\. Choose between syslog, the console, and a log file\. De . .TP \-\-no\-client -Do not create a config client\. This will cause the daemon to run without ever checking for its configuration automatically, and only makes sense when puppet agent is being run with listen = true in puppet\.conf or was started with the \fB\-\-listen\fR option\. +Do not create a config client\. This will cause the daemon to start but not check configuration unless it is triggered with \fBpuppet kick\fR\. This only makes sense when puppet agent is being run with listen = true in puppet\.conf or was started with the \fB\-\-listen\fR option\. . .TP \-\-noop diff --git a/man/man8/puppet-apply.8 b/man/man8/puppet-apply.8 index 91b940472..64df05ff3 100644 --- a/man/man8/puppet-apply.8 +++ b/man/man8/puppet-apply.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-APPLY" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-APPLY" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-apply\fR \- Apply Puppet manifests locally @@ -10,7 +10,7 @@ Applies a standalone Puppet manifest to the local system\. . .SH "USAGE" -puppet apply [\-h|\-\-help] [\-V|\-\-version] [\-d|\-\-debug] [\-v|\-\-verbose] [\-e|\-\-execute] [\-\-detailed\-exitcodes] [\-l|\-\-logdest \fIfile\fR] [\-\-noop] [\-\-apply \fIcatalog\fR] [\-\-catalog \fIcatalog\fR] \fIfile\fR +puppet apply [\-h|\-\-help] [\-V|\-\-version] [\-d|\-\-debug] [\-v|\-\-verbose] [\-e|\-\-execute] [\-\-detailed\-exitcodes] [\-l|\-\-logdest \fIfile\fR] [\-\-noop] [\-\-catalog \fIcatalog\fR] \fIfile\fR . .SH "DESCRIPTION" This is the standalone puppet execution tool; use it to apply individual manifests\. @@ -60,10 +60,6 @@ Execute a specific piece of Puppet code Print extra information\. . .TP -\-\-apply -Apply a JSON catalog (such as one generated with \'puppet master \-\-compile\')\. You can either specify a JSON file or pipe in JSON from standard input\. Deprecated, please use \-\-catalog instead\. -. -.TP \-\-catalog Apply a JSON catalog (such as one generated with \'puppet master \-\-compile\')\. You can either specify a JSON file or pipe in JSON from standard input\. . diff --git a/man/man8/puppet-ca.8 b/man/man8/puppet-ca.8 index 88ea9cde2..f97bbe744 100644 --- a/man/man8/puppet-ca.8 +++ b/man/man8/puppet-ca.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-CA" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-CA" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-ca\fR \- Local Puppet Certificate Authority management\. @@ -16,16 +16,12 @@ This provides local management of the Puppet Certificate Authority\. You can use this subcommand to sign outstanding certificate requests, list and manage local certificates, and inspect the state of the CA\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -89,7 +85,7 @@ Undocumented action\. \fBSYNOPSIS\fR . .IP -puppet ca list [\-\-[no\-]all] [\-\-[no\-]pending] [\-\-[no\-]signed] [\-\-subject PATTERN] +puppet ca list [\-\-[no\-]all] [\-\-[no\-]pending] [\-\-[no\-]signed] [\-\-digest ALGORITHM] [\-\-subject PATTERN] . .IP \fBDESCRIPTION\fR @@ -101,6 +97,9 @@ This will list the current certificates and certificate signing requests in the \fBOPTIONS\fR \fI\-\-[no\-]all\fR \- Include all certificates and requests\. . .IP +\fI\-\-digest ALGORITHM\fR \- The hash algorithm to use when displaying the fingerprint +. +.IP \fI\-\-[no\-]pending\fR \- Include pending certificate signing requests\. . .IP diff --git a/man/man8/puppet-catalog.8 b/man/man8/puppet-catalog.8 index b2736b1b4..0e5db96c7 100644 --- a/man/man8/puppet-catalog.8 +++ b/man/man8/puppet-catalog.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-CATALOG" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-CATALOG" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-catalog\fR \- Compile, save, view, and convert catalogs\. @@ -13,16 +13,12 @@ puppet catalog \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HASH] This subcommand deals with catalogs, which are compiled per\-node artifacts generated from a set of Puppet manifests\. By default, it interacts with the compiling subsystem and compiles a catalog using the default manifest and \fBcertname\fR, but you can change the source of the catalog with the \fB\-\-terminus\fR option\. You can also choose to print any catalog in \'dot\' format (for easy graph viewing with OmniGraffle or Graphviz) with \'\-\-render\-as dot\'\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -140,7 +136,7 @@ puppet catalog info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- API only: create or overwrite an object\. @@ -273,6 +269,9 @@ This subcommand is an indirector face, which exposes \fBfind\fR, \fBsearch\fR, \ \fBcompiler\fR . .IP "\(bu" 4 +\fBjson\fR +. +.IP "\(bu" 4 \fBqueue\fR . .IP "\(bu" 4 diff --git a/man/man8/puppet-cert.8 b/man/man8/puppet-cert.8 index 92cdedc00..f9912f527 100644 --- a/man/man8/puppet-cert.8 +++ b/man/man8/puppet-cert.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-CERT" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-CERT" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-cert\fR \- Manage certificates and requests @@ -24,7 +24,7 @@ Revoke a host\'s certificate (if applicable) and remove all files related to tha . .TP fingerprint -Print the DIGEST (defaults to md5) fingerprint of a host\'s certificate\. +Print the DIGEST (defaults to the signing algorithm) fingerprint of a host\'s certificate\. . .TP generate @@ -40,7 +40,7 @@ Print the full\-text version of a host\'s certificate\. . .TP revoke -Revoke the certificate of a client\. The certificate can be specified either by its serial number (given as a decimal number or a hexadecimal number prefixed by \'0x\') or by its hostname\. The certificate is revoked by adding it to the Certificate Revocation List given by the \'cacrl\' configuration option\. Note that the puppet master needs to be restarted after revoking certificates\. +Revoke the certificate of a client\. The certificate can be specified either by its serial number (given as a hexadecimal number prefixed by \'0x\') or by its hostname\. The certificate is revoked by adding it to the Certificate Revocation List given by the \'cacrl\' configuration option\. Note that the puppet master needs to be restarted after revoking certificates\. . .TP sign @@ -62,7 +62,7 @@ Operate on all items\. Currently only makes sense with the \'sign\', \'clean\', . .TP \-\-digest -Set the digest for fingerprinting (defaults to md5)\. Valid values depends on your openssl and openssl ruby extension version, but should contain at least md5, sha1, md2, sha256\. +Set the digest for fingerprinting (defaults to the the digest used when signing the cert)\. Valid values depends on your openssl and openssl ruby extension version\. . .TP \-\-debug diff --git a/man/man8/puppet-certificate.8 b/man/man8/puppet-certificate.8 index 70a4ab7f1..c89d1867f 100644 --- a/man/man8/puppet-certificate.8 +++ b/man/man8/puppet-certificate.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-CERTIFICATE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-CERTIFICATE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-certificate\fR \- Provide access to the CA for certificate management\. @@ -13,16 +13,12 @@ puppet certificate \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HASH] \fI\-\- This subcommand interacts with a local or remote Puppet certificate authority\. Currently, its behavior is not a full superset of \fBpuppet cert\fR; specifically, it is unable to mimic puppet cert\'s "clean" option, and its "generate" action submits a CSR rather than creating a signed certificate\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -134,7 +130,7 @@ puppet certificate info [\-\-terminus TERMINUS] [\-\-extra HASH] \fI\-\-ca\-loca \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBlist\fR \- List all certificate signing requests\. @@ -228,6 +224,9 @@ This subcommand is an indirector face, which exposes \fBfind\fR, \fBsearch\fR, \ \fBca\fR . .IP "\(bu" 4 +\fBdisabled_ca\fR +. +.IP "\(bu" 4 \fBfile\fR . .IP "\(bu" 4 diff --git a/man/man8/puppet-certificate_request.8 b/man/man8/puppet-certificate_request.8 index 3ecf39ded..aafcbaf77 100644 --- a/man/man8/puppet-certificate_request.8 +++ b/man/man8/puppet-certificate_request.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-CERTIFICATE_REQUEST" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-CERTIFICATE_REQUEST" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-certificate_request\fR \- Manage certificate requests\. @@ -13,16 +13,12 @@ puppet certificate_request \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HASH] This subcommand retrieves and submits certificate signing requests (CSRs)\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -93,7 +89,7 @@ puppet certificate_request info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- API only: submit a certificate signing request\. @@ -158,6 +154,9 @@ This subcommand is an indirector face, which exposes \fBfind\fR, \fBsearch\fR, \ \fBca\fR . .IP "\(bu" 4 +\fBdisabled_ca\fR +. +.IP "\(bu" 4 \fBfile\fR . .IP "\(bu" 4 diff --git a/man/man8/puppet-certificate_revocation_list.8 b/man/man8/puppet-certificate_revocation_list.8 index 66c6b7b34..fd94d3fc4 100644 --- a/man/man8/puppet-certificate_revocation_list.8 +++ b/man/man8/puppet-certificate_revocation_list.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-CERTIFICATE_REVOCATION_LIST" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-CERTIFICATE_REVOCATION_LIST" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-certificate_revocation_list\fR \- Manage the list of revoked certificates\. @@ -13,16 +13,12 @@ puppet certificate_revocation_list \fIaction\fR [\-\-terminus TERMINUS] [\-\-ext This subcommand is primarily for retrieving the certificate revocation list from the CA\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -111,7 +107,7 @@ puppet certificate_revocation_list info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- Invalid for this subcommand\. @@ -155,6 +151,9 @@ This subcommand is an indirector face, which exposes \fBfind\fR, \fBsearch\fR, \ \fBca\fR . .IP "\(bu" 4 +\fBdisabled_ca\fR +. +.IP "\(bu" 4 \fBfile\fR . .IP "\(bu" 4 diff --git a/man/man8/puppet-config.8 b/man/man8/puppet-config.8 index fdc2d1b3c..2e5459057 100644 --- a/man/man8/puppet-config.8 +++ b/man/man8/puppet-config.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-CONFIG" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-CONFIG" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-config\fR \- Interact with Puppet\'s configuration options\. @@ -10,16 +10,12 @@ puppet config \fIaction\fR . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -59,7 +55,7 @@ A single value when called with one config setting, and a list of settings and v \fBNOTES\fR . .IP -By default, this action reads the configuration in agent mode\. Use the \'\-\-mode\' and \'\-\-environment\' flags to examine other configuration domains\. +By default, this action reads the configuration in agent mode\. Use the \'\-\-run_mode\' and \'\-\-environment\' flags to examine other configuration domains\. . .SH "EXAMPLES" \fBprint\fR @@ -74,7 +70,7 @@ $ puppet config print rundir Get a list of important directories from the master\'s config: . .P -$ puppet config print all \-\-mode master | grep \-E "(path|dir)" +$ puppet config print all \-\-run_mode master | grep \-E "(path|dir)" . .SH "COPYRIGHT AND LICENSE" Copyright 2011 by Puppet Labs Apache 2 license; see COPYING diff --git a/man/man8/puppet-describe.8 b/man/man8/puppet-describe.8 index 6b8ca8b0c..4d9bc5720 100644 --- a/man/man8/puppet-describe.8 +++ b/man/man8/puppet-describe.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-DESCRIBE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-DESCRIBE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-describe\fR \- Display help about resource types diff --git a/man/man8/puppet-device.8 b/man/man8/puppet-device.8 index 1bd09410b..913573c2d 100644 --- a/man/man8/puppet-device.8 +++ b/man/man8/puppet-device.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-DEVICE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-DEVICE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-device\fR \- Manage remote network devices diff --git a/man/man8/puppet-doc.8 b/man/man8/puppet-doc.8 index d7cb51928..f6d016ab1 100644 --- a/man/man8/puppet-doc.8 +++ b/man/man8/puppet-doc.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-DOC" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-DOC" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-doc\fR \- Generate Puppet documentation and references @@ -43,7 +43,7 @@ Used only in \'rdoc\' mode\. The directory to which the rdoc output should be wr . .TP \-\-mode -Determine the output mode\. Valid modes are \'text\', \'pdf\' and \'rdoc\'\. The \'pdf\' mode creates PDF formatted files in the /tmp directory\. The default mode is \'text\'\. In \'rdoc\' mode you must provide \'manifests\-path\' +Determine the output mode\. Valid modes are \'text\', \'pdf\' and \'rdoc\'\. The \'pdf\' mode creates PDF formatted files in the /tmp directory\. The default mode is \'text\'\. . .TP \-\-reference @@ -63,7 +63,7 @@ Used only in \'rdoc\' mode\. The directory or directories to scan for modules\. . .TP \-\-environment -Used only in \'rdoc\' mode\. The configuration environment from which to read the modulepath and manifestdir settings, when reading said settings from puppet\.conf\. Due to a known bug, this option is not currently effective\. +Used only in \'rdoc\' mode\. The configuration environment from which to read the modulepath and manifestdir settings, when reading said settings from puppet\.conf\. . .SH "EXAMPLE" . diff --git a/man/man8/puppet-facts.8 b/man/man8/puppet-facts.8 index a15f0514b..8dc6367cc 100644 --- a/man/man8/puppet-facts.8 +++ b/man/man8/puppet-facts.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-FACTS" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-FACTS" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-facts\fR \- Retrieve and store facts\. @@ -16,16 +16,12 @@ This subcommand manages facts, which are collections of normalized system inform When used with the \fBrest\fR terminus, this subcommand is essentially a front\-end to the inventory service REST API\. See the inventory service documentation at \fIhttp://docs\.puppetlabs\.com/guides/inventory_service\.html\fR for more detail\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -105,7 +101,7 @@ puppet facts info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- API only: create or overwrite an object\. @@ -177,7 +173,7 @@ $ puppet facts find somenode\.puppetlabs\.lan \-\-terminus rest Query a DB\-backed inventory directly (bypassing the REST API): . .P -$ puppet facts find somenode\.puppetlabs\.lan \-\-terminus inventory_active_record \-\-mode master +$ puppet facts find somenode\.puppetlabs\.lan \-\-terminus inventory_active_record \-\-run_mode master . .P \fBupload\fR diff --git a/man/man8/puppet-file.8 b/man/man8/puppet-file.8 index 72f9af2c7..6026c2078 100644 --- a/man/man8/puppet-file.8 +++ b/man/man8/puppet-file.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-FILE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-FILE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-file\fR \- Retrieve and store files in a filebucket @@ -13,16 +13,12 @@ puppet file \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HASH] This subcommand interacts with objects stored in a local or remote filebucket\. File objects are accessed by their MD5 sum; see the examples for the relevant syntax\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -115,7 +111,7 @@ puppet file info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- API only: create or overwrite an object\. @@ -210,6 +206,9 @@ This subcommand is an indirector face, which exposes \fBfind\fR, \fBsearch\fR, \ .IP "\(bu" 4 \fBrest\fR . +.IP "\(bu" 4 +\fBselector\fR +. .IP "" 0 . .SH "COPYRIGHT AND LICENSE" diff --git a/man/man8/puppet-filebucket.8 b/man/man8/puppet-filebucket.8 index 2a65b3b57..4d50121bf 100644 --- a/man/man8/puppet-filebucket.8 +++ b/man/man8/puppet-filebucket.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-FILEBUCKET" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-FILEBUCKET" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-filebucket\fR \- Store and retrieve files in a filebucket diff --git a/man/man8/puppet-help.8 b/man/man8/puppet-help.8 index bcca7921f..c3d7b8db5 100644 --- a/man/man8/puppet-help.8 +++ b/man/man8/puppet-help.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-HELP" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-HELP" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-help\fR \- Display Puppet help\. @@ -10,16 +10,12 @@ puppet help \fIaction\fR . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . diff --git a/man/man8/puppet-inspect.8 b/man/man8/puppet-inspect.8 index 1e93e666c..791e20c09 100644 --- a/man/man8/puppet-inspect.8 +++ b/man/man8/puppet-inspect.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-INSPECT" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-INSPECT" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-inspect\fR \- Send an inspection report diff --git a/man/man8/puppet-instrumentation_data.8 b/man/man8/puppet-instrumentation_data.8 index e5e7efcd8..2110dbca5 100644 --- a/man/man8/puppet-instrumentation_data.8 +++ b/man/man8/puppet-instrumentation_data.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-INSTRUMENTATION_DATA" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-INSTRUMENTATION_DATA" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-instrumentation_data\fR \- Manage instrumentation listener accumulated data\. @@ -13,16 +13,12 @@ puppet instrumentation_data \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HASH This subcommand allows to retrieve the various listener data\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -93,7 +89,7 @@ puppet instrumentation_data info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- Invalid for this subcommand\. diff --git a/man/man8/puppet-instrumentation_listener.8 b/man/man8/puppet-instrumentation_listener.8 index 27a77b3fe..35ce84f78 100644 --- a/man/man8/puppet-instrumentation_listener.8 +++ b/man/man8/puppet-instrumentation_listener.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-INSTRUMENTATION_LISTENER" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-INSTRUMENTATION_LISTENER" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-instrumentation_listener\fR \- Manage instrumentation listeners\. @@ -13,16 +13,12 @@ puppet instrumentation_listener \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra This subcommand enables/disables or list instrumentation listeners\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -131,7 +127,7 @@ puppet instrumentation_listener info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- API only: modify an instrumentation listener status\. diff --git a/man/man8/puppet-instrumentation_probe.8 b/man/man8/puppet-instrumentation_probe.8 index 11b4e5a25..a883c7cbb 100644 --- a/man/man8/puppet-instrumentation_probe.8 +++ b/man/man8/puppet-instrumentation_probe.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-INSTRUMENTATION_PROBE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-INSTRUMENTATION_PROBE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-instrumentation_probe\fR \- Manage instrumentation probes\. @@ -13,16 +13,12 @@ puppet instrumentation_probe \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HAS This subcommand enables/disables or list instrumentation listeners\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -125,7 +121,7 @@ puppet instrumentation_probe info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- API only: enable all instrumentation probes\. diff --git a/man/man8/puppet-key.8 b/man/man8/puppet-key.8 index 4183fdce3..9f4553ee5 100644 --- a/man/man8/puppet-key.8 +++ b/man/man8/puppet-key.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-KEY" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-KEY" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-key\fR \- Create, save, and remove certificate keys\. @@ -13,16 +13,12 @@ puppet key \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HASH] This subcommand manages certificate private keys\. Keys are created automatically by puppet agent and when certificate requests are generated with \'puppet certificate generate\'; it should not be necessary to use this subcommand directly\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -87,7 +83,7 @@ puppet key info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- API only: create or overwrite an object\. @@ -122,6 +118,9 @@ This subcommand is an indirector face, which exposes \fBfind\fR, \fBsearch\fR, \ \fBca\fR . .IP "\(bu" 4 +\fBdisabled_ca\fR +. +.IP "\(bu" 4 \fBfile\fR . .IP "" 0 diff --git a/man/man8/puppet-kick.8 b/man/man8/puppet-kick.8 index 35a5dbdac..3e587fcbe 100644 --- a/man/man8/puppet-kick.8 +++ b/man/man8/puppet-kick.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-KICK" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-KICK" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-kick\fR \- Remotely control puppet agent @@ -101,6 +101,10 @@ Whether the client should ignore schedules when running its configuration\. This How parallel to make the connections\. Parallelization is provided by forking for each client to which to connect\. The default is 1, meaning serial execution\. . .TP +\-\-puppetport +Use the specified TCP port to connect to agents\. Defaults to 8139\. +. +.TP \-\-tag Specify a tag for selecting the objects to apply\. Does not work with the \-\-test option\. . diff --git a/man/man8/puppet-man.8 b/man/man8/puppet-man.8 index 05251a630..6edec5480 100644 --- a/man/man8/puppet-man.8 +++ b/man/man8/puppet-man.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-MAN" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-MAN" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-man\fR \- Display Puppet manual pages\. @@ -13,16 +13,12 @@ puppet man \fIaction\fR This subcommand displays manual pages for all Puppet subcommands\. If the \fBronn\fR gem (\fIhttps://github\.com/rtomayko/ronn/\fR) is installed on your system, puppet man will display fully\-formated man pages\. If \fBronn\fR is not available, puppet man will display the raw (but human\-readable) source text in a pager\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . diff --git a/man/man8/puppet-master.8 b/man/man8/puppet-master.8 index 88e6e69e8..323e3688a 100644 --- a/man/man8/puppet-master.8 +++ b/man/man8/puppet-master.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-MASTER" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-MASTER" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-master\fR \- The puppet master daemon @@ -75,4 +75,4 @@ Close file descriptors for log files and reopen them\. Used with logrotate\. Luke Kanies . .SH "COPYRIGHT" -Copyright (c) 2011 Puppet Labs, LLC Licensed under the Apache 2\.0 License +Copyright (c) 2012 Puppet Labs, LLC Licensed under the Apache 2\.0 License diff --git a/man/man8/puppet-module.8 b/man/man8/puppet-module.8 index 32ba28753..3fc9fd7dd 100644 --- a/man/man8/puppet-module.8 +++ b/man/man8/puppet-module.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-MODULE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-MODULE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-module\fR \- Creates, installs and searches for modules on the Puppet Forge\. @@ -13,16 +13,12 @@ puppet module \fIaction\fR [\-\-environment production ] [\-\-modulepath $confdi This subcommand can find, install, and manage modules from the Puppet Forge, a repository of user\-contributed Puppet code\. It can also generate empty modules, and prepare locally developed modules for release on the Forge\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -49,7 +45,7 @@ The search path for modules, as a list of directories separated by the system pa \fBSYNOPSIS\fR . .IP -puppet module build \fIpath\fR +puppet module build [\fIpath\fR] . .IP \fBDESCRIPTION\fR @@ -124,7 +120,7 @@ puppet module install [\-\-force | \-f] [\-\-target\-dir DIR | \-i DIR] [\-\-ign Installs a module from the Puppet Forge or from a release archive file\. . .IP -The specified module will be installed into the directory specified with the \fB\-\-target\-dir\fR option, which defaults to /Users/matthaus/\.puppet/modules\. +The specified module will be installed into the directory specified with the \fB\-\-target\-dir\fR option, which defaults to /Users/josh/\.puppet/modules\. . .IP \fBOPTIONS\fR \fI\-\-force\fR | \fI\-f\fR \- Force overwrite of existing module, if any\. @@ -251,7 +247,13 @@ Hash Build a module release: . .P -$ puppet module build puppetlabs\-apache notice: Building /Users/kelseyhightower/puppetlabs\-apache for release puppetlabs\-apache/pkg/puppetlabs\-apache\-0\.0\.1\.tar\.gz +$ puppet module build puppetlabs\-apache notice: Building /Users/kelseyhightower/puppetlabs\-apache for release Module built: /Users/kelseyhightower/puppetlabs\-apache/pkg/puppetlabs\-apache\-0\.0\.1\.tar\.gz +. +.P +Build the module in the current working directory: +. +.P +$ cd /Users/kelseyhightower/puppetlabs\-apache $ puppet module build notice: Building /Users/kelseyhightower/puppetlabs\-apache for release Module built: /Users/kelseyhightower/puppetlabs\-apache/pkg/puppetlabs\-apache\-0\.0\.1\.tar\.gz . .P \fBchanges\fR diff --git a/man/man8/puppet-node.8 b/man/man8/puppet-node.8 index e0aad1281..6b9aca5b7 100644 --- a/man/man8/puppet-node.8 +++ b/man/man8/puppet-node.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-NODE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-NODE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-node\fR \- View and manage node definitions\. @@ -13,16 +13,12 @@ puppet node \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HASH] This subcommand interacts with node objects, which are used by Puppet to build a catalog\. A node object consists of the node\'s facts, environment, node parameters (exposed in the parser as top\-scope variables), and classes\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -50,8 +46,9 @@ The terminus for an action is often determined by context, but occasionally need . .SH "ACTIONS" . -.IP "\(bu" 4 -\fBclean\fR \- Clean up everything a puppetmaster knows about a node: \fBSYNOPSIS\fR +.TP +\fBclean\fR \- Clean up everything a puppetmaster knows about a node\. +\fBSYNOPSIS\fR . .IP puppet node clean [\-\-terminus TERMINUS] [\-\-extra HASH] [\-\-[no\-]unexport] \fIhost1\fR [\fIhost2\fR \.\.\.] @@ -60,33 +57,32 @@ puppet node clean [\-\-terminus TERMINUS] [\-\-extra HASH] [\-\-[no\-]unexport] \fBDESCRIPTION\fR . .IP -This includes +Clean up everything a puppet master knows about a node, including certificates and storeconfigs data\. . -.IP "\(bu" 4 -Signed certificates ($vardir/ssl/ca/signed/node\.domain\.pem) -. -.IP "\(bu" 4 -Cached facts ($vardir/yaml/facts/node\.domain\.yaml) +.IP +The full list of info cleaned by this action is: . -.IP "\(bu" 4 -Cached node stuff ($vardir/yaml/node/node\.domain\.yaml) +.IP +\fISigned certificates\fR \- ($vardir/ssl/ca/signed/node\.domain\.pem) . -.IP "\(bu" 4 -Reports ($vardir/reports/node\.domain) +.IP +\fICached facts\fR \- ($vardir/yaml/facts/node\.domain\.yaml) . -.IP "\(bu" 4 -Stored configs: it can either remove all data from an host in your storedconfig database, or with \-\-unexport turn every exported resource supporting ensure to absent so that any other host checking out their config can remove those exported configurations\. +.IP +\fICached node objects\fR \- ($vardir/yaml/node/node\.domain\.yaml) . -.IP "" 0 +.IP +\fIReports\fR \- ($vardir/reports/node\.domain) . .IP -This will unexport exported resources of a host, so that consumers of these resources can remove the exported resources and we will safely remove the node from our infrastructure\. +\fIStored configs\fR \- (in database) The clean action can either remove all data from a host in your storeconfigs database, or, with the \fI\-\-unexport\fR option, turn every exported resource supporting ensure to absent so that any other host that collected those resources can remove them\. Without unexporting, a removed node\'s exported resources become unmanaged by Puppet, and may linger as cruft unless you are purging that resource type\. . .IP -\fBOPTIONS\fR \fI\-\-[no\-]unexport\fR \- Unexport exported resources +\fBOPTIONS\fR \fI\-\-[no\-]unexport\fR \- Whether to remove this node\'s exported resources from other nodes . -.IP "\(bu" 4 -\fBdestroy\fR \- Invalid for this subcommand\.: \fBSYNOPSIS\fR +.TP +\fBdestroy\fR \- Invalid for this subcommand\. +\fBSYNOPSIS\fR . .IP puppet node destroy [\-\-terminus TERMINUS] [\-\-extra HASH] \fIkey\fR @@ -97,8 +93,9 @@ puppet node destroy [\-\-terminus TERMINUS] [\-\-extra HASH] \fIkey\fR .IP Invalid for this subcommand\. . -.IP "\(bu" 4 -\fBfind\fR \- Retrieve a node object\.: \fBSYNOPSIS\fR +.TP +\fBfind\fR \- Retrieve a node object\. +\fBSYNOPSIS\fR . .IP puppet node find [\-\-terminus TERMINUS] [\-\-extra HASH] \fIhost\fR @@ -118,8 +115,9 @@ A hash containing the node\'s \fBclasses\fR, \fBenvironment\fR, \fBexpiration\fR .IP RENDERING ISSUES: Rendering as string and json are currently broken; node objects can only be rendered as yaml\. . -.IP "\(bu" 4 -\fBinfo\fR \- Print the default terminus class for this face\.: \fBSYNOPSIS\fR +.TP +\fBinfo\fR \- Print the default terminus class for this face\. +\fBSYNOPSIS\fR . .IP puppet node info [\-\-terminus TERMINUS] [\-\-extra HASH] @@ -128,10 +126,11 @@ puppet node info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . -.IP "\(bu" 4 -\fBsave\fR \- Invalid for this subcommand\.: \fBSYNOPSIS\fR +.TP +\fBsave\fR \- Invalid for this subcommand\. +\fBSYNOPSIS\fR . .IP puppet node save [\-\-terminus TERMINUS] [\-\-extra HASH] \fIkey\fR @@ -142,8 +141,9 @@ puppet node save [\-\-terminus TERMINUS] [\-\-extra HASH] \fIkey\fR .IP Invalid for this subcommand\. . -.IP "\(bu" 4 -\fBsearch\fR \- Invalid for this subcommand\.: \fBSYNOPSIS\fR +.TP +\fBsearch\fR \- Invalid for this subcommand\. +\fBSYNOPSIS\fR . .IP puppet node search [\-\-terminus TERMINUS] [\-\-extra HASH] \fIquery\fR @@ -154,8 +154,6 @@ puppet node search [\-\-terminus TERMINUS] [\-\-extra HASH] \fIquery\fR .IP Invalid for this subcommand\. . -.IP "" 0 -. .SH "EXAMPLES" \fBfind\fR . @@ -169,7 +167,7 @@ $ puppet node find somenode\.puppetlabs\.lan \-\-terminus plain \-\-render\-as y Retrieve a node using the puppet master\'s configured ENC: . .P -$ puppet node find somenode\.puppetlabs\.lan \-\-terminus exec \-\-mode master \-\-render\-as yaml +$ puppet node find somenode\.puppetlabs\.lan \-\-terminus exec \-\-run_mode master \-\-render\-as yaml . .P Retrieve the same node from the puppet master: @@ -202,6 +200,9 @@ This subcommand is an indirector face, which exposes \fBfind\fR, \fBsearch\fR, \ \fBstore_configs\fR . .IP "\(bu" 4 +\fBwrite_only_yaml\fR +. +.IP "\(bu" 4 \fByaml\fR . .IP "" 0 diff --git a/man/man8/puppet-parser.8 b/man/man8/puppet-parser.8 index da71df7ba..b486c6060 100644 --- a/man/man8/puppet-parser.8 +++ b/man/man8/puppet-parser.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-PARSER" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-PARSER" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-parser\fR \- Interact directly with the parser\. @@ -10,16 +10,12 @@ puppet parser \fIaction\fR . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . diff --git a/man/man8/puppet-plugin.8 b/man/man8/puppet-plugin.8 index ce61eb460..5029170c4 100644 --- a/man/man8/puppet-plugin.8 +++ b/man/man8/puppet-plugin.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-PLUGIN" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-PLUGIN" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-plugin\fR \- Interact with the Puppet plugin system\. @@ -16,16 +16,12 @@ This subcommand provides network access to the puppet master\'s store of plugins The puppet master serves Ruby code collected from the \fBlib\fR directories of its modules\. These plugins can be used on agent nodes to extend Facter and implement custom types and providers\. Plugins are normally downloaded by puppet agent during the course of a run\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . diff --git a/man/man8/puppet-queue.8 b/man/man8/puppet-queue.8 index 14d5abe2c..aaca284cf 100644 --- a/man/man8/puppet-queue.8 +++ b/man/man8/puppet-queue.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-QUEUE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-QUEUE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-queue\fR \- Queuing daemon for asynchronous storeconfigs diff --git a/man/man8/puppet-report.8 b/man/man8/puppet-report.8 index dee29cb9f..489cda93b 100644 --- a/man/man8/puppet-report.8 +++ b/man/man8/puppet-report.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-REPORT" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-REPORT" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-report\fR \- Create, display, and submit reports\. @@ -10,16 +10,12 @@ puppet report \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HASH] . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -84,7 +80,7 @@ puppet report info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- API only: submit a report\. diff --git a/man/man8/puppet-resource.8 b/man/man8/puppet-resource.8 index 78fa049b0..82f8f4320 100644 --- a/man/man8/puppet-resource.8 +++ b/man/man8/puppet-resource.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-RESOURCE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-RESOURCE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-resource\fR \- The resource abstraction layer shell diff --git a/man/man8/puppet-resource_type.8 b/man/man8/puppet-resource_type.8 index 83eb642b6..85d125f6e 100644 --- a/man/man8/puppet-resource_type.8 +++ b/man/man8/puppet-resource_type.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-RESOURCE_TYPE" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-RESOURCE_TYPE" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-resource_type\fR \- View classes, defined resource types, and nodes from all manifests\. @@ -16,16 +16,12 @@ This subcommand reads information about the resource collections (classes, nodes It will eventually be extended to examine native resource types\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -105,7 +101,7 @@ puppet resource_type info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- Invalid for this subcommand\. diff --git a/man/man8/puppet-secret_agent.8 b/man/man8/puppet-secret_agent.8 index 7d060a3ed..d687b7c0a 100644 --- a/man/man8/puppet-secret_agent.8 +++ b/man/man8/puppet-secret_agent.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-SECRET_AGENT" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-SECRET_AGENT" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-secret_agent\fR \- Mimics puppet agent\. @@ -13,16 +13,12 @@ puppet secret_agent \fIaction\fR This subcommand currently functions as a proof of concept, demonstrating how the Faces API exposes Puppet\'s internal systems to application logic; compare the actual code for puppet agent\. It will eventually replace puppet agent entirely, and can provide a template for users who wish to implement agent\-like functionality with non\-standard application logic\. . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . diff --git a/man/man8/puppet-status.8 b/man/man8/puppet-status.8 index 0793d9928..5cef3ca13 100644 --- a/man/man8/puppet-status.8 +++ b/man/man8/puppet-status.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET\-STATUS" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET\-STATUS" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\-status\fR \- View puppet server status\. @@ -10,16 +10,12 @@ puppet status \fIaction\fR [\-\-terminus TERMINUS] [\-\-extra HASH] . .SH "OPTIONS" -Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR is a valid configuration parameter, so you can specify \fB\-\-server <servername>\fR as an argument\. +Note that any configuration parameter that\'s valid in the configuration file is also a valid long argument, although it may or may not be relevant to the present action\. For example, \fBserver\fR and \fBrun_mode\fR are valid configuration parameters, so you can specify \fB\-\-server <servername>\fR, or \fB\-\-run_mode <runmode>\fR as an argument\. . .P See the configuration file documentation at \fIhttp://docs\.puppetlabs\.com/references/stable/configuration\.html\fR for the full list of acceptable parameters\. A commented list of all configuration options can also be generated by running puppet with \fB\-\-genconfig\fR\. . .TP -\-\-mode MODE -The run mode to use for the current action\. Valid modes are \fBuser\fR, \fBagent\fR, and \fBmaster\fR\. -. -.TP \-\-render\-as FORMAT The format in which to render output\. The most common formats are \fBjson\fR, \fBs\fR (string), \fByaml\fR, and \fBconsole\fR, but other options such as \fBdot\fR are sometimes available\. . @@ -102,7 +98,7 @@ puppet status info [\-\-terminus TERMINUS] [\-\-extra HASH] \fBDESCRIPTION\fR . .IP -Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-mode\' option\. +Prints the default terminus class for this subcommand\. Note that different run modes may have different default termini; when in doubt, specify the run mode with the \'\-\-run_mode\' option\. . .TP \fBsave\fR \- Invalid for this subcommand\. diff --git a/man/man8/puppet.8 b/man/man8/puppet.8 index 440033f86..4e77ab843 100644 --- a/man/man8/puppet.8 +++ b/man/man8/puppet.8 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "PUPPET" "8" "May 2012" "Puppet Labs, LLC" "Puppet manual" +.TH "PUPPET" "8" "January 2013" "Puppet Labs, LLC" "Puppet manual" . .SH "NAME" \fBpuppet\fR diff --git a/spec/integration/application/apply_spec.rb b/spec/integration/application/apply_spec.rb index 233766e88..98de31d35 100755 --- a/spec/integration/application/apply_spec.rb +++ b/spec/integration/application/apply_spec.rb @@ -6,7 +6,7 @@ require 'puppet/application/apply' describe "apply" do include PuppetSpec::Files - describe "when applying provided catalogs", :if => Puppet.features.pson? do + describe "when applying provided catalogs" do it "should be able to apply catalogs provided in a file in pson" do file_to_create = tmpfile("pson_catalog") catalog = Puppet::Resource::Catalog.new diff --git a/spec/integration/defaults_spec.rb b/spec/integration/defaults_spec.rb index bdf857025..2764be1bb 100755 --- a/spec/integration/defaults_spec.rb +++ b/spec/integration/defaults_spec.rb @@ -87,6 +87,7 @@ describe "Puppet defaults" do it "should use the service user and group for the yamldir" do Puppet.settings.stubs(:service_user_available?).returns true + Puppet.settings.stubs(:service_group_available?).returns true Puppet.settings.setting(:yamldir).owner.should == Puppet.settings[:user] Puppet.settings.setting(:yamldir).group.should == Puppet.settings[:group] end diff --git a/spec/integration/indirector/catalog/queue_spec.rb b/spec/integration/indirector/catalog/queue_spec.rb index 31f5c1e49..f0f75263a 100755 --- a/spec/integration/indirector/catalog/queue_spec.rb +++ b/spec/integration/indirector/catalog/queue_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' require 'puppet/resource/catalog' -describe "Puppet::Resource::Catalog::Queue", :if => Puppet.features.pson? do +describe "Puppet::Resource::Catalog::Queue" do before do Puppet::Resource::Catalog.indirection.terminus(:queue) @catalog = Puppet::Resource::Catalog.new diff --git a/spec/integration/network/formats_spec.rb b/spec/integration/network/formats_spec.rb index 5a328a3cb..2834e33f0 100755 --- a/spec/integration/network/formats_spec.rb +++ b/spec/integration/network/formats_spec.rb @@ -45,60 +45,47 @@ describe Puppet::Network::FormatHandler.format(:s) do end describe Puppet::Network::FormatHandler.format(:pson) do - describe "when pson is absent", :if => (! Puppet.features.pson?) do - - before do - @pson = Puppet::Network::FormatHandler.format(:pson) - end - - it "should not be suitable" do - @pson.should_not be_suitable - end + before do + @pson = Puppet::Network::FormatHandler.format(:pson) end - describe "when pson is available", :if => Puppet.features.pson? do - before do - @pson = Puppet::Network::FormatHandler.format(:pson) - end - - it "should be able to render an instance to pson" do - instance = PsonIntTest.new("foo") - PsonIntTest.canonical_order(@pson.render(instance)).should == PsonIntTest.canonical_order('{"type":"PsonIntTest","data":["foo"]}' ) - end + it "should be able to render an instance to pson" do + instance = PsonIntTest.new("foo") + PsonIntTest.canonical_order(@pson.render(instance)).should == PsonIntTest.canonical_order('{"type":"PsonIntTest","data":["foo"]}' ) + end - it "should be able to render arrays to pson" do - @pson.render([1,2]).should == '[1,2]' - end + it "should be able to render arrays to pson" do + @pson.render([1,2]).should == '[1,2]' + end - it "should be able to render arrays containing hashes to pson" do - @pson.render([{"one"=>1},{"two"=>2}]).should == '[{"one":1},{"two":2}]' - end + it "should be able to render arrays containing hashes to pson" do + @pson.render([{"one"=>1},{"two"=>2}]).should == '[{"one":1},{"two":2}]' + end - it "should be able to render multiple instances to pson" do - one = PsonIntTest.new("one") - two = PsonIntTest.new("two") + it "should be able to render multiple instances to pson" do + one = PsonIntTest.new("one") + two = PsonIntTest.new("two") - PsonIntTest.canonical_order(@pson.render([one,two])).should == PsonIntTest.canonical_order('[{"type":"PsonIntTest","data":["one"]},{"type":"PsonIntTest","data":["two"]}]') - end + PsonIntTest.canonical_order(@pson.render([one,two])).should == PsonIntTest.canonical_order('[{"type":"PsonIntTest","data":["one"]},{"type":"PsonIntTest","data":["two"]}]') + end - it "should be able to intern pson into an instance" do - @pson.intern(PsonIntTest, '{"type":"PsonIntTest","data":["foo"]}').should == PsonIntTest.new("foo") - end + it "should be able to intern pson into an instance" do + @pson.intern(PsonIntTest, '{"type":"PsonIntTest","data":["foo"]}').should == PsonIntTest.new("foo") + end - it "should be able to intern pson with no class information into an instance" do - @pson.intern(PsonIntTest, '["foo"]').should == PsonIntTest.new("foo") - end + it "should be able to intern pson with no class information into an instance" do + @pson.intern(PsonIntTest, '["foo"]').should == PsonIntTest.new("foo") + end - it "should be able to intern multiple instances from pson" do - @pson.intern_multiple(PsonIntTest, '[{"type": "PsonIntTest", "data": ["one"]},{"type": "PsonIntTest", "data": ["two"]}]').should == [ - PsonIntTest.new("one"), PsonIntTest.new("two") - ] - end + it "should be able to intern multiple instances from pson" do + @pson.intern_multiple(PsonIntTest, '[{"type": "PsonIntTest", "data": ["one"]},{"type": "PsonIntTest", "data": ["two"]}]').should == [ + PsonIntTest.new("one"), PsonIntTest.new("two") + ] + end - it "should be able to intern multiple instances from pson with no class information" do - @pson.intern_multiple(PsonIntTest, '[["one"],["two"]]').should == [ - PsonIntTest.new("one"), PsonIntTest.new("two") - ] - end + it "should be able to intern multiple instances from pson with no class information" do + @pson.intern_multiple(PsonIntTest, '[["one"],["two"]]').should == [ + PsonIntTest.new("one"), PsonIntTest.new("two") + ] end end diff --git a/spec/integration/parser/collector_spec.rb b/spec/integration/parser/collector_spec.rb index 27503ba5d..cb210b372 100755 --- a/spec/integration/parser/collector_spec.rb +++ b/spec/integration/parser/collector_spec.rb @@ -1,37 +1,117 @@ #! /usr/bin/env ruby require 'spec_helper' +require 'puppet_spec/compiler' require 'puppet/parser/collector' describe Puppet::Parser::Collector do - before do - @scope = Puppet::Parser::Scope.new(Puppet::Parser::Compiler.new(Puppet::Node.new("mynode"))) + include PuppetSpec::Compiler - @resource = Puppet::Parser::Resource.new("file", "/tmp/testing", :scope => @scope, :source => "fakesource") - {:owner => "root", :group => "bin", :mode => "644"}.each do |param, value| - @resource[param] = value - end + def expect_the_message_to_be(expected_messages, code, node = Puppet::Node.new('the node')) + catalog = compile_to_catalog(code, node) + messages = catalog.resources.find_all { |resource| resource.type == 'Notify' }. + collect { |notify| notify[:message] } + messages.should include(*expected_messages) + end + + it "matches on title" do + expect_the_message_to_be(["the message"], <<-MANIFEST) + @notify { "testing": message => "the message" } + + Notify <| title == "testing" |> + MANIFEST end - def query(text) - code = "File <| #{text} |>" - parser = Puppet::Parser::Parser.new(@scope.compiler) - return parser.parse(code).code[0].query - end - - {true => [%{title == "/tmp/testing"}, %{(title == "/tmp/testing")}, %{group == bin}, - %{title == "/tmp/testing" and group == bin}, %{title == bin or group == bin}, - %{title == "/tmp/testing" or title == bin}, %{title == "/tmp/testing"}, - %{(title == "/tmp/testing" or title == bin) and group == bin}], - false => [%{title == bin}, %{title == bin or (title == bin and group == bin)}, - %{title != "/tmp/testing"}, %{title != "/tmp/testing" and group != bin}] - }.each do |result, ary| - ary.each do |string| - it "should return '#{result}' when collecting resources with '#{string}'" do - str, code = query(string).evaluate @scope - code.should be_instance_of(Proc) - code.call(@resource).should == result - end + it "matches on other parameters" do + expect_the_message_to_be(["the message"], <<-MANIFEST) + @notify { "testing": message => "the message" } + @notify { "other testing": message => "the wrong message" } + + Notify <| message == "the message" |> + MANIFEST + end + + it "allows criteria to be combined with 'and'" do + expect_the_message_to_be(["the message"], <<-MANIFEST) + @notify { "testing": message => "the message" } + @notify { "other": message => "the message" } + + Notify <| title == "testing" and message == "the message" |> + MANIFEST + end + + it "allows criteria to be combined with 'or'" do + expect_the_message_to_be(["the message", "other message"], <<-MANIFEST) + @notify { "testing": message => "the message" } + @notify { "other": message => "other message" } + @notify { "yet another": message => "different message" } + + Notify <| title == "testing" or message == "other message" |> + MANIFEST + end + + it "allows criteria to be combined with 'or'" do + expect_the_message_to_be(["the message", "other message"], <<-MANIFEST) + @notify { "testing": message => "the message" } + @notify { "other": message => "other message" } + @notify { "yet another": message => "different message" } + + Notify <| title == "testing" or message == "other message" |> + MANIFEST + end + + it "allows criteria to be grouped with parens" do + expect_the_message_to_be(["the message", "different message"], <<-MANIFEST) + @notify { "testing": message => "different message", withpath => true } + @notify { "other": message => "the message" } + @notify { "yet another": message => "the message", withpath => true } + + Notify <| (title == "testing" or message == "the message") and withpath == true |> + MANIFEST + end + + it "does not do anything if nothing matches" do + expect_the_message_to_be([], <<-MANIFEST) + @notify { "testing": message => "different message" } + + Notify <| title == "does not exist" |> + MANIFEST + end + + it "excludes items with inequalities" do + expect_the_message_to_be(["good message"], <<-MANIFEST) + @notify { "testing": message => "good message" } + @notify { "the wrong one": message => "bad message" } + + Notify <| title != "the wrong one" |> + MANIFEST + end + + context "issue #10963" do + it "collects with override when inside a class" do + expect_the_message_to_be(["overridden message"], <<-MANIFEST) + @notify { "testing": message => "original message" } + + include collector_test + class collector_test { + Notify <| |> { + message => "overridden message" + } + } + MANIFEST + end + + it "collects with override when inside a define" do + expect_the_message_to_be(["overridden message"], <<-MANIFEST) + @notify { "testing": message => "original message" } + + collector_test { testing: } + define collector_test() { + Notify <| |> { + message => "overridden message" + } + } + MANIFEST end end end diff --git a/spec/integration/parser/ruby_manifest_spec.rb b/spec/integration/parser/ruby_manifest_spec.rb index e9cd819a7..75e9dd9be 100755 --- a/spec/integration/parser/ruby_manifest_spec.rb +++ b/spec/integration/parser/ruby_manifest_spec.rb @@ -13,6 +13,7 @@ describe "Pure ruby manifests" do @scope_resource = stub 'scope_resource', :builtin? => true, :finish => nil, :ref => 'Class[main]' @scope = stub 'scope', :resource => @scope_resource, :source => mock("source") @test_dir = tmpdir('ruby_manifest_test') + Puppet.expects(:deprecation_warning).at_least(1) end after do diff --git a/spec/integration/parser/scope_spec.rb b/spec/integration/parser/scope_spec.rb index 5bad1166e..66d29a438 100644 --- a/spec/integration/parser/scope_spec.rb +++ b/spec/integration/parser/scope_spec.rb @@ -4,7 +4,7 @@ require 'puppet_spec/compiler' describe "Two step scoping for variables" do include PuppetSpec::Compiler - def expect_the_message_to_be(message, node = Puppet::Node.new('the node')) + def expect_the_message_to_be(message, node = Puppet::Node.new('the node')) catalog = compile_to_catalog(yield, node) catalog.resource('Notify', 'something')[:message].should == message end @@ -13,6 +13,69 @@ describe "Two step scoping for variables" do Puppet.expects(:deprecation_warning).never end + describe "fully qualified variable names" do + it "keeps nodescope separate from topscope" do + expect_the_message_to_be('topscope') do <<-MANIFEST + $c = "topscope" + node default { + $c = "nodescope" + notify { 'something': message => $::c } + } + MANIFEST + end + end + end + + describe "when colliding class and variable names" do + it "finds a topscope variable with the same name as a class" do + expect_the_message_to_be('topscope') do <<-MANIFEST + $c = "topscope" + class c { } + node default { + include c + notify { 'something': message => $c } + } + MANIFEST + end + end + + it "finds a node scope variable with the same name as a class" do + expect_the_message_to_be('nodescope') do <<-MANIFEST + class c { } + node default { + $c = "nodescope" + include c + notify { 'something': message => $c } + } + MANIFEST + end + end + + it "finds a class variable when the class collides with a nodescope variable" do + expect_the_message_to_be('class') do <<-MANIFEST + class c { $b = "class" } + node default { + $c = "nodescope" + include c + notify { 'something': message => $c::b } + } + MANIFEST + end + end + + it "finds a class variable when the class collides with a topscope variable" do + expect_the_message_to_be('class') do <<-MANIFEST + $c = "topscope" + class c { $b = "class" } + node default { + include c + notify { 'something': message => $::c::b } + } + MANIFEST + end + end + end + describe "when using shadowing and inheritance" do it "finds value define in the inherited node" do expect_the_message_to_be('parent_msg') do <<-MANIFEST diff --git a/spec/integration/resource/catalog_spec.rb b/spec/integration/resource/catalog_spec.rb index 9d5d7ef0b..5877b4984 100755 --- a/spec/integration/resource/catalog_spec.rb +++ b/spec/integration/resource/catalog_spec.rb @@ -2,10 +2,8 @@ require 'spec_helper' describe Puppet::Resource::Catalog do - describe "when pson is available", :if => Puppet.features.pson? do - it "should support pson" do - Puppet::Resource::Catalog.supported_formats.should be_include(:pson) - end + it "should support pson" do + Puppet::Resource::Catalog.supported_formats.should be_include(:pson) end describe "when using the indirector" do diff --git a/spec/integration/type/package_spec.rb b/spec/integration/type/package_spec.rb index bd328b93a..34d648d4d 100755 --- a/spec/integration/type/package_spec.rb +++ b/spec/integration/type/package_spec.rb @@ -11,7 +11,7 @@ describe Puppet::Type.type(:package), "when choosing a default package provider" if Facter.value(:operatingsystem) == 'Solaris' && Puppet::Util::Package.versioncmp(Facter.value(:kernelrelease), '5.11') >= 0 :pkg else - {"Ubuntu" => :apt, "Debian" => :apt, "Darwin" => :pkgdmg, "RedHat" => :up2date, "Fedora" => :yum, "FreeBSD" => :ports, "OpenBSD" => :openbsd, "Solaris" => :sun}[os] + {"Ubuntu" => :apt, "Debian" => :apt, "Darwin" => :pkgdmg, "RedHat" => :up2date, "Fedora" => :yum, "FreeBSD" => :ports, "OpenBSD" => :openbsd, "Solaris" => :sun, "DragonFly" => :pkgin}[os] end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 3c9aad056..4f67f7218 100755 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -47,6 +47,17 @@ end RSpec.configure do |config| include PuppetSpec::Fixtures + # Examples or groups can selectively tag themselves as broken. + # For example; + # + # rbv = "#{RUBY_VERSION}-p#{RbConfig::CONFIG['PATCHLEVEL']}" + # describe "mostly working", :broken => false unless rbv == "1.9.3-p327" do + # it "parses a valid IP" do + # IPAddr.new("::2:3:4:5:6:7:8") + # end + # end + config.filter_run_excluding :broken => true + config.mock_with :mocha tmpdir = Dir.mktmpdir("rspecrun") @@ -59,6 +70,8 @@ RSpec.configure do |config| config.formatters.each { |f| f.instance_variable_set(:@output, $stdout) } end + Puppet::Test::TestHelper.initialize + config.before :all do Puppet::Test::TestHelper.before_all_tests() end diff --git a/spec/unit/application/agent_spec.rb b/spec/unit/application/agent_spec.rb index 275a9ad5f..9bcbad6ee 100755 --- a/spec/unit/application/agent_spec.rb +++ b/spec/unit/application/agent_spec.rb @@ -455,7 +455,6 @@ describe Puppet::Application::Agent do describe "when setting up listen" do before :each do - Puppet[:authconfig] = 'auth' FileTest.stubs(:exists?).with('auth').returns(true) File.stubs(:exist?).returns(true) @puppetd.options.stubs(:[]).with(:serve).returns([]) diff --git a/spec/unit/application/apply_spec.rb b/spec/unit/application/apply_spec.rb index ce75a6a78..c2a935c62 100755 --- a/spec/unit/application/apply_spec.rb +++ b/spec/unit/application/apply_spec.rb @@ -208,7 +208,7 @@ describe Puppet::Application::Apply do it "should raise an error if we can't find the node" do Puppet::Node.indirection.expects(:find).returns(nil) - lambda { @apply.main }.should raise_error + lambda { @apply.main }.should raise_error(RuntimeError, /Could not find node/) end it "should load custom classes if loadclasses" do diff --git a/spec/unit/application/face_base_spec.rb b/spec/unit/application/face_base_spec.rb index bf27872e6..88b9aeb07 100755 --- a/spec/unit/application/face_base_spec.rb +++ b/spec/unit/application/face_base_spec.rb @@ -58,9 +58,10 @@ describe Puppet::Application::FaceBase do it "should stop if the first thing found is not an action" do app.command_line.stubs(:args).returns %w{banana count_args} + expect { app.run }.to exit_with 1 - @logs.first.should_not be_nil - @logs.first.message.should =~ /has no 'banana' action/ + + @logs.map(&:message).should == ["'basetest' has no 'banana' action. See `puppet help basetest`."] end it "should use the default action if not given any arguments" do @@ -161,12 +162,18 @@ describe Puppet::Application::FaceBase do it "does not skip when a puppet global setting is given as one item" do app.command_line.stubs(:args).returns %w{--confdir=/tmp/puppet foo} - expect { app.preinit; app.parse_options }.not_to raise_error + app.preinit + app.parse_options + app.action.name.should == :foo + app.options.should == {} end it "does not skip when a puppet global setting is given as two items" do app.command_line.stubs(:args).returns %w{--confdir /tmp/puppet foo} - expect { app.preinit; app.parse_options }.not_to raise_error + app.preinit + app.parse_options + app.action.name.should == :foo + app.options.should == {} end { "boolean options before" => %w{--trace foo}, diff --git a/spec/unit/application/indirection_base_spec.rb b/spec/unit/application/indirection_base_spec.rb index 8257657f2..1610f85ff 100755 --- a/spec/unit/application/indirection_base_spec.rb +++ b/spec/unit/application/indirection_base_spec.rb @@ -1,5 +1,6 @@ #! /usr/bin/env ruby require 'spec_helper' +require 'puppet/util/command_line' require 'puppet/application/indirection_base' require 'puppet/indirector/face' @@ -20,8 +21,6 @@ Puppet::Face.register(face) ######################################################################## describe Puppet::Application::IndirectionBase do - subject { Puppet::Application::TestIndirection.new } - it "should accept a terminus command line option" do # It would be nice not to have to stub this, but whatever... writing an # entire indirection stack would cause us more grief. --daniel 2011-03-31 @@ -35,14 +34,11 @@ describe Puppet::Application::IndirectionBase do Puppet::Indirector::Indirection.expects(:instance). with(:test_indirection).returns(terminus) - subject.command_line.instance_variable_set('@args', %w{--terminus foo save bar}) - - # Not a very nice thing. :( - $stderr.stubs(:puts) - Puppet.stubs(:err) + command_line = Puppet::Util::CommandLine.new("puppet", %w{test_indirection --terminus foo save bar}) + application = Puppet::Application::TestIndirection.new(command_line) expect { - subject.run + application.run }.to exit_with 0 end end diff --git a/spec/unit/application/kick_spec.rb b/spec/unit/application/kick_spec.rb index 4b540d496..57217685b 100755 --- a/spec/unit/application/kick_spec.rb +++ b/spec/unit/application/kick_spec.rb @@ -14,8 +14,11 @@ describe Puppet::Application::Kick, :if => Puppet.features.posix? do describe ".new" do it "should take a command-line object as an argument" do - command_line = stub_everything "command_line" - lambda{ Puppet::Application::Kick.new( command_line ) }.should_not raise_error + command_line = Puppet::Util::CommandLine.new("puppet", ['kick', 'myhost']) + app = Puppet::Application::Kick.new(command_line) + + app.command_line.subcommand_name.should == "kick" + app.command_line.args.should == ['myhost'] end end diff --git a/spec/unit/application/master_spec.rb b/spec/unit/application/master_spec.rb index 932f9cfcd..689a6c692 100755 --- a/spec/unit/application/master_spec.rb +++ b/spec/unit/application/master_spec.rb @@ -242,12 +242,6 @@ describe Puppet::Application::Master, :unless => Puppet.features.microsoft_windo Puppet[:manifest] = "site.pp" Puppet.stubs(:err) @master.stubs(:jj) - Puppet.features.stubs(:pson?).returns true - end - - it "should fail if pson isn't available" do - Puppet.features.expects(:pson?).returns false - lambda { @master.compile }.should raise_error end it "should compile a catalog for the specified node" do diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb index ccdd6667a..912416d53 100755 --- a/spec/unit/application_spec.rb +++ b/spec/unit/application_spec.rb @@ -17,6 +17,20 @@ describe Puppet::Application do end + describe "application commandline" do + it "should not pick up changes to the array of arguments" do + args = %w{subcommand --arg} + command_line = Puppet::Util::CommandLine.new('puppet', args) + app = Puppet::Application.new(command_line) + + args[0] = 'different_subcommand' + args[1] = '--other-arg' + + app.command_line.subcommand_name.should == 'subcommand' + app.command_line.args.should == ['--arg'] + end + end + describe "application defaults" do it "should fail if required app default values are missing" do @app.stubs(:app_defaults).returns({ :foo => 'bar' }) @@ -48,7 +62,9 @@ describe Puppet::Application do value =~ /no such file to load|cannot load such file/ end - expect { @klass.find("ThisShallNeverEverEverExist") }.to raise_error(LoadError) + expect { + @klass.find("ThisShallNeverEverEverExist") + }.to raise_error(LoadError) end it "#12114: should prevent File namespace collisions" do @@ -58,6 +74,27 @@ describe Puppet::Application do end end + describe "#available_application_names" do + it 'should be able to find available application names' do + apps = %w{describe filebucket kick queue resource agent cert apply doc master} + Puppet::Util::Autoload.expects(:files_to_load).returns(apps) + + Puppet::Application.available_application_names.should =~ apps + end + + it 'should find applications from multiple paths' do + Puppet::Util::Autoload.expects(:files_to_load).with('puppet/application').returns(%w{ /a/foo.rb /b/bar.rb }) + + Puppet::Application.available_application_names.should =~ %w{ foo bar } + end + + it 'should return unique application names' do + Puppet::Util::Autoload.expects(:files_to_load).with('puppet/application').returns(%w{ /a/foo.rb /b/foo.rb }) + + Puppet::Application.available_application_names.should == %w{ foo } + end + end + describe ".run_mode" do it "should default to user" do @appclass.run_mode.name.should == :user @@ -103,19 +140,6 @@ describe Puppet::Application do end end - - it "it should not allow initialize_app_defaults to be called multiple times" do - app = Puppet::Application.new - expect { - app.initialize_app_defaults - }.to_not raise_error - - expect { - app.initialize_app_defaults - }.to raise_error - end - - it "should explode when an invalid run mode is set at runtime, for great victory" do expect { class InvalidRunModeTestApp < Puppet::Application diff --git a/spec/unit/face/help_spec.rb b/spec/unit/face/help_spec.rb index 15c2e682e..d81031ee3 100755 --- a/spec/unit/face/help_spec.rb +++ b/spec/unit/face/help_spec.rb @@ -72,7 +72,7 @@ describe Puppet::Face[:help, '0.0.1'] do # that can't be run from the command line, so, rather than iterating # over all available faces, we need to iterate over the subcommands # that are available from the command line. - Puppet::Util::CommandLine.available_subcommands.each do |name| + Puppet::Application.available_application_names.each do |name| next unless help_face.is_face_app?(name) next if help_face.exclude_from_docs?(name) face = Puppet::Face[name, :current] @@ -84,12 +84,10 @@ describe Puppet::Face[:help, '0.0.1'] do end context "face summaries" do - # we need to set a bunk module path here, because without doing so, - # the autoloader will try to use it before it is initialized. - Puppet[:modulepath] = "/dev/null" - - Puppet::Face.faces.each do |name| - it "has a summary for #{name}" do + it "can generate face summaries" do + faces = Puppet::Face.faces + faces.length.should > 0 + faces.each do |name| Puppet::Face[name, :current].should have_a_summary end end diff --git a/spec/unit/indirector/certificate_request/rest_spec.rb b/spec/unit/indirector/certificate_request/rest_spec.rb index 47e19d95e..4949bff76 100755 --- a/spec/unit/indirector/certificate_request/rest_spec.rb +++ b/spec/unit/indirector/certificate_request/rest_spec.rb @@ -19,4 +19,8 @@ describe Puppet::SSL::CertificateRequest::Rest do it "should set port_setting to :ca_port" do Puppet::SSL::CertificateRequest::Rest.port_setting.should == :ca_port end + + it "should use the :ca SRV service" do + Puppet::SSL::CertificateRequest::Rest.srv_service.should == :ca + end end diff --git a/spec/unit/indirector/certificate_revocation_list/rest_spec.rb b/spec/unit/indirector/certificate_revocation_list/rest_spec.rb index 4da306865..f8d37c341 100755 --- a/spec/unit/indirector/certificate_revocation_list/rest_spec.rb +++ b/spec/unit/indirector/certificate_revocation_list/rest_spec.rb @@ -19,4 +19,8 @@ describe Puppet::SSL::CertificateRevocationList::Rest do it "should set port_setting to :ca_port" do Puppet::SSL::CertificateRevocationList::Rest.port_setting.should == :ca_port end + + it "should use the :ca SRV service" do + Puppet::SSL::CertificateRevocationList::Rest.srv_service.should == :ca + end end diff --git a/spec/unit/indirector/certificate_status/rest_spec.rb b/spec/unit/indirector/certificate_status/rest_spec.rb index c09855a6f..33dff7528 100755 --- a/spec/unit/indirector/certificate_status/rest_spec.rb +++ b/spec/unit/indirector/certificate_status/rest_spec.rb @@ -11,4 +11,8 @@ describe "Puppet::CertificateStatus::Rest" do it "should be a terminus on Puppet::SSL::Host" do @terminus.should be_instance_of(Puppet::Indirector::CertificateStatus::Rest) end + + it "should use the :ca SRV service" do + Puppet::Indirector::CertificateStatus::Rest.srv_service.should == :ca + end end diff --git a/spec/unit/indirector/file_metadata/rest_spec.rb b/spec/unit/indirector/file_metadata/rest_spec.rb index a1b6af41e..ddc4d9d7e 100755 --- a/spec/unit/indirector/file_metadata/rest_spec.rb +++ b/spec/unit/indirector/file_metadata/rest_spec.rb @@ -2,7 +2,12 @@ require 'spec_helper' require 'puppet/indirector/file_metadata' +require 'puppet/indirector/file_metadata/rest' describe "Puppet::Indirector::Metadata::Rest" do it "should add the node's cert name to the arguments" + + it "should use the :fileserver SRV service" do + Puppet::Indirector::FileMetadata::Rest.srv_service.should == :fileserver + end end diff --git a/spec/unit/indirector/hiera_spec.rb b/spec/unit/indirector/hiera_spec.rb index 0ab433e21..794a4b01f 100644 --- a/spec/unit/indirector/hiera_spec.rb +++ b/spec/unit/indirector/hiera_spec.rb @@ -96,7 +96,9 @@ describe Puppet::Indirector::Hiera do it "should return a hiera configuration hash" do results = @hiera_class.hiera_config - results.should == default_hiera_config + default_hiera_config.each do |key,value| + results[key].should == value + end results.should be_a_kind_of Hash end diff --git a/spec/unit/indirector/queue_spec.rb b/spec/unit/indirector/queue_spec.rb index b90837199..3711b1846 100755 --- a/spec/unit/indirector/queue_spec.rb +++ b/spec/unit/indirector/queue_spec.rb @@ -25,7 +25,7 @@ class FooExampleData end end -describe Puppet::Indirector::Queue, :if => Puppet.features.pson? do +describe Puppet::Indirector::Queue do before :each do @model = mock 'model' @indirection = stub 'indirection', :name => :my_queue, :register_terminus_type => nil, :model => @model @@ -46,12 +46,6 @@ describe Puppet::Indirector::Queue, :if => Puppet.features.pson? do @request = stub 'request', :key => :me, :instance => @subject end - it "should require PSON" do - Puppet.features.expects(:pson?).returns false - - expect { @store_class.new }.to raise_error(ArgumentError) - end - it 'should use the correct client type and queue' do @store.queue.should == :my_queue @store.client.should be_an_instance_of(Puppet::Indirector::Queue::TestClient) diff --git a/spec/unit/indirector/ssl_file_spec.rb b/spec/unit/indirector/ssl_file_spec.rb index aa4a34971..4cc0e216f 100755 --- a/spec/unit/indirector/ssl_file_spec.rb +++ b/spec/unit/indirector/ssl_file_spec.rb @@ -27,6 +27,12 @@ describe Puppet::Indirector::SslFile do Puppet[:trace] = false end + after :each do + @file_class.store_in nil + @file_class.store_at nil + @file_class.store_ca_at nil + end + it "should use :main and :ssl upon initialization" do Puppet.settings.expects(:use).with(:main, :ssl) @file_class.new @@ -43,11 +49,12 @@ describe Puppet::Indirector::SslFile do end it "should fail if no store directory or file location has been set" do + Puppet.settings.expects(:use).with(:main, :ssl) @file_class.store_in nil @file_class.store_at nil - FileTest.expects(:exists?).with(File.dirname(@path)).at_least(0).returns(true) - Dir.stubs(:mkdir).with(@path) - lambda { @file_class.new }.should raise_error(Puppet::DevError, /No file or directory setting provided/) + expect { + @file_class.new + }.to raise_error(Puppet::DevError, /No file or directory setting provided/) end describe "when managing ssl files" do @@ -113,30 +120,45 @@ describe Puppet::Indirector::SslFile do describe "when finding certificates on disk" do describe "and no certificate is present" do - before do - # Stub things so the case management bits work. - FileTest.stubs(:exist?).with(File.dirname(@certpath)).returns false - FileTest.expects(:exist?).with(@certpath).returns false - end - it "should return nil" do + FileTest.expects(:exist?).with(@path).returns(true) + Dir.expects(:entries).with(@path).returns([]) + FileTest.expects(:exist?).with(@certpath).returns(false) + @searcher.find(@request).should be_nil end end describe "and a certificate is present" do - before do - FileTest.expects(:exist?).with(@certpath).returns true - end + let(:cert) { mock 'cert' } + let(:model) { mock 'model' } - it "should return an instance of the model, which it should use to read the certificate" do - cert = mock 'cert' - model = mock 'model' + before(:each) do @file_class.stubs(:model).returns model + end + + context "is readable" do + it "should return an instance of the model, which it should use to read the certificate" do + FileTest.expects(:exist?).with(@certpath).returns true + + model.expects(:new).with("myname").returns cert + cert.expects(:read).with(@certpath) + + @searcher.find(@request).should equal(cert) + end + end - model.expects(:new).with("myname").returns cert - cert.expects(:read).with(@certpath) - @searcher.find(@request).should equal(cert) + context "is unreadable" do + it "should raise an exception" do + FileTest.expects(:exist?).with(@certpath).returns(true) + + model.expects(:new).with("myname").returns cert + cert.expects(:read).with(@certpath).raises(Errno::EACCES) + + expect { + @searcher.find(@request) + }.to raise_error(Errno::EACCES) + end end end @@ -262,41 +284,46 @@ describe Puppet::Indirector::SslFile do end describe "when searching for certificates" do - before do - @model = mock 'model' - @file_class.stubs(:model).returns @model + let(:one) { stub 'one' } + let(:two) { stub 'two' } + let(:one_path) { File.join(@path, 'one.pem') } + let(:two_path) { File.join(@path, 'two.pem') } + let(:model) { mock 'model' } + + before :each do + @file_class.stubs(:model).returns model end - it "should return a certificate instance for all files that exist" do - Dir.expects(:entries).with(@path).returns %w{one.pem two.pem} - one = stub 'one', :read => nil - two = stub 'two', :read => nil + it "should return a certificate instance for all files that exist" do + Dir.expects(:entries).with(@path).returns(%w{. .. one.pem two.pem}) - @model.expects(:new).with("one").returns one - @model.expects(:new).with("two").returns two + model.expects(:new).with("one").returns one + one.expects(:read).with(one_path) + model.expects(:new).with("two").returns two + two.expects(:read).with(two_path) @searcher.search(@request).should == [one, two] end - it "should read each certificate in using the model's :read method" do - Dir.expects(:entries).with(@path).returns %w{one.pem} - - one = stub 'one' - one.expects(:read).with(File.join(@path, "one.pem")) + it "should raise an exception if any file is unreadable" do + Dir.expects(:entries).with(@path).returns(%w{. .. one.pem two.pem}) - @model.expects(:new).with("one").returns one + model.expects(:new).with("one").returns(one) + one.expects(:read).with(one_path) + model.expects(:new).with("two").returns(two) + two.expects(:read).raises(Errno::EACCES) - @searcher.search(@request) + expect { + @searcher.search(@request) + }.to raise_error(Errno::EACCES) end it "should skip any files that do not match /\.pem$/" do - Dir.expects(:entries).with(@path).returns %w{. .. one.pem} - - one = stub 'one', :read => nil + Dir.expects(:entries).with(@path).returns(%w{. .. one two.notpem}) - @model.expects(:new).with("one").returns one + model.expects(:new).never - @searcher.search(@request) + @searcher.search(@request).should == [] end end end diff --git a/spec/unit/module_spec.rb b/spec/unit/module_spec.rb index a79320a45..24cc16ee9 100755 --- a/spec/unit/module_spec.rb +++ b/spec/unit/module_spec.rb @@ -521,7 +521,7 @@ describe Puppet::Module do mod end - describe "when loading the metadata file", :if => Puppet.features.pson? do + describe "when loading the metadata file" do before do @data = { :license => "GPL2", diff --git a/spec/unit/module_tool_spec.rb b/spec/unit/module_tool_spec.rb index 0343984d6..93db99afe 100755 --- a/spec/unit/module_tool_spec.rb +++ b/spec/unit/module_tool_spec.rb @@ -152,93 +152,126 @@ TREE TREE end end + describe '.set_option_defaults' do - include PuppetSpec::Files - let (:setting) { {:environment => "foo", :modulepath => make_absolute("foo")} } + describe 'option :environment' do + context 'passed:' do + let (:environment) { "ahgkduerh" } + let (:options) { {:environment => environment} } - [:environment, :modulepath].each do |value| - describe "if #{value} is part of options" do - let (:options) { {} } + it 'Puppet[:environment] should be set to the value of the option' do + subject.set_option_defaults options - before(:each) do - options[value] = setting[value] - Puppet[value] = "bar" + Puppet[:environment].should == environment end - it "should set Puppet[#{value}] to the options[#{value}]" do + it 'the option value should not be overridden' do + Puppet[:environment] = :foo subject.set_option_defaults options - Puppet[value].should == options[value] + + options[:environment].should == environment + end + end + + context 'NOT passed:' do + it 'Puppet[:environment] should NOT be overridden' do + Puppet[:environment] = :foo + + subject.set_option_defaults({}) + Puppet[:environment].should == :foo end - it "should not override options[#{value}]" do + it 'the option should be set to the value of Puppet[:environment]' do + options_to_modify = Hash.new + Puppet[:environment] = :abcdefg + + subject.set_option_defaults options_to_modify + + options_to_modify[:environment].should == :abcdefg + end + end + end + + describe 'option :modulepath' do + context 'passed:' do + let (:modulepath) { PuppetSpec::Files.make_absolute('/bar') } + let (:options) { {:modulepath => modulepath} } + + it 'Puppet[:modulepath] should be set to the value of the option' do + subject.set_option_defaults options - options[value].should == setting[value] + + Puppet[:modulepath].should == modulepath end + it 'the option value should not be overridden' do + Puppet[:modulepath] = "/foo" + + subject.set_option_defaults options + + options[:modulepath].should == modulepath + end end - describe "if #{value} is not part of options" do - let (:options) { {} } + context 'NOT passed:' do + let (:options) { {:environment => :pmttestenv} } before(:each) do - Puppet[value] = setting[value] + Puppet[:modulepath] = "/no" + Puppet[:environment] = :pmttestenv + Puppet.settings.set_value(:modulepath, + ["/foo", "/bar", "/no"].join(File::PATH_SEPARATOR), + :pmttestenv) end - it "should populate options[#{value}] with the value of Puppet[#{value}]" do + it 'Puppet[:modulepath] should be reset to the module path of the current environment' do subject.set_option_defaults options - Puppet[value].should == options[value] + + Puppet[:modulepath].should == Puppet.settings.value(:modulepath, :pmttestenv) end - it "should not override Puppet[#{value}]" do + it 'the option should be set to the module path of the current environment' do subject.set_option_defaults options - Puppet[value].should == setting[value] + + options[:modulepath].should == Puppet.settings.value(:modulepath, :pmttestenv) end end end - describe ':target_dir' do - let (:sep) { File::PATH_SEPARATOR } + describe 'option :target_dir' do + let (:target_dir) { 'boo' } - let (:my_fake_path) { - ["/my/fake/dir", "/my/other/dir"].collect { |dir| make_absolute(dir) } .join(sep) - } - let (:options) { {:modulepath => my_fake_path}} + context 'passed:' do + let (:options) { {:target_dir => target_dir} } - describe "when not specified" do + it 'the option value should be prepended to the Puppet[:modulepath]' do + Puppet[:modulepath] = "/fuz" + original_modulepath = Puppet[:modulepath] - it "should set options[:target_dir]" do subject.set_option_defaults options - options[:target_dir].should_not be_nil + + Puppet[:modulepath].should == options[:target_dir] + File::PATH_SEPARATOR + original_modulepath end - it "should be the first path of options[:modulepath]" do + it 'the option value should be turned into an absolute path' do subject.set_option_defaults options - options[:target_dir].should == my_fake_path.split(sep).first - end - end - describe "when specified" do - let (:my_target_dir) { make_absolute("/foo/bar") } - before(:each) do - options[:target_dir] = my_target_dir + options[:target_dir].should == File.expand_path(target_dir) end + end - it "should not be overridden" do - subject.set_option_defaults options - options[:target_dir].should == my_target_dir + describe 'NOT passed:' do + before :each do + Puppet[:modulepath] = 'foo' + File::PATH_SEPARATOR + 'bar' end - it "should be prepended to options[:modulepath]" do + it 'the option should be set to the first component of Puppet[:modulepath]' do + options = Hash.new subject.set_option_defaults options - options[:modulepath].split(sep).first.should == my_target_dir - end - it "should leave the remainder of options[:modulepath] untouched" do - subject.set_option_defaults options - options[:modulepath].split(sep).drop(1).join(sep).should == my_fake_path + options[:target_dir].should == Puppet[:modulepath].split(File::PATH_SEPARATOR)[0] end end - end end end diff --git a/spec/unit/network/authstore_spec.rb b/spec/unit/network/authstore_spec.rb index 6d2309c28..54815ca32 100755 --- a/spec/unit/network/authstore_spec.rb +++ b/spec/unit/network/authstore_spec.rb @@ -1,5 +1,6 @@ #! /usr/bin/env ruby require 'spec_helper' +require 'rbconfig' require 'puppet/network/authconfig' @@ -214,7 +215,6 @@ describe Puppet::Network::AuthStore::Declaration do "1::2:3:4", "1::2:3", "1::8", - "::2:3:4:5:6:7:8", "::2:3:4:5:6:7", "::2:3:4:5:6", "::2:3:4:5", @@ -291,6 +291,27 @@ describe Puppet::Network::AuthStore::Declaration do end unless ip =~ /:.*\./ # Hybrid IPs aren't supported by ruby's ipaddr } + [ + "::2:3:4:5:6:7:8", + ].each { |ip| + describe "when the pattern is a valid IP such as #{ip}" do + let(:declaration) do + Puppet::Network::AuthStore::Declaration.new(:allow_ip,ip) + end + + issue_7477 = !(IPAddr.new(ip) rescue false) + + it "should match the specified IP" do + pending "resolution of ruby issue [7477](http://goo.gl/Bb1LU)", :if => issue_7477 + declaration.should be_match('www.testsite.org',ip) + end + it "should not match other IPs" do + pending "resolution of ruby issue [7477](http://goo.gl/Bb1LU)", :if => issue_7477 + declaration.should_not be_match('www.testsite.org','200.101.99.98') + end + end + } + { 'spirit.mars.nasa.gov' => 'a PQDN', 'ratchet.2ndsiteinc.com' => 'a PQDN with digits', diff --git a/spec/unit/network/formats_spec.rb b/spec/unit/network/formats_spec.rb index bd488ad49..df0d62f4d 100755 --- a/spec/unit/network/formats_spec.rb +++ b/spec/unit/network/formats_spec.rb @@ -220,7 +220,7 @@ describe "Puppet Network Format" do Puppet::Network::FormatHandler.format(:pson).should_not be_nil end - describe "pson", :if => Puppet.features.pson? do + describe "pson" do before do @pson = Puppet::Network::FormatHandler.format(:pson) end @@ -311,6 +311,10 @@ describe "Puppet Network Format" do end end + it "should render empty hashes as empty strings" do + subject.render({}).should == '' + end + it "should render a non-trivially-keyed Hash as JSON" do hash = { [1,2] => 3, [2,3] => 5, [3,4] => 7 } subject.render(hash).should == json.render(hash).chomp diff --git a/spec/unit/parser/collector_spec.rb b/spec/unit/parser/collector_spec.rb index 32e7a1c15..132bddbc5 100755 --- a/spec/unit/parser/collector_spec.rb +++ b/spec/unit/parser/collector_spec.rb @@ -34,7 +34,7 @@ describe Puppet::Parser::Collector, "when initializing" do @collector.equery.should equal(@equery) end - it "should canonize the type name" do + it "should canonicalize the type name" do @collector = Puppet::Parser::Collector.new(@scope, "resource::type", @equery, @vquery, @form) @collector.type.should == "Resource::Type" end diff --git a/spec/unit/parser/functions/create_resources_spec.rb b/spec/unit/parser/functions/create_resources_spec.rb index a7a6e0074..b16f9111b 100755 --- a/spec/unit/parser/functions/create_resources_spec.rb +++ b/spec/unit/parser/functions/create_resources_spec.rb @@ -19,7 +19,7 @@ describe 'function for dynamically creating resources' do end it 'should require two or three arguments' do - expect { @scope.function_create_resources(['foo']) }.to raise_error(ArgumentError, 'create_resources(): wrong number of arguments (1; must be 2 or 3)') + expect { @scope.function_create_resources(['foo']) }.to raise_error(ArgumentError, 'create_resources(): Wrong number of arguments given (1 for minimum 2)') expect { @scope.function_create_resources(['foo', 'bar', 'blah', 'baz']) }.to raise_error(ArgumentError, 'create_resources(): wrong number of arguments (4; must be 2 or 3)') end @@ -50,6 +50,17 @@ describe 'function for dynamically creating resources' do catalog.resource(:file, "/etc/foo")['ensure'].should == 'present' end + it 'should be able to add virtual resources' do + catalog = compile_to_catalog("create_resources('@file', {'/etc/foo'=>{'ensure'=>'present'}})\nrealize(File['/etc/foo'])") + catalog.resource(:file, "/etc/foo")['ensure'].should == 'present' + end + + it 'should be able to add exported resources' do + catalog = compile_to_catalog("create_resources('@@file', {'/etc/foo'=>{'ensure'=>'present'}})") + catalog.resource(:file, "/etc/foo")['ensure'].should == 'present' + catalog.resource(:file, "/etc/foo").exported.should == true + end + it 'should accept multiple types' do catalog = compile_to_catalog("create_resources('notify', {'foo'=>{'message'=>'one'}, 'bar'=>{'message'=>'two'}})") catalog.resource(:notify, "foo")['message'].should == 'one' diff --git a/spec/unit/parser/functions/extlookup_spec.rb b/spec/unit/parser/functions/extlookup_spec.rb index 4bc2702b7..fae32fa97 100755 --- a/spec/unit/parser/functions/extlookup_spec.rb +++ b/spec/unit/parser/functions/extlookup_spec.rb @@ -19,12 +19,12 @@ describe "the extlookup function" do Puppet::Parser::Functions.function("extlookup").should == "function_extlookup" end - it "should raise a ParseError if there is less than 1 arguments" do - lambda { @scope.function_extlookup([]) }.should( raise_error(Puppet::ParseError)) + it "should raise a ArgumentError if there is less than 1 arguments" do + lambda { @scope.function_extlookup([]) }.should( raise_error(ArgumentError)) end - it "should raise a ParseError if there is more than 3 arguments" do - lambda { @scope.function_extlookup(["foo", "bar", "baz", "gazonk"]) }.should( raise_error(Puppet::ParseError)) + it "should raise a ArgumentError if there is more than 3 arguments" do + lambda { @scope.function_extlookup(["foo", "bar", "baz", "gazonk"]) }.should( raise_error(ArgumentError)) end it "should return the default" do diff --git a/spec/unit/parser/functions/hiera_array_spec.rb b/spec/unit/parser/functions/hiera_array_spec.rb index d9e25cef0..e8efb727f 100644 --- a/spec/unit/parser/functions/hiera_array_spec.rb +++ b/spec/unit/parser/functions/hiera_array_spec.rb @@ -8,7 +8,7 @@ describe 'Puppet::Parser::Functions#hiera_array' do let :scope do Puppet::Parser::Scope.new_for_test_harness('foo') end it 'should require a key argument' do - expect { scope.function_hiera_array([]) }.to raise_error(Puppet::ParseError) + expect { scope.function_hiera_array([]) }.to raise_error(ArgumentError) end it 'should raise a useful error when nil is returned' do diff --git a/spec/unit/parser/functions/hiera_hash_spec.rb b/spec/unit/parser/functions/hiera_hash_spec.rb index c7c9d4432..a345a6c7f 100644 --- a/spec/unit/parser/functions/hiera_hash_spec.rb +++ b/spec/unit/parser/functions/hiera_hash_spec.rb @@ -4,7 +4,7 @@ describe 'Puppet::Parser::Functions#hiera_hash' do let :scope do Puppet::Parser::Scope.new_for_test_harness('foo') end it 'should require a key argument' do - expect { scope.function_hiera_hash([]) }.to raise_error(Puppet::ParseError) + expect { scope.function_hiera_hash([]) }.to raise_error(ArgumentError) end it 'should raise a useful error when nil is returned' do diff --git a/spec/unit/parser/functions/hiera_include_spec.rb b/spec/unit/parser/functions/hiera_include_spec.rb index 3fd7b7740..f06d8c69c 100644 --- a/spec/unit/parser/functions/hiera_include_spec.rb +++ b/spec/unit/parser/functions/hiera_include_spec.rb @@ -10,7 +10,7 @@ describe 'Puppet::Parser::Functions#hiera_include' do end it 'should require a key argument' do - expect { scope.function_hiera_include([]) }.to raise_error(Puppet::ParseError) + expect { scope.function_hiera_include([]) }.to raise_error(ArgumentError) end it 'should raise a useful error when nil is returned' do diff --git a/spec/unit/parser/functions/hiera_spec.rb b/spec/unit/parser/functions/hiera_spec.rb index 657d4f6fb..0abcb1b28 100755 --- a/spec/unit/parser/functions/hiera_spec.rb +++ b/spec/unit/parser/functions/hiera_spec.rb @@ -6,7 +6,7 @@ describe 'Puppet::Parser::Functions#hiera' do let :scope do Puppet::Parser::Scope.new_for_test_harness('foo') end it 'should require a key argument' do - expect { scope.function_hiera([]) }.to raise_error(Puppet::ParseError) + expect { scope.function_hiera([]) }.to raise_error(ArgumentError) end it 'should raise a useful error when nil is returned' do diff --git a/spec/unit/parser/functions/regsubst_spec.rb b/spec/unit/parser/functions/regsubst_spec.rb index 439c16270..c75b16c0e 100755 --- a/spec/unit/parser/functions/regsubst_spec.rb +++ b/spec/unit/parser/functions/regsubst_spec.rb @@ -16,12 +16,12 @@ describe "the regsubst function" do Puppet::Parser::Functions.function("regsubst").should == "function_regsubst" end - it "should raise a ParseError if there is less than 3 arguments" do - lambda { @scope.function_regsubst(["foo", "bar"]) }.should( raise_error(Puppet::ParseError)) + it "should raise a ArgumentError if there is less than 3 arguments" do + lambda { @scope.function_regsubst(["foo", "bar"]) }.should( raise_error(ArgumentError)) end - it "should raise a ParseError if there is more than 5 arguments" do - lambda { @scope.function_regsubst(["foo", "bar", "gazonk", "del", "x", "y"]) }.should( raise_error(Puppet::ParseError)) + it "should raise a ArgumentError if there is more than 5 arguments" do + lambda { @scope.function_regsubst(["foo", "bar", "gazonk", "del", "x", "y"]) }.should( raise_error(ArgumentError)) end diff --git a/spec/unit/parser/functions/split_spec.rb b/spec/unit/parser/functions/split_spec.rb index 20a6f4204..5ddbe8d44 100755 --- a/spec/unit/parser/functions/split_spec.rb +++ b/spec/unit/parser/functions/split_spec.rb @@ -16,12 +16,12 @@ describe "the split function" do Puppet::Parser::Functions.function("split").should == "function_split" end - it "should raise a ParseError if there is less than 2 arguments" do - lambda { @scope.function_split(["foo"]) }.should( raise_error(Puppet::ParseError)) + it "should raise a ArgumentError if there is less than 2 arguments" do + lambda { @scope.function_split(["foo"]) }.should( raise_error(ArgumentError)) end - it "should raise a ParseError if there is more than 2 arguments" do - lambda { @scope.function_split(["foo", "bar", "gazonk"]) }.should( raise_error(Puppet::ParseError)) + it "should raise a ArgumentError if there is more than 2 arguments" do + lambda { @scope.function_split(["foo", "bar", "gazonk"]) }.should( raise_error(ArgumentError)) end it "should raise a RegexpError if the regexp is malformed" do diff --git a/spec/unit/parser/functions/sprintf_spec.rb b/spec/unit/parser/functions/sprintf_spec.rb index e1d738e66..36c0ae1b7 100755 --- a/spec/unit/parser/functions/sprintf_spec.rb +++ b/spec/unit/parser/functions/sprintf_spec.rb @@ -16,8 +16,8 @@ describe "the sprintf function" do Puppet::Parser::Functions.function("sprintf").should == "function_sprintf" end - it "should raise a ParseError if there is less than 1 argument" do - lambda { @scope.function_sprintf([]) }.should( raise_error(Puppet::ParseError)) + it "should raise a ArgumentError if there is less than 1 argument" do + lambda { @scope.function_sprintf([]) }.should( raise_error(ArgumentError)) end it "should format integers" do diff --git a/spec/unit/parser/functions/versioncmp_spec.rb b/spec/unit/parser/functions/versioncmp_spec.rb index 5a6668678..760a286c5 100755 --- a/spec/unit/parser/functions/versioncmp_spec.rb +++ b/spec/unit/parser/functions/versioncmp_spec.rb @@ -16,12 +16,12 @@ describe "the versioncmp function" do Puppet::Parser::Functions.function("versioncmp").should == "function_versioncmp" end - it "should raise a ParseError if there is less than 2 arguments" do - lambda { @scope.function_versioncmp(["1.2"]) }.should raise_error(Puppet::ParseError) + it "should raise a ArgumentError if there is less than 2 arguments" do + lambda { @scope.function_versioncmp(["1.2"]) }.should raise_error(ArgumentError) end - it "should raise a ParseError if there is more than 2 arguments" do - lambda { @scope.function_versioncmp(["1.2", "2.4.5", "3.5.6"]) }.should raise_error(Puppet::ParseError) + it "should raise a ArgumentError if there is more than 2 arguments" do + lambda { @scope.function_versioncmp(["1.2", "2.4.5", "3.5.6"]) }.should raise_error(ArgumentError) end it "should call Puppet::Util::Package.versioncmp (included in scope)" do diff --git a/spec/unit/parser/functions_spec.rb b/spec/unit/parser/functions_spec.rb index ef50447da..1430ff26f 100755 --- a/spec/unit/parser/functions_spec.rb +++ b/spec/unit/parser/functions_spec.rb @@ -39,7 +39,7 @@ describe Puppet::Parser::Functions do end end - describe "when calling function to test function existance" do + describe "when calling function to test function existence" do before do @module = Module.new Puppet::Parser::Functions.stubs(:environment_module).returns @module @@ -64,6 +64,56 @@ describe Puppet::Parser::Functions do end end + describe "when calling function to test arity" do + before :each do + Puppet::Node::Environment.stubs(:current).returns(nil) + @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foo")) + @scope = Puppet::Parser::Scope.new(@compiler) + end + + it "should raise an error if the function is called with too many arguments" do + Puppet::Parser::Functions.newfunction("name", :arity => 2) { |args| } + lambda { @scope.function_name([1,2,3]) }.should raise_error ArgumentError + end + + it "should raise an error if the function is called with too few arguments" do + Puppet::Parser::Functions.newfunction("name", :arity => 2) { |args| } + lambda { @scope.function_name([1]) }.should raise_error ArgumentError + end + + it "should not raise an error if the function is called with correct number of arguments" do + Puppet::Parser::Functions.newfunction("name", :arity => 2) { |args| } + lambda { @scope.function_name([1,2]) }.should_not raise_error ArgumentError + end + + it "should raise an error if the variable arg function is called with too few arguments" do + Puppet::Parser::Functions.newfunction("name", :arity => -3) { |args| } + lambda { @scope.function_name([1]) }.should raise_error ArgumentError + end + + it "should not raise an error if the variable arg function is called with correct number of arguments" do + Puppet::Parser::Functions.newfunction("name", :arity => -3) { |args| } + lambda { @scope.function_name([1,2]) }.should_not raise_error ArgumentError + end + + it "should not raise an error if the variable arg function is called with more number of arguments" do + Puppet::Parser::Functions.newfunction("name", :arity => -3) { |args| } + lambda { @scope.function_name([1,2,3]) }.should_not raise_error ArgumentError + end + end + + describe "::arity" do + it "returns the given arity of a function" do + Puppet::Parser::Functions.newfunction("name", :arity => 4) { |args| } + Puppet::Parser::Functions.arity(:name).should == 4 + end + + it "returns -1 if no arity is given" do + Puppet::Parser::Functions.newfunction("name") { |args| } + Puppet::Parser::Functions.arity(:name).should == -1 + end + end + describe "::get_function" do it "can retrieve a function defined on the *root* environment" do Thread.current[:environment] = nil diff --git a/spec/unit/parser/type_loader_spec.rb b/spec/unit/parser/type_loader_spec.rb index 918770c71..e15c05fea 100755 --- a/spec/unit/parser/type_loader_spec.rb +++ b/spec/unit/parser/type_loader_spec.rb @@ -11,6 +11,7 @@ describe Puppet::Parser::TypeLoader do before do @loader = Puppet::Parser::TypeLoader.new(:myenv) + Puppet.expects(:deprecation_warning).never end it "should support an environment" do @@ -146,6 +147,8 @@ describe Puppet::Parser::TypeLoader do end it "should load all ruby manifests from all modules in the specified environment" do + Puppet.expects(:deprecation_warning).at_least(1) + @module1 = mk_module(@modulebase1, "one") @module2 = mk_module(@modulebase2, "two") diff --git a/spec/unit/provider/augeas/augeas_spec.rb b/spec/unit/provider/augeas/augeas_spec.rb index 53d8e8521..77a1621f6 100755 --- a/spec/unit/provider/augeas/augeas_spec.rb +++ b/spec/unit/provider/augeas/augeas_spec.rb @@ -570,6 +570,7 @@ describe provider_class do it "should handle setm commands" do @resource[:changes] = ["set test[1]/Jar/Jar Foo","set test[2]/Jar/Jar Bar","setm test Jar/Jar Binks"] @resource[:context] = "/foo/" + @augeas.expects(:respond_to?).with("setm").returns(true) @augeas.expects(:set).with("/foo/test[1]/Jar/Jar", "Foo").returns(true) @augeas.expects(:set).with("/foo/test[2]/Jar/Jar", "Bar").returns(true) @augeas.expects(:setm).with("/foo/test", "Jar/Jar", "Binks").returns(true) @@ -577,6 +578,36 @@ describe provider_class do @augeas.expects(:close) @provider.execute_changes.should == :executed end + + it "should throw error if setm command not supported" do + @resource[:changes] = ["set test[1]/Jar/Jar Foo","set test[2]/Jar/Jar Bar","setm test Jar/Jar Binks"] + @resource[:context] = "/foo/" + @augeas.expects(:respond_to?).with("setm").returns(false) + @augeas.expects(:set).with("/foo/test[1]/Jar/Jar", "Foo").returns(true) + @augeas.expects(:set).with("/foo/test[2]/Jar/Jar", "Bar").returns(true) + expect { @provider.execute_changes }.to raise_error RuntimeError, /command 'setm' not supported/ + end + + it "should handle clearm commands" do + @resource[:changes] = ["set test[1]/Jar/Jar Foo","set test[2]/Jar/Jar Bar","clearm test Jar/Jar"] + @resource[:context] = "/foo/" + @augeas.expects(:respond_to?).with("clearm").returns(true) + @augeas.expects(:set).with("/foo/test[1]/Jar/Jar", "Foo").returns(true) + @augeas.expects(:set).with("/foo/test[2]/Jar/Jar", "Bar").returns(true) + @augeas.expects(:clearm).with("/foo/test", "Jar/Jar").returns(true) + @augeas.expects(:save).returns(true) + @augeas.expects(:close) + @provider.execute_changes.should == :executed + end + + it "should throw error if clearm command not supported" do + @resource[:changes] = ["set test[1]/Jar/Jar Foo","set test[2]/Jar/Jar Bar","clearm test Jar/Jar"] + @resource[:context] = "/foo/" + @augeas.expects(:respond_to?).with("clearm").returns(false) + @augeas.expects(:set).with("/foo/test[1]/Jar/Jar", "Foo").returns(true) + @augeas.expects(:set).with("/foo/test[2]/Jar/Jar", "Bar").returns(true) + expect { @provider.execute_changes }.to raise_error RuntimeError, /command 'clearm' not supported/ + end end describe "when making changes", :if => Puppet.features.augeas? do diff --git a/spec/unit/provider/package/apt_spec.rb b/spec/unit/provider/package/apt_spec.rb index 5085af105..55ff321d0 100755 --- a/spec/unit/provider/package/apt_spec.rb +++ b/spec/unit/provider/package/apt_spec.rb @@ -76,8 +76,6 @@ Version table: @provider.run_preseed end - it "should fail if a cdrom is listed in the sources list and :allowcdrom is not specified" - describe "when installing" do it "should preseed if a responsefile is provided" do @resource.expects(:[]).with(:responsefile).returns "/my/file" diff --git a/spec/unit/provider/package/openbsd_spec.rb b/spec/unit/provider/package/openbsd_spec.rb index 37f61f69a..42d24e37f 100755 --- a/spec/unit/provider/package/openbsd_spec.rb +++ b/spec/unit/provider/package/openbsd_spec.rb @@ -5,11 +5,36 @@ require 'stringio' provider_class = Puppet::Type.type(:package).provider(:openbsd) describe provider_class do - subject { provider_class } + let(:package) { Puppet::Type.type(:package).new(:name => 'bash', :provider => 'openbsd') } + let(:provider) { provider_class.new(package) } - def package(args = {}) - defaults = { :name => 'bash', :provider => 'openbsd' } - Puppet::Type.type(:package).new(defaults.merge(args)) + def expect_read_from_pkgconf(lines) + pkgconf = stub(:readlines => lines) + File.expects(:exist?).with('/etc/pkg.conf').returns(true) + File.expects(:open).with('/etc/pkg.conf', 'rb').returns(pkgconf) + end + + def expect_pkgadd_with_source(source) + provider.expects(:pkgadd).with do |fullname| + ENV.should_not be_key 'PKG_PATH' + fullname.should == source + end + end + + def expect_pkgadd_with_env_and_name(source, &block) + ENV.should_not be_key 'PKG_PATH' + + provider.expects(:pkgadd).with do |fullname| + ENV.should be_key 'PKG_PATH' + ENV['PKG_PATH'].should == source + + fullname.should == provider.resource[:name] + end + provider.expects(:execpipe).with(['/bin/pkg_info', '-I', provider.resource[:name]]).yields('') + + yield + + ENV.should_not be_key 'PKG_PATH' end before :each do @@ -22,78 +47,167 @@ describe provider_class do context "::instances" do it "should return nil if execution failed" do - subject.expects(:execpipe).raises(Puppet::ExecutionFailure, 'wawawa') - subject.instances.should be_nil + provider_class.expects(:execpipe).raises(Puppet::ExecutionFailure, 'wawawa') + provider_class.instances.should be_nil end it "should return the empty set if no packages are listed" do - subject.expects(:execpipe).with(%w{/bin/pkg_info -a}).yields(StringIO.new('')) - subject.instances.should be_empty + provider_class.expects(:execpipe).with(%w{/bin/pkg_info -a}).yields(StringIO.new('')) + provider_class.instances.should be_empty end it "should return all packages when invoked" do fixture = File.read(my_fixture('pkginfo.list')) - subject.expects(:execpipe).with(%w{/bin/pkg_info -a}).yields(fixture) - subject.instances.map(&:name).sort.should == + provider_class.expects(:execpipe).with(%w{/bin/pkg_info -a}).yields(fixture) + provider_class.instances.map(&:name).sort.should == %w{bash bzip2 expat gettext libiconv lzo openvpn python vim wget}.sort end end context "#install" do it "should fail if the resource doesn't have a source" do - provider = subject.new(package()) - expect { provider.install }. - to raise_error Puppet::Error, /must specify a package source/ + File.expects(:exist?).with('/etc/pkg.conf').returns(false) + + expect { + provider.install + }.to raise_error Puppet::Error, /must specify a package source/ end - it "should install correctly when given a directory-unlike source" do - ENV.should_not be_key 'PKG_PATH' + it "should fail if /etc/pkg.conf exists, but is not readable" do + File.expects(:exist?).with('/etc/pkg.conf').returns(true) + File.expects(:open).with('/etc/pkg.conf', 'rb').raises(Errno::EACCES) + expect { + provider.install + }.to raise_error Errno::EACCES, /Permission denied/ + end + + it "should fail if /etc/pkg.conf exists, but there is no installpath" do + expect_read_from_pkgconf([]) + expect { + provider.install + }.to raise_error Puppet::Error, /No valid installpath found in \/etc\/pkg\.conf and no source was set/ + end + + it "should install correctly when given a directory-unlike source" do source = '/whatever.pkg' - provider = subject.new(package(:source => source)) - provider.expects(:pkgadd).with do |name| - ENV.should_not be_key 'PKG_PATH' - name == source - end + provider.resource[:source] = source + expect_pkgadd_with_source(source) provider.install - ENV.should_not be_key 'PKG_PATH' end it "should install correctly when given a directory-like source" do - ENV.should_not be_key 'PKG_PATH' - source = '/whatever/' - provider = subject.new(package(:source => source)) - provider.expects(:pkgadd).with do |name| - ENV.should be_key 'PKG_PATH' - ENV['PKG_PATH'].should == source + provider.resource[:source] = source + expect_pkgadd_with_env_and_name(source) do + provider.install + end + end - name == provider.resource[:name] + it "should install correctly when given a CDROM installpath" do + dir = '/mnt/cdrom/5.2/packages/amd64/' + expect_read_from_pkgconf(["installpath = #{dir}"]) + expect_pkgadd_with_env_and_name(dir) do + provider.install end - provider.expects(:execpipe).with(%w{/bin/pkg_info -I bash}).yields('') + end + + it "should install correctly when given a ftp mirror" do + url = 'ftp://your.ftp.mirror/pub/OpenBSD/5.2/packages/amd64/' + expect_read_from_pkgconf(["installpath = #{url}"]) + expect_pkgadd_with_env_and_name(url) do + provider.install + end + end + + it "should set the resource's source parameter" do + url = 'ftp://your.ftp.mirror/pub/OpenBSD/5.2/packages/amd64/' + expect_read_from_pkgconf(["installpath = #{url}"]) + expect_pkgadd_with_env_and_name(url) do + provider.install + end + + provider.resource[:source].should == url + end + + it "should strip leading whitespace in installpath" do + dir = '/one/' + lines = ["# Notice the extra spaces after the ='s\n", + "installpath = #{dir}\n", + "# And notice how each line ends with a newline\n"] + + expect_read_from_pkgconf(lines) + expect_pkgadd_with_env_and_name(dir) do + provider.install + end + end + + it "should not require spaces around the equals" do + dir = '/one/' + lines = ["installpath=#{dir}"] + + expect_read_from_pkgconf(lines) + expect_pkgadd_with_env_and_name(dir) do + provider.install + end + end + + it "should be case-insensitive" do + dir = '/one/' + lines = ["INSTALLPATH = #{dir}"] + + expect_read_from_pkgconf(lines) + expect_pkgadd_with_env_and_name(dir) do + provider.install + end + end + + it "should ignore unknown keywords" do + dir = '/one/' + lines = ["foo = bar\n", + "installpath = #{dir}\n"] + + expect_read_from_pkgconf(lines) + expect_pkgadd_with_env_and_name(dir) do + provider.install + end + end + + it "should preserve trailing spaces" do + dir = '/one/ ' + lines = ["installpath = #{dir}"] + + expect_read_from_pkgconf(lines) + expect_pkgadd_with_source(dir) provider.install - ENV.should_not be_key 'PKG_PATH' + end + + %w{ installpath installpath= }.each do |line| + it "should reject '#{line}'" do + expect_read_from_pkgconf([line]) + expect { + provider.install + }.to raise_error(Puppet::Error, /No valid installpath found in \/etc\/pkg\.conf and no source was set/) + end end end context "#get_version" do it "should return nil if execution fails" do - provider = subject.new(package) provider.expects(:execpipe).raises(Puppet::ExecutionFailure, 'wawawa') provider.get_version.should be_nil end it "should return the package version if in the output" do fixture = File.read(my_fixture('pkginfo.list')) - provider = subject.new(package(:name => 'bash')) provider.expects(:execpipe).with(%w{/bin/pkg_info -I bash}).yields(fixture) provider.get_version.should == '3.1.17' end it "should return the empty string if the package is not present" do - provider = subject.new(package(:name => 'zsh')) + provider.resource[:name] = 'zsh' provider.expects(:execpipe).with(%w{/bin/pkg_info -I zsh}).yields(StringIO.new('')) provider.get_version.should == '' end @@ -102,13 +216,12 @@ describe provider_class do context "#query" do it "should return the installed version if present" do fixture = File.read(my_fixture('pkginfo.detail')) - provider = subject.new(package(:name => 'bash')) provider.expects(:pkginfo).with('bash').returns(fixture) provider.query.should == { :ensure => '3.1.17' } end it "should return nothing if not present" do - provider = subject.new(package(:name => 'zsh')) + provider.resource[:name] = 'zsh' provider.expects(:pkginfo).with('zsh').returns('') provider.query.should be_nil end diff --git a/spec/unit/provider/package/pip_spec.rb b/spec/unit/provider/package/pip_spec.rb index 2129da362..2213b6f63 100755 --- a/spec/unit/provider/package/pip_spec.rb +++ b/spec/unit/provider/package/pip_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' provider_class = Puppet::Type.type(:package).provider(:pip) +osfamilies = { 'RedHat' => 'pip-python', 'Not RedHat' => 'pip' } describe provider_class do @@ -30,19 +31,36 @@ describe provider_class do end - describe "instances" do + describe "cmd" do + it "should return pip-python on RedHat systems" do + Facter.stubs(:value).with(:osfamily).returns("RedHat") + provider_class.cmd.should == 'pip-python' + end - it "should return an array when pip is present" do - provider_class.expects(:which).with('pip').returns("/fake/bin/pip") - p = stub("process") - p.expects(:collect).yields("real_package==1.2.5") - provider_class.expects(:execpipe).with("/fake/bin/pip freeze").yields(p) - provider_class.instances + it "should return pip by default" do + Facter.stubs(:value).with(:osfamily).returns("Not RedHat") + provider_class.cmd.should == 'pip' end - it "should return an empty array when pip is missing" do - provider_class.expects(:which).with('pip').returns nil - provider_class.instances.should == [] + end + + describe "instances" do + + osfamilies.each do |osfamily, pip_cmd| + it "should return an array on #{osfamily} when #{pip_cmd} is present" do + Facter.stubs(:value).with(:osfamily).returns(osfamily) + provider_class.expects(:which).with(pip_cmd).returns("/fake/bin/pip") + p = stub("process") + p.expects(:collect).yields("real_package==1.2.5") + provider_class.expects(:execpipe).with("/fake/bin/pip freeze").yields(p) + provider_class.instances + end + + it "should return an empty array on #{osfamily} when #{pip_cmd} is missing" do + Facter.stubs(:value).with(:osfamily).returns(osfamily) + provider_class.expects(:which).with(pip_cmd).returns nil + provider_class.instances.should == [] + end end end @@ -109,11 +127,21 @@ describe provider_class do @provider.install end + it "omits the -e flag (GH-1256)" do + # The -e flag makes the provider non-idempotent + @resource[:ensure] = :installed + @resource[:source] = @url + @provider.expects(:lazy_pip).with() do |*args| + not args.include?("-e") + end + @provider.install + end + it "should install from SCM" do @resource[:ensure] = :installed @resource[:source] = @url @provider.expects(:lazy_pip). - with("install", '-q', '-e', "#{@url}#egg=fake_package") + with("install", '-q', "#{@url}#egg=fake_package") @provider.install end @@ -121,7 +149,7 @@ describe provider_class do @resource[:ensure] = "0123456" @resource[:source] = @url @provider.expects(:lazy_pip). - with("install", "-q", "-e", "#{@url}@0123456#egg=fake_package") + with("install", "-q", "#{@url}@0123456#egg=fake_package") @provider.install end @@ -169,23 +197,29 @@ describe provider_class do @provider.method(:lazy_pip).call "freeze" end - it "should retry if pip has not yet been found" do - @provider.expects(:pip).twice.with('freeze').raises(NoMethodError).then.returns(nil) - @provider.expects(:which).with('pip').returns("/fake/bin/pip") - @provider.method(:lazy_pip).call "freeze" - end - - it "should fail if pip is missing" do - @provider.expects(:pip).with('freeze').raises(NoMethodError) - @provider.expects(:which).with('pip').returns(nil) - expect { @provider.method(:lazy_pip).call("freeze") }.to raise_error(NoMethodError) - end + osfamilies.each do |osfamily, pip_cmd| + it "should retry on #{osfamily} if #{pip_cmd} has not yet been found" do + Facter.stubs(:value).with(:osfamily).returns(osfamily) + @provider.expects(:pip).twice.with('freeze').raises(NoMethodError).then.returns(nil) + @provider.expects(:which).with(pip_cmd).returns("/fake/bin/pip") + @provider.method(:lazy_pip).call "freeze" + end + + it "should fail on #{osfamily} if #{pip_cmd} is missing" do + Facter.stubs(:value).with(:osfamily).returns(osfamily) + @provider.expects(:pip).with('freeze').raises(NoMethodError) + @provider.expects(:which).with(pip_cmd).returns(nil) + expect { @provider.method(:lazy_pip).call("freeze") }.to raise_error(NoMethodError) + end + + it "should output a useful error message on #{osfamily} if #{pip_cmd} is missing" do + Facter.stubs(:value).with(:osfamily).returns(osfamily) + @provider.expects(:pip).with('freeze').raises(NoMethodError) + @provider.expects(:which).with(pip_cmd).returns(nil) + expect { @provider.method(:lazy_pip).call("freeze") }. + to raise_error(NoMethodError, 'Could not locate the pip command.') + end - it "should output a useful error message if pip is missing" do - @provider.expects(:pip).with('freeze').raises(NoMethodError) - @provider.expects(:which).with('pip').returns(nil) - expect { @provider.method(:lazy_pip).call("freeze") }. - to raise_error(NoMethodError, 'Could not locate the pip command.') end end diff --git a/spec/unit/provider/package/portage_spec.rb b/spec/unit/provider/package/portage_spec.rb new file mode 100644 index 000000000..48726918c --- /dev/null +++ b/spec/unit/provider/package/portage_spec.rb @@ -0,0 +1,65 @@ +#! /usr/bin/env ruby + +require 'spec_helper' + +provider = Puppet::Type.type(:package).provider(:portage) + +describe provider do + before do + packagename="sl" + @resource = stub('resource', :[] => packagename,:should => true) + @provider = provider.new(@resource) + + portage = stub(:executable => "foo",:execute => true) + Puppet::Provider::CommandDefiner.stubs(:define).returns(portage) + + @nomatch_result = "" + @match_result = "app-misc sl [] [] http://www.tkl.iis.u-tokyo.ac.jp/~toyoda/index_e.html http://www.izumix.org.uk/sl/ sophisticated graphical program which corrects your miss typing\n" + end + + it "is versionable" do + provider.should be_versionable + end + + it "uses :emerge to install packages" do + @provider.expects(:emerge) + + @provider.install + end + + it "uses query to find the latest package" do + @provider.expects(:query).returns({:versions_available => "myversion"}) + + @provider.latest + end + + it "uses eix to search the lastest version of a package" do + @provider.stubs(:update_eix) + @provider.expects(:eix).returns(StringIO.new(@match_result)) + + @provider.query + end + + it "eix arguments must not include --stable" do + @provider.class.eix_search_arguments.should_not include("--stable") + end + + it "eix arguments must not include --exact" do + @provider.class.eix_search_arguments.should_not include("--exact") + end + + it "query uses default arguments" do + @provider.stubs(:update_eix) + @provider.expects(:eix).returns(StringIO.new(@match_result)) + @provider.class.expects(:eix_search_arguments).returns([]) + + @provider.query + end + + it "can handle search output with empty square brackets" do + @provider.stubs(:update_eix) + @provider.expects(:eix).returns(StringIO.new(@match_result)) + + @provider.query[:name].should eq("sl") + end +end diff --git a/spec/unit/provider/service/freebsd_spec.rb b/spec/unit/provider/service/freebsd_spec.rb index ed5452295..0f523e84f 100755 --- a/spec/unit/provider/service/freebsd_spec.rb +++ b/spec/unit/provider/service/freebsd_spec.rb @@ -35,6 +35,14 @@ OUTPUT @provider.rcvar.should == ['# ntpd', 'ntpd_enable="YES"', '# (default: "")'] end + it "should correctly parse rcvar for DragonFly BSD" do + @provider.stubs(:execute).returns <<OUTPUT +# ntpd +$ntpd=YES +OUTPUT + @provider.rcvar.should == ['# ntpd', 'ntpd=YES'] + end + it "should find the right rcvar_value for FreeBSD < 7" do @provider.stubs(:rcvar).returns(['# ntpd', 'ntpd_enable=YES']) diff --git a/spec/unit/provider/service/gentoo_spec.rb b/spec/unit/provider/service/gentoo_spec.rb index 963bb6471..dab315537 100755 --- a/spec/unit/provider/service/gentoo_spec.rb +++ b/spec/unit/provider/service/gentoo_spec.rb @@ -72,12 +72,12 @@ describe Puppet::Type.type(:service).provider(:gentoo) do describe "#start" do it "should use the supplied start command if specified" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :start => '/bin/foo')) - provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :override_locale => false, :squelch => true) provider.start end it "should start the service with <initscript> start otherwise" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) - provider.expects(:execute).with(['/etc/init.d/sshd',:start], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:start], :failonfail => true, :override_locale => false, :squelch => true) provider.expects(:search).with('sshd').returns('/etc/init.d/sshd') provider.start end @@ -86,12 +86,12 @@ describe Puppet::Type.type(:service).provider(:gentoo) do describe "#stop" do it "should use the supplied stop command if specified" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :stop => '/bin/foo')) - provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :override_locale => false, :squelch => true) provider.stop end it "should stop the service with <initscript> stop otherwise" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) - provider.expects(:execute).with(['/etc/init.d/sshd',:stop], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:stop], :failonfail => true, :override_locale => false, :squelch => true) provider.expects(:search).with('sshd').returns('/etc/init.d/sshd') provider.stop end @@ -153,23 +153,23 @@ describe Puppet::Type.type(:service).provider(:gentoo) do describe "when a special status command is specified" do it "should use the status command from the resource" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) - provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never - provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :override_locale => false, :squelch => true) provider.status end it "should return :stopped when the status command returns with a non-zero exitcode" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) - provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never - provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :override_locale => false, :squelch => true) $CHILD_STATUS.stubs(:exitstatus).returns 3 provider.status.should == :stopped end it "should return :running when the status command returns with a zero exitcode" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) - provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never - provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :override_locale => false, :squelch => true) $CHILD_STATUS.stubs(:exitstatus).returns 0 provider.status.should == :running end @@ -178,14 +178,14 @@ describe Puppet::Type.type(:service).provider(:gentoo) do describe "when hasstatus is false" do it "should return running if a pid can be found" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => false)) - provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never provider.expects(:getpid).returns 1000 provider.status.should == :running end it "should return stopped if no pid can be found" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => false)) - provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never provider.expects(:getpid).returns nil provider.status.should == :stopped end @@ -195,7 +195,7 @@ describe Puppet::Type.type(:service).provider(:gentoo) do it "should return running if <initscript> status exits with a zero exitcode" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => true)) provider.expects(:search).with('sshd').returns('/etc/init.d/sshd') - provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :override_locale => false, :squelch => true) $CHILD_STATUS.stubs(:exitstatus).returns 0 provider.status.should == :running end @@ -203,7 +203,7 @@ describe Puppet::Type.type(:service).provider(:gentoo) do it "should return stopped if <initscript> status exits with a non-zero exitcode" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => true)) provider.expects(:search).with('sshd').returns('/etc/init.d/sshd') - provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:status], :failonfail => false, :override_locale => false, :squelch => true) $CHILD_STATUS.stubs(:exitstatus).returns 3 provider.status.should == :stopped end @@ -213,24 +213,24 @@ describe Puppet::Type.type(:service).provider(:gentoo) do describe "#restart" do it "should use the supplied restart command if specified" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :restart => '/bin/foo')) - provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :squelch => true).never - provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :override_locale => false, :squelch => true) provider.restart end it "should restart the service with <initscript> restart if hasrestart is true" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasrestart => true)) provider.expects(:search).with('sshd').returns('/etc/init.d/sshd') - provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :override_locale => false, :squelch => true) provider.restart end it "should restart the service with <initscript> stop/start if hasrestart is false" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasrestart => false)) provider.expects(:search).with('sshd').returns('/etc/init.d/sshd') - provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :squelch => true).never - provider.expects(:execute).with(['/etc/init.d/sshd',:stop], :failonfail => true, :squelch => true) - provider.expects(:execute).with(['/etc/init.d/sshd',:start], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:restart], :failonfail => true, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/etc/init.d/sshd',:stop], :failonfail => true, :override_locale => false, :squelch => true) + provider.expects(:execute).with(['/etc/init.d/sshd',:start], :failonfail => true, :override_locale => false, :squelch => true) provider.restart end end diff --git a/spec/unit/provider/service/launchd_spec.rb b/spec/unit/provider/service/launchd_spec.rb index 8b6fa9d5f..dd22c81a0 100755 --- a/spec/unit/provider/service/launchd_spec.rb +++ b/spec/unit/provider/service/launchd_spec.rb @@ -60,7 +60,6 @@ describe Puppet::Type.type(:service).provider(:launchd) do provider.expects(:get_macosx_version_major).returns("10.6") subject.expects(:plist_from_label).returns([joblabel, {"Disabled" => true}]) provider.expects(:read_plist).returns({joblabel => {"Disabled" => false}}) - provider.stubs(:launchd_overrides).returns(launchd_overrides) FileTest.expects(:file?).with(launchd_overrides).returns(true) subject.enabled?.should == :true end @@ -68,7 +67,6 @@ describe Puppet::Type.type(:service).provider(:launchd) do provider.expects(:get_macosx_version_major).returns("10.6") subject.expects(:plist_from_label).returns([joblabel, {"Disabled" => false}]) provider.expects(:read_plist).returns({joblabel => {"Disabled" => true}}) - provider.stubs(:launchd_overrides).returns(launchd_overrides) FileTest.expects(:file?).with(launchd_overrides).returns(true) subject.enabled?.should == :false end @@ -76,7 +74,6 @@ describe Puppet::Type.type(:service).provider(:launchd) do provider.expects(:get_macosx_version_major).returns("10.6") subject.expects(:plist_from_label).returns([joblabel, {}]) provider.expects(:read_plist).returns({}) - provider.stubs(:launchd_overrides).returns(launchd_overrides) FileTest.expects(:file?).with(launchd_overrides).returns(true) subject.enabled?.should == :true end @@ -122,6 +119,12 @@ describe Puppet::Type.type(:service).provider(:launchd) do subject.expects(:execute).with([:launchctl, :load, '-w', joblabel]) subject.start end + + it "(#16271) Should stop and start the service when a restart is called" do + subject.expects(:stop) + subject.expects(:start) + subject.restart + end end describe "when stopping the service" do @@ -191,7 +194,6 @@ describe Puppet::Type.type(:service).provider(:launchd) do resource[:enable] = true provider.expects(:get_macosx_version_major).returns("10.6") provider.expects(:read_plist).returns({}) - provider.stubs(:launchd_overrides).returns(launchd_overrides) Plist::Emit.expects(:save_plist).once subject.enable end @@ -202,7 +204,6 @@ describe Puppet::Type.type(:service).provider(:launchd) do resource[:enable] = false provider.stubs(:get_macosx_version_major).returns("10.6") provider.stubs(:read_plist).returns({}) - provider.stubs(:launchd_overrides).returns(launchd_overrides) Plist::Emit.expects(:save_plist).once subject.enable end diff --git a/spec/unit/provider/service/openrc_spec.rb b/spec/unit/provider/service/openrc_spec.rb index 489807fe2..aa8162226 100755 --- a/spec/unit/provider/service/openrc_spec.rb +++ b/spec/unit/provider/service/openrc_spec.rb @@ -35,12 +35,12 @@ describe Puppet::Type.type(:service).provider(:openrc) do describe "#start" do it "should use the supplied start command if specified" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :start => '/bin/foo')) - provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :override_locale => false, :squelch => true) provider.start end it "should start the service with rc-service start otherwise" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:start], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:start], :failonfail => true, :override_locale => false, :squelch => true) provider.start end end @@ -48,12 +48,12 @@ describe Puppet::Type.type(:service).provider(:openrc) do describe "#stop" do it "should use the supplied stop command if specified" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :stop => '/bin/foo')) - provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :override_locale => false, :squelch => true) provider.stop end it "should stop the service with rc-service stop otherwise" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd')) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:stop], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:stop], :failonfail => true, :override_locale => false, :squelch => true) provider.stop end end @@ -128,23 +128,23 @@ describe Puppet::Type.type(:service).provider(:openrc) do describe "when a special status command if specified" do it "should use the status command from the resource" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :squelch => true).never - provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :override_locale => false, :squelch => true) provider.status end it "should return :stopped when status command returns with a non-zero exitcode" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :squelch => true).never - provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :override_locale => false, :squelch => true) $CHILD_STATUS.stubs(:exitstatus).returns 3 provider.status.should == :stopped end it "should return :running when status command returns with a zero exitcode" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :status => '/bin/foo')) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :squelch => true).never - provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => false, :override_locale => false, :squelch => true) $CHILD_STATUS.stubs(:exitstatus).returns 0 provider.status.should == :running end @@ -153,14 +153,14 @@ describe Puppet::Type.type(:service).provider(:openrc) do describe "when hasstatus is false" do it "should return running if a pid can be found" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => false)) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never provider.expects(:getpid).returns 1000 provider.status.should == :running end it "should return stopped if no pid can be found" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => false)) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :squelch => true).never + provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :override_locale => false, :squelch => true).never provider.expects(:getpid).returns nil provider.status.should == :stopped end @@ -169,14 +169,14 @@ describe Puppet::Type.type(:service).provider(:openrc) do describe "when hasstatus is true" do it "should return running if rc-service status exits with a zero exitcode" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => true)) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :override_locale => false, :squelch => true) $CHILD_STATUS.stubs(:exitstatus).returns 0 provider.status.should == :running end it "should return stopped if rc-service status exits with a non-zero exitcode" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasstatus => true)) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:status], :failonfail => false, :override_locale => false, :squelch => true) $CHILD_STATUS.stubs(:exitstatus).returns 3 provider.status.should == :stopped end @@ -186,22 +186,22 @@ describe Puppet::Type.type(:service).provider(:openrc) do describe "#restart" do it "should use the supplied restart command if specified" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :restart => '/bin/foo')) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:restart], :failonfail => true, :squelch => true).never - provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:restart], :failonfail => true, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/bin/foo'], :failonfail => true, :override_locale => false, :squelch => true) provider.restart end it "should restart the service with rc-service restart if hasrestart is true" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasrestart => true)) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:restart], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:restart], :failonfail => true, :override_locale => false, :squelch => true) provider.restart end it "should restart the service with rc-service stop/start if hasrestart is false" do provider = described_class.new(Puppet::Type.type(:service).new(:name => 'sshd', :hasrestart => false)) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:restart], :failonfail => true, :squelch => true).never - provider.expects(:execute).with(['/sbin/rc-service','sshd',:stop], :failonfail => true, :squelch => true) - provider.expects(:execute).with(['/sbin/rc-service','sshd',:start], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:restart], :failonfail => true, :override_locale => false, :squelch => true).never + provider.expects(:execute).with(['/sbin/rc-service','sshd',:stop], :failonfail => true, :override_locale => false, :squelch => true) + provider.expects(:execute).with(['/sbin/rc-service','sshd',:start], :failonfail => true, :override_locale => false, :squelch => true) provider.restart end end diff --git a/spec/unit/provider/service/src_spec.rb b/spec/unit/provider/service/src_spec.rb index 9f6f6c917..8d857a060 100755 --- a/spec/unit/provider/service/src_spec.rb +++ b/spec/unit/provider/service/src_spec.rb @@ -35,12 +35,12 @@ describe provider_class do end it "should execute the startsrc command" do - @provider.expects(:execute).with(['/usr/bin/startsrc', '-s', "myservice"], {:squelch => true, :failonfail => true}) + @provider.expects(:execute).with(['/usr/bin/startsrc', '-s', "myservice"], {:override_locale => false, :squelch => true, :failonfail => true}) @provider.start end it "should execute the stopsrc command" do - @provider.expects(:execute).with(['/usr/bin/stopsrc', '-s', "myservice"], {:squelch => true, :failonfail => true}) + @provider.expects(:execute).with(['/usr/bin/stopsrc', '-s', "myservice"], {:override_locale => false, :squelch => true, :failonfail => true}) @provider.stop end @@ -90,8 +90,8 @@ _EOF_ myservice::--no-daemonize:/usr/sbin/puppetd:0:0:/dev/null:/var/log/puppet.log:/var/log/puppet.log:-O:-Q:-S:0:0:20:15:9:-d:20::" _EOF_ @provider.expects(:execute).with(['/usr/bin/lssrc', '-Ss', "myservice"]).returns sample_output - @provider.expects(:execute).with(['/usr/bin/stopsrc', '-s', "myservice"], {:squelch => true, :failonfail => true}) - @provider.expects(:execute).with(['/usr/bin/startsrc', '-s', "myservice"], {:squelch => true, :failonfail => true}) + @provider.expects(:execute).with(['/usr/bin/stopsrc', '-s', "myservice"], {:override_locale => false, :squelch => true, :failonfail => true}) + @provider.expects(:execute).with(['/usr/bin/startsrc', '-s', "myservice"], {:override_locale => false, :squelch => true, :failonfail => true}) @provider.restart end end diff --git a/spec/unit/provider/service/systemd_spec.rb b/spec/unit/provider/service/systemd_spec.rb index 38294d86d..5041c56a9 100755 --- a/spec/unit/provider/service/systemd_spec.rb +++ b/spec/unit/provider/service/systemd_spec.rb @@ -17,14 +17,6 @@ describe provider_class do @provider.resource = @resource end - osfamily = [ 'redhat', 'suse' ] - - osfamily.each do |osfamily| - it "should be the default provider on #{osfamily}" do - pending "This test is pending the change in RedHat-related Linuxes to systemd for service management" - end - end - [:enabled?, :enable, :disable, :start, :stop, :status, :restart].each do |method| it "should have a #{method} method" do @provider.should respond_to(method) diff --git a/spec/unit/provider/service/windows_spec.rb b/spec/unit/provider/service/windows_spec.rb index dfbfe68b2..86ab266f4 100755 --- a/spec/unit/provider/service/windows_spec.rb +++ b/spec/unit/provider/service/windows_spec.rb @@ -119,7 +119,7 @@ describe Puppet::Type.type(:service).provider(:windows), :if => Puppet.features. resource[:restart] = 'c:/bin/foo' provider.expects(:execute).never - provider.expects(:execute).with(['c:/bin/foo'], :failonfail => true, :squelch => true) + provider.expects(:execute).with(['c:/bin/foo'], :failonfail => true, :override_locale => false, :squelch => true) provider.restart end diff --git a/spec/unit/provider/user/hpux_spec.rb b/spec/unit/provider/user/hpux_spec.rb index f20da4b39..4001b6695 100755 --- a/spec/unit/provider/user/hpux_spec.rb +++ b/spec/unit/provider/user/hpux_spec.rb @@ -1,24 +1,52 @@ -#! /usr/bin/env ruby +#!/usr/bin/env ruby require 'spec_helper' +require 'etc' provider_class = Puppet::Type.type(:user).provider(:hpuxuseradd) describe provider_class do - # left from the useradd test... I have no clue what I'm doing. - before do - @resource = stub("resource", :name => "myuser", :managehome? => nil, :should => "fakeval", :[] => "fakeval") - @provider = provider_class.new(@resource) + let :resource do + Puppet::Type.type(:user).new( + :title => 'testuser', + :comment => 'Test J. User', + :provider => :hpuxuseradd + ) end + let(:provider) { resource.provider } it "should add -F when modifying a user" do - @resource.expects(:allowdupe?).returns true - @provider.expects(:execute).with { |args| args.include?("-F") } - @provider.uid = 1000 + resource.stubs(:allowdupe?).returns true + provider.expects(:execute).with { |args| args.include?("-F") } + provider.uid = 1000 end it "should add -F when deleting a user" do - @provider.stubs(:exists?).returns(true) - @provider.expects(:execute).with { |args| args.include?("-F") } - @provider.delete + provider.stubs(:exists?).returns(true) + provider.expects(:execute).with { |args| args.include?("-F") } + provider.delete + end + + context "managing passwords" do + let :pwent do + Struct::Passwd.new("testuser", "foopassword") + end + + before :each do + Etc.stubs(:getpwent).returns(pwent) + Etc.stubs(:getpwnam).returns(pwent) + end + + it "should have feature manages_passwords" do + provider_class.should be_manages_passwords + end + + it "should return nil if user does not exist" do + Etc.stubs(:getpwent).returns(nil) + provider.password.must be_nil + end + + it "should return password entry if exists" do + provider.password.must == "foopassword" + end end end diff --git a/spec/unit/provider/user/useradd_spec.rb b/spec/unit/provider/user/useradd_spec.rb index 254a2cc8b..d11d4f767 100755 --- a/spec/unit/provider/user/useradd_spec.rb +++ b/spec/unit/provider/user/useradd_spec.rb @@ -25,7 +25,7 @@ describe Puppet::Type.type(:user).provider(:useradd) do it "should add -o when allowdupe is enabled and the user is being created" do resource[:allowdupe] = true - provider.expects(:execute).with(['/usr/sbin/useradd', '-o', 'myuser']) + provider.expects(:execute).with(includes('-o')) provider.create end @@ -33,7 +33,7 @@ describe Puppet::Type.type(:user).provider(:useradd) do it "should add -r when system is enabled" do resource[:system] = :true provider.should be_system_users - provider.expects(:execute).with(['/usr/sbin/useradd', '-r', 'myuser']) + provider.expects(:execute).with(includes('-r')) provider.create end end @@ -51,7 +51,7 @@ describe Puppet::Type.type(:user).provider(:useradd) do described_class.has_feature :manages_password_age resource[:password_min_age] = 5 resource[:password_max_age] = 10 - provider.expects(:execute).with(['/usr/sbin/useradd', 'myuser']) + provider.expects(:execute).with(includes('/usr/sbin/useradd')) provider.expects(:execute).with(['/usr/bin/chage', '-m', 5, '-M', 10, 'myuser']) provider.create end @@ -109,42 +109,35 @@ describe Puppet::Type.type(:user).provider(:useradd) do end describe "#check_manage_home" do - it "should check manage home" do - resource.expects(:managehome?) - provider.check_manage_home - end - it "should return an array with -m flag if home is managed" do resource[:managehome] = :true - provider.check_manage_home.must == ["-m"] + provider.expects(:execute).with(includes('-m')) + provider.create end it "should return an array with -r flag if home is managed" do resource[:managehome] = :true resource[:ensure] = :absent - provider.deletecmd.must == ['/usr/sbin/userdel', '-r', 'myuser'] + provider.stubs(:exists?).returns(true) + provider.expects(:execute).with(includes('-r')) + provider.delete end - it "should return an array with -M if home is not managed and on Redhat" do - Facter.stubs(:value).with(:operatingsystem).returns("RedHat") + it "should use -M flag if home is not managed and on Redhat" do + Facter.stubs(:value).with(:osfamily).returns("RedHat") resource[:managehome] = :false - provider.check_manage_home.must == ["-M"] + provider.expects(:execute).with(includes('-M')) + provider.create end - it "should return an empty array if home is not managed and not on Redhat" do - Facter.stubs(:value).with(:operatingsystem).returns("some OS") + it "should not use -M flag if home is not managed and not on Redhat" do + Facter.stubs(:value).with(:osfamily).returns("not RedHat") resource[:managehome] = :false - provider.check_manage_home.must == [] + provider.expects(:execute).with(Not(includes('-M'))) + provider.create end end - describe "when adding properties" do - it "should get the valid properties" - it "should not add the ensure property" - it "should add the flag and value to an array" - it "should return and array of flags and values" - end - describe "#addcmd" do before do resource[:allowdupe] = :true diff --git a/spec/unit/relationship_spec.rb b/spec/unit/relationship_spec.rb index 01e863ff1..a6aeffc4f 100755 --- a/spec/unit/relationship_spec.rb +++ b/spec/unit/relationship_spec.rb @@ -151,7 +151,7 @@ describe Puppet::Relationship, " when matching edges with a non-standard event" end end -describe Puppet::Relationship, "when converting to pson", :if => Puppet.features.pson? do +describe Puppet::Relationship, "when converting to pson" do before do @edge = Puppet::Relationship.new(:a, :b, :event => :random, :callback => :whatever) end @@ -184,7 +184,7 @@ describe Puppet::Relationship, "when converting to pson", :if => Puppet.features end end -describe Puppet::Relationship, "when converting from pson", :if => Puppet.features.pson? do +describe Puppet::Relationship, "when converting from pson" do before do @event = "random" @callback = "whatever" diff --git a/spec/unit/resource/catalog_spec.rb b/spec/unit/resource/catalog_spec.rb index aa84107ae..52673c726 100755 --- a/spec/unit/resource/catalog_spec.rb +++ b/spec/unit/resource/catalog_spec.rb @@ -775,7 +775,7 @@ describe Puppet::Resource::Catalog, "when compiling" do end end -describe Puppet::Resource::Catalog, "when converting to pson", :if => Puppet.features.pson? do +describe Puppet::Resource::Catalog, "when converting to pson" do before do @catalog = Puppet::Resource::Catalog.new("myhost") end @@ -833,7 +833,7 @@ describe Puppet::Resource::Catalog, "when converting to pson", :if => Puppet.fea end end -describe Puppet::Resource::Catalog, "when converting from pson", :if => Puppet.features.pson? do +describe Puppet::Resource::Catalog, "when converting from pson" do def pson_result_should Puppet::Resource::Catalog.expects(:new).with { |hash| yield hash } end diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index a682a7b48..e80e903d8 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -150,24 +150,6 @@ describe Puppet::Resource::Type do Puppet::Resource::Type.new(:node, "fOo").match("foO").should be_true end end - - it "should return the name converted to a string when the name is not a regex" do - pending "Need to define LoadedCode behaviour first" - name = Puppet::Parser::AST::HostName.new(:value => "foo") - Puppet::Resource::Type.new(:node, name).name.should == "foo" - end - - it "should return the name converted to a string when the name is a regex" do - pending "Need to define LoadedCode behaviour first" - name = Puppet::Parser::AST::HostName.new(:value => /regex/) - Puppet::Resource::Type.new(:node, name).name.should == /regex/.to_s - end - - it "should mark any created scopes as a node scope" do - pending "Need to define LoadedCode behaviour first" - name = Puppet::Parser::AST::HostName.new(:value => /regex/) - Puppet::Resource::Type.new(:node, name).name.should == /regex/.to_s - end end describe "when initializing" do diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index dab9c2b82..4ce718758 100755 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -647,7 +647,7 @@ type: File end end - describe "when converting to pson", :if => Puppet.features.pson? do + describe "when converting to pson" do def pson_output_should @resource.class.expects(:pson_create).with { |hash| yield hash } end @@ -726,7 +726,7 @@ type: File end end - describe "when converting from pson", :if => Puppet.features.pson? do + describe "when converting from pson" do def pson_result_should Puppet::Resource.expects(:new).with { |hash| yield hash } end diff --git a/spec/unit/settings/config_file_spec.rb b/spec/unit/settings/config_file_spec.rb new file mode 100644 index 000000000..0d3112097 --- /dev/null +++ b/spec/unit/settings/config_file_spec.rb @@ -0,0 +1,100 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' +require 'puppet/settings/config_file' + +describe Puppet::Settings::ConfigFile do + NOTHING = {} + + def section_containing(data) + meta = data[:meta] || {} + values = data.reject { |key, _| key == :meta } + values.merge({ :_meta => Hash[values.keys.collect { |key| [key, meta[key] || {}] }] }) + end + + def the_parse_of(*lines) + config.parse_file(filename, lines.join("\n")) + end + + let(:identity_transformer) { Proc.new { |value| value } } + let(:config) { Puppet::Settings::ConfigFile.new(identity_transformer) } + + let(:filename) { "a/fake/filename.conf" } + + it "interprets an empty file to contain a main section with no entries" do + the_parse_of("").should == { :main => section_containing(NOTHING) } + end + + it "interprets an empty main section the same as an empty file" do + the_parse_of("").should == config.parse_file(filename, "[main]") + end + + it "places an entry in no section in main" do + the_parse_of("var = value").should == { :main => section_containing(:var => "value") } + end + + it "places an entry after a section header in that section" do + the_parse_of("[section]", "var = value").should == { :main => section_containing(NOTHING), + :section => section_containing(:var => "value") } + end + + it "does not include trailing whitespace in the value" do + the_parse_of("var = value\t ").should == { :main => section_containing(:var => "value") } + end + + it "does not include leading whitespace in the name" do + the_parse_of(" \t var=value").should == { :main => section_containing(:var => "value") } + end + + it "skips lines that are commented out" do + the_parse_of("#var = value").should == { :main => section_containing(NOTHING) } + end + + it "skips lines that are entirely whitespace" do + the_parse_of(" \t ").should == { :main => section_containing(NOTHING) } + end + + it "errors when a line is not a known form" do + expect { the_parse_of("unknown") }.to raise_error Puppet::Settings::ParseError, /Could not match line/ + end + + it "stores file meta information in the _meta section" do + the_parse_of("var = value { owner = me, group = you, mode = 0666 }").should == + { :main => section_containing(:var => "value", :meta => { :var => { :owner => "me", + :group => "you", + :mode => "0666" } }) } + end + + it "errors when there is unknown meta information" do + expect { the_parse_of("var = value { unknown = no }") }. + to raise_error ArgumentError, /Invalid file option 'unknown'/ + end + + it "errors when the mode is not numeric" do + expect { the_parse_of("var = value { mode = no }") }. + to raise_error ArgumentError, "File modes must be numbers" + end + + it "errors when the options are not key-value pairs" do + expect { the_parse_of("var = value { mode }") }. + to raise_error ArgumentError, "Could not parse 'value { mode }'" + end + + it "errors when an application_defaults section is created" do + expect { the_parse_of("[application_defaults]") }. + to raise_error Puppet::Error, + "Illegal section 'application_defaults' in config file #{filename} at line [application_defaults]" + end + + it "transforms values with the given function" do + config = Puppet::Settings::ConfigFile.new(Proc.new { |value| value + " changed" }) + + config.parse_file(filename, "var = value").should == { :main => section_containing(:var => "value changed") } + end + + it "does not try to transform an entry named 'mode'" do + config = Puppet::Settings::ConfigFile.new(Proc.new { raise "Should not transform" }) + + config.parse_file(filename, "mode = value").should == { :main => section_containing(:mode => "value") } + end +end + diff --git a/spec/unit/settings/file_setting_spec.rb b/spec/unit/settings/file_setting_spec.rb index 63564032c..33915ccd4 100755 --- a/spec/unit/settings/file_setting_spec.rb +++ b/spec/unit/settings/file_setting_spec.rb @@ -9,111 +9,113 @@ describe Puppet::Settings::FileSetting do include PuppetSpec::Files - before do - @basepath = make_absolute("/somepath") - end + describe "when controlling permissions" do + def settings(wanted_values = {}) + real_values = { + :user => 'root', + :group => 'root', + :mkusers => false, + :service_user_available? => false, + :service_group_available? => false + }.merge(wanted_values) - describe "when determining whether the service user should be used" do - before do - @settings = mock 'settings' - @settings.stubs(:[]).with(:mkusers).returns false - @settings.stubs(:service_user_available?).returns true - end + settings = mock("settings") - it "should be true if the service user is available" do - @settings.expects(:service_user_available?).returns true - setting = FileSetting.new(:settings => @settings, :owner => "root", :desc => "a setting") - setting.should be_use_service_user - end + settings.stubs(:[]).with(:user).returns real_values[:user] + settings.stubs(:[]).with(:group).returns real_values[:group] + settings.stubs(:[]).with(:mkusers).returns real_values[:mkusers] + settings.stubs(:service_user_available?).returns real_values[:service_user_available?] + settings.stubs(:service_group_available?).returns real_values[:service_group_available?] - it "should be true if 'mkusers' is set" do - @settings.expects(:[]).with(:mkusers).returns true - setting = FileSetting.new(:settings => @settings, :owner => "root", :desc => "a setting") - setting.should be_use_service_user + settings end - it "should be false if the service user is not available and 'mkusers' is unset" do - setting = FileSetting.new(:settings => @settings, :owner => "root", :desc => "a setting") - setting.should be_use_service_user - end - end + context "owner" do + it "can always be root" do + settings = settings(:user => "the_service", :mkusers => true) - describe "when setting the owner" do - it "should allow the file to be owned by root" do - root_owner = lambda { FileSetting.new(:settings => mock("settings"), :owner => "root", :desc => "a setting") } - root_owner.should_not raise_error - end + setting = FileSetting.new(:settings => settings, :owner => "root", :desc => "a setting") - it "should allow the file to be owned by the service user" do - service_owner = lambda { FileSetting.new(:settings => mock("settings"), :owner => "service", :desc => "a setting") } - service_owner.should_not raise_error - end + setting.owner.should == "root" + end - it "should allow the ownership of the file to be unspecified" do - no_owner = lambda { FileSetting.new(:settings => mock("settings"), :desc => "a setting") } - no_owner.should_not raise_error - end + it "is the service user if we are making users" do + settings = settings(:user => "the_service", :mkusers => true, :service_user_available? => false) - it "should not allow other owners" do - invalid_owner = lambda { FileSetting.new(:settings => mock("settings"), :owner => "invalid", :desc => "a setting") } - invalid_owner.should raise_error(FileSetting::SettingError) - end - end + setting = FileSetting.new(:settings => settings, :owner => "service", :desc => "a setting") - describe "when reading the owner" do - it "should be root when the setting specifies root" do - setting = FileSetting.new(:settings => mock("settings"), :owner => "root", :desc => "a setting") - setting.owner.should == "root" - end + setting.owner.should == "the_service" + end - it "should be the owner of the service when the setting specifies service and the service user should be used" do - settings = mock("settings") - settings.stubs(:[]).returns "the_service" + it "is the service user if the user is available on the system" do + settings = settings(:user => "the_service", :mkusers => false, :service_user_available? => true) - setting = FileSetting.new(:settings => settings, :owner => "service", :desc => "a setting") - setting.expects(:use_service_user?).returns true - setting.owner.should == "the_service" - end + setting = FileSetting.new(:settings => settings, :owner => "service", :desc => "a setting") - it "should be the root when the setting specifies service and the service user should not be used" do - settings = mock("settings") - settings.stubs(:[]).returns "the_service" + setting.owner.should == "the_service" + end - setting = FileSetting.new(:settings => settings, :owner => "service", :desc => "a setting") - setting.expects(:use_service_user?).returns false - setting.owner.should == "root" - end + it "is root when the setting specifies service and the user is not available on the system" do + settings = settings(:user => "the_service", :mkusers => false, :service_user_available? => false) - it "should be nil when the owner is unspecified" do - FileSetting.new(:settings => mock("settings"), :desc => "a setting").owner.should be_nil - end - end + setting = FileSetting.new(:settings => settings, :owner => "service", :desc => "a setting") - describe "when setting the group" do - it "should allow the group to be service" do - service_group = lambda { FileSetting.new(:settings => mock("settings"), :group => "service", :desc => "a setting") } - service_group.should_not raise_error - end + setting.owner.should == "root" + end - it "should allow the group to be unspecified" do - no_group = lambda { FileSetting.new(:settings => mock("settings"), :desc => "a setting") } - no_group.should_not raise_error - end + it "is unspecified when no specific owner is wanted" do + FileSetting.new(:settings => settings(), :desc => "a setting").owner.should be_nil + end - it "should not allow invalid groups" do - invalid_group = lambda { FileSetting.new(:settings => mock("settings"), :group => "invalid", :desc => "a setting") } - invalid_group.should raise_error(FileSetting::SettingError) + it "does not allow other owners" do + expect { FileSetting.new(:settings => settings(), :desc => "a setting", :name => "testing", :default => "the default", :owner => "invalid") }. + to raise_error(FileSetting::SettingError, /The :owner parameter for the setting 'testing' must be either 'root' or 'service'/) + end end - end - describe "when reading the group" do - it "should be service when the setting specifies service" do - setting = FileSetting.new(:settings => mock("settings", :[] => "the_service"), :group => "service", :desc => "a setting") - setting.group.should == "the_service" - end + context "group" do + it "is unspecified when no specific group is wanted" do + setting = FileSetting.new(:settings => settings(), :desc => "a setting") + + setting.group.should be_nil + end + + it "is root if root is requested" do + settings = settings(:group => "the_group") + + setting = FileSetting.new(:settings => settings, :group => "root", :desc => "a setting") + + setting.group.should == "root" + end + + it "is the service group if we are making users" do + settings = settings(:group => "the_service", :mkusers => true) - it "should be nil when the group is unspecified" do - FileSetting.new(:settings => mock("settings"), :desc => "a setting").group.should be_nil + setting = FileSetting.new(:settings => settings, :group => "service", :desc => "a setting") + + setting.group.should == "the_service" + end + + it "is the service user if the group is available on the system" do + settings = settings(:group => "the_service", :mkusers => false, :service_group_available? => true) + + setting = FileSetting.new(:settings => settings, :group => "service", :desc => "a setting") + + setting.group.should == "the_service" + end + + it "is unspecified when the setting specifies service and the group is not available on the system" do + settings = settings(:group => "the_service", :mkusers => false, :service_group_available? => false) + + setting = FileSetting.new(:settings => settings, :group => "service", :desc => "a setting") + + setting.group.should be_nil + end + + it "does not allow other groups" do + expect { FileSetting.new(:settings => settings(), :group => "invalid", :name => 'testing', :desc => "a setting") }. + to raise_error(FileSetting::SettingError, /The :group parameter for the setting 'testing' must be either 'root' or 'service'/) + end end end @@ -123,6 +125,7 @@ describe Puppet::Settings::FileSetting do describe "when being converted to a resource" do before do + @basepath = make_absolute("/somepath") @settings = mock 'settings' @file = Puppet::Settings::FileSetting.new(:settings => @settings, :desc => "eh", :name => :myfile, :section => "mysect") @file.stubs(:create_files?).returns true diff --git a/spec/unit/settings/value_translator_spec.rb b/spec/unit/settings/value_translator_spec.rb new file mode 100644 index 000000000..a318f6d48 --- /dev/null +++ b/spec/unit/settings/value_translator_spec.rb @@ -0,0 +1,77 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' +require 'puppet/settings/value_translator' + +describe Puppet::Settings::ValueTranslator do + let(:translator) { Puppet::Settings::ValueTranslator.new } + + context "booleans" do + it "translates strings representing booleans to booleans" do + translator['true'].should == true + translator['false'].should == false + end + + it "translates boolean values into themselves" do + translator[true].should == true + translator[false].should == false + end + + it "leaves a boolean string with whitespace as a string" do + translator[' true'].should == " true" + translator['true '].should == "true" + + translator[' false'].should == " false" + translator['false '].should == "false" + end + end + + context "numbers" do + it "translates integer strings to integers" do + translator["1"].should == 1 + translator["2"].should == 2 + end + + it "translates numbers starting with a 0 as octal" do + translator["011"].should == 9 + end + + it "leaves hex numbers as strings" do + translator["0x11"].should == "0x11" + end + end + + context "arbitrary strings" do + it "translates an empty string as the empty string" do + translator[""].should == "" + end + + + it "strips double quotes" do + translator['"a string"'].should == 'a string' + end + + it "strips single quotes" do + translator["'a string'"].should == "a string" + end + + it "does not strip preceeding whitespace" do + translator[" \ta string"].should == " \ta string" + end + + it "strips trailing whitespace" do + translator["a string\t "].should == "a string" + end + + it "leaves leading quote that is preceeded by whitespace" do + translator[" 'a string'"].should == " 'a string" + end + + it "leaves trailing quote that is succeeded by whitespace" do + translator["'a string' "].should == "a string'" + end + + it "leaves quotes that are not at the beginning or end of the string" do + translator["a st'\"ring"].should == "a st'\"ring" + end + end +end diff --git a/spec/unit/settings_spec.rb b/spec/unit/settings_spec.rb index b2196bed6..42013ac64 100755 --- a/spec/unit/settings_spec.rb +++ b/spec/unit/settings_spec.rb @@ -85,14 +85,6 @@ describe Puppet::Settings do @settings.define_settings(:main, PuppetSpec::Settings::TEST_APP_DEFAULT_DEFINITIONS) end - it "should fail if someone attempts to initialize app defaults more than once" do - @settings.initialize_app_defaults(default_values) - - expect { - @settings.initialize_app_defaults(default_values) - }.to raise_error(Puppet::DevError) - end - it "should fail if the app defaults hash is missing any required values" do incomplete_default_values = default_values.reject { |key, _| key == :confdir } expect { @@ -676,6 +668,7 @@ describe Puppet::Settings do before do @settings = Puppet::Settings.new @settings.stubs(:service_user_available?).returns true + @settings.stubs(:service_group_available?).returns true @file = make_absolute("/some/file") @userconfig = make_absolute("/test/userconfigfile") @settings.define_settings :section, :user => { :default => "suser", :desc => "doc" }, :group => { :default => "sgroup", :desc => "doc" } @@ -785,6 +778,33 @@ describe Puppet::Settings do @settings.metadata(:myfile).should == {:owner => "suser"} end + it "should support loading metadata (owner, group, or mode) from a run_mode section in the configuration file" do + default_values = {} + PuppetSpec::Settings::TEST_APP_DEFAULT_DEFINITIONS.keys.each do |key| + default_values[key] = 'default value' + end + @settings.define_settings :main, PuppetSpec::Settings::TEST_APP_DEFAULT_DEFINITIONS + @settings.define_settings :master, :myfile => { :type => :file, :default => make_absolute("/myfile"), :desc => "a" } + + otherfile = make_absolute("/other/file") + text = "[master] + myfile = #{otherfile} {mode = 664} + " + @settings.expects(:read_file).returns(text) + + # will start initialization as user + @settings.preferred_run_mode.should == :user + @settings.send(:parse_config_files) + + # change app run_mode to master + @settings.initialize_app_defaults(default_values.merge(:run_mode => :master)) + @settings.preferred_run_mode.should == :master + + # initializing the app should have reloaded the metadata based on run_mode + @settings[:myfile].should == otherfile + @settings.metadata(:myfile).should == {:mode => "664"} + end + it "should call hooks associated with values set in the configuration file" do values = [] @settings.define_settings :section, :mysetting => {:default => "defval", :desc => "a", :hook => proc { |v| values << v }} @@ -1245,6 +1265,7 @@ describe Puppet::Settings do before do @settings = Puppet::Settings.new @settings.stubs(:service_user_available?).returns true + @settings.stubs(:service_group_available?).returns true @settings.define_settings :main, :noop => { :default => false, :desc => "", :type => :boolean } @settings.define_settings :main, :maindir => { :type => :directory, :default => make_absolute("/maindir"), :desc => "a" }, @@ -1282,12 +1303,6 @@ describe Puppet::Settings do @settings.use(:main, :other) end - it "should ignore tags and schedules when creating files and directories" - - it "should be able to provide all of its parameters in a format compatible with GetOpt::Long" do - pending "Not converted from test/unit yet" - end - it "should convert the created catalog to a RAL catalog" do @catalog = Puppet::Resource::Catalog.new("foo") @settings.expects(:to_catalog).with(:main).returns @catalog @@ -1403,8 +1418,6 @@ describe Puppet::Settings do @settings.print_configs end - it "should print a whole bunch of stuff if :configprint = all" - it "should return true after printing" do @settings.stubs(:value).with(:configprint).returns("something") @settings.stubs(:include?).with("something").returns(true) @@ -1460,35 +1473,89 @@ describe Puppet::Settings do end describe "when determining if the service user is available" do + let(:settings) do + settings = Puppet::Settings.new + settings.define_settings :main, :user => { :default => nil, :desc => "doc" } + settings + end + + def a_user_type_for(username) + user = mock 'user' + Puppet::Type.type(:user).expects(:new).with { |args| args[:name] == username }.returns user + user + end + it "should return false if there is no user setting" do - Puppet::Settings.new.should_not be_service_user_available + settings.should_not be_service_user_available end it "should return false if the user provider says the user is missing" do - settings = Puppet::Settings.new - settings.define_settings :main, :user => { :default => "foo", :desc => "doc" } - - user = mock 'user' - user.expects(:exists?).returns false + settings[:user] = "foo" - Puppet::Type.type(:user).expects(:new).with { |args| args[:name] == "foo" }.returns user + a_user_type_for("foo").expects(:exists?).returns false settings.should_not be_service_user_available end it "should return true if the user provider says the user is present" do - settings = Puppet::Settings.new - settings.define_settings :main, :user => { :default => "foo", :desc => "doc" } + settings[:user] = "foo" - user = mock 'user' - user.expects(:exists?).returns true + a_user_type_for("foo").expects(:exists?).returns true - Puppet::Type.type(:user).expects(:new).with { |args| args[:name] == "foo" }.returns user + settings.should be_service_user_available + end + + it "caches the result of determining if the user is present" do + settings[:user] = "foo" + + a_user_type_for("foo").expects(:exists?).returns true + settings.should be_service_user_available settings.should be_service_user_available end + end + + describe "when determining if the service group is available" do + let(:settings) do + settings = Puppet::Settings.new + settings.define_settings :main, :group => { :default => nil, :desc => "doc" } + settings + end - it "should cache the result" + def a_group_type_for(groupname) + group = mock 'group' + Puppet::Type.type(:group).expects(:new).with { |args| args[:name] == groupname }.returns group + group + end + + it "should return false if there is no group setting" do + settings.should_not be_service_group_available + end + + it "should return false if the group provider says the group is missing" do + settings[:group] = "foo" + + a_group_type_for("foo").expects(:exists?).returns false + + settings.should_not be_service_group_available + end + + it "should return true if the group provider says the group is present" do + settings[:group] = "foo" + + a_group_type_for("foo").expects(:exists?).returns true + + settings.should be_service_group_available + end + + it "caches the result of determining if the group is present" do + settings[:group] = "foo" + + a_group_type_for("foo").expects(:exists?).returns true + settings.should be_service_group_available + + settings.should be_service_group_available + end end describe "#writesub" do diff --git a/spec/unit/ssl/certificate_request_spec.rb b/spec/unit/ssl/certificate_request_spec.rb index 8b804d58b..b6d07c695 100755 --- a/spec/unit/ssl/certificate_request_spec.rb +++ b/spec/unit/ssl/certificate_request_spec.rb @@ -211,6 +211,24 @@ describe Puppet::SSL::CertificateRequest do generated.should be_a(OpenSSL::X509::Request) generated.should be(request.content) end + + it "should use SHA1 to sign the csr when SHA256 isn't available" do + csr = OpenSSL::X509::Request.new + OpenSSL::Digest.expects(:const_defined?).with("SHA256").returns(false) + OpenSSL::Digest.expects(:const_defined?).with("SHA1").returns(true) + signer = Puppet::SSL::CertificateSigner.new + signer.sign(csr, key.content) + csr.verify(key.content).should be_true + end + + it "should raise an error if neither SHA256 nor SHA1 are available" do + csr = OpenSSL::X509::Request.new + OpenSSL::Digest.expects(:const_defined?).with("SHA256").returns(false) + OpenSSL::Digest.expects(:const_defined?).with("SHA1").returns(false) + expect { + signer = Puppet::SSL::CertificateSigner.new + }.to raise_error(Puppet::Error) + end end describe "when a CSR is saved" do diff --git a/spec/unit/type/file/ensure_spec.rb b/spec/unit/type/file/ensure_spec.rb index 44cb3e025..310558ff8 100755 --- a/spec/unit/type/file/ensure_spec.rb +++ b/spec/unit/type/file/ensure_spec.rb @@ -1,84 +1,123 @@ #! /usr/bin/env ruby require 'spec_helper' +require 'puppet/type/file/ensure' -property = Puppet::Type.type(:file).attrclass(:ensure) +describe Puppet::Type::File::Ensure do + include PuppetSpec::Files -describe property do - before do - # Wow that's a messy interface to the resource. - @resource = stub 'resource', :[] => nil, :[]= => nil, :property => nil, :newattr => nil, :parameter => nil, :replace? => true - @resource.stubs(:[]).returns "foo" - @resource.stubs(:[]).with(:path).returns "/my/file" - @ensure = property.new :resource => @resource - end + let(:path) { tmpfile('file_ensure') } + let(:resource) { Puppet::Type.type(:file).new(:ensure => 'file', :path => path, :replace => true) } + let(:property) { resource.property(:ensure) } it "should be a subclass of Ensure" do - property.superclass.must == Puppet::Property::Ensure + described_class.superclass.must == Puppet::Property::Ensure end describe "when retrieving the current state" do it "should return :absent if the file does not exist" do - @ensure = property.new(:resource => @resource) - @resource.expects(:stat).returns nil + resource.expects(:stat).returns nil - @ensure.retrieve.should == :absent + property.retrieve.should == :absent end it "should return the current file type if the file exists" do - @ensure = property.new(:resource => @resource) stat = mock 'stat', :ftype => "directory" - @resource.expects(:stat).returns stat + resource.expects(:stat).returns stat - @ensure.retrieve.should == :directory + property.retrieve.should == :directory end end describe "when testing whether :ensure is in sync" do - before do - @ensure = property.new(:resource => @resource) - @stat = stub 'stat', :ftype => "file" - end - it "should always be in sync if replace is 'false' unless the file is missing" do - @ensure.should = :file - @resource.expects(:replace?).returns false - @ensure.safe_insync?(:link).should be_true + property.should = :file + resource.expects(:replace?).returns false + property.safe_insync?(:link).should be_true end it "should be in sync if :ensure is set to :absent and the file does not exist" do - @ensure.should = :absent + property.should = :absent - @ensure.must be_safe_insync(:absent) + property.must be_safe_insync(:absent) end it "should not be in sync if :ensure is set to :absent and the file exists" do - @ensure.should = :absent + property.should = :absent - @ensure.should_not be_safe_insync(:file) + property.should_not be_safe_insync(:file) end it "should be in sync if a normal file exists and :ensure is set to :present" do - @ensure.should = :present + property.should = :present - @ensure.must be_safe_insync(:file) + property.must be_safe_insync(:file) end it "should be in sync if a directory exists and :ensure is set to :present" do - @ensure.should = :present + property.should = :present - @ensure.must be_safe_insync(:directory) + property.must be_safe_insync(:directory) end it "should be in sync if a symlink exists and :ensure is set to :present" do - @ensure.should = :present + property.should = :present - @ensure.must be_safe_insync(:link) + property.must be_safe_insync(:link) end it "should not be in sync if :ensure is set to :file and a directory exists" do - @ensure.should = :file + property.should = :file + + property.should_not be_safe_insync(:directory) + end + end + + describe "#sync" do + context "directory" do + before :each do + resource[:ensure] = :directory + end + + it "should raise if the parent directory doesn't exist" do + newpath = File.join(path, 'nonexistentparent', 'newdir') + resource[:path] = newpath + + expect { + property.sync + }.to raise_error(Puppet::Error, /Cannot create #{newpath}; parent directory #{File.dirname(newpath)} does not exist/) + end + + it "should accept octal mode as fixnum" do + resource[:mode] = 0700 + resource.expects(:property_fix) + Dir.expects(:mkdir).with(path, 0700) + + property.sync + end + + it "should accept octal mode as string" do + resource[:mode] = "700" + resource.expects(:property_fix) + Dir.expects(:mkdir).with(path, 0700) + + property.sync + end + + it "should accept octal mode as string with leading zero" do + resource[:mode] = "0700" + resource.expects(:property_fix) + Dir.expects(:mkdir).with(path, 0700) + + property.sync + end + + it "should accept symbolic mode" do + resource[:mode] = "u=rwx,go=x" + resource.expects(:property_fix) + Dir.expects(:mkdir).with(path, 0711) - @ensure.should_not be_safe_insync(:directory) + property.sync + end end end end diff --git a/spec/unit/type/file_spec.rb b/spec/unit/type/file_spec.rb index b910cf87b..d71c041a8 100755 --- a/spec/unit/type/file_spec.rb +++ b/spec/unit/type/file_spec.rb @@ -194,32 +194,6 @@ describe Puppet::Type.type(:file) do end end - describe "#asuser" do - before :each do - # Mocha won't let me just stub SUIDManager.asuser to yield and return, - # but it will do exactly that if we're not root. - Puppet.features.stubs(:root?).returns false - end - - it "should return the desired owner if they can write to the parent directory" do - file[:owner] = 1001 - FileTest.stubs(:writable?).with(File.dirname file[:path]).returns true - - file.asuser.should == 1001 - end - - it "should return nil if the desired owner can't write to the parent directory" do - file[:owner] = 1001 - FileTest.stubs(:writable?).with(File.dirname file[:path]).returns false - - file.asuser.should == nil - end - - it "should return nil if not managing owner" do - file.asuser.should == nil - end - end - describe "#bucket" do it "should return nil if backup is off" do file[:backup] = false @@ -288,48 +262,6 @@ describe Puppet::Type.type(:file) do end end - describe "#bucket" do - it "should return nil if backup is off" do - file[:backup] = false - file.bucket.should == nil - end - - it "should return nil if using a file extension for backup" do - file[:backup] = '.backup' - - file.bucket.should == nil - end - - it "should return the default filebucket if using the 'puppet' filebucket" do - file[:backup] = 'puppet' - bucket = stub('bucket') - file.stubs(:default_bucket).returns bucket - - file.bucket.should == bucket - end - - it "should fail if using a remote filebucket and no catalog exists" do - file.catalog = nil - file[:backup] = 'my_bucket' - - expect { file.bucket }.to raise_error(Puppet::Error, "Can not find filebucket for backups without a catalog") - end - - it "should fail if the specified filebucket isn't in the catalog" do - file[:backup] = 'my_bucket' - - expect { file.bucket }.to raise_error(Puppet::Error, "Could not find filebucket my_bucket specified in backup") - end - - it "should use the specified filebucket if it is in the catalog" do - file[:backup] = 'my_bucket' - filebucket = Puppet::Type.type(:filebucket).new(:name => 'my_bucket') - catalog.add_resource(filebucket) - - file.bucket.should == filebucket.bucket - end - end - describe "#exist?" do it "should be considered existent if it can be stat'ed" do file.expects(:stat).returns mock('stat') diff --git a/spec/unit/type/group_spec.rb b/spec/unit/type/group_spec.rb index c87249e90..f8d24f0df 100755 --- a/spec/unit/type/group_spec.rb +++ b/spec/unit/type/group_spec.rb @@ -51,4 +51,14 @@ describe Puppet::Type.type(:group) do group.provider.expects(:delete) group.parameter(:ensure).sync end + + it "delegates the existance check to its provider" do + provider = @class.provide(:testing) {} + provider_instance = provider.new + provider_instance.expects(:exists?).returns true + + type = @class.new(:name => "group", :provider => provider_instance) + + type.exists?.should == true + end end diff --git a/spec/unit/util/autoload_spec.rb b/spec/unit/util/autoload_spec.rb index f9a57df1e..933855914 100755 --- a/spec/unit/util/autoload_spec.rb +++ b/spec/unit/util/autoload_spec.rb @@ -262,4 +262,10 @@ describe Puppet::Util::Autoload do end end end + + describe "#expand" do + it "should expand relative to the autoloader's prefix" do + @autoload.expand('bar').should == 'tmp/bar' + end + end end diff --git a/spec/unit/util/command_line_spec.rb b/spec/unit/util/command_line_spec.rb index 809c46636..3d8f896d1 100755 --- a/spec/unit/util/command_line_spec.rb +++ b/spec/unit/util/command_line_spec.rb @@ -6,64 +6,62 @@ require 'puppet/util/command_line' describe Puppet::Util::CommandLine do include PuppetSpec::Files - let :tty do stub("tty", :tty? => true) end - let :pipe do stub("pipe", :tty? => false) end context "#initialize" do it "should pull off the first argument if it looks like a subcommand" do - command_line = Puppet::Util::CommandLine.new("puppet", %w{ client --help whatever.pp }, tty) + command_line = Puppet::Util::CommandLine.new("puppet", %w{ client --help whatever.pp }) command_line.subcommand_name.should == "client" command_line.args.should == %w{ --help whatever.pp } end it "should return nil if the first argument looks like a .pp file" do - command_line = Puppet::Util::CommandLine.new("puppet", %w{ whatever.pp }, tty) + command_line = Puppet::Util::CommandLine.new("puppet", %w{ whatever.pp }) command_line.subcommand_name.should == nil command_line.args.should == %w{ whatever.pp } end it "should return nil if the first argument looks like a .rb file" do - command_line = Puppet::Util::CommandLine.new("puppet", %w{ whatever.rb }, tty) + command_line = Puppet::Util::CommandLine.new("puppet", %w{ whatever.rb }) command_line.subcommand_name.should == nil command_line.args.should == %w{ whatever.rb } end it "should return nil if the first argument looks like a flag" do - command_line = Puppet::Util::CommandLine.new("puppet", %w{ --debug }, tty) + command_line = Puppet::Util::CommandLine.new("puppet", %w{ --debug }) command_line.subcommand_name.should == nil command_line.args.should == %w{ --debug } end it "should return nil if the first argument is -" do - command_line = Puppet::Util::CommandLine.new("puppet", %w{ - }, tty) + command_line = Puppet::Util::CommandLine.new("puppet", %w{ - }) command_line.subcommand_name.should == nil command_line.args.should == %w{ - } end it "should return nil if the first argument is --help" do - command_line = Puppet::Util::CommandLine.new("puppet", %w{ --help }, tty) + command_line = Puppet::Util::CommandLine.new("puppet", %w{ --help }) command_line.subcommand_name.should == nil end - it "should return nil if there are no arguments on a tty" do - command_line = Puppet::Util::CommandLine.new("puppet", [], tty) + it "should return nil if there are no arguments" do + command_line = Puppet::Util::CommandLine.new("puppet", []) command_line.subcommand_name.should == nil command_line.args.should == [] end - it "should return nil if there are no arguments on a pipe" do - command_line = Puppet::Util::CommandLine.new("puppet", [], pipe) - - command_line.subcommand_name.should == nil - command_line.args.should == [] + it "should pick up changes to the array of arguments" do + args = %w{subcommand} + command_line = Puppet::Util::CommandLine.new("puppet", args) + args[0] = 'different_subcommand' + command_line.subcommand_name.should == 'different_subcommand' end end @@ -71,40 +69,32 @@ describe Puppet::Util::CommandLine do %w{--version -V}.each do |arg| it "should print the version and exit if #{arg} is given" do expect do - described_class.new("puppet", [arg], tty).execute - end.to have_printed(Puppet.version) + described_class.new("puppet", [arg]).execute + end.to have_printed(/^#{Puppet.version}$/) end end end describe "when dealing with puppet commands" do it "should return the executable name if it is not puppet" do - command_line = Puppet::Util::CommandLine.new("puppetmasterd", [], tty) + command_line = Puppet::Util::CommandLine.new("puppetmasterd", []) command_line.subcommand_name.should == "puppetmasterd" end describe "when the subcommand is not implemented" do it "should find and invoke an executable with a hyphenated name" do - commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument'], tty) + commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument']) Puppet::Util.expects(:which).with('puppet-whatever'). returns('/dev/null/puppet-whatever') - # It is important that we abort at the point exec is called, because - # the code (reasonably) assumes that if `exec` is called processing - # immediately terminates, and we are replaced by the executed process. - # - # This raise isn't a perfect simulation of that, but it is enough to - # validate that the system works, and ... well, if exec is broken we - # have two problems, y'know. - commandline.expects(:exec).with('/dev/null/puppet-whatever', 'argument'). - raises(SystemExit) - - expect { commandline.execute }.to raise_error SystemExit + Kernel.expects(:exec).with('/dev/null/puppet-whatever', 'argument') + + commandline.execute end describe "and an external implementation cannot be found" do it "should abort and show the usage message" do - commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument'], tty) + commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument']) Puppet::Util.expects(:which).with('puppet-whatever').returns(nil) commandline.expects(:exec).never @@ -112,43 +102,45 @@ describe Puppet::Util::CommandLine do commandline.execute }.to have_printed(/Unknown Puppet subcommand 'whatever'/) end + + it "should abort and show the help message" do + commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', 'argument']) + Puppet::Util.expects(:which).with('puppet-whatever').returns(nil) + commandline.expects(:exec).never + + expect { + commandline.execute + }.to have_printed(/See 'puppet help' for help on available puppet subcommands/) + end + + %w{--version -V}.each do |arg| + it "should abort and display #{arg} information" do + commandline = Puppet::Util::CommandLine.new("puppet", ['whatever', arg]) + Puppet::Util.expects(:which).with('puppet-whatever').returns(nil) + commandline.expects(:exec).never + + expect { + commandline.execute + }.to have_printed(/^#{Puppet.version}$/) + end + end end end + describe 'when loading commands' do - let :core_apps do - %w{describe filebucket kick queue resource agent cert apply doc master} - end + it "should deprecate the available_subcommands instance method" do + Puppet::Application.expects(:available_application_names) + Puppet.expects(:deprecation_warning).with("Puppet::Util::CommandLine#available_subcommands is deprecated; please use Puppet::Application.available_application_names instead.") - let :command_line do - Puppet::Util::CommandLine.new("foo", %w{ client --help whatever.pp }, tty) + command_line = Puppet::Util::CommandLine.new("foo", %w{ client --help whatever.pp }) + command_line.available_subcommands end - it "should expose available_subcommands as a class method" do - core_apps.each do |command| - command_line.available_subcommands.should include command - end - end - it 'should be able to find all existing commands' do - core_apps.each do |command| - command_line.available_subcommands.should include command - end - end - describe 'when multiple paths have applications' do - before do - @dir=tmpdir('command_line_plugin_test') - @appdir="#{@dir}/puppet/application" - FileUtils.mkdir_p(@appdir) - FileUtils.touch("#{@appdir}/foo.rb") - $LOAD_PATH.unshift(@dir) # WARNING: MUST MATCH THE AFTER ACTIONS! - end - it 'should be able to find commands from both paths' do - found = command_line.available_subcommands - found.should include 'foo' - core_apps.each { |cmd| found.should include cmd } - end - after do - $LOAD_PATH.shift # WARNING: MUST MATCH THE BEFORE ACTIONS! - end + it "should deprecate the available_subcommands class method" do + Puppet::Application.expects(:available_application_names) + Puppet.expects(:deprecation_warning).with("Puppet::Util::CommandLine.available_subcommands is deprecated; please use Puppet::Application.available_application_names instead.") + + Puppet::Util::CommandLine.available_subcommands end end end diff --git a/spec/unit/util/metric_spec.rb b/spec/unit/util/metric_spec.rb index ea60b7a71..d3b4c929f 100755 --- a/spec/unit/util/metric_spec.rb +++ b/spec/unit/util/metric_spec.rb @@ -83,13 +83,4 @@ describe Puppet::Util::Metric do it "should return nil if the named value cannot be found" do @metric["foo"].should == 0 end - - # LAK: I'm not taking the time to develop these tests right now. - # I expect they should actually be extracted into a separate class - # anyway. - it "should be able to graph metrics using RRDTool" - - it "should be able to create a new RRDTool database" - - it "should be able to store metrics into an RRDTool database" end diff --git a/spec/unit/util/posix_spec.rb b/spec/unit/util/posix_spec.rb index 64dc65ff7..cc5f960ba 100755 --- a/spec/unit/util/posix_spec.rb +++ b/spec/unit/util/posix_spec.rb @@ -248,8 +248,4 @@ describe Puppet::Util::POSIX do it "should be able to iteratively search for posix values" do @posix.should respond_to(:search_posix_field) end - - describe "when searching for posix values iteratively" do - it "should iterate across all of the structs returned by Etc and return the appropriate field from the first matching value" - end end diff --git a/spec/unit/util/rdoc_spec.rb b/spec/unit/util/rdoc_spec.rb index 87d4cd7fb..b13591374 100755 --- a/spec/unit/util/rdoc_spec.rb +++ b/spec/unit/util/rdoc_spec.rb @@ -142,18 +142,6 @@ describe Puppet::Util::RDoc do # any other output must fail Puppet::Util::RDoc.manifestdoc([my_fixture('basic.pp')]) end - - it "should output resource documentation if needed" do - pending "#6634 being fixed" - Puppet.settings[:document_all] = true - byline = sequence('documentation outputs in line order') - Puppet::Util::RDoc.expects(:puts).with("im a class\n").in_sequence(byline) - Puppet::Util::RDoc.expects(:puts).with("im a node\n").in_sequence(byline) - Puppet::Util::RDoc.expects(:puts).with("im a define\n").in_sequence(byline) - Puppet::Util::RDoc.expects(:puts).with("im a resource\n").in_sequence(byline) - # any other output must fail - Puppet::Util::RDoc.manifestdoc([my_fixture('basic.pp')]) - end end end end diff --git a/spec/unit/util/rubygems_spec.rb b/spec/unit/util/rubygems_spec.rb index 85435f83b..8fda3485f 100644 --- a/spec/unit/util/rubygems_spec.rb +++ b/spec/unit/util/rubygems_spec.rb @@ -37,7 +37,7 @@ describe Puppet::Util::RubyGems::Source do before(:each) { described_class.stubs(:source).returns(Puppet::Util::RubyGems::Gems18Source) } it "#directories returns the lib subdirs of Gem::Specification.latest_specs" do - Gem::Specification.expects(:latest_specs).returns([fake_gem]) + Gem::Specification.expects(:latest_specs).with(true).returns([fake_gem]) described_class.new.directories.should == [gem_lib] end diff --git a/spec/unit/util/selinux_spec.rb b/spec/unit/util/selinux_spec.rb index 2b7f14395..ac2bc2977 100755 --- a/spec/unit/util/selinux_spec.rb +++ b/spec/unit/util/selinux_spec.rb @@ -135,7 +135,6 @@ describe Puppet::Util::SELinux do Selinux.stubs(:matchpathcon).with("/root/chuj", 0).returns(-1) self.stubs(:file_lstat).with("/root/chuj").raises(Errno::EACCES, "/root/chuj") - self.expects(:warning).with("Could not stat; Permission denied - /root/chuj") get_selinux_default_context("/root/chuj").should be_nil end @@ -145,7 +144,6 @@ describe Puppet::Util::SELinux do Selinux.stubs(:matchpathcon).with("/root/chuj", 0).returns(-1) self.stubs(:file_lstat).with("/root/chuj").raises(Errno::ENOENT, "/root/chuj") - self.expects(:warning).with("Could not stat; No such file or directory - /root/chuj") get_selinux_default_context("/root/chuj").should be_nil end diff --git a/spec/unit/util/zaml_spec.rb b/spec/unit/util/zaml_spec.rb index 4aa2f1a4f..9c6e2dfba 100755 --- a/spec/unit/util/zaml_spec.rb +++ b/spec/unit/util/zaml_spec.rb @@ -16,8 +16,24 @@ require 'spec_helper' require 'puppet/util/monkey_patches' describe "Pure ruby yaml implementation" do - def can_round_trip(value) - YAML.load(value.to_yaml).should == value + RSpec::Matchers.define :round_trip_through_yaml do + match do |object| + YAML.load(object.to_yaml) == object + end + end + + RSpec::Matchers.define :be_equivalent_to do |expected_yaml| + match do |object| + object.to_yaml == expected_yaml and YAML.load(expected_yaml) == object + end + + failure_message_for_should do |object| + if object.to_yaml != expected_yaml + "#{object} serialized to #{object.to_yaml}" + else + "#{expected_yaml} deserialized as #{YAML.load(expected_yaml)}" + end + end end { @@ -34,14 +50,67 @@ describe "Pure ruby yaml implementation" do [] => "--- []", :symbol => "--- !ruby/sym symbol", {:a => "A"} => "--- \n !ruby/sym a: A", - {:a => "x\ny"} => "--- \n !ruby/sym a: |-\n x\n y" + {:a => "x\ny"} => "--- \n !ruby/sym a: |-\n x\n y", }.each do |data, serialized| it "should convert the #{data.class} #{data.inspect} to yaml" do - data.to_yaml.should == serialized + data.should be_equivalent_to serialized + end + end + + context Time do + def the_time_in(timezone) + Puppet::Util.withenv("TZ" => timezone) do + Time.local(2012, "dec", 11, 15, 59, 2) + end + end + + def the_time_in_yaml_offset_by(offset) + "--- 2012-12-11 15:59:02.000000 #{offset}" + end + + it "serializes a time in UTC" do + pending("not supported on Windows", :if => Puppet.features.microsoft_windows?) do + the_time_in("Europe/London").should be_equivalent_to(the_time_in_yaml_offset_by("+00:00")) + end + end + + it "serializes a time behind UTC" do + pending("not supported on Windows", :if => Puppet.features.microsoft_windows?) do + the_time_in("America/Chicago").should be_equivalent_to(the_time_in_yaml_offset_by("-06:00")) + end end - it "should produce yaml for the #{data.class} #{data.inspect} that can be reconstituted" do - can_round_trip data + it "serializes a time behind UTC that is not a complete hour (Bug #15496)" do + pending("not supported on Windows", :if => Puppet.features.microsoft_windows?) do + the_time_in("America/Caracas").should be_equivalent_to(the_time_in_yaml_offset_by("-04:30")) + end + end + + it "serializes a time ahead of UTC" do + pending("not supported on Windows", :if => Puppet.features.microsoft_windows?) do + the_time_in("Europe/Berlin").should be_equivalent_to(the_time_in_yaml_offset_by("+01:00")) + end + end + + it "serializes a time ahead of UTC that is not a complete hour" do + pending("not supported on Windows", :if => Puppet.features.microsoft_windows?) do + the_time_in("Asia/Kathmandu").should be_equivalent_to(the_time_in_yaml_offset_by("+05:45")) + end + end + + it "serializes a time more than 12 hours ahead of UTC" do + pending("not supported on Windows", :if => Puppet.features.microsoft_windows?) do + the_time_in("Pacific/Kiritimati").should be_equivalent_to(the_time_in_yaml_offset_by("+14:00")) + end + end + + it "should roundtrip Time.now" do + tm = Time.now + # yaml only emits 6 digits of precision, but on some systems with ruby 1.9 + # the original time object may contain nanoseconds, which will cause + # the equality check to fail. So truncate the time object to only microsecs + tm = Time.at(tm.to_i, tm.usec) + tm.should round_trip_through_yaml end end @@ -63,7 +132,7 @@ describe "Pure ruby yaml implementation" do { "b:" => { "a" => [] } } ].each do |value| it "properly escapes #{value.inspect}, which contains YAML characters" do - can_round_trip value + value.should round_trip_through_yaml end end @@ -88,11 +157,7 @@ describe "Pure ruby yaml implementation" do x = [1, 2] y = [3, 4] z = [x, y, x, y] - z.to_yaml.should == "--- \n - &id001\n - 1\n - 2\n - &id002\n - 3\n - 4\n - *id001\n - *id002" - z2 = YAML.load(z.to_yaml) - z2.should == z - z2[0].should equal(z2[2]) - z2[1].should equal(z2[3]) + z.should be_equivalent_to("--- \n - &id001\n - 1\n - 2\n - &id002\n - 3\n - 4\n - *id001\n - *id002") end it "should emit proper labels and backreferences for recursive objects" do @@ -106,141 +171,134 @@ describe "Pure ruby yaml implementation" do x2[1].should == 2 x2[2].should equal(x2) end -end - -# Note, many of these tests will pass on Ruby 1.8 but fail on 1.9 if the patch -# fix is not applied to Puppet or there's a regression. These version -# dependant failures are intentional since the string encoding behavior changed -# significantly in 1.9. -describe "UTF-8 encoded String#to_yaml (Bug #11246)" do - # JJM All of these snowmen are different representations of the same - # UTF-8 encoded string. - let(:snowman) { 'Snowman: [☃]' } - let(:snowman_escaped) { "Snowman: [\xE2\x98\x83]" } - describe "UTF-8 String Literal" do - subject { snowman } + # Note, many of these tests will pass on Ruby 1.8 but fail on 1.9 if the patch + # fix is not applied to Puppet or there's a regression. These version + # dependant failures are intentional since the string encoding behavior changed + # significantly in 1.9. + context "UTF-8 encoded String#to_yaml (Bug #11246)" do + # JJM All of these snowmen are different representations of the same + # UTF-8 encoded string. + let(:snowman) { 'Snowman: [☃]' } + let(:snowman_escaped) { "Snowman: [\xE2\x98\x83]" } - it "should serialize to YAML" do - subject.to_yaml - end it "should serialize and deserialize to the same thing" do - YAML.load(subject.to_yaml).should == subject + snowman.should round_trip_through_yaml end + it "should serialize and deserialize to a String compatible with a UTF-8 encoded Regexp" do - YAML.load(subject.to_yaml).should =~ /☃/u + YAML.load(snowman.to_yaml).should =~ /☃/u end end -end -describe "binary data" do - subject { "M\xC0\xDF\xE5tt\xF6" } + context "binary data" do + subject { "M\xC0\xDF\xE5tt\xF6" } - if String.method_defined?(:encoding) - def binary(str) - str.force_encoding('binary') + if String.method_defined?(:encoding) + def binary(str) + str.force_encoding('binary') + end + else + def binary(str) + str + end end - else - def binary(str) - str - end - end - it "should not explode encoding binary data" do - expect { subject.to_yaml }.not_to raise_error - end + it "should not explode encoding binary data" do + expect { subject.to_yaml }.not_to raise_error + end - it "should mark the binary data as binary" do - subject.to_yaml.should =~ /!binary/ - end + it "should mark the binary data as binary" do + subject.to_yaml.should =~ /!binary/ + end - it "should round-trip the data" do - yaml = subject.to_yaml - read = YAML.load(yaml) - binary(read).should == binary(subject) - end + it "should round-trip the data" do + yaml = subject.to_yaml + read = YAML.load(yaml) + binary(read).should == binary(subject) + end - [ - "\xC0\xAE", # over-long UTF-8 '.' character - "\xC0\x80", # over-long NULL byte - "\xC0\xFF", - "\xC1\xAE", - "\xC1\x80", - "\xC1\xFF", - "\x80", # first continuation byte - "\xbf", # last continuation byte - # all possible continuation bytes in one shot - "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" + - "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" + - "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF" + - "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF", - # lonely start characters - first, all possible two byte sequences - "\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 \xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF " + - "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 \xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF ", - # and so for three byte sequences, four, five, and six, as follow. - "\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 \xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF ", - "\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 ", - "\xF8 \xF9 \xFA \xFB ", - "\xFC \xFD ", - # sequences with the last byte missing - "\xC0", "\xE0", "\xF0\x80\x80", "\xF8\x80\x80\x80", "\xFC\x80\x80\x80\x80", - "\xDF", "\xEF\xBF", "\xF7\xBF\xBF", "\xFB\xBF\xBF\xBF", "\xFD\xBF\xBF\xBF\xBF", - # impossible bytes - "\xFE", "\xFF", "\xFE\xFE\xFF\xFF", - # over-long '/' character - "\xC0\xAF", - "\xE0\x80\xAF", - "\xF0\x80\x80\xAF", - "\xF8\x80\x80\x80\xAF", - "\xFC\x80\x80\x80\x80\xAF", - # maximum overlong sequences - "\xc1\xbf", - "\xe0\x9f\xbf", - "\xf0\x8f\xbf\xbf", - "\xf8\x87\xbf\xbf\xbf", - "\xfc\x83\xbf\xbf\xbf\xbf", - # overlong NUL - "\xc0\x80", - "\xe0\x80\x80", - "\xf0\x80\x80\x80", - "\xf8\x80\x80\x80\x80", - "\xfc\x80\x80\x80\x80\x80", - ].each do |input| - # It might seem like we should more correctly reject these sequences in - # the encoder, and I would personally agree, but the sad reality is that - # we do not distinguish binary and textual data in our language, and so we - # wind up with the same thing - a string - containing both. - # - # That leads to the position where we must treat these invalid sequences, - # which are both legitimate binary content, and illegitimate potential - # attacks on the system, as something that passes through correctly in - # a string. --daniel 2012-07-14 - it "binary encode highly dubious non-compliant UTF-8 input #{input.inspect}" do - encoded = ZAML.dump(binary(input)) - encoded.should =~ /!binary/ - YAML.load(encoded).should == input + [ + "\xC0\xAE", # over-long UTF-8 '.' character + "\xC0\x80", # over-long NULL byte + "\xC0\xFF", + "\xC1\xAE", + "\xC1\x80", + "\xC1\xFF", + "\x80", # first continuation byte + "\xbf", # last continuation byte + # all possible continuation bytes in one shot + "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F" + + "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F" + + "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF" + + "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF", + # lonely start characters - first, all possible two byte sequences + "\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 \xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF " + + "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 \xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF ", + # and so for three byte sequences, four, five, and six, as follow. + "\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 \xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF ", + "\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 ", + "\xF8 \xF9 \xFA \xFB ", + "\xFC \xFD ", + # sequences with the last byte missing + "\xC0", "\xE0", "\xF0\x80\x80", "\xF8\x80\x80\x80", "\xFC\x80\x80\x80\x80", + "\xDF", "\xEF\xBF", "\xF7\xBF\xBF", "\xFB\xBF\xBF\xBF", "\xFD\xBF\xBF\xBF\xBF", + # impossible bytes + "\xFE", "\xFF", "\xFE\xFE\xFF\xFF", + # over-long '/' character + "\xC0\xAF", + "\xE0\x80\xAF", + "\xF0\x80\x80\xAF", + "\xF8\x80\x80\x80\xAF", + "\xFC\x80\x80\x80\x80\xAF", + # maximum overlong sequences + "\xc1\xbf", + "\xe0\x9f\xbf", + "\xf0\x8f\xbf\xbf", + "\xf8\x87\xbf\xbf\xbf", + "\xfc\x83\xbf\xbf\xbf\xbf", + # overlong NUL + "\xc0\x80", + "\xe0\x80\x80", + "\xf0\x80\x80\x80", + "\xf8\x80\x80\x80\x80", + "\xfc\x80\x80\x80\x80\x80", + ].each do |input| + # It might seem like we should more correctly reject these sequences in + # the encoder, and I would personally agree, but the sad reality is that + # we do not distinguish binary and textual data in our language, and so we + # wind up with the same thing - a string - containing both. + # + # That leads to the position where we must treat these invalid sequences, + # which are both legitimate binary content, and illegitimate potential + # attacks on the system, as something that passes through correctly in + # a string. --daniel 2012-07-14 + it "binary encode highly dubious non-compliant UTF-8 input #{input.inspect}" do + encoded = ZAML.dump(binary(input)) + encoded.should =~ /!binary/ + YAML.load(encoded).should == input + end end end -end -describe "multi-line values" do - [ - "none", - "one\n", - "two\n\n", - ["one\n", "two"], - ["two\n\n", "three"], - { "\nkey" => "value" }, - { "key\n" => "value" }, - { "\nkey\n" => "value" }, - { "key\nkey" => "value" }, - { "\nkey\nkey" => "value" }, - { "key\nkey\n" => "value" }, - { "\nkey\nkey\n" => "value" }, - ].each do |input| - it "handles #{input.inspect} without corruption" do - zaml = ZAML.dump(input) - YAML.load(zaml).should == input + context "multi-line values" do + [ + "none", + "one\n", + "two\n\n", + ["one\n", "two"], + ["two\n\n", "three"], + { "\nkey" => "value" }, + { "key\n" => "value" }, + { "\nkey\n" => "value" }, + { "key\nkey" => "value" }, + { "\nkey\nkey" => "value" }, + { "key\nkey\n" => "value" }, + { "\nkey\nkey\n" => "value" }, + ].each do |input| + it "handles #{input.inspect} without corruption" do + input.should round_trip_through_yaml + end end end end diff --git a/spec/unit/version_spec.rb b/spec/unit/version_spec.rb new file mode 100644 index 000000000..d2e8b5138 --- /dev/null +++ b/spec/unit/version_spec.rb @@ -0,0 +1,42 @@ +require "spec_helper" +require "puppet/version" +require 'pathname' + +describe "Puppet.version Public API" do + before :each do + Puppet.instance_eval do + if @puppet_version + @puppet_version = nil + end + end + end + + context "without a VERSION file" do + before :each do + Puppet.stubs(:read_version_file).returns(nil) + end + + it "is Puppet::PUPPETVERSION" do + Puppet.version.should == Puppet::PUPPETVERSION + end + it "respects the version= setter" do + Puppet.version = '1.2.3' + Puppet.version.should == '1.2.3' + end + end + + context "with a VERSION file" do + it "is the content of the file" do + Puppet.expects(:read_version_file).with() do |path| + pathname = Pathname.new(path) + pathname.basename.to_s == "VERSION" + end.returns('3.0.1-260-g9ca4e54') + + Puppet.version.should == '3.0.1-260-g9ca4e54' + end + it "respects the version= setter" do + Puppet.version = '1.2.3' + Puppet.version.should == '1.2.3' + end + end +end |
