# Copyright 2023 Google LLC
#
# 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.

# Patch to add an init container that creates a gRPC xDS bootstrap config file,
# with a self-managed xDS control plane management server.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: greeter
spec:
  template:
    spec:
      containers:
      - name: app
        env:
        - name: GRPC_XDS_BOOTSTRAP
          value: /etc/grpc-xds/bootstrap.json
        volumeMounts:
        - name: grpc-xds-conf
          mountPath: /etc/grpc-xds
          readOnly: true
      initContainers:
      - name: grpc-xds-init
        image: busybox
        command:
        - /bin/sh
        - -c
        - |
          #
          # Create the gRPC xDS bootstrap configuration file and populate it
          # with values from the Pod environment and the GKE metadata server:
          #
          cat << EOF > /etc/grpc-xds/bootstrap.json
          {
            "xds_servers": [
              {
                "server_uri": "dns:///control-plane.xds:50051",
                "channel_creds": [
                  {
                    "type": "insecure"
                  }
                ],
                "server_features": [
                  "xds_v3",
                  "ignore_resource_deletion"
                ]
              }
            ],
            "authorities": {
              "control-plane.xds.svc.cluster.example.com": {
                "xds_servers": [
                  {
                    "server_uri": "dns:///control-plane.xds.svc.cluster.example.com:50051",
                    "channel_creds": [
                      {
                        "type": "insecure"
                      }
                    ],
                    "server_features": [
                      "xds_v3",
                      "ignore_resource_deletion"
                    ]
                  }
                ],
                "client_listener_resource_name_template": "xdstp://control-plane.xds.svc.cluster.example.com/envoy.config.listener.v3.Listener/%s"
              },
              "control-plane.xds.svc.cluster2.example.com": {
                "xds_servers": [
                  {
                    "server_uri": "dns:///control-plane.xds.svc.cluster2.example.com:50051",
                    "channel_creds": [
                      {
                        "type": "insecure"
                      }
                    ],
                    "server_features": [
                      "xds_v3",
                      "ignore_resource_deletion"
                    ]
                  }
                ],
                "client_listener_resource_name_template": "xdstp://control-plane.xds.svc.cluster2.example.com/envoy.config.listener.v3.Listener/%s"
              }
            },
            "node": {
              "id": "$(cat /proc/sys/kernel/random/uuid)~$(hostname -i)",
              "cluster": "$(cat /etc/podinfo/label-app-name)",
              "metadata": {
                "INSTANCE_IP": "$(hostname -i)",
                "K8S_NAMESPACE": "$(cat /etc/podinfo/namespace)",
                "K8S_POD": "$(hostname -s)",
                "XDS_STREAM_TYPE": "ADS"
              },
              "locality": {
                "zone": "$(wget --header Metadata-Flavor:Google -qO- http://metadata.google.internal/computeMetadata/v1/instance/zone 2> /dev/null | cut -d/ -f4)"
              }
            },
            "certificate_providers": {
              "google_cloud_private_spiffe": {
                "plugin_name": "file_watcher",
                "config": {
                  "ca_certificate_file": "/var/run/secrets/workload-spiffe-credentials/ca_certificates.pem",
                  "certificate_file": "/var/run/secrets/workload-spiffe-credentials/certificates.pem",
                  "private_key_file": "/var/run/secrets/workload-spiffe-credentials/private_key.pem",
                  "refresh_interval": "600s"
                }
              }
            },
            "server_listener_resource_name_template": "grpc/server?xds.resource.listening_address=%s",
            "client_default_listener_resource_name_template": "%s"
          }
          EOF
          #
          # Set `locality.zone` from a file if the GKE metadata server is unavailable,
          # e.g., when running on a local kind cluster. Also handle the special cases of
          # Cloud Workstations (https://cloud.google.com/workstations/docs) and
          # gLinux Rodete (https://cloud.google.com/blog/topics/developers-practitioners/how-google-got-to-rolling-linux-releases-for-desktops).
          #
          wget --header Metadata-Flavor:Google --spider -q http://metadata.google.internal/computeMetadata/v1/instance/zone 2> /dev/null \
            && ( ! wget --header Metadata-Flavor:Google -qO- http://metadata.google.internal/computeMetadata/v1/instance/tags 2> /dev/null | grep '"cloud-workstations-instance"' > /dev/null ) \
            && grep -v rodete <(uname -r) > /dev/null \
            || sed -i "s/\"zone\": \".*\"$/\"zone\": \"$(cat /etc/nodeinfo/zone)\"/" /etc/grpc-xds/bootstrap.json
        resources:
          requests:
            cpu: 10m
            memory: 100Mi
        volumeMounts:
        - name: grpc-xds-conf
          mountPath: /etc/grpc-xds
        - name: nodeinfo
          mountPath: /etc/nodeinfo
          readOnly: true
        - name: podinfo
          mountPath: /etc/podinfo
          readOnly: true
      volumes:
      - name: grpc-xds-conf
        emptyDir: {}
      - name: nodeinfo
        emptyDir: {}
      - name: podinfo
        downwardAPI:
          # Used when creating the xDS bootstrap file.
          items:
          - path: label-app-name
            fieldRef:
              fieldPath: metadata.labels['app.kubernetes.io/name']
          - path: namespace
            fieldRef:
              fieldPath: metadata.namespace
