{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://catalog.lintel.tools/schemas/schemastore/cdk-environment-manager-environment-definition/latest.json",
  "title": "Environment Definition",
  "description": "Definition of an application environment",
  "x-lintel": {
    "source": "https://www.schemastore.org/ti8m-cdk-environment-definition.json",
    "sourceSha256": "9b082dc1a0b6f10ad1ad9f0d104e855d09085af908d04c424235f814b929e0e1",
    "fileMatch": [
      "**/environment-definition.json",
      "**/environment-definition.yaml",
      "**/environment-definition.yml"
    ],
    "parsers": [
      "json",
      "yaml"
    ]
  },
  "type": "object",
  "properties": {
    "app": {
      "type": "string",
      "description": "the name of the application-(component) defined by this environment"
    },
    "config-set": {
      "type": "object",
      "description": "configuration sets, which can be referenced from the service definitions",
      "additionalProperties": {
        "$ref": "#/$defs/serviceConfiguration",
        "description": "A set of service-configurations applied to several services in the same way."
      }
    },
    "services": {
      "type": "array",
      "description": "list of services which are part of this environment",
      "items": {
        "type": "object",
        "allOf": [
          {
            "$ref": "#/$defs/serviceConfiguration"
          },
          {
            "type": "object",
            "properties": {
              "alias": {
                "type": "string",
                "description": "a convenient name, unique within the environment."
              },
              "name": {
                "type": "string",
                "description": "the name of the service, usually prefixed by the environment name to continue the historic way of supporting plain docker/docker-compose environments"
              },
              "hostname": {
                "type": "string",
                "description": "the hostname of the docker-container, to override the automatic created hostnames for docker-compose environments"
              },
              "external-name": {
                "type": "string",
                "description": "the external name of the service, this is usually a DNS name for an external service, e.g. api.google.com"
              },
              "image": {
                "type": "string",
                "description": "URL of the docker registry containing the services image"
              },
              "config-sets": {
                "type": "array",
                "description": "list of configuration sets to be applied to this service",
                "items": {
                  "type": "string"
                }
              },
              "exposed-route": {
                "type": "object",
                "description": "Additional properties for routes",
                "properties": {
                  "timeout": {
                    "type": "string",
                    "description": "the timeout in minutes or seconds (e.g. 10m, 10s)"
                  },
                  "rewrite-target": {
                    "type": "string",
                    "description": "the target path for url rewrites (replaces the entry path of the route)"
                  }
                }
              }
            },
            "required": [
              "name",
              "alias"
            ]
          }
        ]
      }
    }
  },
  "required": [
    "app"
  ],
  "$defs": {
    "serviceConfiguration": {
      "type": "object",
      "properties": {
        "environment": {
          "type": "object",
          "description": "List of environment variables set in the Container/Pod",
          "additionalProperties": false,
          "patternProperties": {
            "^.*$": {
              "anyOf": [
                {
                  "type": "object",
                  "properties": {
                    "keyRefName": {
                      "type": "string",
                      "description": "the name of the secret to reference"
                    },
                    "key": {
                      "type": "string",
                      "description": "the (entry) key of the referenced secret"
                    }
                  },
                  "additionalProperties": false
                },
                {
                  "type": "string",
                  "description": "plain simple value of the variable"
                },
                {
                  "type": "number",
                  "description": "plain simple value of the variable"
                },
                {
                  "type": "boolean",
                  "description": "plain simple value of the variable"
                }
              ]
            }
          }
        },
        "entrypoint": {
          "type": "string",
          "description": "The entrypoint that is used to start the image (Only works with docker-compose and OpenShift"
        },
        "additionalLabels": {
          "type": "object",
          "properties": {
            "deployment": {
              "$ref": "#/$defs/labels",
              "type": "object",
              "description": "List of labels for deployments"
            },
            "service": {
              "$ref": "#/$defs/labels",
              "type": "object",
              "description": "List of labels for services"
            }
          },
          "additionalProperties": false
        },
        "liveness": {
          "$ref": "#/$defs/probe",
          "type": "object",
          "description": "Defines a check, failure of which leads to the restart of the service"
        },
        "startup": {
          "$ref": "#/$defs/probe",
          "type": "object",
          "description": "A startup probe indicates whether the application within a container is started. All other probes are disabled until the startup succeeds"
        },
        "readiness": {
          "$ref": "#/$defs/probe",
          "type": "object",
          "description": "Defines a check, failure of which leads to the service not receiving any requests"
        },
        "deploymentStrategy": {
          "type": "object",
          "description": "How to roll out changed versions of the service (Recreate or Rolling)",
          "properties": {
            "type": {
              "enum": [
                "Rolling",
                "Recreate"
              ],
              "default": "Recreate"
            },
            "params": {
              "type": "object",
              "properties": {
                "updatePeriodSeconds": {
                  "type": "number",
                  "description": "Number of seconds to wait between pod updates"
                },
                "intervalSeconds": {
                  "type": "number",
                  "description": "Number of seconds to wait between evaluations of the deployment status"
                },
                "timeoutSeconds": {
                  "description": "Time to wait for a successful scale-up before rolling back to the previous deployment",
                  "oneOf": [
                    {
                      "type": "number"
                    },
                    {
                      "$ref": "#/$defs/templateParameterReference"
                    }
                  ]
                },
                "maxSurge": {
                  "description": "Maximum temporary excess number of pods above the desired number of replicas",
                  "oneOf": [
                    {
                      "type": "number"
                    },
                    {
                      "$ref": "#/$defs/templateParameterReference"
                    }
                  ]
                },
                "maxUnavailable": {
                  "description": "Maximum temporarily lacking pods compared to the desired number of replicas",
                  "oneOf": [
                    {
                      "type": "number"
                    },
                    {
                      "$ref": "#/$defs/templateParameterReference"
                    }
                  ]
                }
              }
            }
          }
        },
        "needsDbSchema": {
          "type": "boolean",
          "description": "true, if this service needs a database schema to persist information."
        },
        "pull-policy": {
          "type": "string",
          "description": "Image pull policy for openshift. Default: IfNotPresent",
          "enum": [
            "IfNotPresent",
            "Always"
          ]
        },
        "service-account": {
          "type": "string",
          "description": "The service account to use for Openshift."
        },
        "service-account-name": {
          "type": "string",
          "description": "The name of the service account to use for Openshift."
        },
        "host-aliases": {
          "$ref": "#/$defs/host-aliases",
          "type": "array",
          "description": "Host entries added to /etc/hosts file"
        },
        "replicas": {
          "description": "Number of desired instances.",
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/templateParameterReference"
            }
          ]
        },
        "resources": {
          "$ref": "#/$defs/resourceSpec",
          "description": "Specifies resource usage of a container instance"
        },
        "deploymentResources": {
          "$ref": "#/$defs/resourceSpec",
          "type": "object",
          "description": "Specifies resource usage of a deployment container instance"
        },
        "nodeSelector": {
          "$ref": "#/$defs/nodeSelector",
          "type": "array",
          "description": "Label for a desired node selector"
        },
        "tolerations": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/toleration"
          },
          "description": "Tolerations section for Openshift"
        },
        "podAntiAffinity": {
          "$ref": "#/$defs/podAntiAffinity",
          "type": "array",
          "description": "podAntiAffinity"
        },
        "port-override": {
          "$ref": "#/$defs/port-override",
          "type": "array",
          "description": "ports exposed by the service"
        },
        "nlb": {
          "type": "boolean",
          "description": "marks this service as 'network load-balanced'. On AWS this is a simple alternative to setting up a router and ingresses, which is the preferred method."
        },
        "config-files": {
          "$ref": "#/$defs/config-files",
          "type": "array",
          "description": "configuration files to be mapped into the pod"
        },
        "secret-files": {
          "$ref": "#/$defs/secret-files",
          "type": "array",
          "description": "secret files to be mounted in the pod"
        },
        "volumes": {
          "oneOf": [
            {
              "$ref": "#/$defs/volumes",
              "type": "array",
              "description": "Volumes claimed by the service - these are usable cluster environments as well as docker-compose"
            },
            {
              "type": "object",
              "description": "For docker-compose targets: Keys in this object are directories on the host (if they contain slashes), or names of global volumes (if there are no slashes)",
              "additionalProperties": true
            }
          ]
        },
        "customData": {
          "type": "object",
          "description": "Custom data object which will be passed as is into the render context",
          "additionalProperties": true
        },
        "expose": {
          "$ref": "#/$defs/expose"
        },
        "template-parameters": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/templateParameter"
          }
        },
        "external-port": {
          "type": "number"
        },
        "external-ip": {
          "type": "string"
        },
        "disableAutomountServiceAccountToken": {
          "description": "(K8s/OpenShift only) Indicates whether a service account token should be mounted",
          "type": "boolean"
        },
        "disableServiceLinks": {
          "description": "(K8s/OpenShift only) Indicates whether information about services should be injected into pod's environment variables, matching the syntax of Docker links",
          "type": "boolean"
        },
        "revisionHistoryLimit": {
          "description": "(K8s/OpenShift only) The number of old ReplicationControllers to retain to allow for rollbacks",
          "type": "number"
        }
      }
    },
    "probe": {
      "type": "object",
      "oneOf": [
        {
          "properties": {
            "path": {
              "type": "string",
              "description": "the url-path to http-GET for the check."
            },
            "port": {
              "type": "string",
              "description": "the port on which to http-GET the path for checking this service"
            },
            "scheme": {
              "type": "string",
              "description": "(optional) the scheme used for the probe HTTP or HTTPS defaults to HTTP",
              "pattern": "(HTTP|HTTPS)"
            }
          },
          "required": [
            "port",
            "path"
          ],
          "type": "object"
        },
        {
          "properties": {
            "tcpSocket": {
              "type": "string",
              "description": "the port on which to tcp checking this service"
            }
          },
          "required": [
            "tcpSocket"
          ],
          "type": "object"
        },
        {
          "properties": {
            "commands": {
              "type": "array",
              "description": "list of probe commands",
              "items": {
                "type": "object",
                "properties": {
                  "arg": {
                    "type": "string",
                    "description": "argument"
                  }
                }
              }
            }
          },
          "required": [
            "commands"
          ],
          "type": "object"
        }
      ],
      "properties": {
        "initialDelay": {
          "type": "number",
          "description": "(optional) the initial delay to wait before starting to probe in seconds"
        },
        "timeout": {
          "type": "number",
          "description": "(optional) the time in seconds to wait for an http response for each call to the probe endpoint"
        },
        "failureThreshold": {
          "type": "integer",
          "minimum": 1,
          "description": "(optional) the number of times the probe is allowed to fail the health check before performing its duty (e.g., recreating a pod or marking a pod as unavailable)"
        },
        "successThreshold": {
          "type": "integer",
          "minimum": 1,
          "description": "(optional) the number of times the probe has to pass the health check before performing its duty (e.g., marking a pod as available)"
        }
      }
    },
    "resourceSpec": {
      "type": "object",
      "properties": {
        "limits": {
          "$ref": "#/$defs/resources",
          "type": "object",
          "description": "Upper limits of resources available to a container instance"
        },
        "requests": {
          "$ref": "#/$defs/resources",
          "type": "object",
          "description": "Amount of resources necessary to run a container instance. Must be less than limits."
        }
      }
    },
    "nodeSelector": {
      "type": "object",
      "properties": {
        "key": {
          "type": "string",
          "description": "nodeSelector key"
        },
        "value": {
          "type": "string",
          "description": "nodeSelector value"
        }
      }
    },
    "podAntiAffinity": {
      "type": "object",
      "properties": {
        "key": {
          "type": "string",
          "description": "podAntiAffinity key"
        },
        "operator": {
          "type": "string",
          "description": "podAntiAffinity operator"
        },
        "values": {
          "type": "array",
          "description": "podAntiAffinity values",
          "items": {
            "type": "string"
          }
        },
        "topologyKey": {
          "type": "string",
          "description": "podAntiAffinity topologyKey"
        }
      }
    },
    "toleration": {
      "type": "object",
      "properties": {
        "key": {
          "type": "string",
          "description": "Toleration key. The key is any string, up to 253 characters. The key must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores."
        },
        "operator": {
          "type": "string",
          "description": "Toleration operator. The operator is one of the following: Equal or Exists"
        },
        "value": {
          "type": "string",
          "description": "Toleration value. The value is any string, up to 63 characters. The value must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores."
        },
        "effect": {
          "type": "string",
          "description": "Toleration effect. The effect is one of the following: NoSchedule, PreferNoSchedule or NoExecute"
        }
      }
    },
    "resources": {
      "type": "object",
      "properties": {
        "cpu": {
          "description": "The number of cores, can be specified as integer cores, or in milli-cores (eg: '100m')",
          "oneOf": [
            {
              "$ref": "#/$defs/templateParameterReference"
            },
            {
              "type": "string",
              "pattern": "\\d+m?"
            }
          ]
        },
        "memory": {
          "description": "The amount of main memory in either of M,G (base 10) or Mi, Gi (base 2). (eg: '3Gi')",
          "oneOf": [
            {
              "type": "string",
              "pattern": "\\d+(M|G|Mi|Gi)"
            },
            {
              "$ref": "#/$defs/templateParameterReference"
            }
          ]
        }
      },
      "required": [
        "cpu",
        "memory"
      ]
    },
    "config-files": {
      "type": "array",
      "description": "list of configuration files to be mapped into the service-container",
      "items": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "description": "name of the source file"
          },
          "target": {
            "type": "string",
            "description": "name & path of the file inside the container"
          },
          "isBinaryFile": {
            "type": "boolean",
            "description": "Whether the file is binary. Needed for kubernetes environments so that binaryData is used in the ConfigMap.",
            "default": false
          }
        }
      }
    },
    "secret-files": {
      "type": "array",
      "description": "list of secret files to be mounted in the service-container",
      "items": {
        "type": "object",
        "required": [
          "secret",
          "mountPath"
        ],
        "properties": {
          "secret": {
            "type": "string",
            "description": "Name of the secret to be mounted. If no key and target specified, all the items of the secret will be mounted in the mount path.",
            "examples": [
              "truststore"
            ]
          },
          "mountPath": {
            "type": "string",
            "description": "Mount path in the target service-container where the secret files will be available.",
            "examples": [
              "/secrets"
            ]
          },
          "key": {
            "type": "string",
            "description": "(Optional) Specifies the use of a single item of the secret identified by its key.",
            "examples": [
              "truststore.jks"
            ]
          },
          "target": {
            "type": "string",
            "description": "(Optional) When using a specific secret item, then target file name needs to be specified.",
            "examples": [
              "truststore.jks"
            ]
          }
        }
      }
    },
    "volumes": {
      "type": "array",
      "description": "list of volumes needed by this service, may result in persistent volume-claims or transient volumes",
      "items": {
        "type": "object",
        "properties": {
          "persistentVolumeClaimName": {
            "type": "string",
            "description": "existing pvc Name that is already existing on openshift"
          },
          "path": {
            "type": "string",
            "description": "path onto which the volume will be mounted"
          },
          "size": {
            "type": "string",
            "description": "the requested size of the volume in Mega- or Giga-Byte. If this is specified, it will generate a volume-claim, if not an anonymous volume of type emptyDir will be created",
            "pattern": "\\d+(M|G|Mi|Gi)"
          },
          "shared": {
            "type": "boolean",
            "description": "whether or not the volume can be mounted by multiple nodes, generates a global volume for docker-compose environments"
          }
        },
        "required": [
          "path"
        ]
      }
    },
    "labels": {
      "type": "object",
      "description": "List of labels",
      "additionalProperties": false,
      "patternProperties": {
        "^.*$": {
          "type": "string"
        }
      }
    },
    "host-aliases": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "ip": {
            "type": "string",
            "description": "IP of the hostalias"
          },
          "hostnames": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "hostname": {
                  "type": "string",
                  "description": "Hostname"
                }
              }
            }
          }
        }
      }
    },
    "port-override": {
      "type": "array",
      "items": {
        "oneOf": [
          {
            "type": "number"
          },
          {
            "type": "object",
            "properties": {
              "port": {
                "type": "number",
                "description": "port number exposed by the container"
              },
              "externalPort": {
                "type": "number",
                "description": "port number exposed to clients (service port). If omitted implicitly equal to the port"
              },
              "nodePort": {
                "description": "port number exposed on the Kubernetes cluster nodes. This generates a separate Service of type NodePort, if set.",
                "oneOf": [
                  {
                    "type": "number"
                  },
                  {
                    "$ref": "#/$defs/templateParameterReference"
                  }
                ]
              },
              "portLabel": {
                "type": "string",
                "description": "name of the port"
              }
            }
          }
        ]
      }
    },
    "expose": {
      "anyOf": [
        {
          "$ref": "#/$defs/exposure"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/exposure"
          }
        }
      ]
    },
    "exposure": {
      "type": "object",
      "description": "defines, which endpoints, if any, to expose to the outside of the cluster",
      "properties": {
        "hostname": {
          "type": "string",
          "description": "The host to be used for this exposure, the global cluster host is the default."
        },
        "path": {
          "type": "array",
          "description": "list of paths (path-beginnings) to be routed to this service",
          "items": {
            "type": "string"
          }
        },
        "port": {
          "type": "integer",
          "description": "the internal port of the service that exposes the path"
        },
        "tls-termination": {
          "type": "string",
          "description": "TLS termination on OpenShift",
          "enum": [
            "edge",
            "passthrough",
            "reencrypt"
          ]
        }
      },
      "required": [
        "path"
      ]
    },
    "templateParameterReference": {
      "type": "string",
      "pattern": "\\$\\{\\{?.+\\}?\\}"
    },
    "templateParameter": {
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "value": {
          "type": "string"
        },
        "description": {
          "type": "string"
        }
      },
      "required": [
        "description",
        "name",
        "value"
      ]
    }
  }
}
