|
1 | 1 | package collect |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
4 | 5 | "context" |
| 6 | + "encoding/base64" |
| 7 | + "encoding/json" |
| 8 | + "io/ioutil" |
5 | 9 | "time" |
6 | 10 |
|
7 | 11 | "github.com/pkg/errors" |
@@ -30,7 +34,15 @@ func Run(c *Collector, runCollector *troubleshootv1beta2.Run) (map[string][]byte |
30 | 34 | logger.Printf("Failed to delete pod %s: %v\n", pod.Name, err) |
31 | 35 | } |
32 | 36 | }() |
33 | | - |
| 37 | + if runCollector.ImagePullSecret.Data != nil { |
| 38 | + defer func() { |
| 39 | + for _, k := range pod.Spec.ImagePullSecrets { |
| 40 | + if err := client.CoreV1().Secrets(pod.Namespace).Delete(ctx, k.Name, metav1.DeleteOptions{}); err != nil { |
| 41 | + logger.Printf("Failed to delete secret %s: %v\n", k.Name, err) |
| 42 | + } |
| 43 | + } |
| 44 | + }() |
| 45 | + } |
34 | 46 | if runCollector.Timeout == "" { |
35 | 47 | return runWithoutTimeout(ctx, c, pod, runCollector) |
36 | 48 | } |
@@ -137,10 +149,79 @@ func runPod(ctx context.Context, client *kubernetes.Clientset, runCollector *tro |
137 | 149 | }, |
138 | 150 | } |
139 | 151 |
|
| 152 | + if runCollector.ImagePullSecret != nil { |
| 153 | + err := createSecret(ctx, client, runCollector.ImagePullSecret, &pod) |
| 154 | + if err != nil { |
| 155 | + return nil, errors.Wrap(err, "failed to create secret") |
| 156 | + } |
| 157 | + } |
140 | 158 | created, err := client.CoreV1().Pods(namespace).Create(ctx, &pod, metav1.CreateOptions{}) |
141 | 159 | if err != nil { |
142 | 160 | return nil, errors.Wrap(err, "failed to create pod") |
143 | 161 | } |
144 | 162 |
|
145 | 163 | return created, nil |
146 | 164 | } |
| 165 | +func createSecret(ctx context.Context, client *kubernetes.Clientset, imagePullSecret *troubleshootv1beta2.ImagePullSecrets, pod *corev1.Pod) error { |
| 166 | + //In case a new secret needs to be created |
| 167 | + if imagePullSecret.Data != nil { |
| 168 | + var out bytes.Buffer |
| 169 | + data := make(map[string][]byte) |
| 170 | + if imagePullSecret.SecretType == "kubernetes.io/dockerconfigjson" { |
| 171 | + //If secret type is dockerconfigjson, check if required field in data exists |
| 172 | + v, found := imagePullSecret.Data[".dockerconfigjson"] |
| 173 | + if !found { |
| 174 | + return errors.Errorf("Secret type kubernetes.io/dockerconfigjson requires argument \".dockerconfigjson\"") |
| 175 | + } |
| 176 | + if len(imagePullSecret.Data) > 1 { |
| 177 | + return errors.Errorf("Secret type kubernetes.io/dockerconfigjson accepts only one argument \".dockerconfigjson\"") |
| 178 | + } |
| 179 | + //Then, if data is a path to a config file, it is opened |
| 180 | + configFile, err := ioutil.ReadFile(v) |
| 181 | + if err != nil { |
| 182 | + //If data is not a valid path, we assume data is a base64 encoded config.json file |
| 183 | + //Client only accepts Json formated files as data, so we decode and indent it (indentation is required) |
| 184 | + parsedConfig, err := base64.StdEncoding.DecodeString(v) |
| 185 | + if err != nil { |
| 186 | + return errors.Wrap(err, "Secret's config file not found or unable to decode data.") |
| 187 | + } |
| 188 | + err = json.Indent(&out, parsedConfig, "", "\t") |
| 189 | + if err != nil { |
| 190 | + return errors.Wrap(err, "Unable to parse encoded data.") |
| 191 | + } |
| 192 | + data[".dockerconfigjson"] = out.Bytes() |
| 193 | + } else { |
| 194 | + data[".dockerconfigjson"] = configFile |
| 195 | + } |
| 196 | + } else { |
| 197 | + for k, v := range imagePullSecret.Data { |
| 198 | + data[k] = []byte(v) |
| 199 | + } |
| 200 | + } |
| 201 | + secret := corev1.Secret{ |
| 202 | + TypeMeta: metav1.TypeMeta{ |
| 203 | + APIVersion: "v1", |
| 204 | + Kind: "Secret", |
| 205 | + }, |
| 206 | + ObjectMeta: metav1.ObjectMeta{ |
| 207 | + Name: imagePullSecret.Name, |
| 208 | + GenerateName: "troubleshoot", |
| 209 | + Namespace: pod.Namespace, |
| 210 | + }, |
| 211 | + Data: data, |
| 212 | + Type: corev1.SecretType(imagePullSecret.SecretType), |
| 213 | + } |
| 214 | + created, err := client.CoreV1().Secrets(pod.Namespace).Create(ctx, &secret, metav1.CreateOptions{}) |
| 215 | + if err != nil { |
| 216 | + return errors.Wrap(err, "failed to create secret") |
| 217 | + } |
| 218 | + pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, corev1.LocalObjectReference{Name: created.Name}) |
| 219 | + return nil |
| 220 | + } |
| 221 | + //In case secret must only be added to the specs. |
| 222 | + if imagePullSecret.Name != "" { |
| 223 | + pod.Spec.ImagePullSecrets = append(pod.Spec.ImagePullSecrets, corev1.LocalObjectReference{Name: imagePullSecret.Name}) |
| 224 | + return nil |
| 225 | + } |
| 226 | + return errors.Errorf("Secret must at least have a Name") |
| 227 | +} |
0 commit comments