JSON and YAML support in CFEngine
Introduction
JSON is a well-known data language. It even has a specification (Seehttp://json.org).
YAML is another well-known data language. It has a longer, much more complex specification (Seehttp://yaml.org).
CFEngine has core support for JSON and YAML. Let's see what it can do.
Problem statement
We'd like to read, access, and merge JSON-sourced data structures:they should be weakly typed, arbitrarily nested, with consistentquoting and syntax.
We'd like to read, access, and merge YAML-sourced data structures justlike JSON-sourced, to keep policy and internals simple.
In addition, we must not break backward compatibility with CFEngine3.5 and older, so we'd like to use the standard CFEngine arraya[b]syntax.
Data containers
A new data type, the data container, was introduced in 3.6.
It's simply calleddata. The documentation with some examples is athttps://cfengine.com/docs/master/reference-promise-types-vars.html#data-container-variables
Reading JSON
There are many ways to read JSON data; here are a few:
readjson(): read from a JSON file, e.g."mydata" data => readjson("/my/file", 100k);parsejson(): read from a JSON string, e.g."mydata" data => parsejson('{ "x": "y" }');data_readstringarray()anddata_readstringarrayidx(): read text data from a file, split it on a delimiter, and make them into structured data.mergedata(): merge data containers, slists, and classic CFEngine arrays, e.g."mydata" data => mergedata(container1, slist2, array3);
mergedata in particular is very powerful. It can convert a slist or a classic CFEngine array to a data container easily:"mydata" data => mergedata(myslist);
Reading YAML
There are two ways to read YAML data:
readyaml(): read from a YAML file, e.g."mydata" data => readyaml("/my/file.yaml", 100k);parseyaml(): read from a YAML string, e.g."mydata" data => parseyaml('- arrayentry1');
Since these functions return data containers, everything aboutJSON-sourced data structures applies to YAML-sourced data structuresas well.
Accessing JSON
To access JSON data, you can use:
- the
nth()function to access an array element, e.g."myx" string => nth(container1, 0); - the
nthfunction to access a map element, e.g."myx" string => nth(container1, "x"); - the
a[b]notation, e.g."myx" string => "$(container1[x])";. You can nest, e.g.a[b][c][0][d]. This only works if the element is something that can be expanded in a string. So a number or a string work. A list of strings or numbers works. A key-value map underxwon't work. - the
getindices()andgetvalues()functions, just like classic CFEngine arrays
A full example
This example can be saved and run. It will load a key-value map wherethe keys are class names and the values are hostname regularexpressions or class names.
- if your host name is
corbor the classescorbare defined, thedevclass will be defined - if your host name is
fleaor the classfleais defined, theprodclass will be defined - if your host name is
aor the classais defined, theqaclass will be defined - if your host name is
linuxor the classlinuxis defined, theprivateclass will be defined
Easy, right?
bodycommoncontrol{bundlesequence=>{"run"};}bundleagentrun{vars:"bykey"data=>parsejson('{"dev":["c","b"],"prod":["flea"],"qa":["a"],"private":["linux"]}');"keys"slist=>getindices("bykey");classes:# define the class from the key name if any of the items under the key match the host name"$(keys)"expression=>regcmp("$(bykey[$(keys)])",$(sys.host));# define the class from the key name if any of the items under the key are a defined class"$(keys)"expression=>classmatch("$(bykey[$(keys)])");reports:"keys =$(keys)";"I am in class$(keys)"if=>$(keys);}So, where's the magic? Well, if you're familiar with classic CFEnginearrays, you will be happy to hear that the exact same syntax workswith them. In other words, data containers don't change how you useCFEngine. You still usegetindices to get the keys, then iteratethrough them and look up values.
Well, you can change
"bykey"data=>parsejson('{"dev":["c","b"],"prod":["flea"],"qa":["a"],"private":["linux"]}');with
"bykey"data=>data_readstringarray(...);and read the same container from a text file. The file should beformatted like this to produce the same data as above:
dev c bprod fleaqa aprivate linuxYou can also use
"bykey"data=>readjson(...);and read the same container from a JSON file.
Summary
Using JSON and YAML from CFEngine is easy and does not change how you use CFEngine. Try it out and see for yourself!
- Overview
- Getting started
- Reference
- Components
- Functions
- accessedbefore
- accumulated
- ago
- and
- basename
- bundlesmatching
- bundlestate
- callstack_callers
- callstack_promisers
- canonify
- canonifyuniquely
- cf_version_after
- cf_version_at
- cf_version_before
- cf_version_between
- cf_version_maximum
- cf_version_minimum
- changedbefore
- classesmatching
- classfiltercsv
- classify
- classmatch
- concat
- countclassesmatching
- countlinesmatching
- data_expand
- data_readstringarray
- data_readstringarrayidx
- data_regextract
- data_sysctlvalues
- datastate
- difference
- dirname
- diskfree
- escape
- eval
- every
- execresult
- execresult_as_data
- expandrange
- file_hash
- fileexists
- filesexist
- filesize
- filestat
- filter
- findfiles
- findfiles_up
- findprocesses
- format
- getclassmetatags
- getenv
- getfields
- getgid
- getindices
- getuid
- getuserinfo
- getusers
- getvalues
- getvariablemetatags
- grep
- groupexists
- hash
- hash_to_int
- hashmatch
- host2ip
- hostinnetgroup
- hostrange
- hostsseen
- hostswithclass
- hubknowledge
- ifelse
- int
- intersection
- ip2host
- iprange
- irange
- isdir
- isexecutable
- isgreaterthan
- isipinsubnet
- islessthan
- islink
- isnewerthan
- isplain
- isreadable
- isvariable
- join
- lastnode
- laterthan
- ldaparray
- ldaplist
- ldapvalue
- length
- lsdir
- makerule
- maparray
- mapdata
- maplist
- max
- mean
- mergedata
- min
- network_connections
- none
- not
- now
- nth
- on
- or
- packagesmatching
- packageupdatesmatching
- parseintarray
- parsejson
- parserealarray
- parsestringarray
- parsestringarrayidx
- parseyaml
- peerleader
- peerleaders
- peers
- processexists
- product
- randomint
- read_module_protocol
- readcsv
- readdata
- readenvfile
- readfile
- readintarray
- readintlist
- readjson
- readrealarray
- readreallist
- readstringarray
- readstringarrayidx
- readstringlist
- readtcp
- readyaml
- regarray
- regcmp
- regex_replace
- regextract
- registryvalue
- regldap
- regline
- reglist
- remoteclassesmatching
- remotescalar
- returnszero
- reverse
- rrange
- selectservers
- shuffle
- some
- sort
- splayclass
- splitstring
- storejson
- strcmp
- strftime
- string
- string_downcase
- string_head
- string_length
- string_mustache
- string_replace
- string_reverse
- string_split
- string_tail
- string_trim
- string_upcase
- sublist
- sum
- sysctlvalue
- translatepath
- type
- unique
- url_get
- usemodule
- userexists
- validdata
- validjson
- variablesmatching
- variablesmatching_as_data
- variance
- version_compare
- Language concepts
- Masterfiles Policy Framework
- promises.cf
- .no-distrib/
- update.cf
- standalone_self_upgrade.cf
- cfe_internal/
- cfe_internal/CFE_cfengine.cf
- cfe_internal/core/
- cfe_internal/core/watchdog
- cfe_internal/core/watchdog/watchdog.cf
- cfe_internal/enterprise/
- cfe_internal/enterprise/federation/
- cfe_internal/enterprise/federation/federation.cf
- cfe_internal/recommendations.cf
- cfe_internal/update/
- cfe_internal/update/cfe_internal_dc_workflow.cf
- cfe_internal/update/cfe_internal_update_from_repository.cf
- cfe_internal/update/lib.cf
- cfe_internal/update/systemd_units.cf
- cfe_internal/update/update_bins.cf
- cfe_internal/update/update_policy.cf
- cfe_internal/update/update_processes.cf
- controls/
- controls/cf_agent.cf
- controls/cf_execd.cf
- controls/cf_hub.cf
- controls/cf_monitord.cf
- controls/cf_runagent.cf
- controls/cf_serverd.cf
- controls/def.cf
- controls/def_inputs.cf
- controls/reports.cf
- controls/update_def.cf
- controls/update_def_inputs.cf
- inventory/
- inventory/any.cf
- inventory/debian.cf
- inventory/freebsd.cf
- inventory/generic.cf
- inventory/linux.cf
- inventory/lsb.cf
- inventory/macos.cf
- inventory/os.cf
- inventory/redhat.cf
- inventory/suse.cf
- inventory/windows.cf
- lib/
- lib/autorun.cf
- lib/bundles.cf
- lib/cfe_internal.cf
- lib/cfe_internal_hub.cf
- lib/cfengine_enterprise_hub_ha.cf
- lib/commands.cf
- lib/common.cf
- lib/databases.cf
- lib/edit_xml.cf
- lib/event.cf
- lib/examples.cf
- lib/feature.cf
- lib/files.cf
- lib/guest_environments.cf
- lib/monitor.cf
- lib/packages.cf
- lib/paths.cf
- lib/processes.cf
- lib/reports.cf
- lib/services.cf
- lib/stdlib.cf
- lib/storage.cf
- lib/testing.cf
- lib/users.cf
- lib/vcs.cf
- modules/
- modules/mustache/
- modules/packages/
- modules/packages/vendored/
- modules/promises/
- modules/promises/cfengine.py
- modules/promises/cfengine.sh
- services/
- services/autorun/
- services/main.cf
- Macros
- Promise types
- Special variables
- All promise and body types
- Release notes
- Web UI
- Settings
- Health
- Hosts
- Alerts and notifications
- Custom actions for alerts
- Enterprise reporting
- Federated reporting
- Measurements app
- Hub administration
- Decommissioning hosts
- Extending Mission Portal
- Extending query builder in Mission Portal
- Adjusting schedules
- Backup and restore
- Configure a custom LDAP port
- Custom LDAPs certificate
- Custom SSL certificate
- Enable plain http
- Lookup license info
- Policy deployment
- Public key distribution
- Re-installing Enterprise hub
- Regenerate self signed SSL certificate
- Reset administrative credentials
- Debugging Mission Portal
- License
- Examples and tutorials
- Example snippets
- General examples
- Administration examples
- Measuring examples
- Software administration examples
- Commands, scripts, and execution examples
- File and directory examples
- File template examples
- Interacting with directory services
- Database examples
- Network examples
- System security examples
- System information examples
- System administration examples
- System file examples
- Windows registry examples
- File permissions
- User management examples
- Common promise patterns
- Aborting execution
- Change detection
- Check filesystem space
- Copy single files
- Create files and directories
- Customize message of the day
- Distribute ssh keys
- Ensure a process is not running
- Ensure a service is enabled and running
- Find the MAC address
- Install packages
- Mount NFS filesystem
- Restart a process
- Set up name resolution with DNS
- Set up sudo
- Set up time management through NTP
- Updating from a central policy server
- Tutorials
- JSON and YAML support in CFEngine
- Installing CFEngine Enterprise agent
- Managing local users
- Managing network time protocol
- Managing processes and services
- Package management
- Writing CFEngine policy
- Distributing files from a central location
- File editing
- Reporting and remediation of security vulnerabilities
- Masterfiles Policy Framework upgrade
- Tags for variables, classes, and bundles
- Custom inventory
- Dashboard alerts
- Integrating alerts with PagerDuty
- Integrating alerts with ticketing systems
- Integrating with Sumo Logic
- Rendering files with Mustache templates
- Reporting
- File comparison
- High availability
- Writing and serving policy
- Example snippets
- Resources
- FAQ
- Why knowledge management?
- Requesting a CFEngine Enterprise License
- Uninstalling / reinstalling
- Agent output email
- Debugging slow queries
- Enterprise Report Filtering
- Enterprise report collection
- Enterprise reporting database
- How can I tell what classes and variables are defined?
- How do I find the public key for a given host
- How do I fix trust after an IP change?
- How do I fix undefined body errors?
- How do I integrate custom policy?
- How do I pass a data type variable?
- Manual execution
- Mustache templating
- Unable to log into Mission Portal
- Users
- What is promise locking?
- Why are remote agents not updating?
- Why are some files inside masterfiles not being updated/distributed?
- Why does CFEngine install into /var/cfengine instead of following the FHS?
- Bootstrapping
- Tuning PostgreSQL
- What did CFEngine do?
- External resources
- Additional topics
- Best practices
- FAQ
- API
- Enterprise API examples
- Enterprise API reference
- Actions API
- Build API
- CMDB API
- Changes REST API
- Federated reporting configuration API
- File changes API
- Health diagnostic API
- Host REST API
- Import & export API
- Import & export compliance report API
- Inventory API
- LDAP authentication API
- Personal groups API
- Query REST API
- SQL schema
- SSH keys API
- Shared groups API
- Status and settings REST API
- Two-factor authentication API
- Users and access-control REST API
- VCS settings API
- Web RBAC API