From 31b87ccdef3c3db02b4abb371b1a362b4c005c7b Mon Sep 17 00:00:00 2001 From: Ye Cao Date: Fri, 21 Jul 2023 21:14:02 +0800 Subject: [PATCH] * Add the volumes and volumesMount to the workload in the 'schedule workload' command. * Support to inject sidecar container to a pod more than a workload. * Add the description of commands and update relevant doc. Signed-off-by: Ye Cao --- docs/notes/developers/build-from-source.rst | 2 + k8s/cmd/README.md | 266 +++++++++++++++++- .../flags/scheduler_workload_flags.go | 9 + .../commands/schedule/schedule_workload.go | 196 ++++++++++++- k8s/cmd/commands/sidecar/inject.go | 191 ++++++++++++- k8s/pkg/injector/sidecar_injector.go | 32 +++ 6 files changed, 663 insertions(+), 33 deletions(-) diff --git a/docs/notes/developers/build-from-source.rst b/docs/notes/developers/build-from-source.rst index f9d850b5d9..c9fd0f3f3b 100644 --- a/docs/notes/developers/build-from-source.rst +++ b/docs/notes/developers/build-from-source.rst @@ -150,6 +150,8 @@ Vineyardctl is available on the Github release page, you can download the binary export OS=$(uname -s | tr '[:upper:]' '[:lower:]') export ARCH=${$(uname -m)/x86_64/amd64} curl -Lo vineyardctl https://github.com/v6d-io/v6d/releases/download/$LATEST_TAG/vineyardctl-$LATEST_TAG-$OS-$ARCH + chmod +x vineyardctl + sudo mv vineyardctl /usr/local/bin/ Building the documentation diff --git a/k8s/cmd/README.md b/k8s/cmd/README.md index 8f6aa230df..62216965ed 100644 --- a/k8s/cmd/README.md +++ b/k8s/cmd/README.md @@ -1065,12 +1065,185 @@ Inject the vineyard sidecar container into a workload Inject the vineyard sidecar container into a workload. You can input a workload yaml or a workload json and then get the injected -workload and some etcd manifests from the output. +workload and some etcd manifests from the output. The workload can +be a pod or a deployment or a statefulset, etc. The output is a set of manifests that includes the injected workload, the rpc service, the etcd service and the etcd cluster(e.g. several -pods and services). Next, we will introduce a simple example to show -the injection. +pods and services). + +If you have a pod yaml: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + name: python +spec: + containers: + - name: python + image: python:3.10 +command: ["python", "-c", "import time; time.sleep(100000)"] +``` +Then, you can use the following command to inject the vineyard sidecar + +$ vineyardctl inject -f pod.yaml + +After running the command, the output is as follows: + +```yaml +apiVersion: v1 +kind: Pod +metadata: + labels: +app.vineyard.io/name: vineyard-sidecar +app.vineyard.io/role: etcd +etcd_node: vineyard-sidecar-etcd-0 + name: vineyard-sidecar-etcd-0 + namespace: null + ownerReferences: [] +spec: + containers: + - command: +- etcd +- --name +- vineyard-sidecar-etcd-0 +- --initial-advertise-peer-urls +- http://vineyard-sidecar-etcd-0:2380 +- --advertise-client-urls +- http://vineyard-sidecar-etcd-0:2379 +- --listen-peer-urls +- http://0.0.0.0:2380 +- --listen-client-urls +- http://0.0.0.0:2379 +- --initial-cluster +- vineyard-sidecar-etcd-0=http://vineyard-sidecar-etcd-0:2380 +- --initial-cluster-state +- new +image: vineyardcloudnative/vineyardd:latest +name: etcd +ports: +- containerPort: 2379 + name: client + protocol: TCP +- containerPort: 2380 + name: server + protocol: TCP + restartPolicy: Always +--- +apiVersion: v1 +kind: Service +metadata: + labels: +etcd_node: vineyard-sidecar-etcd-0 + name: vineyard-sidecar-etcd-0 + namespace: null + ownerReferences: [] +spec: + ports: + - name: client + port: 2379 +protocol: TCP +targetPort: 2379 + - name: server +port: 2380 +protocol: TCP +targetPort: 2380 + selector: +app.vineyard.io/role: etcd +etcd_node: vineyard-sidecar-etcd-0 +--- +apiVersion: v1 +kind: Service +metadata: + name: vineyard-sidecar-etcd-service + namespace: null + ownerReferences: [] +spec: + ports: + - name: vineyard-sidecar-etcd-for-vineyard-port +port: 2379 +protocol: TCP +targetPort: 2379 + selector: +app.vineyard.io/name: vineyard-sidecar +app.vineyard.io/role: etcd +--- +apiVersion: v1 +kind: Service +metadata: + labels: +app.vineyard.io/name: vineyard-sidecar + name: vineyard-sidecar-rpc + namespace: null + ownerReferences: [] +spec: + ports: + - name: vineyard-rpc +port: 9600 +protocol: TCP + selector: +app.vineyard.io/name: vineyard-sidecar +app.vineyard.io/role: vineyardd + type: ClusterIP +--- +apiVersion: v1 +kind: Pod +metadata: + creationTimestamp: null + labels: +app.vineyard.io/name: vineyard-sidecar +app.vineyard.io/role: vineyardd + name: python + ownerReferences: [] +spec: + containers: + - command: +- python +- -c +- while [ ! -e /var/run/vineyard.sock ]; do sleep 1; done;import time; time.sleep(100000) +env: +- name: VINEYARD_IPC_SOCKET + value: /var/run/vineyard.sock +image: python:3.10 +name: python +resources: {} +volumeMounts: +- mountPath: /var/run + name: vineyard-socket + - command: +- /bin/bash +- -c +- | + /usr/bin/wait-for-it.sh -t 60 vineyard-sidecar-etcd-service..svc.cluster.local:2379; sleep 1; /usr/local/bin/vineyardd --sync_crds true --socket /var/run/vineyard.sock --size --stream_threshold 80 --etcd_cmd etcd --etcd_prefix /vineyard --etcd_endpoint http://vineyard-sidecar-etcd-service:2379 +env: +- name: VINEYARDD_UID + value: null +- name: VINEYARDD_NAME + value: vineyard-sidecar +- name: VINEYARDD_NAMESPACE + value: null +image: vineyardcloudnative/vineyardd:latest +imagePullPolicy: IfNotPresent +name: vineyard-sidecar +ports: +- containerPort: 9600 + name: vineyard-rpc + protocol: TCP +resources: + limits: null + requests: null +volumeMounts: +- mountPath: /var/run + name: vineyard-socket + volumes: + - emptyDir: {} +name: vineyard-socket +status: {} +``` + +Next, we will introduce a simple example to show the injection with +the apply-resources flag. Assume you have the following workload yaml: @@ -1098,6 +1271,8 @@ spec: ``` Then, you can use the following command to inject the vineyard sidecar +which means that all resources will be created during the injection except +the workload itself. The workload should be created by users. $ vineyardctl inject -f workload.yaml --apply-resources @@ -1561,7 +1736,87 @@ Schedule the workload to a vineyard cluster Schedule the workload to a vineyard cluster. It will add the podAffinity to the workload so that the workload -will be scheduled to the vineyard cluster. +will be scheduled to the vineyard cluster. Besides, if the workload +does not have the socket volumeMount and volume, it will add one. + +Assume you have the following workload yaml: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + name: python-client + # Notice, you must set the namespace here + namespace: vineyard-job +spec: + selector: + matchLabels: + app: python + template: + metadata: + labels: + app: python + spec: + containers: + - name: python + image: python:3.10 + command: ["python", "-c", "import time; time.sleep(100000)"] +``` + +Then you can run the following command to add the podAffinity and socket volume +to the workload yaml: + +$ vineyard schedule workload -f workload.yaml -o yaml + +After that, you will get the following workload yaml: + +```yaml +apiVersion: apps/v1 +kind: Deployment +metadata: + creationTimestamp: null + name: python-client + namespace: vineyard-job +spec: + selector: +matchLabels: + app: python + strategy: {} + template: +metadata: + creationTimestamp: null + labels: +app: python +spec: + affinity: +podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/instance +operator: In +values: +- vineyard-system-vineyardd-sample +topologyKey: kubernetes.io/hostname + containers: + - command: +- python +- -c +- import time; time.sleep(100000) +env: +- name: VINEYARD_IPC_SOCKET + value: /var/run/vineyard.sock +image: python:3.10 +name: python +resources: {} +volumeMounts: +- mountPath: /var/run + name: vineyard-socket + volumes: + - hostPath: + path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample +name: vineyard-socket +``` ``` vineyardctl schedule workload [flags] @@ -1650,9 +1905,10 @@ vineyardctl schedule workload [flags] ### Options ``` + -f, --file string the file path of workload -h, --help help for workload + -o, --output string the output format for vineyardctl schedule workload command (default "json") --resource string the json string of kubernetes workload --vineyardd-name string the namespace of vineyard cluster (default "vineyardd-sample") --vineyardd-namespace string the namespace of vineyard cluster (default "vineyard-system") ``` - diff --git a/k8s/cmd/commands/flags/scheduler_workload_flags.go b/k8s/cmd/commands/flags/scheduler_workload_flags.go index 476efaf9e1..3736e8a931 100644 --- a/k8s/cmd/commands/flags/scheduler_workload_flags.go +++ b/k8s/cmd/commands/flags/scheduler_workload_flags.go @@ -23,11 +23,20 @@ var ( // the namespace of vineyard cluster VineyarddNamespace string + + // the output format for vineyardctl schedule workload command + ScheduleOutputFormat string + + // the file path of workload + WorkloadFile string ) func ApplySchedulerWorkloadOpts(cmd *cobra.Command) { cmd.Flags().StringVarP(&Resource, "resource", "", "", "the json string of kubernetes workload") + cmd.Flags().StringVarP(&WorkloadFile, "file", "f", "", "the file path of workload") + cmd.Flags().StringVarP(&ScheduleOutputFormat, "output", "o", "json", + "the output format for vineyardctl schedule workload command") cmd.Flags(). StringVarP(&VineyarddName, "vineyardd-name", "", "vineyardd-sample", "the namespace of vineyard cluster") diff --git a/k8s/cmd/commands/schedule/schedule_workload.go b/k8s/cmd/commands/schedule/schedule_workload.go index a00c6c68fe..b0d405ab09 100644 --- a/k8s/cmd/commands/schedule/schedule_workload.go +++ b/k8s/cmd/commands/schedule/schedule_workload.go @@ -27,14 +27,101 @@ import ( "github.com/v6d-io/v6d/k8s/cmd/commands/flags" "github.com/v6d-io/v6d/k8s/cmd/commands/util" + "github.com/v6d-io/v6d/k8s/pkg/injector" "github.com/v6d-io/v6d/k8s/pkg/log" ) +const ( + // VineyardDeploymentSocketPrefix is the prefix of vineyard deployment socket + VineyardDeploymentSocketPrefix = "/var/run/vineyard-kubernetes/" + + // ScheduleWorkloadMountPath is the mount path of the vineyard socket + ScheduleWorkloadMountPath = "/var/run" +) + var ( scheduleWorkloadLong = util.LongDesc(` Schedule the workload to a vineyard cluster. It will add the podAffinity to the workload so that the workload - will be scheduled to the vineyard cluster.`) + will be scheduled to the vineyard cluster. Besides, if the workload + does not have the socket volumeMount and volume, it will add one. + + Assume you have the following workload yaml:` + + "\n\n```yaml" + ` + apiVersion: apps/v1 + kind: Deployment + metadata: + name: python-client + # Notice, you must set the namespace here + namespace: vineyard-job + spec: + selector: + matchLabels: + app: python + template: + metadata: + labels: + app: python + spec: + containers: + - name: python + image: python:3.10 + command: ["python", "-c", "import time; time.sleep(100000)"]` + + "\n```" + ` + + Then you can run the following command to add the podAffinity and socket volume + to the workload yaml: + + $ vineyard schedule workload -f workload.yaml -o yaml + + After that, you will get the following workload yaml: ` + + "\n\n```yaml" + ` + apiVersion: apps/v1 + kind: Deployment + metadata: + creationTimestamp: null + name: python-client + namespace: vineyard-job + spec: + selector: + matchLabels: + app: python + strategy: {} + template: + metadata: + creationTimestamp: null + labels: + app: python + spec: + affinity: + podAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: app.kubernetes.io/instance + operator: In + values: + - vineyard-system-vineyardd-sample + topologyKey: kubernetes.io/hostname + containers: + - command: + - python + - -c + - import time; time.sleep(100000) + env: + - name: VINEYARD_IPC_SOCKET + value: /var/run/vineyard.sock + image: python:3.10 + name: python + resources: {} + volumeMounts: + - mountPath: /var/run + name: vineyard-socket + volumes: + - hostPath: + path: /var/run/vineyard-kubernetes/vineyard-system/vineyardd-sample + name: vineyard-socket` + + "\n```") scheduleWorkloadExample = util.Examples(` # Add the podAffinity to the workload for the specific vineyard cluster @@ -119,18 +206,33 @@ var scheduleWorkloadCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { util.AssertNoArgs(cmd, args) - obj, v, err := getWorkload(flags.Resource) - if err != nil || !v { - log.Fatal(err, "failed to validate the workload") - } client := util.KubernetesClient() + var obj *unstructured.Unstructured + if flags.WorkloadFile != "" { + resource, err := util.ReadFromFile(flags.WorkloadFile) + if err != nil { + log.Fatal(err, "failed to read the workload file") + } + obj, err = util.ParseManifestToObject(resource) + if err != nil { + log.Fatal(err, "failed to parse the workload yaml") + } - workload, err := SchedulingWorkload(client, obj) + } else { + var v bool + var err error + obj, v, err = getWorkload(flags.Resource) + if err != nil || !v { + log.Fatal(err, "failed to validate the workload") + } + } + obj, err := SchedulingWorkload(client, obj) if err != nil { log.Fatal(err, "failed to schedule workload") } - - log.Output(workload) + if err := output(obj); err != nil { + log.Fatal(err, "failed to output the workload") + } }, } @@ -172,11 +274,11 @@ func getWorkload(workload string) (*unstructured.Unstructured, bool, error) { // SchedulingWorkload is used to schedule the workload to the vineyard cluster // and add the podAffinity to the workload func SchedulingWorkload(c client.Client, - unstructuredObj *unstructured.Unstructured) (string, error) { + unstructuredObj *unstructured.Unstructured) (*unstructured.Unstructured, error) { name := client.ObjectKey{Name: flags.VineyarddName, Namespace: flags.VineyarddNamespace} deployment := appsv1.Deployment{} if err := c.Get(context.TODO(), name, &deployment); err != nil { - return "", errors.Wrap(err, "failed to get the deployment") + return nil, errors.Wrap(err, "failed to get the deployment") } value := flags.VineyarddNamespace + "-" + flags.VineyarddName @@ -203,12 +305,80 @@ func SchedulingWorkload(c client.Client, err := unstructured.SetNestedSlice(unstructuredObj.Object, required, "spec", "template", "spec", "affinity", "podAffinity", "requiredDuringSchedulingIgnoredDuringExecution") if err != nil { - return "", errors.Wrap(err, "failed to set the nested slice") + return nil, errors.Wrap(err, "failed to set the nested slice") + } + + // check the socket's volumeMount and volume exist or not + // if not, add the socket's volumeMount and volume to the workload + socketPath := VineyardDeploymentSocketPrefix + flags.VineyarddNamespace + "/" + flags.VineyarddName + volumes, err := injector.GetVolume(unstructuredObj) + if err != nil { + return nil, errors.Wrap(err, "failed to get the volumes") + } + // if the volume exists, return the workload + for _, volume := range volumes { + hostPath := volume.(map[string]interface{})["hostPath"] + if hostPath != nil { + path := hostPath.(map[string]interface{})["path"] + if path != nil && path.(string) == socketPath { + return unstructuredObj, nil + } + } + } + // add the socket path volumeMount and volume to the workload + socketVolume := map[string]interface{}{ + "name": "vineyard-socket", + "hostPath": map[string]interface{}{ + "path": socketPath, + }, + } + volumes = append(volumes, socketVolume) + err = injector.SetVolume(unstructuredObj, volumes) + if err != nil { + return nil, errors.Wrap(err, "failed to set the volumes") + } + + containers, err := injector.GetContainer(unstructuredObj) + if err != nil { + return nil, errors.Wrap(err, "failed to get the containers") + } + socketVolumeMount := map[string]interface{}{ + "name": "vineyard-socket", + "mountPath": ScheduleWorkloadMountPath, + } + for _, container := range containers { + volumesMounts := container.(map[string]interface{})["volumeMounts"] + if volumesMounts == nil { + volumesMounts = []interface{}{} + } + volumesMounts = append(volumesMounts.([]interface{}), socketVolumeMount) + container.(map[string]interface{})["volumeMounts"] = volumesMounts } + injector.InjectEnv(&containers, ScheduleWorkloadMountPath) + + err = injector.SetContainer(unstructuredObj, containers) + if err != nil { + return nil, errors.Wrap(err, "failed to set the containers") + } + + return unstructuredObj, nil +} + +func output(unstructuredObj *unstructured.Unstructured) error { ss, err := unstructuredObj.MarshalJSON() if err != nil { - return "", errors.Wrap(err, "failed to marshal the unstructuredObj") + return errors.Wrap(err, "failed to marshal the unstructuredObj") + } + jsonStr := string(ss) + if flags.ScheduleOutputFormat == "json" { + log.Output(jsonStr) + } else { + yamlStr, err := util.ConvertToYaml(jsonStr) + if err != nil { + return errors.Wrap(err, "failed to convert to yaml") + } + log.Output(yamlStr) } - return string(ss), nil + return nil } diff --git a/k8s/cmd/commands/sidecar/inject.go b/k8s/cmd/commands/sidecar/inject.go index 9877ae02d8..fba99bf5bc 100644 --- a/k8s/cmd/commands/sidecar/inject.go +++ b/k8s/cmd/commands/sidecar/inject.go @@ -72,12 +72,183 @@ var ( injectLong = util.LongDesc(` Inject the vineyard sidecar container into a workload. You can input a workload yaml or a workload json and then get the injected - workload and some etcd manifests from the output. + workload and some etcd manifests from the output. The workload can + be a pod or a deployment or a statefulset, etc. The output is a set of manifests that includes the injected workload, the rpc service, the etcd service and the etcd cluster(e.g. several - pods and services). Next, we will introduce a simple example to show - the injection. + pods and services). + + If you have a pod yaml: ` + + "\n\n```yaml" + ` + apiVersion: v1 + kind: Pod + metadata: + name: python + spec: + containers: + - name: python + image: python:3.10 + command: ["python", "-c", "import time; time.sleep(100000)"]` + + "\n```" + ` + Then, you can use the following command to inject the vineyard sidecar + + $ vineyardctl inject -f pod.yaml + + After running the command, the output is as follows:` + + "\n\n```yaml" + ` + apiVersion: v1 + kind: Pod + metadata: + labels: + app.vineyard.io/name: vineyard-sidecar + app.vineyard.io/role: etcd + etcd_node: vineyard-sidecar-etcd-0 + name: vineyard-sidecar-etcd-0 + namespace: null + ownerReferences: [] + spec: + containers: + - command: + - etcd + - --name + - vineyard-sidecar-etcd-0 + - --initial-advertise-peer-urls + - http://vineyard-sidecar-etcd-0:2380 + - --advertise-client-urls + - http://vineyard-sidecar-etcd-0:2379 + - --listen-peer-urls + - http://0.0.0.0:2380 + - --listen-client-urls + - http://0.0.0.0:2379 + - --initial-cluster + - vineyard-sidecar-etcd-0=http://vineyard-sidecar-etcd-0:2380 + - --initial-cluster-state + - new + image: vineyardcloudnative/vineyardd:latest + name: etcd + ports: + - containerPort: 2379 + name: client + protocol: TCP + - containerPort: 2380 + name: server + protocol: TCP + restartPolicy: Always + --- + apiVersion: v1 + kind: Service + metadata: + labels: + etcd_node: vineyard-sidecar-etcd-0 + name: vineyard-sidecar-etcd-0 + namespace: null + ownerReferences: [] + spec: + ports: + - name: client + port: 2379 + protocol: TCP + targetPort: 2379 + - name: server + port: 2380 + protocol: TCP + targetPort: 2380 + selector: + app.vineyard.io/role: etcd + etcd_node: vineyard-sidecar-etcd-0 + --- + apiVersion: v1 + kind: Service + metadata: + name: vineyard-sidecar-etcd-service + namespace: null + ownerReferences: [] + spec: + ports: + - name: vineyard-sidecar-etcd-for-vineyard-port + port: 2379 + protocol: TCP + targetPort: 2379 + selector: + app.vineyard.io/name: vineyard-sidecar + app.vineyard.io/role: etcd + --- + apiVersion: v1 + kind: Service + metadata: + labels: + app.vineyard.io/name: vineyard-sidecar + name: vineyard-sidecar-rpc + namespace: null + ownerReferences: [] + spec: + ports: + - name: vineyard-rpc + port: 9600 + protocol: TCP + selector: + app.vineyard.io/name: vineyard-sidecar + app.vineyard.io/role: vineyardd + type: ClusterIP + --- + apiVersion: v1 + kind: Pod + metadata: + creationTimestamp: null + labels: + app.vineyard.io/name: vineyard-sidecar + app.vineyard.io/role: vineyardd + name: python + ownerReferences: [] + spec: + containers: + - command: + - python + - -c + - while [ ! -e /var/run/vineyard.sock ]; do sleep 1; done;import time; time.sleep(100000) + env: + - name: VINEYARD_IPC_SOCKET + value: /var/run/vineyard.sock + image: python:3.10 + name: python + resources: {} + volumeMounts: + - mountPath: /var/run + name: vineyard-socket + - command: + - /bin/bash + - -c + - | + /usr/bin/wait-for-it.sh -t 60 vineyard-sidecar-etcd-service..svc.cluster.local:2379; sleep 1; /usr/local/bin/vineyardd --sync_crds true --socket /var/run/vineyard.sock --size --stream_threshold 80 --etcd_cmd etcd --etcd_prefix /vineyard --etcd_endpoint http://vineyard-sidecar-etcd-service:2379 + env: + - name: VINEYARDD_UID + value: null + - name: VINEYARDD_NAME + value: vineyard-sidecar + - name: VINEYARDD_NAMESPACE + value: null + image: vineyardcloudnative/vineyardd:latest + imagePullPolicy: IfNotPresent + name: vineyard-sidecar + ports: + - containerPort: 9600 + name: vineyard-rpc + protocol: TCP + resources: + limits: null + requests: null + volumeMounts: + - mountPath: /var/run + name: vineyard-socket + volumes: + - emptyDir: {} + name: vineyard-socket + status: {}` + + "\n```" + ` + + Next, we will introduce a simple example to show the injection with + the apply-resources flag. Assume you have the following workload yaml:` + "\n\n```yaml" + ` @@ -104,6 +275,8 @@ var ( "\n```" + ` Then, you can use the following command to inject the vineyard sidecar + which means that all resources will be created during the injection except + the workload itself. The workload should be created by users. $ vineyardctl inject -f workload.yaml --apply-resources @@ -279,18 +452,6 @@ func GetWorkloadObj(workload string) (*unstructured.Unstructured, error) { return nil, errors.Wrap(err, "failed to parse the workload") } - // check if the workload is valid - _, found, err := unstructured.NestedMap(unstructuredObj.Object, "spec", "template") - if err != nil { - return nil, errors.Wrap(err, "failed to get the template of the workload") - } - if !found { - return nil, errors.Wrap( - fmt.Errorf("failed to find the template of the workload"), - "invalid workload", - ) - } - return unstructuredObj, nil } diff --git a/k8s/pkg/injector/sidecar_injector.go b/k8s/pkg/injector/sidecar_injector.go index 9450b79b15..744b5a8dde 100644 --- a/k8s/pkg/injector/sidecar_injector.go +++ b/k8s/pkg/injector/sidecar_injector.go @@ -29,6 +29,9 @@ import ( var ( // PodKind is the kind of the kubernetes pod. PodKind = "Pod" + + // SocketEnv is the env of vineyard ipc socket. + SocketEnv = "VINEYARD_IPC_SOCKET" ) // GetLabels returns the labels of the given unstructured kubernetes object. @@ -144,6 +147,30 @@ func GetContainersAndVolumes(obj *unstructured.Unstructured) ([]interface{}, []i return containers, volumes, nil } +// InjectEnv injects the vineyard ipc socket env into the containers env. +func InjectEnv(containers *[]interface{}, mountPath string) { + // check if the vineyard ipc socket env is already exist + // if exist, update the value + for _, c := range *containers { + if c.(map[string]interface{})["env"] == nil { + c.(map[string]interface{})["env"] = make([]interface{}, 0) + } + env := c.(map[string]interface{})["env"].([]interface{}) + newEnv := make([]interface{}, 0) + for _, e := range env { + if e.(map[string]interface{})["name"] == SocketEnv { + continue + } + newEnv = append(newEnv, e) + } + newEnv = append(newEnv, map[string]interface{}{ + "name": SocketEnv, + "value": mountPath + "/vineyard.sock", + }) + c.(map[string]interface{})["env"] = newEnv + } +} + // injectContainersAndVolumes injects the sidecar containers and volumes into the workload containers and volumes. func injectContainersAndVolumes(workloadContainers []interface{}, workloadVolumes []interface{}, @@ -194,6 +221,8 @@ func injectContainersAndVolumes(workloadContainers []interface{}, c["volumeMounts"] = volumeMounts } + InjectEnv(&workloadContainers, mountPath) + containers = append(workloadContainers, sidecarContainers...) volumes = append(workloadVolumes, sidecarVolumes...) @@ -231,6 +260,9 @@ func InjectSidecar(workload, sidecar *unstructured.Unstructured, s *v1alpha1.Sid return err } + if labels == nil { + labels = make(map[string]string) + } selectors := strings.Split(selector, ",") for i := range selectors { s := strings.Split(selectors[i], "=")