forked from ungleich-public/cdist
Add documentation and mentions for polyglot scripting capabilities for configuring and extending cdist [POLYGLOT]
This commit is contained in:
parent
9b3505e8a1
commit
ae10ff49dd
7 changed files with 673 additions and 67 deletions
|
@ -3,12 +3,29 @@ Explorer
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
Explorers are small shell scripts, which will be executed on the target
|
Explorers are small scripts, typically written in POSIX shell,
|
||||||
host. The aim of each explorer is to give hints to types on how to act on the
|
which will be executed on the target host.
|
||||||
|
The aim of each explorer is to give hints to types on how to act on the
|
||||||
target system. An explorer outputs the result to stdout, which is usually
|
target system. An explorer outputs the result to stdout, which is usually
|
||||||
a one liner, but may be empty or multi line especially in the case of
|
a one liner, but may be empty or multi line especially in the case of
|
||||||
type explorers.
|
type explorers.
|
||||||
|
|
||||||
|
.. tip::
|
||||||
|
An :program:`explorer` can be written in **any scripting language**,
|
||||||
|
provided it is executable and has a proper **shebang**.
|
||||||
|
|
||||||
|
Nevertheless, for explorers, it is usually best to stick with the
|
||||||
|
**POSIX shell** in order to minimize
|
||||||
|
requirements on target hosts where they would need to be executed.
|
||||||
|
|
||||||
|
For executable shell code, the recommended shebang is :code:`#!/bin/sh -e`.
|
||||||
|
|
||||||
|
If an :program:`explorer` lacks `execute` permissions,
|
||||||
|
:program:`cdist` assumes it to be written in **shell** and executes it using
|
||||||
|
`$CDIST_REMOTE_SHELL`, which defaults to :code:`/bin/sh -e`.
|
||||||
|
|
||||||
|
For more details and examples, see :doc:`cdist-polyglot`.
|
||||||
|
|
||||||
There are general explorers, which are run in an early stage, and
|
There are general explorers, which are run in an early stage, and
|
||||||
type explorers. Both work almost exactly the same way, with the difference
|
type explorers. Both work almost exactly the same way, with the difference
|
||||||
that the values of the general explorers are stored in a general location and
|
that the values of the general explorers are stored in a general location and
|
||||||
|
@ -32,9 +49,14 @@ error message on stderr, which will cause cdist to abort.
|
||||||
You can also use stderr for debugging purposes while developing a new
|
You can also use stderr for debugging purposes while developing a new
|
||||||
explorer.
|
explorer.
|
||||||
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
A very simple explorer may look like this::
|
A very simple explorer may look like this:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
hostname
|
hostname
|
||||||
|
|
||||||
|
@ -44,6 +66,8 @@ A type explorer, which could check for the status of a package may look like thi
|
||||||
|
|
||||||
.. code-block:: sh
|
.. code-block:: sh
|
||||||
|
|
||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
if [ -f "$__object/parameter/name" ]; then
|
if [ -f "$__object/parameter/name" ]; then
|
||||||
name="$(cat "$__object/parameter/name")"
|
name="$(cat "$__object/parameter/name")"
|
||||||
else
|
else
|
||||||
|
|
|
@ -22,8 +22,14 @@ Fast development
|
||||||
Focus on straightforwardness of type creation is a main development objective
|
Focus on straightforwardness of type creation is a main development objective
|
||||||
Batteries included: A lot of requirements can be solved using standard types
|
Batteries included: A lot of requirements can be solved using standard types
|
||||||
|
|
||||||
Modern Programming Language
|
Modern Programming Language (for cdist itself)
|
||||||
cdist is written in Python
|
cdist itself is written in Python
|
||||||
|
|
||||||
|
Language-agnostic / Polyglot (for the rest)
|
||||||
|
Although cdist itself is written in Python, it can be configured
|
||||||
|
and extended with any scripting language available.
|
||||||
|
|
||||||
|
(The `POSIX shell <https://en.wikipedia.org/wiki/Unix_shell>`_ is recommended, especially for any code destined to run on target hosts)
|
||||||
|
|
||||||
Requirements, Scalability
|
Requirements, Scalability
|
||||||
No central server needed, cdist operates in push mode and can be run from any computer
|
No central server needed, cdist operates in push mode and can be run from any computer
|
||||||
|
@ -44,5 +50,6 @@ UNIX, familiar environment, documentation
|
||||||
Is available as manpages and HTML
|
Is available as manpages and HTML
|
||||||
|
|
||||||
UNIX, simplicity, familiar environment
|
UNIX, simplicity, familiar environment
|
||||||
cdist is configured in POSIX shell
|
The ubiquitious `POSIX shell <https://en.wikipedia.org/wiki/Unix_shell>`_ is the recommended language for configuring and extending cdist.
|
||||||
|
|
||||||
|
The :program:`Cdist API` is based on simple and familiar UNIX constructs: environment variables, standard I/O, and files/directories
|
||||||
|
|
|
@ -3,7 +3,9 @@ Manifest
|
||||||
|
|
||||||
Description
|
Description
|
||||||
-----------
|
-----------
|
||||||
Manifests are used to define which objects to create.
|
Manifests are scripts that are executed *locally* (on master)
|
||||||
|
for the purpose of defining which objects to create.
|
||||||
|
|
||||||
Objects are instances of **types**, like in object oriented programming languages.
|
Objects are instances of **types**, like in object oriented programming languages.
|
||||||
An object is represented by the combination of
|
An object is represented by the combination of
|
||||||
**type + slash + object name**: **\__file/etc/cdist-configured** is an
|
**type + slash + object name**: **\__file/etc/cdist-configured** is an
|
||||||
|
@ -24,10 +26,10 @@ at an example::
|
||||||
# Same with the __directory type
|
# Same with the __directory type
|
||||||
__directory /tmp/cdist --state present
|
__directory /tmp/cdist --state present
|
||||||
|
|
||||||
These two lines create objects, which will later be used to realise the
|
These two lines create objects, which will later be used to realise the
|
||||||
configuration on the target host.
|
configuration on the target host.
|
||||||
|
|
||||||
Manifests are executed locally as a shell script using **/bin/sh -e**.
|
Manifests are executed *locally* (on master).
|
||||||
The resulting objects are stored in an internal database.
|
The resulting objects are stored in an internal database.
|
||||||
|
|
||||||
The same object can be redefined in multiple different manifests as long as
|
The same object can be redefined in multiple different manifests as long as
|
||||||
|
@ -36,6 +38,20 @@ the parameters are exactly the same.
|
||||||
In general, manifests are used to define which types are used depending
|
In general, manifests are used to define which types are used depending
|
||||||
on given conditions.
|
on given conditions.
|
||||||
|
|
||||||
|
.. tip::
|
||||||
|
|
||||||
|
A manifest can be written in **any scripting language**,
|
||||||
|
provided that the script is executable and has a proper **shebang**.
|
||||||
|
|
||||||
|
For executable shell code, the recommended shebang is :code:`#!/bin/sh -e`.
|
||||||
|
|
||||||
|
If :program:`manifest` lacks `execute` permissions, :program:`cdist` assumes
|
||||||
|
it to be written in **shell** and executes it using
|
||||||
|
`$CDIST_LOCAL_SHELL`, which defaults to :code:`/bin/sh -e`.
|
||||||
|
|
||||||
|
For more details and examples, see :doc:`cdist-polyglot`.
|
||||||
|
|
||||||
|
.. _cdist-manifest#initial-and-type-manifests:
|
||||||
|
|
||||||
Initial and type manifests
|
Initial and type manifests
|
||||||
--------------------------
|
--------------------------
|
||||||
|
@ -64,14 +80,14 @@ environment variable **__target_host** and/or **__target_hostname** and/or
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
This manifest says: Independent of the host, always use the type
|
This manifest says: Independent of the host, always use the type
|
||||||
**__cdistmarker**, which creates the file **/etc/cdist-configured**,
|
**__cdistmarker**, which creates the file **/etc/cdist-configured**,
|
||||||
with the timestamp as content.
|
with the timestamp as content.
|
||||||
The directory **/home/services/kvm-vm**, including all parent directories,
|
The directory **/home/services/kvm-vm**, including all parent directories,
|
||||||
is only created on the host **localhost**.
|
is only created on the host **localhost**.
|
||||||
|
|
||||||
As you can see, there is no magic involved, the manifest is simple shell code that
|
As you can see, there is no magic involved, the manifest is simple shell code that
|
||||||
utilises cdist types. Every available type can be executed like a normal
|
utilises cdist types. Every available type can be executed like a normal
|
||||||
command.
|
command.
|
||||||
|
|
||||||
|
|
||||||
|
@ -102,17 +118,17 @@ delimiters including space, tab and newline.
|
||||||
|
|
||||||
1 # No dependency
|
1 # No dependency
|
||||||
2 __file /etc/cdist-configured
|
2 __file /etc/cdist-configured
|
||||||
3
|
3
|
||||||
4 # Require above object
|
4 # Require above object
|
||||||
5 require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \
|
5 require="__file/etc/cdist-configured" __link /tmp/cdist-testfile \
|
||||||
6 --source /etc/cdist-configured --type symbolic
|
6 --source /etc/cdist-configured --type symbolic
|
||||||
7
|
7
|
||||||
8 # Require two objects
|
8 # Require two objects
|
||||||
9 require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \
|
9 require="__file/etc/cdist-configured __link/tmp/cdist-testfile" \
|
||||||
10 __file /tmp/cdist-another-testfile
|
10 __file /tmp/cdist-another-testfile
|
||||||
|
|
||||||
|
|
||||||
Above the "require" variable is only set for the command that is
|
Above the "require" variable is only set for the command that is
|
||||||
immediately following it. Dependencies should always be declared that way.
|
immediately following it. Dependencies should always be declared that way.
|
||||||
|
|
||||||
On line 4 you can see that the instantiation of a type "\__link" object needs
|
On line 4 you can see that the instantiation of a type "\__link" object needs
|
||||||
|
@ -156,7 +172,7 @@ in `cdist execution stages <cdist-stages.html>`_ and of how types work in `cdist
|
||||||
|
|
||||||
Create dependencies from execution order
|
Create dependencies from execution order
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
You can tell cdist to execute all types in the order in which they are created
|
You can tell cdist to execute all types in the order in which they are created
|
||||||
in the manifest by setting up the variable CDIST_ORDER_DEPENDENCY.
|
in the manifest by setting up the variable CDIST_ORDER_DEPENDENCY.
|
||||||
When cdist sees that this variable is setup, the current created object
|
When cdist sees that this variable is setup, the current created object
|
||||||
automatically depends on the previously created object.
|
automatically depends on the previously created object.
|
||||||
|
@ -288,14 +304,14 @@ and there are no other dependencies from this manifest.
|
||||||
|
|
||||||
Overrides
|
Overrides
|
||||||
---------
|
---------
|
||||||
In some special cases, you would like to create an already defined object
|
In some special cases, you would like to create an already defined object
|
||||||
with different parameters. In normal situations this leads to an error in cdist.
|
with different parameters. In normal situations this leads to an error in cdist.
|
||||||
If you wish, you can setup the environment variable CDIST_OVERRIDE
|
If you wish, you can setup the environment variable CDIST_OVERRIDE
|
||||||
(any value or even empty is ok) to tell cdist, that this object override is
|
(any value or even empty is ok) to tell cdist, that this object override is
|
||||||
wanted and should be accepted.
|
wanted and should be accepted.
|
||||||
ATTENTION: Only use this feature if you are 100% sure in which order
|
ATTENTION: Only use this feature if you are 100% sure in which order
|
||||||
cdist encounters the affected objects, otherwise this results
|
cdist encounters the affected objects, otherwise this results
|
||||||
in an undefined situation.
|
in an undefined situation.
|
||||||
|
|
||||||
If CDIST_OVERRIDE and CDIST_ORDER_DEPENDENCY are set for an object,
|
If CDIST_OVERRIDE and CDIST_ORDER_DEPENDENCY are set for an object,
|
||||||
CDIST_ORDER_DEPENDENCY will be ignored, because adding a dependency in case of
|
CDIST_ORDER_DEPENDENCY will be ignored, because adding a dependency in case of
|
||||||
|
@ -348,11 +364,11 @@ How to override objects:
|
||||||
# (e.g. for example only sourced if a special application is on the target host)
|
# (e.g. for example only sourced if a special application is on the target host)
|
||||||
|
|
||||||
# this leads to an error ...
|
# this leads to an error ...
|
||||||
__user foobar --password 'some_other_hash'
|
__user foobar --password 'some_other_hash'
|
||||||
|
|
||||||
# this tells cdist, that you know that this is an override and should be accepted
|
# this tells cdist, that you know that this is an override and should be accepted
|
||||||
CDIST_OVERRIDE=yes __user foobar --password 'some_other_hash'
|
CDIST_OVERRIDE=yes __user foobar --password 'some_other_hash'
|
||||||
# it's only an override, means the parameter --home is not touched
|
# it's only an override, means the parameter --home is not touched
|
||||||
# and stays at the original value of /home/foobarexample
|
# and stays at the original value of /home/foobarexample
|
||||||
|
|
||||||
Dependencies defined by execution order work as following:
|
Dependencies defined by execution order work as following:
|
||||||
|
|
443
docs/src/cdist-polyglot.rst
Normal file
443
docs/src/cdist-polyglot.rst
Normal file
|
@ -0,0 +1,443 @@
|
||||||
|
Polyglot
|
||||||
|
========
|
||||||
|
|
||||||
|
Description
|
||||||
|
-----------
|
||||||
|
|
||||||
|
Although **cdist** itself is written in **Python**, it features a
|
||||||
|
*language-agnostic* (and hence *polyglot*) extension system.
|
||||||
|
|
||||||
|
As such, **cdist** can be extended with a mix-and-match of
|
||||||
|
**any scripting language** in addition to the usual -and recommended-
|
||||||
|
**POSIX shell** (`sh`): `bash`, `perl`, `python`, `ruby`, `node`, ... whatever.
|
||||||
|
|
||||||
|
This is true for all extension mechanisms available for **cdist**, namely:
|
||||||
|
|
||||||
|
.. list-table::
|
||||||
|
|
||||||
|
* - :doc:`manifests <cdist-manifest>`
|
||||||
|
- (including :ref:`manifest/init <cdist-manifest#initial-and-type-manifests>`
|
||||||
|
and :ref:`type manifests <cdist-type#manifest>`)
|
||||||
|
|
||||||
|
* - :doc:`explorers <cdist-explorer>`
|
||||||
|
- (both **global** and :ref:`type explorers <cdist-type#explorers>`)
|
||||||
|
|
||||||
|
* - :ref:`gencode-* scripts <cdist-type#gencode-scripts>`
|
||||||
|
- (both :program:`gencode-local` and :program:`gencode-remote`)
|
||||||
|
|
||||||
|
* - and even :ref:`generated code <cdist-type#gencode-scripts>`
|
||||||
|
- (i.e. the outputs from
|
||||||
|
:ref:`gencode-* scripts <cdist-type#gencode-scripts>`)
|
||||||
|
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<a>You do not have to commit to any single language...</a>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
.. container::
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
It's indeed possible (though not necessarily recommended)
|
||||||
|
to **mix-and-match** different
|
||||||
|
languages when extending **cdist**, for example:
|
||||||
|
|
||||||
|
A **type** could, in principal, have a `manifest` and an **explorer** written
|
||||||
|
in **POSIX shell**, a `gencode-remote` in **Python**
|
||||||
|
(which could generate code in **POSIX shell**) and a `gencode-local`
|
||||||
|
in **Perl** (which could generate code in **Perl**,
|
||||||
|
or some other language), while you are at it...
|
||||||
|
|
||||||
|
Just don't expect to submit such a hodge-podge as a candidate for being
|
||||||
|
distributed with **cdist** itself, though... :-)
|
||||||
|
especially if it turns out to be something that can be acheieved with
|
||||||
|
reasonable effort in **POSIX shell**.
|
||||||
|
|
||||||
|
In practise, you would at least want to enforce some consistency, if anything for
|
||||||
|
code maintainibility and your own sanity, in addition to the
|
||||||
|
the `CAVEATS`_ mentioned down below.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
Needless to say, just because you *can* do something,
|
||||||
|
doesn't mean you *should* be doing it, or it's even a *good idea* to do so.
|
||||||
|
|
||||||
|
As a general rule of thumb, when extending **cdist**,
|
||||||
|
there are many good reasons in favor of sticking with the **POSIX shell**
|
||||||
|
wherever you can, and very few in favor of opting for some other
|
||||||
|
scripting language.
|
||||||
|
|
||||||
|
This is particularly true for any code that is meant to be run *remotely*
|
||||||
|
on **target hosts** (such as **explorers**),
|
||||||
|
where it is usually important to keep assumptions and requirements/dependencies
|
||||||
|
to a bare minimum. See the `CAVEATS`_ down below.
|
||||||
|
|
||||||
|
That being said, **polyglot** capabilities of **cdist** can come
|
||||||
|
quite handy for when you really need this sort of thing,
|
||||||
|
provided that you are ready to bare the consequences,
|
||||||
|
including the burden of extra dependecies
|
||||||
|
--- which is usually not that hard for code run *locally* on **master**
|
||||||
|
(`manifests`, `gencode-*` scripts, and code generated by `gencode-local`).
|
||||||
|
|
||||||
|
In any case, the mere fact of knowing we *can* escape the POSIX hatch
|
||||||
|
if we really have to, can be quite comforting for those of us suffering
|
||||||
|
from POSIX claustrophobia... which *is* of course a real health hazard
|
||||||
|
associated with high anxiety levels and all,
|
||||||
|
in case you didn't already know... ;-)
|
||||||
|
|
||||||
|
|
||||||
|
Writing polyglot extensions for **cdist**
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Whatever the kind of script (`manifest`, explorer, ...) you are writing,
|
||||||
|
you need to ensure that all 3 conditions below are met:
|
||||||
|
|
||||||
|
1. your script starts with an appropriate **shebang** line, such as::
|
||||||
|
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
.. comment: It would have been nice to make use of an extension
|
||||||
|
(such as `"sphinx_design"`) which provides a `.. dropdown::`
|
||||||
|
directive (for toggling visibility) which is the reason for
|
||||||
|
the ugly `.. raw:: html` stuff below...
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><a>It's usually preferable to rely on the <b>env</b> program...</a></summary>
|
||||||
|
|
||||||
|
.. container::
|
||||||
|
|
||||||
|
It's usually preferable to rely on the :program:`env` program,
|
||||||
|
like in the example above, to find the interpreter by searching the PATH.
|
||||||
|
|
||||||
|
The :program:`env` program is almost guaranteed to exist even on a rudimentary
|
||||||
|
UNIX/Linux system at a pretty stable location: `/usr/bin/env`
|
||||||
|
|
||||||
|
It is, of course, also possible to write down a **hard coded** path
|
||||||
|
for the interpreter, if you are certain that it will always be
|
||||||
|
located at that location, like so::
|
||||||
|
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
This may sometimes be desirable, for example when you want to ascertain
|
||||||
|
using a specific version of an interpreter or when you are unsure about
|
||||||
|
what might get foundthrough the PATH.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
2. your script has "*execute*" permissions set (in the Unix/Linux sense),
|
||||||
|
like so::
|
||||||
|
|
||||||
|
chmod a+x /path/to/your/script
|
||||||
|
|
||||||
|
This is essentially what matters to **cdist**, which it will take as a
|
||||||
|
clue for invoking your script *directly* (instead of passing it
|
||||||
|
to a shell as an argument).
|
||||||
|
|
||||||
|
For **generated code**, `cdist` will automatically take care of setting
|
||||||
|
*execute* permissions for you,
|
||||||
|
based on the presence of a leading **shebang** within the generated code.
|
||||||
|
|
||||||
|
3. the **interpreter** referenced by the **shebang** is available on any host(s)
|
||||||
|
where your code will run.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
<a>
|
||||||
|
Even for the <b>POSIX shell</b>,
|
||||||
|
it is still recommended to <b>follow the same guidelines</b> outlined above.
|
||||||
|
</a>
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Even if you are just writing for the **POSIX shell**,
|
||||||
|
it is still recommended to follow the same guidelines outlined above.
|
||||||
|
|
||||||
|
At the very least, make sure your script has a proper **shebang**.
|
||||||
|
|
||||||
|
- If you have been following the usual **cdist** advise:
|
||||||
|
you probably already have a proper **shebang** at the very beginning
|
||||||
|
of your POSIX shell scripts.
|
||||||
|
|
||||||
|
|
||||||
|
- If (and *only* if), your POSIX shell script *does* contain a proper **shebang**:
|
||||||
|
you are also encouraged to also give it *"execute"* permissions,
|
||||||
|
so that your **shebang** will actually get honored.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
</details>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
|
||||||
|
That's pretty much it... except...
|
||||||
|
|
||||||
|
.. seealso:: The `CAVEATS`_ below.
|
||||||
|
|
||||||
|
|
||||||
|
CAVEATS
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Shebang and execute permissions
|
||||||
|
"""""""""""""""""""""""""""""""""
|
||||||
|
In general, the first two conditions above are trivial to satisfy:
|
||||||
|
Just make sure you put in a **shebang** and mark your script as *executable*.
|
||||||
|
|
||||||
|
|
||||||
|
**Beware**, however, that:
|
||||||
|
|
||||||
|
.. attention::
|
||||||
|
|
||||||
|
- If your script lacks `execute` permissions (regardless of any **shebang**):
|
||||||
|
**cdist** will end up passing your script to `/bin/sh -e`
|
||||||
|
(or to `local_shell` / `remote_shell`,
|
||||||
|
if one is configured for the current context),
|
||||||
|
which may or may not be what you want.
|
||||||
|
|
||||||
|
- If your script *does* have `execute` permissions but *lacks* a **shebang**:
|
||||||
|
you can no longer be sure which interpreter (if any) will end up running your script.
|
||||||
|
|
||||||
|
What is certain, on the other hand, is that there is a wide range of
|
||||||
|
different things that could happen in such a case, depending on the OS and the chain
|
||||||
|
of execution up to that point...
|
||||||
|
|
||||||
|
It is possible (but not certain) that, in such a case, your script may
|
||||||
|
end up getting fed into `/bin/sh` or the default shell
|
||||||
|
(whatever it happens to be for the current user).
|
||||||
|
|
||||||
|
There's even a legend according to which even `csh` may get a chance to feed
|
||||||
|
on your script, and then proceed to burning your barn...
|
||||||
|
|
||||||
|
So, don't do that.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Interpreter availibility
|
||||||
|
"""""""""""""""""""""""""""""""""
|
||||||
|
|
||||||
|
For the last condition (interpreter availability),
|
||||||
|
your mileage may vary for languages other than the **POSIX shell**.
|
||||||
|
|
||||||
|
- For scripts meant to be run *locally* on the **master**, things remain relatively easy :
|
||||||
|
All you may need, if anything,
|
||||||
|
is a one time installation of stuff.
|
||||||
|
|
||||||
|
So, things should be realtively easy when it comes to: :file:`manifest` and :file:`gencode-*` scripts themselves, as well as any code generated by :file:`gencode-local`.
|
||||||
|
|
||||||
|
|
||||||
|
- For scripts meant to be run *remotely* on **target hosts**, things might get quite tricky,
|
||||||
|
depending on how likely it is
|
||||||
|
for the desired **interpreter** to be installed by default
|
||||||
|
on the **target system**.
|
||||||
|
|
||||||
|
This is an important concern for :file:`explorer` scripts
|
||||||
|
and any code generated by :file:`gencode-remote`.
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
Apart from the POSIX shell (`/bin/sh`), there aren't many interpreters out
|
||||||
|
there that are likely to have a guaranteed presence on a pristine system.
|
||||||
|
|
||||||
|
At the very least, you would have to make sure that the required interpreter
|
||||||
|
(and any extra modules/libraries your script might depend on)
|
||||||
|
are indeed available on those host(s)
|
||||||
|
before your script is invoked...
|
||||||
|
which kind of goes against the near-zero-dependency philosphy embraced
|
||||||
|
by **cdist**.
|
||||||
|
|
||||||
|
Depending on the target host OS, you might get lucky with
|
||||||
|
`bash`, `perl`, or `python` being preinstalled.
|
||||||
|
Even then, those may not necessarily be the version you expect
|
||||||
|
or have the extra modules/libraries your script might require.
|
||||||
|
|
||||||
|
**You have been warned.**
|
||||||
|
|
||||||
|
|
||||||
|
More details
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
As mentioned earlier, **cdist** itself mostly cares about the script
|
||||||
|
being marked as an *executable*, which it will take as a clue for invoking
|
||||||
|
that script *directly* (instead of passing it to a shell as an argument).
|
||||||
|
|
||||||
|
The **shebang** magic is handled by the usual process `exec` mechanisms
|
||||||
|
of the host OS (where the script is invoked) that will take over from
|
||||||
|
that point on.
|
||||||
|
|
||||||
|
|
||||||
|
Here is a simplified summary :
|
||||||
|
|
||||||
|
+-------------+---------------+------------------------------+--------------+--------------------------------------------------------+
|
||||||
|
| executable? | shebang | invocation resembles | interpreter | remarks |
|
||||||
|
+=============+===============+==============================+==============+========================================================+
|
||||||
|
| yes | `#!/bin/sh` | `/path/to/script` | `/bin/sh` | shebang **honored** by OS |
|
||||||
|
+-------------+---------------+------------------------------+--------------+--------------------------------------------------------+
|
||||||
|
| yes | `#!/bin/bash` | `/path/to/script` | `/bin/bash` | shebang **honored** by OS |
|
||||||
|
+-------------+---------------+------------------------------+--------------+--------------------------------------------------------+
|
||||||
|
| yes | | `/path/to/script` | *uncertain* | shebang **absent** |
|
||||||
|
+-------------+---------------+------------------------------+--------------+--------------------------------------------------------+
|
||||||
|
| no | `#!/bin/sh` | `/bin/sh -e /path/to/script` | `/bin/sh -e` | shebang **irrelevant** (as script is not "executable") |
|
||||||
|
+-------------+---------------+------------------------------+--------------+--------------------------------------------------------+
|
||||||
|
| no | `#!/bin/bash` | `/bin/sh -e /path/to/script` | `/bin/sh -e` | shebang **irrelevant** (as script is not "executable") |
|
||||||
|
+-------------+---------------+------------------------------+--------------+--------------------------------------------------------+
|
||||||
|
| no | | `/bin/sh -e /path/to/script` | `/bin/sh -e` | shebang **irrelevant** (as script is not "executable") |
|
||||||
|
+-------------+---------------+------------------------------+--------------+--------------------------------------------------------+
|
||||||
|
|
||||||
|
In fact, it's a little bit more involved than the above. Remember:
|
||||||
|
|
||||||
|
- As a special case, for any **generated code** (output by `gencode-*` scripts),
|
||||||
|
**cdist** will solely rely on the presence (or absence) of a leading **shebang**,
|
||||||
|
and set the executable bits accordingly, for obvious reasons.
|
||||||
|
|
||||||
|
- In the end, if a script is NOT marked as "executable",
|
||||||
|
it will simply be passed as an argument to the configured shell
|
||||||
|
that corresponds to the relevant context (i.e. `local_shell` or `remote_shell`),
|
||||||
|
if one is defined within the **cdist** configuration,
|
||||||
|
or else to `/bin/sh -e`, as a fallback in in both cases.
|
||||||
|
|
||||||
|
Well, there are also some gory implementation details
|
||||||
|
(related to how environment variables get propagated),
|
||||||
|
but those should normally have no relevance to this discussion.
|
||||||
|
|
||||||
|
|
||||||
|
The API between **cdist** and any polyglot extensions
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Conceptually, the API, based on well-known UNIX constructs,
|
||||||
|
remains exactly the same as it is for
|
||||||
|
any extension written for the **POSIX shell**.
|
||||||
|
|
||||||
|
Basically, you are all set as long as your scripting language is capable of:
|
||||||
|
|
||||||
|
- accessing **environment variables**;
|
||||||
|
- reading from and writing to the **filesystem** (files, directories, ...);
|
||||||
|
- reading from :file:`STDIN` and writing to :file:`STDOUT` (and eventually to :file:`STDERR`)
|
||||||
|
- **executing** other programs/commands;
|
||||||
|
- **exiting** with an appropriate **status code** (where 0=>success).
|
||||||
|
|
||||||
|
For all we know, no serious scripting language out there
|
||||||
|
would be missing any such basics.
|
||||||
|
|
||||||
|
The actual syntax and mechanisms will obviously be different,
|
||||||
|
the shell idioms usually being much more concise for this sort of thing,
|
||||||
|
as expected.
|
||||||
|
|
||||||
|
See the below example entitled "`Interacting with the cdist API`_".
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Interacting with the cdist API
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
As an API example, here's an excerpt from a **cdist** `type manifest`,
|
||||||
|
written for the POSIX shell, showing how one would get at the name
|
||||||
|
of the kernel on the **target host**:::
|
||||||
|
|
||||||
|
kernel_name=$(cat "${__global}/explorer/kernel_name")
|
||||||
|
|
||||||
|
# ... do something with kernel_name ...
|
||||||
|
|
||||||
|
|
||||||
|
In a nutshell, the above snippet gives the general idea about the cdist API:
|
||||||
|
|
||||||
|
Basically, we are stuffing a shell variable with the contents of a file...
|
||||||
|
which happens to contain the output from the `kernel_name` explorer...
|
||||||
|
|
||||||
|
Before invoking our `manifest` script, **cdist** would have, among other things,
|
||||||
|
run all **global explorers** on the **target host**,
|
||||||
|
collected and copied their outputs under a temporary directory on the **master**, and
|
||||||
|
set a specific environment variable (`$__global`)
|
||||||
|
to the path of a specifc subdirectory of that temporary working area.
|
||||||
|
|
||||||
|
At this point, that file (which contains the kernel name) is sitting there,
|
||||||
|
ready to be slurped... which can obviously be done from any language
|
||||||
|
that can access environment variables and read files from the filesystem...
|
||||||
|
|
||||||
|
Here's how you could do the same thing in **Python**:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
def read_file(path):
|
||||||
|
content = ""
|
||||||
|
try:
|
||||||
|
with open(path, "r") as fd:
|
||||||
|
content = fd.read().rstrip('\n')
|
||||||
|
except EnvironmentError:
|
||||||
|
pass
|
||||||
|
return content
|
||||||
|
|
||||||
|
kernel_name = read_file( os.environ['__global'] + '/explorer/kernel_name' )
|
||||||
|
|
||||||
|
# ... do something with kernel_name ...
|
||||||
|
|
||||||
|
|
||||||
|
And in **Perl**, it could look like:
|
||||||
|
|
||||||
|
.. code-block:: perl
|
||||||
|
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
sub read_file {
|
||||||
|
my ($path) = @_;
|
||||||
|
return unless open( my $fh, $path );
|
||||||
|
local ($/);
|
||||||
|
<$fh>
|
||||||
|
}
|
||||||
|
|
||||||
|
my $kernel_name = read_file("$ENV{__global}/explorer/kernel_name");
|
||||||
|
|
||||||
|
# ... do something with kernel_name ...
|
||||||
|
|
||||||
|
|
||||||
|
Incidently, this example also helps appreciate some aspects of programming
|
||||||
|
for the shell... which were designed for this sort of thing in the first place...
|
||||||
|
|
||||||
|
A polygot type explorer (in Perl)
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Here's an imaginary type explorer written in **Perl**,
|
||||||
|
that ouputs the version of the perl interpreter running on the target host:
|
||||||
|
|
||||||
|
.. code-block:: perl
|
||||||
|
|
||||||
|
#!/usr/bin/env perl
|
||||||
|
|
||||||
|
use English;
|
||||||
|
|
||||||
|
print "${PERL_VERSION}\n";
|
||||||
|
|
||||||
|
If the path to the intended interpreter can be ascertained, you can
|
||||||
|
put that down directly on the **shebang**, like so::
|
||||||
|
|
||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
However, more often than not, you would want to rely
|
||||||
|
on the `env` program (`/usr/bin/env`) to
|
||||||
|
invoke the first interpreter with the given name (`perl`, in this case)
|
||||||
|
found on the current PATH, like in the above example.
|
||||||
|
|
||||||
|
Don't forget to set *execute* permissions on the script file:::
|
||||||
|
|
||||||
|
chmod a+x ...
|
||||||
|
|
||||||
|
Or else **cdist** will feed it to a shell instance...
|
||||||
|
which may burn your barn... :-)
|
|
@ -79,9 +79,9 @@ then this content is printed as a deprecation messages, e.g.:
|
||||||
|
|
||||||
.. code-block:: sh
|
.. code-block:: sh
|
||||||
|
|
||||||
$ ls -l deprecated
|
$ ls -l deprecated
|
||||||
-rw-r--r-- 1 darko darko 71 May 20 18:30 deprecated
|
-rw-r--r-- 1 darko darko 71 May 20 18:30 deprecated
|
||||||
$ cat deprecated
|
$ cat deprecated
|
||||||
This type is deprecated. It will be removed in the next minor release.
|
This type is deprecated. It will be removed in the next minor release.
|
||||||
$ echo '__foo foo' | ./bin/cdist config -i - 185.203.112.26
|
$ echo '__foo foo' | ./bin/cdist config -i - 185.203.112.26
|
||||||
WARNING: 185.203.112.26: Type __foo is deprecated: This type is deprecated. It will be removed in the next minor release.
|
WARNING: 185.203.112.26: Type __foo is deprecated: This type is deprecated. It will be removed in the next minor release.
|
||||||
|
@ -90,7 +90,7 @@ If 'deprecated' marker has no content then general message is printed, e.g.:
|
||||||
|
|
||||||
.. code-block:: sh
|
.. code-block:: sh
|
||||||
|
|
||||||
$ ls -l deprecated
|
$ ls -l deprecated
|
||||||
-rw-r--r-- 1 darko darko 0 May 20 18:36 deprecated
|
-rw-r--r-- 1 darko darko 0 May 20 18:36 deprecated
|
||||||
$ echo '__bar foo' | ./bin/cdist config -i - 185.203.112.26
|
$ echo '__bar foo' | ./bin/cdist config -i - 185.203.112.26
|
||||||
WARNING: 185.203.112.26: Type __bar is deprecated.
|
WARNING: 185.203.112.26: Type __bar is deprecated.
|
||||||
|
@ -98,41 +98,132 @@ If 'deprecated' marker has no content then general message is printed, e.g.:
|
||||||
|
|
||||||
How to write a new type
|
How to write a new type
|
||||||
-----------------------
|
-----------------------
|
||||||
A type consists of
|
|
||||||
|
|
||||||
- parameter (optional)
|
|
||||||
- manifest (optional)
|
|
||||||
- singleton (optional)
|
|
||||||
- explorer (optional)
|
|
||||||
- gencode (optional)
|
|
||||||
- nonparallel (optional)
|
|
||||||
|
|
||||||
Types are stored below cdist/conf/type/. Their name should always be prefixed with
|
Types are stored below cdist/conf/type/. Their name should always be prefixed with
|
||||||
two underscores (__) to prevent collisions with other executables in $PATH.
|
two underscores (__) to prevent collisions with other executables in :code:`$PATH`.
|
||||||
|
|
||||||
To implement a new type, create the directory **cdist/conf/type/__NAME**.
|
To implement a new type, create the directory :file:`cdist/conf/type/{__NAME}`,
|
||||||
|
either manually or using the helper script `cdist-new-type <man1/cdist-new-type.html>`_
|
||||||
|
which will also create the basic skeleton for you.
|
||||||
|
|
||||||
Type manifest and gencode can be written in any language. They just need to be
|
A type consists of the following elements (all of which are currently *optional*):
|
||||||
executable and have a proper shebang. If they are not executable then cdist assumes
|
|
||||||
they are written in shell so they are executed using '/bin/sh -e' or 'CDIST_LOCAL_SHELL'.
|
|
||||||
|
|
||||||
For executable shell code it is suggested that shebang is '#!/bin/sh -e'.
|
* some **markers** in the form of **plain files** within the type's directory:
|
||||||
|
|
||||||
For creating type skeleton you can use helper script
|
.. list-table::
|
||||||
`cdist-new-type <man1/cdist-new-type.html>`_.
|
|
||||||
|
|
||||||
|
* - :file:`singleton`
|
||||||
|
- *(optional)*
|
||||||
|
- A type flagged as a :file:`singleton` may be used **only
|
||||||
|
once per host**, which is useful for types that can be used only once on a
|
||||||
|
system.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
Singleton types do not take an object name as argument.
|
||||||
|
|
||||||
|
* - :file:`nonparallel`
|
||||||
|
- (optional)
|
||||||
|
- Objects of a type flagged as :file:`nonparallel` cannot be run in parallel
|
||||||
|
when using :code:`-j` option.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
|
||||||
|
An example of such a type is :program:`__package_dpkg` type
|
||||||
|
where :program:`dpkg` itself prevents to be run in more than one instance.
|
||||||
|
|
||||||
|
* - :file:`install`
|
||||||
|
- *(optional)*
|
||||||
|
- A type flagged as :file:`install` is used only with :command:`install` command.
|
||||||
|
With other :program:`cdist` commands, i.e. :command:`config`, such types are skipped if used.
|
||||||
|
|
||||||
|
* - :file:`deprecated`
|
||||||
|
- *(optional)*
|
||||||
|
- A type flagged as :file:`deprecated` causes
|
||||||
|
:program:`cdist` to emit a **warning** whenever that type is used.
|
||||||
|
|
||||||
|
.. raw:: html
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
If the file that corresponds to the `deprecated` marker has any content,
|
||||||
|
then this is used as a custom **deprecation message** for the warning.
|
||||||
|
|
||||||
|
* some more **metadata**:
|
||||||
|
|
||||||
|
.. list-table::
|
||||||
|
|
||||||
|
* - :file:`parameter/\*`
|
||||||
|
- *(optional)*
|
||||||
|
- A type may have **parameters**. These must be declared following a simple convention described in `Defining parameters`_, which
|
||||||
|
permits specifying additional properties for each parameter:
|
||||||
|
|
||||||
|
* required or optional
|
||||||
|
* single-value or multi-value
|
||||||
|
* string or boolean
|
||||||
|
|
||||||
|
It is also possible to give a `default` value for each optional parameter.
|
||||||
|
|
||||||
|
* and some **code** (scripts):
|
||||||
|
|
||||||
|
.. list-table::
|
||||||
|
|
||||||
|
* - :file:`manifest`
|
||||||
|
- *(optional)*
|
||||||
|
- :doc:`Type manifest <cdist-manifest>`
|
||||||
|
|
||||||
|
* - :file:`explorer/*`
|
||||||
|
- *(optional)*
|
||||||
|
- Any number of :doc:`type explorer <cdist-explorer>` scripts may exist under :file:`explorer` subdirectory.
|
||||||
|
|
||||||
|
* - :file:`gencode-local`
|
||||||
|
- *(optional)*
|
||||||
|
- A script that generates code to be executed *locally* (on master).
|
||||||
|
|
||||||
|
* - :file:`gencode-remote`
|
||||||
|
- *(optional)*
|
||||||
|
- A script that generates code to be executed *remotely* (on target host).
|
||||||
|
|
||||||
|
|
||||||
|
.. tip::
|
||||||
|
|
||||||
|
Each of the above-mentioned scripts can be written in **any scripting language**,
|
||||||
|
provided that the script is executable and has a proper **shebang**.
|
||||||
|
|
||||||
|
For executable shell code, the recommended shebang is :code:`#!/bin/sh -e`.
|
||||||
|
|
||||||
|
If a script lacks `execute` permissions, :program:`cdist` assumes
|
||||||
|
it to be written in **shell** and executes it using
|
||||||
|
`$CDIST_LOCAL_SHELL` or `$CDIST_REMOTE_SHELL`, if one is defined
|
||||||
|
for the current execution context (*local* or *remote*),
|
||||||
|
or else falling back to :code:`/bin/sh -e`.
|
||||||
|
|
||||||
|
|
||||||
|
For any code susceptible to run on remote target hosts
|
||||||
|
(i.e. **explorers** and any code generated by :code:`gencode-remote`),
|
||||||
|
it is recommended to stick to **POSIX shell**
|
||||||
|
in order to minimize requirements on target hosts where they would need to be executed.
|
||||||
|
|
||||||
|
For more details and examples, see :doc:`cdist-polyglot`.
|
||||||
|
|
||||||
|
.. seealso:: `cdist execution stages <cdist-stages.html>`_
|
||||||
|
|
||||||
Defining parameters
|
Defining parameters
|
||||||
-------------------
|
-------------------
|
||||||
Every type consists of required, optional and boolean parameters, which must
|
Every type consists of required, optional and boolean parameters, which must
|
||||||
each be declared in a newline separated file in **parameter/required**,
|
each be declared in a newline separated file in **parameter/required**,
|
||||||
**parameter/required_multiple**, **parameter/optional**,
|
**parameter/required_multiple**, **parameter/optional**,
|
||||||
**parameter/optional_multiple** and **parameter/boolean**.
|
**parameter/optional_multiple** and **parameter/boolean**.
|
||||||
Parameters which are allowed multiple times should be listed in
|
Parameters which are allowed multiple times should be listed in
|
||||||
required_multiple or optional_multiple respectively. All other parameters
|
required_multiple or optional_multiple respectively. All other parameters
|
||||||
follow the standard unix behaviour "the last given wins".
|
follow the standard unix behaviour "the last given wins".
|
||||||
If either is missing, the type will have no required, no optional, no boolean
|
If either is missing, the type will have no required, no optional, no boolean
|
||||||
or no parameters at all.
|
or no parameters at all.
|
||||||
|
|
||||||
Default values for optional parameters can be predefined in
|
Default values for optional parameters can be predefined in
|
||||||
**parameter/default/<name>**.
|
**parameter/default/<name>**.
|
||||||
|
@ -237,7 +328,7 @@ In the __file type, stdin is used as source for the file, if - is used for sourc
|
||||||
source="$(cat "$__object/parameter/source")"
|
source="$(cat "$__object/parameter/source")"
|
||||||
if [ "$source" = "-" ]; then
|
if [ "$source" = "-" ]; then
|
||||||
source="$__object/stdin"
|
source="$__object/stdin"
|
||||||
fi
|
fi
|
||||||
....
|
....
|
||||||
|
|
||||||
|
|
||||||
|
@ -307,6 +398,7 @@ stdin from */dev/null*:
|
||||||
done < "$__object/parameter/foo"
|
done < "$__object/parameter/foo"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
.. _cdist-type#manifest:
|
||||||
|
|
||||||
Writing the manifest
|
Writing the manifest
|
||||||
--------------------
|
--------------------
|
||||||
|
@ -380,6 +472,7 @@ in your type directory:
|
||||||
|
|
||||||
For example, package types are nonparallel types.
|
For example, package types are nonparallel types.
|
||||||
|
|
||||||
|
.. _cdist-type#explorers:
|
||||||
|
|
||||||
The type explorers
|
The type explorers
|
||||||
------------------
|
------------------
|
||||||
|
@ -402,6 +495,7 @@ client, like this (shortened version from the type __file):
|
||||||
md5sum < "$destination"
|
md5sum < "$destination"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
.. _cdist-type#gencode-scripts:
|
||||||
|
|
||||||
Writing the gencode script
|
Writing the gencode script
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
|
@ -4,44 +4,65 @@ Why should I use cdist?
|
||||||
There are several motivations to use cdist, these
|
There are several motivations to use cdist, these
|
||||||
are probably the most popular ones.
|
are probably the most popular ones.
|
||||||
|
|
||||||
Known language
|
No need to learn a new language
|
||||||
--------------
|
-------------------------------
|
||||||
|
|
||||||
Cdist is being configured in
|
When adopting cdist, your staff does not need to learn a new
|
||||||
`shell script <https://en.wikipedia.org/wiki/Shell_script>`_.
|
|
||||||
Shell script is used by UNIX system engineers for decades.
|
|
||||||
So when cdist is introduced, your staff does not need to learn a new
|
|
||||||
`DSL <https://en.wikipedia.org/wiki/Domain-specific_language>`_
|
`DSL <https://en.wikipedia.org/wiki/Domain-specific_language>`_
|
||||||
or programming language.
|
or programming language, as cdist can be configured
|
||||||
|
and extended in **any scripting language**, the recommended one
|
||||||
|
being `shell scripts <https://en.wikipedia.org/wiki/Shell_script>`_.
|
||||||
|
|
||||||
|
Shell scripts enjoy ubiquity: they have been widely used by UNIX system engineers
|
||||||
|
for decades, and a suitable interpreter (:code:`/bin/sh`) is all but
|
||||||
|
guaranteed to be widely available on target hosts.
|
||||||
|
|
||||||
|
|
||||||
|
Easy idempotance -- without having to give up control
|
||||||
|
-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
For the sake of `idempotence <https://en.wikipedia.org/wiki/Idempotence>`_, many **contemporary SCMs** choose to ditch the power and versatality of general purpose programming languages, and adopt some form of
|
||||||
|
declarative `DSL <https://en.wikipedia.org/wiki/Domain-specific_language>`_ for describing the desired end states on target systems.
|
||||||
|
|
||||||
|
:program:`Cdist` takes a quite different approach, enabling *both* `idempotence <https://en.wikipedia.org/wiki/Idempotence>`_ *and* a decent level of programming power.
|
||||||
|
|
||||||
|
Unlike other SCMs, :program:`cdist` allows you to use a general purpose scripting language (POSIX shell is recommended) for describing the desired end states on target systems, instead of some declarative `DSL <https://en.wikipedia.org/wiki/Domain-specific_language>`_.
|
||||||
|
|
||||||
|
Unlike regular scripting, however, you are not left on your own for ensuring `idempotence <https://en.wikipedia.org/wiki/Idempotence>`_. :program:`Cdist` makes this really easy.
|
||||||
|
|
||||||
|
It does not matter how many times you "invoke" **cdist types** and in which order: :program:`cdist` will ensure that the actual code associated with each type will be executed only once (in dependency order) which, in turn, may effectively end up becoming a no-op, if the actual state is already the same as the desired one.
|
||||||
|
|
||||||
|
.. TODO: It would be great if there were an "architectural overview" page which could be referenced from here.
|
||||||
|
|
||||||
|
|
||||||
Powerful language
|
Powerful language
|
||||||
-----------------
|
--------------------
|
||||||
|
|
||||||
Not only is shell scripting widely known by system engineers,
|
Compared to a typical `DSL <https://en.wikipedia.org/wiki/Domain-specific_language>`_,
|
||||||
but it is also a very powerful language. Here are some features
|
shell scripts feature a much more powerful language.
|
||||||
which make daily work easy:
|
Here are some features which make daily work easy:
|
||||||
|
|
||||||
* Configuration can react dynamically on explored values
|
* Ability to dynamically adapt configuration based on information
|
||||||
|
*explored* from target hosts;
|
||||||
* High level string manipulation (using sed, awk, grep)
|
* High level string manipulation (using sed, awk, grep)
|
||||||
* Conditional support (**if, case**)
|
* Conditional support (**if, case**)
|
||||||
* Loop support (**for, while**)
|
* Loop support (**for, while**)
|
||||||
* Support for dependencies between cdist types
|
* Variable expansion
|
||||||
|
* Support for dependencies between cdist types and objects
|
||||||
|
|
||||||
|
If and when needed, it's always possible to simply
|
||||||
|
make use of **any other scripting language** at your disposal
|
||||||
|
*(albeit at the expense of adding a dependency on the corresponding interpreter
|
||||||
|
and libraries)*.
|
||||||
|
|
||||||
More than shell scripting
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
If you compare regular shell scripting with cdist, there is one major
|
|
||||||
difference: When using cdist types,
|
|
||||||
the results are
|
|
||||||
`idempotent <https://en.wikipedia.org/wiki/Idempotence>`_.
|
|
||||||
In practise that means it does not matter in which order you
|
|
||||||
call cdist types, the result is always the same.
|
|
||||||
|
|
||||||
Zero dependency configuration management
|
Zero dependency configuration management
|
||||||
----------------------------------------
|
-----------------------------------------
|
||||||
|
|
||||||
Cdist requires very little on a target system. Even better,
|
Cdist requires very little on a target system. Even better,
|
||||||
in almost all cases all dependencies are usually fulfilled.
|
in almost all cases all dependencies are usually already
|
||||||
|
fulfilled.
|
||||||
Cdist does not require an agent or high level programming
|
Cdist does not require an agent or high level programming
|
||||||
languages on the target host: it will run on any host that
|
languages on the target host: it will run on any host that
|
||||||
has a **ssh server running** and a POSIX compatible shell
|
has a **ssh server running** and a POSIX compatible shell
|
||||||
|
|
|
@ -30,6 +30,7 @@ It natively supports IPv6 since the first release.
|
||||||
cdist-type
|
cdist-type
|
||||||
cdist-types
|
cdist-types
|
||||||
cdist-explorer
|
cdist-explorer
|
||||||
|
cdist-polyglot
|
||||||
cdist-messaging
|
cdist-messaging
|
||||||
cdist-parallelization
|
cdist-parallelization
|
||||||
cdist-inventory
|
cdist-inventory
|
||||||
|
|
Loading…
Reference in a new issue