diff options
author | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-06-17 01:56:04 +0000 |
---|---|---|
committer | luke <luke@980ebf18-57e1-0310-9a29-db15c13687c0> | 2006-06-17 01:56:04 +0000 |
commit | 644fd4e5ff3cf3a31370be48c7d960e74204477d (patch) | |
tree | 98619c04b07ac461935505abc95ac2d533e10108 /documentation/introduction.page | |
parent | f0907607347c26127dd566fbe5b19c8528d25f5d (diff) | |
download | puppet-644fd4e5ff3cf3a31370be48c7d960e74204477d.tar.gz puppet-644fd4e5ff3cf3a31370be48c7d960e74204477d.tar.xz puppet-644fd4e5ff3cf3a31370be48c7d960e74204477d.zip |
updating docs to work with webgen
git-svn-id: https://reductivelabs.com/svn/puppet/trunk@1293 980ebf18-57e1-0310-9a29-db15c13687c0
Diffstat (limited to 'documentation/introduction.page')
-rw-r--r-- | documentation/introduction.page | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/documentation/introduction.page b/documentation/introduction.page new file mode 100644 index 000000000..2d1cd680c --- /dev/null +++ b/documentation/introduction.page @@ -0,0 +1,313 @@ +--- +inMenu: true +--- +# Introduction + +Puppet is a system configuration tool. It has a library for managing the +system, a language for specifying the configuration you want, and a set of +clients and servers for communicating the configuration and other information. + +The library is entirely responsible for all action, and the language is +entirely responsible for expressing configuration choices. Everything is +developed so that the language operations can take place centrally on a single +server (or bank of servers), and all library operations will take place on each +individual client. Thus, there is a clear demarcation between language +operations and library operations, as this document will mention. + +# Setup + +The vast majority of Puppet architectures will look like a star, with a +central server running `puppetmasterd`, and each client node running +`puppetd`, contacting that central server. Your central manifest, which +contains the configuration for all of your nodes, needs to be on the central +server, most likely at `/etc/puppet/manifests/site.pp`. + +Start the `puppetmasterd` daemon, and then tell your clients to contact that +server by specifying `-s <servername>` as arguments to `puppetd`, replacing +"<servername>" with the name of the server. Alternatively, `puppetd` defaults +to looking for a server named "puppet", so you can just create a CNAME for +your server, so that it answers to "puppet". + +It is a good idea to run both the server and client in verbose mode, enabled +with the `-v` flag, until you are sure everything is working. As each new +client connects, you will need to run `puppetca --list` to list the +certificates waiting to be signed, and then `puppetca --sign <name>`, +replacing "<name>" with the name of the client whose certificate you want to +sign. You can turn on autosigning by creating `/etc/puppet/autosign.conf` and +put the hosts, domains, or IP addresses or ranges that you want to sign in +there. + +# Language + +The language is declarative, and is modeled somewhat after cfengine's concept +of actions, action instances, and instance parameters. Here is how a file +element would look in puppet: + + file { "/etc/passwd": + owner => root, + group => root, + mode => 644 + } + +Each instance of a low-level element like ``file`` must have a name parameter +defined, because that is how you uniquely refer to the element you are +managing. Any string that doesn't match ``\w+`` or ``\d+`` needs to be quoted +(e.g., file names). + +There are two ways for types to be available in the language: They'll either +be ``primitive types`` included in the Puppet framework itself, or they'll be +``defined types`` resulting from definitions or server classes. + +## Definitions + +Because experience with cfengine showed that objects of different types are +often related, puppet focuses on making creation of associations between +objects of any type easier than making many objects of the same type. The +fundamental unit of association is a 'definition': + + # currently, the variables don't have '$' attached in the definition prototype + # this might change + define sudo(source,group) { + package { sudo: + version => "1.6.7" + } + file { "/etc/sudoers": + source => $source, # parameterization; copy the file from where? + mode => 440 # the 'file' type converts this appropriately to + # octal + } + file { "/usr/sbin/sudo": + owner => root, + group => $group + } + } + +A definition has its own scope, so variables defined within it are only +available within the definition itself. + +This definition can now be treated as a type: + + sudo { + group => root, + source => "http://fileserver/files/sudoers?v=production" + } + +One significant difference between definitions and types is that types +generally have many associated parameters, most of which are optional, while a +given definition will (at this point) always require all parameters. You can +manage as little or as much of a file as you want, for instance, but once you +wrap it in a definition you have to pass every specified parameter to instances +of the definition. + +It is appropriate to think of definitions as declarative functions; referring +to the name of a definition results in the associated declarative code being +executed with the provided parameters. + +I will likely soon add the ability to provide defaults to definition +parameters; any other feature requests are welcome. + +## Classes + +In addition to definitions, the language supports server classes. Classes are +different from definitions in two fundamental ways: They do not (currently) +support parameterization, and sub classes can override base classes. + +Classes can be called using the same syntax as definitions, although always +without arguments and usually without names, but they are generally called +with the ``include`` keyword, which is more flexible in that it supports +variable interpolation and conditional expressions: + + class base { + include sudo + } + + class server inherits base { + include ssh + } + + case $hostname { + myhost: { include server } + default: { include base } + } + + include $operatingsystem + + +## Variables + +Because it is assumed that strings will be used far more than variables, simple +strings don't have be quoted or otherwise marked, but variables must have the +``$`` attached: + + $group = "root" + + file { "/etc/sudoers": + group => $group + } + +Strings and booleans (``true`` and ``false``) are the only data types; even +numbers are converted to strings. Arrays are supported, although their +behaviour has not been characterized for all cases. One particular use of +arrays is for implicit iteration: + + $files = ["/etc/passwd","/etc/group","/etc/fstab"] + + file { $files: + owner => root, + group => root + } + +This implicitly iterates across the file list and performs all of the +appropriate checks. + +Currently, ``puppet`` collects as much information as it can (using the +``Facter`` library) and sets all of it as top-level variables. So, you can +expect variables like ``$operatingsystem`` and ``$ipaddress``. + +Also, because ``puppet`` is a declarative language, reassigning a variable +within the same scope is currently an error. The language is written such that +this could be disabled (please let me know if you need this feature), but it is +currently always enabled. You can override defaults in a lower scope: + + $var = default + + define test { + $var = override + ... + } + +It is expected that parameter passing to definitions will be the primary +mechanism for variable assignment, so it seems unlikely that this limitation +will cause much trouble. + +## Importing + +Files can be imported using the ``import`` command: + + import "filename" + +There is currently no search path or anything; files are looked for in the same +directory as the file doing the importing. Each file should have its own +lexical scope, but I haven't yet figured out how to do that. + +## Control Structures + +There are currently two basic control structures, one meant to return a value +and the other just a normal 'if/elsif/else' structure. + +### Selectors + +One of the primary goals of Puppet is to simplify building a single +configuration that works across multiple machines and machine classes. One +mechanism for this is currently called a 'selector'; it is similar to the +trinary operator ``:?``: + + $value = $variable ? { + value1 => setvalue1, + value2 => setvalue2, + default => other + } + +This sets the variable ``$value`` depending on the value of ``$variable``. If +it is ``value1``, then ``$value`` gets set to ``setvalue1``, else the value +gets set to ``other``. + +The brackets can be in either part of the expression, or not at all: + + $value = $variable ? "value1" => "setvalue1" + +A selector that doesn't match a value is a compile error. + +These structures are useful for simplistic abstraction across platforms: + + file { "/etc/sudoers": + owner => root, + group => $operatingsystem ? { + SunOS => root, + Linux => root, + FreeBSD => wheel + } + } + +Selectors can specify default values using the ``default`` keyword. + +### Case Statements + +Puppet currently supports a normal Case structure similar to so many other +languages: + + case $operatingsystem { + solaris: { include sunos } + debian: { include linux } + default: { include $operatingsystem } + } + +As you can see, case statements also support defaults. + +The difference between the case stateements and the selectors is that the +selectors just return values while the case statements execute arbitrary +Puppet code. + +# Library + +This section discusses some aspects of the internals of the Puppet library. +This information can be useful but is not critical for use and understanding +of Puppet. + +The library is composed of two fundamental types of objects: Types and states +(yes, the terminology is atrocious). States are things that can be configured +to change one aspect of an object (e.g., a file's owner), types are essentially +named collections of states. So, there is a File type, and it is a collection +of all of the states available to modify files. + +In addition to states, which necessarily modify 'the bits on disk', as it were, +types can also have non-state parameters which modify how that type instance +behaves: + + file { "/bin": + owner => bin, + recurse => true + } + +The ``recurse`` parameter to ``file`` does not modify the system itself, it +modifies how the ``file`` type manages ``/bin``. + +Not all types as expressed in the language are types defined in the library; +some language types are actually definitions or server classes. Types that +are defined in the language itself are termed ``primitive types`` or just +``primitives``, and types that generate other types are termed ``metatypes``. + +At this point, all types have a unique name (within the current scope, but it +probably should actually be global). This name is set using a class instance +variable: : + + # in the library + Puppet::Type.newtype(:mytype) + ... + end + + # in the language + mytype { "yay": ... } + +The states similarly have unique names, although this uniqueness is only +per-type. When a type is defined, all states and parameters are added using +class methods. Here is the File type declaration: + + newstate(:ensure) do ... end + newstate(:owner) do ... end + newstate(:group) do ... end + ... + newparam(:path) do ... end + +Lastly, each type must either provide a state or parameter of ':name', or it +must mark a parameter as the namevar so that the system knows what is +considered the name: + + newparam(:path) do + isnamevar + end + +With this declaration, ``file { "/tmp/file": }`` is basically equivalent to ``file { path => "/tmp/file" }``. + +See [Creating a Puppet Type](creating-a-puppet-type.html) for more +information. |