Events
This guide provides an overview of the event tracking system in OpsChain.
After following this guide you should know:
- how events are handled in OpsChain
- which events are created by OpsChain automatically
- how to query events via the API
- how to create custom events using the API
All the examples in this guide assume the OpsChain API server is running on your local machine. Replace <host> with your OpsChain server name if connecting to a remote OpsChain server.
Overview
Any API request that modifies data in OpsChain will be tracked for auditing and reporting purposes, this includes creating and updating data, interacting with activities and more. In future versions, OpsChain will track more events, please let us know if there are particular events you would like tracked.
OpsChain does not track API requests to the api/events API itself.
The data provided within the attributes section of the event API response varies depending on the type of event, but it contains more detailed information about the event context.
All automatically created API events start with the api: prefix and are then followed by the API controller, and then the API method. When a failure occurs, OpsChain will create an event with the error: prefix.
System created events
Events created internally by OpsChain can be identified by the system property. If system is true then the event was created by OpsChain, if it is false then the event was created by a user using the api/events endpoint - the username field identifies the user that initiated the request.
Further down we present a list of the event types created by OpsChain.
Viewing events
You can view events in the OpsChain web UI by navigating to the audit history page.
On the API, the OpsChain api/events endpoint can be queried to see events in the OpsChain system.
curl -u "{{username}}:{{password}}" http://<host>/api/events
The response is a JSON:API payload containing a list of the most recent events. The response will include the relevant events from oldest to newest in the response data array, i.e. data[0] will be the oldest event in the result set.
Example change start event
Below is an example of a change start event returned by the api/events endpoint.
{
"id": "43404b06-e265-4d4e-a387-4fc83320a778",
"type": "event",
"attributes": {
"username": "opschain",
"system": true,
"type": "api:changes:start",
"created_at": "2021-01-01T01:00:00.000000Z"
},
"relationships": {
"source": {
"links": {
"source": "/api/projects/hello_world/changes/d57edfd7-7536-40fc-9c5b-9492faa0a6fd"
}
}
},
"links": {
"self": "/api/events/43404b06-e265-4d4e-a387-4fc83320a778"
}
}
Filtering events on the API
The query to the api/events endpoint can be filtered by providing the relevant query parameters.
For example, the following query will return up to 100 events that were created after 2021-01-01.
By default, the response is limited to only 10 events, and there is a hard limit of 1000 events. The response status code will be 206 Partial Content when the response has been truncated by the limit.
curl --globoff --user "{{username}}:{{password}}" 'http://<host>/api/events?filter[created_at_gt]=2021-01-01T01:00:00.000000Z&limit=100'
The --globoff argument is required when using the filtering queries using curl.
Filtering examples with the API
The API filtering and sorting guide includes a variety of examples that highlight OpsChain's filtering feature and how it can be used to find specific events.
More complex examples using the event API endpoint
Below are some more complex examples of querying the api/events API.
The examples require the jq and curl utilities, and have been tested with Zsh and Bash 4.
Waiting for an event to occur
The following is an example of watching the events API waiting for a change start event to occur.
user='{{username}}:{{password}}'
since="$(date --iso-8601=ns)"
event='api:changes:start'
while true; do
response="$(curl -s -G --user "${user}" http://<host>/api/events --data-urlencode "filter[created_at_gt]=${since}" --data-urlencode "filter[type_eq]=${event}")"
if jq -e '.data | length > 0' <<<"${response}" >/dev/null; then
echo "${response}"
break
fi
sleep 1
done
Don't forget to add --data-urlencode "filter[system_true]=yes" if you wish to wait for a system event.
Paginating through events
The following is an example of paginating backwards through the events API. It will output the newest event to the oldest.
user='{{username}}:{{password}}'
while true; do
response="$(curl -s -G --user "${user}" http://<host>/api/events --data-urlencode "filter[created_at_lt]=${before}")"
before="$(jq -r '.data[0].attributes.created_at // empty' <<<"${response}")"
if [[ -z "${before}" ]]; then
break
fi
jq '.data | reverse[]' <<<"${response}"
done
Creating custom events
Events can be created in the OpsChain events framework by sending a POST request to the api/events endpoint.
The request needs to be a valid JSON:API request. E.g.
curl --fail --user {{username}}:{{password}} http://<host>/api/events -H 'content-type: application/vnd.api+json' -d '{ "data": { "type": "Event", "attributes": { "type": "custom", "some": "value", "nesting": { "also": "works" } } } }'
curl --fail --user {{username}}:{{password}} http://<host>/api/events -H 'content-type: application/vnd.api+json' -d @event-file.json
OpsChain responds with a 201 status code and no response body when the event is created successfully.
Linking events
Events can be linked to data within OpsChain. Below is an example of linking a project with the path /projects/bank (this is the same as a project with the code bank) to a custom event.
curl --fail --user {{username}}:{{password}} http://<host>/api/events -H 'content-type: application/vnd.api+json' -d '{ "data": { "type": "Event", "attributes": { "type": "linked:to:project:example", "project_path": "/projects/bank" } } }'
Events can be linked to:
- Projects via a path or an ID, e.g.
"project_path": "/projects/bank", or"node_path": "/projects/bank", or"project_id": "ff1bf781-4fe0-4b14-b0d2-20ef8cb1be80" - Environments via a path or an ID, e.g.
"node_path": "/projects/bank/environments/dev", or"node_id": "969a2b4c-a700-40d2-a25c-1f4f68cf6d54" - Assets via a path or an ID, e.g.
"node_path": "/projects/bank/environments/dev/assets/obp", or"node_id": "2f988308-325d-4a41-bdab-4cf0b8c3103a" - In addition, the following models can be linked via an ID, (e.g.
"{{model_type_id}}": "ff1bf781-4fe0-4b14-b0d2-20ef8cb1be80"):- Scheduled changes (via
scheduled_change_id) - Changes (via
change_id) - Steps (via
step_id) - Workflow steps (via
workflow_step_id) - Workflow runs (via
workflow_run_id) - Bookmarks (via
bookmark_id) - Templates (via
template_id) - Template versions (via
template_version_id) - Git remotes (via
git_remote_id) - Properties (via
properties_id) - Properties versions (via
properties_version_id) - Settings (via
settings_id) - Settings versions (via
settings_version_id)
- Scheduled changes (via
System event types
Every system event type is made up of a level, a subject and an action, separated by colons. The level tells you how to react to the event:
api:— a normal operation was carried out, usually via the API.audit:— a user made an approval decision. These are kept as a record of who approved or rejected what.info:— OpsChain did something in the background worth knowing about.warn:andwarning:— something was not right, but OpsChain carried on.error:— an operation failed. The reason is in the event'serrordata key, and abacktraceis often included.
Some events are throttled, meaning OpsChain records at most one of them in the stated period no matter how often the underlying condition occurs. This keeps a repeating failure from filling the event history.
Changes
api:changes:create— a change was created.api:changes:start— a change was started.api:changes:success— every step in the change completed successfully.api:changes:error— the change stopped because one of its steps failed.api:changes:cancel— the change was cancelled.api:changes:abort— the change was aborted.api:changes:retry_settings_pruned— an incomplete change was retried and some of its settings overrides were dropped because they are no longer valid for a change. Thedropped_settingsdata key lists them.api:changes:destroy— a change was deleted.api:change_listener:error— the listener that picks up change cancellations failed.error:change_worker:delete— the change's runner pod could not be removed after the change finished. The pod may need to be removed by hand.
Steps
api:steps:start— a step was started.api:steps:approve— a step was approved.api:steps:reject— a step was rejected.api:steps:continue— a waiting step was continued.api:steps:success— the step's action completed successfully.api:steps:error— a step transition could not be applied.api:steps:cancel— the step was cancelled.api:steps:abort— the step was aborted.error:step:action— the step's action raised an error.error:step:processing— OpsChain could not process the step at all, so it was failed.error:step:aasm_failure— a step status transition raised an error.error:steps:transient_error— a temporary database error stopped a step transition being applied. OpsChain retries, and moves the step tosystem_errorif the retries are exhausted. Throttled to one event per hour.api:assign_system_error_job:error— the job that moves a step tosystem_errorfailed.
Step approvals
audit:steps:approve— a user approved a step that was waiting for approval.audit:steps:reject— a user rejected a step that was waiting for approval, aborting it.audit:steps:continue— a user continued a step that was waiting.audit:steps:approve:denied— a user tried to approve a step they are not an approver for.audit:steps:reject:denied— a user tried to reject a step they are not an approver for.audit:workflow_steps:approve— a user approved a workflow step that was waiting for approval.audit:workflow_steps:reject— a user rejected a workflow step that was waiting for approval, aborting it.audit:workflow_steps:continue— a user continued a workflow step that was waiting.audit:workflow_steps:approve:denied— a user tried to approve a workflow step they are not an approver for.audit:workflow_steps:reject:denied— a user tried to reject a workflow step they are not an approver for.warn:approval_identity_unresolved— identities stored in arequires_approval_fromsetting no longer exist as OpsChain users or LDAP groups. Steps waiting on them cannot be approved until the setting is corrected. Throttled to one event per hour.warn:approval_identity_validation_skipped—requires_approval_fromidentities were accepted without being checked because the LDAP directory could not be reached. Throttled to one event per hour.
Workflows
api:workflows:create— a workflow was created.api:workflows:update— a workflow was updated.api:workflow_runs:create— a workflow run was created.api:workflow_runs:start— a workflow run was started.api:workflow_runs:success— every step in the workflow run completed successfully.api:workflow_runs:error— the workflow run stopped because one of its steps failed.api:workflow_runs:cancel— the workflow run was cancelled.api:workflow_runs:abort— the workflow run was aborted.api:workflow_runs:destroy— a workflow run was deleted.api:workflow_steps:start— a workflow step was started.api:workflow_steps:approve— a workflow step was approved.api:workflow_steps:reject— a workflow step was rejected.api:workflow_steps:continue— a waiting workflow step was continued.api:workflow_steps:success— the workflow step completed successfully.api:workflow_steps:error— the workflow step failed.api:workflow_steps:cancel— the workflow step was cancelled.api:workflow_steps:abort— the workflow step was aborted.error:workflow_step:aasm_failure— a workflow step status transition raised an error.error:workflow_step:run_failure— running the workflow step raised an error.
Scheduled changes and workflows
api:scheduled_changes:create— a scheduled change was created.api:scheduled_changes:destroy— a scheduled change was deleted.api:scheduled_workflows:create— a scheduled workflow was created.api:scheduled_workflows:destroy— a scheduled workflow was deleted.api:scheduled_changes:change_creation:create— a scheduled change came due and started creating its change.api:scheduled_changes:change_creation:success— a scheduled change created its change successfully.api:scheduled_workflows:workflow_run_creation:create— a scheduled workflow came due and started creating its workflow run.api:scheduled_workflows:workflow_run_creation:success— a scheduled workflow created its workflow run successfully.error:scheduled_changes:change_creation— a scheduled change could not create its change.error:scheduled_changes:git_sha— the Git SHA for a scheduled change could not be resolved, so no change was created.error:scheduled_workflows:workflow_run_creation— a scheduled workflow could not create its workflow run.warning:scheduled_activity:skipped— a scheduled change or workflow was skipped because one it created earlier was still running and it does not allow parallel execution. Throttled to one event per hour.
Projects, environments and assets
api:projects:create— a project was created.api:projects:update— a project was updated.api:projects:destroy— a project was deleted.api:nodes:create— an environment, asset or agent was created.api:nodes:update— an environment, asset or agent was updated.api:nodes:destroy— an environment, asset or agent was deleted.api:bookmarks:create— a bookmark was created.api:bookmarks:update— a bookmark was updated.api:bookmarks:destroy— a bookmark was deleted.
Properties and settings
api:properties:update— properties were updated.api:settings:update— settings were updated.warn:settings:override— a setting was overridden by anOPSCHAIN_OVERRIDE_environment variable supplied by the deployment, so it takes precedence over the value stored in OpsChain.
Templates and template versions
api:templates:create— a template was created.api:templates:update— a template was updated.api:template_versions:update— a template version was updated.api:action_refresh:warn— an asset's actions could not be refreshed after its template version changed. The asset keeps its previous actions, and theerrordata key holds the reason.info:template_version:fetch_initialize— a template version was created and queued for its first fetch.info:template_version:fetch— the fetch of a template version's Git repository started. Itsprogressdata key is updated as the fetch produces output, so this event doubles as the live fetch log.info:template_version:fetch_complete— the fetch finished. Thesuccessdata key records whether it worked.info:template_version:refresh_cancelled— an in-progress actions refresh was cancelled.error:template_version:fetch— the template version's Git repository could not be fetched. Thefetch_outputdata key holds the Git output.error:template_version:commit_verification— the template version's Git remote and revision could not be verified.error:template_version:broken— the template version was marked broken and cannot be used until it is corrected.error:template_version:build_agent_image— the agent image for the template version could not be built.error:template_version:refresh_actions— the template version's actions could not be refreshed.error:template_version:refresh_cancelled— cancelling an in-progress actions refresh failed.
MintModel
api:generate_actions_request:create— a request to generate an asset's actions was created. Thetriggerdata key records what prompted it.error:generate_actions_request:generate— an actions generation request failed.error:mintmodel:generate— the MintModel API could not generate the asset's MintModel. The converged properties sent to the API are included to help diagnose the failure.error:mintmodel:derive_actions— the asset's actions could not be derived from its MintModel.error:mintmodel:actions_cache_not_persisted— the generated actions could not be cached, so they will be regenerated every time they are needed until this is resolved. Throttled to one event per hour.error:mint_model_concretise_task:concretise— a MintModel concretisation task failed.
Agents
api:agent:start— an agent was asked to start and the task to create its container was created.api:agent:started— the agent's container is running.api:agent:stop— an agent was asked to stop and the task to remove its container was created.api:agent:stopped— the agent's container was removed.error:agent:start— the agent's container could not be created.error:agent:stop— the agent's container could not be removed.error:build_agent_image_task:build— building the agent's image failed.
Image builds
info:image_build:queued— an image build was held back because the configured number of concurrent image builds was already running. Thequeued_behinddata key lists the builds ahead of it.info:image_build:started— an image build started.info:image_build:completed— an image build finished successfully.info:image_build:failed— an image build failed.warn:image_build:content_key_error— the key used to recognise an equivalent existing image could not be calculated, so the image was built again instead of being reused.warn:image_build:required_check_error— OpsChain could not work out whether an image build was needed, so it built one to be safe.
Runner base image
info:runner_base_image_warm:completed— the runner base image was pulled into the build service cache ahead of time, so the next runner image build does not have to wait for it. Theduration_secondsdata key records how long it took.warn:runner_base_image_warm:failed— the runner base image could not be pulled into the build service cache. Runner image builds still work, but the first one pays the download cost. Throttled to one event per hour.
Image registry
info:registry_reconcile:summary— the image registry was reconciled against the images OpsChain still needs, and unused images were removed.error:registry_reconcile:failure— reconciling the image registry failed.
Git remotes
api:git_remotes:create— a Git remote was created.api:git_remotes:update— a Git remote was updated.api:git_remotes:destroy— a Git remote was deleted.error:git_remote:create— the Git remote could not be reached when it was created. It is still created, but changes using it will fail until it is reachable.error:git_remote:update— the Git remote could not be reached after it was updated.error:git_remote:fetch— fetching from the Git remote failed.
Secrets and the secret vault
api:secrets:encrypt— a value was encrypted and stored in the secret vault.api:secrets:resolve— a stored secret was decrypted and returned.info:secret_vault_pod_roll:summary— secret vault pods running out-of-date configuration were restarted.error:secret_vault_pod_roll:failure— restarting out-of-date secret vault pods failed.
Authorisation
api:authorisation_policies:create— an authorisation policy was created.api:authorisation_policies:update— an authorisation policy was updated.api:authorisation_policies:destroy— an authorisation policy was deleted.api:authorisation_rules:create— an authorisation rule was created.api:authorisation_rules:update— an authorisation rule was updated.api:authorisation_rules:destroy— an authorisation rule was deleted.api:policy_assignments:create— a policy was assigned to a user or group.api:policy_assignments:destroy— a policy assignment was removed.api:policy_rules:create— a rule was added to a policy.api:policy_rules:destroy— a rule was removed from a policy.
Users and LDAP
api:ldap_refresh:user_start— a refresh of the cached LDAP user entries started. The search base and filter used are included.api:ldap_refresh:group_start— a refresh of the cached LDAP group entries started.api:ldap_refresh:success— the LDAP refresh completed, and the entry counts are recorded in the event data.api:ldap_refresh:warn— the LDAP refresh completed but something was not right. The cached entries were left as they were.api:ldap_refresh:error— the LDAP refresh failed, or completed with problems serious enough that stale cached entries were removed.
Events and notifications
api:event_filter:error— an event filter could not be evaluated, so its subscribers were not notified.api:event_subscriber:error— an event subscriber could not be notified. Throttled to one event per hour.api:event_processor:error— an event could not be processed. Throttled to one event per hour.api:notification:error— a notification could not be delivered. Throttled to one event per hour.
Data cleaning
info:data_cleanup:activities— a data cleaning rule removed finished changes and workflow runs. Theremoved_countandfiltersdata keys record how many were removed and the rule that removed them.info:data_cleanup:events— a data cleaning rule removed old events.info:data_cleanup:jobs— a data cleaning rule removed old job history.info:data_cleanup:agent_images— a data cleaning rule removed unused agent images.error:data_cleanup:activities— removing finished changes and workflow runs failed.error:data_cleanup:events— removing old events failed.error:data_cleanup:jobs— removing old job history failed.error:data_cleanup:agent_images— removing unused agent images failed.
Resource slots
warn:resource_slot_pool:full— every slot in a resource slot pool was in use, so work that needed one had to wait. Thepoolandconfigured_limitdata keys identify which pool and its limit. Throttled per cluster and pool.api:resource_slot_freed_listener:error— the listener that wakes work waiting on a freed resource slot failed. Waiting work still runs, but starts later than it could have.
API autoscaler
info:api_autoscaler:grow— an API worker was added because the request backlog stayed high.info:api_autoscaler:shrink— an API worker was removed because the request backlog had cleared.warn:api_autoscaler:grow_blocked_connections— the autoscaler wanted to add an API worker but did not, because too few database connections were spare. Throttled to one event every five minutes.warn:api_autoscaler:grow_blocked_memory— the autoscaler wanted to add an API worker but did not, because the pod had too little spare memory. Throttled to one event every five minutes.error:api_autoscaler:tick_failed— an autoscaler evaluation failed. Throttled to one event every five minutes.
Platform and background jobs
error:api:controller:unhandled— an API request failed with an error OpsChain did not expect. Therequest_methodandrequest_pathdata keys identify the request.api:job:error— a recurring background job could not be re-queued, so it may not run until the next attempt.error:fluentd:log_failure— step logs could not be sent to the log aggregator and were written straight to the database instead. The logs are not lost, but log queries may be slower.
Custom (i.e. user created) events can have any type as it is specified when the event is created.
Removing events
Older OpsChain events can be removed to free up space, see the OpsChain data cleaning guide for more details.