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

kubevirt / containerized-data-importer / #4852

13 Aug 2024 12:06AM UTC coverage: 59.141% (-0.03%) from 59.171%
#4852

push

travis-ci

web-flow
nbdkit datapath debug (#3361)

* pkg/image/nbdkit: Enable controlpath debugging

Disabling datapath debugging reduces noise, but controlpath debugging
is actually useful, not very noisy, and usually you would want it to
be enabled.

The difference is explained here:

https://libguestfs.org/nbdkit.1.html#SERVER-DEBUG-FLAGS

Virt-v2v disables datapath debugging but keeps controlpath debugging
enabled.

Signed-off-by: Richard W.M. Jones <rjones@redhat.com>

* pkg/image/nbdkit: Enable recommended nbdkit VDDK debugging options

VDDK datapath debugging logs every VDDK read and write which is noisy
and unnecessary.

Enabling VDDK stats gives useful information about how long each VDDK
call took, for virtually no overhead.  This information is printed to
stderr when nbdkit closes the connection.

This matches the upstream recommendations here, and also the flags
used by virt-v2v:

https://libguestfs.org/nbdkit-vddk-plugin.1.html#Troubleshooting-performance-problems

Signed-off-by: Richard W.M. Jones <rjones@redhat.com>

---------

Signed-off-by: Richard W.M. Jones <rjones@redhat.com>

0 of 2 new or added lines in 1 file covered. (0.0%)

152 existing lines in 5 files now uncovered.

16488 of 27879 relevant lines covered (59.14%)

0.65 hits per line

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

37.17
/pkg/operator/controller/controller.go
1
/*
2
Copyright 2018 The CDI Authors.
3

4
Licensed under the Apache License, Version 2.0 (the "License");
5
you may not use this file except in compliance with the License.
6
You may obtain a copy of the License at
7

8
    http://www.apache.org/licenses/LICENSE-2.0
9

10
Unless required by applicable law or agreed to in writing, software
11
distributed under the License is distributed on an "AS IS" BASIS,
12
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
See the License for the specific language governing permissions and
14
limitations under the License.
15
*/
16

17
package controller
18

19
import (
20
        "context"
21
        "fmt"
22
        "os"
23
        "strconv"
24
        "time"
25

26
        "github.com/kelseyhightower/envconfig"
27
        conditionsv1 "github.com/openshift/custom-resource-status/conditions/v1"
28

29
        corev1 "k8s.io/api/core/v1"
30
        "k8s.io/apimachinery/pkg/api/errors"
31
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
32
        "k8s.io/apimachinery/pkg/runtime"
33
        "k8s.io/client-go/tools/record"
34

35
        "sigs.k8s.io/controller-runtime/pkg/cache"
36
        "sigs.k8s.io/controller-runtime/pkg/client"
37
        "sigs.k8s.io/controller-runtime/pkg/controller"
38
        "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
39
        logf "sigs.k8s.io/controller-runtime/pkg/log"
40
        "sigs.k8s.io/controller-runtime/pkg/manager"
41
        "sigs.k8s.io/controller-runtime/pkg/reconcile"
42

43
        cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
44
        metrics "kubevirt.io/containerized-data-importer/pkg/monitoring/metrics/operator-controller"
45
        "kubevirt.io/containerized-data-importer/pkg/monitoring/rules"
46
        "kubevirt.io/containerized-data-importer/pkg/operator"
47
        cdicerts "kubevirt.io/containerized-data-importer/pkg/operator/resources/cert"
48
        cdicluster "kubevirt.io/containerized-data-importer/pkg/operator/resources/cluster"
49
        "kubevirt.io/containerized-data-importer/pkg/operator/resources/generate/install"
50
        cdinamespaced "kubevirt.io/containerized-data-importer/pkg/operator/resources/namespaced"
51
        "kubevirt.io/containerized-data-importer/pkg/util"
52
        "kubevirt.io/controller-lifecycle-operator-sdk/pkg/sdk/callbacks"
53
        sdkr "kubevirt.io/controller-lifecycle-operator-sdk/pkg/sdk/reconciler"
54
)
55

56
const (
57
        finalizerName = "operator.cdi.kubevirt.io"
58

59
        createVersionLabel = "operator.cdi.kubevirt.io/createVersion"
60
        updateVersionLabel = "operator.cdi.kubevirt.io/updateVersion"
61
        // LastAppliedConfigAnnotation is the annotation that holds the last resource state which we put on resources under our governance
62
        LastAppliedConfigAnnotation = "operator.cdi.kubevirt.io/lastAppliedConfiguration"
63

64
        certPollInterval = 1 * time.Minute
65

66
        createResourceFailed  = "CreateResourceFailed"
67
        createResourceSuccess = "CreateResourceSuccess"
68

69
        deleteResourceFailed   = "DeleteResourceFailed"
70
        deleteResourceSuccess  = "DeleteResourceSuccess"
71
        dumpInstallStrategyKey = "DUMP_INSTALL_STRATEGY"
72

73
        annInjectUploadProxyCert = "operator.cdi.kubevirt.io/injectUploadProxyCert"
74
        updateUserRouteSuccess   = "UploadProxyRouteInjectSuccess"
75
)
76

77
var (
78
        log = logf.Log.WithName("cdi-operator")
79
)
80

81
func init() {
1✔
82
        // Setup metrics for our various controllers
1✔
83
        err := metrics.SetupMetrics()
1✔
84
        if err != nil {
1✔
UNCOV
85
                log.Info("Error setting up metrics: %v", err)
×
UNCOV
86
        }
×
87
        metrics.SetInit()
1✔
88
}
89

90
// Add creates a new CDI Controller and adds it to the Manager. The Manager will set fields on the Controller
91
// and Start it when the Manager is Started.
92
func Add(mgr manager.Manager) error {
×
93
        r, err := newReconciler(mgr)
×
94
        if err != nil {
×
UNCOV
95
                return err
×
UNCOV
96
        }
×
UNCOV
97
        return r.add(mgr)
×
98
}
99

100
// newReconciler returns a new reconcile.Reconciler
101
func newReconciler(mgr manager.Manager) (*ReconcileCDI, error) {
×
102
        var namespacedArgs cdinamespaced.FactoryArgs
×
103
        namespace := util.GetNamespace()
×
104
        restClient := mgr.GetClient()
×
105
        clusterArgs := &cdicluster.FactoryArgs{
×
106
                Namespace: namespace,
×
107
                Client:    restClient,
×
108
                Logger:    log,
×
109
        }
×
110
        dumpInstallStrategy := false
×
111
        if value, ok := os.LookupEnv(dumpInstallStrategyKey); ok {
×
112
                ret, err := strconv.ParseBool(value)
×
113
                if err != nil {
×
114
                        return nil, err
×
UNCOV
115
                }
×
UNCOV
116
                dumpInstallStrategy = ret
×
117
                log.Info("Dump Install Strategy", "VARS", ret)
×
118
        }
119

120
        err := envconfig.Process("", &namespacedArgs)
×
UNCOV
121
        if err != nil {
×
122
                return nil, err
×
123
        }
×
124

125
        namespacedArgs.Namespace = namespace
×
126

×
127
        log.Info("", "VARS", fmt.Sprintf("%+v", namespacedArgs))
×
128

×
129
        scheme := mgr.GetScheme()
×
130
        uncachedClient, err := client.New(mgr.GetConfig(), client.Options{
×
131
                Scheme: scheme,
×
132
                Mapper: mgr.GetRESTMapper(),
×
133
        })
×
UNCOV
134
        if err != nil {
×
135
                return nil, err
×
136
        }
×
137

138
        err = rules.SetupRules(namespace)
×
UNCOV
139
        if err != nil {
×
140
                return nil, err
×
141
        }
×
142

143
        recorder := mgr.GetEventRecorderFor("operator-controller")
×
144

×
145
        haveRoutes, err := haveRoutes(uncachedClient)
×
146
        if err != nil {
×
147
                return nil, err
×
148
        }
×
149

150
        r := &ReconcileCDI{
×
151
                client:              restClient,
×
152
                uncachedClient:      uncachedClient,
×
153
                scheme:              scheme,
×
154
                getCache:            mgr.GetCache,
×
155
                recorder:            recorder,
×
156
                namespace:           namespace,
×
157
                clusterArgs:         clusterArgs,
×
158
                namespacedArgs:      &namespacedArgs,
×
159
                dumpInstallStrategy: dumpInstallStrategy,
×
UNCOV
160
                haveRoutes:          haveRoutes,
×
UNCOV
161
        }
×
UNCOV
162
        callbackDispatcher := callbacks.NewCallbackDispatcher(log, restClient, uncachedClient, scheme, namespace)
×
UNCOV
163
        r.reconciler = sdkr.NewReconciler(r, log, restClient, callbackDispatcher, scheme, mgr.GetCache, createVersionLabel, updateVersionLabel, LastAppliedConfigAnnotation, certPollInterval, finalizerName, false, recorder)
×
UNCOV
164

×
UNCOV
165
        r.registerHooks()
×
UNCOV
166
        addReconcileCallbacks(r)
×
UNCOV
167

×
UNCOV
168
        return r, nil
×
169
}
170

171
var _ reconcile.Reconciler = &ReconcileCDI{}
172

173
// ReconcileCDI reconciles a CDI object
174
type ReconcileCDI struct {
175
        // This Client, initialized using mgr.client() above, is a split Client
176
        // that reads objects from the cache and writes to the apiserver
177
        client client.Client
178

179
        // use this for getting any resources not in the install namespace or cluster scope
180
        uncachedClient client.Client
181
        scheme         *runtime.Scheme
182
        getCache       func() cache.Cache
183
        recorder       record.EventRecorder
184
        controller     controller.Controller
185

186
        namespace      string
187
        clusterArgs    *cdicluster.FactoryArgs
188
        namespacedArgs *cdinamespaced.FactoryArgs
189

190
        certManager         CertManager
191
        reconciler          *sdkr.Reconciler
192
        dumpInstallStrategy bool
193
        haveRoutes          bool
194
}
195

196
// SetController sets the controller dependency
UNCOV
197
func (r *ReconcileCDI) SetController(controller controller.Controller) {
×
UNCOV
198
        r.controller = controller
×
UNCOV
199
        r.reconciler.WithController(controller)
×
UNCOV
200
}
×
201

202
// Reconcile reads that state of the cluster for a CDI object and makes changes based on the state read
203
// and what is in the CDI.Spec
204
// Note:
205
// The Controller will requeue the Request to be processed again if the returned error is non-nil or
206
// Result.Requeue is true, otherwise upon completion it will remove the work from the queue.
207
func (r *ReconcileCDI) Reconcile(_ context.Context, request reconcile.Request) (reconcile.Result, error) {
1✔
208
        reqLogger := log.WithValues("Request.Namespace", request.Namespace, "Request.Name", request.Name)
1✔
209
        reqLogger.Info("Reconciling CDI CR")
1✔
210
        operatorVersion := r.namespacedArgs.OperatorVersion
1✔
211
        cr := &cdiv1.CDI{}
1✔
212
        crKey := client.ObjectKey{Namespace: "", Name: request.NamespacedName.Name}
1✔
213
        err := r.client.Get(context.TODO(), crKey, cr)
1✔
214
        if err != nil {
1✔
215
                if errors.IsNotFound(err) {
×
216
                        reqLogger.Info("CDI CR does not exist")
×
217
                        return reconcile.Result{}, nil
×
218
                }
×
219
                reqLogger.Error(err, "Failed to get CDI object")
×
220
                return reconcile.Result{}, err
×
221
        }
222

223
        if r.dumpInstallStrategy {
1✔
224
                reqLogger.Info("Dumping Install Strategy")
×
225
                objects, err := r.GetAllResources(cr)
×
226
                if err != nil {
×
227
                        reqLogger.Error(err, "Failed to get all CDI object")
×
228
                        return reconcile.Result{}, err
×
229
                }
×
UNCOV
230
                var runtimeObjects []runtime.Object
×
UNCOV
231
                for _, obj := range objects {
×
UNCOV
232
                        runtimeObjects = append(runtimeObjects, obj)
×
UNCOV
233
                }
×
UNCOV
234
                installerLabels := util.GetRecommendedInstallerLabelsFromCr(cr)
×
UNCOV
235
                err = install.DumpInstallStrategyToConfigMap(r.client, runtimeObjects, reqLogger, r.namespace, installerLabels)
×
UNCOV
236
                if err != nil {
×
UNCOV
237
                        reqLogger.Error(err, "Failed to dump CDI object in configmap")
×
UNCOV
238
                        return reconcile.Result{}, err
×
UNCOV
239
                }
×
240
        }
241

242
        // Ready metric so we can alert whenever we are not ready for a while
243
        if conditionsv1.IsStatusConditionTrue(cr.Status.Conditions, conditionsv1.ConditionAvailable) {
2✔
244
                metrics.SetReady()
1✔
245
        } else if !conditionsv1.IsStatusConditionTrue(cr.Status.Conditions, conditionsv1.ConditionProgressing) {
3✔
246
                // Not an issue if progress is still ongoing
1✔
247
                metrics.SetNotReady()
1✔
248
        }
1✔
249
        return r.reconciler.Reconcile(request, operatorVersion, reqLogger)
1✔
250
}
251

252
func (r *ReconcileCDI) add(mgr manager.Manager) error {
×
253
        // Create a new controller
×
254
        c, err := controller.New("cdi-operator-controller", mgr, controller.Options{
×
255
                MaxConcurrentReconciles: 3,
×
256
                Reconciler:              r,
×
UNCOV
257
        })
×
258
        if err != nil {
×
259
                return err
×
260
        }
×
261

UNCOV
262
        r.SetController(c)
×
263

×
264
        if err = r.reconciler.WatchCR(); err != nil {
×
265
                return err
×
UNCOV
266
        }
×
267

UNCOV
268
        cm, err := NewCertManager(mgr, r.namespace)
×
UNCOV
269
        if err != nil {
×
UNCOV
270
                return err
×
UNCOV
271
        }
×
272

UNCOV
273
        r.certManager = cm
×
UNCOV
274

×
UNCOV
275
        return nil
×
276
}
277

278
func (r *ReconcileCDI) getCertificateDefinitions(cdi *cdiv1.CDI) []cdicerts.CertificateDefinition {
1✔
279
        args := &cdicerts.FactoryArgs{Namespace: r.namespace}
1✔
280

1✔
281
        if cdi != nil && cdi.Spec.CertConfig != nil {
2✔
282
                if cdi.Spec.CertConfig.CA != nil {
2✔
283
                        if cdi.Spec.CertConfig.CA.Duration != nil {
2✔
284
                                args.SignerDuration = &cdi.Spec.CertConfig.CA.Duration.Duration
1✔
285
                        }
1✔
286

287
                        if cdi.Spec.CertConfig.CA.RenewBefore != nil {
2✔
288
                                args.SignerRenewBefore = &cdi.Spec.CertConfig.CA.RenewBefore.Duration
1✔
289
                        }
1✔
290
                }
291

292
                if cdi.Spec.CertConfig.Server != nil {
2✔
293
                        if cdi.Spec.CertConfig.Server.Duration != nil {
2✔
294
                                args.ServerDuration = &cdi.Spec.CertConfig.Server.Duration.Duration
1✔
295
                        }
1✔
296

297
                        if cdi.Spec.CertConfig.Server.RenewBefore != nil {
2✔
298
                                args.ServerRenewBefore = &cdi.Spec.CertConfig.Server.RenewBefore.Duration
1✔
299
                        }
1✔
300
                }
301

302
                if cdi.Spec.CertConfig.Client != nil {
2✔
303
                        if cdi.Spec.CertConfig.Client.Duration != nil {
2✔
304
                                args.ClientDuration = &cdi.Spec.CertConfig.Client.Duration.Duration
1✔
305
                        }
1✔
306

307
                        if cdi.Spec.CertConfig.Client.RenewBefore != nil {
2✔
308
                                args.ClientRenewBefore = &cdi.Spec.CertConfig.Client.RenewBefore.Duration
1✔
309
                        }
1✔
310
                }
311
        }
312

313
        return cdicerts.CreateCertificateDefinitions(args)
1✔
314
}
315

316
func (r *ReconcileCDI) getConfigMap() (*corev1.ConfigMap, error) {
1✔
317
        cm := &corev1.ConfigMap{}
1✔
318
        key := client.ObjectKey{Name: operator.ConfigMapName, Namespace: r.namespace}
1✔
319

1✔
320
        if err := r.client.Get(context.TODO(), key, cm); err != nil {
2✔
321
                if errors.IsNotFound(err) {
2✔
322
                        return nil, nil
1✔
323
                }
1✔
UNCOV
324
                return nil, err
×
325
        }
326

327
        return cm, nil
1✔
328
}
329

330
// createOperatorConfig creates operator config map
331
func (r *ReconcileCDI) createOperatorConfig(cr client.Object) error {
1✔
332
        cdiCR := cr.(*cdiv1.CDI)
1✔
333
        installerLabels := util.GetRecommendedInstallerLabelsFromCr(cdiCR)
1✔
334

1✔
335
        cm := &corev1.ConfigMap{
1✔
336
                ObjectMeta: metav1.ObjectMeta{
1✔
337
                        Name:      operator.ConfigMapName,
1✔
338
                        Namespace: r.namespace,
1✔
339
                        Labels:    map[string]string{"operator.cdi.kubevirt.io": ""},
1✔
340
                },
1✔
341
        }
1✔
342
        util.SetRecommendedLabels(cm, installerLabels, "cdi-operator")
1✔
343

1✔
344
        if err := controllerutil.SetControllerReference(cr, cm, r.scheme); err != nil {
1✔
UNCOV
345
                return err
×
UNCOV
346
        }
×
347

348
        return r.client.Create(context.TODO(), cm)
1✔
349
}
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