# generated by datamodel-codegen:
#   filename:  application.json
#   timestamp: 2023-03-24T12:37:18+00:00

from __future__ import annotations

from enum import Enum
from typing import Dict, List, Optional, Union

from pydantic import BaseModel, Field, confloat, conint, constr
from typing_extensions import Literal


class BasicAuthCreds(BaseModel):
    """
    +label=Username and password for service auth
    """

    type: Literal["basic_auth"]
    username: constr(regex=r"^[a-z0-9-@\.]{1,64}$") = Field(
        ...,
        description="+label=Username for service auth\n+message=Upto 64 lower case alphanumeric character long",
    )
    password: constr(regex=r"^[a-zA-Z0-9\.!@#$%^&*()_+=\-]{1,64}$") = Field(
        ...,
        description="+label=Password for service auth\n+message=Password should not be more than 64 characters",
    )


class BlueGreen(BaseModel):
    """
    +docs=This strategy brings up the new release completely before switching the complete load to the new release.
    This minimizes the time that two versions are serving traffic at the same time.
    +label=Blue Green strategy
    """

    type: Literal["blue_green"] = Field(..., description="+value=blue_green")
    enable_auto_promotion: bool = Field(
        False,
        description="+docs=Promote the new release to handle the complete traffic. A manual promotion would be needed if this is disabled\n+label=Auto-promotion",
    )
    auto_promotion_seconds: conint(ge=0) = Field(
        30,
        description="+docs=Promote the new release to handle the complete traffic after waiting for these many seconds\n+label=Auto-promotion seconds",
    )


class CPUUtilizationMetric(BaseModel):
    type: Literal["cpu_utilization"]
    value: conint(lt=100, gt=0) = Field(
        ...,
        description="+label=CPU utilization %\n+usage=Percentage of cpu request averaged over all replicas which the autoscaler should try to maintain",
    )


class CanaryStep(BaseModel):
    weight_percentage: conint(ge=0, le=100) = Field(
        ...,
        description="+docs=Percentage of total traffic to be shifted to the canary release.\nThe rest will continue to go to the existing deployment\n+label=Canary weight percentage\n+unit=%\n+placeholder=Weight",
    )
    pause_duration: conint(ge=0) = Field(
        30,
        description="+docs=Duration for which to pause the release. The release process will wait for these seconds before proceeding to the next step.\nIf this is not set, the step will pause indefinitely on this step\n+label=Pause duration\n+unit=seconds\n+placeholder=Duration",
    )


class DockerFileBuild(BaseModel):
    """
    +docs=Describes that we are using a dockerfile to build our image
    +label=Docker File (I already have Docker File)
    +icon=fa-brands fa-docker:#0db7ed
    """

    type: constr(regex=r"^dockerfile$") = Field(..., description="+value=dockerfile")
    dockerfile_path: str = Field(
        "./Dockerfile",
        description="+label=Path to Dockerfile\n+usage=The file path of the Dockerfile relative to project root path.",
    )
    build_context_path: str = Field(
        "./",
        description="+label=Path to build context\n+usage=Build context path for the Dockerfile relative to project root path.",
    )
    command: Optional[Union[str, List[str]]] = Field(
        None,
        description="+label=Entrypoint Override\n+usage=Override the command to run when the container starts\nWhen deploying a Job, the command can be templatized by defining `params` and referencing them in command\nE.g. `python main.py --learning_rate {{learning_rate}}`",
    )


class FileMount(BaseModel):
    mount_path: str = Field(
        ..., description="+usage=Path at which data is to be mounted"
    )
    is_base64_encoded: bool = Field(
        False, description="+usage=Set this flag if your data values are base64 encoded"
    )
    data: Dict[str, str] = Field(
        ...,
        description="+usage=Data to be mounted. Each key will be the filename and the value will be the file content. Files will be mounted at mount_path",
    )


class GPU(BaseModel):
    type: str = Field(
        ...,
        description="+label=Type\n+usage=Name of the Nvidia GPU. One of [K80, P4, P100, V100, T4, A10G, A100_40GB, A100_80GB]\nOne instance of the card contains the following amount of memory:\nK80: 12 GB\nP4: 8 GB\nP100: 16 GB\nV100: 16 GB\nT4: 16 GB\nA10G: 24 GB\nA100_40GB: 40GB\nA100_80GB: 80 GB",
    )
    count: conint(ge=1, le=16) = Field(
        1,
        description="+label=Count\n+usage=Count of GPUs to provide to the application\nNote the exact count and max count available for a given GPU type depends on cloud provider and cluster type.\nK80: 1-16 on AWS EKS, 1-8 on GCP GKE Standard, NA on GCP GKE Autopilot\nP4: NA on AWS EKS, 1-4 on GCP GKE Standard, NA on GCP GKE Autopilot\nP100: NA on AWS EKS, 1-4 on GCP GKE Standard, NA on GCP GKE Autopilot\nV100: 1-8 on AWS EKS, 1-8 on GCP GKE Standard, NA on GCP GKE Autopilot\nT4: 1-8 on AWS EKS, 1-4 on GCP GKE Standard, exactly 1 or 2 or 4 on GCP GKE Autopilot\nA10G: 1-8 on AWS EKS, NA on GCP GKE Standard, NA on GCP GKE Autopilot\nA100_40GB: 1-8 on AWS EKS, 1-16 on GCP GKE Standard, exactly 1 or 2 or 4 or 8 or 16 on GCP GKE Autopilot\nA100_80GB: 1-8 on AWS EKS, 1-8 on GCP GKE Standard, NA on GCP GKE Autopilot",
    )


class GitSource(BaseModel):
    """
    +docs=Describes that we are using code stored in a git repository to build our image
    +label=Git Source
    +icon=fa-solid fa-code-branch:black
    +sort=300
    """

    type: constr(regex=r"^git$") = Field(..., description="+value=git")
    repo_url: constr(
        regex=r"^(http(s?)://)(github\.com|(.+@)*bitbucket\.org|gitlab\.com).*$"
    ) = Field(
        ...,
        description="+label=Repo URL\n+usage=The repository URL.\n+sort=1\n+message=Needs to be a valid Github, Bitbucket or Gitlab link",
    )
    ref: str = Field(
        ..., description="+label=Commit SHA\n+usage=The commit SHA.\n+sort=2"
    )
    branch_name: Optional[str] = Field(
        None,
        description="+label=Branch Name\n+usage=Selecting branch will select latest commit SHA of the branch.\n+sort=3\n+ignore",
    )


class HttpProbe(BaseModel):
    """
    +docs=Describes the Instructions for assessing container health by executing an HTTP GET request.
    To learn more you can go [here](https://docs.truefoundry.com/docs/add-health-checks-to-deployments)
    +label=Instructions for assessing container health by executing an HTTP GET request.
    """

    type: constr(regex=r"^http$") = Field(..., description="+sort=1\n+value=http")
    path: str = Field(
        ...,
        description="+usage=The endpoint, relative to the port, to which the HTTP GET request should be directed.\n+sort=2",
    )
    port: conint(ge=0, le=65535) = Field(
        ...,
        description="+usage=The TCP socket within the container to which the HTTP GET request should be directed.\n+sort=3",
    )
    host: Optional[str] = Field(
        None,
        description="+sort=4\n+usage=Host name to connect to, defaults to the pod IP",
    )
    scheme: str = Field(
        "HTTP", description="+sort=5\n+usage=Scheme to use for connecting to the host"
    )


class HuggingfaceModelHub(BaseModel):
    """
    +docs=Huggingface model hub (deploy a model from HF model hub)
    +label=Huggingface model hub
    +usage=Deploy a model from HF model hub
    """

    type: constr(regex=r"^hf-model-hub$") = Field(
        ..., description="+value=hf-model-hub"
    )
    model_id: constr(regex=r"^[\w\-\._/]+$") = Field(
        ...,
        description="+label=Model repository name\n+usage=The name of the model that you want to deploy. Example:- `t5-small`, `philschmid/bart-large-cnn-samsum`.\n+placeholder=philschmid/bart-large-cnn-samsum",
    )
    pipeline: Optional[constr(regex=r"^[a-z0-9\-_]+$")] = Field(
        None,
        description="+label=Pipeline\n+usage=Pipeline to use for inference. If not set, we will try to infer the `task` name for the given model.\nExamples:- `summarization`, `text-generation`, `text-classification`, etc.\nYou can read more about HF pipelines here:- https://huggingface.co/docs/transformers/pipeline_tutorial\nYou can find a list of tasks here:- https://huggingface.co/docs/transformers/v4.24.0/en/main_classes/pipelines#transformers.pipeline.task\n+placeholder=summarization",
    )


class Image(BaseModel):
    """
    +docs=Describes that we are using a pre-built image stored in a Docker Image registry
    +label=Docker Image (Deploy an existing image)
    +icon=fa-brands fa-docker:#0db7ed
    """

    type: constr(regex=r"^image$") = Field(..., description="+value=image")
    image_uri: str = Field(
        ...,
        description="+label=Image URI\n+usage=The image URI. Specify the name of the image and the tag.\nIf the image is in Dockerhub, you can skip registry-url (for e.g. `tensorflow/tensorflow`).\nYou can use an image from a private registry using Advanced fields\n+placeholder=registry-url/account/image:version (e.g. docker.io/tensorflow/tensorflow)",
    )
    docker_registry: Optional[str] = Field(
        None,
        description="+docs=FQN of the container registry. You can the FQN of your desired container registry (or add one)\nin the  Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
    )
    command: Optional[Union[str, List[str]]] = Field(
        None,
        description="+label=Entrypoint Override\n+usage=Override the command to run when container starts.\nWhen deploying a Job, the command can be templatized by defining `params` and referencing them in command\nE.g. `python main.py --learning_rate {{learning_rate}}`",
    )


class LocalSource(BaseModel):
    """
    +docs=Describes that we are using code stored in a local developement environment to build our image
    +label=Local
    +icon=fa-folder:black
    +sort=100
    """

    type: constr(regex=r"^local$") = Field(..., description="+value=local")
    project_root_path: str = Field("./", description="+usage=Local project root path.")
    local_build: bool = Field(True, description="run docker build locally")


class Manual(BaseModel):
    """
    +docs=Describes that we are going to manually trigger our job.
    +label=Manual
    +usage=Trigger the job manually. [Docs](https://docs.truefoundry.com/docs/more-configurations)
    """

    type: constr(regex=r"^manual$") = Field(..., description="+value=manual")


class Param(BaseModel):
    name: constr(regex=r"^[a-z][a-z0-9\-_]{0,30}[a-z0-9]$") = Field(
        ...,
        description="+usage=Name of the param\n+message=name can contain lower case alphabets, digits, underscore (_) and hypen (-). It can be 32 characters long, should start with an alphabet, and should end with either an alphabet or digit.",
    )
    description: Optional[constr(regex=r"^.{1,127}$")] = Field(
        None,
        description="+usage=Description of param\n+message=description cannot be longer than 127 characters",
    )
    default: Optional[constr(regex=r"^.{1,127}$")] = Field(
        None,
        description="+usage=Default value or placeholder\n+message=default value cannot be longer than 127 characters\n+label=Default value",
    )


class Protocol(str, Enum):
    """
    +usage=Protocol for the port.
    """

    TCP = "TCP"
    UDP = "UDP"


class AppProtocol(str, Enum):
    """
    +label=Application Protocol
    +usage=Application Protocol for the port.
    Select the application protocol used by your service. For most use cases, this should be `http`(HTTP/1.1).
    If you are running a gRPC server, select the `grpc` option.
    This is only applicable if `expose=true`.
    """

    http = "http"
    grpc = "grpc"
    tcp = "tcp"


class Port(BaseModel):
    """
    +docs=Describes the ports the service should be exposed to.
    """

    port: conint(ge=0, le=65535) = Field(
        80, description="+usage=Port number to expose."
    )
    protocol: Protocol = Field("TCP", description="+usage=Protocol for the port.")
    expose: bool = Field(True, description="+usage=Expose the port")
    host: Optional[
        constr(
            regex=r"^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$"
        )
    ] = Field(
        None,
        description="+usage=Host e.g. ai.example.com, app.truefoundry.com\n+message=Upto 253 characters, each part of host should be at most 63 characters long, can contain alphabets, digits and hypen, must begin and end with an alphanumeric characters. Parts must be separated by periods (.)",
    )
    path: Optional[
        constr(regex=r"^(/([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-_\.]*[a-zA-Z0-9]))*/$")
    ] = Field(
        None,
        description="+usage=Path e.g. /v1/api/ml/, /v2/docs/\n+message=Should begin and end with a forward slash (/). Each part can can contain alphabets, digits and hypen, must begin and end with an alphanumeric characters. Parts should be separated by forward slashes (/)",
    )
    rewrite_path_to: Optional[
        constr(regex=r"^(/([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-_\.]*[a-zA-Z0-9]))*/$")
    ] = Field(
        None,
        description="+label=Rewrite Path to\n+usage=Rewrite the path prefix to a different path.\nIf `path` is `/v1/api` and `rewrite_path_to` is `/api`. The URI in the HTTP request `http://0.0.0.0:8080/v1/api/houses` will be rewritten to `http://0.0.0.0:8080/api/houses` before the request is forwarded your service.\nDefaults to `/`.\nThis is only applicable if `path` is given.\n+message=Should begin and end with a forward slash (/). Each part can can contain alphabets, digits and hypen, must begin and end with an alphanumeric characters. Parts should be separated by forward slashes (/)",
    )
    app_protocol: Optional[AppProtocol] = Field(
        None,
        description="+label=Application Protocol\n+usage=Application Protocol for the port.\nSelect the application protocol used by your service. For most use cases, this should be `http`(HTTP/1.1).\nIf you are running a gRPC server, select the `grpc` option.\nThis is only applicable if `expose=true`.",
    )
    auth: Optional[BasicAuthCreds] = None


class PythonBuild(BaseModel):
    """
    +docs=Describes that we are using python to build a container image with a specific python version and pip packages installed.
    +label=Python Code (I don't have Dockerfile)
    +icon=fa-brands fa-python:#306998
    """

    type: constr(regex=r"^tfy-python-buildpack$") = Field(
        ..., description="+value=tfy-python-buildpack"
    )
    python_version: constr(regex=r"^\d+(\.\d+){1,2}$") = Field(
        "3.9",
        description="+label=Python version\n+usage=Python version to run your application.\n+message=Please enter a valid Python version",
    )
    build_context_path: str = Field(
        "./",
        description="+label=Path to build context\n+usage=Build path relative to project root path.",
    )
    requirements_path: Optional[str] = Field(
        None,
        description="`Path to build context`\n+label=Path to requirements\n+usage=Path to `requirements.txt` relative to\n`Path to build context`",
    )
    pip_packages: Optional[List[str]] = Field(
        None,
        description="+label=Pip packages to install\n+usage=Define pip package requirements.",
    )
    apt_packages: Optional[List[str]] = Field(
        None,
        description='+label=Debian packages to install via apt.\n+usage=Define Debian packages to install via apt.\nE.g. `["ffmpeg", "libsm6", "libxext6"]',
    )
    command: Union[str, List[str]] = Field(
        ...,
        description="Command will be set as the Entrypoint of the generated\nimage.\n+label=Command\n+usage=Command to run when the container starts.\nCommand will be set as the Entrypoint of the generated image.\nWhen deploying a Job, the command can be templatized by defining `params` and referencing them in command\nE.g. `python main.py --learning_rate {{learning_rate}}`",
    )
    cuda_version: Optional[
        constr(
            regex=r"^((\d+\.\d+(\.\d+)?-cudnn\d+-(runtime|devel)-ubuntu\d+\.\d+)|9\.2-cudnn7|10\.0-cudnn7|10\.1-cudnn7|10\.1-cudnn8|10\.2-cudnn7|10\.2-cudnn8|11\.0-cudnn8|11\.1-cudnn8|11\.2-cudnn8|11\.3-cudnn8|11\.4-cudnn8|11\.5-cudnn8|11\.6-cudnn8|11\.7-cudnn8|11\.8-cudnn8)$"
        )
    ] = Field(
        None,
        description="+label=CUDA Version\n+usage=Version of CUDA Toolkit and CUDNN to install in the image\nThese combinations are based off of publically available docker images on docker hub\nYou can also specify a valid tag of the form {cuda_version_number}-cudnn{cudnn_version_number}-{runtime|devel}-ubuntu{ubuntu_version}\nRefer https://hub.docker.com/r/nvidia/cuda/tags for valid set of values\nNote: We use deadsnakes ubuntu ppa to add Python that currently supports only Ubuntu 18.04, 20.04 and 22.04",
    )


class RPSMetric(BaseModel):
    type: Literal["rps"]
    value: conint(ge=1) = Field(
        ...,
        description="+label=Requests per second\n+usage=Average request per second averaged over all replicas that autoscaler should try to maintain",
    )


class RemoteSource(BaseModel):
    """
    +docs=Describes that we are using code stored in a remote respository to build our image
    +label=S3
    +icon=fa-brands fa-aws:black
    +sort=200
    """

    type: constr(regex=r"^remote$") = Field(..., description="+value=remote")
    remote_uri: str = Field(
        ..., description="+docs=Remote repository URI\n+label=Remote URI"
    )


class Resources(BaseModel):
    """
    +docs=Describes the resource constraints for the application so that it can be deployed accordingly on the cluster
    To learn more you can go [here](https://docs.truefoundry.com/docs/resources)
    +icon=fa-microchip
    +label=Resources
    +usage=Set resource constraints for the application. [Docs](https://docs.truefoundry.com/docs/resources)
    """

    cpu_request: confloat(ge=0.001, le=16.0) = Field(
        0.2,
        description="+label=CPU Request\n+sort=1\n+usage=Requested CPU which determines the minimum cost incurred. The CPU usage can exceed the requested\namount, but not the value specified in the limit. 1 CPU means 1 CPU core. Fractional CPU can be requested\nlike `0.5` or `0.05`",
    )
    cpu_limit: confloat(ge=0.001, le=16.0) = Field(
        0.5,
        description="+label=CPU Limit\n+usage=CPU limit beyond which the usage cannot be exceeded. 1 CPU means 1 CPU core. Fractional CPU can be requested\nlike `0.5`. CPU limit should be >= cpu request.\n+sort=2",
    )
    memory_request: conint(ge=1, le=32000) = Field(
        200,
        description="+label=Memory Request\n+usage=Requested memory which determines the minimum cost incurred. The unit of memory is in megabytes(MB).\nSo 1 means 1 MB and 2000 means 2GB.\n+sort=3",
    )
    memory_limit: conint(ge=1, le=32000) = Field(
        500,
        description="+label=Memory Limit\n+usage=Memory limit after which the application will be killed with an OOM error. The unit of memory is\nin megabytes(MB). So 1 means 1 MB and 2000 means 2GB. MemoryLimit should be greater than memory request.\n+sort=4",
    )
    ephemeral_storage_request: conint(ge=1, le=500000) = Field(
        1000,
        description="+label=Storage Request\n+usage=Requested disk storage. The unit of memory is in megabytes(MB).\nThis is ephemeral storage and will be wiped out on pod restarts or eviction\n+sort=5",
    )
    ephemeral_storage_limit: conint(ge=1, le=500000) = Field(
        2000,
        description="+label=Storage Limit\n+usage=Disk storage limit. The unit of memory is in megabytes(MB). Exceeding this limit will result in eviction.\nIt should be greater than the request. This is ephemeral storage and will be wiped out on pod restarts or eviction\n+sort=6",
    )
    gpu: Optional[GPU] = None
    instance_family: Optional[List[str]] = Field(
        None,
        description="+label=Instance family\n+usage=Instance family of the underlying machine to use. Multiple instance families can be supplied.\nThe workload is guaranteed to be scheduled on one of them.",
    )
    shared_memory_size: Optional[conint(ge=64, le=32000)] = Field(
        None,
        description="+label=Shared Memory Size\n+usage=Define the shared memory requirements for your workload. Machine learning libraries like Pytorch can use Shared Memory\nfor inter-process communication. If you use this, we will mount a `tmpfs` backed volume at the `/dev/shm` directory.\nAny usage will also count against the workload's memory limit (`resources.memory_limit`) along with your workload's memory usage.\nIf the overall usage goes above `resources.memory_limit` the user process may get killed.\nShared Memory Size cannot be more than the defined Memory Limit for the workload.",
    )


class Rolling(BaseModel):
    """
    +docs=This strategy updates the pods in a rolling fashion such that a subset of the
    total pods are replaced with new version at one time.
    A commonly used strategy can be to have maxUnavailablePercentage close to 0 so that there
    is no downtime and keep the maxSurgePercentage to around 25%. If you are anyways running
    a large number of pods, the service can often tolerate a few pods going down - so you
    max maxUnavailablePercentage = 10 and maxSurgePercentage=0. You can read about it more
    [here](https://spot.io/resources/kubernetes-autoscaling/5-kubernetes-deployment-strategies-roll-out-like-the-pros/)
    +label=Rolling update strategy
    """

    type: constr(regex=r"^rolling_update$") = Field(
        ..., description="+value=rolling_update"
    )
    max_unavailable_percentage: conint(ge=0, le=100) = Field(
        25,
        description="+label=Max unavailable(%)\n+usage=Percentage of total replicas that can be brought down at one time.\nFor a value of 25 when replicas are set to 12 this would mean minimum (25% of 12) = 3 pods might be unavailable during the deployment.\nSetting this to a higher value can help in speeding up the deployment process.",
    )
    max_surge_percentage: conint(ge=0, le=100) = Field(
        0,
        description="+label=Max Surge(%)\n+usage=Percentage of total replicas of updated image that can be brought up over the total replicas count.\nFor a value of 25 when replicas are set to 12 this would mean (12+(25% of 12) = 15) pods might be running at one time.\nSetting this to a higher value can help in speeding up the deployment process.",
    )


class ConcurrencyPolicy(str, Enum):
    """
    +usage=Choose whether to allow this job to run while another instance of the job is running, or to replace the currently running instance. Allow
    will enable multiple instances of this job to run. Forbid will keep the current instance of the job running and stop a new instance from being run.
    Replace will terminate any currently running instance of the job and start a new one.
    """

    Forbid = "Forbid"
    Allow = "Allow"
    Replace = "Replace"


class Schedule(BaseModel):
    """
    +docs=Describes that we are going to schedule our job to run at a schedule, making our job a cron job.
    +label=Schedule
    +usage=Run the job on a schedule. [Docs](https://docs.truefoundry.com/docs/deploy-a-cron-job)
    """

    type: constr(regex=r"^scheduled$") = Field(..., description="+value=scheduled")
    schedule: str = Field(
        ...,
        description="+docs=Specify the schedule for this job to be run periodically in cron format. [Learn more](https://docs.truefoundry.com/docs/deploy-a-cron-job)\n+usage=Specify the schedule for this job to be run periodically in cron format.\n```\n* * * * *\n| | | | |\n| | | | |___ day of week (0-6) (Sunday is 0)\n| | | |_____ month (1-12)\n| | |_______ day of month (1-31)\n| |_________ hour (0-23)\n|___________ minute (0-59)\n```",
    )
    concurrency_policy: ConcurrencyPolicy = Field(
        "Forbid",
        description="+usage=Choose whether to allow this job to run while another instance of the job is running, or to replace the currently running instance. Allow\nwill enable multiple instances of this job to run. Forbid will keep the current instance of the job running and stop a new instance from being run.\nReplace will terminate any currently running instance of the job and start a new one.",
    )
    timezone: Optional[str] = Field(
        None,
        description='+usage=Timezone against which the cron schedule will be calculated, e.g. "Asia/Tokyo". Default is machine\'s local time.\nhttps://docs.truefoundry.com/docs/list-of-supported-timezones',
    )


class SecretMount(BaseModel):
    type: constr(regex=r"^secret$") = Field(..., description="+value=secret")
    mount_path: constr(regex=r"^\/(?:[^/\n]+\/*)*[^/\n]+(\.[^/\n]+)?$") = Field(
        ...,
        description="+label=File path\n+usage=Absolute file path where the file will be created.\n+message=Please enter a valid file path",
    )
    secret_fqn: constr(regex=r"^tfy-secret:\/\/.+:.+:.+$") = Field(
        ...,
        description="+label=Secret\n+usage=The Truefoundry secret whose value will be the file content.",
    )


class StringDataMount(BaseModel):
    type: constr(regex=r"^string$") = Field(..., description="+value=string")
    mount_path: constr(regex=r"^\/(?:[^/\n]+\/*)*[^/\n]+(\.[^/\n]+)?$") = Field(
        ...,
        description="+label=File Path\n+usage=Absolute file path where the file will be created.\n+message=Please enter a valid file path",
    )
    data: str = Field(..., description="+label=Data\n+usage=The file content.")


class TruefoundryModelRegistry(BaseModel):
    """
    +docs=Truefoundry model registry (deploy a model from TFY model registry)
    +label=Truefoundry model registry
    +usage=Deploy a model from TFY model registry
    """

    type: constr(regex=r"^tfy-model-registry$") = Field(
        ..., description="+value=tfy-model-registry"
    )
    model_version_fqn: constr(regex=r"^model:[a-zA-Z0-9/_\-]+:\d+$") = Field(
        ...,
        description="+label=Model Version FQN\n+usage=The FQN of the model version that you want to deploy.",
    )


class Autoscaling(BaseModel):
    min_replicas: conint(ge=1) = Field(
        1,
        description="+label=Minimum replicas\n+usage=Minimum number of replicas to keep available",
    )
    max_replicas: conint(ge=1, le=20) = Field(
        ...,
        description="+label=Maximum replicas\n+usage=Maximum number of replicas allowed for the component.",
    )
    metrics: Union[CPUUtilizationMetric, RPSMetric] = Field(
        ...,
        description="+label=Autoscaling metrics\n+usage=Metrics to use for the autoscaler",
    )


class Build(BaseModel):
    """
    +docs=Describes how we build our code into a Docker image.
    +label=Source Code (Build and deploy source code)
    +icon=fa-code
    """

    type: constr(regex=r"^build$") = Field(..., description="+value=build")
    docker_registry: Optional[str] = Field(
        None,
        description="+docs=FQN of the container registry. You can the FQN of your desired container registry (or add one)\nin the  Integrations page[Integrations](https://app.truefoundry.tech/integrations?tab=docker-registry) page\n+label=Docker Registry\n+usage=FQN of the container registry. If you can't find your registry here,\nadd it through the [Integrations](/integrations?tab=docker-registry) page",
    )
    build_source: Union[RemoteSource, GitSource, LocalSource] = Field(
        ...,
        description="+docs=Source code location.\n+label=Fetch source code to build and deploy\n+icon=fa-code\n+sort=1",
    )
    build_spec: Union[DockerFileBuild, PythonBuild] = Field(
        ...,
        description="+docs=Instructions to build a container image out of the build source\n+label=Build using DockerFile or using Buildpack\n+icon=fa-wrench\n+sort=2",
    )


class Canary(BaseModel):
    """
    +docs=This strategy brings up the new release without bringing the older release down. Traffic is shifted from the older release to the newer release in a staged manner.
    This can help with verifying the health of the new release without shifting complete traffic.
    +label=Canary strategy
    """

    type: Literal["canary"] = Field(..., description="+value=canary")
    steps: List[CanaryStep] = Field(
        ...,
        description="+docs=These steps would be executed in order to enable shifting of traffic slowly from stable to canary version\n+label=Steps",
    )


class HealthProbe(BaseModel):
    """
    +docs=Describes the configuration for the Health Probe's
    To learn more you can go [here](https://docs.truefoundry.com/docs/add-health-checks-to-deployments)
    +icon=fa-heart
    """

    config: HttpProbe
    initial_delay_seconds: conint(ge=0, le=36000) = Field(
        0,
        description="+usage=Number of seconds after the container is started before the first probe is initiated.",
    )
    period_seconds: conint(ge=1, le=36000) = Field(
        10, description="+usage=How often, in seconds, to execute the probe."
    )
    timeout_seconds: conint(ge=1, le=36000) = Field(
        1, description="+usage=Number of seconds after which the probe times out."
    )
    success_threshold: conint(ge=1, le=100) = Field(
        1,
        description="+usage=Minimum consecutive successes for the probe to be considered successful after having failed.",
    )
    failure_threshold: conint(ge=1, le=100) = Field(
        3,
        description="+usage=Number of consecutive failures required to determine the container is not alive (liveness probe) or not ready (readiness probe).",
    )


class Job(BaseModel):
    """
    +docs=Describes the configuration for the job
    """

    type: constr(regex=r"^job$") = Field(..., description="+value=job")
    name: constr(regex=r"^[a-z][a-z0-9\-]{1,23}[a-z0-9]$") = Field(
        ...,
        description="+usage=Name of the job\n+sort=1\n+message=3 to 25 lower case characters long alphanumeric word, may contain - in between, cannot start with a number",
    )
    image: Union[Build, Image] = Field(
        ...,
        description="+docs=Specify whether you want to deploy a Docker image or build and deploy from source code\n+label=Deploy a Docker image or build and deploy from source code\n+icon=fa-solid fa-cloud-arrow-up:#21B6A8\n+sort=2",
    )
    resources: Optional[Resources] = None
    trigger: Union[Manual, Schedule] = Field(
        {"type": "manual"}, description="+docs=Specify the trigger\n+sort=3"
    )
    retries: conint(ge=0, le=10) = Field(
        0,
        description="+label=Retries\n+usage=Specify the maximum number of attempts to retry a job before it is marked as failed.\n+icon=fa-clone",
    )
    timeout: Optional[conint(le=432000, gt=0)] = Field(
        None,
        description="+label=Timeout\n+usage=Job timeout in seconds.\n+icon=fa-clone",
    )
    params: Optional[List[Param]] = Field(
        None,
        description="+label=Params for input\n+usage=Configure params and pass it to create different job runs\n+icon=fa-globe\n+sort=7",
    )
    env: Optional[Dict[str, str]] = Field(
        None,
        description="+label=Environment Variables\n+usage=Configure environment variables to be injected in the service. [Docs](https://docs.truefoundry.com/docs/env-variables)\n+icon=fa-globe\n+sort=8",
    )
    service_account: Optional[str] = Field(
        None, description="+usage=Service account that this workload should use"
    )
    file_mounts: Optional[List[FileMount]] = Field(
        None,
        description="+usage=Files to be mounted to job pod(s). **Deprecated**\n+ignore\n+sort=10010",
    )
    mounts: Optional[List[Union[SecretMount, StringDataMount]]] = Field(
        None,
        description="+usage=Configure data to be mounted to job pod(s)\n+ignore\n+sort=10011",
    )
    labels: Optional[Dict[str, str]] = Field(
        None, description="+label=Labels\n+usage=Add labels to service metadata"
    )


class ModelDeployment(BaseModel):
    """
    +docs=Describes the configuration for the model deployment
    +usage=To learn more you can go [here](https://dash.readme.com/project/truefoundry/v0.1.1/docs/model-deployment-2)
    """

    type: constr(regex=r"^model-deployment$") = Field(
        ..., description="+value=model-deployment"
    )
    name: constr(regex=r"^[a-z][a-z0-9\-]{1,17}[a-z0-9]$") = Field(
        ...,
        description="+usage=Name of the model deployment. This uniquely identifies this deployment in the workspace.\n> Name can only contain alphanumeric characters and '-' and can be atmost 20 characters long\n+sort=1\n+label=Model deployment name\n+message=3 to 19 lower case characters long alphanumeric word, may contain - in between, cannot start with a number",
    )
    model_source: Union[TruefoundryModelRegistry, HuggingfaceModelHub] = Field(
        ...,
        description="+docs=Specify the model to be deployed\n+sort=2\n+label=Model to deploy",
    )
    resources: Optional[Resources] = None
    grpc: bool = Field(False, description="+docs=Use grpc\n+sort=4\n+label=Use gRPC")
    labels: Optional[Dict[str, str]] = Field(
        None, description="+label=Labels\n+usage=Add labels to service metadata"
    )


class Service(BaseModel):
    """
    +docs=Describes the configuration for the service
    """

    type: constr(regex=r"^service$") = Field(..., description="+value=service")
    name: constr(regex=r"^[a-z][a-z0-9\-]{1,23}[a-z0-9]$") = Field(
        ...,
        description="+usage=Name of the service. This uniquely identifies this service in the workspace.\n> Name can only contain alphanumeric characters and '-' and can be atmost 25 characters long\n+sort=1\n+message=3 to 25 lower case characters long alphanumeric word, may contain - in between, cannot start with a number",
    )
    image: Union[Build, Image] = Field(
        ...,
        description="+docs=Specify whether you want to deploy a Docker image or build and deploy from source code\n+label=Deploy a Docker image or build and deploy from source code\n+icon=fa-solid fa-cloud-arrow-up:#21B6A8\n+sort=2",
    )
    resources: Optional[Resources] = None
    replicas: Union[confloat(ge=1.0, le=20.0), Autoscaling] = Field(
        1,
        description="+label=Replicas\n+usage=Replicas of service you want to run\n+icon=fa-clone\n+sort=3",
    )
    env: Optional[Dict[str, str]] = Field(
        None,
        description="+label=Environment Variables\n+usage=Configure environment variables to be injected in the service. [Docs](https://docs.truefoundry.com/docs/env-variables)\n+icon=fa-globe\n+sort=6",
    )
    ports: List[Port] = Field(
        ...,
        description="+docs=Specify the ports you want the service to be exposed to\n+label=Ports (Ports to route customer traffic to)\n+icon=fa-plug\n+sort=4",
    )
    liveness_probe: Optional[HealthProbe] = None
    readiness_probe: Optional[HealthProbe] = None
    service_account: Optional[str] = Field(
        None, description="+usage=Service account that this workload should use"
    )
    file_mounts: Optional[List[FileMount]] = Field(
        None,
        description="+usage=Files to be mounted to service pod(s). **Deprecated**\n+ignore\n+sort=10010",
    )
    mounts: Optional[List[Union[SecretMount, StringDataMount]]] = Field(
        None,
        description="+usage=Configure data to be mounted to service pod(s)\n+ignore\n+sort=10011",
    )
    labels: Optional[Dict[str, str]] = Field(
        None, description="+label=Labels\n+usage=Add labels to service metadata"
    )
    rollout_strategy: Optional[Union[Rolling, Canary, BlueGreen]] = Field(
        None,
        description="+label=Rollout strategy\n+usage=Strategy to dictate how a rollout should happen when a new release for this service is made",
    )


class Application(BaseModel):
    __root__: Union[Service, Job, ModelDeployment]
