From 4b2e7e153e32b106a135dce83f3c7e4460f136e0 Mon Sep 17 00:00:00 2001 From: Matias Manavella Date: Fri, 4 Sep 2020 12:41:47 -0300 Subject: [PATCH] add or create ImagePullSecret --- .../troubleshoot/v1beta1/collector_shared.go | 21 +++-- .../troubleshoot/v1beta2/collector_shared.go | 21 +++-- pkg/collect/run.go | 83 ++++++++++++++++++- 3 files changed, 110 insertions(+), 15 deletions(-) diff --git a/pkg/apis/troubleshoot/v1beta1/collector_shared.go b/pkg/apis/troubleshoot/v1beta1/collector_shared.go index aeaf7735..5a4bbd64 100644 --- a/pkg/apis/troubleshoot/v1beta1/collector_shared.go +++ b/pkg/apis/troubleshoot/v1beta1/collector_shared.go @@ -52,13 +52,20 @@ type Data struct { type Run struct { CollectorMeta `json:",inline" yaml:",inline"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - Namespace string `json:"namespace" yaml:"namespace"` - Image string `json:"image" yaml:"image"` - Command []string `json:"command,omitempty" yaml:"command,omitempty"` - Args []string `json:"args,omitempty" yaml:"args,omitempty"` - Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"` - ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Namespace string `json:"namespace" yaml:"namespace"` + Image string `json:"image" yaml:"image"` + Command []string `json:"command,omitempty" yaml:"command,omitempty"` + Args []string `json:"args,omitempty" yaml:"args,omitempty"` + Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"` + ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"` + ImagePullSecret *ImagePullSecrets `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"` +} + +type ImagePullSecrets struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Data map[string]string `json:"data,omitempty" yaml:"data,omitempty"` + SecretType string `json:"type,omitempty" yaml:"type,omitempty"` } type Exec struct { diff --git a/pkg/apis/troubleshoot/v1beta2/collector_shared.go b/pkg/apis/troubleshoot/v1beta2/collector_shared.go index 97009856..5a21bec3 100644 --- a/pkg/apis/troubleshoot/v1beta2/collector_shared.go +++ b/pkg/apis/troubleshoot/v1beta2/collector_shared.go @@ -52,13 +52,20 @@ type Data struct { type Run struct { CollectorMeta `json:",inline" yaml:",inline"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - Namespace string `json:"namespace" yaml:"namespace"` - Image string `json:"image" yaml:"image"` - Command []string `json:"command,omitempty" yaml:"command,omitempty"` - Args []string `json:"args,omitempty" yaml:"args,omitempty"` - Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"` - ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Namespace string `json:"namespace" yaml:"namespace"` + Image string `json:"image" yaml:"image"` + Command []string `json:"command,omitempty" yaml:"command,omitempty"` + Args []string `json:"args,omitempty" yaml:"args,omitempty"` + Timeout string `json:"timeout,omitempty" yaml:"timeout,omitempty"` + ImagePullPolicy string `json:"imagePullPolicy,omitempty" yaml:"imagePullPolicy,omitempty"` + ImagePullSecret *ImagePullSecrets `json:"imagePullSecret,omitempty" yaml:"imagePullSecret,omitempty"` +} + +type ImagePullSecrets struct { + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Data map[string]string `json:"data,omitempty" yaml:"data,omitempty"` + SecretType string `json:"type,omitempty" yaml:"type,omitempty"` } type Exec struct { diff --git a/pkg/collect/run.go b/pkg/collect/run.go index a54bf7e3..5be71efb 100644 --- a/pkg/collect/run.go +++ b/pkg/collect/run.go @@ -1,7 +1,11 @@ package collect import ( + "bytes" "context" + "encoding/base64" + "encoding/json" + "io/ioutil" "time" "github.com/pkg/errors" @@ -30,7 +34,15 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (map[string][]byte logger.Printf("Failed to delete pod %s: %v\n", pod.Name, err) } }() - + if runCollector.ImagePullSecret.Data != nil { + defer func() { + for _, k := range pod.Spec.ImagePullSecrets { + if err := client.CoreV1().Secrets(pod.Namespace).Delete(ctx, k.Name, metav1.DeleteOptions{}); err != nil { + logger.Printf("Failed to delete secret %s: %v\n", k.Name, err) + } + } + }() + } if runCollector.Timeout == "" { return runWithoutTimeout(ctx, c, pod, runCollector) } @@ -137,6 +149,12 @@ func runPod(ctx context.Context, client *kubernetes.Clientset, runCollector *tro }, } + if runCollector.ImagePullSecret != nil { + err := createSecret(ctx, client, runCollector.ImagePullSecret, &pod) + if err != nil { + return nil, err + } + } created, err := client.CoreV1().Pods(namespace).Create(ctx, &pod, metav1.CreateOptions{}) if err != nil { return nil, errors.Wrap(err, "failed to create pod") @@ -144,3 +162,66 @@ func runPod(ctx context.Context, client *kubernetes.Clientset, runCollector *tro return created, nil } +func createSecret(ctx context.Context, client *kubernetes.Clientset, imagePullSecret *troubleshootv1beta2.ImagePullSecrets, pod *corev1.Pod) error { + //In case a new secret needs to be created + if imagePullSecret.Data != nil { + var out bytes.Buffer + data := make(map[string][]byte) + if imagePullSecret.SecretType == "kubernetes.io/dockerconfigjson" { + //If secret type is dockerconfigjson, check if required field in data exists + v, found := imagePullSecret.Data[".dockerconfigjson"] + if !found { + return errors.Errorf("Secret type kubernetes.io/dockerconfigjson requires argument \".dockerconfigjson\"") + } + if len(imagePullSecret.Data) > 1 { + return errors.Errorf("Secret type kubernetes.io/dockerconfigjson accepts only one argument \".dockerconfigjson\"") + } + //Then, if data is a path to a config file, it is opened + configFile, err := ioutil.ReadFile(v) + if err != nil { + //If data is not a valid path, we assume data is a base64 encoded config.json file + //Client only accepts Json formated files as data, so we decode and indent it (indentation is required) + parsedConfig, err := base64.StdEncoding.DecodeString(v) + if err != nil { + return err + } + err = json.Indent(&out, parsedConfig, "", "\t") + if err != nil { + return errors.Errorf("Secret's config file not found or unable to parse encoded data.") + } + data[".dockerconfigjson"] = out.Bytes() + } else { + data[".dockerconfigjson"] = configFile + } + } else { + for k, v := range imagePullSecret.Data { + data[k] = []byte(v) + } + } + secret := corev1.Secret{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Secret", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: imagePullSecret.Name, + GenerateName: "tmpsecret", + Namespace: pod.Namespace, + }, + Data: data, + Type: corev1.SecretType(imagePullSecret.SecretType), + } + created, err := client.CoreV1().Secrets(pod.Namespace).Create(ctx, &secret, metav1.CreateOptions{}) + if err != nil { + return err + } + pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, corev1.LocalObjectReference{Name: created.Name}) + return nil + } + //In case secret must only be added to the specs. + if imagePullSecret.Name != "" { + pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, corev1.LocalObjectReference{Name: imagePullSecret.Name}) + return nil + } + return errors.Errorf("Secret must at least have a Name") +}