From 891aa81b7a3dc6940209e6f0bf1465f1626565a8 Mon Sep 17 00:00:00 2001 From: Alexander Mattoni <5110855+mattoni@users.noreply.github.com> Date: Tue, 16 Apr 2024 12:46:52 -0700 Subject: [PATCH] Update telemetry options for tcp/udp --- .../v1/transports/HttpTransportConfig.yml | 9 ++++++++- .../v1/transports/TcpTransportConfig.yml | 19 +++++++++++++++++++ .../v1/transports/UdpTransportConfig.yml | 19 +++++++++++++++++++ stackspec/stackspec.json | 2 +- 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/HttpTransportConfig.yml b/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/HttpTransportConfig.yml index f9900cec..81170c24 100644 --- a/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/HttpTransportConfig.yml +++ b/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/HttpTransportConfig.yml @@ -33,19 +33,26 @@ properties: - disable_url_tracking - disable_router_metrics properties: + persist_restarts: + type: + - boolean + - "null" + description: If true, Cycle will maintain telemetry/metrics across load balancer restarts. disable_url_tracking: description: "Determines if the load balancer will track url metrics. Defaults to false." type: boolean + default: false disable_router_metrics: description: "Determines if the load balancer will track router metrics. Defaults to false." type: boolean + default: false max_trackable_urls: description: "Determines how many URLs the load balancer will track at one time. Defaults to 150." type: - integer - "null" tracking_window: - description: "Determines how long the load balancer will track a URL from its last hit. Helps reduce noise by not tracking URLs that are occasionally hit. Defaults to 8h." + description: "Determines how long the load balancer will track a URL from its last hit. If there is zero activity for this duration, the metrics will be dropped. Helps reduce noise by not tracking URLs that are occasionally hit. Defaults to 8h." anyOf: - $ref: ../../../../../../../Duration.yml - type: "null" diff --git a/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/TcpTransportConfig.yml b/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/TcpTransportConfig.yml index 7639b622..0e2f0586 100644 --- a/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/TcpTransportConfig.yml +++ b/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/TcpTransportConfig.yml @@ -13,7 +13,26 @@ properties: type: object required: - connections + - telemetry properties: connections: type: object additionalProperties: {} + telemetry: + type: object + description: Configuration options for how telemetry is handled on the load balancer. + properties: + persist_restarts: + type: + - boolean + - "null" + description: If true, Cycle will maintain telemetry/metrics across load balancer restarts. + disable_router_metrics: + description: "Determines if the load balancer will track router metrics. Defaults to false." + type: boolean + default: false + tracking_window: + description: "Determines how long the load balancer will track a URL from its last hit. If there is zero activity for this duration, the metrics will be dropped. Helps reduce noise by not tracking URLs that are occasionally hit. Defaults to 8h." + anyOf: + - $ref: ../../../../../../../Duration.yml + - type: "null" diff --git a/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/UdpTransportConfig.yml b/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/UdpTransportConfig.yml index 549133e6..e99724f2 100644 --- a/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/UdpTransportConfig.yml +++ b/components/schemas/stacks/spec/services/loadbalancer/types/v1/transports/UdpTransportConfig.yml @@ -13,7 +13,26 @@ properties: type: object required: - connections + - telemetry properties: connections: type: object additionalProperties: {} + telemetry: + type: object + description: Configuration options for how telemetry is handled on the load balancer. + properties: + persist_restarts: + type: + - boolean + - "null" + description: If true, Cycle will maintain telemetry/metrics across load balancer restarts. + disable_router_metrics: + description: "Determines if the load balancer will track router metrics. Defaults to false." + type: boolean + default: false + tracking_window: + description: "Determines how long the load balancer will track a URL from its last hit. If there is zero activity for this duration, the metrics will be dropped. Helps reduce noise by not tracking URLs that are occasionally hit. Defaults to 8h." + anyOf: + - $ref: ../../../../../../../Duration.yml + - type: "null" diff --git a/stackspec/stackspec.json b/stackspec/stackspec.json index 0f5149f8..e7bc88bb 100644 --- a/stackspec/stackspec.json +++ b/stackspec/stackspec.json @@ -1 +1 @@ -{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"StackSpec","description":"A Cycle stack file is an \"environment as code\". Anything that can be done in an environment on Cycle can be described in a stack file and deployed as a new environment.\nStack files can list multiple containers and their configurations, load balancer settings, scoped variables, and much more.\n","type":"object","required":["version","containers"],"properties":{"version":{"type":"string","description":"The version of the Cycle stack file used.","enum":["1.0"]},"about":{"description":"Various properties describing this stack.","type":["object","null"],"required":["description","version"],"properties":{"version":{"type":"string","description":"A custom, user-defined version of the stack."},"description":{"type":"string","description":"Custom, user-defined details about this stack."}}},"scoped_variables":{"description":"Describes variables that are assigned to one or more containers at runtime. Can be assigned as an environment variable, written as a file inside the container(s), or accessed over the internal API.","type":["array","null"],"items":{"title":"StackSpecScopedVariable","type":"object","required":["identifier","scope","access"],"properties":{"identifier":{"title":"Identifier","type":"string","description":"A human-readable identifier used to refer to a resource, where using the official ID may be inconvenient.\nThe identifier is automatically tokenized from the name/relevant field of the resource if one is not provided. For example, a container named \"My Container\" will\nhave the identifier of `my-container` and is automatically created by the platform.\n\nThe identifier does not have to be unique.\n"},"scope":{"type":"object","required":["containers"],"properties":{"containers":{"type":"object","description":"Describes the containers that have access to this scoped variable.","required":["global"],"properties":{"global":{"type":"boolean","description":"If true, all containers in the environment will have access to this variable."},"ids":{"type":["array","null"],"description":"A list of container IDs that are granted access to this variable.","items":{"type":"string"}},"identifiers":{"type":["array","null"],"description":"A list of container identifiers that are granted access to this variable.","items":{"$ref":"#/properties/scoped_variables/items/properties/identifier"}}}}}},"access":{"type":"object","properties":{"env_variable":{"description":"Grants access to this variable from within a container as an environment variable.","type":["object","null"],"required":["key"],"properties":{"key":{"description":"The environment variable inside the container that stores the value of the variable.","type":"string"}}},"internal_api":{"description":"Grants access to this variable over the Internal API.","type":["object","null"],"properties":{"duration":{"description":"Sets the duration that this variable can be accessed over the Internal API, after container start. Provides additional security as sensitive data can only be accessed for a limited time.","anyOf":[{"title":"Duration","type":"string","description":"A string signifying a duration of time. Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\", \"d\", \"w\", \"y\".","example":"72h45m2s"},{"type":"null"}]}}},"file":{"description":"Grants access to this variable as a file inside the container.","type":["object","null"],"required":["decode","path"],"x-ogen-properties":{"decode":{"name":"DecodeBase64"}},"properties":{"decode":{"description":"When true, Cycle will interpret this variable as a base-64 encoded string, and decode it before writing it to the file inside the container.","type":"boolean"},"path":{"type":["string","null"],"example":"/var/run/cycle/variables/","description":"The absolute path to write the variable to (including file name). If `null`, it will be written to `/var/run/cycle/variables/{variable-identifier}`."}}}}},"source":{"type":["object","null"],"description":"Describes the source/value of the variable.\n- **raw**: Directly set the value of the variable in the stack. - **url**: Cycle will fetch the variable content from a remote source when the container starts.\n","discriminator":{"propertyName":"type","mapping":{"url":"./StackSpecScopedVariableUrlSource.yml","raw":"./StackSpecScopedVariableRawSource.yml"}},"oneOf":[{"title":"StackSpecScopedVariableUrlSource","type":"object","description":"A variable who's value is fetched from a URL when the container starts.","required":["type","details"],"properties":{"type":{"type":"string","description":"The type of scoped variable.","enum":["url"]},"details":{"type":"object","required":["url","headers","auth_token_url"],"properties":{"url":{"type":"string","description":"The URL to call to fetch the value."},"headers":{"type":"object","description":"Additional headers that can be attached to the URL request. Useful for adding meta-data to third-party services.","additionalProperties":{}},"auth_token_url":{"type":["string","null"],"description":"A URL that can be provided to authenticate with a third party secret service. Cycle will make a request to this URL before fetching the secret URL, and use the response as the value of an Authorization header when requesting the secret."}}}}},{"title":"StackSpecScopedVariableRawSource","type":"object","description":"A variable with a hard-coded value.","required":["type","details"],"properties":{"type":{"type":"string","description":"The type of scoped variable.","enum":["raw"]},"details":{"type":"object","required":["value","blob","secret"],"properties":{"value":{"type":"string","description":"The value of the variable."},"blob":{"type":"boolean","description":"A boolean where true represents the text the user is entering will be multi line."},"secret":{"type":["object","null"],"properties":{"iv":{"type":"string","description":"A string describing the IV Hex associated with the encryption of the variable."},"hint":{"type":"string","description":"A user specified hint that will suggest what the encryption key might be"}}}}}}}]}}}},"containers":{"type":"object","description":"A mapping of containers that will be deployed as a part of this stack. The key is used as the container's identifier.","additionalProperties":{"title":"StackContainer","description":"A container template defined within a stack.","type":"object","required":["name","image","config","stateful"],"properties":{"name":{"type":"string","description":"The human-readable name of this container."},"image":{"description":"Details about the image used for this container.","title":"StackSpecContainerImage","type":"object","required":["origin"],"properties":{"name":{"description":"The human-readable name of this image.","type":["string","null"]},"origin":{"description":"Instructions on how to fetch or build this image.","title":"ImageOrigin","type":"object","discriminator":{"propertyName":"type","mapping":{"docker-hub":"dockerHub/DockerHubOrigin.yml","docker-file":"dockerFile/DockerFileOrigin.yml","docker-registry":"dockerRegistry/DockerRegistryOrigin.yml","oci-registry":"ociRegistry/OciRegistryOrigin.yml","cycle-upload":"cycleUpload/CycleUploadOrigin.yml","cycle-source":"cycleSource/CycleSourceOrigin.yml","none":"none/NoneOrigin.yml"}},"oneOf":[{"title":"DockerHubOrigin","type":"object","description":"An image origin where the image is pulled from DockerHub.","required":["type","details"],"properties":{"type":{"type":"string","enum":["docker-hub"]},"details":{"type":"object","required":["target"],"properties":{"existing":{"anyOf":[{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/origin/oneOf/2/properties/details/properties/existing"},{"type":"null"}]},"target":{"type":"string","description":"The DockerHub target string. ex - `mysql:5.7`"},"username":{"type":"string","description":"For authentication, a username."},"token":{"type":"string","description":"For authentication, a token."}}}}},{"title":"DockerFileOrigin","type":"object","description":"An image origin where the image is built from a Dockerfile located in a git repository.","required":["type","details"],"properties":{"type":{"type":"string","enum":["docker-file"]},"details":{"type":"object","properties":{"existing":{"anyOf":[{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/origin/oneOf/2/properties/details/properties/existing"},{"type":"null"}]},"repo":{"anyOf":[{"title":"RepoSourceType","type":"object","description":"Information about the repostiory.","required":["url"],"properties":{"url":{"type":"string","description":"The URL of the repository."},"branch":{"type":"string","description":"An optional branch arguement. Default value is `master`."},"auth":{"type":["object","null"],"description":"Authentication information for the repository.","discriminator":{"propertyName":"type","mapping":{"http":"../CredentialsHTTP.yml","ssh":"../CredentialsSSH.yml"}},"oneOf":[{"title":"HTTPSourceCredentials","type":"object","required":["type","credentials"],"properties":{"type":{"type":"string","enum":["http"]},"credentials":{"type":"object","description":"Authentication credentails for the Dockerfile image source type when authenticating over HTTP.","required":["username","password"],"properties":{"username":{"type":"string","description":"For authentication, the username."},"password":{"type":"string","description":"For authentication, the password."}}}}},{"title":"SSHSourceCredentials","type":"object","required":["type","credentials"],"properties":{"type":{"type":"string","enum":["ssh"]},"credentials":{"type":"object","description":"Authentication credentials for the Dockerfile image source type when authenticating with SSH.","required":["username","passphrase","private_key"],"properties":{"username":{"type":"string","description":"The username for the repo service, that is used to authenticate an ssh key."},"passphrase":{"type":"string","description":"The passphrase used for the key."},"private_key":{"type":"string","description":"A pem encoded private key."}}}}}]},"ref":{"type":["object","null"],"description":"Repository reference information.","required":["type","value"],"properties":{"type":{"type":"string","description":"The type of reference being used."},"value":{"type":"string","description":"The value for the given reference type."}}}}},{"type":"null"}]},"targz_url":{"type":["string","null"],"description":"An endpoint that serves the tar file."},"context_dir":{"type":["string","null"],"description":"The path to the directory to use as the context when building the image."},"build_file":{"type":["string","null"],"description":"The path to the Dockerfile to be used for buiding the image."},"credentials":{"anyOf":[{"title":"DockerfileCredentails","description":"An array of credentials objects to be used when authenticating against private images used by the Dockerfile.","type":"array","items":{"type":"object","description":"Credentials object used for authentication of indirect resources such as private parent images.","properties":{"url":{"type":"string","description":"The url the resource is located at."},"username":{"type":"string","description":"A username for authentication."},"token":{"type":"string","description":"A token for authentication."}}}},{"type":"null"}]}}}}},{"title":"DockerRegistryOrigin","type":"object","description":"An image origin where the image is pulled from a private Docker registry.","required":["type","details"],"properties":{"type":{"type":"string","enum":["docker-registry"]},"details":{"type":"object","required":["target","url"],"properties":{"existing":{"title":"ExistingSource","type":"object","description":"In a stack, specifies an image source ID from which Cycle will derive any values not specified in the stack file. This is useful for avoiding direct placement of credentials in a stack file, for example.","properties":{"source_id":{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/origin/oneOf/5/properties/details/properties/source_id","description":"The ID of the image source this image should be built from."}}},"target":{"type":"string","description":"The image name on the registry."},"url":{"type":"string","description":"The url of the remote registry."},"username":{"type":"string","description":"For authentication, a username."},"token":{"type":"string","description":"For authentication, a token."},"password":{"type":"string","description":"For authentication, a password."}}}}},{"title":"OciRegistryOrigin","type":"object","description":"An image origin that pulls images fro an OCI-compatible registry. Also used for provider-native registries, such as AWS ECR.","required":["type","details"],"properties":{"type":{"type":"string","enum":["oci-registry"]},"details":{"type":"object","required":["target","url","auth"],"properties":{"existing":{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/origin/oneOf/2/properties/details/properties/existing"},"target":{"type":"string","description":"The image name on the registry."},"url":{"type":"string","description":"The url of the remote registry."},"auth":{"anyOf":[{"title":"RegistryAuth","type":"object","description":"Authentication details for a third party image registry/source.","discriminator":{"propertyName":"type","mapping":{"user":"RegistryAuthUser.yml","provider":"RegistryAuthProvider.yml","webhook":"RegistryAuthWebhook.yml"}},"oneOf":[{"title":"RegistryAuthUser","description":"User/token based credentials for authentication to a third-party image source.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["user"]},"details":{"type":"object","properties":{"username":{"type":"string"},"token":{"type":"string"}}}}},{"title":"RegistryAuthProvider","description":"Credentials for authentication to a provider-native image registry, such as AWS ECR.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["provider"]},"details":{"type":"object","required":["flavor","credentials"],"properties":{"flavor":{"type":"string","enum":["ecr"]},"credentials":{"title":"RegistryAuthProviderCredentials","type":"object","properties":{"region":{"type":"string"},"namespace":{"type":"string"},"api_key":{"type":"string"},"secret":{"type":"string"},"subscription_id":{"type":"string"},"client_id":{"type":"string"},"config":{"type":"string","description":"A base64'd string of additional configuration options."}}}}}}},{"title":"RegistryAuthWebhook","description":"Webhook-based authentication to the provided URL. This webhook expects to receive a base-64 string that when decoded is in the format `username:password`","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["webhook"]},"details":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}}}}]},{"type":"null"}]}}}}},{"title":"CycleUploadOrigin","type":"object","description":"An image origin where the image is pushed directly to the factory, bypassing the need for a registry or external source.\n\nIn order to utilize this image origin type, a tar file of an OCI compliant image will need to be generated and pushed directly to the factory. The authentication token is generated when this image is created, and expires at the provided time.\nOnce you have a token, it can be uploaded as multipart form data under the key `file.tar`, directly to the factory at `https://factory.cycle.io:9414/v1/images//upload?hub-id=&token=`.\n","properties":{"type":{"type":"string","enum":["cycle-upload"]},"details":{"type":"object","required":["expires","token"],"properties":{"expires":{"description":"The date-time at which the authorization token for uploading this image expires.","title":"DateTime","type":"string","format":"date-time","example":"2021-01-30T08:30:00Z"},"token":{"type":"string","description":"The token that is required by the factory to accept an upload for this image."}}}}},{"title":"CycleSourceOrigin","type":"object","description":"An image origin that references an image source on Cycle. \n\nThis origin will never be embedded in an image source. It is for use in stacks, describing an image which is already a part of an image source on Cycle.\n","required":["type","details"],"properties":{"type":{"type":"string","enum":["cycle-source"]},"details":{"type":"object","required":["source_id"],"properties":{"source_id":{"description":"The ID referencing the image source where this image originated.","title":"ID","type":"string","format":"objectid","example":"651586fca6078e98982dbd90"}}}}},{"title":"NoneOrigin","type":"object","description":"An empty origin. No details are provided for this image.","required":["type"],"properties":{"type":{"type":"string","enum":["none"]},"details":{"type":"object"}}}]},"build":{"description":"Additional details applied when building an image.","type":["object","null"],"required":["args"],"properties":{"args":{"type":"object","description":"A map of build arguments applied to the image at build time.","additionalProperties":{"type":"string"}}}},"builder":{"description":"A specific builder to use. By default, Cycle uses its factory service and a standard build command to build images, but this can be enhanced by using an image builder integration.","type":["object","null"],"required":["integration_id"],"properties":{"integration_id":{"description":"The ID of the integration to use when building the image. The integration must support image building to be compatible.","title":"HybridIdentifier","type":"string","example":"my-image-source"}}}}},"annotations":{"type":["object","null"],"description":"Additional user-provided meta data about the container.","additionalProperties":{}},"stateful":{"type":"boolean","description":"Whether or not to mark the container as stateful when deployed. Stateful containers can utilize volumes (stateful data) and are generally used for running databases or other data management applications."},"config":{"type":"object","description":"Configuration options for this container that will be applied when deployed as part of the stack.","title":"StackContainerConfig","required":["network","deploy"],"properties":{"network":{"title":"StackContainerConfigNetwork.yml","description":"Stack configuration options related to the container's network.","type":"object","required":["public","hostname"],"properties":{"public":{"description":"The level of public network access this container should have.","type":"string","enum":["enable","disable","egress-only"]},"hostname":{"description":"The hostname of the container. This is how it can be referenced by other containers in the same environment.","type":"string"},"ports":{"description":"A list of port mappings on this container.","type":"array","items":{"type":"string"},"examples":["80:80","443:80","3000"]}}},"deploy":{"title":"StackContainerConfigDeploy.yml","type":"object","description":"Stack configuration options related to how the container behaves over its lifecycle (startup, shutdown, health checks, etc).","required":["instances"],"properties":{"instances":{"description":"The number of desired instances to deploy.","type":"integer"},"strategy":{"description":"The strategy Cycle will apply when deploying instances of this container.\n- ** resource-density **: Cycle will distribute instances across servers to maintain balanced resource usage. - ** high-availability **: Cycle will deploy instances over servers with an emphasis on geographic and physical separation - ** first-available **: Cycle will deploy one instance to every node that matches the specified criteria. (default) - ** node **: Cycle will deploy one instance to every node that matches the specified criteria. - ** edge **: Cycle will prioritize geographic distribution of instances. - ** function **: Every ingress request/connection receives its own instance. - ** manual **: Cycle will not make any decisions on where instances are deployed. Instead, instances must be deployed manually using the portal or API.\n","type":["string","null"],"enum":["resource-density","manual","high-availability","first-available","node","edge","function"],"default":"first-available"},"stateful":{"description":"Configuration options for stateful containers.","type":["object","null"],"required":["options"],"properties":{"options":{"description":"Stateful container options.","type":["object","null"],"properties":{"use_base_hostname":{"description":"When enabled, instances will utilize stateless base hostnames instead of being prefixed with a unique ID.","type":["boolean","null"]}}}}},"constraints":{"description":"Configuration options that provide the ability to set restrictions on which nodes instances of this container are able to be deployed to. (i.e. if you have a GPU container, it should only go on nodes with a GPU).","type":["object","null"],"properties":{"node":{"type":["object","null"],"required":["tags"],"properties":{"tags":{"description":"Tags applied to a node. Cycle generates some automatically, but additional, custom tags can be applied on a per-node basis.","type":"object","properties":{"any":{"description":"If a node has at least one of these tags, it is considered a valid deployment target for this container.","type":"array","items":{"type":"string"}},"all":{"description":"A node must have **ALL** of these tags to be considered a valid deployment target for this container.","type":"array","items":{"type":"string"}}}}}}}},"shutdown":{"description":"Configuration options for how this container behaves during shutdown.","type":["object","null"],"properties":{"graceful_timeout":{"description":"How long the platform will wait for a container to stop gracefully.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]},"signals":{"type":"array","description":"Signals that should be sent to the container on shutdown.","items":{"type":"string","enum":["SIGTERM","SIGINT","SIGUSR1","SIGUSR2","SIGHUB","SIGKILL","SIGQUIT"]}}}},"startup":{"description":"Configuration options for how this container behaves during startup.","type":["object","null"],"properties":{"delay":{"description":"How long the platform will wait before sending the start signal to the given container.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]}}},"update":{"type":["object","null"],"description":"Configurations for how the container behaves during updates.","properties":{"stagger":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"description":"When set, Cycle will pick a random time from `0 - this duration`, and stagger the instances so they all start at different times (up to the time specified here)."}}},"restart":{"description":"Configuration options for how Cycle should handle restarting this container (i.e. in case the process inside the container dies).","type":["object","null"],"required":["condition","delay","max_attempts"],"properties":{"condition":{"description":"Under what circumstances Cycle should try to restart this container.","type":"string","enum":["always","never","failure"]},"delay":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"How long the platform will wait between restart attempts."},"max_attempts":{"type":"integer","description":"The maximum number of restart attempts Cycle will make."},"notify":{"description":"Configuration options for notifying on container restart.","type":["object","null"],"properties":{"emails":{"description":"A list of emails Cycle will attempt to notify when a container restarts.","type":"array","items":{"type":"string"}},"web_hook":{"description":"An endpoint Cycle will make a request to.\nThe post body will contain an object that looks like: ``` {\n \"instance_id\": ,\n \"container_id\": ,\n \"environment_id\": ,\n \"error\": ,\n \"time\": \n} ```\n","type":"string"}}}}},"health_check":{"description":"Configuration options for automated container health checks.","type":["object","null"],"required":["command","retries","interval","timeout","restart"],"properties":{"command":{"type":"string","description":"The command or script to run to verify the health of the container. This script is run inside the container by Cycle.\nThis command accepts two types of entries:\n- The first is a reference to a script that already lives in the container filesystem. This can be defined by giving the full path to the script as the value. - The second format is an inline script. If you need the code to execute within a shell, wrap the commands in escaped quotes like this `\"\\\"curl -s -o /dev/console -w \\\"%{http_code}\\\" http://localhost:3000/_health | grep '200' && exit 0 || exit 1\\\"\"`. Do not use the `/bin/sh -c ` format, this will not be accepted.\n","example":"/bin/sh healthcheck.sh"},"retries":{"type":"integer","description":"The number of times to retry the command before marking an instance unhealthy."},"interval":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"How long to wait between running health checks."},"timeout":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"How long before a health check attempt times out."},"restart":{"type":"boolean","description":"A boolean where true represents the desire for the container to restart if any instance is unhealthy."},"delay":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"description":"How long to wait after a container start event before running health checks."}}},"telemetry":{"description":"Configuration options for how the instance telemetry (CPU usage, etc) is handled.","type":["object","null"],"required":["disable"],"properties":{"retention":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"description":"How long telemetry data should be retained."},"interval":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"description":"The duration between samples."},"web_hook":{"type":["string","null"],"description":"A URL where Cycle will send telemetry data to. The payload will be an instance resource snapshot."},"disable":{"type":"boolean","description":"If true, Cycle will not aggregate telemetry for this container's instances."}}}}},"scaling":{"description":"Configuration options for auto-scaling.","anyOf":[{"title":"StackContainerConfigScaling.yml","type":"object","description":"Stack configuration options for auto-scaling.","required":["autoscale_group","instances","window","thresholds"],"properties":{"autoscale_group":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/identifier"},{"type":"null"}],"description":"The identifier of the auto-scaling group assigned to this container. The auto-scale group determines which infrastructure this container can spin up if it needs more resources to meet demand. Setting it to `null` will limit auto-scaling to only instances."},"instances":{"type":"object","description":"Describes the criteria for deploying new instances when an auto-scale criteria is met.","required":["delta","max","max_server","min_ttl"],"properties":{"delta":{"type":"integer","description":"Number of additional instances the auto-scaler will add/subtract per scaling event."},"max":{"type":"integer","description":"Maximum additional instances the auto-scaler will run at any time."},"max_server":{"type":"integer","description":"Minimum number of instances per server."},"min_ttl":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"Minimum amount of time an instance will live."}}},"window":{"description":"Duration in which the auto-scaler will watch for changes.","$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},"thresholds":{"description":"An array of rules that dictate when a scaling event will be triggered.","type":"array","items":{"title":"StackContainerScaleThreshold","type":"object","description":"Discriminated union describing the different types of scaling threshold and their respective details","discriminator":{"propertyName":"type","mapping":{"ram":"./StackContainerScaleThresholdRam.yml","cpu":"./StackContainerScaleThresholdCpu.yml","network-connections":"./StackContainerScaleThresholdNetworkConnections.yml","network-requests":"./StackContainerScaleThresholdNetworkRequests.yml","network-throughput":"./StackContainerScaleThresholdNetworkThroughput.yml"}},"oneOf":[{"title":"StackContainerScaleThresholdRam","type":"object","description":"Describes the RAM threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["ram"]},"details":{"type":"object","required":["used"],"properties":{"used":{"type":"string","description":"The limit (maximum) amount of RAM each instance of the given container can use before triggering a scaling event.","examples":["1G","50M"]}}}}},{"title":"StackContainerScaleThresholdCpu","type":"object","description":"Describes the CPU threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["cpu"]},"details":{"type":"object","required":["utilization"],"properties":{"utilization":{"type":"integer"}}}}},{"title":"StackContainerScaleThresholdNetworkConnections","type":"object","description":"Describes the network connections threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["network-connections"]},"details":{"type":"object","required":["connections_total"],"properties":{"connections_total":{"type":"integer"}}}}},{"title":"StackContainerScaleThresholdNetworkRequests","type":"object","description":"Describes the network requests threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["network-requests"]},"details":{"type":"object","required":["requests_total"],"properties":{"requests_total":{"type":"integer"}}}}},{"title":"StackContainerScaleThresholdNetworkThroughput","type":"object","description":"Describes the network throughput threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["network-throughput"]},"details":{"type":"object","required":["private","bandwidth"],"properties":{"private":{"type":"boolean"},"bandwidth":{"type":"string","description":"The limit (maximum) amount of throughput each instance of the given container can use before triggering a scaling event.","examples":["1G","50M"]}}}}}]}}}},{"type":"null"}]},"runtime":{"anyOf":[{"title":"StackContainerConfigRuntime","description":"Configuration options related to how the container behaves while it is running (environment variables, command overrides, kernel capabilities, etc. )","type":"object","properties":{"workdir":{"type":"string","description":"The working directory to execute the command in."},"command":{"type":"object","description":"The command to execute when this container starts. Will override the default specified in the container.","properties":{"path":{"type":"string"},"args":{"type":"string"}}},"environment_vars":{"type":"object","description":"A map of environment variables that will be injected into the container.","additionalProperties":{"type":"string"}},"namespaces":{"type":"array","description":"Container namespaces to apply. By default, all are applied. Removing/changing this can have security implications.","items":{"type":"string","enum":["ipc","pid","uts","network","mount","user","cgroup"]}},"sysctl":{"type":"object","description":"Sysctl options to apply.","additionalProperties":{"type":"string"}},"rlimits":{"type":"object","description":"RLIMIT options to apply.","additionalProperties":{"type":"object","required":["hard","soft"],"properties":{"hard":{"type":"integer"},"soft":{"type":"integer"}}}},"seccomp":{"type":"object","description":"Configuration options for seccomp. Cycle enables seccomp by default.","required":["disable","rules"],"properties":{"disable":{"type":"boolean"},"rules":{"type":"array","items":{"type":"object","required":["capabilities","syscall"],"properties":{"capabilities":{"type":"object","required":["includes","excludes"],"properties":{"includes":{"type":"string"},"excludes":{"type":"string"}}},"syscall":{"type":"object","required":["names","action"],"properties":{"names":{"type":"array","items":{"type":"string"}},"action":{"type":"string","enum":["SCMP_ACT_KILL","SCMP_ACT_KILL_PROCESS","SCMP_ACT_KILL_THREAD","SCMP_ACT_TRAP","SCMP_ACT_ERRNO","SCMP_ACT_TRACE","SCMP_ACT_ALLOW","SCMP_ACT_LOG","SCMP_ACT_NOTIFY"]},"errnoRet":{"type":"integer"},"args":{"type":"array","items":{"type":"object","required":["index","value","op"],"properties":{"index":{"type":"integer"},"value":{"type":"integer"},"valuetwo":{"type":"integer"},"op":{"type":"string","enum":["SCMP_CMP_NE","SCMP_CMP_LT","SCMP_CMP_LE","SCMP_CMP_EQ","SCMP_CMP_GE","SCMP_CMP_GT","SCMP_CMP_MASKED_EQ"]}}}}}}}}}}},"host":{"description":"Configuration options regarding the underlying host.","type":["object","null"],"properties":{"expose_proc":{"description":"If true, Cycle will mount the `/proc` directory into the container, giving it access to the host metrics. This is useful if you're running i.e. a monitoring agent.","type":["boolean","null"]}}},"privileged":{"description":"If true, the container process will run in fully-privileged mode. **WARNING** This is considered insecure, and should only be done if you know what you're doing.","type":"boolean"},"capabilities":{"type":"array","description":"Additional Linux kernel capabilities to apply to this container process.","items":{"type":"string","enum":["CAP_CHOWN","CAP_FSETID","CAP_DAC_OVERRIDE","CAP_FOWNER","CAP_SETFCAP","CAP_SETGID","CAP_SETUID","CAP_KILL","CAP_MKNOD","CAP_NET_BIND_SERVICE","CAP_NET_RAW","CAP_AUDIT_WRITE","CAP_SYS_CHROOT","CAP_SETPCAP","CAP_DAC_READ_SEARCH","CAP_NET_ADMIN","CAP_NET_BROADCAST","CAP_SYS_ADMIN","CAP_SYS_MODULE","CAP_SYS_NICE","CAP_SYS_PACCT","CAP_SYS_PTRACE","CAP_SYS_RAWIO","CAP_SYS_RESOURCE","CAP_SYS_BOOT","CAP_SYS_TIME","CAP_SYS_TTY_CONFIG","CAP_SYSLOG","CAP_AUDIT_CONTROL","CAP_AUDIT_READ","CAP_IPC_LOCK","CAP_IPC_OWNER","CAP_LINUX_IMMUTABLE","CAP_MAC_ADMIN","CAP_MAC_OVERRIDE","CAP_BLOCK_SUSPEND","CAP_LEASE","CAP_WAKE_ALARM"]}},"rootfs":{"type":"object","description":"Configuration options for the root filesystem.","required":["readonly"],"properties":{"readonly":{"description":"If true, the container's filesystem will be read-only.","type":"boolean"}}}}},{"type":"null"}]},"resources":{"anyOf":[{"title":"StackContainerConfigResources","description":"Configuration options for container resource limits and reserves.","type":"object","required":["cpu","ram"],"properties":{"cpu":{"type":"object","properties":{"shares":{"type":"object","required":["limit","reserve"],"properties":{"limit":{"type":"integer"},"reserve":{"type":"integer"}}},"cpus":{"type":"string"}}},"ram":{"type":"object","properties":{"limit":{"type":"string"},"reserve":{"type":"string"},"swappiness":{"type":"number"}}}}},{"type":"null"}]},"integrations":{"anyOf":[{"title":"StackContainerConfigIntegrations","type":"object","description":"Configuration options for additional integrations/features that Cycle provides.","properties":{"webhooks":{"description":"Enable additional webhooks that Cycle will call out to during the course of a container's lifetime. All webhooks send a payload as an object containing the instance, container, server, and environment IDs.","type":["object","null"],"properties":{"events":{"description":"Webhooks that are triggered during a container event.","type":["object","null"],"properties":{"deploy":{"description":"Cycle will call this endpoint when the container is deployed.","type":["string","null"]},"start":{"description":"Cycle will call this endpoint when the container is started.","type":["string","null"]},"stop":{"description":"Cycle will call this endpoint when the container is stopped.","type":["string","null"]}}},"config":{"description":"The webhook to hit when the container's configuration is changed.","type":["string","null"]}}},"lets_encrypt":{"description":"When enabled, this integration will configure Let's Encrypt certificates that will be injected into the container at runtime. The certificates will be managed by the platform and renewed automatically.","type":["object","null"],"required":["enable"],"properties":{"enable":{"type":"boolean"},"certificate_path":{"type":["string","null"]},"chain_path":{"type":["string","null"]},"key_path":{"type":["string","null"]},"bundle_path":{"type":["string","null"]},"additional_certs_path":{"type":["string","null"]}}},"files":{"description":"When enabled, Cycle will fetch and inject remote files into the container at the specified destination during runtime.","type":["array","null"],"items":{"type":"object","required":["source","destination"],"properties":{"source":{"type":"string"},"destination":{"type":"string"}}}},"backups":{"description":"When enabled, Cycle will automatically manage backups of this container. This is only available for stateful containers.","type":["object","null"],"required":["destination","backup","restore","retention"],"properties":{"integration_id":{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/builder/properties/integration_id","description":"An identifier of an integration that supports backups. All backups will be sent to this destination."},"backup":{"type":"object","description":"Configuration options for how the container should be backed up.","required":["command","timeout","cron_string"],"properties":{"command":{"description":"The command to run to capture a backup. The output sent to `STDOUT` will be captured and sent to the specified integration.","type":"string"},"timeout":{"description":"How long the backup will attempt to run before timing out.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]},"cron_string":{"description":"A cron string describing how often to run the backup command.","type":["string","null"]}}},"restore":{"description":"Configuration options for how the backup should be restored.","type":["object","null"],"required":["command","timeout"],"properties":{"command":{"type":"string"},"timeout":{"description":"The time in seconds for the restore to attempt to complete before timing out.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]}}},"retention":{"description":"How long the platform will keep backups. Default is 1 year.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"default":"365d"}}},"shared_file_systems":{"description":"When enabled, Cycle will mount a shared host directory into this container. The directory will be shared with all other containers that mount it.","type":["object","null"],"additionalProperties":{"type":"object","required":["writable","mount_point"],"properties":{"writable":{"type":"boolean"},"mount_point":{"type":"string"}}}}}},{"type":"null"}]}}},"role":{"description":"The role applied to this container. **Not yet implemented**","type":["string","null"],"enum":["conductor"]},"volumes":{"description":"A list of configurations for volumes that will be attached to the container. Only applicable if the container is set to `stateful`.","type":["array","null"],"items":{"title":"StackContainerVolume","description":"A container volume configuration.","type":"object","required":["destination","read_only"],"properties":{"local":{"description":"Configuration options for local volumes.","type":"object","required":["max_size"],"properties":{"max_size":{"description":"The maximum size this volume can grow to. Container volumes on Cycle are thinly provisioned, meaning this isn't an allocation - the volume will only use the space it needs up to this size.","type":"string","examples":["5G","500M"]},"storage_pool":{"description":"A boolean where true signifies using the largest drive over 2TB for the target server.","type":"boolean"}}},"destination":{"description":"The path this volume should be mounted at inside the container.","type":"string"},"read_only":{"description":"If true, the container will be unable to write data to the volume.","type":"boolean"},"remote_access":{"description":"Configuration options for setting up remote access to this volume via SFTP.","type":"object","required":["enable","password"],"properties":{"enable":{"description":"If true, this volume will be accessible over SFTP.","type":"boolean"},"ips":{"description":"A list of IPs that SFTP access will be limited to.","type":"array","items":{"type":"string"}},"web_hook":{"description":"If set, Cycle will call out to this URL for authentication. Anything other than a 200 response will be considered a validation failure.","type":"string"},"password":{"type":"object","description":"The password used for logging in to this volume via SFTP.","required":["algorithm","data"],"properties":{"algorithm":{"type":"string","description":"The algorithm the password is encoded with. `raw` means the password is plain-text.","enum":["raw","sha512","md5"]},"data":{"description":"The password string.","type":"string"}}}}}}}},"deprecate":{"description":"If true, the container is marked as `deprecated`, and cannot be started anymore. Deprecated containers also don't count toward resource utilization.","type":"boolean"},"lock":{"description":"If true, the container is marked as `locked` and cannot be deleted in any way until the lock is lifted.","type":"boolean"}}}},"services":{"title":"StackSpecServices","type":["object","null"],"properties":{"discovery":{"type":["object","null"],"properties":{"hosts":{"type":["object","null"],"additionalProperties":{"type":"object","properties":{"ipv4":{"type":["array","null"],"items":{"type":"string"}},"ipv6":{"type":["array","null"],"items":{"type":"string"}}}}}}},"loadbalancer":{"anyOf":[{"title":"StackSpecLoadBalancerConfig","type":"object","description":"The config object for the loadbalancer service.","discriminator":{"propertyName":"type","mapping":{"haproxy":"types/haproxy/HaProxyLbType.yml","v1":"types/v1/V1LbType.yml","default":"types/DefaultLbType.yml"}},"oneOf":[{"title":"HaProxyLbType","type":"object","required":["type","details","ipv4","ipv6"],"properties":{"ipv4":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv4."},"ipv6":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv6."},"type":{"type":"string","enum":["haproxy"]},"details":{"anyOf":[{"type":"object","description":"Describes settings that are passed to HAProxy within the load balancer.","required":["default","ports"],"properties":{"default":{"description":"Settings that are applied to any port that is not overridden in the following ports section.","$ref":"#/properties/services/properties/loadbalancer/anyOf/0/oneOf/0/properties/details/anyOf/0/properties/ports/additionalProperties"},"ports":{"description":"An object that defines how HAProxy will act on a specific port. The key is a custom port, and the value is the same settings object found under `default` above.","type":"object","additionalProperties":{"title":"HAProxyConfig","type":"object","required":["frontend","backend"],"properties":{"frontend":{"type":"object","description":"Settings that describe how incoming traffic to the load balancer is handled.","required":["mode","max_connections","timeouts"],"properties":{"mode":{"type":"string","description":"The type of traffic expected by the load balancer for this port. Can be either: \n - tcp: Traffic is forwarded without any parsing or additional manipulation. \n - http: Traffic is treated as web traffic. If a LINKED record is configured for a container exposing this port, the domain will be parsed and it will be forwarded to the proper container. This allows multiple services to run on port 80 in the same environment.","enum":["tcp","http"]},"max_connections":{"type":["integer","null"],"description":"The number of simultaneous connections that can be processed at a time."},"timeouts":{"type":["object","null"],"description":"Various options for handling timeouts when communicating with the client.","required":["client_secs","client_fin_ms","http_keep_alive_ms","http_request_ms"],"properties":{"client_secs":{"type":["integer","null"],"description":"The number of seconds the load balancer will wait for a response from a client before disconnecting."},"client_fin_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for a client to send it data when one direction is already closed. This is particularly useful to avoid keeping connections in a waiting state for too long when clients do not disconnect cleanly."},"http_keep_alive_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for a new HTTP request to start coming after a response was set. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-timeout%20http-request) for more information. (`http` mode only)"},"http_request_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for a complete HTTP request. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-timeout%20http-request) for more information. (`http` mode only)"}}}}},"backend":{"type":"object","description":"Settings related to how the load balancer routes connections to container instances.","required":["balance","timeouts"],"properties":{"balance":{"type":"string","description":"How connections are balanced across your container instances. Can be one of the following: \n - `roundrobin`: Each container instance is used in turns. \n - `static-rr`: Each container instance is used in turns, but is faster than Round Robin at the expense of being less dynamic. \n - `leastconn`: Routes traffic to the instance with the least number of active connections. \n - `first`: Routes traffic to the first available instance. \n - `source`: The same client IP always reaches the same container instance as long as no instance goes down or up.","enum":["roundrobin","static-rr","leastconn","first","source"]},"timeouts":{"type":["object","null"],"description":"Various options for handling timeouts when communicating with a container instance behind the load balancer.","required":["server_secs","server_fin_ms","connect_ms","queue_ms","tunnel_secs"],"properties":{"server_secs":{"type":["integer","null"],"description":"The number of seconds the load balancer will wait for a response from the container instance. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-timeout%20server) for more information."},"server_fin_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for the server to send data when one direction is already closed. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4-timeout%20server-fin) for more information."},"connect_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for a successful connection to a container instance. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4-timeout%20connect) for more information."},"queue_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will hold connections in a queue when the maximum number of connections has been reached. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4-timeout%20queue) for more information."},"tunnel_secs":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will allow for inactivity on a bidirectional tunnel. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4-timeout%20tunnel) for more information."}}}}}}}}}},{"type":"null"}]},"bind_host":{"description":"Binds the load balancer to the host server IP address. \n\n**Pros**: This allows for significantly lower cost (utilizing fewer IPv4 addresses), and enables building out a true edge network with lower latency.\n**Cons**: Only 1 environment is allowed on the host. This is because the load balancer is the only ingress point for an environment, and if it is sharing\nthe same IP as the host, that host can only operate under that environment.\n","type":["boolean","null"]}}},{"title":"V1LbType","type":"object","required":["type","details","ipv4","ipv6"],"properties":{"ipv4":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv4."},"ipv6":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv6."},"type":{"type":"string","enum":["v1"]},"details":{"title":"V1LbConfig","type":"object","required":["controllers"],"properties":{"controllers":{"type":"array","description":"A configuration for a specific port.","items":{"title":"V1LbController","type":"object","required":["default","identifier","transport"],"properties":{"default":{"type":"boolean"},"identifier":{"type":"string","description":"A human-readable identifier for this controller. It will default to the port, i.e. `port-443`, but can be renamed to anything, such as the service this controller represents."},"transport":{"title":"V1LbControllerTransport","description":"Defines how traffic comes in to the load balancer, and how the load balancer handles it.","type":"object","required":["mode","config","routers","disable"],"properties":{"disable":{"type":"boolean","description":"When true, this controller is disabled and will not be used."},"mode":{"type":"string","description":"The kind of traffic (http/tcp/udp) that will be sent to the load balancer.","enum":["tcp","udp","http"]},"config":{"type":"object","description":"Defines how the transport for this controller operates.","required":["performance","ingress","timeouts","verbosity"],"properties":{"performance":{"type":"boolean","description":"Enable/disable performance mode. If enabled, some telemetry will be disabled to dedicate full processing to handling requests.\nYou will not see per-request breakdowns or URL logging if performance mode is enabled.\n"},"ingress":{"type":"object","description":"Defines how traffic gets into the load balancer.","required":["port"],"properties":{"port":{"type":"integer","description":"The port inbound trafic is accepted on."},"tls":{"type":["object","null"],"required":["enable"],"properties":{"enable":{"type":"boolean","description":"Enables or disables TLS."}}}}},"timeouts":{"type":"object","description":"Defines settings for various types of timeouts.","required":["idle"],"properties":{"idle":{"description":"The total amount of time a connection can be idle before being killed.","$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"}}},"verbosity":{"type":"string","description":"Verbosity describes the level of logging detail for the controller","enum":["low","normal","high","debug"]},"extension":{"type":"object","description":"Extended configurations for the specified transport mode (http/tcp)","discriminator":{"propertyName":"type","mapping":{"tcp":"transports/TcpTransportConfig.yml","http":"transports/HttpTransportConfig.yml","udp":"transports/UdpTransportConfig.yml"}},"oneOf":[{"title":"TcpTransportConfig","description":"Additional configuration options for the TCP transport mode.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["tcp"]},"details":{"type":"object","required":["connections"],"properties":{"connections":{"type":"object","additionalProperties":{}}}}}},{"title":"HttpTransportConfig","description":"Additional configuration options for the HTTP transport mode.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["http"]},"details":{"type":"object","required":["connections","telemetry"],"properties":{"connections":{"type":"object","required":["max_idle_conns_per_connection"],"description":"Defines extra configuration options connections to the load balancer","properties":{"max_idle_conns_per_connection":{"type":["integer","null"],"description":"Maximum number of simultaneous connections (via http/2) per connection."}}},"telemetry":{"type":"object","description":"Configuration options for how telemetry is handled.","required":["disable_url_tracking","disable_router_metrics"],"properties":{"disable_url_tracking":{"description":"Determines if the load balancer will track url metrics. Defaults to false.","type":"boolean"},"disable_router_metrics":{"description":"Determines if the load balancer will track router metrics. Defaults to false.","type":"boolean"},"max_trackable_urls":{"description":"Determines how many URLs the load balancer will track at one time. Defaults to 150.","type":["integer","null"]},"tracking_window":{"description":"Determines how long the load balancer will track a URL from its last hit. Helps reduce noise by not tracking URLs that are occasionally hit. Defaults to 8h.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]},"track_invalid_requests":{"description":"Whether or not to track invalid requests. An invalid request is a request that came in that no router existed for. Usually this means bot requests. Defaults to false.","type":["boolean","null"]},"group_paths":{"description":"Group paths is used to group URLs. The key is the URL and the value is the regex used to match URLs.","type":["object","null"],"additionalProperties":{"type":"string"}},"ignore_paths":{"description":"An array of paths to exclude from tracking.","type":["array","null"],"items":{"type":"string"}}}}}}}},{"title":"UdpTransportConfig","description":"Additional configuration options for the UDP transport mode.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["udp"]},"details":{"type":"object","required":["connections"],"properties":{"connections":{"type":"object","additionalProperties":{}}}}}}]}}},"routers":{"type":"array","description":"Defines where traffic is sent. Many can be defined per controller.","items":{"title":"V1LbRouterConfig","description":"A specific router configuration that describes how traffic matching the rule is handled.","type":"object","required":["match","mode","config"],"properties":{"match":{"type":"object","description":"The ruleset for this router to be selected. If both `domains`` and `internal_port` are null, then this match acts as a wildcard and will match all.","required":["domains","internal_port"],"properties":{"domains":{"type":["array","null"],"description":"The specific domains to match against.","items":{"type":"string"}},"internal_port":{"type":["array","null"],"description":"The specific ports to match against.","items":{"type":"integer"}},"path":{"type":["string","null"]}}},"mode":{"type":"string","description":"How to route the traffic to the destination.\n`random`: Pick a valid destination at random.\n`round-robin`: Send each request to the 'next' destination on the list, restarting from the beginning when the last destination is used.\n","enum":["random","round-robin"]},"config":{"type":"object","required":["sticky_sessions","destination_retries","timeouts"],"properties":{"sticky_sessions":{"type":"boolean","description":"If a request comes in from the same origin, ensure it hits the same destination."},"destination_retries":{"type":"integer","description":"If a destination is unavailable, retry up to [x] times, instead of immediately failing with a 503/504 error."},"tls":{"type":["object","null"],"description":"TLS termination configuration. If null, the platform will use the default configuration. Port 443 by default has TLS termination enabled.","properties":{"server_name":{"type":["string","null"],"description":"[Advanced] Change the domain the controller listens on.\n"},"allow_insecure":{"type":["boolean","null"],"description":"If enabled, accept TLS traffic with an invalid certificate. This is usually done for development/testing, and is not recommended for production use."},"client_cert_auth":{"description":"A PEM encoded string of certificates.","type":["string","null"]},"client_auth":{"description":"Defines how to validate the connecting TLS certificate.\n`none`: Do not require a TLS certificate to be sent\n`request`: Asks the client to send a TLS certificate, but does not require nor validate it.\n`require`: Requires a certificate be sent for the request to be valid, but does not validate the certificate.\n`require-verify`: Requires both that the client send a certificate, and that the certificate is valid. This is required when using https.\n","oneOf":[{"type":"string","enum":["none","request","require","require-verify"]},{"type":"null"}]}}},"timeouts":{"type":"object","description":"Defines how the length of various sorts of timeouts when communicating with the destination.","required":["destination_connection"],"properties":{"destination_connection":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"The duration the load balancer will wait before timing out while attempting to connect to the destination."}}},"extension":{"type":"object","description":"Additional configuration options specific to the selected mode (tcp/http).","discriminator":{"propertyName":"type","mapping":{"tcp":"routers/TcpRouterConfig.yml","udp":"routers/UdpRouterConfig.yml","http":"routers/HttpRouterConfig.yml"}},"oneOf":[{"title":"TcpRouterConfig","description":"Additional configuration options for TCP mode routers","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["tcp"]},"details":{"type":"object","additionalProperties":{}}}},{"title":"HttpRouterConfig","description":"Additional configuration options for HTTP mode routers.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["http"]},"details":{"type":"object","properties":{"redirect":{"type":["object","null"],"required":["auto_https_redirect","remove_www"],"description":"Defines a built-in redirect for HTTP mode routers","properties":{"auto_https_redirect":{"type":"boolean","description":"If enabled and a sibling controller exists for port 443, requests will be auto redirected to it. Essentially sets up automatic TLS redirection for this router."},"remove_www":{"description":"If true, any request comes in with \"www\" prefix will be permanently redirected to the same path without www.","type":"boolean"},"port":{"type":["integer","null"],"description":"The port to redirect traffic to."},"scheme":{"type":["string","null"],"description":"The scheme to redirect to. (i.e. `https`)"},"url":{"type":["string","null"],"description":"A specific URL to redirect to."}}},"forward":{"type":["object","null"],"properties":{"scheme":{"type":["string","null"]},"content_mod":{"description":"Allows the load balancer to modify content before it reaches the user.","type":["object","null"],"properties":{"replace":{"description":"An array that describes a list of replacement match/value pairs.","type":["array","null"],"items":{"type":"object","required":["match","value"],"properties":{"match":{"description":"String that will be replaced.","type":"string"},"value":{"description":"Replacement value.","type":"string"}}}}}}}},"proxy":{"type":["object","null"],"properties":{"domain":{"type":["string","null"],"description":"The proxy domain for this router."},"content_mod":{"description":"Allows the load balancer to modify content before it reaches the user.","type":["object","null"],"properties":{"replace":{"description":"An array that describes a list of replacement match/value pairs.","type":["array","null"],"items":{"type":"object","required":["match","value"],"properties":{"match":{"description":"String that will be replaced.","type":"string"},"value":{"description":"Replacement value.","type":"string"}}}}}}}},"caching":{"type":["object","null"],"properties":{"files":{"type":["array","null"],"items":{"type":"object","required":["match","ttl"],"properties":{"match":{"description":"Regex string that describes the files to cache.","example":"(.*)\\\\.(js|jpg|css|png|svg)$","type":"string"},"ttl":{"description":"Time string that describes the time to live.","$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"}}}}}}}}}},{"title":"UdpRouterConfig","description":"Additional configuration options for UDP mode routers","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["udp"]},"details":{"type":"object","additionalProperties":{}}}}]}}}}}}}}}}},"controller_template":{"anyOf":[{"$ref":"#/properties/services/properties/loadbalancer/anyOf/0/oneOf/1/properties/details/properties/controllers/items"},{"type":"null"}]}}},"bind_host":{"description":"Binds the load balancer to the host server IP address. \n\n**Pros**: This allows for significantly lower cost (utilizing fewer IPv4 addresses), and enables building out a true edge network with lower latency.\n**Cons**: Only 1 environment is allowed on the host. This is because the load balancer is the only ingress point for an environment, and if it is sharing\nthe same IP as the host, that host can only operate under that environment.\n","type":["boolean","null"]}}},{"title":"DefaultLbType","type":"object","required":["type","details","ipv4","ipv6"],"properties":{"ipv4":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv4."},"ipv6":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv6."},"type":{"type":"string","enum":["default"]},"details":{"oneOf":[{"$ref":"#/properties/services/properties/loadbalancer/anyOf/0/oneOf/0/properties/details/anyOf/0"},{"$ref":"#/properties/services/properties/loadbalancer/anyOf/0/oneOf/1/properties/details"},{"type":"null"}]}}}]},{"type":"null"}]},"vpn":{"type":"object","required":["auth","allow_internet"],"properties":{"auth":{"type":"object","required":["cycle_accounts","vpn_accounts"],"properties":{"webhook":{"type":"string"},"cycle_accounts":{"type":"boolean"},"vpn_accounts":{"type":"boolean"}}},"allow_internet":{"type":"boolean"}}}}},"annotations":{"type":"object","description":"Additional meta info about the stack.","additionalProperties":{}}}} \ No newline at end of file +{"$schema":"https://json-schema.org/draft/2020-12/schema","title":"StackSpec","description":"A Cycle stack file is an \"environment as code\". Anything that can be done in an environment on Cycle can be described in a stack file and deployed as a new environment.\nStack files can list multiple containers and their configurations, load balancer settings, scoped variables, and much more.\n","type":"object","required":["version","containers"],"properties":{"version":{"type":"string","description":"The version of the Cycle stack file used.","enum":["1.0"]},"about":{"description":"Various properties describing this stack.","type":["object","null"],"required":["description","version"],"properties":{"version":{"type":"string","description":"A custom, user-defined version of the stack."},"description":{"type":"string","description":"Custom, user-defined details about this stack."}}},"scoped_variables":{"description":"Describes variables that are assigned to one or more containers at runtime. Can be assigned as an environment variable, written as a file inside the container(s), or accessed over the internal API.","type":["array","null"],"items":{"title":"StackSpecScopedVariable","type":"object","required":["identifier","scope","access"],"properties":{"identifier":{"title":"Identifier","type":"string","description":"A human-readable identifier used to refer to a resource, where using the official ID may be inconvenient.\nThe identifier is automatically tokenized from the name/relevant field of the resource if one is not provided. For example, a container named \"My Container\" will\nhave the identifier of `my-container` and is automatically created by the platform.\n\nThe identifier does not have to be unique.\n"},"scope":{"type":"object","required":["containers"],"properties":{"containers":{"type":"object","description":"Describes the containers that have access to this scoped variable.","required":["global"],"properties":{"global":{"type":"boolean","description":"If true, all containers in the environment will have access to this variable."},"ids":{"type":["array","null"],"description":"A list of container IDs that are granted access to this variable.","items":{"type":"string"}},"identifiers":{"type":["array","null"],"description":"A list of container identifiers that are granted access to this variable.","items":{"$ref":"#/properties/scoped_variables/items/properties/identifier"}}}}}},"access":{"type":"object","properties":{"env_variable":{"description":"Grants access to this variable from within a container as an environment variable.","type":["object","null"],"required":["key"],"properties":{"key":{"description":"The environment variable inside the container that stores the value of the variable.","type":"string"}}},"internal_api":{"description":"Grants access to this variable over the Internal API.","type":["object","null"],"properties":{"duration":{"description":"Sets the duration that this variable can be accessed over the Internal API, after container start. Provides additional security as sensitive data can only be accessed for a limited time.","anyOf":[{"title":"Duration","type":"string","description":"A string signifying a duration of time. Valid time units are \"ns\", \"us\" (or \"µs\"), \"ms\", \"s\", \"m\", \"h\", \"d\", \"w\", \"y\".","example":"72h45m2s"},{"type":"null"}]}}},"file":{"description":"Grants access to this variable as a file inside the container.","type":["object","null"],"required":["decode","path"],"x-ogen-properties":{"decode":{"name":"DecodeBase64"}},"properties":{"decode":{"description":"When true, Cycle will interpret this variable as a base-64 encoded string, and decode it before writing it to the file inside the container.","type":"boolean"},"path":{"type":["string","null"],"example":"/var/run/cycle/variables/","description":"The absolute path to write the variable to (including file name). If `null`, it will be written to `/var/run/cycle/variables/{variable-identifier}`."}}}}},"source":{"type":["object","null"],"description":"Describes the source/value of the variable.\n- **raw**: Directly set the value of the variable in the stack. - **url**: Cycle will fetch the variable content from a remote source when the container starts.\n","discriminator":{"propertyName":"type","mapping":{"url":"./StackSpecScopedVariableUrlSource.yml","raw":"./StackSpecScopedVariableRawSource.yml"}},"oneOf":[{"title":"StackSpecScopedVariableUrlSource","type":"object","description":"A variable who's value is fetched from a URL when the container starts.","required":["type","details"],"properties":{"type":{"type":"string","description":"The type of scoped variable.","enum":["url"]},"details":{"type":"object","required":["url","headers","auth_token_url"],"properties":{"url":{"type":"string","description":"The URL to call to fetch the value."},"headers":{"type":"object","description":"Additional headers that can be attached to the URL request. Useful for adding meta-data to third-party services.","additionalProperties":{}},"auth_token_url":{"type":["string","null"],"description":"A URL that can be provided to authenticate with a third party secret service. Cycle will make a request to this URL before fetching the secret URL, and use the response as the value of an Authorization header when requesting the secret."}}}}},{"title":"StackSpecScopedVariableRawSource","type":"object","description":"A variable with a hard-coded value.","required":["type","details"],"properties":{"type":{"type":"string","description":"The type of scoped variable.","enum":["raw"]},"details":{"type":"object","required":["value","blob","secret"],"properties":{"value":{"type":"string","description":"The value of the variable."},"blob":{"type":"boolean","description":"A boolean where true represents the text the user is entering will be multi line."},"secret":{"type":["object","null"],"properties":{"iv":{"type":"string","description":"A string describing the IV Hex associated with the encryption of the variable."},"hint":{"type":"string","description":"A user specified hint that will suggest what the encryption key might be"}}}}}}}]}}}},"containers":{"type":"object","description":"A mapping of containers that will be deployed as a part of this stack. The key is used as the container's identifier.","additionalProperties":{"title":"StackContainer","description":"A container template defined within a stack.","type":"object","required":["name","image","config","stateful"],"properties":{"name":{"type":"string","description":"The human-readable name of this container."},"image":{"description":"Details about the image used for this container.","title":"StackSpecContainerImage","type":"object","required":["origin"],"properties":{"name":{"description":"The human-readable name of this image.","type":["string","null"]},"origin":{"description":"Instructions on how to fetch or build this image.","title":"ImageOrigin","type":"object","discriminator":{"propertyName":"type","mapping":{"docker-hub":"dockerHub/DockerHubOrigin.yml","docker-file":"dockerFile/DockerFileOrigin.yml","docker-registry":"dockerRegistry/DockerRegistryOrigin.yml","oci-registry":"ociRegistry/OciRegistryOrigin.yml","cycle-upload":"cycleUpload/CycleUploadOrigin.yml","cycle-source":"cycleSource/CycleSourceOrigin.yml","none":"none/NoneOrigin.yml"}},"oneOf":[{"title":"DockerHubOrigin","type":"object","description":"An image origin where the image is pulled from DockerHub.","required":["type","details"],"properties":{"type":{"type":"string","enum":["docker-hub"]},"details":{"type":"object","required":["target"],"properties":{"existing":{"anyOf":[{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/origin/oneOf/2/properties/details/properties/existing"},{"type":"null"}]},"target":{"type":"string","description":"The DockerHub target string. ex - `mysql:5.7`"},"username":{"type":"string","description":"For authentication, a username."},"token":{"type":"string","description":"For authentication, a token."}}}}},{"title":"DockerFileOrigin","type":"object","description":"An image origin where the image is built from a Dockerfile located in a git repository.","required":["type","details"],"properties":{"type":{"type":"string","enum":["docker-file"]},"details":{"type":"object","properties":{"existing":{"anyOf":[{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/origin/oneOf/2/properties/details/properties/existing"},{"type":"null"}]},"repo":{"anyOf":[{"title":"RepoSourceType","type":"object","description":"Information about the repostiory.","required":["url"],"properties":{"url":{"type":"string","description":"The URL of the repository."},"branch":{"type":"string","description":"An optional branch arguement. Default value is `master`."},"auth":{"type":["object","null"],"description":"Authentication information for the repository.","discriminator":{"propertyName":"type","mapping":{"http":"../CredentialsHTTP.yml","ssh":"../CredentialsSSH.yml"}},"oneOf":[{"title":"HTTPSourceCredentials","type":"object","required":["type","credentials"],"properties":{"type":{"type":"string","enum":["http"]},"credentials":{"type":"object","description":"Authentication credentails for the Dockerfile image source type when authenticating over HTTP.","required":["username","password"],"properties":{"username":{"type":"string","description":"For authentication, the username."},"password":{"type":"string","description":"For authentication, the password."}}}}},{"title":"SSHSourceCredentials","type":"object","required":["type","credentials"],"properties":{"type":{"type":"string","enum":["ssh"]},"credentials":{"type":"object","description":"Authentication credentials for the Dockerfile image source type when authenticating with SSH.","required":["username","passphrase","private_key"],"properties":{"username":{"type":"string","description":"The username for the repo service, that is used to authenticate an ssh key."},"passphrase":{"type":"string","description":"The passphrase used for the key."},"private_key":{"type":"string","description":"A pem encoded private key."}}}}}]},"ref":{"type":["object","null"],"description":"Repository reference information.","required":["type","value"],"properties":{"type":{"type":"string","description":"The type of reference being used."},"value":{"type":"string","description":"The value for the given reference type."}}}}},{"type":"null"}]},"targz_url":{"type":["string","null"],"description":"An endpoint that serves the tar file."},"context_dir":{"type":["string","null"],"description":"The path to the directory to use as the context when building the image."},"build_file":{"type":["string","null"],"description":"The path to the Dockerfile to be used for buiding the image."},"credentials":{"anyOf":[{"title":"DockerfileCredentails","description":"An array of credentials objects to be used when authenticating against private images used by the Dockerfile.","type":"array","items":{"type":"object","description":"Credentials object used for authentication of indirect resources such as private parent images.","properties":{"url":{"type":"string","description":"The url the resource is located at."},"username":{"type":"string","description":"A username for authentication."},"token":{"type":"string","description":"A token for authentication."}}}},{"type":"null"}]}}}}},{"title":"DockerRegistryOrigin","type":"object","description":"An image origin where the image is pulled from a private Docker registry.","required":["type","details"],"properties":{"type":{"type":"string","enum":["docker-registry"]},"details":{"type":"object","required":["target","url"],"properties":{"existing":{"title":"ExistingSource","type":"object","description":"In a stack, specifies an image source ID from which Cycle will derive any values not specified in the stack file. This is useful for avoiding direct placement of credentials in a stack file, for example.","properties":{"source_id":{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/origin/oneOf/5/properties/details/properties/source_id","description":"The ID of the image source this image should be built from."}}},"target":{"type":"string","description":"The image name on the registry."},"url":{"type":"string","description":"The url of the remote registry."},"username":{"type":"string","description":"For authentication, a username."},"token":{"type":"string","description":"For authentication, a token."},"password":{"type":"string","description":"For authentication, a password."}}}}},{"title":"OciRegistryOrigin","type":"object","description":"An image origin that pulls images fro an OCI-compatible registry. Also used for provider-native registries, such as AWS ECR.","required":["type","details"],"properties":{"type":{"type":"string","enum":["oci-registry"]},"details":{"type":"object","required":["target","url","auth"],"properties":{"existing":{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/origin/oneOf/2/properties/details/properties/existing"},"target":{"type":"string","description":"The image name on the registry."},"url":{"type":"string","description":"The url of the remote registry."},"auth":{"anyOf":[{"title":"RegistryAuth","type":"object","description":"Authentication details for a third party image registry/source.","discriminator":{"propertyName":"type","mapping":{"user":"RegistryAuthUser.yml","provider":"RegistryAuthProvider.yml","webhook":"RegistryAuthWebhook.yml"}},"oneOf":[{"title":"RegistryAuthUser","description":"User/token based credentials for authentication to a third-party image source.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["user"]},"details":{"type":"object","properties":{"username":{"type":"string"},"token":{"type":"string"}}}}},{"title":"RegistryAuthProvider","description":"Credentials for authentication to a provider-native image registry, such as AWS ECR.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["provider"]},"details":{"type":"object","required":["flavor","credentials"],"properties":{"flavor":{"type":"string","enum":["ecr"]},"credentials":{"title":"RegistryAuthProviderCredentials","type":"object","properties":{"region":{"type":"string"},"namespace":{"type":"string"},"api_key":{"type":"string"},"secret":{"type":"string"},"subscription_id":{"type":"string"},"client_id":{"type":"string"},"config":{"type":"string","description":"A base64'd string of additional configuration options."}}}}}}},{"title":"RegistryAuthWebhook","description":"Webhook-based authentication to the provided URL. This webhook expects to receive a base-64 string that when decoded is in the format `username:password`","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["webhook"]},"details":{"type":"object","required":["url"],"properties":{"url":{"type":"string"}}}}}]},{"type":"null"}]}}}}},{"title":"CycleUploadOrigin","type":"object","description":"An image origin where the image is pushed directly to the factory, bypassing the need for a registry or external source.\n\nIn order to utilize this image origin type, a tar file of an OCI compliant image will need to be generated and pushed directly to the factory. The authentication token is generated when this image is created, and expires at the provided time.\nOnce you have a token, it can be uploaded as multipart form data under the key `file.tar`, directly to the factory at `https://factory.cycle.io:9414/v1/images//upload?hub-id=&token=`.\n","properties":{"type":{"type":"string","enum":["cycle-upload"]},"details":{"type":"object","required":["expires","token"],"properties":{"expires":{"description":"The date-time at which the authorization token for uploading this image expires.","title":"DateTime","type":"string","format":"date-time","example":"2021-01-30T08:30:00Z"},"token":{"type":"string","description":"The token that is required by the factory to accept an upload for this image."}}}}},{"title":"CycleSourceOrigin","type":"object","description":"An image origin that references an image source on Cycle. \n\nThis origin will never be embedded in an image source. It is for use in stacks, describing an image which is already a part of an image source on Cycle.\n","required":["type","details"],"properties":{"type":{"type":"string","enum":["cycle-source"]},"details":{"type":"object","required":["source_id"],"properties":{"source_id":{"description":"The ID referencing the image source where this image originated.","title":"ID","type":"string","format":"objectid","example":"651586fca6078e98982dbd90"}}}}},{"title":"NoneOrigin","type":"object","description":"An empty origin. No details are provided for this image.","required":["type"],"properties":{"type":{"type":"string","enum":["none"]},"details":{"type":"object"}}}]},"build":{"description":"Additional details applied when building an image.","type":["object","null"],"required":["args"],"properties":{"args":{"type":"object","description":"A map of build arguments applied to the image at build time.","additionalProperties":{"type":"string"}}}},"builder":{"description":"A specific builder to use. By default, Cycle uses its factory service and a standard build command to build images, but this can be enhanced by using an image builder integration.","type":["object","null"],"required":["integration_id"],"properties":{"integration_id":{"description":"The ID of the integration to use when building the image. The integration must support image building to be compatible.","title":"HybridIdentifier","type":"string","example":"my-image-source"}}}}},"annotations":{"type":["object","null"],"description":"Additional user-provided meta data about the container.","additionalProperties":{}},"stateful":{"type":"boolean","description":"Whether or not to mark the container as stateful when deployed. Stateful containers can utilize volumes (stateful data) and are generally used for running databases or other data management applications."},"config":{"type":"object","description":"Configuration options for this container that will be applied when deployed as part of the stack.","title":"StackContainerConfig","required":["network","deploy"],"properties":{"network":{"title":"StackContainerConfigNetwork.yml","description":"Stack configuration options related to the container's network.","type":"object","required":["public","hostname"],"properties":{"public":{"description":"The level of public network access this container should have.","type":"string","enum":["enable","disable","egress-only"]},"hostname":{"description":"The hostname of the container. This is how it can be referenced by other containers in the same environment.","type":"string"},"ports":{"description":"A list of port mappings on this container.","type":"array","items":{"type":"string"},"examples":["80:80","443:80","3000"]}}},"deploy":{"title":"StackContainerConfigDeploy.yml","type":"object","description":"Stack configuration options related to how the container behaves over its lifecycle (startup, shutdown, health checks, etc).","required":["instances"],"properties":{"instances":{"description":"The number of desired instances to deploy.","type":"integer"},"strategy":{"description":"The strategy Cycle will apply when deploying instances of this container.\n- ** resource-density **: Cycle will distribute instances across servers to maintain balanced resource usage. - ** high-availability **: Cycle will deploy instances over servers with an emphasis on geographic and physical separation - ** first-available **: Cycle will deploy one instance to every node that matches the specified criteria. (default) - ** node **: Cycle will deploy one instance to every node that matches the specified criteria. - ** edge **: Cycle will prioritize geographic distribution of instances. - ** function **: Every ingress request/connection receives its own instance. - ** manual **: Cycle will not make any decisions on where instances are deployed. Instead, instances must be deployed manually using the portal or API.\n","type":["string","null"],"enum":["resource-density","manual","high-availability","first-available","node","edge","function"],"default":"first-available"},"stateful":{"description":"Configuration options for stateful containers.","type":["object","null"],"required":["options"],"properties":{"options":{"description":"Stateful container options.","type":["object","null"],"properties":{"use_base_hostname":{"description":"When enabled, instances will utilize stateless base hostnames instead of being prefixed with a unique ID.","type":["boolean","null"]}}}}},"constraints":{"description":"Configuration options that provide the ability to set restrictions on which nodes instances of this container are able to be deployed to. (i.e. if you have a GPU container, it should only go on nodes with a GPU).","type":["object","null"],"properties":{"node":{"type":["object","null"],"required":["tags"],"properties":{"tags":{"description":"Tags applied to a node. Cycle generates some automatically, but additional, custom tags can be applied on a per-node basis.","type":"object","properties":{"any":{"description":"If a node has at least one of these tags, it is considered a valid deployment target for this container.","type":"array","items":{"type":"string"}},"all":{"description":"A node must have **ALL** of these tags to be considered a valid deployment target for this container.","type":"array","items":{"type":"string"}}}}}}}},"shutdown":{"description":"Configuration options for how this container behaves during shutdown.","type":["object","null"],"properties":{"graceful_timeout":{"description":"How long the platform will wait for a container to stop gracefully.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]},"signals":{"type":"array","description":"Signals that should be sent to the container on shutdown.","items":{"type":"string","enum":["SIGTERM","SIGINT","SIGUSR1","SIGUSR2","SIGHUB","SIGKILL","SIGQUIT"]}}}},"startup":{"description":"Configuration options for how this container behaves during startup.","type":["object","null"],"properties":{"delay":{"description":"How long the platform will wait before sending the start signal to the given container.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]}}},"update":{"type":["object","null"],"description":"Configurations for how the container behaves during updates.","properties":{"stagger":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"description":"When set, Cycle will pick a random time from `0 - this duration`, and stagger the instances so they all start at different times (up to the time specified here)."}}},"restart":{"description":"Configuration options for how Cycle should handle restarting this container (i.e. in case the process inside the container dies).","type":["object","null"],"required":["condition","delay","max_attempts"],"properties":{"condition":{"description":"Under what circumstances Cycle should try to restart this container.","type":"string","enum":["always","never","failure"]},"delay":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"How long the platform will wait between restart attempts."},"max_attempts":{"type":"integer","description":"The maximum number of restart attempts Cycle will make."},"notify":{"description":"Configuration options for notifying on container restart.","type":["object","null"],"properties":{"emails":{"description":"A list of emails Cycle will attempt to notify when a container restarts.","type":"array","items":{"type":"string"}},"web_hook":{"description":"An endpoint Cycle will make a request to.\nThe post body will contain an object that looks like: ``` {\n \"instance_id\": ,\n \"container_id\": ,\n \"environment_id\": ,\n \"error\": ,\n \"time\": \n} ```\n","type":"string"}}}}},"health_check":{"description":"Configuration options for automated container health checks.","type":["object","null"],"required":["command","retries","interval","timeout","restart"],"properties":{"command":{"type":"string","description":"The command or script to run to verify the health of the container. This script is run inside the container by Cycle.\nThis command accepts two types of entries:\n- The first is a reference to a script that already lives in the container filesystem. This can be defined by giving the full path to the script as the value. - The second format is an inline script. If you need the code to execute within a shell, wrap the commands in escaped quotes like this `\"\\\"curl -s -o /dev/console -w \\\"%{http_code}\\\" http://localhost:3000/_health | grep '200' && exit 0 || exit 1\\\"\"`. Do not use the `/bin/sh -c ` format, this will not be accepted.\n","example":"/bin/sh healthcheck.sh"},"retries":{"type":"integer","description":"The number of times to retry the command before marking an instance unhealthy."},"interval":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"How long to wait between running health checks."},"timeout":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"How long before a health check attempt times out."},"restart":{"type":"boolean","description":"A boolean where true represents the desire for the container to restart if any instance is unhealthy."},"delay":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"description":"How long to wait after a container start event before running health checks."}}},"telemetry":{"description":"Configuration options for how the instance telemetry (CPU usage, etc) is handled.","type":["object","null"],"required":["disable"],"properties":{"retention":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"description":"How long telemetry data should be retained."},"interval":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"description":"The duration between samples."},"web_hook":{"type":["string","null"],"description":"A URL where Cycle will send telemetry data to. The payload will be an instance resource snapshot."},"disable":{"type":"boolean","description":"If true, Cycle will not aggregate telemetry for this container's instances."}}}}},"scaling":{"description":"Configuration options for auto-scaling.","anyOf":[{"title":"StackContainerConfigScaling.yml","type":"object","description":"Stack configuration options for auto-scaling.","required":["autoscale_group","instances","window","thresholds"],"properties":{"autoscale_group":{"anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/identifier"},{"type":"null"}],"description":"The identifier of the auto-scaling group assigned to this container. The auto-scale group determines which infrastructure this container can spin up if it needs more resources to meet demand. Setting it to `null` will limit auto-scaling to only instances."},"instances":{"type":"object","description":"Describes the criteria for deploying new instances when an auto-scale criteria is met.","required":["delta","max","max_server","min_ttl"],"properties":{"delta":{"type":"integer","description":"Number of additional instances the auto-scaler will add/subtract per scaling event."},"max":{"type":"integer","description":"Maximum additional instances the auto-scaler will run at any time."},"max_server":{"type":"integer","description":"Minimum number of instances per server."},"min_ttl":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"Minimum amount of time an instance will live."}}},"window":{"description":"Duration in which the auto-scaler will watch for changes.","$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},"thresholds":{"description":"An array of rules that dictate when a scaling event will be triggered.","type":"array","items":{"title":"StackContainerScaleThreshold","type":"object","description":"Discriminated union describing the different types of scaling threshold and their respective details","discriminator":{"propertyName":"type","mapping":{"ram":"./StackContainerScaleThresholdRam.yml","cpu":"./StackContainerScaleThresholdCpu.yml","network-connections":"./StackContainerScaleThresholdNetworkConnections.yml","network-requests":"./StackContainerScaleThresholdNetworkRequests.yml","network-throughput":"./StackContainerScaleThresholdNetworkThroughput.yml"}},"oneOf":[{"title":"StackContainerScaleThresholdRam","type":"object","description":"Describes the RAM threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["ram"]},"details":{"type":"object","required":["used"],"properties":{"used":{"type":"string","description":"The limit (maximum) amount of RAM each instance of the given container can use before triggering a scaling event.","examples":["1G","50M"]}}}}},{"title":"StackContainerScaleThresholdCpu","type":"object","description":"Describes the CPU threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["cpu"]},"details":{"type":"object","required":["utilization"],"properties":{"utilization":{"type":"integer"}}}}},{"title":"StackContainerScaleThresholdNetworkConnections","type":"object","description":"Describes the network connections threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["network-connections"]},"details":{"type":"object","required":["connections_total"],"properties":{"connections_total":{"type":"integer"}}}}},{"title":"StackContainerScaleThresholdNetworkRequests","type":"object","description":"Describes the network requests threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["network-requests"]},"details":{"type":"object","required":["requests_total"],"properties":{"requests_total":{"type":"integer"}}}}},{"title":"StackContainerScaleThresholdNetworkThroughput","type":"object","description":"Describes the network throughput threshold at which scaling will occur.","required":["type","details"],"properties":{"type":{"type":"string","enum":["network-throughput"]},"details":{"type":"object","required":["private","bandwidth"],"properties":{"private":{"type":"boolean"},"bandwidth":{"type":"string","description":"The limit (maximum) amount of throughput each instance of the given container can use before triggering a scaling event.","examples":["1G","50M"]}}}}}]}}}},{"type":"null"}]},"runtime":{"anyOf":[{"title":"StackContainerConfigRuntime","description":"Configuration options related to how the container behaves while it is running (environment variables, command overrides, kernel capabilities, etc. )","type":"object","properties":{"workdir":{"type":"string","description":"The working directory to execute the command in."},"command":{"type":"object","description":"The command to execute when this container starts. Will override the default specified in the container.","properties":{"path":{"type":"string"},"args":{"type":"string"}}},"environment_vars":{"type":"object","description":"A map of environment variables that will be injected into the container.","additionalProperties":{"type":"string"}},"namespaces":{"type":"array","description":"Container namespaces to apply. By default, all are applied. Removing/changing this can have security implications.","items":{"type":"string","enum":["ipc","pid","uts","network","mount","user","cgroup"]}},"sysctl":{"type":"object","description":"Sysctl options to apply.","additionalProperties":{"type":"string"}},"rlimits":{"type":"object","description":"RLIMIT options to apply.","additionalProperties":{"type":"object","required":["hard","soft"],"properties":{"hard":{"type":"integer"},"soft":{"type":"integer"}}}},"seccomp":{"type":"object","description":"Configuration options for seccomp. Cycle enables seccomp by default.","required":["disable","rules"],"properties":{"disable":{"type":"boolean"},"rules":{"type":"array","items":{"type":"object","required":["capabilities","syscall"],"properties":{"capabilities":{"type":"object","required":["includes","excludes"],"properties":{"includes":{"type":"string"},"excludes":{"type":"string"}}},"syscall":{"type":"object","required":["names","action"],"properties":{"names":{"type":"array","items":{"type":"string"}},"action":{"type":"string","enum":["SCMP_ACT_KILL","SCMP_ACT_KILL_PROCESS","SCMP_ACT_KILL_THREAD","SCMP_ACT_TRAP","SCMP_ACT_ERRNO","SCMP_ACT_TRACE","SCMP_ACT_ALLOW","SCMP_ACT_LOG","SCMP_ACT_NOTIFY"]},"errnoRet":{"type":"integer"},"args":{"type":"array","items":{"type":"object","required":["index","value","op"],"properties":{"index":{"type":"integer"},"value":{"type":"integer"},"valuetwo":{"type":"integer"},"op":{"type":"string","enum":["SCMP_CMP_NE","SCMP_CMP_LT","SCMP_CMP_LE","SCMP_CMP_EQ","SCMP_CMP_GE","SCMP_CMP_GT","SCMP_CMP_MASKED_EQ"]}}}}}}}}}}},"host":{"description":"Configuration options regarding the underlying host.","type":["object","null"],"properties":{"expose_proc":{"description":"If true, Cycle will mount the `/proc` directory into the container, giving it access to the host metrics. This is useful if you're running i.e. a monitoring agent.","type":["boolean","null"]}}},"privileged":{"description":"If true, the container process will run in fully-privileged mode. **WARNING** This is considered insecure, and should only be done if you know what you're doing.","type":"boolean"},"capabilities":{"type":"array","description":"Additional Linux kernel capabilities to apply to this container process.","items":{"type":"string","enum":["CAP_CHOWN","CAP_FSETID","CAP_DAC_OVERRIDE","CAP_FOWNER","CAP_SETFCAP","CAP_SETGID","CAP_SETUID","CAP_KILL","CAP_MKNOD","CAP_NET_BIND_SERVICE","CAP_NET_RAW","CAP_AUDIT_WRITE","CAP_SYS_CHROOT","CAP_SETPCAP","CAP_DAC_READ_SEARCH","CAP_NET_ADMIN","CAP_NET_BROADCAST","CAP_SYS_ADMIN","CAP_SYS_MODULE","CAP_SYS_NICE","CAP_SYS_PACCT","CAP_SYS_PTRACE","CAP_SYS_RAWIO","CAP_SYS_RESOURCE","CAP_SYS_BOOT","CAP_SYS_TIME","CAP_SYS_TTY_CONFIG","CAP_SYSLOG","CAP_AUDIT_CONTROL","CAP_AUDIT_READ","CAP_IPC_LOCK","CAP_IPC_OWNER","CAP_LINUX_IMMUTABLE","CAP_MAC_ADMIN","CAP_MAC_OVERRIDE","CAP_BLOCK_SUSPEND","CAP_LEASE","CAP_WAKE_ALARM"]}},"rootfs":{"type":"object","description":"Configuration options for the root filesystem.","required":["readonly"],"properties":{"readonly":{"description":"If true, the container's filesystem will be read-only.","type":"boolean"}}}}},{"type":"null"}]},"resources":{"anyOf":[{"title":"StackContainerConfigResources","description":"Configuration options for container resource limits and reserves.","type":"object","required":["cpu","ram"],"properties":{"cpu":{"type":"object","properties":{"shares":{"type":"object","required":["limit","reserve"],"properties":{"limit":{"type":"integer"},"reserve":{"type":"integer"}}},"cpus":{"type":"string"}}},"ram":{"type":"object","properties":{"limit":{"type":"string"},"reserve":{"type":"string"},"swappiness":{"type":"number"}}}}},{"type":"null"}]},"integrations":{"anyOf":[{"title":"StackContainerConfigIntegrations","type":"object","description":"Configuration options for additional integrations/features that Cycle provides.","properties":{"webhooks":{"description":"Enable additional webhooks that Cycle will call out to during the course of a container's lifetime. All webhooks send a payload as an object containing the instance, container, server, and environment IDs.","type":["object","null"],"properties":{"events":{"description":"Webhooks that are triggered during a container event.","type":["object","null"],"properties":{"deploy":{"description":"Cycle will call this endpoint when the container is deployed.","type":["string","null"]},"start":{"description":"Cycle will call this endpoint when the container is started.","type":["string","null"]},"stop":{"description":"Cycle will call this endpoint when the container is stopped.","type":["string","null"]}}},"config":{"description":"The webhook to hit when the container's configuration is changed.","type":["string","null"]}}},"lets_encrypt":{"description":"When enabled, this integration will configure Let's Encrypt certificates that will be injected into the container at runtime. The certificates will be managed by the platform and renewed automatically.","type":["object","null"],"required":["enable"],"properties":{"enable":{"type":"boolean"},"certificate_path":{"type":["string","null"]},"chain_path":{"type":["string","null"]},"key_path":{"type":["string","null"]},"bundle_path":{"type":["string","null"]},"additional_certs_path":{"type":["string","null"]}}},"files":{"description":"When enabled, Cycle will fetch and inject remote files into the container at the specified destination during runtime.","type":["array","null"],"items":{"type":"object","required":["source","destination"],"properties":{"source":{"type":"string"},"destination":{"type":"string"}}}},"backups":{"description":"When enabled, Cycle will automatically manage backups of this container. This is only available for stateful containers.","type":["object","null"],"required":["destination","backup","restore","retention"],"properties":{"integration_id":{"$ref":"#/properties/containers/additionalProperties/properties/image/properties/builder/properties/integration_id","description":"An identifier of an integration that supports backups. All backups will be sent to this destination."},"backup":{"type":"object","description":"Configuration options for how the container should be backed up.","required":["command","timeout","cron_string"],"properties":{"command":{"description":"The command to run to capture a backup. The output sent to `STDOUT` will be captured and sent to the specified integration.","type":"string"},"timeout":{"description":"How long the backup will attempt to run before timing out.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]},"cron_string":{"description":"A cron string describing how often to run the backup command.","type":["string","null"]}}},"restore":{"description":"Configuration options for how the backup should be restored.","type":["object","null"],"required":["command","timeout"],"properties":{"command":{"type":"string"},"timeout":{"description":"The time in seconds for the restore to attempt to complete before timing out.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]}}},"retention":{"description":"How long the platform will keep backups. Default is 1 year.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}],"default":"365d"}}},"shared_file_systems":{"description":"When enabled, Cycle will mount a shared host directory into this container. The directory will be shared with all other containers that mount it.","type":["object","null"],"additionalProperties":{"type":"object","required":["writable","mount_point"],"properties":{"writable":{"type":"boolean"},"mount_point":{"type":"string"}}}}}},{"type":"null"}]}}},"role":{"description":"The role applied to this container. **Not yet implemented**","type":["string","null"],"enum":["conductor"]},"volumes":{"description":"A list of configurations for volumes that will be attached to the container. Only applicable if the container is set to `stateful`.","type":["array","null"],"items":{"title":"StackContainerVolume","description":"A container volume configuration.","type":"object","required":["destination","read_only"],"properties":{"local":{"description":"Configuration options for local volumes.","type":"object","required":["max_size"],"properties":{"max_size":{"description":"The maximum size this volume can grow to. Container volumes on Cycle are thinly provisioned, meaning this isn't an allocation - the volume will only use the space it needs up to this size.","type":"string","examples":["5G","500M"]},"storage_pool":{"description":"A boolean where true signifies using the largest drive over 2TB for the target server.","type":"boolean"}}},"destination":{"description":"The path this volume should be mounted at inside the container.","type":"string"},"read_only":{"description":"If true, the container will be unable to write data to the volume.","type":"boolean"},"remote_access":{"description":"Configuration options for setting up remote access to this volume via SFTP.","type":"object","required":["enable","password"],"properties":{"enable":{"description":"If true, this volume will be accessible over SFTP.","type":"boolean"},"ips":{"description":"A list of IPs that SFTP access will be limited to.","type":"array","items":{"type":"string"}},"web_hook":{"description":"If set, Cycle will call out to this URL for authentication. Anything other than a 200 response will be considered a validation failure.","type":"string"},"password":{"type":"object","description":"The password used for logging in to this volume via SFTP.","required":["algorithm","data"],"properties":{"algorithm":{"type":"string","description":"The algorithm the password is encoded with. `raw` means the password is plain-text.","enum":["raw","sha512","md5"]},"data":{"description":"The password string.","type":"string"}}}}}}}},"deprecate":{"description":"If true, the container is marked as `deprecated`, and cannot be started anymore. Deprecated containers also don't count toward resource utilization.","type":"boolean"},"lock":{"description":"If true, the container is marked as `locked` and cannot be deleted in any way until the lock is lifted.","type":"boolean"}}}},"services":{"title":"StackSpecServices","type":["object","null"],"properties":{"discovery":{"type":["object","null"],"properties":{"hosts":{"type":["object","null"],"additionalProperties":{"type":"object","properties":{"ipv4":{"type":["array","null"],"items":{"type":"string"}},"ipv6":{"type":["array","null"],"items":{"type":"string"}}}}}}},"loadbalancer":{"anyOf":[{"title":"StackSpecLoadBalancerConfig","type":"object","description":"The config object for the loadbalancer service.","discriminator":{"propertyName":"type","mapping":{"haproxy":"types/haproxy/HaProxyLbType.yml","v1":"types/v1/V1LbType.yml","default":"types/DefaultLbType.yml"}},"oneOf":[{"title":"HaProxyLbType","type":"object","required":["type","details","ipv4","ipv6"],"properties":{"ipv4":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv4."},"ipv6":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv6."},"type":{"type":"string","enum":["haproxy"]},"details":{"anyOf":[{"type":"object","description":"Describes settings that are passed to HAProxy within the load balancer.","required":["default","ports"],"properties":{"default":{"description":"Settings that are applied to any port that is not overridden in the following ports section.","$ref":"#/properties/services/properties/loadbalancer/anyOf/0/oneOf/0/properties/details/anyOf/0/properties/ports/additionalProperties"},"ports":{"description":"An object that defines how HAProxy will act on a specific port. The key is a custom port, and the value is the same settings object found under `default` above.","type":"object","additionalProperties":{"title":"HAProxyConfig","type":"object","required":["frontend","backend"],"properties":{"frontend":{"type":"object","description":"Settings that describe how incoming traffic to the load balancer is handled.","required":["mode","max_connections","timeouts"],"properties":{"mode":{"type":"string","description":"The type of traffic expected by the load balancer for this port. Can be either: \n - tcp: Traffic is forwarded without any parsing or additional manipulation. \n - http: Traffic is treated as web traffic. If a LINKED record is configured for a container exposing this port, the domain will be parsed and it will be forwarded to the proper container. This allows multiple services to run on port 80 in the same environment.","enum":["tcp","http"]},"max_connections":{"type":["integer","null"],"description":"The number of simultaneous connections that can be processed at a time."},"timeouts":{"type":["object","null"],"description":"Various options for handling timeouts when communicating with the client.","required":["client_secs","client_fin_ms","http_keep_alive_ms","http_request_ms"],"properties":{"client_secs":{"type":["integer","null"],"description":"The number of seconds the load balancer will wait for a response from a client before disconnecting."},"client_fin_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for a client to send it data when one direction is already closed. This is particularly useful to avoid keeping connections in a waiting state for too long when clients do not disconnect cleanly."},"http_keep_alive_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for a new HTTP request to start coming after a response was set. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-timeout%20http-request) for more information. (`http` mode only)"},"http_request_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for a complete HTTP request. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-timeout%20http-request) for more information. (`http` mode only)"}}}}},"backend":{"type":"object","description":"Settings related to how the load balancer routes connections to container instances.","required":["balance","timeouts"],"properties":{"balance":{"type":"string","description":"How connections are balanced across your container instances. Can be one of the following: \n - `roundrobin`: Each container instance is used in turns. \n - `static-rr`: Each container instance is used in turns, but is faster than Round Robin at the expense of being less dynamic. \n - `leastconn`: Routes traffic to the instance with the least number of active connections. \n - `first`: Routes traffic to the first available instance. \n - `source`: The same client IP always reaches the same container instance as long as no instance goes down or up.","enum":["roundrobin","static-rr","leastconn","first","source"]},"timeouts":{"type":["object","null"],"description":"Various options for handling timeouts when communicating with a container instance behind the load balancer.","required":["server_secs","server_fin_ms","connect_ms","queue_ms","tunnel_secs"],"properties":{"server_secs":{"type":["integer","null"],"description":"The number of seconds the load balancer will wait for a response from the container instance. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4.2-timeout%20server) for more information."},"server_fin_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for the server to send data when one direction is already closed. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4-timeout%20server-fin) for more information."},"connect_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will wait for a successful connection to a container instance. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4-timeout%20connect) for more information."},"queue_ms":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will hold connections in a queue when the maximum number of connections has been reached. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4-timeout%20queue) for more information."},"tunnel_secs":{"type":["integer","null"],"description":"The number of milliseconds the load balancer will allow for inactivity on a bidirectional tunnel. See the [HAProxy Docs](https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#4-timeout%20tunnel) for more information."}}}}}}}}}},{"type":"null"}]},"bind_host":{"description":"Binds the load balancer to the host server IP address. \n\n**Pros**: This allows for significantly lower cost (utilizing fewer IPv4 addresses), and enables building out a true edge network with lower latency.\n**Cons**: Only 1 environment is allowed on the host. This is because the load balancer is the only ingress point for an environment, and if it is sharing\nthe same IP as the host, that host can only operate under that environment.\n","type":["boolean","null"]}}},{"title":"V1LbType","type":"object","required":["type","details","ipv4","ipv6"],"properties":{"ipv4":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv4."},"ipv6":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv6."},"type":{"type":"string","enum":["v1"]},"details":{"title":"V1LbConfig","type":"object","required":["controllers"],"properties":{"controllers":{"type":"array","description":"A configuration for a specific port.","items":{"title":"V1LbController","type":"object","required":["default","identifier","transport"],"properties":{"default":{"type":"boolean"},"identifier":{"type":"string","description":"A human-readable identifier for this controller. It will default to the port, i.e. `port-443`, but can be renamed to anything, such as the service this controller represents."},"transport":{"title":"V1LbControllerTransport","description":"Defines how traffic comes in to the load balancer, and how the load balancer handles it.","type":"object","required":["mode","config","routers","disable"],"properties":{"disable":{"type":"boolean","description":"When true, this controller is disabled and will not be used."},"mode":{"type":"string","description":"The kind of traffic (http/tcp/udp) that will be sent to the load balancer.","enum":["tcp","udp","http"]},"config":{"type":"object","description":"Defines how the transport for this controller operates.","required":["performance","ingress","timeouts","verbosity"],"properties":{"performance":{"type":"boolean","description":"Enable/disable performance mode. If enabled, some telemetry will be disabled to dedicate full processing to handling requests.\nYou will not see per-request breakdowns or URL logging if performance mode is enabled.\n"},"ingress":{"type":"object","description":"Defines how traffic gets into the load balancer.","required":["port"],"properties":{"port":{"type":"integer","description":"The port inbound trafic is accepted on."},"tls":{"type":["object","null"],"required":["enable"],"properties":{"enable":{"type":"boolean","description":"Enables or disables TLS."}}}}},"timeouts":{"type":"object","description":"Defines settings for various types of timeouts.","required":["idle"],"properties":{"idle":{"description":"The total amount of time a connection can be idle before being killed.","$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"}}},"verbosity":{"type":"string","description":"Verbosity describes the level of logging detail for the controller","enum":["low","normal","high","debug"]},"extension":{"type":"object","description":"Extended configurations for the specified transport mode (http/tcp)","discriminator":{"propertyName":"type","mapping":{"tcp":"transports/TcpTransportConfig.yml","http":"transports/HttpTransportConfig.yml","udp":"transports/UdpTransportConfig.yml"}},"oneOf":[{"title":"TcpTransportConfig","description":"Additional configuration options for the TCP transport mode.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["tcp"]},"details":{"type":"object","required":["connections","telemetry"],"properties":{"connections":{"type":"object","additionalProperties":{}},"telemetry":{"type":"object","description":"Configuration options for how telemetry is handled on the load balancer.","properties":{"persist_restarts":{"type":["boolean","null"],"description":"If true, Cycle will maintain telemetry/metrics across load balancer restarts."},"disable_router_metrics":{"description":"Determines if the load balancer will track router metrics. Defaults to false.","type":"boolean","default":false},"tracking_window":{"description":"Determines how long the load balancer will track a URL from its last hit. If there is zero activity for this duration, the metrics will be dropped. Helps reduce noise by not tracking URLs that are occasionally hit. Defaults to 8h.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]}}}}}}},{"title":"HttpTransportConfig","description":"Additional configuration options for the HTTP transport mode.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["http"]},"details":{"type":"object","required":["connections","telemetry"],"properties":{"connections":{"type":"object","required":["max_idle_conns_per_connection"],"description":"Defines extra configuration options connections to the load balancer","properties":{"max_idle_conns_per_connection":{"type":["integer","null"],"description":"Maximum number of simultaneous connections (via http/2) per connection."}}},"telemetry":{"type":"object","description":"Configuration options for how telemetry is handled.","required":["disable_url_tracking","disable_router_metrics"],"properties":{"persist_restarts":{"type":["boolean","null"],"description":"If true, Cycle will maintain telemetry/metrics across load balancer restarts."},"disable_url_tracking":{"description":"Determines if the load balancer will track url metrics. Defaults to false.","type":"boolean","default":false},"disable_router_metrics":{"description":"Determines if the load balancer will track router metrics. Defaults to false.","type":"boolean","default":false},"max_trackable_urls":{"description":"Determines how many URLs the load balancer will track at one time. Defaults to 150.","type":["integer","null"]},"tracking_window":{"description":"Determines how long the load balancer will track a URL from its last hit. If there is zero activity for this duration, the metrics will be dropped. Helps reduce noise by not tracking URLs that are occasionally hit. Defaults to 8h.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]},"track_invalid_requests":{"description":"Whether or not to track invalid requests. An invalid request is a request that came in that no router existed for. Usually this means bot requests. Defaults to false.","type":["boolean","null"]},"group_paths":{"description":"Group paths is used to group URLs. The key is the URL and the value is the regex used to match URLs.","type":["object","null"],"additionalProperties":{"type":"string"}},"ignore_paths":{"description":"An array of paths to exclude from tracking.","type":["array","null"],"items":{"type":"string"}}}}}}}},{"title":"UdpTransportConfig","description":"Additional configuration options for the UDP transport mode.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["udp"]},"details":{"type":"object","required":["connections","telemetry"],"properties":{"connections":{"type":"object","additionalProperties":{}},"telemetry":{"type":"object","description":"Configuration options for how telemetry is handled on the load balancer.","properties":{"persist_restarts":{"type":["boolean","null"],"description":"If true, Cycle will maintain telemetry/metrics across load balancer restarts."},"disable_router_metrics":{"description":"Determines if the load balancer will track router metrics. Defaults to false.","type":"boolean","default":false},"tracking_window":{"description":"Determines how long the load balancer will track a URL from its last hit. If there is zero activity for this duration, the metrics will be dropped. Helps reduce noise by not tracking URLs that are occasionally hit. Defaults to 8h.","anyOf":[{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"},{"type":"null"}]}}}}}}}]}}},"routers":{"type":"array","description":"Defines where traffic is sent. Many can be defined per controller.","items":{"title":"V1LbRouterConfig","description":"A specific router configuration that describes how traffic matching the rule is handled.","type":"object","required":["match","mode","config"],"properties":{"match":{"type":"object","description":"The ruleset for this router to be selected. If both `domains`` and `internal_port` are null, then this match acts as a wildcard and will match all.","required":["domains","internal_port"],"properties":{"domains":{"type":["array","null"],"description":"The specific domains to match against.","items":{"type":"string"}},"internal_port":{"type":["array","null"],"description":"The specific ports to match against.","items":{"type":"integer"}},"path":{"type":["string","null"]}}},"mode":{"type":"string","description":"How to route the traffic to the destination.\n`random`: Pick a valid destination at random.\n`round-robin`: Send each request to the 'next' destination on the list, restarting from the beginning when the last destination is used.\n","enum":["random","round-robin"]},"config":{"type":"object","required":["sticky_sessions","destination_retries","timeouts"],"properties":{"sticky_sessions":{"type":"boolean","description":"If a request comes in from the same origin, ensure it hits the same destination."},"destination_retries":{"type":"integer","description":"If a destination is unavailable, retry up to [x] times, instead of immediately failing with a 503/504 error."},"tls":{"type":["object","null"],"description":"TLS termination configuration. If null, the platform will use the default configuration. Port 443 by default has TLS termination enabled.","properties":{"server_name":{"type":["string","null"],"description":"[Advanced] Change the domain the controller listens on.\n"},"allow_insecure":{"type":["boolean","null"],"description":"If enabled, accept TLS traffic with an invalid certificate. This is usually done for development/testing, and is not recommended for production use."},"client_cert_auth":{"description":"A PEM encoded string of certificates.","type":["string","null"]},"client_auth":{"description":"Defines how to validate the connecting TLS certificate.\n`none`: Do not require a TLS certificate to be sent\n`request`: Asks the client to send a TLS certificate, but does not require nor validate it.\n`require`: Requires a certificate be sent for the request to be valid, but does not validate the certificate.\n`require-verify`: Requires both that the client send a certificate, and that the certificate is valid. This is required when using https.\n","oneOf":[{"type":"string","enum":["none","request","require","require-verify"]},{"type":"null"}]}}},"timeouts":{"type":"object","description":"Defines how the length of various sorts of timeouts when communicating with the destination.","required":["destination_connection"],"properties":{"destination_connection":{"$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0","description":"The duration the load balancer will wait before timing out while attempting to connect to the destination."}}},"extension":{"type":"object","description":"Additional configuration options specific to the selected mode (tcp/http).","discriminator":{"propertyName":"type","mapping":{"tcp":"routers/TcpRouterConfig.yml","udp":"routers/UdpRouterConfig.yml","http":"routers/HttpRouterConfig.yml"}},"oneOf":[{"title":"TcpRouterConfig","description":"Additional configuration options for TCP mode routers","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["tcp"]},"details":{"type":"object","additionalProperties":{}}}},{"title":"HttpRouterConfig","description":"Additional configuration options for HTTP mode routers.","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["http"]},"details":{"type":"object","properties":{"redirect":{"type":["object","null"],"required":["auto_https_redirect","remove_www"],"description":"Defines a built-in redirect for HTTP mode routers","properties":{"auto_https_redirect":{"type":"boolean","description":"If enabled and a sibling controller exists for port 443, requests will be auto redirected to it. Essentially sets up automatic TLS redirection for this router."},"remove_www":{"description":"If true, any request comes in with \"www\" prefix will be permanently redirected to the same path without www.","type":"boolean"},"port":{"type":["integer","null"],"description":"The port to redirect traffic to."},"scheme":{"type":["string","null"],"description":"The scheme to redirect to. (i.e. `https`)"},"url":{"type":["string","null"],"description":"A specific URL to redirect to."}}},"forward":{"type":["object","null"],"properties":{"scheme":{"type":["string","null"]},"content_mod":{"description":"Allows the load balancer to modify content before it reaches the user.","type":["object","null"],"properties":{"replace":{"description":"An array that describes a list of replacement match/value pairs.","type":["array","null"],"items":{"type":"object","required":["match","value"],"properties":{"match":{"description":"String that will be replaced.","type":"string"},"value":{"description":"Replacement value.","type":"string"}}}}}}}},"proxy":{"type":["object","null"],"properties":{"domain":{"type":["string","null"],"description":"The proxy domain for this router."},"content_mod":{"description":"Allows the load balancer to modify content before it reaches the user.","type":["object","null"],"properties":{"replace":{"description":"An array that describes a list of replacement match/value pairs.","type":["array","null"],"items":{"type":"object","required":["match","value"],"properties":{"match":{"description":"String that will be replaced.","type":"string"},"value":{"description":"Replacement value.","type":"string"}}}}}}}},"caching":{"type":["object","null"],"properties":{"files":{"type":["array","null"],"items":{"type":"object","required":["match","ttl"],"properties":{"match":{"description":"Regex string that describes the files to cache.","example":"(.*)\\\\.(js|jpg|css|png|svg)$","type":"string"},"ttl":{"description":"Time string that describes the time to live.","$ref":"#/properties/scoped_variables/items/properties/access/properties/internal_api/properties/duration/anyOf/0"}}}}}}}}}},{"title":"UdpRouterConfig","description":"Additional configuration options for UDP mode routers","type":"object","required":["type","details"],"properties":{"type":{"type":"string","enum":["udp"]},"details":{"type":"object","additionalProperties":{}}}}]}}}}}}}}}}},"controller_template":{"anyOf":[{"$ref":"#/properties/services/properties/loadbalancer/anyOf/0/oneOf/1/properties/details/properties/controllers/items"},{"type":"null"}]}}},"bind_host":{"description":"Binds the load balancer to the host server IP address. \n\n**Pros**: This allows for significantly lower cost (utilizing fewer IPv4 addresses), and enables building out a true edge network with lower latency.\n**Cons**: Only 1 environment is allowed on the host. This is because the load balancer is the only ingress point for an environment, and if it is sharing\nthe same IP as the host, that host can only operate under that environment.\n","type":["boolean","null"]}}},{"title":"DefaultLbType","type":"object","required":["type","details","ipv4","ipv6"],"properties":{"ipv4":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv4."},"ipv6":{"type":"boolean","description":"Allow / disallow traffic to be routed via IPv6."},"type":{"type":"string","enum":["default"]},"details":{"oneOf":[{"$ref":"#/properties/services/properties/loadbalancer/anyOf/0/oneOf/0/properties/details/anyOf/0"},{"$ref":"#/properties/services/properties/loadbalancer/anyOf/0/oneOf/1/properties/details"},{"type":"null"}]}}}]},{"type":"null"}]},"vpn":{"type":"object","required":["auth","allow_internet"],"properties":{"auth":{"type":"object","required":["cycle_accounts","vpn_accounts"],"properties":{"webhook":{"type":"string"},"cycle_accounts":{"type":"boolean"},"vpn_accounts":{"type":"boolean"}}},"allow_internet":{"type":"boolean"}}}}},"annotations":{"type":"object","description":"Additional meta info about the stack.","additionalProperties":{}}}} \ No newline at end of file