diff options
| author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-10-23 16:24:27 +0000 |
|---|---|---|
| committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-10-23 16:24:27 +0000 |
| commit | 033de88eedba55623bf3c71597d87b5da8df46b4 (patch) | |
| tree | 9ae4649351d09b36a6b502e4d7d8ca028aed7410 /documentation | |
| parent | e741b7b7552918fbca849a59c17baaf0351e16df (diff) | |
| download | puppet-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.page | 3 | ||||
| -rw-r--r-- | documentation/documentation/language/resources.page | 121 | ||||
| -rw-r--r-- | documentation/documentation/language/tutorial.page (renamed from documentation/documentation/language/languagetutorial.page) | 5 | ||||
| -rw-r--r-- | documentation/documentation/programmers/providers.page | 180 |
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$ |
