Templates
Overview​
Templates are a powerful way to create re-useable body templates with the ability to randomize your data. All commands which send a request body to Cumulocity support using a template.
The template combines with the existing command arguments to build the request's body which is sent to Cumulocity.
Background​
Creating data via the command line can be time consuming especially if there are are lot of required input parameters. To make things easier, the c8y cli tool supports data templates when creating or updating Cumulocity objects (i.e. measurements, managed objects, events, alarms etc.). The data templates allow the user to specify a file containing the template instead of having to provide all of the inputs manually on the command line.
The data templates are implemented using the data template language jsonnet
(pronounced "jay sonnet"). This is an unofficial Google product which can be used to create json structures in a simple yet powerful way. jsonnet
looks a lot like json however it is not so strict with the syntax, and you can also use variables, expressions, functions, inside a template. All of these features give the user a lot of flexibility to be able to create custom data structures quickly and efficiently.
Data templates are supported for all commands which create new data or edit existing data in Cumulocity.
Please read the examples to understand the usage of such templates, and checkout the jsonnet documentation for more about the language and a live editor to experiment with its features.
Example: Creating a measurement​
Let's assume that you are building a weather monitoring application and you want to simulate some measurements in Cumulocity. You want to create a measurement which has two different series.
c8y_Weather.temperature
c8y_Weather.barometricPressure
You can create a jsonnet template file with the following contents.
{
c8y_Weather: {
// simulate temperature in Brisbane, Australia: 15 - 35 °C
temperature: {
value: _.Int(35,15),
unit: "°C",
},
// simulate barometric pressure: 980.0 - 1030.0 hPa with a precision of 1 decimal place
barometricPressure: {
value: _.Float(1030, 980, 1),
unit: "hPa",
},
},
}
The template can then be used from the command line using the template
parameter.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y measurements create --device 1234 --template ./example.jsonnet --dry
c8y measurements create --device 1234 --template ./example.jsonnet --dry
New-Measurement -Device 1234 -Template ./example.jsonnet -Dry
{
"c8y_Weather": {
"barometricPressure": {
"unit": "hPa",
"value": 1018.7
},
"temperature": {
"unit": "°C",
"value": 34
}
},
"source": {
"id": "1234"
},
"time": "2021-05-09T09:46:42.8280961Z",
"type": "iot_weather_sensor1"
}
The template will be used as the base for constructing the body, then the additional parameters, like device will be added to it. This keeps your template free of hard coding any device ids.
The template should mostly look familiar to you as jsonnet uses a json-like structure. However jsonnet
extends json by adding some of the following features:
- Allowing comments (using
//
) - Trailing commas
- Strings can be defined using single or double quotes
- Arithmetic, functions, local variables can be used
The example also uses some internally defined functions which are provided by go-c8y-ci, for example, _.Int()
and _.Float()
. These functions are not provided by default by jsonnet but are injected by go-c8y-cli into each template when it is being evaluated.
Example: Template string to update a list of devices​
Templates don't have to be stored in a file, you can also provide it as a string. This makes it possible to utilize some of the template functions quickly to update
The following adds a fragment to a list of devices (via pipeline) and adds the timestamp when the fragment was applied using the _.Now()
helper function.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y devices list |
c8y devices update \
--template "{c8y_ScriptResult: {status: 'OK', lastUpdated: _.Now()}}" \
--select "id,name,c8y_ScriptResult" \
--output json -c
c8y devices list |
c8y devices update `
--template "{c8y_ScriptResult: {status: 'OK', lastUpdated: _.Now()}}" `
--select "id,name,c8y_ScriptResult" `
--output json -c
New-DeviceCollection |
Update-Device `
-Template "{c8y_ScriptResult: {status: 'OK', lastUpdated: _.Now()}}" `
-Select "id,name,c8y_ScriptResult" `
-Output json -c
{"c8y_ScriptResult":{"lastUpdated":"2021-05-09T11:04:05.650Z","status":"OK"},"id":"503627","name":"demo_001"}
{"c8y_ScriptResult":{"lastUpdated":"2021-05-09T11:04:05.652Z","status":"OK"},"id":"503533","name":"demo_002"}
{"c8y_ScriptResult":{"lastUpdated":"2021-05-09T11:04:05.750Z","status":"OK"},"id":"503624","name":"demo_003"}
{"c8y_ScriptResult":{"lastUpdated":"2021-05-09T11:04:05.785Z","status":"OK"},"id":"503625","name":"demo_004"}
{"c8y_ScriptResult":{"lastUpdated":"2021-05-09T11:04:05.818Z","status":"OK"},"id":"503626","name":"demo_005"}
Template Variables​
Variables can also be injected into your template at runtime. These variables can then be referenced from inside your jsonnet template.
For example if we want to generate a device managed object from a template, however you would like to change the type at runtime (via the command line).
Firstly when creating your jsonnet template, you can reference a template variable using the var(name, [default])
function, where it accepts the name of the template variable and an optional default value (in case the variable is not provided by the user)
The following is an example of such a template:
{
name: "my device",
type: var("type", "defaultType"),
[var("fragment", "c8y_Default")]: {},
c8y_IsDevice: {},
}
The template can then be used when creating a managed object, and the type
and fragment
variables can be injected by using the templateVars
parameter.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y inventory create \
--template "./examples/templates/device.jsonnet" \
--templateVars "type=macOS,fragment=customer_Agent" \
--dry
c8y inventory create `
--template "./examples/templates/device.jsonnet" `
--templateVars "type=macOS,fragment=customer_Agent" `
--dry
New-ManagedObject `
-Template "./examples/templates/device.jsonnet" `
-TemplateVars "type=macOS,fragment=customer_Agent" `
-Dry
{
"name": "my device",
"type": "macOS",
"customer_Agent": {},
"c8y_IsDevice": {}
}
When using c8y
directly, --templateVars
can be used multiple times in the same command. This provides a better tab completion experience for the template variable names.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y inventory create \
--template "./examples/templates/device.jsonnet" \
--templateVars "type=macOS" \
--templateVars "fragment=customer_Agent" \
--dry
c8y inventory create `
--template "./examples/templates/device.jsonnet" `
--templateVars "type=macOS" `
--templateVars "fragment=customer_Agent" `
--dry
New-ManagedObject `
-Template "./examples/templates/device.jsonnet" `
-TemplateVars "type=macOS" `
-TemplateVars "fragment=customer_Agent" `
-Dry
Template Functions (added by go-c8y-cli)​
Below lists the additional functions which are available in jsonnet template files. These functions are added to your template automatically by the c8y cli tool itself, and are not part of the standard jsonnet library. The built-in jsonnet standard library provides additional functions that can be used in combination with those injected by go-c8y-cli.
Function | Description | Example |
---|---|---|
var(name, [defaultValue]) | Reference a template variable from the templateVars cli parameter | value of variable |
_.GetURLPath(url) | Get the URL path from a string | /test?pageSize=1 |
_.GetURLHost(url) | Get the hostname from a string | https://example.com |
_.Int([max=100],[min=0]) | Random integer (int64) between min and (max - 1) inclusive | 42 |
_.Bool() | Generate a random boolean value | true |
_.Float([max=100],[min=0]) | Random float between min and max (inclusive) | 42.0 |
_.Now([offset='0s']) | Generate ISO8601 date (with millisecond resolution) from a relative date or date string | 2021-05-09T07:48:43.949Z |
_.NowNano([offset='0s']) | Generate ISO8601 date (with nanosecond resolution) from a relative date or date string | 2021-05-09T07:48:33.0030745Z |
_.Name([prefix=''],[postfix='']) | Generate a random name with an optional prefix and postfix | GfheJoa;Ktx,F56s |
_.Password([length=32]) | Generate a randomized password of a specified length | NlXYngK;bj!xeOvhpydJ4VIG6HuDcLBR |
_.Hex([length=16]) | Random Hexadecimal string of a given length. | 8b7e0736a5a6ed80 |
_.Char([length=16]) | Random string with only character a-zA-Z of a given length | exxUQqCDFwRHpUog |
_.Digit([length=16]) | Random 0 padded string with only digits | 0261177197719716 |
_.AlphaNumeric([length=16]) | Random AlphaNumeric string of a given length | f087oAAzjnvzkPdf |
_.StripKeys([object]) | Strip protected Cumulocity properties from a object. The following properties are removed from the given object: additionParents, assetParents, childAdditions, childAssets, childDevices, deviceParents, creationTime, lastUpdated, self | {} |
_.Get(object, key, default=null) | Get a property value using dot notation. Use a default value if it does not exist | - |
_.Has(object, key) | Check if a key exists in an object. Accept dot notation as the key | - |
_.Select(object, keys=['*']) | Select specific keys from a given object. It behaves the same as the --select flag. keys can also be provided as a csv string | See examples |
_.SelectMerge(a={}, b={}) | Merge b into a, but only include the fields which are present in b | See examples |
_.Date(now="now", offset="0s", format="", utc=false) | Generic date function to either format or add a relative duration to a timestamp. | See examples |
_.Duration(dateA='now', dateB='now', unit='object') | Get the duration (difference) between two timestamps. The duration is calculated by duration = dateA - dateB | See examples |
Example: Generating random data​
Below is an example jsonnet template making use of the above functions provided by go-c8y-cli.
{
boolean: {
Bool: _.Bool(),
},
numbers: {
Float: _.Float(1, 0.5),
Int: _.Int(50, -50),
},
dateString: {
Now: _.Now('-5m'),
NowNano: _.NowNano('-10d'),
},
url: {
GetURLPath: _.GetURLPath('https://example.com/test?pageSize=1'),
GetURLHost: _.GetURLHost('https://example.com/test?pageSize=1'),
},
strings: {
Name: _.Name('device_', '_example'),
Password: _.Password(32),
Char: _.Char(16),
Digit: _.Digit(10),
Hex: _.Hex(24),
AlphaNumeric: _.AlphaNumeric(20),
}
}
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y template execute --template "./template.jsonnet"
c8y template execute --template "./template.jsonnet"
Invoke-Template -Template "./template.jsonnet"
{
"boolean": {
"Bool": true
},
"dateString": {
"Now": "2021-05-09T08:01:22.505Z",
"NowNano": "2021-04-29T08:06:22.5057679Z"
},
"numbers": {
"Float": 0.8675182149724747,
"Int": 29
},
"strings": {
"AlphaNumeric": "dm7J1CxhnH1KC8grDLnu",
"Char": "ZsPIfwRTFtGafuMI",
"Digit": "3496063026",
"Hex": "ffc9ceb63ac73a463dd5d202",
"Name": "device_q4b9L)p+WjMhJGsm_example",
"Password": "u_ZsojR5ekPYh8WyvldDBNFincVOzUC["
},
"url": {
"GetURLHost": "https://example.com",
"GetURLPath": "/test?pageSize=1"
}
}
jsonnet has its own standard library which provides useful functions like uppercase, lowercase etc. For more information about jsonnet and its additional functions please checkout the following links:
Referencing piped input in a template​
go-c8y-cli supports chaining multiple commands, the template
function supports referencing the current pipeline item via a special variables injected into the template engine by go-c8y-cli before the template is evaluated.
Variable | Description |
---|---|
input.index | Pipeline iterator index (starting from 1) |
input.value | Current pipeline item |
Example: Referencing line delimited input in a template​
If the piped input is not json, then the current line being processed will be available from the input.value
variable in the template.
Each line is processed through the template separately. The following shows piping 3 lines being piped to the generic c8y template execute
command and referencing the input in the template string to show how the values are mapped
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
echo -e "one\ntwo\nthree" |
c8y template execute \
--template "{ index: input.index, value: input.value, input:: '' }" \
--output json -c
"one", "two", "three" |
c8y template execute `
--template "{ index: input.index, value: input.value, input:: '' }" `
--output json -c
"one", "two", "three" |
Invoke-Template `
-Template "{ index: input.index, value: input.value, input:: '' }" `
-Output json -Compact
{"index":1,"value":"one"}
{"index":2,"value":"two"}
{"index":3,"value":"three"}
c8y template execute
automatically maps the piped input to the input
property of the body. The above example is hiding this property by using the jsonnet syntax prop::
which causes this property to be excluded in the output.
Example: Referencing piped json in a template​
When piping json lines to a command, the current json line row can be referenced from the input.value
variable. Since json lines is being piped, this variable represents the complect json line object, and nested properties can be accessed directly from it, i.e. input.value.type
, however an jsonnet will throw an exception if the property does not exist.
For example take the following json line file. Each line represents a full json object (it is not an array!)
{"type": "linux_agent", "ramSize": "38MB"}
{"type": "macOS_agent", "ramSize": "40MB"}
{"type": "windows_agent", "ramSize": "50MB"}
The contents of the file can be piped to any command, in this case we are using command to create a new managed object from the piped input. The template reshapes the input value to custom fragments.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
cat input.json |
c8y inventory create \
--template "{ type: input.value.type, agentProperties: { ram: input.value.ramSize } }" \
--select id,type,agentProperties \
--output json
cat input.json |
c8y inventory create `
--template "{ type: input.value.type, agentProperties: { ram: input.value.ramSize } }" `
--select id,type,agentProperties `
--output json
Get-Content input.json |
New-ManagedObject `
-Template "{ type: input.value.type, agentProperties: { ram: input.value.ramSize } }" `
-Select id,type,agentProperties `
-Output json
{
"agentProperties": {
"ram": "38MB"
},
"id": "520078",
"type": "linux_agent"
}
{
"agentProperties": {
"ram": "40MB"
},
"id": "519798",
"type": "macOS_agent"
}
{
"agentProperties": {
"ram": "50MB"
},
"id": "520121",
"type": "windows_agent"
}
Example: Select a subset of fragments from an input object​
The _.Select()
function provides the same functionality as the global --select
flag.
To demonstrate this, image you have the following managed object.
{
"id": "1234",
"name": "MyDevice",
"other": {
"nestedValue": 1
},
"c8y_IsDevice": {},
"c8y_SupportedOperations": [
"c8y_Restart"
]
}
We can select fragments from the piped input (by referencing input.value
). Below shows that only the id
, name
and other.*
fragments are selected.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y devices get --id 1234 |
c8y devices update --template "_.Select(input.value, 'id,name,other.*')" --dry
c8y devices get --id 1234 |
c8y devices update --template "_.Select(input.value, 'id,name,other.*')" --dry
Get-Device -Id 1234 |
Update-Device -Template "_.Select(input.value, 'id,name,other.*')" -Dry
{
"id": "1234",
"name": "MyDevice",
"other": {
"nestedValue": 1
}
}
Example: Merging device managed object fragments​
Update a nested fragment is normally difficult as it involves retrieving the existing values, altering the existing values, then only sending the updated fragment to Cumulocity.
This is made easier if you combine the piped data and using the _.SelectMerge()
function.
This examples shows how the c8y_SupportedOperations
fragment can be extended to support a new type.
Here is the device managed object before the merge.
{
"id": "1234",
"c8y_IsDevice": {},
"c8y_SupportedOperations": [
"c8y_Restart"
]
}
The following command will add c8y_Command
to the list of supported operations.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y devices get --id 1234 |
c8y devices update --template "_.SelectMerge(input.value, {c8y_SupportedOperations:['c8y_Command']})"
c8y devices get --id 1234 |
c8y devices update --template "_.SelectMerge(input.value, {c8y_SupportedOperations:['c8y_Command']})"
Get-Device -Id 1234 |
Update-Device -Template "_.SelectMerge(input.value, {c8y_SupportedOperations:['c8y_Command']})"
{
"id": "1234",
"c8y_IsDevice": {},
"c8y_SupportedOperations": [
"c8y_Restart",
"c8y_Command"
]
}
If piped variable input.value
does not contain a property called c8y_SupportedOperations
then a default value will be used of the same type as the value being merged (i.e. either array or object).
Example: Remove a nested fragment from a managed object​
Removing a nested fragment can be done by retrieving the existing value, and merging it with snippet which uses jsonnet property defined using ::
which will hide/remove the value.
Here is the device managed object before the merge.
{
"id": "1234",
"c8y_IsDevice": {},
"c8y_Model": {
"serialNumber": "123456789",
"otherValue": ""
}
}
The following command will remove the otherValue
property from the c8y_Model
fragment.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y devices get --id 1234 |
c8y devices update --template "_.DeprecatedMerge('c8y_Model', input.value, {otherValue:: null})"
c8y devices get --id 1234 |
c8y devices update --template "_.DeprecatedMerge('c8y_Model', input.value, {otherValue:: null})"
Get-Device -Id 1234 |
Update-Device -Template "_.DeprecatedMerge('c8y_Model', input.value, {otherValue:: null})"
{
"id": "1234",
"c8y_IsDevice": {},
"c8y_Model": {
"serialNumber": "123456789"
}
}
The same thing could als
Example: Retry a failed operation​
Retrying an operation just involved creating a new operation based on the contents of the failed operation.
The select
parameter can be used to remove the readonly fragments from the failed operation before passing it to the create operation command.
The template
variable just references passes the piped input untouched as data being piped is already in json format.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y operations list --status "FAILED" --select '**,!id,!deviceName!status,!creationTime' |
c8y operations create --template "input.value"
c8y operations list --status "FAILED" --select '**,!id,!deviceName!status,!creationTime' |
c8y operations create --template "input.value"
Get-OperationCollection -Status "FAILED" -Select '**,!id,!deviceName!status,!creationTime' |
New-Operation -Template "input.value"
Example: Clone a device​
Templates can be used to clone existing items by first fetching the reference item, piping it to the create command, and then using the input.value
variable which references the current piped input line in the template
parameter.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y devices list --pageSize 1 --select '**,copiedFrom:id,!id,!lastUpdated' |
c8y devices create --name "myclone" --template "input.value" --output json
c8y devices list --pageSize 1 --select '**,copiedFrom:id,!id,!lastUpdated' |
c8y devices create --name "myclone" --template "input.value" --output json
New-DeviceCollection -PageSize 1 -Select '**,copiedFrom:id,!id,!lastUpdated' |
New-Device -Name "myclone" -Template "input.value" -Output json
select '**,copiedFrom:id,!id,!lastUpdated'
is used to select all of the input properties except for id and lastUpdated as these properties can not be part of the body for the create device command. It also maps the id field to copiedFrom
so a reference to the source device will be present in the newly created device.
{
"copiedFrom": "507325",
"creationTime": "2021-05-07T16:39:18.827Z",
"id": "519792",
"lastUpdated": "2021-05-09T21:06:40.620Z",
"name": "myclone",
"owner": "exampleuser",
"self": "https://t12345.example.c8y.com/inventory/managedObjects/519792",
"type": "altest"
}
Example: add durations to a fixed timestamp​
This example uses a fixed timestamp, however you can specify the datetime in a lot of different formats, below are some of the more common formats:
2013-06-29T09:05:14.00+0200
2013-06-29T09:05:14.00Z
2013-06-29
1688064371 (linux timestamp in seconds)
1688064371 (linux timestamp in milliseconds)
Some example of date manipulation are show below:
# Add seconds
c8y template execute --template "_.Date('2023-06-29T09:05:14.000+0200', '10s')"
# => 2023-06-29T09:05:24.000+02:00
# Add days
c8y template execute --template "_.Date('2023-06-29T09:05:14.000+0200', '10d')"
# => 2023-07-09T09:05:14.000+02:00
# Subtract seconds (as integer)
c8y template execute --template "_.Date('2023-06-29T09:05:14.000+0200', -20.2)"
# => 2023-06-29T09:04:53.800+02:00
# Add randomized delay in seconds between 60 and 120 seconds
c8y template execute --template "_.Date('2023-06-29T09:05:14.000+0200', _.Int(60, 120))"
# => 2023-06-29T09:06:25.000+02:00
# Get date in utc
c8y template execute --template "_.Date('2023-06-29T09:05:14.000+0200', utc=true)"
# => 2023-06-29T07:05:14.000Z
# Get date in utc
c8y template execute --template "_.Date('2023-06-29T09:05:14.000+0200', utc=true)"
# => 2023-06-29T07:05:14.000Z
# Just return the date (not the time). This uses custom format string using go's slightly weird formatting syntax, see golang https://pkg.go.dev/time#pkg-constants for details
c8y template execute --template "_.Date('2023-06-29T09:05:14.000+0200', format='2006-02-01', utc=true)"
# => 2023-29-06
Example: Generate new events from existing ones but add an offset to the timestamp​
c8y events list -p 1 --select '**,!id,!lastUpdated,!creationTime,!self' \
| c8y events create --template "input.value + {time: _.Date(input.value.time, '2months')}" --dry
The same example can be randomized by using the _.Int()
function to returned a value between 1 and 5, and using a jsonnet format string to build offset in months, e.g. 4months
.
c8y events list -p 1 --select '**,!id,!lastUpdated,!creationTime,!self' \
| c8y events create --template "input.value + {time: _.Date(input.value.time, '%smonths' % _.Int(1,5))}" --dry
Example: Calculate a duration between two dates​
By default the _.Duration()
function returns an object with properties containing the same duration in various formats. You can then access them using normal dot notation, e.g. _.Duration('2023-01-01', '2020-01-01').minutes
.
{
"days": 0.0035185185185185185,
"duration": "5m4s",
"hours": 0.08444444444444445,
"milliseconds": 304000,
"minutes": 5.066666666666666,
"seconds": 304
}
Alternatively you can specify which units you want returned by providing the unit="<type>"
named argument.
Supported unit
values:
Unit | Example |
---|---|
object (default) | {"days":0.0035185185185185185,"duration":"5m4s","hours":0.08444444444444445,"milliseconds":304000,"minutes":5.066666666666666,"seconds":304} |
duration | "32h9m12.6s" |
days , d | 1.02 |
hours , h | 32.5 |
minutes , m | 16.1 |
seconds , s | 12.1 |
milliseconds , ms | 12100 |
Example: Check out long ago an event was created​
You can get the relative timestamp (to now) as a human friendly string (e.g. -5.6seconds, -32h30min2s etc.)
c8y events list -p 5 | c8y template execute --template "{id: input.value.id, relativeTime: _.Duration(input.value.time).duration}"
| id | relativeTime |
|--------------|--------------|
| 2776297 | -5.605s |
| 2776296 | -7.763s |
| 2775121 | -8.206s |
| 2776295 | -8.208s |
| 2658776 | -32h9m12.6s |
You can also control the units to return the value in seconds.
c8y events list -p 5 | c8y template execute --template "{id: input.value.id, time: input.value.time, relativeTime: _.Duration(input.value.time, unit='seconds')}"
| id | relativeTime | time |
|--------------|------------------|-------------------------------|
| 2658776 | -116010.555 | 2023-06-28T12:04:56.671Z |
| 2658770 | -116012.645 | 2023-06-28T12:04:54.591Z |
| 2658693 | -117088.392 | 2023-06-28T11:46:58.845Z |
| 2658687 | -117090.536 | 2023-06-28T11:46:56.702Z |
| 2673447 | -122514.6 | 2023-06-28T10:16:32.641Z |
Example: Convert units of time​
You can also use it to convert between different units of time, e.g. hours => seconds, seconds to days etc.
c8y template execute --template "_.Duration('1h12min', unit='seconds')"
# => 4320
c8y template execute --template "_.Duration('1h', unit='seconds')"
# => 3600
c8y template execute --template "_.Duration('10s', unit='days')"
# => 0.00011574074074074075
Template settings​
Template (jsonnet) files can be stored in a folder and this folder can be added to the settings.template.path
settings within the global or session configuration.
{
"settings": {
"template.path": "/workspaces/go-c8y-cli/.cumulocity/templates"
}
}
The template path will be used when looking up template filenames if the user does not specify a relative or full path to it.
i.e.
c8y template execute --template event.jsonnet
c8y will look for a file called "event.jsonnet" inside the template.path
folder.
PSc8y also supports argument completion for template files if the path is set.
PS /workspaces/go-c8y-cli> Invoke-Template -Template <tab>
alarm.jsonnet device.template.jsonnet event.jsonnet measurement.advanced.jsonnet
Complex Examples​
Create devices with variable software lists​
Add a complex device managed object where the number of installed software applications in the c8y_SoftwareList
fragment can be set via the command line.
// Helper: Create software entry
local newSoftware(i) = {
name: "app" + i,
version: "1.0." + i,
url: "",
};
// Output: Device Managed Object
{
name: "name1",
value: var("name", "defaultName"),
type: var("type"),
["c8y_" + var("type")]: {},
c8y_SoftwareList: [ newSoftware(i) for i in std.range(1, var("softwareCount", 1))],
}
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y inventory create \
--dry \
--template ./examples/templates/device.template.jsonnet \
--templateVars "softwareCount=2"
c8y inventory create `
--dry `
--template ./examples/templates/device.template.jsonnet `
--templateVars "softwareCount=2"
New-ManagedObject `
-Dry `
-Template ./examples/templates/device.template.jsonnet `
-TemplateVars "softwareCount=2"
{
"c8y_SoftwareList": [
{
"name": "app1",
"url": "",
"version": "1.0.1"
},
{
"name": "app2",
"url": "",
"version": "1.0.2"
}
],
"c8y_defaultType": {},
"name": "name1",
"type": "defaultType",
"value": "test"
}
Template development​
To help with the development of templates, there is a command which evaluates a template and prints the output to the console.
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
c8y template execute --template ./mytemplate.jsonnet
c8y template execute --template ./mytemplate.jsonnet
Invoke-Template -Template ./mytemplate.jsonnet
Debugging​
If you are having problems with your templates, you can print out the full template including all of the automatically injected variables and functions by setting the following environment variable:
- Shell
- PowerShell (native)
- PowerShell (PSc8y)
export C8Y_JSONNET_DEBUG=true
$env:C8Y_JSONNET_DEBUG = "true"
$env:C8Y_JSONNET_DEBUG = "true"