summaryrefslogtreecommitdiffstats
path: root/documentation
diff options
context:
space:
mode:
authorluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-10-23 16:24:27 +0000
committerluke <luke@980ebf18-57e1-0310-9a29-db15c13687c0>2006-10-23 16:24:27 +0000
commit033de88eedba55623bf3c71597d87b5da8df46b4 (patch)
tree9ae4649351d09b36a6b502e4d7d8ca028aed7410 /documentation
parente741b7b7552918fbca849a59c17baaf0351e16df (diff)
downloadpuppet-033de88eedba55623bf3c71597d87b5da8df46b4.tar.gz
puppet-033de88eedba55623bf3c71597d87b5da8df46b4.tar.xz
puppet-033de88eedba55623bf3c71597d87b5da8df46b4.zip
Making some documentation changes
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1824 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'documentation')
-rw-r--r--documentation/documentation/language/index.page3
-rw-r--r--documentation/documentation/language/resources.page121
-rw-r--r--documentation/documentation/language/tutorial.page (renamed from documentation/documentation/language/languagetutorial.page)5
-rw-r--r--documentation/documentation/programmers/providers.page180
4 files changed, 275 insertions, 34 deletions
diff --git a/documentation/documentation/language/index.page b/documentation/documentation/language/index.page
index 08ce4eeff..fe37e6701 100644
--- a/documentation/documentation/language/index.page
+++ b/documentation/documentation/language/index.page
@@ -9,7 +9,8 @@ subtreeLevel: 6
Language Syntax
===============
-* [Puppet Language Tutorial](languagetutorial.html)
+* [Specifying Resources](resources.html)
+* [Puppet Language Tutorial](tutorial.html)
* [Control Structures](structures.html)
diff --git a/documentation/documentation/language/resources.page b/documentation/documentation/language/resources.page
new file mode 100644
index 000000000..ef0577e09
--- /dev/null
+++ b/documentation/documentation/language/resources.page
@@ -0,0 +1,121 @@
+---
+inMenu: true
+title: Language Introduction
+orderInfo: 30
+---
+
+# Resources
+
+The fundamental building block in a Puppet configuration is called a
+``resource``, which is just an object that models some element on a
+computer. Each of these resources has a specific associated type, such
+as ``user`` or ``package``, and each of these types has a fixed list of
+allowed parameters (there are also
+[metaparameters](../reference/typedocs.html#meta-parameters), which all
+types accept).
+
+All resources also have a name that identifies them uniquely.
+
+Puppet provides a simple hash-like syntax for specifying resources; for
+instance, here is how you might specify that a file should exist:
+
+ file { "/etc/myfile":
+ content => "Some text",
+ mode => 644
+ }
+
+Here we have the three key elements to any resource specification: The
+type (``file``), the name (``/etc/file``), and an attribute list (in
+this case, ``content`` and ``mode``). Multiple attributes must be
+comma-separated, and trailing commas are acceptable.
+
+Whitespace generally doesn't matter; your resource can be specified on
+one line, or split over several as above.
+
+## Multiple Resources
+
+You can just specify multiple resources one after the other in your
+manifest:
+
+ package { sudo: ensure => installed }
+
+ file { "/etc/sudoers": mode => 440, owner => root }
+
+If you have many resources of the same type, you can semicolon-separate
+them in one statement:
+
+ file {
+ "/etc/passwd": owner => root, mode => 644;
+ "/etc/shadow": owner => root, mode => 440;
+ }
+
+Trailing semicolons are accepted, as you can see.
+
+If you have multiple resources of the same type and with the same
+attribute list, you can use an array for the name:
+
+ package { [openssh, openssl]: ensure => installed }
+
+## Relationships
+
+No resource lives in a vacuum -- resources usually work together to
+provide some needed functionality. Puppet provides some facilities for
+specifying that resources are related, and specifying these
+relationships provides some extra functionality.
+
+There are two kinds of relationships in Puppet -- normal dependency, and
+reactive dependency -- and you can specify them from either end of the
+relationship. Because any resource can be related to any other
+resource, relationships are specified with
+[metaparameters](../reference/typedocs.html#meta-parameters).
+
+Normal dependency relationships are just used for ordering; as long as
+you do not create circular dependencies, Puppet guarantees that your
+resources will be configured in the order of their dependencies. For
+instance:
+
+ user { myuser: ensure => present }
+
+ file { "/tmp/file":
+ owner => myuser,
+ ensure => directory
+ require => User[myuser]
+ }
+
+Notice how the dependency is specified -- this is called a ``resource
+reference``, and is composed of the type and name of the related
+resource. Puppet operations on types are capitalized, and in this case
+you are essentially treating the type as a hash and looking an instance
+up by name.
+
+Reactive dependencies provide the same ordering relationship as normal
+dependencies, and in addition the dependency attempts to react to any
+changes in required resources. Most resource types are not capable of
+reacting to anything (e.g., users do not need to be restarted, nor do
+files need to get refreshed), but this is an important functionality
+for resources like ``service``.
+
+Plain dependencies are specified using ``require`` and ``before``, while
+reactive dependencies are specified using ``subscribe`` and ``notify``.
+
+It is important to always specify your relationships and not to depend
+on file order, because Puppet does a topological sort of all resources
+based on relationship, and resources that are not guaranteed to stay in
+the same order in which they are specified.
+
+### Autorequire
+
+The above example is actually redundant, because Puppet makes every
+attempt to automatically determine relationships. The ``file`` resource
+is smart enough to automatically list any associated users or groups as
+dependencies, for instance. In most cases, Puppet resources are smart
+enough to autorequire any directly related resources.
+
+### Syntax vs. Attributes
+
+It is important to note that Puppet's interpreter only validates that
+attributes are valid for the associated type, it never interprets their
+values in any way. A resource specification that successfully compiles
+for a client may fail to pass validation on that client, for instance.
+
+*$Id$
diff --git a/documentation/documentation/language/languagetutorial.page b/documentation/documentation/language/tutorial.page
index 9c849ea49..5179e7b86 100644
--- a/documentation/documentation/language/languagetutorial.page
+++ b/documentation/documentation/language/tutorial.page
@@ -45,7 +45,7 @@ Here we create a symbolic name instead of using the path as the name, and now
we can refer to that element by name elsewhere in the manifest:
service { sshd:
- subscribe => file[sshdconfig]
+ subscribe => File[sshdconfig]
}
This will cause the ``sshd`` service to get restarted when the ``sshdconfig``
@@ -131,7 +131,7 @@ trees are created as a manifest is parsed. Take the following configuration:
}
class sub inherits base {
- file { "/etc/issue":
+ File["/etc/issue"] {
source => "puppet://server/module/mysite/issue"
}
}
@@ -171,4 +171,5 @@ This can be used for any element type. For instance, CentOS defaults to using
}
...
+
*$Id$*
diff --git a/documentation/documentation/programmers/providers.page b/documentation/documentation/programmers/providers.page
index 0fb6155a9..f8b2c1379 100644
--- a/documentation/documentation/programmers/providers.page
+++ b/documentation/documentation/programmers/providers.page
@@ -6,46 +6,164 @@ orderInfo: 70
# Providers
-Since different systems often have ways of doing things, Puppet's uses a layer of abstraction called "providers" to provide a mechanism for implementing its types in system-specific ways.
+One of Puppet's primary goals is to function as a portable abstraction
+layer above different operating systems, relieving developers and users
+from the need to know how to use every command on every operating
+system. The top layer of the abstraction layer is composed of Puppet
+types, such as Users, Groups, and Packages; these types provide the
+modeling for how to manage a given resource, such as what attributes are
+appropriate and how to validate them.
-For instance, on most UNIX systems, users and groups are added to the system simply by adding the new user or group to a flat file in the `/etc` directory. However, other systems may use different mechanisms (such as NetInfo, LDAP, or Kerberos) either alone or in combination with flat files.
+For some resource types and on some platforms, simple types are
+sufficient. In the far more common case, though, types must be
+implemented differently on different platforms, and a layer exists below
+the types to handle this implementation variety. This layer is composed
+of what we call ``providers``. For example, Puppet currently supports
+more than 15 different package providers, such as ``apt``, ``yum``, and
+``gem``. Puppet will usually select an appropriate provider for your
+system, but you can override that default selection using the
+``provider`` attribute as appropriate.
-Currently, providers exist for groups, users, packages, nameservice, and system services using these mechanisms:
+This document is meant to help you understand how to create new
+providers. They are usually quite simple, and they are a great way to
+get started with Puppet development. Puppet automatically loads
+providers on demand, so you can create a new provider, drop it into your
+Ruby search path, and start using it immediately. We are also always
+glad to add new providers to the main Puppet distribution.
-The following providers exist to add groups and users:
-* `groupadd`/`useradd`
-* NetInfo
-* flat files
+Puppet types are not required to have providers, and not all of the core
+types that ship with Puppet have yet been converted to using them, but
+it is our goal to do so, and it is recommended that all new types split
+the modeling and implementation into types and providers.
-There are also providers for the following package management utilities:
-* Apple Package Manager (pkg)
-* `apt`
-* `aptitude`
-* `blastwave`
-* `darwinport`
-* Debian Package format (`dpkg`)
-* FreeBSD Package format
-* Ruby Gems
-* OpenBSD Package format
-* Portage
-* Ports
-* Redhat Package Manager (`rpm`)
-* Sun
-* Sunfreeware
-* `up2date`
-* `yum`
+Any type that does have providers will automatically have a ``provider``
+attribute created, and this attribute can be used to specify the
+provider; otherwise, Puppet will try to determine the appropriate one.
-These providers can be used to add system services:
-* base (basic service description)
-* Standard SysV `init`
-* debian-style SysV `init`
-* redhat-style SysV `init` using `chkconfig`
-* Sun Microsystem's "Service Management Framework" (`smf`)
+## Provider Suitability
-If you create provider code for mechanisms not cited above, please consider contributing them to the project.
+Providers are inherently tied to a given platform or a given tool, so
+the majority of providers will usually not be suitable on a given
+system. To handle this fact, Puppet provides mechanisms for confining
+providers based on their requirements. You can confine providers to
+specific platforms according to facts returned by Facter, but it is
+usually best to confine them based on what binaries they require to
+function.
+Confinement is accomplished using two provider class methods:
+``commands`` and ``confine``.
+### Confinement
+The most important method is ``confine``, and in fact it's used by
+``commands``. It supports four criteria for determining suitability:
+Existence of a file, truth of a value, falseness of a value, or whether
+a fact matches. Generally the true and false tests are used in
+combination with another statement; for instance, you could try to load
+a library, set a value based on the results of the load, and then
+confine a provider based on the value.
+The ``exists`` test is mostly useful for checking for binaries, so it is
+better to use the ``commands`` method in those cases as it is more
+useful.
+Any ``confine`` arguments that are not ``true``, ``false``, or
+``exists`` are expected to be Facter facts, with a single value or an
+array of values to test against. If the host's value for that fact is
+not in the list of provided values, then the host is not suitable. Fact
+names and values can be passed as strings or symbols of any case.
+Here is an example using all of the tests:
+
+ confine :exists => "/etc/pam.d"
+ confine :true => defined?(ActiveRecord)
+ confine :false => defined?(OtherClass)
+ confine :operatingsystem => [:darwin, :solaris]
+
+### Commands
+
+You specify the binaries that your provider needs using the ``commands``
+method; for example, this is how the ``apt`` provider confines itself to
+appropriate systems:
+
+ commands :aptget => "/usr/bin/apt-get",
+ :aptcache => "/usr/bin/apt-cache",
+ :preseed => "/usr/bin/debconf-set-selections"
+
+This method does two things for you: It calls ``confine`` with the
+binary as an ``exists`` test, and it stores the value in a place that
+instances can easily access it. Instances can call ``command`` with the
+name you use and get the full path back:
+
+ execute(command(:aptget), "install", "mypkg")
+
+Even more usefully, though, this defines an instance method with the
+name you use, so you can just call this instead:
+
+ aptget "install", "mypkg"
+
+When you use ``commands``, you can choose whether your binary is
+specified fully qualifed or unqualified. If you do not qualify the
+binary, then the provider is suitable as long as the binary is somewhere
+in Puppet's search path; if the binary is fully qualified, then it must
+exist at exactly that location.
+
+### Defaults
+
+Because hosts might often have multiple suitable providers for a given
+type, you can specify that a provider is a default, based again on fact
+comparisons:
+
+ defaultfor :operatingsystem => :debian
+
+Puppet will use the longest matching list of defaults to select a
+provider, so the following provider would be chosen in preference to the
+above provider:
+
+ defaultfor :operatingsystem => :debian, :hardwaremodel => "i386"
+
+## Provider APIs
+
+Providers only ever interact with an instance of its associated type, so
+the only class that needs to know the provider API is that associated
+type. Puppet defaults to a simple API based on attributes, but the type
+can override if appropriate. Unless you are creating a new Puppet type,
+the best way to determine what your provider API is usually to look at
+other providers.
+
+By default, Puppet will just call setter and getter methods on the
+provider according to the attributes being modified. For instance,
+``user`` providers define ``uid=`` and ``uid`` methods, and the ``user``
+type calls these methods to modify a user's UID. If this API is
+appropriate for your type, then you just need to implement the
+validation and documentation in your type, and the provider will do the
+rest.
+
+If this API is not appropriate, however, as in packages and services,
+then you can define a custom API. Generally you would implement this by
+calling different provider methods for different values; here is a
+snippet of how the ``package`` provider interface is called:
+
+ newvalue(:present, :event => :package_installed) do
+ provider.install
+ end
+
+Here, the type supports multiple values for the ``ensure`` state, and
+each value results in a different method being called on the provider.
+
+## Documentation
+
+Providers, like many other aspects of Puppet, can provide a
+documentation string (in Markdown) to describe how to use them. When
+the Type reference is generated, all providers will be listed for each
+type, along with each provider's doc string, the list of binaries it
+requires, and for what systems it is a default.
+
+This doc string is specified using the ``desc`` class method:
+
+ Puppet::Type.type(:package).provide :apt do
+ desc "The apt provider."
+ ...
+ end
+
+# $Id$