// Copyright 2023 The Kubeflow Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package kfp_kubernetes;

import "google/protobuf/struct.proto";
import "pipeline_spec.proto";

option go_package = "github.com/kubeflow/pipelines/kubernetes_platform/go/kubernetesplatform";

message KubernetesExecutorConfig {
    repeated SecretAsVolume secret_as_volume = 1;
    repeated SecretAsEnv secret_as_env = 2;
    repeated PvcMount pvc_mount = 3;
    NodeSelector node_selector = 4;
    PodMetadata pod_metadata = 5;
    repeated ImagePullSecret image_pull_secret = 6;
    // One of Always, Never, IfNotPresent.
    string image_pull_policy = 7;
    repeated ConfigMapAsVolume config_map_as_volume = 8;
    repeated ConfigMapAsEnv config_map_as_env = 9;
    int64 active_deadline_seconds = 10;
    repeated FieldPathAsEnv field_path_as_env = 11;
    repeated Toleration tolerations = 12;
    repeated GenericEphemeralVolume generic_ephemeral_volume = 13;
    repeated NodeAffinityTerm node_affinity = 14;
    repeated PodAffinityTerm pod_affinity = 15;
    EnabledSharedMemory enabled_shared_memory = 16;
    repeated EmptyDirMount empty_dir_mounts = 17;
}

message EnabledSharedMemory {
    // Name of the Shared Memory Volume.
    string volume_name = 1;
    // Size of the Shared Memory.
    string size = 2;
}

message SecretAsVolume {
    // Deprecated, use secret_name_parameter instead.
    string secret_name = 1 [deprecated = true];
    // Container path to mount the Secret data.
    string mount_path = 2;
    // An optional boolean value indicating whether the Secret must be defined.
    optional bool optional = 3;

    // Name of the Secret.
    ml_pipelines.TaskInputsSpec.InputParameterSpec secret_name_parameter = 4;
}

message SecretAsEnv {
    // Deprecated, use secret_name_parameter instead.
    string secret_name = 1 [deprecated = true];

    message SecretKeyToEnvMap {
        // Corresponds to a key of the Secret.data field.
        string secret_key = 1;
        // Env var to which secret_key's data should be set.
        string env_var = 2;
    }

    repeated SecretKeyToEnvMap key_to_env = 2;
    // An optional boolean value indicating whether the Secret must be defined.
    optional bool optional = 3;

    // Name of the Secret.
    ml_pipelines.TaskInputsSpec.InputParameterSpec secret_name_parameter = 4;
}

message PvcMount {
    // Deprecated, use pvc_name_parameter instead.
    oneof pvc_reference {
        // Output parameter from an upstream task.
        ml_pipelines.TaskInputsSpec.InputParameterSpec.TaskOutputParameterSpec task_output_parameter = 1  [deprecated = true];
        // A constant value.
        string constant = 2 [deprecated = true];
        // Pass the input parameter from parent component input parameter.
        string component_input_parameter = 3 [deprecated = true];
    }
    // Container path to which the PVC should be mounted.
    string mount_path = 4;

    // Name of the PVC.
    ml_pipelines.TaskInputsSpec.InputParameterSpec pvc_name_parameter = 5;
}

message CreatePvc {
    oneof name {
        // Name of the PVC, if not dynamically generated.
        string pvc_name = 1;
        // Suffix for a dynamically generated PVC name of the form
        // {{workflow.name}}-<pvc_name_suffix>.
        string pvc_name_suffix = 2;
    }
    // Corresponds to PersistentVolumeClaim.spec.accessMode field.
    repeated string access_modes = 3;
    // Corresponds to PersistentVolumeClaim.spec.resources.requests.storage field.
    string size = 4;
    // If true, corresponds to omitted PersistentVolumeClaim.spec.storageClassName.
    bool default_storage_class = 5;
    // Corresponds to PersistentVolumeClaim.spec.storageClassName string field.
    // Should only be used if default_storage_class is false.
    string storage_class_name = 6;
    // Corresponds to PersistentVolumeClaim.spec.volumeName field.
    string volume_name = 7;
    // Corresponds to PersistentVolumeClaim.metadata.annotations field.
    google.protobuf.Struct annotations = 8;
}

message DeletePvc {
    // Identifier for the PVC.
    // Used like TaskInputsSpec.ml_pipelines.TaskInputsSpec.InputParameterSpec.kind.
    oneof pvc_reference {
        // Output parameter from an upstream task.
        ml_pipelines.TaskInputsSpec.InputParameterSpec.TaskOutputParameterSpec task_output_parameter = 1;
        // A constant value.
        string constant = 2;
        // Pass the input parameter from parent component input parameter.
        string component_input_parameter = 3;
    }
}

message NodeSelector {
    // map of label key to label value
    // corresponds to Pod.spec.nodeSelector field https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#scheduling
    map<string, string> labels = 1;

    // Provide a JSON struct of node selector
    // Takes precedence over labels.
    // Example: {"disk-type": "ssd", "region": "us-west"}
    ml_pipelines.TaskInputsSpec.InputParameterSpec node_selector_json = 2;
}

message PodMetadata {
    // values of metadata spec such as labels and annotations for the pod object
    // corresponds to Pod.metadata field https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#Pod
    map<string, string> labels = 1;
    map<string, string> annotations = 2;
}

message ConfigMapAsVolume {
    // Deprecated, use config_name_parameter instead.
    string config_map_name = 1 [deprecated = true];
    // Container path to mount the ConfigMap data.
    string mount_path = 2;
    // An optional boolean value indicating whether the ConfigMap must be defined.
    optional bool optional = 3;

    // Name of the ConfigMap.
    ml_pipelines.TaskInputsSpec.InputParameterSpec config_map_name_parameter = 4;
}

message ConfigMapAsEnv {
    // Deprecated, use config_name_parameter instead.
    string config_map_name = 1 [deprecated = true];

    message ConfigMapKeyToEnvMap {
        // Corresponds to a key of the ConfigMap.
        string config_map_key = 1;
        // Env var to which configmap_key's data should be set.
        string env_var = 2;
    }

    repeated ConfigMapKeyToEnvMap key_to_env = 2;

    // Name of the ConfigMap.
    ml_pipelines.TaskInputsSpec.InputParameterSpec config_map_name_parameter = 3;
    // An optional boolean value indicating whether the ConfigMap must be defined.
    optional bool optional = 4;
}

message GenericEphemeralVolume {
    // more details in https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/#generic-ephemeral-volumes
    // Name of the ephemeral volume.
    string volume_name = 1;
    // Container path to mount the volume
    string mount_path = 2;
    // Corresponds to ephemeral.volumeClaimTemplate.spec.accessModes field.
    repeated string access_modes = 3;
    // Corresponds to ephemeral.volumeClaimTemplate.spec.resources.requests.storage field.
    string size = 4;
    // If true, corresponds to omitted ephemeral.volumeClaimTemplate.spec.storageClassName.
    bool default_storage_class = 5;
    // Corresponds to ephemeral.volumeClaimTemplate.spec.storageClassName string field.
    // Should only be used if default_storage_class is false.
    string storage_class_name = 6;
    // Corresponds to ephemeral.volumeClaimTemplate.metadata.
    // This is not exactly a pod metadata but the fields are the same
    PodMetadata metadata = 7;
}

message ImagePullSecret {
    // Name of the image pull secret.
    string secret_name = 1 [deprecated = true];

    ml_pipelines.TaskInputsSpec.InputParameterSpec secret_name_parameter = 2;
}

message FieldPathAsEnv {
    // Name of the environment variable
    string name = 1;

    // Value of the field path string
    string field_path = 2;
}

message Toleration {
    string key = 1;
    string operator = 2;
    string value = 3;
    string effect = 4;
    optional int64 toleration_seconds = 5;

    // Provide a json struct of the toleration
    // Takes precedence over key, operator, value, effect.
    // Example: {"key": "key1", "operator": "Equal", "value": "value1", "effect": "NoSchedule"}
    // The JSON must follow Kubernetes
    // Toleration structure:
    // https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core
    ml_pipelines.TaskInputsSpec.InputParameterSpec toleration_json = 6;
}

// Matches https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#labelselectorrequirement-v1-meta and
// https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#nodeselectorrequirement-v1-core
message SelectorRequirement {
    string key = 1;
    string operator = 2;
    repeated string values = 3;
}

message NodeAffinityTerm {
    repeated SelectorRequirement match_expressions = 1;
    repeated SelectorRequirement match_fields = 2;
    //Setting the weight makes it use PreferredDuringSchedulingIgnoredDuringExecution rules instead of RequiredDuringSchedulingIgnoredDuringExecution rules
    optional int32 weight = 3;    
    // Provide a JSON struct of node affinity. Takes precedence over PreferredDuringSchedulingIgnoredDuringExecution rules/RequiredDuringSchedulingIgnoredDuringExecution rules.
    // The JSON must follow Kubernetes
    // NodeAffinity structure:
    // https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#nodeaffinity-v1-core
    // Example:
    // { "requiredDuringSchedulingIgnoredDuringExecution": { "nodeSelectorTerms": [ ... ] } }
    ml_pipelines.TaskInputsSpec.InputParameterSpec node_affinity_json = 4;
} 

message PodAffinityTerm {
    repeated SelectorRequirement match_pod_expressions = 1;
    map<string,string> match_pod_labels = 2;
    string topology_key = 3;
    repeated string namespaces = 4;
    repeated SelectorRequirement match_namespace_expressions = 5;
    map<string,string> match_namespace_labels = 6;
    //Setting a weight makes it use PreferredDuringSchedulingIgnoredDuringExecution rules instead of RequiredDuringSchedulingIgnoredDuringExecution rules
    optional int32 weight = 7;
    //Flag indicating if it is a podaffinity or podantiaffinity
    optional bool anti = 8;
}

message EmptyDirMount {
    // https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.25/#emptydirvolumesource-v1-core
    string volume_name = 1;
    string mount_path = 2;
    optional string medium = 3;
    optional string size_limit = 4;
}
