// Copyright 2019 Istio 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
//
//     http://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";

import "k8s.io/api/core/v1/generated.proto";
import "k8s.io/api/autoscaling/v2beta1/generated.proto";
import "k8s.io/apimachinery/pkg/apis/meta/v1/generated.proto";
import "github.com/gogo/protobuf/protobuf/google/protobuf/wrappers.proto";

// $title: Installation Options (istioctl)
// $description: Configuration options for Istio control plane installation using istioctl.
// $weight: 10
// $location: https://istio.io/docs/reference/config/istio.operator.v1alpha12.pb.html
//
// TODO: for some reason the below fails proto compilation in this repo.
// https://github.com/istio/istio/issues/16899
// package istio.operator.v1alpha2;
// option go_package="istio.io/istio/operator/pkg/apis/istio/v1alpha2";

// IstioControlPlane is a schema for both defining and customizing Istio control plane installations.
// Running the operator with an empty user defined InstallSpec results in an control plane with default values, using the
// default charts.
//
// The simplest install specialization is to point the user InstallSpec profile to a different values file, for
// example an Istio minimal control plane, which will use the values associated with the minimal control plane profile for
// Istio.
//
// Deeper customization is possible at three levels:
//
// 1. New APIs defined in this file
//
//     Feature API: this API groups an Istio install by features and allows enabling/disabling the features, selecting base
//     control plane profiles, as well as some additional high level settings that are feature specific. Each feature contains
//     one or more components, which correspond to Istio components (Pods) in the cluster.
//
//     k8s API: this API is a pass through to k8s resource settings for Istio k8s resources. It allows customizing Istio k8s
//     resources like Affinity, Resource requests/limits, PodDisruptionBudgetSpec, Selectors etc. in a more consistent and
//     k8s specific way compared to values.yaml. See KubernetesResourcesSpec in this file for details.
//
// 1. values.yaml
//
//     The entirety of values.yaml settings is accessible through InstallSpec (see CommonComponentSpec/Values).
//     This API will gradually be deprecated and values there will be moved either into CRDs that are used to directly
//     configure components or, in the case of k8s settings, will be replaced by the new API above.
//
// 1. k8s resource overlays
//
//     Once a manifest is rendered from InstallSpec, a further customization can be applied by specifying k8s resource
//     overlays. The concept is similar to kustomize, where JSON patches are applied for object paths. This allows
//     customization at the lowest level and eliminates the need to create ad-hoc template parameters, or edit templates.
//
// Here are a few example uses:
//
// 1. Default Istio install
//
//     ```
//     spec:
//     ```
//
// 1. Default minimal profile install
//
//     ```
//     spec:
//       profile: minimal
//     ```
//
// 1. Default install with telemetry disabled
//
//     ```
//     spec:
//       telemetry:
//         enabled: false
//     ```
//
// 1. Default install with each feature installed to different namespace and security components in separate namespaces
//
//     ```
//     spec:
//       traffic_management:
//         components:
//           namespace: istio-traffic-management
//       policy:
//         components:
//           namespace: istio-policy
//       telemetry:
//         components:
//           namespace: istio-telemetry
//       config_management:
//         components:
//           namespace: istio-config-management
//       security:
//         components:
//           citadel:
//             namespace: istio-citadel
//           cert_manager:
//             namespace: istio-cert-manager
//           node_agent:
//             namespace: istio-node-agent
//     ```
//
// 1. Default install with specialized k8s settings for pilot
//
//     ```
//     spec:
//       traffic_management:
//         components:
//           pilot:
//             k8s:
//               resources:
//                 limits:
//                   cpu: 444m
//                   memory: 333Mi
//                 requests:
//                   cpu: 222m
//                   memory: 111Mi
//               readinessProbe:
//                 failureThreshold: 44
//                 initialDelaySeconds: 11
//                 periodSeconds: 22
//                 successThreshold: 33
//     ```
//
// 1. Default install with values.yaml customizations for proxy
//
//     ```
//     spec:
//       traffic_management:
//         components:
//           proxy:
//             values:
//             - global.proxy.enableCoreDump: true
//             - global.proxy.dnsRefreshRate: 10s
//     ```
//
// 1. Default install with modification to container flag in galley
//
//     ```
//     spec:
//       configuration_management:
//         components:
//           galley:
//             k8s:
//               overlays:
//               - apiVersion: extensions/v1beta1
//                 kind: Deployment
//                 name: istio-galley
//                 patches:
//                 - path: spec.template.spec.containers.[name:galley].command.[--livenessProbeInterval]
//                   value: --livenessProbeInterval=123s
//     ```
package v1alpha2;

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// IstioControlPlane is a CustomResourceDefinition (CRD) describing an Istio control plane.
message IstioControlPlane {
    // Spec defines the desired state of IstioControlPlane.
    IstioControlPlaneSpec spec = 3;
    // Status reports the status of the Istio control plane.
    InstallStatus status = 4;
    string kind = 5;
    string apiVersion = 6;
    // GOFIELD:v11.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,7,opt,name=metadata"`
    // GOFIELD:v11.TypeMeta `json:",inline"`
    string placeholder = 111;
}

// IstioControlPlaneSpec defines the desired state of IstioControlPlane.
// The spec is a used to define a customization of the default profile values that are supplied with each Istio release.
// It is grouped at the top level by feature, where behavior of Istio functional areas is specified.
// Each feature contains components, where k8s resource level defaults can be overridden.
// Because the spec is a customization API, specifying an empty InstallSpec results in a default Istio control plane.
message IstioControlPlaneSpec {
    // Default namespace if feature or component namespaces are not set.
    string default_namespace = 5;

    // Base feature containing resources like CRDs, namespaces etc.
    BaseFeatureSpec base = 20;

    // Selection and configuration of core Istio features.
    TrafficManagementFeatureSpec traffic_management = 25;
    PolicyFeatureSpec policy = 26;
    TelemetryFeatureSpec telemetry = 27;
    SecurityFeatureSpec security = 28;
    ConfigManagementFeatureSpec config_management = 29;
    AutoInjectionFeatureSpec auto_injection = 30;
    GatewayFeatureSpec gateways = 31;
    CNIFeatureSpec cni = 32;
    CoreDNSFeatureSpec coreDNS = 33;
    // Overrides for default global values.yaml.
    TypeMapStringInterface values = 50;
    // Unvalidated overrides for default global values.yaml.
    TypeMapStringInterface unvalidatedValues = 51;
    // Path or name for the profile e.g.
    //     - minimal (looks in profiles dir for a file called minimal.yaml)
    //     - /tmp/istio/install/values/custom/custom-install.yaml (local file path)
    // default profile is used if this field is unset.
    string profile = 100;
    // Path for the install package. e.g.
    //     - /tmp/istio-installer/nightly (local file path)
    string install_package_path = 102;
    // Root for docker image paths e.g. docker.io/istio-release.
    // Releases are published to docker hub under 'istio' project.
    // Daily builds from prow are on gcr.io, and nightly builds from circle on docker.io/istionightly
    string hub = 110;
    // Version tag for docker images e.g. 1.0.6
    string tag = 111;
}

// Base feature settings.
message BaseFeatureSpec {
    // Selects whether base feature is installed. Required for all Istio installs.
    // Should only be disabled when generating partial Istio installation YAMLs.
    TypeBoolValueForPB enabled = 1;

    // Component specific config.
    message Components {
        BaseComponentSpec base = 20;
    }

    Components components = 50;
}

// Configuration options for traffic management.
message TrafficManagementFeatureSpec {
    // Selects whether traffic management is installed.
    // Must be enabled to enable any sub-component.
    TypeBoolValueForPB enabled = 1;

    // Component specific config.
    message Components {
        // Namespace that all traffic management components are installed into.
        string namespace = 1;

        PilotComponentSpec pilot = 20;
        ProxyComponentSpec proxy = 21;
    }

    Components components = 50;
}

// Configuration options for the policy feature.
message PolicyFeatureSpec {
    // Selects whether policy is installed.
    // Must be enabled to enable any sub-component.
    TypeBoolValueForPB enabled = 1;

    // Component specific config.
    message Components {
        // Namespace that all policy components are installed into.
        string namespace = 1;

        PolicyComponentSpec policy = 20;
    }

    Components components = 50;
}

// Configuration options for the telemetry feature.
message TelemetryFeatureSpec {
    // Selects whether telemetry is installed.
    // Must be enabled to enable any sub-component.
    TypeBoolValueForPB enabled = 1;

    // Component specific config.
    message Components {
        // Namespace that all telemetry components are installed into.
        string namespace = 1;

        TelemetryComponentSpec telemetry = 20;
    }

    Components components = 50;
}

// Configuration options for security feature.
message SecurityFeatureSpec {
    // Selects whether security feature is installed. Must be set for any sub-component to be installed.
    TypeBoolValueForPB enabled = 1;

    message Components {
        // Namespace that security components are installed into.
        string namespace = 1;

        CitadelComponentSpec citadel = 20;
        CertManagerComponentSpec cert_manager = 21;
        NodeAgentComponentSpec node_agent = 22;
    }

    Components components = 50;
}

// Configuration options for configuration management feature.
message ConfigManagementFeatureSpec {
    // Selects whether config management feature is installed. Must be set for any sub-component to be installed.
    TypeBoolValueForPB enabled = 1;

    message Components {
        // Namespace that security components are installed into.
        string namespace = 1;

        GalleyComponentSpec galley = 20;
    }

    Components components = 50;
}

// Configuration options for auto injection feature.
message AutoInjectionFeatureSpec {
    // Selects whether auto injection feature is installed. Must be set for any sub-component to be installed.
    TypeBoolValueForPB enabled = 1;

    message Components {
        // Namespace that auto injections components are installed into.
        string namespace = 1;

        SidecarInjectorComponentSpec injector = 20;
    }

    Components components = 50;
}

// Configuration options for gateway feature.
message GatewayFeatureSpec {
    // Selects whether gateway feature is installed. Must be set for any sub-component to be installed.
    TypeBoolValueForPB enabled = 1;

    message Components {
        // Namespace that auto injections components are installed into.
        string namespace = 1;

        // Ingress/egress gateway configuration.
        IngressGatewayComponentSpec ingress_gateway = 31;
        EgressGatewayComponentSpec egress_gateway = 32;
    }

    Components components = 50;
}

// Configuration options for cni feature.
message CNIFeatureSpec {
    // Selects whether CNI feature is installed. Must be set for any sub-component to be installed.
    TypeBoolValueForPB enabled = 1;

    message Components {
        // Namespace that cni components are installed into.
        string namespace = 1;

        CNIComponentSpec cni = 20;
    }

    Components components = 50;
}

// Configuration options for CoreDNS feature.
message CoreDNSFeatureSpec {
    // Selects whether CoreDNS feature is installed. Must be set for any sub-component to be installed.
    TypeBoolValueForPB enabled = 1;

    message Components {
        // Namespace that CoreDNS components are installed into.
        string namespace = 1;

        CoreDNSComponentSpec coreDNS = 20;
    }

    Components components = 50;
}

// Configuration common to all components.

// Selects whether this component is installed.
// TypeBoolValueForPB enabled = 1;

// Namespace that all resources for this component are installed into. Overrides the parent feature namespace and
// IstioControlPlaneSpec.DefaultNamespace.
// string namespace = 2;

// Kubernetes resource spec.
// KubernetesResourcesSpec k8s = 80;

// Configuration options for the base component.
message BaseComponentSpec {
    TypeBoolValueForPB enabled = 1;
}

// Configuration options for the pilot component.
message PilotComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for the proxy.
message ProxyComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for the sidecar injector component.
message SidecarInjectorComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for the policy enforcement component.
message PolicyComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for the telemetry component.
message TelemetryComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for Citadel component.
message CitadelComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for certificate manager component.
message CertManagerComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for node agent component.
message NodeAgentComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for galley component.
message GalleyComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for ingress gateways.
message IngressGatewayComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for egress gateways.
message EgressGatewayComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for cni component.
message CNIComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// Configuration options for CoreDNS component.
message CoreDNSComponentSpec {
    TypeBoolValueForPB enabled = 1;
    string namespace = 2;
    KubernetesResourcesSpec k8s = 80;
}

// KubernetesResourcesConfig is a common set of k8s resource configs for components.
message KubernetesResourcesSpec {
    // k8s affinity.
    // https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
    k8s.io.api.core.v1.Affinity affinity = 1;
    // Deployment environment variables.
    // https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/
    repeated k8s.io.api.core.v1.EnvVar env = 2;
    // k8s HorizontalPodAutoscaler settings.
    // https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
    k8s.io.api.autoscaling.v2beta1.HorizontalPodAutoscalerSpec hpa_spec = 3;
    // k8s imagePullPolicy.
    // https://kubernetes.io/docs/concepts/containers/images/
    string image_pull_policy = 4;
    // k8s nodeSelector.
    // https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
    map<string, string> node_selector = 5;
    // k8s PodDisruptionBudget settings.
    // https://kubernetes.io/docs/concepts/workloads/pods/disruptions/#how-disruption-budgets-work
    PodDisruptionBudgetSpec pod_disruption_budget = 6;
    // k8s pod annotations.
    // https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
    map<string, string> pod_annotations = 7;
    // k8s priority_class_name. Default for all resources unless overridden.
    // https://kubernetes.io/docs/concepts/configuration/pod-priority-preemption/#priorityclass
    string priority_class_name = 8;
    // k8s readinessProbe settings.
    // https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/
    // k8s.io.api.core.v1.Probe readiness_probe = 9;
    ReadinessProbe readiness_probe = 9;
    // k8s Deployment replicas setting.
    // https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
    uint32 replica_count = 10;
    // k8s resources settings.
    // https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#resource-requests-and-limits-of-pod-and-container
    Resources resources = 11;
    // k8s Service settings.
    // https://kubernetes.io/docs/concepts/services-networking/service/
    k8s.io.api.core.v1.ServiceSpec service = 12;
    // k8s deployment strategy.
    // https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
    DeploymentStrategy strategy = 13;
    // k8s toleration
    // https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
    repeated k8s.io.api.core.v1.Toleration tolerations = 14;

    // Overlays for k8s resources in rendered manifests.
    repeated k8sObjectOverlay overlays = 100;
}

// Patch for an existing k8s resource.
message k8sObjectOverlay {
    message PathValue {
        // Path of the form a.b:c.e.:f
        // Where b:c is a list element selector of the form key:value and :f is a list selector of the form :value.
        // All path intermediate nodes must exist.
        string path = 1;
        // Value to add, delete or replace.
        // For add, the path should be a new leaf.
        // For delete, value should be unset.
        // For replace, path should reference an existing node.
        // All values are strings but are converted into appropriate type based on schema.
        TypeInterface value = 2;
    }
    // Resource API version.
    string api_version = 1;
    // Resource kind.
    string kind = 2;
    // Name of resource.
    // Namespace is always the component namespace.
    string name = 3;

    // List of patches to apply to resource.
    repeated PathValue patches = 4;
}

// Observed state of IstioControlPlane.
message InstallStatus {
    enum Status {
        NONE = 0;
        UPDATING = 1;
        HEALTHY = 2;
        ERROR = 3;
        RECONCILING = 4;
    }
    message VersionStatus {
        string version = 1;
        Status status = 2;
        string statusString = 3;
        string error = 4;
    }

    map<string, VersionStatus> status = 1;
}

// Mirrors k8s.io.api.core.v1.ResourceRequirements for unmarshaling.
message Resources {
    map<string, string> limits = 1;
    map<string, string> requests = 2;
}

// Mirrors k8s.io.api.core.v1.Probe for unmarshaling
message ReadinessProbe {
    ExecAction exec = 1;
    HTTPGetAction httpGet = 2;
    TCPSocketAction tcpSocket = 3;
    int32 initialDelaySeconds = 4;
    int32 timeoutSeconds = 5;
    int32 periodSeconds = 6;
    int32 successThreshold = 7;
    int32 failureThreshold = 8;
}

// Mirrors k8s.io.api.core.v1.ExecAction for unmarshaling
message ExecAction {
    repeated string command = 1;
}

// Mirrors k8s.io.api.core.v1.HTTPGetAction for unmarshaling
message HTTPGetAction {
    string path = 1;
    TypeIntOrStringForPB port = 2;
    string host = 3;
    string scheme = 4;
    repeated HTTPHeader httpHeaders = 5;
}

// Mirrors k8s.io.api.core.v1.HTTPHeader for unmarshaling
message HTTPHeader {
    string name = 1;
    string value = 2;
}

// Mirrors k8s.io.api.core.v1.TCPSocketAction for unmarshaling
message TCPSocketAction {
    TypeIntOrStringForPB port = 1;
    string host = 2;
}

// Mirrors k8s.io.api.policy.v1beta1.PodDisruptionBudget for unmarshaling.
message PodDisruptionBudgetSpec {
    uint32 minAvailable = 1;
    k8s.io.apimachinery.pkg.apis.meta.v1.LabelSelector selector = 2;
    uint32 maxUnavailable = 3;
}

// Mirrors k8s.io.api.apps.v1.DeploymentStrategy for unmarshaling.
message DeploymentStrategy {
    string type = 1;
    RollingUpdateDeployment rollingUpdate = 2;
}

// Mirrors k8s.io.api.apps.v1.RollingUpdateDeployment for unmarshaling.
message RollingUpdateDeployment {
    TypeIntOrStringForPB maxUnavailable = 1;
    TypeIntOrStringForPB maxSurge = 2;
}

message ObjectMeta {
    // From k8s.io.apimachinery.pkg.apis.meta.v1.ObjectMeta
    string name = 5;
    string namespace = 6;
}

// GOTYPE: map[string]interface{}
message TypeMapStringInterface {}

// GOTYPE: interface{}
message TypeInterface {}

// GOTYPE: *IntOrStringForPB
message TypeIntOrStringForPB {}

// GOTYPE: *BoolValueForPB
message TypeBoolValueForPB {}


