apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: keepalivedinstances.deckhouse.io
  labels:
    heritage: deckhouse
    module: keepalived
spec:
  group: deckhouse.io
  scope: Cluster
  names:
    plural: keepalivedinstances
    singular: keepalivedinstance
    kind: KeepalivedInstance
  preserveUnknownFields: false
  versions:
    - name: v1alpha1
      served: true
      storage: true
      schema:
        openAPIV3Schema:
          type: object
          description: |
            The CustomResource for configuring keepalived clusters.

            Each `KeepalivedInstance` CR defines a single keepalived cluster.

            `metadata.name` — the name of the cluster (used in pod names).
          required:
            - spec
          properties:
            spec:
              type: object
              required:
                - nodeSelector
                - vrrpInstances
              properties:
                nodeSelector:
                  type: object
                  additionalProperties:
                    type: string
                  x-kubernetes-preserve-unknown-fields: true
                  description: |
                    Defines the `nodeSelector` parameter for keepalived pods.

                    **Format**: the standard `nodeSelector` list. Instance pods inherit this field as is.
                tolerations:
                  description: |
                    Defines `tolerations` for keepalived pods.

                    **Format**: the standard [toleration](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) list. Instance pods inherit this field as is.
                  items:
                    properties:
                      effect:
                        description: |
                          Defines the taint's effect this toleration is associated with (it matches any effect if empty).
                        type: string
                        enum: ["NoSchedule", "PreferNoSchedule", "NoExecute"]
                      key:
                        description: |
                          Defines the taint's key this toleration is associated with (it matches any key if empty).

                          If the key is omitted (emplty), then `operator` must be set to `Exists` (which means it matches any `value` and `key`).
                        type: string
                      operator:
                        description: |
                          Defines how the key and its value are linked — whether the key must be `Equal` to the value or can have any value.

                          Setting it to `Exists` is equivalent to the value having any value so that the pod with the specified toleration can match the corresponding taint.
                        type: string
                        enum: ["Exists", "Equal"]
                        x-doc-default: "Equal"
                      tolerationSeconds:
                        description: |
                          Specifies the period (in seconds) that the scheduler waits before evicting a Pod from a node if 
                          the toleration no longer matches the taint (**only** applicable to the `NoExecute` effect, otherwise ignored).

                          If the parameter **is not set**, the Pod will not be evicted from the node if the toleration no longer matches the taint. If the parameter **is set to zero** (or negative), the Pod will be evicted immediately if the toleration no longer matches the taint.

                          **The default is**: not set.
                        format: int64
                        type: integer
                      value:
                        description: |
                          The value that the toleration must match.

                          Must be empty if the operator parameter is set to `Exists`.
                        type: string
                    type: object
                  type: array
                vrrpInstances:
                  type: array
                  description: |
                    A list of VRRP instances in the keepalived cluster. Essentially, it is a list of address groups that migrate between servers simultaneously and cannot work separately.

                    Do not confuse `vrrpInstance` with `KeepalivedInstance`. `vrrpInstance` is a component of `KeepalivedInstance`.

                    The `keepalived` module configures VRRP instances so that all addresses (all groups) are evenly distributed across all servers (instead of gathering together on the same node).
                  items:
                    type: object
                    required:
                      - id
                      - interface
                      - virtualIPAddresses
                    properties:
                      id:
                        type: integer
                        description: |
                          A unique **cluster-wide** identifier of a VRRP group.

                          Do not use the same ID in different `KeepalivedInstance` instances unless you have a perfect reason to do so.
                        maximum: 255
                        minimum: 1
                      interface:
                        type: object
                        description: |
                          Defines the strategy of detecting interface for the service VRRP traffic on the node.
                        properties:
                          detectionStrategy:
                            type: string
                            description: |
                              You can select one of the following three interface detecting strategis:
                              * `Name` — set the interface name explicitly using the `spec.vrrpInstances[].interface.name` parameter. In this case, all nodes must have the same interface that serves the correct network (e.g., eth0).
                              * `NetworkAddress` — find an interface with an IP from this subnet on the node and use it.
                              * `DefaultRoute` — use the interface for the default route on the node (254 "main" in the table).
                          name:
                            type: string
                            description: |
                              The name of the interface for the service VRRP traffic if the `Name` `detectionStrategy` is used.

                              **A mandatory parameter** if `detectionStrategy` = `Name`.
                            minLength: 1
                          networkAddress:
                            type: string
                            description: |
                              The address of the subnet to use for determining an interface if `detectionStrategy` = `NetworkAddress`.

                              **A mandatory parameter** if `detectionStrategy` = `NetworkAddress`.
                            pattern: '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$'
                            example: '192.168.42.0/24'
                        oneOf:
                          - properties:
                              detectionStrategy:
                                enum: [Name]
                            required: [detectionStrategy, name]
                          - properties:
                              detectionStrategy:
                                enum: [NetworkAddress]
                            required: [detectionStrategy, networkAddress]
                          - properties:
                              detectionStrategy:
                                enum: [DefaultRoute]
                            required: [detectionStrategy]
                      preempt:
                        type: boolean
                        description: |
                          Defines if the IP is passed to a node after its recovery from a failure.

                          It makes sense not to pass the IP if you have just one `vrrpInstance` to preserve connections. If you have a lot of groups and a lot of traffic, it is better to pass it to prevent the concentration of all groups on one node.

                          **The default is** — `true`, that is, the IP will passed to a node after its recovery.
                      virtualIPAddresses:
                        type: array
                        description: 'A list of IP addresses that will "jump" between the servers **in tandem**'
                        items:
                          type: object
                          required:
                            - address
                          properties:
                            address:
                              type: string
                              description: |
                                One of the group addresses.
                              example: '192.168.42.15/32'
                              pattern: '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$'
                            interface:
                              type: object
                              description: |
                                An interface for binding a virtual IP address on a node (similar to `spec.vrrpInstances[].interface`).

                                If omitted, the main service interface defined in `spec.vrrpInstances[].interface` will be used.
                              x-doc-required: false
                              properties:
                                detectionStrategy:
                                  type: string
                                  description: |
                                    You can select one of the following three interface detecting strategis ti bind an IP address:
                                    * `Name` — set the interface name explicitly using the `spec.vrrpInstances[].virtualIPAddresses[].interface.name` parameter. In this case, all nodes must have the same interface that serves the correct network (e.g., eth0).
                                    * `NetworkAddress` — find an interface with an IP from this subnet on the node and use it.
                                    * `DefaultRoute` — use the interface for the default route on the node (254 "main" in the table).
                                name:
                                  type: string
                                  description: |
                                    A name of the interface to bind a virtual IP address if `virtualIPaddresses[].detectionStrategy` = `Name` is used.

                                    **A mandatory parameter** if `virtualIPaddresses[].detectionStrategy` = `Name`.
                                  minLength: 1
                                networkAddress:
                                  type: string
                                  description: |
                                    The address of the subnet to use for determining an interface if `virtualIPaddresses[].detectionStrategy` = `NetworkAddress`.

                                    **A mandatory parameter** if `virtualIPaddresses[].detectionStrategy` = `NetworkAddress`.
                                  pattern: '^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}/[0-9]{1,2}$'
                                  example: '192.168.42.0/24'
                              oneOf:
                                - properties:
                                    detectionStrategy:
                                      enum: [Name]
                                  required: [detectionStrategy, name]
                                - properties:
                                    detectionStrategy:
                                      enum: [NetworkAddress]
                                  required: [detectionStrategy, networkAddress]
                                - properties:
                                    detectionStrategy:
                                      enum: [DefaultRoute]
                                  required: [detectionStrategy]
