This page describes how to create a Design Center sketch from a basic CFEngine agent bundle. In effect the sketch is a wrapper, taking parameters from the Design Center API or the CFEngine Enterprise Mission Portal, and passing them down to the agent bundle.
The bundle we will wrap with a sketch is a simple use of the users
promise type:
```cf3 bundle agent ensure_users(users, group, homedir, shell) { users: “$(users)” -> {“PCI-DSS-2”, “Baseline_developers23”} policy => “present”, home_dir => “$(homedir)/$(users)”, group_primary => $(group), shell => $(shell), handle => “ensure_user_setup”, home_bundle => setup_home_dir($(users), $(homedir)); }
bundle agent setup_home_dir(user, group, homedir) { files: “$(homedir)/$(user)/.” create => “true”; } ```
If you don’t understand what it does, please look at [Tutorials][Tutorials] and the CFEngine [Guide][] to learn more about CFEngine’s policy language, syntax, and operation. We will not worry about the internals except to apply namespaces and testing guards.
The first step is to define the sketch metadata. This is the annoying
administrivia that makes a package system such as Design Center
useful. Simply take an existing sketch.json file such as the one below and modify it:
``` { manifest: { “main.cf”: { description: “main file” }, “README.md”: { documentation: true }, },
metadata:
{
name: "System::Users",
description: "Configure users with parameters",
version: "1.00",
license: "MIT",
tags: [ "cfdc", "users", "enterprise_compatible", "enterprise_3_6" ],
authors: [ "Ted Zlatanov <tzz@lifelogs.com>" ],
depends: { "CFEngine::sketch_template": {}, cfengine: { version: "3.6.0" }, os: [{ "linux": "Linux", "solaris": "Solaris", "aix": "AIX", "windows": "Windows" }] }
},
api:
{
// this is the name of the bundle!
ensure_users:
[
{ type: "bundle_options", name: "Ensure the users exist as specified" },
{ type: "environment", name: "runenv", },
{ type: "metadata", name: "mymetadata", },
{ type: "list", name: "users", validation: "LIST_OF_STRING_NONEMPTY", description: "User names to add (separate by commas)" },
{ type: "string", name: "group", validation: "STRING_NONEMPTY", description: "Primary user group" },
{ type: "string", name: "homedir", default: "/home", validation: "PATH_ABSOLUTE_UNIX_OR_WINDOWS", description: "Location of the user's home directory" },
{ type: "string", name: "shell", default: "/bin/bash", choice: [ "/bin/sh", "/bin/bash", "/bin/csh", "/bin/tcsh", "/bin/zsh" ], description: "User shell" },
],
},
namespace: "cfdc_users",
interface: [ "main.cf" ], } ```
manifestauthors, tags, name, description, etc. metadatabundle_options with the name of the bundle we want to showenvironment and metadata parameters, which carry the “glue” between Design Center and CFEngineusers, group, homedir, and shell parameters with a type, a default if needed, a validation or a choice as needed, and a descriptionnamespace as shown to ensure this bundle won’t conflict with othersinterface to the list of files that have to be included by CFEngine for the sketch to work, normally just main.cfNow main.cf will start with the original bundle, but we’ll modify it.
```cf3 body file control { namespace => “cfdc_users”; }
bundle agent ensure_users(runenv, metadata, users, group, homedir, shell) { #@include “REPO/sketch_template/standard.inc” users: !dc_test:: “$(users)” -> {“PCI-DSS-2”, “Baseline_developers23”} policy => “present”, home_dir => “$(homedir)/$(users)”, group_primary => $(group), shell => $(shell), handle => “ensure_user_setup”, home_bundle => setup_home_dir($(users), $(homedir));
reports: dc_verbose.dc_test:: “$(dcbundle): simulating user = $(users) with group $(group), home dir $(homedir) and shell $(shell)”; dc_verbose.!dc_test:: “$(dcbundle): ensuring user = $(users) with group $(group), home dir $(homedir) and shell $(shell)”; }
bundle agent setup_home_dir(user, group, homedir) { files: “$(homedir)/$(user)/.” create => “true”; } ```
namespace matching sketch.json#@include statement which sets up the Design Center machineryrunenv and metadata parameters (note you don’t use them!)dc_verbose and dc_test which mean “you’re in verbose mode” and “you’re in test mode” respectivelydc_test modeThis part is really too easy. We should make it harder so you have something to complain about!
There are two steps:
/my/repo/sketches/xyz if your sketches will live under /my/repo and the one you made is called xyz). This is just the files from the manifest:
README.md, which you could cut from the manifest or auto-generate, is just a README filemain.cf which you just saw abovesketch.json as shown above/my/repo and install your sketch into /var/cfengine/design-center/sketches (the “live” repository of sketches). Run the following commands:
cp -rp /var/cfengine/share/*Base/sketches/sketch_template /my/repo/sketches/
/var/cfengine/design-center/bin/cf-sketch --make_cfsketches --inputs /my/repo --is=/my/repo/sketches/cfsketches.json
/var/cfengine/design-center/bin/cf-sketch --make_readme --is=/my/repo/sketches/cfsketches.json
/var/cfengine/design-center/bin/cf-sketch --install-all --is=/my/repo/sketches/cfsketches.json --inputs=/var/cfengine/design-center
See [Maintaining your own sketch repository][Maintaining your own sketch repository] for these exact commands to run, with a longer explanation for each one.
That’s all there is to writing a sketch. You should now look at
[sketchify - Write A New Sketch From An Existing Bundle][sketchify - Write A New Sketch From An Existing Bundle]
for a guide to using the sketchify tool. See
[Maintaining your own sketch repository][Maintaining your own sketch repository]
to find out how to create your own sketch repository and install sketches from it.
Your users can then use the sketch you’ve written as described in [Deploy your first Policy][Deploy your first Policy].