CFengine 3.12 new features 'missing_ok' and multiple 'augments'
At SURFsara we use CFEngine on our National Compute Cluster (LISA) and other systems as our configuration management tool. With the release of CFEngine 3.12 I want to highlight 2 new features, namely:
We use these 2 new features heavily in our framework in combination with my open source library
cf_surfsara_lib. This library aims to be a central repository for configuring services, eg: ssh. For configuring the services we use JSON as data format and it is easily to override the default values via JSON. Pre CFEngine 3.12 there is only one strategy possible:
{
"augments": [
"$(sys.inputdir)/json.d/global.json",
"$(sys.inputdir)/json.d/os.json",
"$(sys.inputdir)/json.d/key.json",
"$(sys.inputdir)/json.d/ip.json"
]
}
We only have these definitions in our def.json so we can easily create a local JSON file with local paths for testing and running automatic checks. Another issue is that all the JSON files must be present else an error is reported. This issue has been reported:
Due to this restriction we must have a default JSON file for all defined JSON files in def.json. In our cluster we have defined roles for this we use the CFEngine key, eg: all compute nodes in our cluster share the same CFEngine key. That is the reason why key.json is not the last JSON file being used in our def.json. For copying the JSON files we use variables that are set by CFEngine, namely:
We do not care if the os.json, key.json or ip.json files are present on the policy server. For this I wrote a patch and introduced the missing_ok feature. When this is set then CFEngine will consider the promise kept even if the file is missing. This is how we use this two new features in CFengine at SURFsara. Below I will share the update.conf and cfserverd.conf code. It would be nice for the feature if we can specify another JSON merge option then override. The discussion for other merge options is in ticket:
Another feature that I have proposed is CFE-2790: autoloading JSON file(s). With this feature I can just drop JSON file(s) in a directory and it will be load just like the autorun bundle feature.
{
methods:
any::
"" usebundle => update_json_file("global.json", "global_def_json", "global_def_json");
"" usebundle => update_json_file("os.json", "$(sys.flavor)_def_json", "default_os_def_json");
"" usebundle => update_json_file("key.json", "key_def_json", "default_key_def_json");
"" usebundle => update_json_file("ip.json", "ip_def_json", "default_ip_def_json");
}
bundle agent update_json_file(file, shortcut, failback_shortcut)
{
vars:
"json_file" string => "$(update_init.json_dir)/$(file)";
files:
any::
"$(json_file)"
comment => "def json file copy for $(shortcut), missing_ok: true",
copy_from => update_def_json("$(shortcut)", "true"),
perms => update_perms("600"),
move_obstructions => "true",
action => update_immediate;
"$(json_file)"
comment => "default def json file copy for $(failback_shortcut), missing_ok: false",
copy_from => update_def_json("$(failback_shortcut)", "false"),
perms => update_perms("600"),
move_obstructions => "true",
action => update_immediate,
classes => update_results("$(failback_shortcut)");
reports:
any::
"$(this.bundle): Failed to fetch: $(json_file)"
ifvarclass => or( canonify("$(failback_shortcut)_failed") );
}
body copy_from update_def_json(from, missing)
{
source => "$(from)";
compare => "hash";
copy_backup => "false";
missing_ok => "$(missing)";
protocol_version => "2";
servers => { @(update_init.servers) };
}
{
### Global.json
"/data/cfengine3/cmdb/global.json"
comment => "def.json for all hosts",
shortcut => "global_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
### Key def.json
"/data/cfengine3/cmdb/key/$(connection.key).json"
comment => "host key def.json",
shortcut => "key_def_json",
admit_keys => { "$(connection.key)" };
"/data/cfengine3/cmdb/key/default.json"
comment => "default host key def.json, failback",
shortcut => "default_key_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
### End Key def.json
### IP def.json
"/data/cfengine3/cmdb/ip/$(connection.ip).json"
comment => "host ip def.json",
shortcut => "ip_def_json",
admit_ips => { "$(connection.ip)" };
"/data/cfengine3/cmdb/ip/default.json"
comment => "default host ip def.json, failback",
shortcut => "default_ip_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
### End IP def.json
### OS def.json
"/data/cfengine3/cmdb/os/debian_9.json"
comment => "debian stretch def.json",
shortcut => "debian_9_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
"/data/cfengine3/cmdb/os/debian_8.json"
comment => "debian jessie def.json",
shortcut => "debian_9_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
"/data/cfengine3/cmdb/os/debian_7.json"
comment => "debian jessie def.json",
shortcut => "debian_9_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
"/data/cfengine3/cmdb/os/centos_6.json"
comment => "centos 6 def.json",
shortcut => "centos_6_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
"/data/cfengine3/cmdb/os/default.json"
comment => "default host os def.json, failback",
shortcut => "default_os_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
### End OS def.json
}
We use these 2 new features heavily in our framework in combination with my open source library
cf_surfsara_lib. This library aims to be a central repository for configuring services, eg: ssh. For configuring the services we use JSON as data format and it is easily to override the default values via JSON. Pre CFEngine 3.12 there is only one strategy possible:
- def.json : Setting the initial value
- def.cf : Override the initial value
{
"augments": [
"$(sys.inputdir)/json.d/global.json",
"$(sys.inputdir)/json.d/os.json",
"$(sys.inputdir)/json.d/key.json",
"$(sys.inputdir)/json.d/ip.json"
]
}
We only have these definitions in our def.json so we can easily create a local JSON file with local paths for testing and running automatic checks. Another issue is that all the JSON files must be present else an error is reported. This issue has been reported:
Due to this restriction we must have a default JSON file for all defined JSON files in def.json. In our cluster we have defined roles for this we use the CFEngine key, eg: all compute nodes in our cluster share the same CFEngine key. That is the reason why key.json is not the last JSON file being used in our def.json. For copying the JSON files we use variables that are set by CFEngine, namely:
- os.json is copied via the CFEngine variable: sys.flavor
- key.json is copied via the CFEngine variable: connecton.id
- ip.json : is copied via the CFEngine variable: connection.ip
We do not care if the os.json, key.json or ip.json files are present on the policy server. For this I wrote a patch and introduced the missing_ok feature. When this is set then CFEngine will consider the promise kept even if the file is missing. This is how we use this two new features in CFengine at SURFsara. Below I will share the update.conf and cfserverd.conf code. It would be nice for the feature if we can specify another JSON merge option then override. The discussion for other merge options is in ticket:
Another feature that I have proposed is CFE-2790: autoloading JSON file(s). With this feature I can just drop JSON file(s) in a directory and it will be load just like the autorun bundle feature.
UPDATE def.json setup
bundlle agent update_def_json(){
methods:
any::
"" usebundle => update_json_file("global.json", "global_def_json", "global_def_json");
"" usebundle => update_json_file("os.json", "$(sys.flavor)_def_json", "default_os_def_json");
"" usebundle => update_json_file("key.json", "key_def_json", "default_key_def_json");
"" usebundle => update_json_file("ip.json", "ip_def_json", "default_ip_def_json");
}
bundle agent update_json_file(file, shortcut, failback_shortcut)
{
vars:
"json_file" string => "$(update_init.json_dir)/$(file)";
files:
any::
"$(json_file)"
comment => "def json file copy for $(shortcut), missing_ok: true",
copy_from => update_def_json("$(shortcut)", "true"),
perms => update_perms("600"),
move_obstructions => "true",
action => update_immediate;
"$(json_file)"
comment => "default def json file copy for $(failback_shortcut), missing_ok: false",
copy_from => update_def_json("$(failback_shortcut)", "false"),
perms => update_perms("600"),
move_obstructions => "true",
action => update_immediate,
classes => update_results("$(failback_shortcut)");
reports:
any::
"$(this.bundle): Failed to fetch: $(json_file)"
ifvarclass => or( canonify("$(failback_shortcut)_failed") );
}
body copy_from update_def_json(from, missing)
{
source => "$(from)";
compare => "hash";
copy_backup => "false";
missing_ok => "$(missing)";
protocol_version => "2";
servers => { @(update_init.servers) };
}
CFSERVERD def.json setup
bundle server access_rules(){
### Global.json
"/data/cfengine3/cmdb/global.json"
comment => "def.json for all hosts",
shortcut => "global_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
### Key def.json
"/data/cfengine3/cmdb/key/$(connection.key).json"
comment => "host key def.json",
shortcut => "key_def_json",
admit_keys => { "$(connection.key)" };
"/data/cfengine3/cmdb/key/default.json"
comment => "default host key def.json, failback",
shortcut => "default_key_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
### End Key def.json
### IP def.json
"/data/cfengine3/cmdb/ip/$(connection.ip).json"
comment => "host ip def.json",
shortcut => "ip_def_json",
admit_ips => { "$(connection.ip)" };
"/data/cfengine3/cmdb/ip/default.json"
comment => "default host ip def.json, failback",
shortcut => "default_ip_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
### End IP def.json
### OS def.json
"/data/cfengine3/cmdb/os/debian_9.json"
comment => "debian stretch def.json",
shortcut => "debian_9_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
"/data/cfengine3/cmdb/os/debian_8.json"
comment => "debian jessie def.json",
shortcut => "debian_9_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
"/data/cfengine3/cmdb/os/debian_7.json"
comment => "debian jessie def.json",
shortcut => "debian_9_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
"/data/cfengine3/cmdb/os/centos_6.json"
comment => "centos 6 def.json",
shortcut => "centos_6_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
"/data/cfengine3/cmdb/os/default.json"
comment => "default host os def.json, failback",
shortcut => "default_os_def_json",
admit_ips => { "@(g.acl_admit_ips)" };
### End OS def.json
}
Comments
Post a Comment