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

kubevirt / containerized-data-importer / #5903

23 Mar 2026 05:52PM UTC coverage: 49.333% (+0.05%) from 49.286%
#5903

push

travis-ci

web-flow
feat: set EnableServiceLinks=false on importer/cloner/uploader pods (#4067)

CDI pods fail with 'argument list too long' in namespaces with 2000+
Services because Kubernetes injects ~7 env vars per Service by default.
Set EnableServiceLinks=false on all CDI worker pod specs (importer,
clone source, upload server, forklift populator) to prevent this.

Same fix KubeVirt applied to virt-launcher pods (kubevirt/kubevirt#4393).

Fixes: https://github.com/kubevirt/containerized-data-importer/issues/4059

Signed-off-by: Jeff Holm <jeff.holm@gmail.com>

16 of 19 new or added lines in 5 files covered. (84.21%)

540 existing lines in 6 files now uncovered.

14757 of 29913 relevant lines covered (49.33%)

0.55 hits per line

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

71.43
/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
}
107

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

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

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

UNCOV
171
        return nil
×
172
}
173

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

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

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

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

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

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

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

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

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

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

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

255
        if pod == nil {
2✔
256
                if cc.IsPVCComplete(pvc) {
1✔
257
                        // Don't create the POD if the PVC is completed already
×
UNCOV
258
                        log.V(1).Info("PVC is already complete")
×
259
                } else if pvc.DeletionTimestamp == nil {
2✔
260
                        podsUsingPVC, err := cc.GetPodsUsingPVCs(context.TODO(), r.client, pvc.Namespace, sets.New(pvc.Name), false)
1✔
261
                        if err != nil {
1✔
262
                                return reconcile.Result{}, err
×
UNCOV
263
                        }
×
264

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

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

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

1✔
309
                return reconcile.Result{RequeueAfter: 2 * time.Second}, nil
1✔
310
        }
1✔
311
        return reconcile.Result{}, nil
1✔
312
}
313

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

348
// GetImportProxyConfigMapName returns the import proxy ConfigMap name
349
func GetImportProxyConfigMapName(pvcName string) string {
×
350
        return naming.GetResourceName("import-proxy-cm", pvcName)
×
UNCOV
351
}
×
352

353
func (r *ImportReconciler) initPvcPodName(pvc *corev1.PersistentVolumeClaim, log logr.Logger) error {
1✔
354
        currentPvcCopy := pvc.DeepCopyObject()
1✔
355

1✔
356
        log.V(1).Info("Init pod name on PVC")
1✔
357
        anno := pvc.GetAnnotations()
1✔
358

1✔
359
        anno[cc.AnnImportPod] = createImportPodNameFromPvc(pvc)
1✔
360

1✔
361
        requiresScratch := r.requiresScratchSpace(pvc)
1✔
362
        if requiresScratch {
1✔
363
                anno[cc.AnnRequiresScratch] = "true"
×
UNCOV
364
        }
×
365

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

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

1✔
379
        log.V(1).Info("Updating PVC from pod")
1✔
380
        anno := pvc.GetAnnotations()
1✔
381

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

1✔
388
        scratchSpaceRequired := termMsg != nil && termMsg.ScratchSpaceRequired != nil && *termMsg.ScratchSpaceRequired
1✔
389
        if scratchSpaceRequired {
2✔
390
                log.V(1).Info("Pod requires scratch space, terminating pod, and restarting with scratch space", "pod.Name", pod.Name)
1✔
391
        }
1✔
392
        podModificationsNeeded := scratchSpaceRequired
1✔
393

1✔
394
        if statuses := pod.Status.ContainerStatuses; len(statuses) > 0 {
2✔
395
                if isOOMKilled(statuses[0]) {
2✔
396
                        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✔
397
                        podModificationsNeeded = true
1✔
398
                        anno[cc.AnnRequiresDirectIO] = "true"
1✔
399
                }
1✔
400
                if terminated := statuses[0].State.Terminated; terminated != nil && terminated.ExitCode > 0 {
2✔
401
                        log.Info("Pod termination code", "pod.Name", pod.Name, "ExitCode", terminated.ExitCode)
1✔
402
                        r.recorder.Event(pvc, corev1.EventTypeWarning, ErrImportFailedPVC, terminated.Message)
1✔
403
                }
1✔
404
        }
405

406
        if anno[cc.AnnCurrentCheckpoint] != "" {
1✔
407
                anno[cc.AnnCurrentPodID] = string(pod.ObjectMeta.UID)
×
UNCOV
408
        }
×
409

410
        anno[cc.AnnImportPod] = pod.Name
1✔
411
        if !podModificationsNeeded {
2✔
412
                // No scratch space required, update the phase based on the pod. If we require scratch space we don't want to update the
1✔
413
                // phase, because the pod might terminate cleanly and mistakenly mark the import complete.
1✔
414
                anno[cc.AnnPodPhase] = string(pod.Status.Phase)
1✔
415
        }
1✔
416

417
        anno[cc.AnnPodSchedulable] = "true"
1✔
418
        if phase, ok := anno[cc.AnnPodPhase]; ok && phase == string(corev1.PodPending) {
2✔
419
                for _, cond := range pod.Status.Conditions {
1✔
420
                        if cond.Type == corev1.PodScheduled && cond.Reason == corev1.PodReasonUnschedulable {
×
421
                                anno[cc.AnnPodSchedulable] = "false"
×
UNCOV
422
                                break
×
423
                        }
424
                }
425
        }
426

427
        for _, ev := range pod.Spec.Containers[0].Env {
2✔
428
                if ev.Name == common.CacheMode && ev.Value == common.CacheModeTryNone {
1✔
429
                        anno[cc.AnnRequiresDirectIO] = "false"
×
UNCOV
430
                }
×
431
        }
432

433
        // Check if the POD is waiting for scratch space, if so create some.
434
        if pod.Status.Phase == corev1.PodPending && r.requiresScratchSpace(pvc) {
2✔
435
                if err := r.createScratchPvcForPod(pvc, pod); err != nil {
1✔
436
                        if !k8serrors.IsAlreadyExists(err) {
×
437
                                return err
×
UNCOV
438
                        }
×
439
                }
440
        } else {
1✔
441
                // No scratch space, or scratch space is bound, remove annotation
1✔
442
                delete(anno, cc.AnnBoundCondition)
1✔
443
                delete(anno, cc.AnnBoundConditionMessage)
1✔
444
                delete(anno, cc.AnnBoundConditionReason)
1✔
445
        }
1✔
446

447
        if pvc.GetLabels() == nil {
2✔
448
                pvc.SetLabels(make(map[string]string, 0))
1✔
449
        }
1✔
450
        if !checkIfLabelExists(pvc, common.CDILabelKey, common.CDILabelValue) {
2✔
451
                pvc.GetLabels()[common.CDILabelKey] = common.CDILabelValue
1✔
452
        }
1✔
453
        if cc.IsPVCComplete(pvc) {
2✔
454
                pvc.SetLabels(addLabelsFromTerminationMessage(pvc.GetLabels(), termMsg))
1✔
455
        }
1✔
456

457
        if !reflect.DeepEqual(currentPvcCopy, pvc) {
2✔
458
                if err := r.updatePVC(pvc, log); err != nil {
1✔
459
                        return err
×
UNCOV
460
                }
×
461
                log.V(1).Info("Updated PVC", "pvc.anno.Phase", anno[cc.AnnPodPhase], "pvc.anno.Restarts", anno[cc.AnnPodRestarts])
1✔
462
        }
463

464
        if cc.IsPVCComplete(pvc) || podModificationsNeeded {
2✔
465
                if !podModificationsNeeded {
2✔
466
                        r.recorder.Event(pvc, corev1.EventTypeNormal, ImportSucceededPVC, "Import Successful")
1✔
467
                        log.V(1).Info("Import completed successfully")
1✔
468
                }
1✔
469
                if cc.ShouldDeletePod(pvc) {
2✔
470
                        log.V(1).Info("Deleting pod", "pod.Name", pod.Name)
1✔
471
                        if err := r.cleanup(pvc, pod, log); err != nil {
1✔
472
                                return err
×
UNCOV
473
                        }
×
474
                }
475
        }
476
        return nil
1✔
477
}
478

479
func (r *ImportReconciler) cleanup(pvc *corev1.PersistentVolumeClaim, pod *corev1.Pod, log logr.Logger) error {
1✔
480
        if err := r.client.Delete(context.TODO(), pod); cc.IgnoreNotFound(err) != nil {
1✔
481
                return err
×
UNCOV
482
        }
×
483
        if cc.HasFinalizer(pvc, importPodImageStreamFinalizer) {
1✔
484
                cc.RemoveFinalizer(pvc, importPodImageStreamFinalizer)
×
485
                if err := r.updatePVC(pvc, log); err != nil {
×
486
                        return err
×
UNCOV
487
                }
×
488
        }
489
        return nil
1✔
490
}
491

492
func (r *ImportReconciler) updatePVC(pvc *corev1.PersistentVolumeClaim, log logr.Logger) error {
1✔
493
        if err := r.client.Update(context.TODO(), pvc); err != nil {
1✔
494
                return err
×
UNCOV
495
        }
×
496
        return nil
1✔
497
}
498

499
func (r *ImportReconciler) createImporterPod(pvc *corev1.PersistentVolumeClaim) error {
1✔
500
        r.log.V(1).Info("Creating importer POD for PVC", "pvc.Name", pvc.Name)
1✔
501
        var scratchPvcName *string
1✔
502
        var vddkImageName *string
1✔
503
        var vddkExtraArgs *string
1✔
504
        var err error
1✔
505

1✔
506
        requiresScratch := r.requiresScratchSpace(pvc)
1✔
507
        if requiresScratch {
1✔
508
                name := createScratchNameFromPvc(pvc)
×
509
                scratchPvcName = &name
×
UNCOV
510
        }
×
511

512
        if cc.GetSource(pvc) == cc.SourceVDDK {
2✔
513
                r.log.V(1).Info("Pod requires VDDK sidecar for VMware transfer")
1✔
514
                anno := pvc.GetAnnotations()
1✔
515
                if imageName, ok := anno[cc.AnnVddkInitImageURL]; ok {
2✔
516
                        vddkImageName = &imageName
1✔
517
                } else {
2✔
518
                        if vddkImageName, err = r.getVddkImageName(); err != nil {
2✔
519
                                r.log.V(1).Error(err, "failed to get VDDK image name from configmap")
1✔
520
                        }
1✔
521
                }
522
                if vddkImageName == nil {
2✔
523
                        message := fmt.Sprintf("waiting for %s configmap or %s annotation for VDDK image", common.VddkConfigMap, cc.AnnVddkInitImageURL)
1✔
524
                        anno[cc.AnnBoundCondition] = "false"
1✔
525
                        anno[cc.AnnBoundConditionMessage] = message
1✔
526
                        anno[cc.AnnBoundConditionReason] = common.AwaitingVDDK
1✔
527
                        if err := r.updatePVC(pvc, r.log); err != nil {
1✔
528
                                return err
×
UNCOV
529
                        }
×
530
                        return errors.New(message)
1✔
531
                }
532

533
                if extraArgs, ok := anno[cc.AnnVddkExtraArgs]; ok && extraArgs != "" {
2✔
534
                        r.log.V(1).Info("Mounting extra VDDK args ConfigMap to importer pod", "ConfigMap", extraArgs)
1✔
535
                        vddkExtraArgs = &extraArgs
1✔
536
                }
1✔
537
        }
538

539
        podEnvVar, err := r.createImportEnvVar(pvc)
1✔
540
        if err != nil {
1✔
541
                return err
×
UNCOV
542
        }
×
543
        // all checks passed, let's create the importer pod!
544
        podArgs := &importerPodArgs{
1✔
545
                image:              r.image,
1✔
546
                verbose:            r.verbose,
1✔
547
                pullPolicy:         r.pullPolicy,
1✔
548
                podEnvVar:          podEnvVar,
1✔
549
                pvc:                pvc,
1✔
550
                scratchPvcName:     scratchPvcName,
1✔
551
                vddkImageName:      vddkImageName,
1✔
552
                vddkExtraArgs:      vddkExtraArgs,
1✔
553
                priorityClassName:  cc.GetPriorityClass(pvc),
1✔
554
                serviceAccountName: cc.GetPodServiceAccount(pvc),
1✔
555
        }
1✔
556

1✔
557
        pod, err := createImporterPod(context.TODO(), r.log, r.client, podArgs, r.installerLabels)
1✔
558
        // Check if pod has failed and, in that case, record an event with the error
1✔
559
        if podErr := cc.HandleFailedPod(err, pvc.Annotations[cc.AnnImportPod], pvc, r.recorder, r.client); podErr != nil {
1✔
UNCOV
560
                return podErr
×
UNCOV
561
        }
×
562

563
        r.log.V(1).Info("Created POD", "pod.Name", pod.Name)
1✔
564

1✔
565
        // If importing from image stream, add finalizer. Note we don't watch the importer pod in this case,
1✔
566
        // so to prevent a deadlock we add finalizer only if the pod is not retained after completion.
1✔
567
        if cc.IsImageStream(pvc) && pvc.GetAnnotations()[cc.AnnPodRetainAfterCompletion] != "true" {
1✔
568
                cc.AddFinalizer(pvc, importPodImageStreamFinalizer)
×
569
                if err := r.updatePVC(pvc, r.log); err != nil {
×
UNCOV
570
                        return err
×
UNCOV
571
                }
×
572
        }
573

574
        if requiresScratch {
1✔
575
                r.log.V(1).Info("Pod requires scratch space")
×
UNCOV
576
                return r.createScratchPvcForPod(pvc, pod)
×
UNCOV
577
        }
×
578

579
        return nil
1✔
580
}
581

582
func createScratchNameFromPvc(pvc *v1.PersistentVolumeClaim) string {
×
UNCOV
583
        return naming.GetResourceName(pvc.Name, common.ScratchNameSuffix)
×
UNCOV
584
}
×
585

586
func (r *ImportReconciler) createImportEnvVar(pvc *corev1.PersistentVolumeClaim) (*importPodEnvVar, error) {
1✔
587
        podEnvVar := &importPodEnvVar{}
1✔
588
        podEnvVar.source = cc.GetSource(pvc)
1✔
589
        podEnvVar.contentType = string(cc.GetPVCContentType(pvc))
1✔
590

1✔
591
        var err error
1✔
592
        if podEnvVar.source != cc.SourceNone {
2✔
593
                podEnvVar.ep, err = cc.GetEndpoint(pvc)
1✔
594
                if err != nil {
1✔
UNCOV
595
                        return nil, err
×
UNCOV
596
                }
×
597
                podEnvVar.secretName = r.getSecretName(pvc)
1✔
598
                if podEnvVar.secretName == "" {
2✔
599
                        r.log.V(2).Info("no secret will be supplied to endpoint", "endPoint", podEnvVar.ep)
1✔
600
                }
1✔
601
                //get the CDIConfig to extract the proxy configuration to be used to import an image
602
                cdiConfig := &cdiv1.CDIConfig{}
1✔
603
                err = r.client.Get(context.TODO(), types.NamespacedName{Name: common.ConfigName}, cdiConfig)
1✔
604
                if err != nil {
1✔
UNCOV
605
                        return nil, err
×
UNCOV
606
                }
×
607
                podEnvVar.certConfigMap, err = r.getCertConfigMap(pvc)
1✔
608
                if err != nil {
1✔
UNCOV
609
                        return nil, err
×
UNCOV
610
                }
×
611
                podEnvVar.insecureTLS, err = r.isInsecureTLS(pvc, cdiConfig)
1✔
612
                if err != nil {
1✔
UNCOV
613
                        return nil, err
×
UNCOV
614
                }
×
615
                podEnvVar.diskID = getValueFromAnnotation(pvc, cc.AnnDiskID)
1✔
616
                podEnvVar.backingFile = getValueFromAnnotation(pvc, cc.AnnBackingFile)
1✔
617
                podEnvVar.uuid = getValueFromAnnotation(pvc, cc.AnnUUID)
1✔
618
                podEnvVar.thumbprint = getValueFromAnnotation(pvc, cc.AnnThumbprint)
1✔
619
                podEnvVar.previousCheckpoint = getValueFromAnnotation(pvc, cc.AnnPreviousCheckpoint)
1✔
620
                podEnvVar.currentCheckpoint = getValueFromAnnotation(pvc, cc.AnnCurrentCheckpoint)
1✔
621
                podEnvVar.finalCheckpoint = getValueFromAnnotation(pvc, cc.AnnFinalCheckpoint)
1✔
622
                podEnvVar.registryImageArchitecture = getValueFromAnnotation(pvc, cc.AnnRegistryImageArchitecture)
1✔
623

1✔
624
                for annotation, value := range pvc.Annotations {
2✔
625
                        if strings.HasPrefix(annotation, cc.AnnExtraHeaders) {
1✔
UNCOV
626
                                podEnvVar.extraHeaders = append(podEnvVar.extraHeaders, value)
×
627
                        }
×
628
                        if strings.HasPrefix(annotation, cc.AnnSecretExtraHeaders) {
1✔
UNCOV
629
                                podEnvVar.secretExtraHeaders = append(podEnvVar.secretExtraHeaders, value)
×
UNCOV
630
                        }
×
631
                }
632

633
                var field string
1✔
634
                if field, err = GetImportProxyConfig(cdiConfig, common.ImportProxyHTTP); err != nil {
2✔
635
                        r.log.V(3).Info("no proxy http url will be supplied:", "error", err.Error())
1✔
636
                }
1✔
637
                podEnvVar.httpProxy = field
1✔
638
                if field, err = GetImportProxyConfig(cdiConfig, common.ImportProxyHTTPS); err != nil {
2✔
639
                        r.log.V(3).Info("no proxy https url will be supplied:", "error", err.Error())
1✔
640
                }
1✔
641
                podEnvVar.httpsProxy = field
1✔
642
                if field, err = GetImportProxyConfig(cdiConfig, common.ImportProxyNoProxy); err != nil {
2✔
643
                        r.log.V(3).Info("the noProxy field will not be supplied:", "error", err.Error())
1✔
644
                }
1✔
645
                podEnvVar.noProxy = field
1✔
646
                if field, err = GetImportProxyConfig(cdiConfig, common.ImportProxyConfigMapName); err != nil {
2✔
647
                        r.log.V(3).Info("no proxy CA certiticate will be supplied:", "error", err.Error())
1✔
648
                }
1✔
649
                podEnvVar.certConfigMapProxy = field
1✔
650
        }
651

652
        fsOverhead, err := GetFilesystemOverhead(context.TODO(), r.client, pvc)
1✔
653
        if err != nil {
1✔
UNCOV
654
                return nil, err
×
UNCOV
655
        }
×
656
        podEnvVar.filesystemOverhead = string(fsOverhead)
1✔
657

1✔
658
        if preallocation, err := strconv.ParseBool(getValueFromAnnotation(pvc, cc.AnnPreallocationRequested)); err == nil {
1✔
UNCOV
659
                podEnvVar.preallocation = preallocation
×
UNCOV
660
        } // else use the default "false"
×
661

662
        //get the requested image size.
663
        podEnvVar.imageSize, err = cc.GetRequestedImageSize(pvc)
1✔
664
        if err != nil {
1✔
UNCOV
665
                return nil, err
×
UNCOV
666
        }
×
667

668
        if v, ok := pvc.Annotations[cc.AnnRequiresDirectIO]; ok && v == "true" {
2✔
669
                podEnvVar.cacheMode = common.CacheModeTryNone
1✔
670
        }
1✔
671

672
        return podEnvVar, nil
1✔
673
}
674

675
func (r *ImportReconciler) isInsecureTLS(pvc *corev1.PersistentVolumeClaim, cdiConfig *cdiv1.CDIConfig) (bool, error) {
1✔
676
        // Check if insecureSkipVerify annotation is set (only applicable for ImageIO sources)
1✔
677
        source, sourceOk := pvc.Annotations[cc.AnnSource]
1✔
678
        if sourceOk && source == cc.SourceImageio {
1✔
679
                if insecureSkipVerify, ok := pvc.Annotations[cc.AnnInsecureSkipVerify]; ok && insecureSkipVerify == "true" {
×
UNCOV
680
                        return true, nil
×
UNCOV
681
                }
×
682
        }
683

684
        ep, ok := pvc.Annotations[cc.AnnEndpoint]
1✔
685
        if !ok || ep == "" {
2✔
686
                return false, nil
1✔
687
        }
1✔
688
        return IsInsecureTLS(ep, cdiConfig, r.log)
1✔
689
}
690

691
// IsInsecureTLS checks if TLS security is disabled for the given endpoint
692
func IsInsecureTLS(ep string, cdiConfig *cdiv1.CDIConfig, log logr.Logger) (bool, error) {
1✔
693
        url, err := url.Parse(ep)
1✔
694
        if err != nil {
1✔
UNCOV
695
                return false, err
×
UNCOV
696
        }
×
697

698
        if url.Scheme != "docker" {
2✔
699
                return false, nil
1✔
700
        }
1✔
701

702
        for _, value := range cdiConfig.Spec.InsecureRegistries {
2✔
703
                log.V(1).Info("Checking host against value", "host", url.Host, "value", value)
1✔
704
                if value == url.Host {
2✔
705
                        return true, nil
1✔
706
                }
1✔
707
        }
708
        return false, nil
1✔
709
}
710

711
func (r *ImportReconciler) getCertConfigMap(pvc *corev1.PersistentVolumeClaim) (string, error) {
1✔
712
        value, ok := pvc.Annotations[cc.AnnCertConfigMap]
1✔
713
        if !ok || value == "" {
2✔
714
                return "", nil
1✔
715
        }
1✔
716

717
        configMap := &corev1.ConfigMap{}
1✔
718
        if err := r.uncachedClient.Get(context.TODO(), types.NamespacedName{Name: value, Namespace: pvc.Namespace}, configMap); err != nil {
2✔
719
                if k8serrors.IsNotFound(err) {
2✔
720
                        r.log.V(1).Info("Configmap does not exist, pod will not start until it does", "configMapName", value)
1✔
721
                        return value, nil
1✔
722
                }
1✔
723

UNCOV
724
                return "", err
×
725
        }
726

727
        return value, nil
1✔
728
}
729

730
// returns the name of the secret containing endpoint credentials consumed by the importer pod.
731
// A value of "" implies there are no credentials for the endpoint being used. A returned error
732
// causes processNextItem() to stop.
733
func (r *ImportReconciler) getSecretName(pvc *corev1.PersistentVolumeClaim) string {
1✔
734
        ns := pvc.Namespace
1✔
735
        name, found := pvc.Annotations[cc.AnnSecret]
1✔
736
        if !found || name == "" {
2✔
737
                msg := "getEndpointSecret: "
1✔
738
                if !found {
2✔
739
                        msg += fmt.Sprintf("annotation %q is missing in pvc \"%s/%s\"", cc.AnnSecret, ns, pvc.Name)
1✔
740
                } else {
1✔
UNCOV
741
                        msg += fmt.Sprintf("secret name is missing from annotation %q in pvc \"%s/%s\"", cc.AnnSecret, ns, pvc.Name)
×
UNCOV
742
                }
×
743
                r.log.V(2).Info(msg)
1✔
744
                return "" // importer pod will not contain secret credentials
1✔
745
        }
746
        return name
1✔
747
}
748

749
func (r *ImportReconciler) requiresScratchSpace(pvc *corev1.PersistentVolumeClaim) bool {
1✔
750
        scratchRequired := false
1✔
751
        contentType := cc.GetPVCContentType(pvc)
1✔
752
        // All archive requires scratch space.
1✔
753
        if contentType == cdiv1.DataVolumeArchive {
1✔
UNCOV
754
                scratchRequired = true
×
755
        } else {
1✔
756
                switch cc.GetSource(pvc) {
1✔
757
                case cc.SourceGlance:
×
758
                        scratchRequired = true
×
759
                case cc.SourceImageio:
×
760
                        if val, ok := pvc.Annotations[cc.AnnCurrentCheckpoint]; ok {
×
UNCOV
761
                                scratchRequired = val != ""
×
UNCOV
762
                        }
×
763
                case cc.SourceRegistry:
1✔
764
                        scratchRequired = pvc.Annotations[cc.AnnRegistryImportMethod] != string(cdiv1.RegistryPullNode)
1✔
765
                }
766
        }
767
        value, ok := pvc.Annotations[cc.AnnRequiresScratch]
1✔
768
        if ok {
2✔
769
                boolVal, _ := strconv.ParseBool(value)
1✔
770
                scratchRequired = scratchRequired || boolVal
1✔
771
        }
1✔
772
        return scratchRequired
1✔
773
}
774

775
func (r *ImportReconciler) createScratchPvcForPod(pvc *corev1.PersistentVolumeClaim, pod *corev1.Pod) error {
1✔
776
        scratchPvc := &corev1.PersistentVolumeClaim{}
1✔
777
        scratchPVCName, exists := getScratchNameFromPod(pod)
1✔
778
        if !exists {
1✔
UNCOV
779
                return errors.New("Scratch Volume not configured for pod")
×
UNCOV
780
        }
×
781
        anno := pvc.GetAnnotations()
1✔
782
        err := r.client.Get(context.TODO(), types.NamespacedName{Namespace: pvc.GetNamespace(), Name: scratchPVCName}, scratchPvc)
1✔
783
        if cc.IgnoreNotFound(err) != nil {
1✔
UNCOV
784
                return err
×
UNCOV
785
        }
×
786
        if k8serrors.IsNotFound(err) {
2✔
787
                r.log.V(1).Info("Creating scratch space for POD and PVC", "pod.Name", pod.Name, "pvc.Name", pvc.Name)
1✔
788

1✔
789
                storageClassName := GetScratchPvcStorageClass(r.client, pvc)
1✔
790
                // Scratch PVC doesn't exist yet, create it. Determine which storage class to use.
1✔
791
                _, err = createScratchPersistentVolumeClaim(r.client, pvc, pod, scratchPVCName, storageClassName, r.installerLabels, r.recorder)
1✔
792
                if err != nil {
1✔
UNCOV
793
                        return err
×
UNCOV
794
                }
×
795
                anno[cc.AnnBoundCondition] = "false"
1✔
796
                anno[cc.AnnBoundConditionMessage] = "Creating scratch space"
1✔
797
                anno[cc.AnnBoundConditionReason] = creatingScratch
1✔
798
        } else {
×
799
                if scratchPvc.DeletionTimestamp != nil {
×
800
                        // Delete the pod since we are in a deadlock situation now. The scratch PVC from the previous import is not gone
×
801
                        // yet but terminating, and the new pod is still being created and the scratch PVC now has a finalizer on it.
×
802
                        // Only way to break it, is to delete the importer pod, and give the pvc a chance to disappear.
×
803
                        err = r.client.Delete(context.TODO(), pod)
×
804
                        if err != nil {
×
805
                                return err
×
UNCOV
806
                        }
×
UNCOV
807
                        return fmt.Errorf("terminating scratch space found, deleting pod %s", pod.Name)
×
808
                }
809
        }
810
        anno[cc.AnnRequiresScratch] = "false"
1✔
811
        return nil
1✔
812
}
813

814
// Get path to VDDK image from 'v2v-vmware' ConfigMap
815
func (r *ImportReconciler) getVddkImageName() (*string, error) {
1✔
816
        namespace := util.GetNamespace()
1✔
817

1✔
818
        cm := &corev1.ConfigMap{}
1✔
819
        err := r.uncachedClient.Get(context.TODO(), types.NamespacedName{Name: common.VddkConfigMap, Namespace: namespace}, cm)
1✔
820
        if k8serrors.IsNotFound(err) {
2✔
821
                return nil, errors.Errorf("No %s ConfigMap present in namespace %s", common.VddkConfigMap, namespace)
1✔
822
        }
1✔
823

824
        image, found := cm.Data[common.VddkConfigDataKey]
1✔
825
        if found {
2✔
826
                msg := fmt.Sprintf("Found %s ConfigMap in namespace %s, VDDK image path is: ", common.VddkConfigMap, namespace)
1✔
827
                r.log.V(1).Info(msg, common.VddkConfigDataKey, image)
1✔
828
                return &image, nil
1✔
829
        }
1✔
830

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

834
// returns the import image part of the endpoint string
835
func getRegistryImportImage(pvc *corev1.PersistentVolumeClaim) (string, error) {
1✔
836
        ep, err := cc.GetEndpoint(pvc)
1✔
837
        if err != nil {
1✔
UNCOV
838
                return "", nil
×
839
        }
×
840
        if cc.IsImageStream(pvc) {
1✔
UNCOV
841
                return ep, nil
×
UNCOV
842
        }
×
843
        url, err := url.Parse(ep)
1✔
844
        if err != nil {
1✔
UNCOV
845
                return "", errors.Errorf("illegal registry endpoint %s", ep)
×
UNCOV
846
        }
×
847
        return url.Host + url.Path, nil
1✔
848
}
849

850
// getValueFromAnnotation returns the value of an annotation
851
func getValueFromAnnotation(pvc *corev1.PersistentVolumeClaim, annotation string) string {
1✔
852
        return pvc.Annotations[annotation]
1✔
853
}
1✔
854

855
// If this pod is going to transfer one checkpoint in a multi-stage import, attach the checkpoint name to the pod name so
856
// that each checkpoint gets a unique pod. That way each pod can be inspected using the retainAfterCompletion annotation.
857
func podNameWithCheckpoint(pvc *corev1.PersistentVolumeClaim) string {
1✔
858
        if checkpoint := pvc.Annotations[cc.AnnCurrentCheckpoint]; checkpoint != "" {
2✔
859
                return pvc.Name + "-checkpoint-" + checkpoint
1✔
860
        }
1✔
861
        return pvc.Name
1✔
862
}
863

864
func getImportPodNameFromPvc(pvc *corev1.PersistentVolumeClaim) string {
1✔
865
        podName, ok := pvc.Annotations[cc.AnnImportPod]
1✔
866
        if ok {
2✔
867
                return podName
1✔
868
        }
1✔
869
        // fallback to legacy naming, in fact the following function is fully compatible with legacy
870
        // name concatenation "importer-{pvc.Name}" if the name length is under the size limits,
871
        return naming.GetResourceName(common.ImporterPodName, podNameWithCheckpoint(pvc))
1✔
872
}
873

874
func createImportPodNameFromPvc(pvc *corev1.PersistentVolumeClaim) string {
1✔
875
        return naming.GetResourceName(common.ImporterPodName, podNameWithCheckpoint(pvc))
1✔
876
}
1✔
877

878
// createImporterPod creates and returns a pointer to a pod which is created based on the passed-in endpoint, secret
879
// name, and pvc. A nil secret means the endpoint credentials are not passed to the
880
// importer pod.
881
func createImporterPod(ctx context.Context, log logr.Logger, client client.Client, args *importerPodArgs, installerLabels map[string]string) (*corev1.Pod, error) {
1✔
882
        var err error
1✔
883
        args.podResourceRequirements, err = cc.GetDefaultPodResourceRequirements(client)
1✔
884
        if err != nil {
1✔
UNCOV
885
                return nil, err
×
UNCOV
886
        }
×
887

888
        args.imagePullSecrets, err = cc.GetImagePullSecrets(client)
1✔
889
        if err != nil {
1✔
UNCOV
890
                return nil, err
×
UNCOV
891
        }
×
892

893
        args.workloadNodePlacement, err = cc.GetWorkloadNodePlacement(ctx, client)
1✔
894
        if err != nil {
1✔
UNCOV
895
                return nil, err
×
UNCOV
896
        }
×
897

898
        if isRegistryNodeImport(args) {
2✔
899
                args.importImage, err = getRegistryImportImage(args.pvc)
1✔
900
                if err != nil {
1✔
UNCOV
901
                        return nil, err
×
UNCOV
902
                }
×
903
                setRegistryNodeImportEnvVars(args)
1✔
904
                if args.podEnvVar.registryImageArchitecture != "" {
1✔
UNCOV
905
                        setRegistryNodeImportNodeSelector(args)
×
UNCOV
906
                }
×
907
        }
908

909
        pod := makeImporterPodSpec(args)
1✔
910

1✔
911
        util.SetRecommendedLabels(pod, installerLabels, "cdi-controller")
1✔
912

1✔
913
        // add any labels from pvc to the importer pod
1✔
914
        util.MergeLabels(args.pvc.Labels, pod.Labels)
1✔
915

1✔
916
        if err = client.Create(context.TODO(), pod); err != nil {
1✔
UNCOV
917
                return nil, err
×
UNCOV
918
        }
×
919

920
        log.V(3).Info("importer pod created\n", "pod.Name", pod.Name, "pod.Namespace", pod.Namespace, "image name", args.image)
1✔
921
        return pod, nil
1✔
922
}
923

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

1✔
929
        pod := &corev1.Pod{
1✔
930
                TypeMeta: metav1.TypeMeta{
1✔
931
                        Kind:       "Pod",
1✔
932
                        APIVersion: "v1",
1✔
933
                },
1✔
934
                ObjectMeta: metav1.ObjectMeta{
1✔
935
                        Name:      podName,
1✔
936
                        Namespace: args.pvc.Namespace,
1✔
937
                        Annotations: map[string]string{
1✔
938
                                cc.AnnCreatedBy: "yes",
1✔
939
                        },
1✔
940
                        Labels: map[string]string{
1✔
941
                                common.CDILabelKey:        common.CDILabelValue,
1✔
942
                                common.CDIComponentLabel:  common.ImporterPodName,
1✔
943
                                common.PrometheusLabelKey: common.PrometheusLabelValue,
1✔
944
                        },
1✔
945
                        OwnerReferences: []metav1.OwnerReference{
1✔
946
                                {
1✔
947
                                        APIVersion:         "v1",
1✔
948
                                        Kind:               "PersistentVolumeClaim",
1✔
949
                                        Name:               args.pvc.Name,
1✔
950
                                        UID:                args.pvc.GetUID(),
1✔
951
                                        BlockOwnerDeletion: ptr.To[bool](true),
1✔
952
                                        Controller:         ptr.To[bool](true),
1✔
953
                                },
1✔
954
                        },
1✔
955
                },
1✔
956
                Spec: corev1.PodSpec{
1✔
957
                        Containers:         makeImporterContainerSpec(args),
1✔
958
                        InitContainers:     makeImporterInitContainersSpec(args),
1✔
959
                        Volumes:            makeImporterVolumeSpec(args),
1✔
960
                        RestartPolicy:      corev1.RestartPolicyOnFailure,
1✔
961
                        NodeSelector:       args.workloadNodePlacement.NodeSelector,
1✔
962
                        Tolerations:        args.workloadNodePlacement.Tolerations,
1✔
963
                        Affinity:           args.workloadNodePlacement.Affinity,
1✔
964
                        PriorityClassName:  args.priorityClassName,
1✔
965
                        ServiceAccountName: args.serviceAccountName,
1✔
966
                        ImagePullSecrets:   args.imagePullSecrets,
1✔
967
                        // https://kubernetes.io/docs/concepts/services-networking/service/#environment-variables
1✔
968
                        // Disable service environment variable injection to avoid 'argument list too long'
1✔
969
                        // errors in namespaces with many Services (each injects ~7 env vars).
1✔
970
                        EnableServiceLinks: ptr.To(false),
1✔
971
                },
1✔
972
        }
1✔
973

1✔
974
        /**
1✔
975
        FIXME: When registry source is ImageStream, if we set importer pod OwnerReference (to its pvc, like all other cases),
1✔
976
        for some reason (OCP issue?) we get the following error:
1✔
977
                Failed to pull image "imagestream-name": rpc error: code = Unknown
1✔
978
                desc = Error reading manifest latest in docker.io/library/imagestream-name: errors:
1✔
979
                denied: requested access to the resource is denied
1✔
980
                unauthorized: authentication required
1✔
981
        When we don't set pod OwnerReferences, all works well.
1✔
982
        */
1✔
983
        if isRegistryNodeImport(args) && cc.IsImageStream(args.pvc) {
1✔
UNCOV
984
                pod.OwnerReferences = nil
×
UNCOV
985
                pod.Annotations[cc.AnnOpenShiftImageLookup] = "*"
×
UNCOV
986
        }
×
987

988
        cc.CopyAllowedAnnotations(args.pvc, pod)
1✔
989
        cc.SetRestrictedSecurityContext(&pod.Spec)
1✔
990
        // We explicitly define a NodeName for dynamically provisioned PVCs
1✔
991
        // when the PVC is being handled by a populator (PVC')
1✔
992
        cc.SetNodeNameIfPopulator(args.pvc, &pod.Spec)
1✔
993

1✔
994
        return pod
1✔
995
}
996

997
func makeImporterContainerSpec(args *importerPodArgs) []corev1.Container {
1✔
998
        containers := []corev1.Container{
1✔
999
                {
1✔
1000
                        Name:            common.ImporterPodName,
1✔
1001
                        Image:           args.image,
1✔
1002
                        ImagePullPolicy: corev1.PullPolicy(args.pullPolicy),
1✔
1003
                        Args:            []string{"-v=" + args.verbose},
1✔
1004
                        Env:             makeImportEnv(args.podEnvVar, getOwnerUID(args)),
1✔
1005
                        Ports: []corev1.ContainerPort{
1✔
1006
                                {
1✔
1007
                                        Name:          "metrics",
1✔
1008
                                        ContainerPort: 8443,
1✔
1009
                                        Protocol:      corev1.ProtocolTCP,
1✔
1010
                                },
1✔
1011
                        },
1✔
1012
                        TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
1✔
1013
                },
1✔
1014
        }
1✔
1015
        if cc.GetVolumeMode(args.pvc) == corev1.PersistentVolumeBlock {
2✔
1016
                containers[0].VolumeDevices = cc.AddVolumeDevices()
1✔
1017
        } else {
2✔
1018
                containers[0].VolumeMounts = cc.AddImportVolumeMounts()
1✔
1019
        }
1✔
1020
        if isRegistryNodeImport(args) {
2✔
1021
                containers = append(containers, corev1.Container{
1✔
1022
                        Name:            "server",
1✔
1023
                        Image:           args.importImage,
1✔
1024
                        ImagePullPolicy: corev1.PullPolicy(args.pullPolicy),
1✔
1025
                        Command:         []string{"/shared/server", "-p", "8100", "-image-dir", "/disk", "-ready-file", "/shared/ready", "-done-file", "/shared/done"},
1✔
1026
                        VolumeMounts: []corev1.VolumeMount{
1✔
1027
                                {
1✔
1028
                                        MountPath: "/shared",
1✔
1029
                                        Name:      "shared-volume",
1✔
1030
                                },
1✔
1031
                        },
1✔
1032
                        TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
1✔
1033
                })
1✔
1034
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
1✔
1035
                        MountPath: "/shared",
1✔
1036
                        Name:      "shared-volume",
1✔
1037
                })
1✔
1038
        }
1✔
1039
        if args.scratchPvcName != nil {
2✔
1040
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
1✔
1041
                        Name:      cc.ScratchVolName,
1✔
1042
                        MountPath: common.ScratchDataDir,
1✔
1043
                })
1✔
1044
        }
1✔
1045
        if args.vddkImageName != nil {
2✔
1046
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
1✔
1047
                        Name:      "vddk-vol-mount",
1✔
1048
                        MountPath: "/opt",
1✔
1049
                })
1✔
1050
        }
1✔
1051
        if args.vddkExtraArgs != nil {
2✔
1052
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
1✔
1053
                        Name:      common.VddkArgsVolName,
1✔
1054
                        MountPath: common.VddkArgsDir,
1✔
1055
                })
1✔
1056
        }
1✔
1057
        if args.podEnvVar.certConfigMap != "" {
1✔
1058
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
×
1059
                        Name:      CertVolName,
×
UNCOV
1060
                        MountPath: common.ImporterCertDir,
×
1061
                })
×
1062
        }
×
1063
        if args.podEnvVar.certConfigMapProxy != "" {
1✔
1064
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
×
1065
                        Name:      ProxyCertVolName,
×
UNCOV
1066
                        MountPath: common.ImporterProxyCertDir,
×
1067
                })
×
1068
        }
×
1069
        if args.podEnvVar.source == cc.SourceGCS && args.podEnvVar.secretName != "" {
1✔
1070
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
×
1071
                        Name:      SecretVolName,
×
UNCOV
1072
                        MountPath: common.ImporterGoogleCredentialDir,
×
1073
                })
×
1074
        }
×
1075
        for index := range args.podEnvVar.secretExtraHeaders {
1✔
1076
                containers[0].VolumeMounts = append(containers[0].VolumeMounts, corev1.VolumeMount{
×
1077
                        Name:      fmt.Sprintf(secretExtraHeadersVolumeName, index),
×
UNCOV
1078
                        MountPath: path.Join(common.ImporterSecretExtraHeadersDir, fmt.Sprint(index)),
×
1079
                })
×
1080
        }
×
1081
        if args.podResourceRequirements != nil {
1✔
UNCOV
1082
                for i := range containers {
×
UNCOV
1083
                        containers[i].Resources = *args.podResourceRequirements
×
UNCOV
1084
                }
×
1085
        }
1086
        return containers
1✔
1087
}
1088

1089
func makeImporterVolumeSpec(args *importerPodArgs) []corev1.Volume {
1✔
1090
        volumes := []corev1.Volume{
1✔
1091
                {
1✔
1092
                        Name: cc.DataVolName,
1✔
1093
                        VolumeSource: corev1.VolumeSource{
1✔
1094
                                PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
1✔
1095
                                        ClaimName: args.pvc.Name,
1✔
1096
                                        ReadOnly:  false,
1✔
1097
                                },
1✔
1098
                        },
1✔
1099
                },
1✔
1100
        }
1✔
1101
        if isRegistryNodeImport(args) {
2✔
1102
                volumes = append(volumes, corev1.Volume{
1✔
1103
                        Name: "shared-volume",
1✔
1104
                        VolumeSource: corev1.VolumeSource{
1✔
1105
                                EmptyDir: &corev1.EmptyDirVolumeSource{},
1✔
1106
                        },
1✔
1107
                })
1✔
1108
        }
1✔
1109
        if args.scratchPvcName != nil {
2✔
1110
                volumes = append(volumes, corev1.Volume{
1✔
1111
                        Name: cc.ScratchVolName,
1✔
1112
                        VolumeSource: corev1.VolumeSource{
1✔
1113
                                PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{
1✔
1114
                                        ClaimName: *args.scratchPvcName,
1✔
1115
                                        ReadOnly:  false,
1✔
1116
                                },
1✔
1117
                        },
1✔
1118
                })
1✔
1119
        }
1✔
1120
        if args.vddkImageName != nil {
2✔
1121
                volumes = append(volumes, corev1.Volume{
1✔
1122
                        Name: "vddk-vol-mount",
1✔
1123
                        VolumeSource: corev1.VolumeSource{
1✔
1124
                                EmptyDir: &corev1.EmptyDirVolumeSource{},
1✔
1125
                        },
1✔
1126
                })
1✔
1127
        }
1✔
1128
        if args.vddkExtraArgs != nil {
2✔
1129
                volumes = append(volumes, corev1.Volume{
1✔
1130
                        Name: common.VddkArgsVolName,
1✔
1131
                        VolumeSource: corev1.VolumeSource{
1✔
1132
                                ConfigMap: &v1.ConfigMapVolumeSource{
1✔
1133
                                        LocalObjectReference: v1.LocalObjectReference{
1✔
1134
                                                Name: *args.vddkExtraArgs,
1✔
1135
                                        },
1✔
1136
                                },
1✔
1137
                        },
1✔
1138
                })
1✔
1139
        }
1✔
1140
        if args.podEnvVar.certConfigMap != "" {
1✔
1141
                volumes = append(volumes, createConfigMapVolume(CertVolName, args.podEnvVar.certConfigMap))
×
1142
        }
×
1143
        if args.podEnvVar.certConfigMapProxy != "" {
1✔
1144
                volumes = append(volumes, createConfigMapVolume(ProxyCertVolName, GetImportProxyConfigMapName(args.pvc.Name)))
×
1145
        }
×
1146
        if args.podEnvVar.source == cc.SourceGCS && args.podEnvVar.secretName != "" {
1✔
1147
                volumes = append(volumes, createSecretVolume(SecretVolName, args.podEnvVar.secretName))
×
1148
        }
×
1149
        for index, header := range args.podEnvVar.secretExtraHeaders {
1✔
1150
                volumes = append(volumes, corev1.Volume{
×
1151
                        Name: fmt.Sprintf(secretExtraHeadersVolumeName, index),
×
1152
                        VolumeSource: corev1.VolumeSource{
×
1153
                                Secret: &corev1.SecretVolumeSource{
×
1154
                                        SecretName: header,
×
1155
                                },
×
UNCOV
1156
                        },
×
UNCOV
1157
                })
×
UNCOV
1158
        }
×
1159
        return volumes
1✔
1160
}
1161

1162
func makeImporterInitContainersSpec(args *importerPodArgs) []corev1.Container {
1✔
1163
        var initContainers []corev1.Container
1✔
1164
        if isRegistryNodeImport(args) {
2✔
1165
                initContainers = append(initContainers, corev1.Container{
1✔
1166
                        Name:            "init",
1✔
1167
                        Image:           args.image,
1✔
1168
                        ImagePullPolicy: corev1.PullPolicy(args.pullPolicy),
1✔
1169
                        Command:         []string{"sh", "-c", "cp /usr/bin/cdi-containerimage-server /shared/server"},
1✔
1170
                        VolumeMounts: []corev1.VolumeMount{
1✔
1171
                                {
1✔
1172
                                        MountPath: "/shared",
1✔
1173
                                        Name:      "shared-volume",
1✔
1174
                                },
1✔
1175
                        },
1✔
1176
                        TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
1✔
1177
                })
1✔
1178
        }
1✔
1179
        if args.vddkImageName != nil {
2✔
1180
                initContainers = append(initContainers, corev1.Container{
1✔
1181
                        Name:  "vddk-side-car",
1✔
1182
                        Image: *args.vddkImageName,
1✔
1183
                        VolumeMounts: []corev1.VolumeMount{
1✔
1184
                                {
1✔
1185
                                        Name:      "vddk-vol-mount",
1✔
1186
                                        MountPath: "/opt",
1✔
1187
                                },
1✔
1188
                        },
1✔
1189
                        TerminationMessagePolicy: corev1.TerminationMessageFallbackToLogsOnError,
1✔
1190
                })
1✔
1191
        }
1✔
1192
        if args.podResourceRequirements != nil {
1✔
UNCOV
1193
                for i := range initContainers {
×
UNCOV
1194
                        initContainers[i].Resources = *args.podResourceRequirements
×
UNCOV
1195
                }
×
1196
        }
1197
        return initContainers
1✔
1198
}
1199

1200
func isRegistryNodeImport(args *importerPodArgs) bool {
1✔
1201
        return cc.GetSource(args.pvc) == cc.SourceRegistry &&
1✔
1202
                args.pvc.Annotations[cc.AnnRegistryImportMethod] == string(cdiv1.RegistryPullNode)
1✔
1203
}
1✔
1204

1205
func getOwnerUID(args *importerPodArgs) types.UID {
1✔
1206
        if len(args.pvc.OwnerReferences) == 1 {
1✔
UNCOV
1207
                return args.pvc.OwnerReferences[0].UID
×
UNCOV
1208
        }
×
1209
        return args.pvc.UID
1✔
1210
}
1211

1212
func setRegistryNodeImportEnvVars(args *importerPodArgs) {
1✔
1213
        args.podEnvVar.source = cc.SourceHTTP
1✔
1214
        args.podEnvVar.ep = "http://localhost:8100/disk.img"
1✔
1215
        args.podEnvVar.pullMethod = string(cdiv1.RegistryPullNode)
1✔
1216
        args.podEnvVar.readyFile = "/shared/ready"
1✔
1217
        args.podEnvVar.doneFile = "/shared/done"
1✔
1218
}
1✔
1219

1220
func setRegistryNodeImportNodeSelector(args *importerPodArgs) {
×
1221
        if args.workloadNodePlacement.NodeSelector == nil {
×
UNCOV
1222
                args.workloadNodePlacement.NodeSelector = make(map[string]string, 0)
×
UNCOV
1223
        }
×
UNCOV
1224
        args.workloadNodePlacement.NodeSelector[v1.LabelArchStable] = args.podEnvVar.registryImageArchitecture
×
1225
}
1226

1227
func createConfigMapVolume(certVolName, objRef string) corev1.Volume {
1✔
1228
        return corev1.Volume{
1✔
1229
                Name: certVolName,
1✔
1230
                VolumeSource: corev1.VolumeSource{
1✔
1231
                        ConfigMap: &corev1.ConfigMapVolumeSource{
1✔
1232
                                LocalObjectReference: corev1.LocalObjectReference{
1✔
1233
                                        Name: objRef,
1✔
1234
                                },
1✔
1235
                        },
1✔
1236
                },
1✔
1237
        }
1✔
1238
}
1✔
1239

1240
func createSecretVolume(thisVolName, objRef string) corev1.Volume {
×
1241
        return corev1.Volume{
×
1242
                Name: thisVolName,
×
1243
                VolumeSource: corev1.VolumeSource{
×
1244
                        Secret: &corev1.SecretVolumeSource{
×
1245
                                SecretName: objRef,
×
1246
                        },
×
UNCOV
1247
                },
×
UNCOV
1248
        }
×
UNCOV
1249
}
×
1250

1251
// return the Env portion for the importer container.
1252
func makeImportEnv(podEnvVar *importPodEnvVar, uid types.UID) []corev1.EnvVar {
1✔
1253
        env := []corev1.EnvVar{
1✔
1254
                {
1✔
1255
                        Name:  common.ImporterSource,
1✔
1256
                        Value: podEnvVar.source,
1✔
1257
                },
1✔
1258
                {
1✔
1259
                        Name:  common.ImporterEndpoint,
1✔
1260
                        Value: podEnvVar.ep,
1✔
1261
                },
1✔
1262
                {
1✔
1263
                        Name:  common.ImporterContentType,
1✔
1264
                        Value: podEnvVar.contentType,
1✔
1265
                },
1✔
1266
                {
1✔
1267
                        Name:  common.ImporterImageSize,
1✔
1268
                        Value: podEnvVar.imageSize,
1✔
1269
                },
1✔
1270
                {
1✔
1271
                        Name:  common.OwnerUID,
1✔
1272
                        Value: string(uid),
1✔
1273
                },
1✔
1274
                {
1✔
1275
                        Name:  common.FilesystemOverheadVar,
1✔
1276
                        Value: podEnvVar.filesystemOverhead,
1✔
1277
                },
1✔
1278
                {
1✔
1279
                        Name:  common.InsecureTLSVar,
1✔
1280
                        Value: strconv.FormatBool(podEnvVar.insecureTLS),
1✔
1281
                },
1✔
1282
                {
1✔
1283
                        Name:  common.ImporterDiskID,
1✔
1284
                        Value: podEnvVar.diskID,
1✔
1285
                },
1✔
1286
                {
1✔
1287
                        Name:  common.ImporterUUID,
1✔
1288
                        Value: podEnvVar.uuid,
1✔
1289
                },
1✔
1290
                {
1✔
1291
                        Name:  common.ImporterPullMethod,
1✔
1292
                        Value: podEnvVar.pullMethod,
1✔
1293
                },
1✔
1294
                {
1✔
1295
                        Name:  common.ImporterReadyFile,
1✔
1296
                        Value: podEnvVar.readyFile,
1✔
1297
                },
1✔
1298
                {
1✔
1299
                        Name:  common.ImporterDoneFile,
1✔
1300
                        Value: podEnvVar.doneFile,
1✔
1301
                },
1✔
1302
                {
1✔
1303
                        Name:  common.ImporterBackingFile,
1✔
1304
                        Value: podEnvVar.backingFile,
1✔
1305
                },
1✔
1306
                {
1✔
1307
                        Name:  common.ImporterThumbprint,
1✔
1308
                        Value: podEnvVar.thumbprint,
1✔
1309
                },
1✔
1310
                {
1✔
1311
                        Name:  common.ImportProxyHTTP,
1✔
1312
                        Value: podEnvVar.httpProxy,
1✔
1313
                },
1✔
1314
                {
1✔
1315
                        Name:  common.ImportProxyHTTPS,
1✔
1316
                        Value: podEnvVar.httpsProxy,
1✔
1317
                },
1✔
1318
                {
1✔
1319
                        Name:  common.ImportProxyNoProxy,
1✔
1320
                        Value: podEnvVar.noProxy,
1✔
1321
                },
1✔
1322
                {
1✔
1323
                        Name:  common.ImporterCurrentCheckpoint,
1✔
1324
                        Value: podEnvVar.currentCheckpoint,
1✔
1325
                },
1✔
1326
                {
1✔
1327
                        Name:  common.ImporterPreviousCheckpoint,
1✔
1328
                        Value: podEnvVar.previousCheckpoint,
1✔
1329
                },
1✔
1330
                {
1✔
1331
                        Name:  common.ImporterFinalCheckpoint,
1✔
1332
                        Value: podEnvVar.finalCheckpoint,
1✔
1333
                },
1✔
1334
                {
1✔
1335
                        Name:  common.Preallocation,
1✔
1336
                        Value: strconv.FormatBool(podEnvVar.preallocation),
1✔
1337
                },
1✔
1338
                {
1✔
1339
                        Name:  common.CacheMode,
1✔
1340
                        Value: podEnvVar.cacheMode,
1✔
1341
                },
1✔
1342
                {
1✔
1343
                        Name:  common.ImporterRegistryImageArchitecture,
1✔
1344
                        Value: podEnvVar.registryImageArchitecture,
1✔
1345
                },
1✔
1346
        }
1✔
1347
        if podEnvVar.secretName != "" && podEnvVar.source != cc.SourceGCS {
1✔
1348
                env = append(env, corev1.EnvVar{
×
1349
                        Name: common.ImporterAccessKeyID,
×
1350
                        ValueFrom: &corev1.EnvVarSource{
×
1351
                                SecretKeyRef: &corev1.SecretKeySelector{
×
1352
                                        LocalObjectReference: corev1.LocalObjectReference{
×
1353
                                                Name: podEnvVar.secretName,
×
1354
                                        },
×
1355
                                        Key: common.KeyAccess,
×
1356
                                },
×
1357
                        },
×
1358
                }, corev1.EnvVar{
×
1359
                        Name: common.ImporterSecretKey,
×
1360
                        ValueFrom: &corev1.EnvVarSource{
×
1361
                                SecretKeyRef: &corev1.SecretKeySelector{
×
1362
                                        LocalObjectReference: corev1.LocalObjectReference{
×
1363
                                                Name: podEnvVar.secretName,
×
1364
                                        },
×
1365
                                        Key: common.KeySecret,
×
1366
                                },
×
UNCOV
1367
                        },
×
1368
                })
×
1369
        }
×
1370
        if podEnvVar.secretName != "" && podEnvVar.source == cc.SourceGCS {
1✔
1371
                env = append(env, corev1.EnvVar{
×
1372
                        Name:  common.ImporterGoogleCredentialFileVar,
×
UNCOV
1373
                        Value: common.ImporterGoogleCredentialFile,
×
1374
                })
×
1375
        }
×
1376
        if podEnvVar.certConfigMap != "" {
1✔
1377
                env = append(env, corev1.EnvVar{
×
1378
                        Name:  common.ImporterCertDirVar,
×
UNCOV
1379
                        Value: common.ImporterCertDir,
×
1380
                })
×
1381
        }
×
1382
        if podEnvVar.certConfigMapProxy != "" {
1✔
1383
                env = append(env, corev1.EnvVar{
×
1384
                        Name:  common.ImporterProxyCertDirVar,
×
UNCOV
1385
                        Value: common.ImporterProxyCertDir,
×
1386
                })
×
1387
        }
×
1388
        for index, header := range podEnvVar.extraHeaders {
1✔
1389
                env = append(env, corev1.EnvVar{
×
1390
                        Name:  fmt.Sprintf("%s%d", common.ImporterExtraHeader, index),
×
UNCOV
1391
                        Value: header,
×
UNCOV
1392
                })
×
UNCOV
1393
        }
×
1394
        return env
1✔
1395
}
1396

1397
func isOOMKilled(status v1.ContainerStatus) bool {
1✔
1398
        if terminated := status.State.Terminated; terminated != nil {
2✔
1399
                if terminated.Reason == cc.OOMKilledReason {
2✔
1400
                        return true
1✔
1401
                }
1✔
1402
        }
1403
        if terminated := status.LastTerminationState.Terminated; terminated != nil {
2✔
1404
                if terminated.Reason == cc.OOMKilledReason {
1✔
UNCOV
1405
                        return true
×
UNCOV
1406
                }
×
1407
        }
1408

1409
        return false
1✔
1410
}
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