How to create a cdist type

Instructions for creating your own type

Posted on Aug. 22, 2017

How to create a cdist type

An article by Dominique, our head of technology.


A small overview of cdist you can find in our article about basic cdist usage and in other previous cdist blog posts:
cdist types and parameters
The object ID and singleton types
The gencode scripts
The local files

Or check the man pages.

What are cdist types

cdist types are used to to define a specific state of a machine.
For example if you want to create a directory /var/mydocs with the user tester and the permissions 0640. 
In cdist you write your manifest like this: 

__directory /var/mydocs --owner tester --mode 0640

Now the __directory cdist type is responsible to check every time cdist runs the directory /var/mydocs is there (if not create it), tester is the owner (if not change it) and the permissions are set to 0640 (if not set them).

Also cdist types can contain other cdist types, this is important for not bloating a manifest for example.

There are cdist standard types which you get along with cdist (located in <installation_dir>/cdist/conf/type/) 
More you can find on github.

The standard types give you the ability to define your desired state since you can (re)use them in your own cdist types.

Creating your own type

As you know you create your own type under $HOME/.cdist/type/
For creating your own type, you create a new directory below that directory

mkdir $HOME/.cdist/type/__my_test_type

Important: The naming convention is important, all types start with a double underscore __

And now we will create a simple type which will create a directory and then copy a file in this new created folder. 
The new type should be capable of

  • Accept parameters (absolute path of the directory)
  • Being able to copy a specific file from your local computer

Taking parameters

More detailed info you find in the blog article dedicated to parameters.

Here just a short version:

Using parameters for your type is very simple in cdist, you just have to create a directory in your type folder:

mkdir $HOME/.cdist/type/__my_test_type/parameter

And in this new directory you create the file optional with the text "directory" 

echo "directory" > $HOME/.cdist/type/__my_test_type/parameter/optional

We create the file optional because the design behind cdist types is, that when you create a type which could be used multiple times (per run) you have to set an object id. With the object id cdist is able to separate the different type calls. So most of the time the target directory will be set in the object id and only if the user wants to set the folder separately take the parameter --directory.

Local files

More detailed info you find in the blog article dedicated to local files.

Here just a short version:

Cdist types are able to use local files or even directories. This is practical since you probably want to distribute ssh public keys. 
For using your type with this purpose do the following:

Create a new directory in your type folder 

mkdir $HOME/.cdist/type/__my_test_type/files/

Now you can create your test file

echo "Test went successfully through" > $HOME/.cdist/type/__my_test_type/files/testing

Creating the manifest

Now it is time to create the manifest. The manifest is likely the manifest you heard of last time. So your type is able to use other types and so on. 
First we need to take care of the parameters, create the $HOME/.cdist/type/__my_test_type/manifest file and fill it up with the following content:

target_dir="$(cat "$__object/parameter/folder" 2>/dev/null || echo "$__object_id")"

You see cdist will put the parameters in files which you can simply print out.

Now we will create this target_dir (add these lines to your manifest)

__directory ${target_dir}

Next we will copy the local file to our newly created directory (add these lines to your manifest)

require="__directory/$target_dir" __file ${target_dir}/testing --source "$__type/files/testing"

Keep in mind: The permissions of the file get lost. You can set them with parameters from the _file type (See the man page of __file for all parameters) 
The require option is needed because for copying the file to the target directory we must ensure that the target directory gets created first. cdist doesn't take the first command in a manifest first and the second as second and so on, this is why we use require=""
In the require we refer to the type and the object_id (Here the object id appears), so as in the example we take __directory as the type and $target_dir as the object id for the __directory type. 
You can require more than just one type, you can simply attach them at the end: 

require="__directory/$target_dir __file/first_file" ...

Now your manifest should look like this:

target_dir="$(cat "$__object/parameter/folder" 2>/dev/null || echo "$__object_id")" 

__directory ${target_dir} 

require="__directory/$target_dir" __file ${target_dir}/testing --source "$__type/files/testing"

And that's it! Now you can add your type in your main manifest and run them.

Or run only this type:

echo "__my_test_type /tmp/testing" | cdist config -vvvi - <Server_Name>

The -i - parameter means that the manifest will be provided over standard input.

Create the main manifest and run cdist

We already did this in the last blog post, so here simply the command:

echo "__my_test_type /tmp/testing" > $HOME/.cdist/manifest/init

Now run cdist:

cdist config -v localhost

Additional information

The best way to learn cdist is to practice: Try to create you own types which do stuff for you (automatically) and copy from already created and published types. You will see how others managed cdist to do the things they want.

If you have trouble or want more information visit our github page, write us a email or chat directly with us in the cdist channel.