1 package kubedev
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "path/filepath"
8 "reflect"
9 "strings"
10
11 "golang.org/x/sync/errgroup"
12
13 devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
14 "github.com/devfile/library/v2/pkg/devfile/generator"
15 "github.com/devfile/library/v2/pkg/devfile/parser"
16 parsercommon "github.com/devfile/library/v2/pkg/devfile/parser/data/v2/common"
17 devfilefs "github.com/devfile/library/v2/pkg/testingutil/filesystem"
18 dfutil "github.com/devfile/library/v2/pkg/util"
19
20 "github.com/redhat-developer/odo/pkg/component"
21 "github.com/redhat-developer/odo/pkg/dev/common"
22 "github.com/redhat-developer/odo/pkg/dev/kubedev/storage"
23 "github.com/redhat-developer/odo/pkg/dev/kubedev/utils"
24 "github.com/redhat-developer/odo/pkg/devfile/image"
25 "github.com/redhat-developer/odo/pkg/kclient"
26 odolabels "github.com/redhat-developer/odo/pkg/labels"
27 "github.com/redhat-developer/odo/pkg/libdevfile"
28 "github.com/redhat-developer/odo/pkg/log"
29 odocontext "github.com/redhat-developer/odo/pkg/odo/context"
30 "github.com/redhat-developer/odo/pkg/service"
31 storagepkg "github.com/redhat-developer/odo/pkg/storage"
32 "github.com/redhat-developer/odo/pkg/testingutil/filesystem"
33 "github.com/redhat-developer/odo/pkg/util"
34 "github.com/redhat-developer/odo/pkg/watch"
35
36 appsv1 "k8s.io/api/apps/v1"
37 corev1 "k8s.io/api/core/v1"
38 kerrors "k8s.io/apimachinery/pkg/api/errors"
39 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
40 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
41 "k8s.io/klog"
42 "k8s.io/utils/pointer"
43 )
44
45
46
47 func (o *DevClient) createComponents(ctx context.Context, parameters common.PushParameters, componentStatus *watch.ComponentStatus) (bool, error) {
48 var (
49 appName = odocontext.GetApplication(ctx)
50 componentName = odocontext.GetComponentName(ctx)
51 )
52
53
54 err := dfutil.ValidateK8sResourceName("component name", componentName)
55 if err != nil {
56 return false, err
57 }
58
59 err = dfutil.ValidateK8sResourceName("component namespace", o.kubernetesClient.GetCurrentNamespace())
60 if err != nil {
61 return false, err
62 }
63
64 if componentStatus.GetState() == watch.StateSyncOutdated {
65
66 componentStatus.ImageComponentsAutoApplied = make(map[string]devfilev1.ImageComponent)
67 }
68
69 klog.V(4).Infof("component state: %q\n", componentStatus.GetState())
70 err = o.buildPushAutoImageComponents(ctx, o.filesystem, parameters.Devfile, componentStatus)
71 if err != nil {
72 return false, err
73 }
74
75 var deployment *appsv1.Deployment
76 deployment, o.deploymentExists, err = o.getComponentDeployment(ctx)
77 if err != nil {
78 return false, err
79 }
80
81 if componentStatus.GetState() != watch.StateWaitDeployment && componentStatus.GetState() != watch.StateReady {
82 log.SpinnerNoSpin("Waiting for Kubernetes resources")
83 }
84
85
86 runtime := component.GetComponentRuntimeFromDevfileMetadata(parameters.Devfile.Data.GetMetadata())
87 labels := odolabels.GetLabels(componentName, appName, runtime, odolabels.ComponentDevMode, false)
88
89 var updated bool
90 deployment, updated, err = o.createOrUpdateComponent(ctx, parameters, o.deploymentExists, libdevfile.DevfileCommands{
91 BuildCmd: parameters.StartOptions.BuildCommand,
92 RunCmd: parameters.StartOptions.RunCommand,
93 DebugCmd: parameters.StartOptions.DebugCommand,
94 }, deployment)
95 if err != nil {
96 return false, fmt.Errorf("unable to create or update component: %w", err)
97 }
98 ownerReference := generator.GetOwnerReference(deployment)
99
100
101 selector := odolabels.GetSelector(componentName, appName, odolabels.ComponentDevMode, false)
102
103 objectsToRemove, serviceBindingSecretsToRemove, err := o.getRemoteResourcesNotPresentInDevfile(ctx, parameters, selector)
104 if err != nil {
105 return false, fmt.Errorf("unable to determine resources to delete: %w", err)
106 }
107
108 err = o.deleteRemoteResources(objectsToRemove)
109 if err != nil {
110 return false, fmt.Errorf("unable to delete remote resources: %w", err)
111 }
112
113
114
115 if len(serviceBindingSecretsToRemove) != 0 {
116 err = o.deleteServiceBindingSecrets(serviceBindingSecretsToRemove, deployment)
117 if err != nil {
118 return false, fmt.Errorf("unable to delete service binding secrets: %w", err)
119 }
120 }
121
122
123 _, err = o.pushDevfileKubernetesComponents(ctx, parameters, labels, odolabels.ComponentDevMode, ownerReference)
124 if err != nil {
125 return false, err
126 }
127
128 err = o.updatePVCsOwnerReferences(ctx, ownerReference)
129 if err != nil {
130 return false, err
131 }
132
133 if updated {
134 klog.V(4).Infof("Deployment has been updated to generation %d. Waiting new event...\n", deployment.GetGeneration())
135 componentStatus.SetState(watch.StateWaitDeployment)
136 return false, nil
137 }
138
139 numberReplicas := deployment.Status.ReadyReplicas
140 if numberReplicas != 1 {
141 klog.V(4).Infof("Deployment has %d ready replicas. Waiting new event...\n", numberReplicas)
142 componentStatus.SetState(watch.StateWaitDeployment)
143 return false, nil
144 }
145
146 injected, err := o.bindingClient.CheckServiceBindingsInjectionDone(componentName, appName)
147 if err != nil {
148 return false, err
149 }
150
151 if !injected {
152 klog.V(4).Infof("Waiting for all service bindings to be injected...\n")
153 return false, errors.New("some servicebindings are not injected")
154 }
155
156
157 o.portsToForward, err = libdevfile.GetDevfileContainerEndpointMapping(parameters.Devfile, parameters.StartOptions.Debug)
158 if err != nil {
159 return false, err
160 }
161 o.portsChanged = !reflect.DeepEqual(o.portsToForward, o.portForwardClient.GetForwardedPorts())
162
163 if componentStatus.GetState() == watch.StateReady && !o.portsChanged {
164
165 return false, nil
166 }
167 return true, nil
168 }
169
170 func (o *DevClient) buildPushAutoImageComponents(ctx context.Context, fs filesystem.Filesystem, devfileObj parser.DevfileObj, compStatus *watch.ComponentStatus) error {
171 components, err := libdevfile.GetImageComponentsToPushAutomatically(devfileObj)
172 if err != nil {
173 return err
174 }
175
176 for _, c := range components {
177 if c.Image == nil {
178 return fmt.Errorf("component %q should be an Image Component", c.Name)
179 }
180 alreadyApplied, ok := compStatus.ImageComponentsAutoApplied[c.Name]
181 if ok && reflect.DeepEqual(*c.Image, alreadyApplied) {
182 klog.V(1).Infof("Skipping image component %q; already applied and not changed", c.Name)
183 continue
184 }
185
186 err = image.BuildPushSpecificImage(ctx, image.SelectBackend(ctx), fs, c, true)
187 if err != nil {
188 return err
189 }
190 compStatus.ImageComponentsAutoApplied[c.Name] = *c.Image
191 }
192
193
194 devfileHasCompFn := func(n string) bool {
195 for _, c := range components {
196 if c.Name == n {
197 return true
198 }
199 }
200 return false
201 }
202 for n := range compStatus.ImageComponentsAutoApplied {
203 if !devfileHasCompFn(n) {
204 delete(compStatus.ImageComponentsAutoApplied, n)
205 }
206 }
207
208 return nil
209 }
210
211
212
213 func (o *DevClient) getComponentDeployment(ctx context.Context) (*appsv1.Deployment, bool, error) {
214 var (
215 componentName = odocontext.GetComponentName(ctx)
216 appName = odocontext.GetApplication(ctx)
217 )
218
219
220
221
222 selectorLabels := odolabels.GetSelector(componentName, appName, odolabels.ComponentDevMode, true)
223 deployment, err := o.kubernetesClient.GetOneDeploymentFromSelector(selectorLabels)
224
225 if err != nil {
226 if _, ok := err.(*kclient.DeploymentNotFoundError); !ok {
227 return nil, false, fmt.Errorf("unable to determine if component %s exists: %w", componentName, err)
228 }
229 }
230 componentExists := deployment != nil
231 return deployment, componentExists, nil
232 }
233
234
235
236
237 func (o *DevClient) createOrUpdateComponent(
238 ctx context.Context,
239 parameters common.PushParameters,
240 componentExists bool,
241 commands libdevfile.DevfileCommands,
242 deployment *appsv1.Deployment,
243 ) (*appsv1.Deployment, bool, error) {
244
245 var (
246 appName = odocontext.GetApplication(ctx)
247 componentName = odocontext.GetComponentName(ctx)
248 devfilePath = odocontext.GetDevfilePath(ctx)
249 path = filepath.Dir(devfilePath)
250 )
251
252 runtime := component.GetComponentRuntimeFromDevfileMetadata(parameters.Devfile.Data.GetMetadata())
253
254
255 labels := odolabels.GetLabels(componentName, appName, runtime, odolabels.ComponentDevMode, true)
256
257 annotations := make(map[string]string)
258 odolabels.SetProjectType(annotations, component.GetComponentTypeFromDevfileMetadata(parameters.Devfile.Data.GetMetadata()))
259 odolabels.AddCommonAnnotations(annotations)
260 klog.V(4).Infof("We are deploying these annotations: %s", annotations)
261
262 deploymentObjectMeta, err := o.generateDeploymentObjectMeta(ctx, deployment, labels, annotations)
263 if err != nil {
264 return nil, false, err
265 }
266
267 policy, err := o.kubernetesClient.GetCurrentNamespacePolicy()
268 if err != nil {
269 return nil, false, err
270 }
271 podTemplateSpec, err := generator.GetPodTemplateSpec(parameters.Devfile, generator.PodTemplateParams{
272 ObjectMeta: deploymentObjectMeta,
273 PodSecurityAdmissionPolicy: policy,
274 })
275 if err != nil {
276 return nil, false, err
277 }
278 containers := podTemplateSpec.Spec.Containers
279 if len(containers) == 0 {
280 return nil, false, fmt.Errorf("no valid components found in the devfile")
281 }
282
283 initContainers := podTemplateSpec.Spec.InitContainers
284
285 containers, err = utils.UpdateContainersEntrypointsIfNeeded(parameters.Devfile, containers, commands.BuildCmd, commands.RunCmd, commands.DebugCmd)
286 if err != nil {
287 return nil, false, err
288 }
289
290
291 volumes, err := o.buildVolumes(ctx, parameters, containers, initContainers)
292 if err != nil {
293 return nil, false, err
294 }
295 podTemplateSpec.Spec.Volumes = volumes
296
297 selectorLabels := map[string]string{
298 "component": componentName,
299 }
300
301 deployParams := generator.DeploymentParams{
302 TypeMeta: generator.GetTypeMeta(kclient.DeploymentKind, kclient.DeploymentAPIVersion),
303 ObjectMeta: deploymentObjectMeta,
304 PodTemplateSpec: podTemplateSpec,
305 PodSelectorLabels: selectorLabels,
306 Replicas: pointer.Int32(1),
307 }
308
309
310 var originalGeneration int64 = 0
311 if deployment != nil {
312 originalGeneration = deployment.GetGeneration()
313 }
314
315 deployment, err = generator.GetDeployment(parameters.Devfile, deployParams)
316 if err != nil {
317 return nil, false, err
318 }
319 if deployment.Annotations == nil {
320 deployment.Annotations = make(map[string]string)
321 }
322
323 if vcsUri := util.GetGitOriginPath(path); vcsUri != "" {
324 deployment.Annotations["app.openshift.io/vcs-uri"] = vcsUri
325 }
326
327
328 serviceAnnotations := make(map[string]string)
329 serviceAnnotations["service.binding/backend_ip"] = "path={.spec.clusterIP}"
330 serviceAnnotations["service.binding/backend_port"] = "path={.spec.ports},elementType=sliceOfMaps,sourceKey=name,sourceValue=port"
331
332 serviceName, err := util.NamespaceKubernetesObjectWithTrim(componentName, appName, 63)
333 if err != nil {
334 return nil, false, err
335 }
336 serviceObjectMeta := generator.GetObjectMeta(serviceName, o.kubernetesClient.GetCurrentNamespace(), labels, serviceAnnotations)
337 serviceParams := generator.ServiceParams{
338 ObjectMeta: serviceObjectMeta,
339 SelectorLabels: selectorLabels,
340 }
341 svc, err := generator.GetService(parameters.Devfile, serviceParams, parsercommon.DevfileOptions{})
342
343 if err != nil {
344 return nil, false, err
345 }
346 klog.V(2).Infof("Creating deployment %v", deployment.Spec.Template.GetName())
347 klog.V(2).Infof("The component name is %v", componentName)
348 if componentExists {
349
350 klog.V(2).Info("The component already exists, attempting to update it")
351 if o.kubernetesClient.IsSSASupported() {
352 klog.V(4).Info("Applying deployment")
353 deployment, err = o.kubernetesClient.ApplyDeployment(*deployment)
354 } else {
355 klog.V(4).Info("Updating deployment")
356 deployment, err = o.kubernetesClient.UpdateDeployment(*deployment)
357 }
358 if err != nil {
359 return nil, false, err
360 }
361 klog.V(2).Infof("Successfully updated component %v", componentName)
362 ownerReference := generator.GetOwnerReference(deployment)
363 err = o.createOrUpdateServiceForComponent(ctx, svc, ownerReference)
364 if err != nil {
365 return nil, false, err
366 }
367 } else {
368 if o.kubernetesClient.IsSSASupported() {
369 deployment, err = o.kubernetesClient.ApplyDeployment(*deployment)
370 } else {
371 deployment, err = o.kubernetesClient.CreateDeployment(*deployment)
372 }
373
374 if err != nil {
375 return nil, false, err
376 }
377
378 klog.V(2).Infof("Successfully created component %v", componentName)
379 if len(svc.Spec.Ports) > 0 {
380 ownerReference := generator.GetOwnerReference(deployment)
381 originOwnerRefs := svc.OwnerReferences
382 err = o.kubernetesClient.TryWithBlockOwnerDeletion(ownerReference, func(ownerRef metav1.OwnerReference) error {
383 svc.OwnerReferences = append(originOwnerRefs, ownerRef)
384 _, err = o.kubernetesClient.CreateService(*svc)
385 return err
386 })
387 if err != nil {
388 return nil, false, err
389 }
390 klog.V(2).Infof("Successfully created Service for component %s", componentName)
391 }
392
393 }
394 newGeneration := deployment.GetGeneration()
395
396 return deployment, newGeneration != originalGeneration, nil
397 }
398
399
400
401
402 func (o DevClient) getRemoteResourcesNotPresentInDevfile(ctx context.Context, parameters common.PushParameters, selector string) (objectsToRemove, serviceBindingSecretsToRemove []unstructured.Unstructured, err error) {
403 var (
404 devfilePath = odocontext.GetDevfilePath(ctx)
405 path = filepath.Dir(devfilePath)
406 )
407
408 currentNamespace := o.kubernetesClient.GetCurrentNamespace()
409 allRemoteK8sResources, err := o.kubernetesClient.GetAllResourcesFromSelector(selector, currentNamespace)
410 if err != nil {
411 return nil, nil, fmt.Errorf("unable to fetch remote resources: %w", err)
412 }
413
414 var remoteK8sResources []unstructured.Unstructured
415
416 for _, remoteK := range allRemoteK8sResources {
417 if !odolabels.IsCoreComponent(remoteK.GetLabels()) {
418
419
420
421
422 if remoteK.GetDeletionTimestamp() != nil && !odolabels.IsProjectTypeSetInAnnotations(remoteK.GetAnnotations()) {
423 continue
424 }
425 remoteK8sResources = append(remoteK8sResources, remoteK)
426 }
427 }
428
429 var devfileK8sResources []devfilev1.Component
430 devfileK8sResources, err = libdevfile.GetK8sAndOcComponentsToPush(parameters.Devfile, true)
431 if err != nil {
432 return nil, nil, fmt.Errorf("unable to obtain resources from the Devfile: %w", err)
433 }
434
435
436 var devfileK8sResourcesUnstructured []unstructured.Unstructured
437 for _, devfileK := range devfileK8sResources {
438 var devfileKUnstructuredList []unstructured.Unstructured
439 devfileKUnstructuredList, err = libdevfile.GetK8sComponentAsUnstructuredList(parameters.Devfile, devfileK.Name, path, devfilefs.DefaultFs{})
440 if err != nil {
441 return nil, nil, fmt.Errorf("unable to read the resource: %w", err)
442 }
443 devfileK8sResourcesUnstructured = append(devfileK8sResourcesUnstructured, devfileKUnstructuredList...)
444 }
445
446 isSBOSupported, err := o.kubernetesClient.IsServiceBindingSupported()
447 if err != nil {
448 return nil, nil, fmt.Errorf("error in determining support for the Service Binding Operator: %w", err)
449 }
450
451
452 for _, remoteK := range remoteK8sResources {
453 matchFound := false
454 isServiceBindingSecret := false
455 for _, devfileK := range devfileK8sResourcesUnstructured {
456
457 if remoteResourceIsPresentInDevfile := devfileK.GroupVersionKind().GroupKind() == remoteK.GroupVersionKind().GroupKind() &&
458 devfileK.GetName() == remoteK.GetName(); remoteResourceIsPresentInDevfile {
459 matchFound = true
460 break
461 }
462
463
464 if !isSBOSupported && remoteK.GroupVersionKind() == kclient.SecretGVK {
465 if remoteSecretHasLocalServiceBindingOwner := service.IsLinkSecret(remoteK.GetLabels()) &&
466 remoteK.GetLabels()[service.LinkLabel] == devfileK.GetName(); remoteSecretHasLocalServiceBindingOwner {
467 matchFound = true
468 isServiceBindingSecret = true
469 break
470 }
471 }
472 }
473
474 if !matchFound {
475 if isServiceBindingSecret {
476 serviceBindingSecretsToRemove = append(serviceBindingSecretsToRemove, remoteK)
477 } else {
478 objectsToRemove = append(objectsToRemove, remoteK)
479 }
480 }
481 }
482 return objectsToRemove, serviceBindingSecretsToRemove, nil
483 }
484
485
486 func (o DevClient) deleteRemoteResources(objectsToRemove []unstructured.Unstructured) error {
487 if len(objectsToRemove) == 0 {
488 return nil
489 }
490
491 var resources []string
492 for _, u := range objectsToRemove {
493 resources = append(resources, fmt.Sprintf("%s/%s", u.GetKind(), u.GetName()))
494 }
495
496
497 klog.V(3).Infof("Deleting %d resource(s) not present in the Devfile: %s", len(resources), strings.Join(resources, ", "))
498 g := new(errgroup.Group)
499 for _, objectToRemove := range objectsToRemove {
500
501
502 objectToRemove := objectToRemove
503 g.Go(func() error {
504 gvr, err := o.kubernetesClient.GetGVRFromGVK(objectToRemove.GroupVersionKind())
505 if err != nil {
506 return fmt.Errorf("unable to get information about resource: %s/%s: %w", objectToRemove.GetKind(), objectToRemove.GetName(), err)
507 }
508
509 err = o.kubernetesClient.DeleteDynamicResource(objectToRemove.GetName(), gvr, true)
510 if err != nil {
511 if !(kerrors.IsNotFound(err) || kerrors.IsMethodNotSupported(err)) {
512 return fmt.Errorf("unable to delete resource: %s/%s: %w", objectToRemove.GetKind(), objectToRemove.GetName(), err)
513 }
514 klog.V(3).Infof("Failed to delete resource: %s/%s; resource not found or method not supported", objectToRemove.GetKind(), objectToRemove.GetName())
515 }
516
517 return nil
518 })
519 }
520
521 if err := g.Wait(); err != nil {
522 return err
523 }
524
525 return nil
526 }
527
528
529
530 func (o DevClient) deleteServiceBindingSecrets(serviceBindingSecretsToRemove []unstructured.Unstructured, deployment *appsv1.Deployment) error {
531 for _, secretToRemove := range serviceBindingSecretsToRemove {
532 spinner := log.Spinnerf("Deleting Kubernetes resource: %s/%s", secretToRemove.GetKind(), secretToRemove.GetName())
533 defer spinner.End(false)
534
535 err := service.UnbindWithLibrary(o.kubernetesClient, secretToRemove, deployment)
536 if err != nil {
537 return fmt.Errorf("failed to unbind secret %q from the application", secretToRemove.GetName())
538 }
539
540
541
542 err = o.kubernetesClient.DeleteSecret(secretToRemove.GetName(), o.kubernetesClient.GetCurrentNamespace())
543 if err != nil {
544 if !kerrors.IsNotFound(err) {
545 return fmt.Errorf("unable to delete Kubernetes resource: %s/%s: %s", secretToRemove.GetKind(), secretToRemove.GetName(), err.Error())
546 }
547 klog.V(4).Infof("Failed to delete Kubernetes resource: %s/%s; resource not found", secretToRemove.GetKind(), secretToRemove.GetName())
548 }
549 spinner.End(true)
550 }
551 return nil
552 }
553
554
555
556 func (o *DevClient) pushDevfileKubernetesComponents(
557 ctx context.Context,
558 parameters common.PushParameters,
559 labels map[string]string,
560 mode string,
561 reference metav1.OwnerReference,
562 ) ([]devfilev1.Component, error) {
563 var (
564 devfilePath = odocontext.GetDevfilePath(ctx)
565 path = filepath.Dir(devfilePath)
566 )
567
568
569
570 k8sComponents, err := libdevfile.GetK8sAndOcComponentsToPush(parameters.Devfile, false)
571 if err != nil {
572 return nil, fmt.Errorf("error while trying to fetch service(s) from devfile: %w", err)
573 }
574
575
576 err = component.ValidateResourcesExist(o.kubernetesClient, parameters.Devfile, k8sComponents, path)
577 if err != nil {
578 return nil, err
579 }
580
581
582 annotations := make(map[string]string)
583 odolabels.SetProjectType(annotations, component.GetComponentTypeFromDevfileMetadata(parameters.Devfile.Data.GetMetadata()))
584
585
586 err = service.PushKubernetesResources(o.kubernetesClient, parameters.Devfile, k8sComponents, labels, annotations, path, mode, reference)
587 if err != nil {
588 return nil, fmt.Errorf("failed to create Kubernetes resources associated with the component: %w", err)
589 }
590 return k8sComponents, nil
591 }
592
593 func (o *DevClient) updatePVCsOwnerReferences(ctx context.Context, ownerReference metav1.OwnerReference) error {
594 var (
595 componentName = odocontext.GetComponentName(ctx)
596 )
597
598
599 pvcs, err := o.kubernetesClient.ListPVCs(fmt.Sprintf("%v=%v", "component", componentName))
600 if err != nil {
601 return err
602 }
603
604
605 for i := range pvcs {
606 if pvcs[i].OwnerReferences != nil || pvcs[i].DeletionTimestamp != nil {
607 continue
608 }
609 err = o.kubernetesClient.TryWithBlockOwnerDeletion(ownerReference, func(ownerRef metav1.OwnerReference) error {
610 return o.kubernetesClient.UpdateStorageOwnerReference(&pvcs[i], ownerRef)
611 })
612 if err != nil {
613 return err
614 }
615 }
616 return nil
617 }
618
619
620
621 func (o DevClient) generateDeploymentObjectMeta(ctx context.Context, deployment *appsv1.Deployment, labels map[string]string, annotations map[string]string) (metav1.ObjectMeta, error) {
622 var (
623 appName = odocontext.GetApplication(ctx)
624 componentName = odocontext.GetComponentName(ctx)
625 )
626 if deployment != nil {
627 return generator.GetObjectMeta(deployment.Name, o.kubernetesClient.GetCurrentNamespace(), labels, annotations), nil
628 } else {
629 deploymentName, err := util.NamespaceKubernetesObject(componentName, appName)
630 if err != nil {
631 return metav1.ObjectMeta{}, err
632 }
633 return generator.GetObjectMeta(deploymentName, o.kubernetesClient.GetCurrentNamespace(), labels, annotations), nil
634 }
635 }
636
637
638
639
640
641
642
643 func (o *DevClient) buildVolumes(ctx context.Context, parameters common.PushParameters, containers, initContainers []corev1.Container) ([]corev1.Volume, error) {
644 var (
645 appName = odocontext.GetApplication(ctx)
646 componentName = odocontext.GetComponentName(ctx)
647 )
648
649 runtime := component.GetComponentRuntimeFromDevfileMetadata(parameters.Devfile.Data.GetMetadata())
650
651 storageClient := storagepkg.NewClient(componentName, appName, storagepkg.ClientOptions{
652 Client: o.kubernetesClient,
653 Runtime: runtime,
654 })
655
656
657 err := storage.HandleOdoSourceStorage(o.kubernetesClient, storageClient, componentName, o.prefClient.GetEphemeralSourceVolume())
658 if err != nil {
659 return nil, err
660 }
661
662
663
664 ephemerals, err := storagepkg.Push(storageClient, parameters.Devfile)
665 if err != nil {
666 return nil, err
667 }
668
669
670
671 pvcs, err := o.kubernetesClient.ListPVCs(fmt.Sprintf("%v=%v", "component", componentName))
672 if err != nil {
673 return nil, err
674 }
675
676 var allVolumes []corev1.Volume
677
678
679
680 odoSourcePVCName, volumeNameToVolInfo, err := storage.GetVolumeInfos(pvcs)
681 if err != nil {
682 return nil, err
683 }
684
685
686 odoMandatoryVolumes := utils.GetOdoContainerVolumes(odoSourcePVCName)
687 allVolumes = append(allVolumes, odoMandatoryVolumes...)
688
689
690 utils.AddOdoProjectVolume(containers)
691 utils.AddOdoMandatoryVolume(containers)
692
693
694 pvcVolumes, err := storage.GetPersistentVolumesAndVolumeMounts(parameters.Devfile, containers, initContainers, volumeNameToVolInfo, parsercommon.DevfileOptions{})
695 if err != nil {
696 return nil, err
697 }
698 allVolumes = append(allVolumes, pvcVolumes...)
699
700 ephemeralVolumes, err := storage.GetEphemeralVolumesAndVolumeMounts(parameters.Devfile, containers, initContainers, ephemerals, parsercommon.DevfileOptions{})
701 if err != nil {
702 return nil, err
703 }
704 allVolumes = append(allVolumes, ephemeralVolumes...)
705
706 automountVolumes, err := storage.GetAutomountVolumes(o.configAutomountClient, containers, initContainers)
707 if err != nil {
708 return nil, err
709 }
710 allVolumes = append(allVolumes, automountVolumes...)
711
712 return allVolumes, nil
713 }
714
715 func (o *DevClient) createOrUpdateServiceForComponent(ctx context.Context, svc *corev1.Service, ownerReference metav1.OwnerReference) error {
716 var (
717 appName = odocontext.GetApplication(ctx)
718 componentName = odocontext.GetComponentName(ctx)
719 )
720 oldSvc, err := o.kubernetesClient.GetOneService(componentName, appName, true)
721 originOwnerReferences := svc.OwnerReferences
722 if err != nil {
723
724 if len(svc.Spec.Ports) > 0 {
725 err = o.kubernetesClient.TryWithBlockOwnerDeletion(ownerReference, func(ownerRef metav1.OwnerReference) error {
726 svc.OwnerReferences = append(originOwnerReferences, ownerReference)
727 _, err = o.kubernetesClient.CreateService(*svc)
728 return err
729 })
730 if err != nil {
731 return err
732 }
733 klog.V(2).Infof("Successfully created Service for component %s", componentName)
734 }
735 return nil
736 }
737 if len(svc.Spec.Ports) > 0 {
738 svc.Spec.ClusterIP = oldSvc.Spec.ClusterIP
739 svc.ResourceVersion = oldSvc.GetResourceVersion()
740 err = o.kubernetesClient.TryWithBlockOwnerDeletion(ownerReference, func(ownerRef metav1.OwnerReference) error {
741 svc.OwnerReferences = append(originOwnerReferences, ownerRef)
742 _, err = o.kubernetesClient.UpdateService(*svc)
743 return err
744 })
745 if err != nil {
746 return err
747 }
748 klog.V(2).Infof("Successfully update Service for component %s", componentName)
749 return nil
750 }
751
752 return o.kubernetesClient.DeleteService(oldSvc.Name)
753 }
754
View as plain text