Overview
July 27, 2023 ยท View on GitHub
This repo contains the SDC7 installer for Workflow API and Runners, with specific modules, configurations and the required tools to build and setup workflow zones either into SDC Headnode or Compute Nodes.
Please, note this documentation is not about the general purpose wf and backend modules.
Documentation for these is publicly available at
Terminology and system description
and the
Workflow REST API.
A copy of such documents is also available on this server for convenience:
Developer Guide
Adding a Node Module to Workflow's Sandbox
In order to make a new node module available to the Workflow's sandbox used by
the different workflow tasks, you first have to add that module to project's
package.json dependencies section.
Once you've added there, you need to regenerate the npm-shrinkwrap.json file.
Easier way is to just remove the current one, rm -Rf node_modules and run
make all again. Once all the modules have been installed, you need to run
npm shrinkwrap and the file will be regenerated with the lastest version of
the required modules.
Finally, in order to make your module available for the workflow tasks, you
need to add it to etc/config.json.in which is the file used to generate the
configuration file for a SDC setup.
Extra fields
Starting with version 0.9.5 is possible to add custom fields to the buckets
wf_jobs, wf_workflows and wf_jobs_info. While this was theoretically
possible in the past for latest two buckets, it wasn't for wf_jobs.
Additionally, the possible fields were restricted to the moray supported
indexes.
Now it's also possible to add object types, which will be stored into moray
as strings, and properly encoded/decoded when saved/retrieved from the backend.
This change has been introduced to automatically deal with JSON.stringified
objects and arrays.
Fields definition must be placed into configuration file, right under:
backend.opts.extra_fields
it's to say:
{
"backend": {
"module": "../lib/workflow-moray-backend",
"opts": {
"url": "http://10.99.99.17:2222",
"connectTimeout": 1000,
"extra_fields": {
"wf_workflows": {
"custom_object": {
"type": "object",
"index": false,
},
"unique_string": {
"type": "string",
"unique": true
}
"indexed_string": {
"type": "string",
"index": true
}
},
"wf_jobs": {
"vm_uuid": {
"type": "string",
"index": true,
"unique": false
},
"server_uuid": {
"type": "string",
"index": true,
"unique": false
}
},
"wf_jobs_info": {}
}
}
}, ...
}
Let's briefly review the wf_workflows section on the config fragment above:
- The field
custom_objectwill not be added to moray bucket as an index. (indexwas set tofalse). Indeed, this would be the recommended way to proceed for arbitrary length complex objects: do not index them. If you need to search for specific properties, add extra fields with those properties. Anyway, when a JavaScriptArrayorObjectvalue is given to this field, it'll be encoded usingJSON.stringifybefore it's saved into moray and decoded usingJSON.parsewhen it's retrieved from moray. - The field
unique_stringwill be added to moray as anuniqueindex. - The field
indexed_stringwill be added to moray as anon uniqueindex.
Couple important things to note:
-
If you add new fields for an existing setup, you need to change the version number. Otherwise, the moray buckets will not get updated with the new fields. Use a plain integer number for versioning.
-
If you want to be able to add the extra fields to either
jobsorworkflowsusing the API (and you want it), you must also add these to the api config section as follows:"api": { "port": 8080, "wf_extra_params": ["custom_object", "unique_string", "indexed_string"], "job_extra_params": ["vm_uuid", "server_uuid"] },
Operator Guide
Performing searches
Searching Jobs
- Searching
jobsbyvm_uuidis faster, given we are using indexedjob.targetattribute, which always matches'(target=*' + vm_uuid + '*)'for machines' jobs. (Since WORKFLOW-101). - Searching
jobson a given time period is also supported using the argumentssince, for jobs created since the given time anduntilfor jobs created until the specified time. Note both of these attributes values will be included into the search, which is made using LDAP filters. Attributes can take eitherepochtime values or any valid JavaScript Date string. Note that if the given value cannot be transformed into a valid JavaScript Date, the argument will be silently discarded. (Since WORKFLOW-104).
Examples:
The following is a very simple output of a system with very few jobs to help illustrating search options:
[root@headnode (coal) ~]# sdc-workflow /jobs | json -a created_at execution name
2013-05-27T15:38:27.173Z running reboot-7.0.0
2013-05-27T01:12:05.918Z succeeded provision-7.0.6
2013-05-27T01:01:39.919Z succeeded server-sysinfo-1.0.0
2013-05-27T00:56:49.635Z succeeded server-sysinfo-1.0.0
Searching by vm_uuid will retrieve all the jobs associated with the given machine:
[root@headnode (coal) ~]# sdc-workflow /jobs?vm_uuid=767aa4fd-95b4-4c94-bc6c-71d274fb2899 | json -a created_at execution name
2013-05-27T15:38:27.173Z succeeded reboot-7.0.0
2013-05-27T01:12:05.918Z succeeded provision-7.0.6
Searching jobs "until", "within" or "since" a given time period just
requires some caution regarding the format of the passed in since and until
arguments.
For example, to pass in the value 2013-05-27T15:38:27.173Z for one of these
attributes we can either URL encode it, or transform into a time since epoch
integer:
$ node
> encodeURIComponent('2013-05-27T15:38:27.173Z');
'2013-05-27T15%3A38%3A27.173Z'
> new Date('2013-05-27T15:38:27.173Z').getTime();
1369669107173
Either way, we can use for jobs search:
[root@headnode (coal) ~]# sdc-workflow /jobs?since=2013-05-27T15%3A38%3A27.173Z | json -a created_at execution name2013-05-27T15:38:27.173Z succeeded reboot-7.0.0
[root@headnode (coal) ~]# sdc-workflow /jobs?since=1369669107173 | json -a created_at execution name
2013-05-27T15:38:27.173Z succeeded reboot-7.0.0
The same way we search for jobs created since a given time value, we can also search for jobs created until a given time:
[root@headnode (coal) ~]# sdc-workflow /jobs?until=2013-05-27T00%3A56%3A49.635Z | json -a created_at execution name
2013-05-27T00:56:49.635Z succeeded server-sysinfo-1.0.0
And, of course, we can combine both parameters to search jobs created within a given time period:
[root@headnode (coal) ~]# sdc-workflow /jobs?since=2013-05-27T01%3A01%3A39.919Z\&until=2013-05-27T01%3A12%3A05.918Z | json -a created_at execution name
2013-05-27T01:12:05.918Z succeeded provision-7.0.6
2013-05-27T01:01:39.919Z succeeded server-sysinfo-1.0.0
Also, note that it's perfectly possible passing in other valid JavaScript date values
to these parameters, like 2013-05-27. As far as we can transform the given value
into a valid date, everything will work as expected. If the given value cannot be
properly transformed into a valid Date object, the value will be silently discarded.
Searching workflows
(Since WORKFLOW-81)
While it's possible to search workflows by any workflow property, the only indexed property is workflow's name (this will be improved in the future).
Therefore, it's highly recommended to search workflows just by name. Searching by name, with the current model of workflow definition also allows to search workflows by version.
Some search examples:
Exact match:
# A workflow name matches exactly the provided search filter:
[root@headnode (coal) ~]# sdc-workflow /workflows?name=provision-7.0.6| json -a name
provision-7.0.6
# There isn't a single workflow matching name exactly:
[root@headnode (coal) ~]# sdc-workflow /workflows?name=provision| json -a name
Approximate matches:
# workflow's name begins with provision:
[root@headnode (coal) ~]# sdc-workflow /workflows?name=provision*| json -a name
provision-7.0.6
# workflow's name contains provision:
[root@headnode (coal) ~]# sdc-workflow /workflows?name=*provision*| json -a name
provision-7.0.6
reprovision-7.0.0
# workflow's name finishes with '7.0.0' (actually, this matches wf version)
[root@headnode (coal) ~]# sdc-workflow /workflows?name=*7.0.0| json -a name
create-from-snapshot-7.0.0
start-7.0.0
stop-7.0.0
reboot-7.0.0
reprovision-7.0.0
update-7.0.0
destroy-7.0.0
snapshot-7.0.0
rollback-7.0.0
delete-snapshot-7.0.0
remove-nics-7.0.0
Logging and log level changes
Both, wf-api and wf-runner use Bunyan for logging. By default, both
processes are logging to the default SMF stdout file.
To know the exact file each service is logging to:
svcs -L wf-api
svcs -L wf-runner
If you want to see the Bunyan output pretty printed to stdout:
cd /opt/smartdc/workflow
tail -f `svcs -L wf-api` | ./node_modules/.bin/bunyan
tail -f `svcs -L wf-runner` | ./node_modules/.bin/bunyan
By default, both services log level is INFO. This can be easily increased
using bunyan -p to get more verbose logging for each of the processes:
bunyan -p wf-api
bunyan -p wf-runner
Inspecting moray backend from the cli
Besides the default services, an additional wf-console.js script is provided,
which can be initialized and used to directly talk to the moray backend the same
way wf-moray-backend module does.
This script will start a REPL session using an unix socket. In order to initialize the REPL session:
cd /opt/smartdc/workflow
./build/node/bin/node wf-console.js &
The unix socket will be then available at /tmp/node-repl.sock. You can connect
to the socket using:
nc -U /tmp/node-repl.sock
Available objects on the REPL session, apart of the default node globals are:
backend: Moray workflow backend. Checknode_modules/wf-moray-backendfor the details on the available methods to manipulate workflows and jobs.log: Bunyan logger instance used to initialize the backend.config: Configuration file used to initialize the backend (JSON object).wf: Object which can provide access to any of thewfmodule defined objects.
Additionally, backend provides access to moray-client at backend.client, so you
can directly talk REST to moray. Look at moray-client module setup above wf-moray-backend.
Watching for job failures (dtrace)
The wf-runner service fires some dtrace probes. We can use 'wf-job-done'
to watch for job failures. Run the following in the workflow zone:
dtrace -qn 'workflow*:::wf-job-done /copyinstr(arg2) != "succeeded"/ { printf("%s %s %s\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); }'
For example:
[root@9b7dbc12-7374-48ef-841e-18708faf4619 (coal:workflow0) ~]# dtrace -qn 'workflow*:::wf-job-done /copyinstr(arg2) != "succeeded" / { printf("%s %s %s\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2)); }'
6205964e-b588-4605-893a-e72c98a8dc28 provision-7.0.2 failed
Watching for job completion (bunyan)
In the workflow zone:
bunyan -p wf-runner -l info -c 'this.runtime'
or:
tail -f `svcs -L wf-runner` | bunyan -l info -c 'this.runtime'
Or use the 'warn' level to only get unsuccessful job completions.
For example:
[root@9b7dbc12-7374-48ef-841e-18708faf4619 (coal:workflow0) ~]# tail -f `svcs -L wf-runner` | bunyan -l warn -c 'this.runtime'
[2013-05-24T21:34:46.875Z] WARN: workflow-runner/1370 on 9b7dbc12-7374-48ef-841e-18708faf4619: job completed (runner_uuid=9b7dbc12-7374-48ef-841e-18708faf4619, runtime=47471)
job: {
"uuid": "34bda784-beb9-49d4-971c-5a27b58b0e21",
"name": "provision-7.0.2",
"execution": "succeeded"
}
Metrics
Workflow exposes metrics via node-triton-metrics. wf-runner metrics are exposed on http://<ADMIN_IP>:8881/metrics and wf-api metrics are exposed on 'http://<ADMIN_IP>:8882/metrics`.