Skip to main content
Version: Current

Events and Dependencies

Events describe scenario behavior in CRADLE.

The events() block organizes events into three lifecycle phases:

events() >
preEvent(),
mainEvent(),
postEvent().

Each phase declares the events that belong to it. Every declared event is then defined in a matching event("name") block.

Sequential execution

CRADLE events execute sequentially: one event completes before the next event begins. Use dependsOn() to make required ordering between named events explicit.

Event lifecycle​

CRADLE divides scenario behavior into three phases:

PhasePurpose
preEvent()Contains preparation that occurs before the primary scenario.
mainEvent()Contains the primary scenario behavior.
postEvent()Contains follow-up or evidence-related activity.

The lifecycle can be viewed as:

1
preEventPreparation before the primary scenario.
↓
2
mainEventPrimary scenario behavior.
↓
3
postEventFollow-up or evidence-related activity.

Event properties​

The current CRADLE reference documents the following event-related properties:

PropertyArgumentsStatusDescription
eventSemantic event nameStructuralDeclares an event within a lifecycle phase.
instanceInstance nameSchema requiredSelects the instance associated with the event.
needRoottrue or falseSchema requiredIndicates whether elevated privileges are requested. CradleXC defaults to false.
subjectSubject, parametersSchema requiredIdentifies the execution subject and optional parameters.
runObjectObject name, parametersSchema requiredSelects a declared object and optional parameters.
pauseBeforeRunDuration in secondsSchema optionalAdds a delay before the event. CradleXC defaults to 0.
pauseAfterRunDuration in secondsSchema optionalAdds a delay after the event. CradleXC defaults to 0.
dependsOnEvent nameSchema optionalAdds an explicit dependency. Repeat for multiple dependencies.
scheduleExecutionISO 8601 date-timeSchema optionalAssociates the event with a scheduled time.
descriptionTextSchema optionalProvides a human-readable description of the event.
heuristicFramework, identifierCompiler extensionAssociates an external classification or framework identifier with the event.

Declare event phases​

The lifecycle phases are declared through:

events() >
preEvent(),
mainEvent(),
postEvent().

Each phase can then declare its own events.

For example:

preEvent() >
event("initialize_client").

mainEvent() >
event("collect_evidence").

postEvent() >
event("cleanup").

This places:

  • event initialize_client in preEvent
  • event collect_evidence in mainEvent
  • event cleanup in postEvent

Each event must then have a corresponding definition.

Define an event​

A named event block uses the form:

event("name") >
...

For example:

event("initialize_client") >
instance("Client"),
needRoot(false),
subject("bash", ""),
runObject("InitializationScript", ""),
pauseBeforeRun(0),
pauseAfterRun(0),
scheduleExecution("2026-01-15T10:00:00+00:00"),
description("Initialize the example client").

This event:

  • runs on Client
  • does not request root privileges
  • uses bash
  • runs the InitializationScript object
  • has no delay before execution
  • has no delay after execution
  • does not wait for another event
  • includes a scheduled execution time
  • includes a description

Select an instance​

Use instance() inside an event to identify the associated instance.

For example:

event("initialize_client") >
instance("Client").

The referenced instance should have been declared in instances():

instances() >
instance("Client").

and defined in a matching block:

instance("Client") >
os("ubuntu", "20.04").

Conceptually:

instances()
↓
instance("Client")
↓
event("initialize_client")
important

The instance name used by an event must match the corresponding declared instance.

Root privileges​

Use needRoot() to indicate whether the event requests elevated privileges.

For example:

needRoot(false)

or:

needRoot(true)

needRoot() accepts a boolean value:

ValueMeaning
trueRequest elevated privileges.
falseDo not request elevated privileges.

If needRoot() is omitted, CradleXC currently defaults to:

false

A typical event uses:

event("initialize_client") >
instance("Client"),
needRoot(false).

Execution subject​

Use subject() to identify the execution subject and optional parameters.

For example:

subject("bash", "")

The first argument identifies the subject:

bash

The second argument contains optional parameters.

For example:

event("initialize_client") >
subject("bash", "").

The interpretation of the subject and its parameters depends on the scenario and supported CRADLE behavior.

Run an object​

Use runObject() to select a declared object.

For example:

runObject("InitializationScript", "")

The first argument identifies the object:

InitializationScript

The second argument contains optional parameters.

The object should be declared in metadata:

metadata() >
object("InitializationScript").

and defined separately:

object("InitializationScript") >
location("${uriRemote}/scripts/initialize.sh").

The relationship is:

metadata()
↓
object("InitializationScript")
↓
event("initialize_client")
↓
runObject("InitializationScript", "")
important

The object name passed to runObject() must match a declared object.

Object parameters​

The second argument to runObject() can contain optional parameters.

For example:

runObject("InitializationScript", "")

uses no additional parameters.

Where parameters are required, use a structured map.

For example:

runObject("InitializationScript", {
mode = "safe",
count = 1
})

The exact interpretation of those values depends on the object and execution context.

Delay before an event​

Use pauseBeforeRun() to add a delay before an event.

For example:

pauseBeforeRun(10)

The value represents a duration in seconds.

To request no delay:

pauseBeforeRun(0)

CradleXC currently defaults this property to:

0

when omitted.

Delay after an event​

Use pauseAfterRun() to add a delay after an event.

For example:

pauseAfterRun(10)

To request no delay:

pauseAfterRun(0)

CradleXC currently defaults this property to:

0

when omitted.

Event dependencies​

Use dependsOn() to express whether an event depends on another event.

For example:

dependsOn("initialize_client")

This makes the surrounding event wait for initialize_client. Omit the property when no explicit dependency is required.

For example:

mainEvent() >
event("initialize_client"),
event("collect_evidence").

event("initialize_client") >
instance("Client"),
needRoot(false),
subject("bash", ""),
runObject("InitializationScript", "").

event("collect_evidence") >
instance("Client"),
needRoot(false),
subject("bash", ""),
runObject("CollectEvidence", ""),
dependsOn("initialize_client").

Conceptually:

event("collect_evidence")
depends on
event("initialize_client")
important

Every dependsOn() value must match a defined semantic event name.

Event model​

The scenario metadata selects the overall event model with eventType().

For example:

metadata() >
eventType("sequence").

The supported event type is:

sequence

Sequence​

Use:

eventType("sequence")

for sequential event handling.

The Hello World example uses this event model.

Explicit dependencies​

Use dependsOn() to describe ordering relationships between semantic event names while using the supported sequential event model.

Schedule an event​

Use scheduleExecution() to associate an event with an ISO 8601 date-time.

For example:

scheduleExecution("2026-01-15T10:00:00+00:00")

A complete event can include:

event("initialize_client") >
instance("Client"),
scheduleExecution("2026-01-15T10:00:00+00:00").

Use a time-zone designator when specifying scheduled execution times.

The Hello World example contains:

scheduleExecution("2018-11-13T20:20:39+00:00")

for each lifecycle event.

Event descriptions​

Use description() to explain the purpose of an event.

For example:

description("Initialize the example client")

Descriptions provide additional context when reading or reviewing a scenario.

For example:

event("initialize_client") >
instance("Client"),
description("Initialize the example client").

Event heuristics​

Supported events can use:

heuristic("framework", "identifier")

For example:

event("initialize_client") >
heuristic("example-framework", "EXAMPLE-001").

Heuristic properties add classification metadata without replacing the event definition.

See Heuristics for documented conventions and examples.

Complete event example​

The following example defines one event in the main phase:

events() >
preEvent(),
mainEvent(),
postEvent().

mainEvent() >
event("initialize_client").

event("initialize_client") >
instance("Client"),
needRoot(false),
subject("bash", ""),
runObject("InitializationScript", ""),
pauseBeforeRun(0),
pauseAfterRun(0),
scheduleExecution("2026-01-15T10:00:00+00:00"),
description("Initialize the example client").

The lifecycle relationship is:

events()
↓
mainEvent()
↓
event("initialize_client")
↓
event definition

Multiple events in a phase​

A phase can contain more than one event.

For example:

mainEvent() >
event("initialize_client"),
event("collect_evidence"),
event("cleanup").

Each event should then have its own definition:

event("initialize_client") >
...

event("collect_evidence") >
...

event("cleanup") >
...
important

Semantic event names should be unique within the scenario.

Events across multiple phases​

A scenario can define events across all three lifecycle phases.

For example:

events() >
preEvent(),
mainEvent(),
postEvent().

preEvent() >
event("initialize_client").

mainEvent() >
event("collect_evidence").

postEvent() >
event("cleanup").

This gives the scenario a clear lifecycle:

initialize_client
preEvent
↓
collect_evidence
mainEvent
↓
cleanup
postEvent

The canonical HelloWorld scenario declares all three phases and currently places one event in the main phase.

Hello World events​

The Hello World scenario declares:

events() >
preEvent(),
mainEvent(),
postEvent().

The main phase contains:

mainEvent() >
event("initialize_client").

The event definition:

event("initialize_client") >
instance("router"),
needRoot(true),
pauseBeforeRun(0),
pauseAfterRun(0),
scheduleExecution("2018-11-13T20:20:39+00:00"),
description("HelloWorld Event").

This event:

  • references instance("router")
  • requests root privileges
  • uses zero-second pauses
  • does not wait for another event
  • records an explicit execution timestamp

Cross-references​

Events frequently connect several parts of a CRADLE scenario.

Consider:

event("initialize_client") >
instance("Client"),
runObject("InitializationScript", "").

This references:

Client

and:

InitializationScript

Those names should resolve to:

instances() >
instance("Client").

and:

metadata() >
object("InitializationScript").

Conceptually:

instance("Client")
↓
event("initialize_client")
↓
object("InitializationScript")

Schema and compiler behavior​

The current schema and CradleXC behavior contain several event-related differences.

PropertyCurrent behavior
instanceRequired by the current schema.
needRootRequired by the schema, while CradleXC currently defaults to false.
subjectRequired by the current schema.
runObjectRequired by the current schema.
pauseBeforeRunOptional in the schema. CradleXC defaults to 0.
pauseAfterRunOptional in the schema. CradleXC defaults to 0.
waitforThe current schema and compiler behavior differ in how dependencies are represented.
scheduleExecutionOptional in the current schema.
descriptionOptional in the current schema.
heuristicRecognized by CradleXC as a compiler extension.
note

The grammar, schema and compiler should not be treated as identical validation layers. Validate event behavior against the CradleXC release you are using.

Validate event definitions​

Validate a scenario with:

cxc validate -i <scenario.cradle>

For example:

cxc validate -i scenarios/HelloWorld.cradle

When reviewing an event-related problem, check:

  • whether the event belongs to a lifecycle phase
  • whether the event has a matching event("name") definition
  • whether the referenced instance exists
  • whether the referenced object exists
  • whether event names are unique
  • whether dependsOn() references resolve correctly
  • whether scheduled execution values use the intended date-time form
  • whether compiler extensions are supported by the CradleXC release being used

Common mistakes​

Event is declared but not defined​

If a phase contains:

mainEvent() >
event("initialize_client").

there should be a corresponding:

event("initialize_client") >
...

Event definition does not belong to a phase​

An event definition alone does not show which lifecycle phase contains it.

For example:

event("initialize_client") >
instance("Client").

should also be referenced by a phase:

mainEvent() >
event("initialize_client").

Event references an undeclared instance​

Incorrect:

event("initialize_client") >
instance("Client").

when Client has not been declared.

Declare it through:

instances() >
instance("Client").

Event references an undeclared object​

Incorrect:

event("initialize_client") >
runObject("InitializationScript", "").

without a corresponding object declaration.

Declare it in metadata:

metadata() >
object("InitializationScript").

and define it:

object("InitializationScript") >
location("${uriRemote}/scripts/initialize.sh").

Dependency references the wrong event name​

If the intended dependency is event initialize_client:

dependsOn("initialize_client")

the scenario should contain a corresponding event named:

event("initialize_client")

Use matching event identifiers consistently.

Next steps​

Continue with Objects and Interpolation to learn how CRADLE declares external artifacts and constructs their locations.