---
###################################################################################################
# HEADER
###################################################################################################

"$schema": https://github.com/bloomberg/powerfulseal/blob/master/powerfulseal/policy/ps-schema.yaml
title: PowerfulSeal configuration schema
description: >
  The following configuration options document all features available
  for writing policy files with PowerfulSeal.
type: object


###################################################################################################
# PROPERTIES
###################################################################################################

properties:
  config:
    type: object
    "$ref": "#/definitions/config"
    description: General configuration of this policy.
  scenarios:
    type: array
    description: >
      An array of scenarios, each describing a complete `chaos experiment`.
    items:
      type: object
      "$ref": "#/definitions/scenario"
required:
- scenarios
additionalProperties: false


###################################################################################################
# DEFINITIONS
###################################################################################################

definitions:

  config:
    description: "Configure the current policy"
    type: object
    additionalProperties: false
    properties:
      runStrategy:
        type: object
        "$ref": "#/definitions/runStrategy"
      exitStrategy:
        type: object
        "$ref": "#/definitions/exitStrategy"

  runStrategy:
    description: "Configure how the scenarios are run"
    type: object
    additionalProperties: false
    properties:
      strategy:
        type: string
        description: >
          Affects how the scenarios are executed.
          The default `round-robin` iterates over the every scenario in the order they were defined.
          `random` picks a random scenario from the available pool every time.
        default: round-robin
        enum:
        - round-robin
        - random
      runs:
        description: >
          If set, it will exit after the given number of scenario runs. By default, it continues forever.
        type: number
        minimum: 1
      minSecondsBetweenRuns:
        description: >
          The Seal waits a randomized amount of time before executing the scenarios.
          This sets the MIN number of seconds that it will wait.
        type: number
        minimum: 0
        default: 30
      maxSecondsBetweenRuns:
        description: >
          The Seal waits a randomized amount of time before executing the scenarios.
          This sets the MAX number of seconds that it will wait.
        type: number
        minimum: 0
        default: 300

  exitStrategy:
    description: "Configure how exit is configured"
    type: object
    additionalProperties: false
    properties:
      strategy:
        type: string
        description: >
          Affects what PowerfulSeal does when errors occur.
          The default `report` logs an error message, updates metrics and carries on.
          `fail-fast` fails and exits immediately on first exit (useful when running as a job).
        default: report
        enum:
        - report
        - fail-fast

  scenario:
    description: >
      A scenario contains all the steps necessary to prepare, implement and validate a chaos engineering experiment.
    type: object
    additionalProperties: false
    properties:
      name:
        type: string
        description: >
          A brief, descriptive name of the scenario. Will be used to identify the scenario in logs.
        minLength: 3
        maxLength: 80
      description:
        type: string
        description: >
          A longer description, helping to understand what the scenario is doing when reading the yaml file.
          Optional.
      steps:
        type: array
        description: >
          The sequence of events to prepare, validate, execute and analyse the chaos engineering experiment.
        items:
          oneOf:
          - "$ref": "#/definitions/probeHTTP"
          - "$ref": "#/definitions/kubectl"
          - "$ref": "#/definitions/podAction"
          - "$ref": "#/definitions/nodeAction"
          - "$ref": "#/definitions/waitAction"
    required:
    - name
    - steps

  nodeAction:
    description: >
      Match, filter and action on nodes in your kubernetes cluster.
      It can integrate with your cloud provider and take nodes up and down to simulate VMs going down.
      If you're running in SSH mode, it can also execute various commands on hosts. And much more!
      See below for mode details.
    type: object
    additionalProperties: false
    properties:
      nodeAction:
        type: object
        additionalProperties: false
        properties:
          matches:
            type: array
            description: >
              An array of match criteria to select a set of nodes. Will be deduplicated.
            items:
              oneOf:
              - "$ref": "#/definitions/filterPropertyNode"
          filters:
            type: array
            description: >
              An array of filters, which will be applied in the defined order.
            items:
              type: object
              oneOf:
              - "$ref": "#/definitions/filterPropertyNode"
              - "$ref": "#/definitions/filterDayTime"
              - "$ref": "#/definitions/filterRandomSample"
              - "$ref": "#/definitions/filterProbability"
          actions:
            type: array
            description: >
              An array of actions, which will be executed on each node.
            items:
              type: object
              oneOf:
              - "$ref": "#/definitions/actionStartNode"
              - "$ref": "#/definitions/actionStopNode"
              - "$ref": "#/definitions/actionExecuteNode"
              - "$ref": "#/definitions/actionWait"
        required:
        - matches
        - actions
    required:
    - nodeAction

  podAction:
    description: >
      Match, filter and action on pods in your kubernetes cluster.
      Matchers create the initial set.
      That set is de-duplicated and passed on to the filters.
      Filters can exclude items.
      Whatever is passed through the filters will then be actioned with every action in the action array.
      See below for the details of the configuration available.
    type: object
    additionalProperties: false
    properties:
      podAction:
        type: object
        additionalProperties: false
        properties:
          matches:
            type: array
            description: >
              An array of match criteria to select a set of pods. Will be deduplicated.
            items:
              oneOf:
              - "$ref": "#/definitions/matchPodNamespace"
              - "$ref": "#/definitions/matchPodDeploymentAndNamespace"
              - "$ref": "#/definitions/matchPodLabelsAndNamespace"
          filters:
            type: array
            description: >
              An array of filters to only select certain pods from the initial set.
            items:
              type: object
              oneOf:
              - "$ref": "#/definitions/filterPropertyPod"
              - "$ref": "#/definitions/filterDayTime"
              - "$ref": "#/definitions/filterRandomSample"
              - "$ref": "#/definitions/filterProbability"
          actions:
            type: array
            description: >
              An array of actions to be applied to each pod from the set.
            items:
              type: object
              oneOf:
              - "$ref": "#/definitions/actionKillPod"
              - "$ref": "#/definitions/actionWait"
              - "$ref": "#/definitions/checkPodState"
              - "$ref": "#/definitions/checkPodCount"
              - "$ref": "#/definitions/stopPodsHostAction"
        required:
        - matches
        - actions
    required:
    - podAction

  kubectl:
    description: >
      Allows to execute a `kubectl apply` or `kubectl delete` command as part of the scenario.
    type: object
    additionalProperties: false
    properties:
      kubectl:
        type: object
        additionalProperties: false
        properties:
          action:
            type: string
            enum:
            - apply
            - delete
          payload:
            type: string
            description: >
              Free-form, kubectl-compatible payload, which will be passed to kubectl as is.
          autoDelete:
            type: boolean
            description:
              When set to true, all the `kubectl apply` commands will be `kubectl delete`ed at the end of the scenario.
            default: true
          proxy:
            type: string
            description: >
              Proxy to use with the kubectl command.
              If not set no proxy will be used.
              NOTE, that the probe ignores (and overrides) HTTP{S}_PROXY envvars.
            default: ""
          kubectlBinary:
            type: string
            description: >
              The path to the binary of kubectl.
            default: "kubectl"
        required:
        - action
        - payload
    required:
    - kubectl

  probeHTTP:
    description: >
      Issue an HTTP request and validate the response.
    type: object
    additionalProperties: false
    properties:
      probeHTTP:
        type: object
        additionalProperties: false
        properties:
          target:
            type: object
            oneOf:
            - "$ref": "#/definitions/targetURL"
            - "$ref": "#/definitions/targetService"
          retries:
            type: number
            description: >
              Number of retries before failing the probe.
              Ignored, if there are no errors on the probe.
            default: 3
            minimum: 1
          delay:
            type: number
            description: >
              Delay in ms between retries.
            default: 100
            minimum: 1
          timeout:
            type: number
            description: >
              Request timeout in ms.
            default: 1000
            minimum: 1
          code:
            type: number
            description: >
              Expected status code.
            default: 200
            minimum: 1
            maximum: 599
          count:
            type: number
            description: >
              Number of requests to make.
            default: 1
            minimum: 1
          endpoint:
            type: string
            description: >
              Endpoint to add to the url.
              For example `/healthz`.
              Works for both url and service.
          method:
            type: string
            description: >
              HTTP method to use.
            default: get
            enum:
            - get
            - post
            - patch
            - head
            - delete
          body:
            type: string
            description: >
              Body of the HTTP request.
          headers:
            description: >
              Give any additional headers to the request.
            type: array
            items:
              type: object
              additionalProperties: false
              properties:
                name:
                  type: string
                value:
                  type: string
          proxy:
            type: string
            description: >
              Proxy to use with the requests.
              If not set no proxy will be used.
              NOTE, that the probe ignores (and overrides) HTTP{S}_PROXY envvars.
          insecure:
            type: boolean
            description: >
              If you'd like to skip the SSL validation.
              For example for self-signed certs.
            default: false
        required:
        - target
    required:
    - probeHTTP

  waitAction:
    description: >
      Allows to wait a number of seconds.
    type: object
    additionalProperties: false
    properties:
      wait:
        type: object
        additionalProperties: false
        properties:
          seconds:
            type: number
            minimum: 0
        required:
        - seconds
    required:
    - wait


  stopPodsHostAction:
    description: >
      Stops the host on which the pods are running.
    type: object
    additionalProperties: false
    properties:
      stopHost:
        type: object
        additionalProperties: false
        properties:
          autoRestart:
            type: boolean
            description:
              When set to true, the node will be restarted at the end of the scenario.
            default: true
    required:
    - stopHost


###################################################################################################
# MATCHERS
###################################################################################################

  matchPodNamespace:
    type: object
    additionalProperties: false
    description: >
      Pick all pods for a deployment in a namespace.
    properties:
      namespace:
        type: string
    required:
    - namespace

  matchPodDeploymentAndNamespace:
    type: object
    description: >
      Pick all pods for a deployment in a namespace.
    additionalProperties: false
    properties:
      deployment:
        type: object
        additionalProperties: false
        properties:
          name:
            type: string
          namespace:
            type: string
        required:
        - name
        - namespace
    required:
    - deployment

  matchPodLabelsAndNamespace:
    type: object
    description: >
      Pick all pods matching the particular set of labels in a namespace.
    additionalProperties: false
    properties:
      labels:
        type: object
        additionalProperties: false
        properties:
          selector:
            type: string
          namespace:
            type: string
        required:
        - selector
        - namespace
    required:
    - labels


###################################################################################################
# FILTERS
###################################################################################################

  filterRandomSample:
    type: object
    description: >
      Take a random sample.
      Either a specific size (up to N), or a ratio (0.5 == 50%) of the initial size.
    additionalProperties: false
    properties:
      randomSample:
        type: object
        additionalProperties: false
        properties:
          size:
            type: number
            minimum: 1
          ratio:
            type: number
            minimum: 0
            maximum: 1
    required:
    - randomSample

  filterProbability:
    type: object
    description: >
      Only pass the filter with a desired probability.
    additionalProperties: false
    properties:
      probability:
        type: number
        minimum: 0
        maximum: 1
    required:
    - probability

  filterDayTime:
    type: object
    description: >
      Only pass the filter during specific time of the day and week.
    additionalProperties: false
    properties:
      dayTime:
        type: object
        additionalProperties: false
        properties:
          onlyDays:
            type: array
            items:
              type: string
              enum:
              - monday
              - tuesday
              - wednesday
              - thursday
              - friday
              - saturday
              - sunday
          startTime:
            type: object
            "$ref": "#/definitions/time"
          endTime:
            type: object
            "$ref": "#/definitions/time"
        required:
        - onlyDays
        - startTime
        - endTime
    required:
    - dayTime

  filterPropertyNode:
    type: object
    description: >
      Select nodes by property values.
    additionalProperties: false
    properties:
      property:
        type: object
        additionalProperties: false
        properties:
          name:
            type: string
            enum:
            - name
            - ip
            - group
            - az
            - state
          value:
            type: string
          negative:
            type: boolean
            description: Set to true to negate the match (logical NOT)
            default: false
        required:
        - name
        - value
    required:
    - property

  filterPropertyPod:
    type: object
    description: >
      Select pods by property values.
    additionalProperties: false
    properties:
      property:
        type: object
        additionalProperties: false
        properties:
          name:
            type: string
            enum:
            - name
            - state
          value:
            type: string
          negative:
            type: boolean
            description: Set to true to negate the match (logical NOT)
            default: false
        required:
        - name
        - value
    required:
    - property


###################################################################################################
# ACTIONS
###################################################################################################

  actionStartNode:
    type: object
    description: >
      Start a node.
    additionalProperties: false
    properties:
      start:
        type:
        - object
        - 'null'
        additionalProperties: false
    required:
    - start

  actionStopNode:
    type: object
    description: >
      Stop a node.
    additionalProperties: false
    properties:
      stop:
        type: object
        additionalProperties: false
        properties:
          force:
            type: boolean
          autoRestart:
            type: boolean
            description:
              When set to true, the node will be restarted at the end of the scenario.
            default: true
    required:
    - stop

  actionExecuteNode:
    type: object
    description: >
      Executes arbitrary command on a particular node. Use with caution.
    additionalProperties: false
    properties:
      execute:
        type: object
        additionalProperties: false
        properties:
          cmd:
            type: string
        required:
        - cmd
    required:
    - execute

  actionWait:
    type: object
    description: >
      Wait some seconds.
    additionalProperties: false
    properties:
      wait:
        type: object
        additionalProperties: false
        properties:
          seconds:
            type: number
            minimum: 0
        required:
        - seconds
    required:
    - wait

  actionKillPod:
    type: object
    description: >
      Kill a pod.
    additionalProperties: false
    properties:
      kill:
        type: object
        additionalProperties: false
        properties:
          probability:
            type: number
            minimum: 0
            maximum: 1
          force:
            type: boolean
    required:
    - kill

  checkPodCount:
    type: object
    description: >
      Count the pods and fail if they don't match the desired number.
    additionalProperties: false
    properties:
      checkPodCount:
        type: object
        additionalProperties: false
        properties:
          count:
            type: number
        required:
        - count
    required:
    - checkPodCount

  checkPodState:
    type: object
    description: >
      Check that all pods are in the desired state, fail otherwise.
    additionalProperties: false
    properties:
      checkPodState:
        type: object
        additionalProperties: false
        properties:
          state:
            description: >
              Status, as returned by kubernetes (`Running`, `Terminating`, etc).
            type: string
        required:
        - state
    required:
    - checkPodState


###################################################################################################
# MISC
###################################################################################################

  time:
    type: object
    description: >
      Describes a time of the day, in the local timezone.
    additionalProperties: false
    properties:
      hour:
        type: number
        minimum: 0
        maximum: 23
      minute:
        type: number
        minimum: 0
        maximum: 59
      second:
        type: number
        minimum: 0
        maximum: 59
    required:
    - hour
    - minute
    - second

  targetURL:
    type: object
    description: >
      A target of a static URL.
    additionalProperties: false
    properties:
      url:
        type: string
        description: >
          The fully qualified url to issue the request to.
          For example: `http://example.com`.
    required:
    - url

  targetService:
    type: object
    description: >
      Target the given `Kubernetes` service in a given namespace.
      It will use directly the IP of the given service, so make sure it resolves.
    additionalProperties: false
    properties:
      service:
        type: object
        additionalProperties: false
        properties:
          name:
            type: string
            description: >
              Name of the kubernetes service.
          namespace:
            type: string
            description: >
              Namespace of the kubernetes service.
          port:
            type: number
            minimum: 1
            maximum: 65535
            default: 80
            description: >
              Port number to hit. Independent of what the service defines.
          protocol:
            type: string
            enum:
            - http
            - https
            default: http
            description: >
              Protocol to use for the probe.
        required:
        - name
        - namespace
    required:
    - service
