# generated by datamodel-codegen:
#   filename:  application.json
#   timestamp: 2023-01-03T06:27:37+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 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")
    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_dir: str = Field(..., description="+usage=Dir at which data is to be mounted")
    data: Dict[str, str] = Field(
        ...,
        description="+usage=Data to be mounted, the key will be the filename, and the value will be the file content. files will be mounted under mount_dir",
    )


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
    """

    type: constr(regex=r"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")
    path: str = Field(
        ...,
        description="+usage=The endpoint, relative to the port, to which the HTTP GET request should be directed.",
    )
    port: conint(ge=0, le=65535) = Field(
        ...,
        description="+usage=The TCP socket within the container to which the HTTP GET request should be directed.",
    )
    host: Optional[str] = None
    scheme: str = "HTTP"


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")
    model_id: constr(regex=r"[A-Za-z0-9_.-/]+") = 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-z-]+")] = 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")
    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 Restart(str, Enum):
    """
    +usage=When to restart the job
    """

    Never = "Never"
    OnFailure = "OnFailure"
    Always = "Always"


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
    """

    type: constr(regex=r"local")
    project_root_path: str = Field("./", description="+usage=Local project root path.")
    local_build: bool = Field(False, 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")


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",
    )


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

    TCP = "TCP"
    UDP = "UDP"


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

    protocol: Protocol = Field("TCP", description="+usage=Protocol for the port.")
    port: conint(ge=0, le=65535) = Field(
        80, description="+usage=Port number to expose."
    )
    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")
    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")
    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 Buildpack (I don't have Dockerfile)
    +icon=fa-brands fa-python:#306998
    """

    type: constr(regex=r"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=Entrypoint\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}}`",
    )


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
    """

    type: constr(regex=r"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: confloat(ge=1.0, le=32000.0) = 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: confloat(ge=1.0, le=32000.0) = 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: float = 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: float = 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",
    )
    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.",
    )


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")
    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.",
    )


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")
    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 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")
    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 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=0, le=36000) = Field(
        10, description="+usage=How often, in seconds, to execute the probe."
    )
    timeout_seconds: conint(ge=0, le=36000) = Field(
        1, description="+usage=Number of seconds after which the probe times out."
    )
    success_threshold: conint(ge=0, le=100) = Field(
        1,
        description="+usage=Minimum consecutive successes for the probe to be considered successful after having failed.",
    )
    failure_threshold: conint(ge=0, 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")
    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) = Field(
        1,
        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: conint(ge=0, le=3600) = Field(
        1000,
        description="+label=Timeout\n+usage=Job timeout in seconds.\n+icon=fa-clone",
    )
    successful_jobs_history_limit: conint(ge=0, le=100) = Field(
        20,
        description="+usage=Number of successful invocation of this job to keep in history",
    )
    failed_jobs_history_limit: conint(ge=0, le=100) = Field(
        20,
        description="+usage=Number of failed invocation of this job to keep in history",
    )
    restart: Restart = Field("Never", description="+usage=When to restart the job")
    command: Optional[Union[str, List[str]]] = Field(
        None,
        description="+label=Commands\n+usage=Commands to execute to start the application. Overrides the `Entrypoint` command.\n+icon=fa-terminal\n+sort=6",
    )
    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\n+ignore"
    )


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")
    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")


class Notebook(BaseModel):
    """
    +docs=Describes the configuration for the notebook
    """

    type: constr(regex=r"notebook")
    name: constr(regex=r"^[a-z][a-z0-9-]{1,23}[a-z0-9]$") = Field(
        ..., description="+usage=Name of the notebook"
    )
    resources: Optional[Resources] = None


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

    type: constr(regex=r"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: conint(ge=1, le=5) = Field(
        1,
        description="+label=Replicas\n+usage=Number of service instances/replicas you want to run.\n+icon=fa-clone\n+sort=3",
    )
    command: Optional[Union[str, List[str]]] = Field(
        None,
        description="+label=Commands\n+usage=Commands to execute to start the application. Overrides the `Entrypoint` command.\n+icon=fa-terminal",
    )
    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\n+ignore"
    )


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