• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubevirt / containerized-data-importer / #5948

17 Apr 2026 07:15PM UTC coverage: 49.529% (-0.008%) from 49.537%
#5948

push

travis-ci

web-flow
change how we copy labels to importer pod (#4091)

when we are using populators, instead of copying
labels from target pvc -> prime pvc -> pod, skip
copying to prime and instead get the labels from
target pvc by using the prime pvc's owner ref.

convert functional test for this to unit test.

Signed-off-by: dsanatar <dsanatar@redhat.com>

8 of 12 new or added lines in 1 file covered. (66.67%)

7 existing lines in 1 file now uncovered.

14924 of 30132 relevant lines covered (49.53%)

0.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

70.8
/pkg/controller/import-controller.go
1
package controller
2

3
import (
4
        "context"
5
        "fmt"
6
        "net/url"
7
        "path"
8
        "reflect"
9
        "strconv"
10
        "strings"
11
        "time"
12

13
        "github.com/go-logr/logr"
14
        "github.com/pkg/errors"
15

16
        corev1 "k8s.io/api/core/v1"
17
        v1 "k8s.io/api/core/v1"
18
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
19
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20
        "k8s.io/apimachinery/pkg/runtime"
21
        "k8s.io/apimachinery/pkg/types"
22
        "k8s.io/apimachinery/pkg/util/sets"
23
        "k8s.io/client-go/tools/record"
24
        "k8s.io/utils/ptr"
25

26
        "sigs.k8s.io/controller-runtime/pkg/client"
27
        "sigs.k8s.io/controller-runtime/pkg/controller"
28
        "sigs.k8s.io/controller-runtime/pkg/handler"
29
        "sigs.k8s.io/controller-runtime/pkg/manager"
30
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
31
        "sigs.k8s.io/controller-runtime/pkg/source"
32

33
        cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
34
        "kubevirt.io/containerized-data-importer/pkg/common"
35
        cc "kubevirt.io/containerized-data-importer/pkg/controller/common"
36
        featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates"
37
        "kubevirt.io/containerized-data-importer/pkg/util"
38
        "kubevirt.io/containerized-data-importer/pkg/util/naming"
39
        sdkapi "kubevirt.io/controller-lifecycle-operator-sdk/api"
40
)
41

42
const (
43
        // ErrImportFailedPVC provides a const to indicate an import to the PVC failed
44
        ErrImportFailedPVC = "ErrImportFailed"
45
        // ImportSucceededPVC provides a const to indicate an import to the PVC failed
46
        ImportSucceededPVC = "ImportSucceeded"
47

48
        // creatingScratch provides a const to indicate scratch is being created.
49
        creatingScratch = "CreatingScratchSpace"
50

51
        // ImportTargetInUse is reason for event created when an import pvc is in use
52
        ImportTargetInUse = "ImportTargetInUse"
53

54
        // importPodImageStreamFinalizer ensures image stream import pod is deleted when pvc is deleted,
55
        // as in this case pod has no pvc OwnerReference
56
        importPodImageStreamFinalizer = "cdi.kubevirt.io/importImageStream"
57

58
        // secretExtraHeadersVolumeName is the format string that specifies where extra HTTP header secrets will be mounted
59
        secretExtraHeadersVolumeName = "cdi-secret-extra-headers-vol-%d"
60
)
61

62
// ImportReconciler members
63
type ImportReconciler struct {
64
        client             client.Client
65
        uncachedClient     client.Client
66
        recorder           record.EventRecorder
67
        scheme             *runtime.Scheme
68
        log                logr.Logger
69
        image              string
70
        verbose            string
71
        pullPolicy         string
72
        filesystemOverhead string //nolint:unused // TODO: check if need to remove this field
73
        cdiNamespace       string
74
        featureGates       featuregates.FeatureGates
75
        installerLabels    map[string]string
76
}
77

78
type importPodEnvVar struct {
79
        ep                        string
80
        secretName                string
81
        source                    string
82
        contentType               string
83
        imageSize                 string
84
        certConfigMap             string
85
        diskID                    string
86
        uuid                      string
87
        pullMethod                string
88
        readyFile                 string
89
        doneFile                  string
90
        backingFile               string
91
        thumbprint                string
92
        filesystemOverhead        string
93
        insecureTLS               bool
94
        currentCheckpoint         string
95
        previousCheckpoint        string
96
        finalCheckpoint           string
97
        preallocation             bool
98
        httpProxy                 string
99
        httpsProxy                string
100
        noProxy                   string
101
        certConfigMapProxy        string
102
        extraHeaders              []string
103
        secretExtraHeaders        []string
104
        cacheMode                 string
105
        registryImageArchitecture string
106
        checksum                  string
107
}
108

109
type importerPodArgs struct {
110
        image                   string
111
        importImage             string
112
        verbose                 string
113
        pullPolicy              string
114
        podEnvVar               *importPodEnvVar
115
        pvc                     *corev1.PersistentVolumeClaim
116
        scratchPvcName          *string
117
        podResourceRequirements *corev1.ResourceRequirements
118
        imagePullSecrets        []corev1.LocalObjectReference
119
        workloadNodePlacement   *sdkapi.NodePlacement
120
        vddkImageName           *string
121
        vddkExtraArgs           *string
122
        priorityClassName       string
123
        serviceAccountName      string
124
}
125

126
// NewImportController creates a new instance of the import controller.
127
func NewImportController(mgr manager.Manager, log logr.Logger, importerImage, pullPolicy, verbose string, installerLabels map[string]string) (controller.Controller, error) {
×
128
        uncachedClient, err := client.New(mgr.GetConfig(), client.Options{
×
129
                Scheme: mgr.GetScheme(),
×
130
                Mapper: mgr.GetRESTMapper(),
×
131
        })
×
132
        if err != nil {
×
133
                return nil, err
×
134
        }
×
135
        client := mgr.GetClient()
×
136
        reconciler := &ImportReconciler{
×
137
                client:          client,
×
138
                uncachedClient:  uncachedClient,
×
139
                scheme:          mgr.GetScheme(),
×
140
                log:             log.WithName("import-controller"),
×
141
                image:           importerImage,
×
142
                verbose:         verbose,
×
143
                pullPolicy:      pullPolicy,
×
144
                recorder:        mgr.GetEventRecorderFor("import-controller"),
×
145
                cdiNamespace:    util.GetNamespace(),
×
146
                featureGates:    featuregates.NewFeatureGates(client),
×
147
                installerLabels: installerLabels,
×
148
        }
×
149
        importController, err := controller.New("import-controller", mgr, controller.Options{
×
150
                MaxConcurrentReconciles: 3,
×
151
                Reconciler:              reconciler,
×
152
        })
×
153
        if err != nil {
×
154
                return nil, err
×
155
        }
×
156
        if err := addImportControllerWatches(mgr, importController); err != nil {
×
157
                return nil, err
×
158
        }
×
159
        return importController, nil
×
160
}
161

162
func addImportControllerWatches(mgr manager.Manager, importController controller.Controller) error {
×
163
        // Setup watches
×
164
        if err := importController.Watch(source.Kind(mgr.GetCache(), &corev1.PersistentVolumeClaim{}, &handler.TypedEnqueueRequestForObject[*corev1.PersistentVolumeClaim]{})); err != nil {
×
165
                return err
×
166
        }
×
167
        if err := importController.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}, handler.TypedEnqueueRequestForOwner[*corev1.Pod](
×
168
                mgr.GetScheme(), mgr.GetClient().RESTMapper(), &corev1.PersistentVolumeClaim{}, handler.OnlyControllerOwner()))); err != nil {
×
169
                return err
×
170
        }
×
171

172
        return nil
×
173
}
174

175
func (r *ImportReconciler) shouldReconcilePVC(pvc *corev1.PersistentVolumeClaim,
176
        log logr.Logger) (bool, error) {
1✔
177
        _, pvcUsesExternalPopulator := pvc.Annotations[cc.AnnExternalPopulation]
1✔
178
        if pvcUsesExternalPopulator {
1✔
179
                return false, nil
×
180
        }
×
181

182
        waitForFirstConsumerEnabled, err := cc.IsWaitForFirstConsumerEnabled(pvc, r.featureGates)
1✔
183
        if err != nil {
1✔
184
                return false, err
×
185
        }
×
186

187
        return (!cc.IsPVCComplete(pvc) || cc.IsMultiStageImportInProgress(pvc)) &&
1✔
188
                        (checkPVC(pvc, cc.AnnEndpoint, log) || checkPVC(pvc, cc.AnnSource, log)) &&
1✔
189
                        shouldHandlePvc(pvc, waitForFirstConsumerEnabled, log),
1✔
190
                nil
1✔
191
}
192

193
// Reconcile the reconcile loop for the CDIConfig object.
194
func (r *ImportReconciler) Reconcile(_ context.Context, req reconcile.Request) (reconcile.Result, error) {
1✔
195
        log := r.log.WithValues("PVC", req.NamespacedName)
1✔
196
        log.V(1).Info("reconciling Import PVCs")
1✔
197

1✔
198
        // Get the PVC.
1✔
199
        pvc := &corev1.PersistentVolumeClaim{}
1✔
200
        if err := r.client.Get(context.TODO(), req.NamespacedName, pvc); err != nil {
2✔
201
                if k8serrors.IsNotFound(err) {
2✔
202
                        return reconcile.Result{}, nil
1✔
203
                }
1✔
204
                return reconcile.Result{}, err
×
205
        }
206

207
        // only want to update bound condition for relevant type
208
        if checkPVC(pvc, cc.AnnEndpoint, log) || checkPVC(pvc, cc.AnnSource, log) {
2✔
209
                if err := cc.UpdatePVCBoundContionFromEvents(pvc, r.client, log); err != nil {
1✔
210
                        return reconcile.Result{}, err
×
211
                }
×
212
        }
213

214
        shouldReconcile, err := r.shouldReconcilePVC(pvc, log)
1✔
215
        if err != nil {
1✔
216
                return reconcile.Result{}, err
×
217
        }
×
218
        if !shouldReconcile {
2✔
219
                multiStageImport := metav1.HasAnnotation(pvc.ObjectMeta, cc.AnnCurrentCheckpoint)
1✔
220
                multiStageAlreadyDone := metav1.HasAnnotation(pvc.ObjectMeta, cc.AnnMultiStageImportDone)
1✔
221

1✔
222
                log.V(3).Info("Should not reconcile this PVC",
1✔
223
                        "pvc.annotation.phase.complete", cc.IsPVCComplete(pvc),
1✔
224
                        "pvc.annotations.endpoint", checkPVC(pvc, cc.AnnEndpoint, log),
1✔
225
                        "pvc.annotations.source", checkPVC(pvc, cc.AnnSource, log),
1✔
226
                        "isBound", isBound(pvc, log), "isMultistage", multiStageImport, "multiStageDone", multiStageAlreadyDone)
1✔
227
                return reconcile.Result{}, nil
1✔
228
        }
1✔
229

230
        return r.reconcilePvc(pvc, log)
1✔
231
}
232

233
func (r *ImportReconciler) findImporterPod(pvc *corev1.PersistentVolumeClaim, log logr.Logger) (*corev1.Pod, error) {
1✔
234
        podName := getImportPodNameFromPvc(pvc)
1✔
235
        pod := &corev1.Pod{}
1✔
236
        if err := r.client.Get(context.TODO(), types.NamespacedName{Name: podName, Namespace: pvc.GetNamespace()}, pod); err != nil {
2✔
237
                if !k8serrors.IsNotFound(err) {
1✔
238
                        return nil, errors.Wrapf(err, "error getting import pod %s/%s", pvc.Namespace, podName)
×
239
                }
×
240
                return nil, nil
1✔
241
        }
242
        if !metav1.IsControlledBy(pod, pvc) && !cc.IsImageStream(pvc) {
2✔
243
                return nil, errors.Errorf("Pod is not owned by PVC")
1✔
244
        }
1✔
245
        log.V(1).Info("Pod is owned by PVC", pod.Name, pvc.Name)
1✔
246
        return pod, nil
1✔
247
}
248

249
func (r *ImportReconciler) reconcilePvc(pvc *corev1.PersistentVolumeClaim, log logr.Logger) (reconcile.Result, error) {
1✔
250
        // See if we have a pod associated with the PVC, we know the PVC has the needed annotations.
1✔
251
        pod, err := r.findImporterPod(pvc, log)
1✔
252
        if err != nil {
2✔
253
                return reconcile.Result{}, err
1✔
254
        }
1✔
255

256
        if pod == nil {
2✔
257
                if cc.IsPVCComplete(pvc) {
1✔
258
                        // Don't create the POD if the PVC is completed already
×
259
                        log.V(1).Info("PVC is already complete")
×
260
                } else if pvc.Annotations[cc.AnnImportFatalError] == "true" {
1✔
261
                        // Don't create the POD if there was a fatal error (e.g., checksum mismatch)
×
262
                        log.V(1).Info("PVC has fatal error annotation, will not create pod")
×
263
                } else if pvc.DeletionTimestamp == nil {
2✔
264
                        podsUsingPVC, err := cc.GetPodsUsingPVCs(context.TODO(), r.client, pvc.Namespace, sets.New(pvc.Name), false)
1✔
265
                        if err != nil {
1✔
266
                                return reconcile.Result{}, err
×
267
                        }
×
268

269
                        if len(podsUsingPVC) > 0 {
2✔
270
                                for _, pod := range podsUsingPVC {
2✔
271
                                        r.log.V(1).Info("can't create import pod, pvc in use by other pod",
1✔
272
                                                "namespace", pvc.Namespace, "name", pvc.Name, "pod", pod.Name)
1✔
273
                                        r.recorder.Eventf(pvc, corev1.EventTypeWarning, ImportTargetInUse,
1✔
274
                                                "pod %s/%s using PersistentVolumeClaim %s", pod.Namespace, pod.Name, pvc.Name)
1✔
275
                                }
1✔
276
                                return reconcile.Result{Requeue: true}, nil
1✔
277
                        }
278

279
                        if _, ok := pvc.Annotations[cc.AnnImportPod]; ok {
2✔
280
                                // Create importer pod, make sure the PVC owns it.
1✔
281
                                if err := r.createImporterPod(pvc); err != nil {
1✔
282
                                        return reconcile.Result{}, err
×
283
                                }
×
284
                        } else {
1✔
285
                                // Create importer pod Name and store in PVC?
1✔
286
                                if err := r.initPvcPodName(pvc, log); err != nil {
1✔
287
                                        return reconcile.Result{}, err
×
288
                                }
×
289
                        }
290
                }
291
        } else {
1✔
292
                if pvc.DeletionTimestamp != nil {
1✔
293
                        log.V(1).Info("PVC being terminated, delete pods", "pod.Name", pod.Name)
×
294
                        if err := r.cleanup(pvc, pod, log); err != nil {
×
295
                                return reconcile.Result{}, err
×
296
                        }
×
297
                } else {
1✔
298
                        // Copy import proxy ConfigMap (if exists) from cdi namespace to the import namespace
1✔
299
                        if err := r.copyImportProxyConfigMap(pvc, pod); err != nil {
1✔
300
                                return reconcile.Result{}, err
×
301
                        }
×
302
                        // Pod exists, we need to update the PVC status.
303
                        if err := r.updatePvcFromPod(pvc, pod, log); err != nil {
1✔
304
                                return reconcile.Result{}, err
×
305
                        }
×
306
                }
307
        }
308

309
        if !cc.IsPVCComplete(pvc) {
2✔
310
                // We are not done yet, force a re-reconcile in 2 seconds to get an update.
1✔
311
                log.V(1).Info("Force Reconcile pvc import not finished", "pvc.Name", pvc.Name)
1✔
312

1✔
313
                return reconcile.Result{RequeueAfter: 2 * time.Second}, nil
1✔
314
        }
1✔
315
        return reconcile.Result{}, nil
1✔
316
}
317

318
func (r *ImportReconciler) copyImportProxyConfigMap(pvc *corev1.PersistentVolumeClaim, pod *corev1.Pod) error {
1✔
319
        cdiConfig := &cdiv1.CDIConfig{}
1✔
320
        if err := r.client.Get(context.TODO(), types.NamespacedName{Name: common.ConfigName}, cdiConfig); err != nil {
1✔
321
                return err
×
322
        }
×
323
        cmName, err := GetImportProxyConfig(cdiConfig, common.ImportProxyConfigMapName)
1✔
324
        if err != nil || cmName == "" {
2✔
325
                return nil
1✔
326
        }
1✔
327
        cdiConfigMap := &corev1.ConfigMap{}
×
328
        if err := r.uncachedClient.Get(context.TODO(), types.NamespacedName{Name: cmName, Namespace: r.cdiNamespace}, cdiConfigMap); err != nil {
×
329
                return err
×
330
        }
×
331
        importConfigMap := &corev1.ConfigMap{
×
332
                ObjectMeta: metav1.ObjectMeta{
×
333
                        Name:      GetImportProxyConfigMapName(pvc.Name),
×
334
                        Namespace: pvc.Namespace,
×
335
                        OwnerReferences: []metav1.OwnerReference{{
×
336
                                APIVersion:         pod.APIVersion,
×
337
                                Kind:               pod.Kind,
×
338
                                Name:               pod.Name,
×
339
                                UID:                pod.UID,
×
340
                                BlockOwnerDeletion: ptr.To[bool](true),
×
341
                                Controller:         ptr.To[bool](true),
×
342
                        }},
×
343
                },
×
344
                Data: cdiConfigMap.Data,
×
345
        }
×
346
        if err := r.client.Create(context.TODO(), importConfigMap); err != nil && !k8serrors.IsAlreadyExists(err) {
×
347
                return err
×
348
        }
×
349
        return nil
×
350
}
351

352
// GetImportProxyConfigMapName returns the import proxy ConfigMap name
353
func GetImportProxyConfigMapName(pvcName string) string {
×
354
        return naming.GetResourceName("import-proxy-cm", pvcName)
×
355
}
×
356

357
func (r *ImportReconciler) initPvcPodName(pvc *corev1.PersistentVolumeClaim, log logr.Logger) error {
1✔
358
        currentPvcCopy := pvc.DeepCopyObject()
1✔
359

1✔
360
        log.V(1).Info("Init pod name on PVC")
1✔
361
        anno := pvc.GetAnnotations()
1✔
362

1✔
363
        anno[cc.AnnImportPod] = createImportPodNameFromPvc(pvc)
1✔
364

1✔
365
        requiresScratch := r.requiresScratchSpace(pvc)
1✔
366
        if requiresScratch {
1✔
367
                anno[cc.AnnRequiresScratch] = "true"
×
368
        }
×
369

370
        if !reflect.DeepEqual(currentPvcCopy, pvc) {
2✔
371
                if err := r.updatePVC(pvc, log); err != nil {
1✔
372
                        return err
×
373
                }
×
374
                log.V(1).Info("Updated PVC", "pvc.anno.AnnImportPod", anno[cc.AnnImportPod])
1✔
375
        }
376
        return nil
1✔
377
}
378

379
func (r *ImportReconciler) updatePvcFromPod(pvc *corev1.PersistentVolumeClaim, pod *corev1.Pod, log logr.Logger) error {
1✔
380
        // Keep a copy of the original for comparison later.
1✔
381
        currentPvcCopy := pvc.DeepCopyObject()
1✔
382

1✔
383
        log.V(1).Info("Updating PVC from pod")
1✔
384
        anno := pvc.GetAnnotations()
1✔
385

1✔
386
        termMsg, err := parseTerminationMessage(pod)
1✔
387
        if err != nil {
2✔
388
                log.V(3).Info("Ignoring failure to parse termination message", "error", err.Error())
1✔
389
        }
1✔
390
        setAnnotationsFromPodWithPrefix(anno, pod, termMsg, cc.AnnRunningCondition)
1✔
391

1✔
392
        // Handle fatal errors reported via termination message even when the container exited with code 0.
1✔
393
        // In this branch we intentionally override the actual Pod phase (Succeeded) and mark the PVC as Failed + fatal
1✔
394
        // to stop retries; this keeps DV status aligned with the fatal outcome rather than the Pod phase.
1✔
395
        // Check for "checksum mismatch" which is the error message from ErrChecksumMismatch.
1✔
396
        if termMsg != nil && termMsg.Message != nil && strings.Contains(*termMsg.Message, "checksum mismatch") {
1✔
397
                log.Info("Checksum validation failed via termination message (permanent error, will not retry)", "pod.Name", pod.Name)
×
398
                anno[cc.AnnPodPhase] = string(corev1.PodFailed) // override Succeeded to reflect fatal state
×
399
                anno[cc.AnnImportFatalError] = "true"
×
400
                anno[cc.AnnRunningCondition] = "false"
×
401
                if anno[cc.AnnRunningConditionMessage] == "" {
×
402
                        anno[cc.AnnRunningConditionMessage] = simplifyKnownMessage(*termMsg.Message)
×
403
                }
×
404
                anno[cc.AnnRunningConditionReason] = "ChecksumError"
×
405
                r.recorder.Event(pvc, corev1.EventTypeWarning, ErrImportFailedPVC, simplifyKnownMessage(*termMsg.Message))
×
406
        }
407

408
        scratchSpaceRequired := termMsg != nil && termMsg.ScratchSpaceRequired != nil && *termMsg.ScratchSpaceRequired
1✔
409
        if scratchSpaceRequired {
2✔
410
                log.V(1).Info("Pod requires scratch space, terminating pod, and restarting with scratch space", "pod.Name", pod.Name)
1✔
411
        }
1✔
412
        podModificationsNeeded := scratchSpaceRequired
1✔
413

1✔
414
        if statuses := pod.Status.ContainerStatuses; len(statuses) > 0 {
2✔
415
                if isOOMKilled(statuses[0]) {
2✔
416
                        log.V(1).Info("Pod died of an OOM, deleting pod, and restarting with qemu cache mode=none if storage supports it", "pod.Name", pod.Name)
1✔
417
                        podModificationsNeeded = true
1✔
418
                        anno[cc.AnnRequiresDirectIO] = "true"
1✔
419
                }
1✔
420

421
                if terminated := statuses[0].State.Terminated; terminated != nil && terminated.ExitCode > 0 {
2✔
422
                        log.Info("Pod termination code", "pod.Name", pod.Name, "ExitCode", terminated.ExitCode)
1✔
423
                        r.recorder.Event(pvc, corev1.EventTypeWarning, ErrImportFailedPVC, terminated.Message)
1✔
424
                }
1✔
425
        }
426

427
        if anno[cc.AnnCurrentCheckpoint] != "" {
1✔
428
                anno[cc.AnnCurrentPodID] = string(pod.ObjectMeta.UID)
×
429
        }
×
430

431
        anno[cc.AnnImportPod] = pod.Name
1✔
432
        if !podModificationsNeeded && anno[cc.AnnImportFatalError] != "true" {
2✔
433
                // No scratch space required, update the phase based on the pod. If we require scratch space we don't want to update the
1✔
434
                // phase, because the pod might terminate cleanly and mistakenly mark the import complete.
1✔
435
                anno[cc.AnnPodPhase] = string(pod.Status.Phase)
1✔
436
        }
1✔
437

438
        anno[cc.AnnPodSchedulable] = "true"
1✔
439
        if phase, ok := anno[cc.AnnPodPhase]; ok && phase == string(corev1.PodPending) {
2✔
440
                for _, cond := range pod.Status.Conditions {
1✔
441
                        if cond.Type == corev1.PodScheduled && cond.Reason == corev1.PodReasonUnschedulable {
×
442
                                anno[cc.AnnPodSchedulable] = "false"
×
443
                                break
×
444
                        }
445
                }
446
        }
447

448
        for _, ev := range pod.Spec.Containers[0].Env {
2✔
449
                if ev.Name == common.CacheMode && ev.Value == common.CacheModeTryNone {
1✔
450
                        anno[cc.AnnRequiresDirectIO] = "false"
×
451
                }
×
452
        }
453

454
        // Check if the POD is waiting for scratch space, if so create some.
455
        if pod.Status.Phase == corev1.PodPending && r.requiresScratchSpace(pvc) {
2✔
456
                if err := r.createScratchPvcForPod(pvc, pod); err != nil {
1✔
457
                        if !k8serrors.IsAlreadyExists(err) {
×
458
                                return err
×
459
                        }
×
460
                }
461
        } else {
1✔
462
                // No scratch space, or scratch space is bound, remove annotation
1✔
463
                delete(anno, cc.AnnBoundCondition)
1✔
464
                delete(anno, cc.AnnBoundConditionMessage)
1✔
465
                delete(anno, cc.AnnBoundConditionReason)
1✔
466
        }
1✔
467

468
        if pvc.GetLabels() == nil {
2✔
469
                pvc.SetLabels(make(map[string]string, 0))
1✔
470
        }
1✔
471
        if !checkIfLabelExists(pvc, common.CDILabelKey, common.CDILabelValue) {
2✔
472
                pvc.GetLabels()[common.CDILabelKey] = common.CDILabelValue
1✔
473
        }
1✔
474
        if cc.IsPVCComplete(pvc) {
2✔
475
                pvc.SetLabels(addLabelsFromTerminationMessage(pvc.GetLabels(), termMsg))
1✔
476
        }
1✔
477

478
        if !reflect.DeepEqual(currentPvcCopy, pvc) {
2✔
479
                if err := r.updatePVC(pvc, log); err != nil {
1✔
480
                        return err
×
481
                }
×
482
                log.V(1).Info("Updated PVC", "pvc.anno.Phase", anno[cc.AnnPodPhase], "pvc.anno.Restarts", anno[cc.AnnPodRestarts])
1✔
483
        }
484

485
        // If fatal error detected, delete pod immediately to stop K8s restart loop
486
        if anno[cc.AnnImportFatalError] == "true" {
1✔
487
                log.V(1).Info("Deleting pod due to fatal error", "pod.Name", pod.Name)
×
488
                if err := r.cleanup(pvc, pod, log); err != nil {
×
489
                        return err
×
490
                }
×
491
                return nil
×
492
        }
493

494
        if cc.IsPVCComplete(pvc) || podModificationsNeeded {
2✔
495
                if !podModificationsNeeded {
2✔
496
                        r.recorder.Event(pvc, corev1.EventTypeNormal, ImportSucceededPVC, "Import Successful")
1✔
497
                        log.V(1).Info("Import completed successfully")
1✔
498
                }
1✔
499
                if cc.ShouldDeletePod(pvc) {
2✔
500
                        log.V(1).Info("Deleting pod", "pod.Name", pod.Name)
1✔
501
                        if err := r.cleanup(pvc, pod, log); err != nil {
1✔
502
                                return err
×
503
                        }
×
504
                }
505
        }
506
        return nil
1✔
507
}
508

509
func (r *ImportReconciler) cleanup(pvc *corev1.PersistentVolumeClaim, pod *corev1.Pod, log logr.Logger) error {
1✔
510
        if err := r.client.Delete(context.TODO(), pod); cc.IgnoreNotFound(err) != nil {
1✔
511
                return err
×
512
        }
×
513
        if cc.HasFinalizer(pvc, importPodImageStreamFinalizer) {
1✔
514
                cc.RemoveFinalizer(pvc, importPodImageStreamFinalizer)
×
515
                if err := r.updatePVC(pvc, log); err != nil {
×
516
                        return err
×
517
                }
×
518
        }
519
        return nil
1✔
520
}
521

522
func (r *ImportReconciler) updatePVC(pvc *corev1.PersistentVolumeClaim, log logr.Logger) error {
1✔
523
        if err := r.client.Update(context.TODO(), pvc); err != nil {
1✔
524
                return err
×
525
        }
×
526
        return nil
1✔
527
}
528

529
func (r *ImportReconciler) createImporterPod(pvc *corev1.PersistentVolumeClaim) error {
1✔
530
        r.log.V(1).Info("Creating importer POD for PVC", "pvc.Name", pvc.Name)
1✔
531
        var scratchPvcName *string
1✔
532
        var vddkImageName *string
1✔
533
        var vddkExtraArgs *string
1✔
534
        var err error
1✔
535

1✔
536
        requiresScratch := r.requiresScratchSpace(pvc)
1✔
537
        if requiresScratch {
1✔
538
                name := createScratchNameFromPvc(pvc)
×
539
                scratchPvcName = &name
×
540
        }
×
541

542
        if cc.GetSource(pvc) == cc.SourceVDDK {
2✔
543
                r.log.V(1).Info("Pod requires VDDK sidecar for VMware transfer")
1✔
544
                anno := pvc.GetAnnotations()
1✔
545
                if imageName, ok := anno[cc.AnnVddkInitImageURL]; ok {
2✔
546
                        vddkImageName = &imageName
1✔
547
                } else {
2✔
548
                        if vddkImageName, err = r.getVddkImageName(); err != nil {
2✔
549
                                r.log.V(1).Error(err, "failed to get VDDK image name from configmap")
1✔
550
                        }
1✔
551
                }
552
                if vddkImageName == nil {
2✔
553
                        message := fmt.Sprintf("waiting for %s configmap or %s annotation for VDDK image", common.VddkConfigMap, cc.AnnVddkInitImageURL)
1✔
554
                        anno[cc.AnnBoundCondition] = "false"
1✔
555
                        anno[cc.AnnBoundConditionMessage] = message
1✔
556
                        anno[cc.AnnBoundConditionReason] = common.AwaitingVDDK
1✔
557
                        if err := r.updatePVC(pvc, r.log); err != nil {
1✔
558
                                return err
×
559
                        }
×
560
                        return errors.New(message)
1✔
561
                }
562

563
                if extraArgs, ok := anno[cc.AnnVddkExtraArgs]; ok && extraArgs != "" {
2✔
564
                        r.log.V(1).Info("Mounting extra VDDK args ConfigMap to importer pod", "ConfigMap", extraArgs)
1✔
565
                        vddkExtraArgs = &extraArgs
1✔
566
                }
1✔
567
        }
568

569
        podEnvVar, err := r.createImportEnvVar(pvc)
1✔
570
        if err != nil {
1✔
571
                return err
×
572
        }
×
573
        // all checks passed, let's create the importer pod!
574
        podArgs := &importerPodArgs{
1✔
575
                image:              r.image,
1✔
576
                verbose:            r.verbose,
1✔
577
                pullPolicy:         r.pullPolicy,
1✔
578
                podEnvVar:          podEnvVar,
1✔
579
                pvc:                pvc,
1✔
580
                scratchPvcName:     scratchPvcName,
1✔
581
                vddkImageName:      vddkImageName,
1✔
582
                vddkExtraArgs:      vddkExtraArgs,
1✔
583
                priorityClassName:  cc.GetPriorityClass(pvc),
1✔
584
                serviceAccountName: cc.GetPodServiceAccount(pvc),
1✔
585
        }
1✔
586

1✔
587
        pod, err := createImporterPod(context.TODO(), r.log, r.client, podArgs, r.installerLabels)
1✔
588
        // Check if pod has failed and, in that case, record an event with the error
1✔
589
        if podErr := cc.HandleFailedPod(err, pvc.Annotations[cc.AnnImportPod], pvc, r.recorder, r.client); podErr != nil {
1✔
590
                return podErr
×
591
        }
×
592

593
        r.log.V(1).Info("Created POD", "pod.Name", pod.Name)
1✔
594

1✔
595
        // If importing from image stream, add finalizer. Note we don't watch the importer pod in this case,
1✔
596
        // so to prevent a deadlock we add finalizer only if the pod is not retained after completion.
1✔
597
        if cc.IsImageStream(pvc) && pvc.GetAnnotations()[cc.AnnPodRetainAfterCompletion] != "true" {
1✔
598
                cc.AddFinalizer(pvc, importPodImageStreamFinalizer)
×
599
                if err := r.updatePVC(pvc, r.log); err != nil {
×
600
                        return err
×
601
                }
×
602
        }
603

604
        if requiresScratch {
1✔
605
                r.log.V(1).Info("Pod requires scratch space")
×
606
                return r.createScratchPvcForPod(pvc, pod)
×
607
        }
×
608

609
        return nil
1✔
610
}
611

612
func createScratchNameFromPvc(pvc *v1.PersistentVolumeClaim) string {
×
613
        return naming.GetResourceName(pvc.Name, common.ScratchNameSuffix)
×
614
}
×
615

616
func (r *ImportReconciler) createImportEnvVar(pvc *corev1.PersistentVolumeClaim) (*importPodEnvVar, error) {
1✔
617
        podEnvVar := &importPodEnvVar{}
1✔
618
        podEnvVar.source = cc.GetSource(pvc)
1✔
619
        podEnvVar.contentType = string(cc.GetPVCContentType(pvc))
1✔
620

1✔
621
        var err error
1✔
622
        if podEnvVar.source != cc.SourceNone {
2✔
623
                podEnvVar.ep, err = cc.GetEndpoint(pvc)
1✔
624
                if err != nil {
1✔
625
                        return nil, err
×
626
                }
×
627
                podEnvVar.secretName = r.getSecretName(pvc)
1✔
628
                if podEnvVar.secretName == "" {
2✔
629
                        r.log.V(2).Info("no secret will be supplied to endpoint", "endPoint", podEnvVar.ep)
1✔
630
                }
1✔
631
                //get the CDIConfig to extract the proxy configuration to be used to import an image
632
                cdiConfig := &cdiv1.CDIConfig{}
1✔
633
                err = r.client.Get(context.TODO(), types.NamespacedName{Name: common.ConfigName}, cdiConfig)
1✔
634
                if err != nil {
1✔
635
                        return nil, err
×
636
                }
×
637
                podEnvVar.certConfigMap, err = r.getCertConfigMap(pvc)
1✔
638
                if err != nil {
1✔
639
                        return nil, err
×
640
                }
×
641
                podEnvVar.insecureTLS, err = r.isInsecureTLS(pvc, cdiConfig)
1✔
642
                if err != nil {
1✔
643
                        return nil, err
×
644
                }
×
645
                podEnvVar.diskID = getValueFromAnnotation(pvc, cc.AnnDiskID)
1✔
646
                podEnvVar.backingFile = getValueFromAnnotation(pvc, cc.AnnBackingFile)
1✔
647
                podEnvVar.uuid = getValueFromAnnotation(pvc, cc.AnnUUID)
1✔
648
                podEnvVar.thumbprint = getValueFromAnnotation(pvc, cc.AnnThumbprint)
1✔
649
                podEnvVar.previousCheckpoint = getValueFromAnnotation(pvc, cc.AnnPreviousCheckpoint)
1✔
650
                podEnvVar.currentCheckpoint = getValueFromAnnotation(pvc, cc.AnnCurrentCheckpoint)
1✔
651
                podEnvVar.finalCheckpoint = getValueFromAnnotation(pvc, cc.AnnFinalCheckpoint)
1✔
652
                podEnvVar.registryImageArchitecture = getValueFromAnnotation(pvc, cc.AnnRegistryImageArchitecture)
1✔
653
                podEnvVar.checksum = getValueFromAnnotation(pvc, cc.AnnChecksum)
1✔
654

1✔
655
                for annotation, value := range pvc.Annotations {
2✔
656
                        if strings.HasPrefix(annotation, cc.AnnExtraHeaders) {
1✔
657
                                podEnvVar.extraHeaders = append(podEnvVar.extraHeaders, value)
×
658
                        }
×
659
                        if strings.HasPrefix(annotation, cc.AnnSecretExtraHeaders) {
1✔
660
                                podEnvVar.secretExtraHeaders = append(podEnvVar.secretExtraHeaders, value)
×
661
                        }
×
662
                }
663

664
                var field string
1✔
665
                if field, err = GetImportProxyConfig(cdiConfig, common.ImportProxyHTTP); err != nil {
2✔
666
                        r.log.V(3).Info("no proxy http url will be supplied:", "error", err.Error())
1✔
667
                }
1✔
668
                podEnvVar.httpProxy = field
1✔
669
                if field, err = GetImportProxyConfig(cdiConfig, common.ImportProxyHTTPS); err != nil {
2✔
670
                        r.log.V(3).Info("no proxy https url will be supplied:", "error", err.Error())
1✔
671
                }
1✔
672
                podEnvVar.httpsProxy = field
1✔
673
                if field, err = GetImportProxyConfig(cdiConfig, common.ImportProxyNoProxy); err != nil {
2✔
674
                        r.log.V(3).Info("the noProxy field will not be supplied:", "error", err.Error())
1✔
675
                }
1✔
676
                podEnvVar.noProxy = field
1✔
677
                if field, err = GetImportProxyConfig(cdiConfig, common.ImportProxyConfigMapName); err != nil {
2✔
678
                        r.log.V(3).Info("no proxy CA certiticate will be supplied:", "error", err.Error())
1✔
679
                }
1✔
680
                podEnvVar.certConfigMapProxy = field
1✔
681
        }
682

683
        fsOverhead, err := GetFilesystemOverhead(context.TODO(), r.client, pvc)
1✔
684
        if err != nil {
1✔
685
                return nil, err
×
686
        }
×
687
        podEnvVar.filesystemOverhead = string(fsOverhead)
1✔
688

1✔
689
        if preallocation, err := strconv.ParseBool(getValueFromAnnotation(pvc, cc.AnnPreallocationRequested)); err == nil {
1✔
690
                podEnvVar.preallocation = preallocation
×
691
        } // else use the default "false"
×
692

693
        //get the requested image size.
694
        podEnvVar.imageSize, err = cc.GetRequestedImageSize(pvc)
1✔
695
        if err != nil {
1✔
696
                return nil, err
×
697
        }
×
698

699
        if v, ok := pvc.Annotations[cc.AnnRequiresDirectIO]; ok && v == "true" {
2✔
700
                podEnvVar.cacheMode = common.CacheModeTryNone
1✔
701
        }
1✔
702

703
        return podEnvVar, nil
1✔
704
}
705

706
func (r *ImportReconciler) isInsecureTLS(pvc *corev1.PersistentVolumeClaim, cdiConfig *cdiv1.CDIConfig) (bool, error) {
1✔
707
        // Check if insecureSkipVerify annotation is set (only applicable for ImageIO sources)
1✔
708
        source, sourceOk := pvc.Annotations[cc.AnnSource]
1✔
709
        if sourceOk && source == cc.SourceImageio {
1✔
710
                if insecureSkipVerify, ok := pvc.Annotations[cc.AnnInsecureSkipVerify]; ok && insecureSkipVerify == "true" {
×
711
                        return true, nil
×
712
                }
×
713
        }
714

715
        ep, ok := pvc.Annotations[cc.AnnEndpoint]
1✔
716
        if !ok || ep == "" {
2✔
717
                return false, nil
1✔
718
        }
1✔
719
        return IsInsecureTLS(ep, cdiConfig, r.log)
1✔
720
}
721

722
// IsInsecureTLS checks if TLS security is disabled for the given endpoint
723
func IsInsecureTLS(ep string, cdiConfig *cdiv1.CDIConfig, log logr.Logger) (bool, error) {
1✔
724
        url, err := url.Parse(ep)
1✔
725
        if err != nil {
1✔
726
                return false, err
×
727
        }
×
728

729
        if url.Scheme != "docker" {
2✔
730
                return false, nil
1✔
731
        }
1✔
732

733
        for _, value := range cdiConfig.Spec.InsecureRegistries {
2✔
734
                log.V(1).Info("Checking host against value", "host", url.Host, "value", value)
1✔
735
                if value == url.Host {
2✔
736
                        return true, nil
1✔
737
                }
1✔
738
        }
739
        return false, nil
1✔
740
}
741

742
func (r *ImportReconciler) getCertConfigMap(pvc *corev1.PersistentVolumeClaim) (string, error) {
1✔
743
        value, ok := pvc.Annotations[cc.AnnCertConfigMap]
1✔
744
        if !ok || value == "" {
2✔
745
                return "", nil
1✔
746
        }
1✔
747

748
        configMap := &corev1.ConfigMap{}
1✔
749
        if err := r.uncachedClient.Get(context.TODO(), types.NamespacedName{Name: value, Namespace: pvc.Namespace}, configMap); err != nil {
2✔
750
                if k8serrors.IsNotFound(err) {
2✔
751
                        r.log.V(1).Info("Configmap does not exist, pod will not start until it does", "configMapName", value)
1✔
752
                        return value, nil
1✔
753
                }
1✔
754

755
                return "", err
×
756
        }
757

758
        return value, nil
1✔
759
}
760

761
// returns the name of the secret containing endpoint credentials consumed by the importer pod.
762
// A value of "" implies there are no credentials for the endpoint being used. A returned error
763
// causes processNextItem() to stop.
764
func (r *ImportReconciler) getSecretName(pvc *corev1.PersistentVolumeClaim) string {
1✔
765
        ns := pvc.Namespace
1✔
766
        name, found := pvc.Annotations[cc.AnnSecret]
1✔
767
        if !found || name == "" {
2✔
768
                msg := "getEndpointSecret: "
1✔
769
                if !found {
2✔
770
                        msg += fmt.Sprintf("annotation %q is missing in pvc \"%s/%s\"", cc.AnnSecret, ns, pvc.Name)
1✔
771
                } else {
1✔
772
                        msg += fmt.Sprintf("secret name is missing from annotation %q in pvc \"%s/%s\"", cc.AnnSecret, ns, pvc.Name)
×
773
                }
×
774
                r.log.V(2).Info(msg)
1✔
775
                return "" // importer pod will not contain secret credentials
1✔
776
        }
777
        return name
1✔
778
}
779

780
func (r *ImportReconciler) requiresScratchSpace(pvc *corev1.PersistentVolumeClaim) bool {
1✔
781
        scratchRequired := false
1✔
782
        contentType := cc.GetPVCContentType(pvc)
1✔
783
        // All archive requires scratch space.
1✔
784
        if contentType == cdiv1.DataVolumeArchive {
1✔
785
                scratchRequired = true
×
786
        } else {
1✔
787
                switch cc.GetSource(pvc) {
1✔
788
                case cc.SourceGlance:
×
789
                        scratchRequired = true
×
790
                case cc.SourceImageio:
×
791
                        if val, ok := pvc.Annotations[cc.AnnCurrentCheckpoint]; ok {
×
792
                                scratchRequired = val != ""
×
793
                        }
×
794
                case cc.SourceRegistry:
1✔
795
                        scratchRequired = pvc.Annotations[cc.AnnRegistryImportMethod] != string(cdiv1.RegistryPullNode)
1✔
796
                }
797
        }
798
        value, ok := pvc.Annotations[cc.AnnRequiresScratch]
1✔
799
        if ok {
2✔
800
                boolVal, _ := strconv.ParseBool(value)
1✔
801
                scratchRequired = scratchRequired || boolVal
1✔
802
        }
1✔
803
        return scratchRequired
1✔
804
}
805

806
func (r *ImportReconciler) createScratchPvcForPod(pvc *corev1.PersistentVolumeClaim, pod *corev1.Pod) error {
1✔
807
        scratchPvc := &corev1.PersistentVolumeClaim{}
1✔
808
        scratchPVCName, exists := getScratchNameFromPod(pod)
1✔
809
        if !exists {
1✔
810
                return errors.New("Scratch Volume not configured for pod")
×
811
        }
×
812
        anno := pvc.GetAnnotations()
1✔
813
        err := r.client.Get(context.TODO(), types.NamespacedName{Namespace: pvc.GetNamespace(), Name: scratchPVCName}, scratchPvc)
1✔
814
        if cc.IgnoreNotFound(err) != nil {
1✔
815
                return err
×
816
        }
×
817
        if k8serrors.IsNotFound(err) {
2✔
818
                r.log.V(1).Info("Creating scratch space for POD and PVC", "pod.Name", pod.Name, "pvc.Name", pvc.Name)
1✔
819

1✔
820
                storageClassName := GetScratchPvcStorageClass(r.client, pvc)
1✔
821
                // Scratch PVC doesn't exist yet, create it. Determine which storage class to use.
1✔
822
                _, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, scratchPVCName, storageClassName, r.installerLabels, r.recorder)
1✔
823
                if err != nil {
1✔
824
                        return err
×
825
                }
×
826
                anno[cc.AnnBoundCondition] = "false"
1✔
827
                anno[cc.AnnBoundConditionMessage] = "Creating scratch space"
1✔
828
                anno[cc.AnnBoundConditionReason] = creatingScratch
1✔
829
        } else {
×
830
                if scratchPvc.DeletionTimestamp != nil {
×
831
                        // Delete the pod since we are in a deadlock situation now. The scratch PVC from the previous import is not gone
×
832
                        // yet but terminating, and the new pod is still being created and the scratch PVC now has a finalizer on it.
×
833
                        // Only way to break it, is to delete the importer pod, and give the pvc a chance to disappear.
×
834
                        err = r.client.Delete(context.TODO(), pod)
×
835
                        if err != nil {
×
836
                                return err
×
837
                        }
×
838
                        return fmt.Errorf("terminating scratch space found, deleting pod %s", pod.Name)
×
839
                }
840
        }
841
        anno[cc.AnnRequiresScratch] = "false"
1✔
842
        return nil
1✔
843
}
844

845
// Get path to VDDK image from 'v2v-vmware' ConfigMap
846
func (r *ImportReconciler) getVddkImageName() (*string, error) {
1✔
847
        namespace := util.GetNamespace()
1✔
848

1✔
849
        cm := &corev1.ConfigMap{}
1✔
850
        err := r.uncachedClient.Get(context.TODO(), types.NamespacedName{Name: common.VddkConfigMap, Namespace: namespace}, cm)
1✔
851
        if k8serrors.IsNotFound(err) {
2✔
852
                return nil, errors.Errorf("No %s ConfigMap present in namespace %s", common.VddkConfigMap, namespace)
1✔
853
        }
1✔
854

855
        image, found := cm.Data[common.VddkConfigDataKey]
1✔
856
        if found {
2✔
857
                msg := fmt.Sprintf("Found %s ConfigMap in namespace %s, VDDK image path is: ", common.VddkConfigMap, namespace)
1✔
858
                r.log.V(1).Info(msg, common.VddkConfigDataKey, image)
1✔
859
                return &image, nil
1✔
860
        }
1✔
861

862
        return nil, errors.Errorf("found %s ConfigMap in namespace %s, but it does not contain a '%s' entry", common.VddkConfigMap, namespace, common.VddkConfigDataKey)
×
863
}
864

865
// returns the import image part of the endpoint string
866
func getRegistryImportImage(pvc *corev1.PersistentVolumeClaim) (string, error) {
1✔
867
        ep, err := cc.GetEndpoint(pvc)
1✔
868
        if err != nil {
1✔
869
                return "", nil
×
870
        }
×
871
        if cc.IsImageStream(pvc) {
1✔
872
                return ep, nil
×
873
        }
×
874
        url, err := url.Parse(ep)
1✔
875
        if err != nil {
1✔
876
                return "", errors.Errorf("illegal registry endpoint %s", ep)
×
877
        }
×
878
        return url.Host + url.Path, nil
1✔
879
}
880

881
// getValueFromAnnotation returns the value of an annotation
882
func getValueFromAnnotation(pvc *corev1.PersistentVolumeClaim, annotation string) string {
1✔
883
        return pvc.Annotations[annotation]
1✔
884
}
1✔
885

886
// If this pod is going to transfer one checkpoint in a multi-stage import, attach the checkpoint name to the pod name so
887
// that each checkpoint gets a unique pod. That way each pod can be inspected using the retainAfterCompletion annotation.
888
func podNameWithCheckpoint(pvc *corev1.PersistentVolumeClaim) string {
1✔
889
        if checkpoint := pvc.Annotations[cc.AnnCurrentCheckpoint]; checkpoint != "" {
2✔
890
                return pvc.Name + "-checkpoint-" + checkpoint
1✔
891
        }
1✔
892
        return pvc.Name
1✔
893
}
894

895
func getImportPodNameFromPvc(pvc *corev1.PersistentVolumeClaim) string {
1✔
896
        podName, ok := pvc.Annotations[cc.AnnImportPod]
1✔
897
        if ok {
2✔
898
                return podName
1✔
899
        }
1✔
900
        // fallback to legacy naming, in fact the following function is fully compatible with legacy
901
        // name concatenation "importer-{pvc.Name}" if the name length is under the size limits,
902
        return naming.GetResourceName(common.ImporterPodName, podNameWithCheckpoint(pvc))
1✔
903
}
904

905
func createImportPodNameFromPvc(pvc *corev1.PersistentVolumeClaim) string {
1✔
906
        return naming.GetResourceName(common.ImporterPodName, podNameWithCheckpoint(pvc))
1✔
907
}
1✔
908

909
// createImporterPod creates and returns a pointer to a pod which is created based on the passed-in endpoint, secret
910
// name, and pvc. A nil secret means the endpoint credentials are not passed to the
911
// importer pod.
912
func createImporterPod(ctx context.Context, log logr.Logger, client client.Client, args *importerPodArgs, installerLabels map[string]string) (*corev1.Pod, error) {
1✔
913
        var err error
1✔
914
        args.podResourceRequirements, err = cc.GetDefaultPodResourceRequirements(client)
1✔
915
        if err != nil {
1✔
916
                return nil, err
×
917
        }
×
918

919
        args.imagePullSecrets, err = cc.GetImagePullSecrets(client)
1✔
920
        if err != nil {
1✔
921
                return nil, err
×
922
        }
×
923

924
        args.workloadNodePlacement, err = cc.GetWorkloadNodePlacement(ctx, client)
1✔
925
        if err != nil {
1✔
926
                return nil, err
×
927
        }
×
928

929
        if isRegistryNodeImport(args) {
2✔
930
                args.importImage, err = getRegistryImportImage(args.pvc)
1✔
931
                if err != nil {
1✔
932
                        return nil, err
×
933
                }
×
934
                setRegistryNodeImportEnvVars(args)
1✔
935
                if args.podEnvVar.registryImageArchitecture != "" {
1✔
936
                        setRegistryNodeImportNodeSelector(args)
×
937
                }
×
938
        }
939

940
        pod := makeImporterPodSpec(args)
1✔
941

1✔
942
        util.SetRecommendedLabels(pod, installerLabels, "cdi-controller")
1✔
943

1✔
944
        srcLabels := args.pvc.Labels
1✔
945
        if _, isPopulator := args.pvc.Annotations[cc.AnnPopulatorKind]; isPopulator {
2✔
946
                ownerRef := metav1.GetControllerOf(args.pvc)
1✔
947
                if ownerRef == nil || ownerRef.Kind != "PersistentVolumeClaim" {
1✔
NEW
948
                        return nil, fmt.Errorf("pvc %s/%s does not have a valid owner reference", args.pvc.Namespace, args.pvc.Name)
×
NEW
949
                }
×
950

951
                pvc := &corev1.PersistentVolumeClaim{}
1✔
952
                if err := client.Get(context.TODO(), types.NamespacedName{Namespace: args.pvc.Namespace, Name: ownerRef.Name}, pvc); err != nil {
1✔
NEW
953
                        return nil, err
×
NEW
954
                }
×
955
                srcLabels = pvc.GetLabels()
1✔
956
        }
957

958
        // add any labels from pvc to the importer pod
959
        util.MergeLabels(srcLabels, pod.Labels)
1✔
960

1✔
961
        if err = client.Create(context.TODO(), pod); err != nil {
1✔
962
                return nil, err
×
963
        }
×
964

965
        log.V(3).Info("importer pod created\n", "pod.Name", pod.Name, "pod.Namespace", pod.Namespace, "image name", args.image)
1✔
966
        return pod, nil
1✔
967
}
968

969
// makeImporterPodSpec creates and return the importer pod spec based on the passed-in endpoint, secret and pvc.
970
func makeImporterPodSpec(args *importerPodArgs) *corev1.Pod {
1✔
971
        // importer pod name contains the pvc name
1✔
972
        podName := args.pvc.Annotations[cc.AnnImportPod]
1✔
973

1✔
974
        pod := &corev1.Pod{
1✔
975
                TypeMeta: metav1.TypeMeta{
1✔
976
                        Kind:       "Pod",
1✔
977
                        APIVersion: "v1",
1✔
978
                },
1✔
979
                ObjectMeta: metav1.ObjectMeta{
1✔
980
                        Name:      podName,
1✔
981
                        Namespace: args.pvc.Namespace,
1✔
982
                        Annotations: map[string]string{
1✔
983
                                cc.AnnCreatedBy: "yes",
1✔
984
                        },
1✔
985
                        Labels: map[string]string{
1✔
986
                                common.CDILabelKey:        common.CDILabelValue,
1✔
987
                                common.CDIComponentLabel:  common.ImporterPodName,
1✔
988
                                common.PrometheusLabelKey: common.PrometheusLabelValue,
1✔
989
                        },
1✔
990
                        OwnerReferences: []metav1.OwnerReference{
1✔
991
                                {
1✔
992
                                        APIVersion:         "v1",
1✔
993
                                        Kind:               "PersistentVolumeClaim",
1✔
994
                                        Name:               args.pvc.Name,
1✔
995
                                        UID:                args.pvc.GetUID(),
1✔
996
                                        BlockOwnerDeletion: ptr.To[bool](true),
1✔
997
                                        Controller:         ptr.To[bool](true),
1✔
998
                                },
1✔
999
                        },
1✔
1000
                },
1✔
1001
                Spec: corev1.PodSpec{
1✔
1002
                        Containers:         makeImporterContainerSpec(args),
1✔
1003
                        InitContainers:     makeImporterInitContainersSpec(args),
1✔
1004
                        Volumes:            makeImporterVolumeSpec(args),
1✔
1005
                        RestartPolicy:      corev1.RestartPolicyOnFailure,
1✔
1006
                        NodeSelector:       args.workloadNodePlacement.NodeSelector,
1✔
1007
                        Tolerations:        args.workloadNodePlacement.Tolerations,
1✔
1008
                        Affinity:           args.workloadNodePlacement.Affinity,
1✔
1009
                        PriorityClassName:  args.priorityClassName,
1✔
1010
                        ServiceAccountName: args.serviceAccountName,
1✔
1011
                        ImagePullSecrets:   args.imagePullSecrets,
1✔
1012
                        // https://kubernetes.io/docs/concepts/services-networking/service/#environment-variables
1✔
1013
                        // Disable service environment variable injection to avoid 'argument list too long'
1✔
1014
                        // errors in namespaces with many Services (each injects ~7 env vars).
1✔
1015
                        EnableServiceLinks: ptr.To(false),
1✔
1016
                },
1✔
1017
        }
1✔
1018

1✔
1019
        /**
1✔
1020
        FIXME: When registry source is ImageStream, if we set importer pod OwnerReference (to its pvc, like all other cases),
1✔
1021
        for some reason (OCP issue?) we get the following error:
1✔
1022
                Failed to pull image "imagestream-name": rpc error: code = Unknown
1✔
1023
                desc = Error reading manifest latest in docker.io/library/imagestream-name: errors:
1✔
1024
                denied: requested access to the resource is denied
1✔
1025
                unauthorized: authentication required
1✔
1026
        When we don't set pod OwnerReferences, all works well.
1✔
1027
        */
1✔
1028
        if isRegistryNodeImport(args) && cc.IsImageStream(args.pvc) {
1✔
1029
                pod.OwnerReferences = nil
×
1030
                pod.Annotations[cc.AnnOpenShiftImageLookup] = "*"
×
1031
        }
×
1032

1033
        cc.CopyAllowedAnnotations(args.pvc, pod)
1✔
1034
        cc.SetRestrictedSecurityContext(&pod.Spec)
1✔
1035
        // We explicitly define a NodeName for dynamically provisioned PVCs
1✔
1036
        // when the PVC is being handled by a populator (PVC')
1✔
1037
        cc.SetNodeNameIfPopulator(args.pvc, &pod.Spec)
1✔
1038

1✔
1039
        return pod
1✔
1040
}
1041

1042
func makeImporterContainerSpec(args *importerPodArgs) []corev1.Container {
1✔
1043
        containers := []corev1.Container{
1✔
1044
                {
1✔
1045
                        Name:            common.ImporterPodName,
1✔
1046
                        Image:           args.image,
1✔
1047
                        ImagePullPolicy: corev1.PullPolicy(args.pullPolicy),
1✔
1048
                        Args:            []string{"-v=" + args.verbose},
1✔
1049
                        Env:             makeImportEnv(args.podEnvVar, getOwnerUID(args)),
1✔
1050
                        Ports: []corev1.ContainerPort{
1✔
1051
                                {
1✔
1052
                                        Name:          "metrics",
1✔
1053
                                        ContainerPort: 8443,
1✔
1054
                                        Protocol:      corev1.ProtocolTCP,
1✔
1055
                                },
1✔
1056
                        },
1✔
1057
                        TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
1✔
1058
                },
1✔
1059
        }
1✔
1060
        if cc.GetVolumeMode(args.pvc) == corev1.PersistentVolumeBlock {
2✔
1061
                containers[0].VolumeDevices = cc.AddVolumeDevices()
1✔
1062
        } else {
2✔
1063
                containers[0].VolumeMounts = cc.AddImportVolumeMounts()
1✔
1064
        }
1✔
1065
        if isRegistryNodeImport(args) {
2✔
1066
                containers = append(containers, corev1.Container{
1✔
1067
                        Name:            "server",
1✔
1068
                        Image:           args.importImage,
1✔
1069
                        ImagePullPolicy: corev1.PullPolicy(args.pullPolicy),
1✔
1070
                        Command:         []string{"/shared/server", "-p", "8100", "-image-dir", "/disk", "-ready-file", "/shared/ready", "-done-file", "/shared/done"},
1✔
1071
                        VolumeMounts: []corev1.VolumeMount{
1✔
1072
                                {
1✔
1073
                                        MountPath: "/shared",
1✔
1074
                                        Name:      "shared-volume",
1✔
1075
                                },
1✔
1076
                        },
1✔
1077
                        TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
1✔
1078
                })
1✔
1079
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
1✔
1080
                        MountPath: "/shared",
1✔
1081
                        Name:      "shared-volume",
1✔
1082
                })
1✔
1083
        }
1✔
1084
        if args.scratchPvcName != nil {
2✔
1085
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
1✔
1086
                        Name:      cc.ScratchVolName,
1✔
1087
                        MountPath: common.ScratchDataDir,
1✔
1088
                })
1✔
1089
        }
1✔
1090
        if args.vddkImageName != nil {
2✔
1091
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
1✔
1092
                        Name:      "vddk-vol-mount",
1✔
1093
                        MountPath: "/opt",
1✔
1094
                })
1✔
1095
        }
1✔
1096
        if args.vddkExtraArgs != nil {
2✔
1097
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
1✔
1098
                        Name:      common.VddkArgsVolName,
1✔
1099
                        MountPath: common.VddkArgsDir,
1✔
1100
                })
1✔
1101
        }
1✔
1102
        if args.podEnvVar.certConfigMap != "" {
1✔
1103
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
×
1104
                        Name:      CertVolName,
×
1105
                        MountPath: common.ImporterCertDir,
×
1106
                })
×
1107
        }
×
1108
        if args.podEnvVar.certConfigMapProxy != "" {
1✔
1109
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
×
1110
                        Name:      ProxyCertVolName,
×
1111
                        MountPath: common.ImporterProxyCertDir,
×
1112
                })
×
1113
        }
×
1114
        if args.podEnvVar.source == cc.SourceGCS && args.podEnvVar.secretName != "" {
1✔
1115
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
×
1116
                        Name:      SecretVolName,
×
1117
                        MountPath: common.ImporterGoogleCredentialDir,
×
1118
                })
×
1119
        }
×
1120
        for index := range args.podEnvVar.secretExtraHeaders {
1✔
1121
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
×
1122
                        Name:      fmt.Sprintf(secretExtraHeadersVolumeName, index),
×
1123
                        MountPath: path.Join(common.ImporterSecretExtraHeadersDir, fmt.Sprint(index)),
×
1124
                })
×
1125
        }
×
1126
        if args.podResourceRequirements != nil {
1✔
1127
                for i := range containers {
×
1128
                        containers[i].Resources = *args.podResourceRequirements
×
1129
                }
×
1130
        }
1131
        return containers
1✔
1132
}
1133

1134
func makeImporterVolumeSpec(args *importerPodArgs) []corev1.Volume {
1✔
1135
        volumes := []corev1.Volume{
1✔
1136
                {
1✔
1137
                        Name: cc.DataVolName,
1✔
1138
                        VolumeSource: corev1.VolumeSource{
1✔
1139
                                PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
1✔
1140
                                        ClaimName: args.pvc.Name,
1✔
1141
                                        ReadOnly:  false,
1✔
1142
                                },
1✔
1143
                        },
1✔
1144
                },
1✔
1145
        }
1✔
1146
        if isRegistryNodeImport(args) {
2✔
1147
                volumes = append(volumes, corev1.Volume{
1✔
1148
                        Name: "shared-volume",
1✔
1149
                        VolumeSource: corev1.VolumeSource{
1✔
1150
                                EmptyDir: &corev1.EmptyDirVolumeSource{},
1✔
1151
                        },
1✔
1152
                })
1✔
1153
        }
1✔
1154
        if args.scratchPvcName != nil {
2✔
1155
                volumes = append(volumes, corev1.Volume{
1✔
1156
                        Name: cc.ScratchVolName,
1✔
1157
                        VolumeSource: corev1.VolumeSource{
1✔
1158
                                PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
1✔
1159
                                        ClaimName: *args.scratchPvcName,
1✔
1160
                                        ReadOnly:  false,
1✔
1161
                                },
1✔
1162
                        },
1✔
1163
                })
1✔
1164
        }
1✔
1165
        if args.vddkImageName != nil {
2✔
1166
                volumes = append(volumes, corev1.Volume{
1✔
1167
                        Name: "vddk-vol-mount",
1✔
1168
                        VolumeSource: corev1.VolumeSource{
1✔
1169
                                EmptyDir: &corev1.EmptyDirVolumeSource{},
1✔
1170
                        },
1✔
1171
                })
1✔
1172
        }
1✔
1173
        if args.vddkExtraArgs != nil {
2✔
1174
                volumes = append(volumes, corev1.Volume{
1✔
1175
                        Name: common.VddkArgsVolName,
1✔
1176
                        VolumeSource: corev1.VolumeSource{
1✔
1177
                                ConfigMap: &v1.ConfigMapVolumeSource{
1✔
1178
                                        LocalObjectReference: v1.LocalObjectReference{
1✔
1179
                                                Name: *args.vddkExtraArgs,
1✔
1180
                                        },
1✔
1181
                                },
1✔
1182
                        },
1✔
1183
                })
1✔
1184
        }
1✔
1185
        if args.podEnvVar.certConfigMap != "" {
1✔
1186
                volumes = append(volumes, createConfigMapVolume(CertVolName, args.podEnvVar.certConfigMap))
×
1187
        }
×
1188
        if args.podEnvVar.certConfigMapProxy != "" {
1✔
1189
                volumes = append(volumes, createConfigMapVolume(ProxyCertVolName, GetImportProxyConfigMapName(args.pvc.Name)))
×
1190
        }
×
1191
        if args.podEnvVar.source == cc.SourceGCS && args.podEnvVar.secretName != "" {
1✔
1192
                volumes = append(volumes, createSecretVolume(SecretVolName, args.podEnvVar.secretName))
×
1193
        }
×
1194
        for index, header := range args.podEnvVar.secretExtraHeaders {
1✔
1195
                volumes = append(volumes, corev1.Volume{
×
1196
                        Name: fmt.Sprintf(secretExtraHeadersVolumeName, index),
×
1197
                        VolumeSource: corev1.VolumeSource{
×
1198
                                Secret: &corev1.SecretVolumeSource{
×
1199
                                        SecretName: header,
×
1200
                                },
×
1201
                        },
×
1202
                })
×
1203
        }
×
1204
        return volumes
1✔
1205
}
1206

1207
func makeImporterInitContainersSpec(args *importerPodArgs) []corev1.Container {
1✔
1208
        var initContainers []corev1.Container
1✔
1209
        if isRegistryNodeImport(args) {
2✔
1210
                initContainers = append(initContainers, corev1.Container{
1✔
1211
                        Name:            "init",
1✔
1212
                        Image:           args.image,
1✔
1213
                        ImagePullPolicy: corev1.PullPolicy(args.pullPolicy),
1✔
1214
                        Command:         []string{"sh", "-c", "cp /usr/bin/cdi-containerimage-server /shared/server"},
1✔
1215
                        VolumeMounts: []corev1.VolumeMount{
1✔
1216
                                {
1✔
1217
                                        MountPath: "/shared",
1✔
1218
                                        Name:      "shared-volume",
1✔
1219
                                },
1✔
1220
                        },
1✔
1221
                        TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
1✔
1222
                })
1✔
1223
        }
1✔
1224
        if args.vddkImageName != nil {
2✔
1225
                initContainers = append(initContainers, corev1.Container{
1✔
1226
                        Name:  "vddk-side-car",
1✔
1227
                        Image: *args.vddkImageName,
1✔
1228
                        VolumeMounts: []corev1.VolumeMount{
1✔
1229
                                {
1✔
1230
                                        Name:      "vddk-vol-mount",
1✔
1231
                                        MountPath: "/opt",
1✔
1232
                                },
1✔
1233
                        },
1✔
1234
                        TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
1✔
1235
                })
1✔
1236
        }
1✔
1237
        if args.podResourceRequirements != nil {
1✔
1238
                for i := range initContainers {
×
1239
                        initContainers[i].Resources = *args.podResourceRequirements
×
1240
                }
×
1241
        }
1242
        return initContainers
1✔
1243
}
1244

1245
func isRegistryNodeImport(args *importerPodArgs) bool {
1✔
1246
        return cc.GetSource(args.pvc) == cc.SourceRegistry &&
1✔
1247
                args.pvc.Annotations[cc.AnnRegistryImportMethod] == string(cdiv1.RegistryPullNode)
1✔
1248
}
1✔
1249

1250
func getOwnerUID(args *importerPodArgs) types.UID {
1✔
1251
        if len(args.pvc.OwnerReferences) == 1 {
2✔
1252
                return args.pvc.OwnerReferences[0].UID
1✔
1253
        }
1✔
1254
        return args.pvc.UID
1✔
1255
}
1256

1257
func setRegistryNodeImportEnvVars(args *importerPodArgs) {
1✔
1258
        args.podEnvVar.source = cc.SourceHTTP
1✔
1259
        args.podEnvVar.ep = "http://localhost:8100/disk.img"
1✔
1260
        args.podEnvVar.pullMethod = string(cdiv1.RegistryPullNode)
1✔
1261
        args.podEnvVar.readyFile = "/shared/ready"
1✔
1262
        args.podEnvVar.doneFile = "/shared/done"
1✔
1263
}
1✔
1264

1265
func setRegistryNodeImportNodeSelector(args *importerPodArgs) {
×
1266
        if args.workloadNodePlacement.NodeSelector == nil {
×
1267
                args.workloadNodePlacement.NodeSelector = make(map[string]string, 0)
×
1268
        }
×
1269
        args.workloadNodePlacement.NodeSelector[v1.LabelArchStable] = args.podEnvVar.registryImageArchitecture
×
1270
}
1271

1272
func createConfigMapVolume(certVolName, objRef string) corev1.Volume {
1✔
1273
        return corev1.Volume{
1✔
1274
                Name: certVolName,
1✔
1275
                VolumeSource: corev1.VolumeSource{
1✔
1276
                        ConfigMap: &corev1.ConfigMapVolumeSource{
1✔
1277
                                LocalObjectReference: corev1.LocalObjectReference{
1✔
1278
                                        Name: objRef,
1✔
1279
                                },
1✔
1280
                        },
1✔
1281
                },
1✔
1282
        }
1✔
1283
}
1✔
1284

1285
func createSecretVolume(thisVolName, objRef string) corev1.Volume {
×
1286
        return corev1.Volume{
×
1287
                Name: thisVolName,
×
1288
                VolumeSource: corev1.VolumeSource{
×
1289
                        Secret: &corev1.SecretVolumeSource{
×
1290
                                SecretName: objRef,
×
1291
                        },
×
1292
                },
×
1293
        }
×
1294
}
×
1295

1296
// return the Env portion for the importer container.
1297
func makeImportEnv(podEnvVar *importPodEnvVar, uid types.UID) []corev1.EnvVar {
1✔
1298
        env := []corev1.EnvVar{
1✔
1299
                {
1✔
1300
                        Name:  common.ImporterSource,
1✔
1301
                        Value: podEnvVar.source,
1✔
1302
                },
1✔
1303
                {
1✔
1304
                        Name:  common.ImporterEndpoint,
1✔
1305
                        Value: podEnvVar.ep,
1✔
1306
                },
1✔
1307
                {
1✔
1308
                        Name:  common.ImporterContentType,
1✔
1309
                        Value: podEnvVar.contentType,
1✔
1310
                },
1✔
1311
                {
1✔
1312
                        Name:  common.ImporterImageSize,
1✔
1313
                        Value: podEnvVar.imageSize,
1✔
1314
                },
1✔
1315
                {
1✔
1316
                        Name:  common.OwnerUID,
1✔
1317
                        Value: string(uid),
1✔
1318
                },
1✔
1319
                {
1✔
1320
                        Name:  common.FilesystemOverheadVar,
1✔
1321
                        Value: podEnvVar.filesystemOverhead,
1✔
1322
                },
1✔
1323
                {
1✔
1324
                        Name:  common.InsecureTLSVar,
1✔
1325
                        Value: strconv.FormatBool(podEnvVar.insecureTLS),
1✔
1326
                },
1✔
1327
                {
1✔
1328
                        Name:  common.ImporterDiskID,
1✔
1329
                        Value: podEnvVar.diskID,
1✔
1330
                },
1✔
1331
                {
1✔
1332
                        Name:  common.ImporterUUID,
1✔
1333
                        Value: podEnvVar.uuid,
1✔
1334
                },
1✔
1335
                {
1✔
1336
                        Name:  common.ImporterPullMethod,
1✔
1337
                        Value: podEnvVar.pullMethod,
1✔
1338
                },
1✔
1339
                {
1✔
1340
                        Name:  common.ImporterReadyFile,
1✔
1341
                        Value: podEnvVar.readyFile,
1✔
1342
                },
1✔
1343
                {
1✔
1344
                        Name:  common.ImporterDoneFile,
1✔
1345
                        Value: podEnvVar.doneFile,
1✔
1346
                },
1✔
1347
                {
1✔
1348
                        Name:  common.ImporterBackingFile,
1✔
1349
                        Value: podEnvVar.backingFile,
1✔
1350
                },
1✔
1351
                {
1✔
1352
                        Name:  common.ImporterThumbprint,
1✔
1353
                        Value: podEnvVar.thumbprint,
1✔
1354
                },
1✔
1355
                {
1✔
1356
                        Name:  common.ImportProxyHTTP,
1✔
1357
                        Value: podEnvVar.httpProxy,
1✔
1358
                },
1✔
1359
                {
1✔
1360
                        Name:  common.ImportProxyHTTPS,
1✔
1361
                        Value: podEnvVar.httpsProxy,
1✔
1362
                },
1✔
1363
                {
1✔
1364
                        Name:  common.ImportProxyNoProxy,
1✔
1365
                        Value: podEnvVar.noProxy,
1✔
1366
                },
1✔
1367
                {
1✔
1368
                        Name:  common.ImporterCurrentCheckpoint,
1✔
1369
                        Value: podEnvVar.currentCheckpoint,
1✔
1370
                },
1✔
1371
                {
1✔
1372
                        Name:  common.ImporterPreviousCheckpoint,
1✔
1373
                        Value: podEnvVar.previousCheckpoint,
1✔
1374
                },
1✔
1375
                {
1✔
1376
                        Name:  common.ImporterFinalCheckpoint,
1✔
1377
                        Value: podEnvVar.finalCheckpoint,
1✔
1378
                },
1✔
1379
                {
1✔
1380
                        Name:  common.Preallocation,
1✔
1381
                        Value: strconv.FormatBool(podEnvVar.preallocation),
1✔
1382
                },
1✔
1383
                {
1✔
1384
                        Name:  common.CacheMode,
1✔
1385
                        Value: podEnvVar.cacheMode,
1✔
1386
                },
1✔
1387
                {
1✔
1388
                        Name:  common.ImporterRegistryImageArchitecture,
1✔
1389
                        Value: podEnvVar.registryImageArchitecture,
1✔
1390
                },
1✔
1391
                {
1✔
1392
                        Name:  common.ImporterChecksum,
1✔
1393
                        Value: podEnvVar.checksum,
1✔
1394
                },
1✔
1395
        }
1✔
1396
        if podEnvVar.secretName != "" && podEnvVar.source != cc.SourceGCS {
1✔
1397
                env = append(env, corev1.EnvVar{
×
1398
                        Name: common.ImporterAccessKeyID,
×
1399
                        ValueFrom: &corev1.EnvVarSource{
×
1400
                                SecretKeyRef: &corev1.SecretKeySelector{
×
1401
                                        LocalObjectReference: corev1.LocalObjectReference{
×
1402
                                                Name: podEnvVar.secretName,
×
1403
                                        },
×
1404
                                        Key: common.KeyAccess,
×
1405
                                },
×
1406
                        },
×
1407
                }, corev1.EnvVar{
×
1408
                        Name: common.ImporterSecretKey,
×
1409
                        ValueFrom: &corev1.EnvVarSource{
×
1410
                                SecretKeyRef: &corev1.SecretKeySelector{
×
1411
                                        LocalObjectReference: corev1.LocalObjectReference{
×
1412
                                                Name: podEnvVar.secretName,
×
1413
                                        },
×
1414
                                        Key: common.KeySecret,
×
1415
                                },
×
1416
                        },
×
1417
                })
×
1418
        }
×
1419
        if podEnvVar.secretName != "" && podEnvVar.source == cc.SourceGCS {
1✔
1420
                env = append(env, corev1.EnvVar{
×
1421
                        Name:  common.ImporterGoogleCredentialFileVar,
×
1422
                        Value: common.ImporterGoogleCredentialFile,
×
1423
                })
×
1424
        }
×
1425
        if podEnvVar.certConfigMap != "" {
1✔
1426
                env = append(env, corev1.EnvVar{
×
1427
                        Name:  common.ImporterCertDirVar,
×
1428
                        Value: common.ImporterCertDir,
×
1429
                })
×
1430
        }
×
1431
        if podEnvVar.certConfigMapProxy != "" {
1✔
1432
                env = append(env, corev1.EnvVar{
×
1433
                        Name:  common.ImporterProxyCertDirVar,
×
1434
                        Value: common.ImporterProxyCertDir,
×
1435
                })
×
1436
        }
×
1437
        for index, header := range podEnvVar.extraHeaders {
1✔
1438
                env = append(env, corev1.EnvVar{
×
1439
                        Name:  fmt.Sprintf("%s%d", common.ImporterExtraHeader, index),
×
1440
                        Value: header,
×
1441
                })
×
1442
        }
×
1443
        return env
1✔
1444
}
1445

1446
func isOOMKilled(status v1.ContainerStatus) bool {
1✔
1447
        if terminated := status.State.Terminated; terminated != nil {
2✔
1448
                if terminated.Reason == cc.OOMKilledReason {
2✔
1449
                        return true
1✔
1450
                }
1✔
1451
        }
1452
        if terminated := status.LastTerminationState.Terminated; terminated != nil {
2✔
1453
                if terminated.Reason == cc.OOMKilledReason {
1✔
1454
                        return true
×
1455
                }
×
1456
        }
1457

1458
        return false
1✔
1459
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc