cloudsoft.io

Sensors, Widgets, and Policies

Sensors

AMP “sensors” store runtime information on resources. They can come from any source, retrieved on demand or periodically, or can be pushed by external systems. They can hold metrics from monitoring source, additional runtime state from the component or a cloud provider, or any relevant data from other systems, including CMDBs, issue trackers, and source control.

Steps, Output, Triggers, and Period

A sensor is defined in a sensor "NAME" block and should define either an output value or steps to run.

The simplest sensor will evaluate an expression and return it as output:

sensor "main_uri" {
  output = "http://${self.public_ip}:${var.port}/"
}

Most sensors will be more interesting and use workflow steps, for example to call a REST endpoint:

sensor "error_count" {
  steps = [
    "http http://${self.main_uri}/metrics?error_count",
    "return ${content_json}"
  ]
}

The output of any return step, or of the last command, is the value set on the sensor: the content_json field is used above, and it is defined as one of the outputs from the http step. If an output attribute is specified alongside steps, its value is computed after the workflow steps run, with all workflow variables and the output of the last step in scope. Thus example above could also be written as:

sensor "error_count" {
  steps = [ "http http://${self.main_uri}/metrics?error_count" ]
  output = content_json
}

Alongside steps or output (or both), sensor blocks typically also specify either a period of how often it should run, or a list of sensors that act as triggers, or both:

sensor "error_count" {
  steps = [
    "http http://${self.main_uri}/metrics?error_count",
    "return ${content_json}"
  ]
  triggers = [
    "main_uri"
  ]
  period = "1m"
}

The example above will run every minute and whenever the main_uri sensor changes. The syntax for period is any number followed by any valid unit, either ms, s, m, h, or d, and any space separate combination using different units, e.g. 1h 30m. The syntax for triggers is a list where each element is either a string, to indicate a sensor on the local entity, or a map containing an entity reference to a resource address and the name of a sensor on the entity.

A type can be set on a sensor block to enforce that the value be coercible to that that type, and retrieved as that type. For example setting integer on the above will ensure any attempt to read or write will use an integer or throw an error.

It can also be useful to define a sensor without steps or output, if that sensor is expected to be set by another source – either pushed to AMP from an external source via AMP’s REST API, or set by a policy. This is not necessary, but it makes the sensor discoverable on the resource even if it is not set, and it can be used to enforce a type.

As described on effectors, there are several other attributes supported on sensors, including a condition to prevent running and setting a sensor when the condition is not met; along with on-error, lock, and timeout. The parameter block is not applicable to sensors, as sensors run automatically.

Full details on sensors are available in the [../reference/adjuncts.md].

Widgets

The widget block is used alongside sensors to display a sensor value or Terraform attribute.

In its simplest form, it can simply refer to a sensor as the block ID:

widget "main_uri" {}

The example above will display the value of the main_uri sensor defined above, with a label main_uri.

The widget block also supports setting an explicit label, value, and unit. The value can be any expression evaluated at the resource entity, e.g. value = Note that even if label and value` are supplied, the block ID must be supplied so that the source of the definition is uniquely identifiable by Maeztro, in case it is updated or removed.

Full details on widgets are available in the [../reference/widgets.md].

Policies

AMP “policies” describe the control and governance logic to run for a system or resource under management. Structurally these are similar to sensor blocks: they must supply an ID, define steps, and define at least one of period or triggers.

In usage, however, policies tend to be more significant than sensors, and typically they effect some change in an external system or in the AMP model, either by invoking effectors through workflow or running sophisticated workflow steps.

Policies also accept condition, on-error, lock, and timeout attributes.

The following example will invoke a container slack_notifier whenever the error count exceeds 10, passing CHANNEL as an environment variable and a message as an argument:

policy "slack_on_high_error_count" {
  condition = {
    target = self.error_count
    greater-than = 10
  }
  steps = [
    {
      step : "container slack_notifier"
      env : {
        CHANNEL : "sre_ops"
      }
      args: [
        "Maeztro detected ${self.name} has high error count (${self.error_count})"
      ]
    }
  ]
}

Full details on policies are available in the [../reference/adjuncts.md].