From feb49607d423df0dba505c9c32cd370d5cf039eb Mon Sep 17 00:00:00 2001 From: Philippe Martin Date: Thu, 28 Apr 2022 15:51:02 +0200 Subject: [PATCH] Refactor labels (#5618) * refacto labels * Getters * Builder * Do not export labels * Move to pkg/labels + doc * Fix rebase --- pkg/application/labels/labels.go | 61 ------ pkg/application/labels/labels_test.go | 76 ------- pkg/component/component.go | 27 +-- pkg/component/component_test.go | 16 +- pkg/component/delete/delete.go | 9 +- pkg/component/delete/delete_test.go | 12 +- pkg/component/labels/labels.go | 39 ---- pkg/component/labels/labels_test.go | 56 ------ pkg/component/pushed_component.go | 187 ++++++++++++++++++ pkg/deploy/deploy.go | 7 +- .../adapters/kubernetes/component/adapter.go | 17 +- .../kubernetes/component/adapter_test.go | 23 +-- .../adapters/kubernetes/storage/utils.go | 11 +- pkg/kclient/deployments.go | 129 +----------- pkg/kclient/deployments_test.go | 89 --------- pkg/kclient/interface.go | 7 - pkg/kclient/kclient.go | 82 -------- pkg/kclient/kclient_test.go | 22 --- pkg/kclient/mock_Client.go | 100 ---------- pkg/kclient/services.go | 7 +- pkg/kclient/services_test.go | 12 +- pkg/labels/builder.go | 79 ++++++++ pkg/labels/constants.go | 51 +++++ pkg/labels/labels.go | 104 ++++++++++ pkg/labels/labels_test.go | 59 ++++++ pkg/labels/selector_builder.go | 38 ++++ pkg/service/link.go | 7 +- pkg/service/service.go | 5 +- pkg/storage/kubernetes.go | 21 +- pkg/storage/kubernetes_test.go | 46 ++--- pkg/storage/labels/labels.go | 24 --- pkg/storage/labels/labels_test.go | 75 ------- pkg/storage/storage.go | 7 +- pkg/storage/storage_test.go | 6 +- pkg/storage/utils.go | 7 +- pkg/testingutil/deployments.go | 21 +- pkg/testingutil/pods.go | 4 +- pkg/testingutil/services.go | 5 +- tests/helper/helper_kubectl.go | 6 +- tests/helper/helper_oc.go | 5 +- tests/helper/helper_run.go | 10 +- 41 files changed, 640 insertions(+), 929 deletions(-) delete mode 100644 pkg/application/labels/labels.go delete mode 100644 pkg/application/labels/labels_test.go delete mode 100644 pkg/component/labels/labels.go delete mode 100644 pkg/component/labels/labels_test.go create mode 100644 pkg/component/pushed_component.go create mode 100644 pkg/labels/builder.go create mode 100644 pkg/labels/constants.go create mode 100644 pkg/labels/labels.go create mode 100644 pkg/labels/labels_test.go create mode 100644 pkg/labels/selector_builder.go delete mode 100644 pkg/storage/labels/labels.go delete mode 100644 pkg/storage/labels/labels_test.go diff --git a/pkg/application/labels/labels.go b/pkg/application/labels/labels.go deleted file mode 100644 index 98d6d92d8c4..00000000000 --- a/pkg/application/labels/labels.go +++ /dev/null @@ -1,61 +0,0 @@ -package labels - -import ( - "github.com/redhat-developer/odo/pkg/util" - "github.com/redhat-developer/odo/pkg/version" -) - -// ApplicationLabel is label key that is used to group all object that belong to one application -// It should be save to use just this label to filter application -const ApplicationLabel = "app.kubernetes.io/part-of" - -////////////////////////////// -// ADDITIONALLY USED LABELS -////////////////////////////// - -// App is the default name used when labeling -const App = "app" - -// ManagedBy notes that this is managed by odo -const ManagedBy = "app.kubernetes.io/managed-by" - -// ManagerVersion is a Kubernetes label that adds what version of odo is being ran. -const ManagerVersion = "app.kubernetes.io/managed-by-version" - -// GetLabels return labels that identifies given application -// additional labels are used only when creating object -// if you are creating something use additional=true -// if you need labels to filter component then use additional=false -func GetLabels(application string, additional bool) map[string]string { - labels := map[string]string{ - ApplicationLabel: application, - } - - if additional { - labels[App] = application - labels[ManagerVersion] = version.VERSION - labels[ManagedBy] = "odo" - } - - return labels -} - -// GetSelector are supposed to be used for selection of any resource part of an application that is managed by odo -func GetSelector(application string) string { - labels := map[string]string{ - ApplicationLabel: application, - App: application, - ManagedBy: "odo", - } - - return util.ConvertLabelsToSelector(labels) -} - -// GetNonOdoSelector are supposed to be used for selection of any resource part of an application that is not managed by odo -func GetNonOdoSelector(application string) string { - labels := map[string]string{ - ApplicationLabel: application, - ManagedBy: "!odo", - } - return util.ConvertLabelsToSelector(labels) -} diff --git a/pkg/application/labels/labels_test.go b/pkg/application/labels/labels_test.go deleted file mode 100644 index c9a24524dc7..00000000000 --- a/pkg/application/labels/labels_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package labels - -import ( - "fmt" - "reflect" - "strings" - "testing" - - "github.com/redhat-developer/odo/pkg/version" -) - -func TestGetLabels(t *testing.T) { - type args struct { - applicationName string - additional bool - } - tests := []struct { - name string - args args - want map[string]string - }{ - { - name: "Case 1: All labels", - args: args{ - applicationName: "applicationame", - additional: false, - }, - want: map[string]string{ - ApplicationLabel: "applicationame", - }, - }, - { - name: "Case 2: All labels including all additional labels", - args: args{ - - applicationName: "applicationame", - additional: true, - }, - want: map[string]string{ - ApplicationLabel: "applicationame", - App: "applicationame", - ManagedBy: "odo", - ManagerVersion: version.VERSION, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := GetLabels(tt.args.applicationName, tt.args.additional); !reflect.DeepEqual(got, tt.want) { - t.Errorf("GetLabels() = %v, want %v", got, tt.want) - } - }) - } -} - -func TestGetSelector(t *testing.T) { - app := "sample-app" - got := GetSelector(app) - wants := []string{fmt.Sprintf("%v=%v", ApplicationLabel, app), fmt.Sprintf("%v=odo", ManagedBy)} - for _, want := range wants { - if !strings.Contains(got, want) { - t.Errorf("got: %q, want: %q", got, want) - } - } -} - -func TestGetNonOdoSelector(t *testing.T) { - app := "sample-app" - got := GetNonOdoSelector(app) - wants := []string{fmt.Sprintf("%v=%v", ApplicationLabel, app), fmt.Sprintf("%v!=odo", ManagedBy)} - for _, want := range wants { - if !strings.Contains(got, want) { - t.Errorf("got: %q, want: %q", got, want) - } - } -} diff --git a/pkg/component/component.go b/pkg/component/component.go index 7fdc1ad1bee..fee22c5eec2 100644 --- a/pkg/component/component.go +++ b/pkg/component/component.go @@ -11,8 +11,8 @@ import ( "github.com/devfile/library/pkg/devfile/parser" dfutil "github.com/devfile/library/pkg/util" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" corev1 "k8s.io/api/core/v1" "k8s.io/klog" @@ -80,7 +80,7 @@ func Exists(client kclient.ClientInterface, componentName, applicationName strin // GetOnePod gets a pod using the component and app name func GetOnePod(client kclient.ClientInterface, componentName string, appName string) (*corev1.Pod, error) { - return client.GetOnePodFromSelector(componentlabels.GetSelector(componentName, appName)) + return client.GetOnePodFromSelector(odolabels.GetSelector(componentName, appName, odolabels.ComponentDevMode)) } // ComponentExists checks whether a deployment by the given name exists in the given app @@ -149,19 +149,14 @@ func ListAllClusterComponents(client kclient.ClientInterface, namespace string) // Figure out the correct name to use // if there is no instance label, we SKIP the resource as // it is not a component essential for Kubernetes. - var name string - if labels[componentlabels.KubernetesInstanceLabel] != "" { - name = labels[componentlabels.KubernetesInstanceLabel] - } else { + name := odolabels.GetComponentName(labels) + if name == "" { continue } // Get the component type (if there is any..) - var componentType string - switch { - case annotations[componentlabels.OdoProjectTypeAnnotation] != "": - componentType = annotations[componentlabels.OdoProjectTypeAnnotation] - default: + componentType, err := odolabels.GetProjectType(nil, annotations) + if err != nil || componentType == "" { componentType = StateTypeUnknown } @@ -169,11 +164,9 @@ func ListAllClusterComponents(client kclient.ClientInterface, namespace string) // IMPORTANT. If "managed-by" label is BLANK, it is most likely an operator // or a non-component. We do not want to show these in the list of components // so we skip them if there is no "managed-by" label. - var managedBy string - switch { - case labels[componentlabels.KubernetesManagedByLabel] != "": - managedBy = labels[componentlabels.KubernetesManagedByLabel] - default: + + managedBy := odolabels.GetManagedBy(labels) + if managedBy == "" { continue } @@ -183,7 +176,7 @@ func ListAllClusterComponents(client kclient.ClientInterface, namespace string) ManagedBy: managedBy, Type: componentType, } - mode := labels[componentlabels.OdoModeLabel] + mode := odolabels.GetMode(labels) found := false for v, otherCompo := range components { if component.Name == otherCompo.Name { diff --git a/pkg/component/component_test.go b/pkg/component/component_test.go index b1a9cba4309..cf786291137 100644 --- a/pkg/component/component_test.go +++ b/pkg/component/component_test.go @@ -7,8 +7,8 @@ import ( devfilepkg "github.com/devfile/api/v2/pkg/devfile" "github.com/golang/mock/gomock" "github.com/kylelemons/godebug/pretty" - "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/kclient" + "github.com/redhat-developer/odo/pkg/labels" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -263,12 +263,12 @@ func getUnstructured(name, kind, apiVersion, managed, componentType, namespace s u.SetKind(kind) u.SetAPIVersion(apiVersion) u.SetNamespace(namespace) - u.SetLabels(map[string]string{ - labels.KubernetesInstanceLabel: name, - labels.KubernetesManagedByLabel: managed, - }) - u.SetAnnotations(map[string]string{ - labels.OdoProjectTypeAnnotation: componentType, - }) + u.SetLabels(labels.Builder(). + WithComponentName(name). + WithManager(managed). + Labels()) + u.SetAnnotations(labels.Builder(). + WithProjectType(componentType). + Labels()) return } diff --git a/pkg/component/delete/delete.go b/pkg/component/delete/delete.go index f63c3174123..3475c8d2950 100644 --- a/pkg/component/delete/delete.go +++ b/pkg/component/delete/delete.go @@ -11,10 +11,9 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/klog" - applabels "github.com/redhat-developer/odo/pkg/application/labels" "github.com/redhat-developer/odo/pkg/component" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" "github.com/redhat-developer/odo/pkg/libdevfile" "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/util" @@ -34,9 +33,7 @@ func NewDeleteComponentClient(kubeClient kclient.ClientInterface) *DeleteCompone // It only returns resources not owned by another resource of the component, letting the garbage collector do its job func (do *DeleteComponentClient) ListClusterResourcesToDelete(componentName string, namespace string) ([]unstructured.Unstructured, error) { var result []unstructured.Unstructured - labels := componentlabels.GetLabels(componentName, "app", false) - labels[applabels.ManagedBy] = "odo" - selector := util.ConvertLabelsToSelector(labels) + selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentAnyMode) list, err := do.kubeClient.GetAllResourcesFromSelector(selector, namespace) if err != nil { return nil, err @@ -149,7 +146,7 @@ func (do *DeleteComponentClient) ExecutePreStopEvents(devfileObj parser.DevfileO klog.V(4).Infof("Gathering information for component: %q", componentName) klog.V(3).Infof("Checking component status for %q", componentName) - selector := componentlabels.GetSelector(componentName, appName) + selector := odolabels.GetSelector(componentName, appName, odolabels.ComponentDevMode) pod, err := do.kubeClient.GetOnePodFromSelector(selector) if err != nil { klog.V(1).Info("Component not found on the cluster.") diff --git a/pkg/component/delete/delete_test.go b/pkg/component/delete/delete_test.go index c548600ee97..f1548d35ef6 100644 --- a/pkg/component/delete/delete_test.go +++ b/pkg/component/delete/delete_test.go @@ -16,8 +16,8 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime/schema" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" odoTestingUtil "github.com/redhat-developer/odo/pkg/testingutil" "github.com/redhat-developer/odo/pkg/util" ) @@ -498,7 +498,7 @@ func TestDeleteComponentClient_ExecutePreStopEvents(t *testing.T) { kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface { client := kclient.NewMockClientInterface(ctrl) - selector := componentlabels.GetSelector(componentName, "app") + selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode) client.EXPECT().GetOnePodFromSelector(selector).Return(&corev1.Pod{}, &kclient.PodNotFoundError{Selector: selector}) return client }, @@ -515,7 +515,7 @@ func TestDeleteComponentClient_ExecutePreStopEvents(t *testing.T) { kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface { client := kclient.NewMockClientInterface(ctrl) - selector := componentlabels.GetSelector(componentName, "app") + selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode) client.EXPECT().GetOnePodFromSelector(selector).Return(nil, errors.New("some un-ignorable error")) return client }, @@ -532,7 +532,7 @@ func TestDeleteComponentClient_ExecutePreStopEvents(t *testing.T) { kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface { client := kclient.NewMockClientInterface(ctrl) - selector := componentlabels.GetSelector(componentName, "app") + selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode) client.EXPECT().GetOnePodFromSelector(selector).Return(odoTestingUtil.CreateFakePod(componentName, "runtime"), nil) cmd := []string{"/bin/sh", "-c", "cd /projects/nodejs-starter && echo \"Hello World!\""} @@ -553,7 +553,7 @@ func TestDeleteComponentClient_ExecutePreStopEvents(t *testing.T) { kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface { client := kclient.NewMockClientInterface(ctrl) - selector := componentlabels.GetSelector(componentName, "app") + selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode) pod := odoTestingUtil.CreateFakePod(componentName, "runtime") pod.Status.Phase = corev1.PodFailed client.EXPECT().GetOnePodFromSelector(selector).Return(pod, nil) @@ -572,7 +572,7 @@ func TestDeleteComponentClient_ExecutePreStopEvents(t *testing.T) { kubeClient: func(ctrl *gomock.Controller) kclient.ClientInterface { client := kclient.NewMockClientInterface(ctrl) - selector := componentlabels.GetSelector(componentName, "app") + selector := odolabels.GetSelector(componentName, "app", odolabels.ComponentDevMode) client.EXPECT().GetOnePodFromSelector(selector).Return(odoTestingUtil.CreateFakePod(componentName, "runtime"), nil) cmd := []string{"/bin/sh", "-c", "cd /projects/nodejs-starter && echo \"Hello World!\""} diff --git a/pkg/component/labels/labels.go b/pkg/component/labels/labels.go deleted file mode 100644 index ed6f25dbd49..00000000000 --- a/pkg/component/labels/labels.go +++ /dev/null @@ -1,39 +0,0 @@ -package labels - -import ( - applabels "github.com/redhat-developer/odo/pkg/application/labels" - "github.com/redhat-developer/odo/pkg/util" -) - -// KubernetesInstanceLabel is a label key used to identify the component name -const KubernetesInstanceLabel = "app.kubernetes.io/instance" - -// KubernetesManagedByLabel ... -const KubernetesManagedByLabel = "app.kubernetes.io/managed-by" - -// ComponentDevName ... -const ComponentDevName = "Dev" - -// ComponentDeployName ... -const ComponentDeployName = "Deploy" - -// OdoModeLabel ... -const OdoModeLabel = "odo.dev/mode" - -// OdoProjectTypeAnnotation ... -const OdoProjectTypeAnnotation = "odo.dev/project-type" - -// GetLabels return labels that should be applied to every object for given component in active application -// additional labels are used only for creating object -// if you are creating something use additional=true -// if you need labels to filter component then use additional=false -func GetLabels(componentName string, applicationName string, additional bool) map[string]string { - labels := applabels.GetLabels(applicationName, additional) - labels[KubernetesInstanceLabel] = componentName - return labels -} - -// GetSelector are supposed to be used for selection of resources which are a part of the given component -func GetSelector(componentName string, applicationName string) string { - return util.ConvertLabelsToSelector(GetLabels(componentName, applicationName, false)) -} diff --git a/pkg/component/labels/labels_test.go b/pkg/component/labels/labels_test.go deleted file mode 100644 index 4c75094e943..00000000000 --- a/pkg/component/labels/labels_test.go +++ /dev/null @@ -1,56 +0,0 @@ -package labels - -import ( - "reflect" - "testing" - - applabels "github.com/redhat-developer/odo/pkg/application/labels" - "github.com/redhat-developer/odo/pkg/version" -) - -func TestGetLabels(t *testing.T) { - type args struct { - componentName string - applicationName string - additional bool - } - tests := []struct { - name string - args args - want map[string]string - }{ - { - name: "everything filled", - args: args{ - componentName: "componentname", - applicationName: "applicationame", - additional: false, - }, - want: map[string]string{ - applabels.ApplicationLabel: "applicationame", - KubernetesInstanceLabel: "componentname", - }, - }, { - name: "everything with additional", - args: args{ - componentName: "componentname", - applicationName: "applicationame", - additional: true, - }, - want: map[string]string{ - applabels.ApplicationLabel: "applicationame", - applabels.App: "applicationame", - applabels.ManagedBy: "odo", - applabels.ManagerVersion: version.VERSION, - KubernetesInstanceLabel: "componentname", - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := GetLabels(tt.args.componentName, tt.args.applicationName, tt.args.additional); !reflect.DeepEqual(got, tt.want) { - t.Errorf("GetLabels() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/component/pushed_component.go b/pkg/component/pushed_component.go new file mode 100644 index 00000000000..9d3ca06a3bb --- /dev/null +++ b/pkg/component/pushed_component.go @@ -0,0 +1,187 @@ +package component + +import ( + "errors" + "fmt" + + "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" + "github.com/redhat-developer/odo/pkg/storage" + v1 "k8s.io/api/apps/v1" + v12 "k8s.io/api/core/v1" + kerrors "k8s.io/apimachinery/pkg/api/errors" +) + +type provider interface { + GetLabels() map[string]string + GetAnnotations() map[string]string + GetName() string + GetEnvVars() []v12.EnvVar + GetLinkedSecrets() []SecretMount +} + +// PushedComponent is an abstraction over the cluster representation of the component +type PushedComponent interface { + provider + GetApplication() string + GetType() (string, error) + GetStorage() ([]storage.Storage, error) +} + +type defaultPushedComponent struct { + application string + storage []storage.Storage + provider provider + client kclient.ClientInterface + storageClient storage.Client +} + +func (d defaultPushedComponent) GetLabels() map[string]string { + return d.provider.GetLabels() +} + +func (d defaultPushedComponent) GetAnnotations() map[string]string { + return d.provider.GetAnnotations() +} + +func (d defaultPushedComponent) GetName() string { + return d.provider.GetName() +} + +func (d defaultPushedComponent) GetType() (string, error) { + return getType(d.provider) +} + +func (d defaultPushedComponent) GetEnvVars() []v12.EnvVar { + return d.provider.GetEnvVars() +} + +func (d defaultPushedComponent) GetLinkedSecrets() []SecretMount { + return d.provider.GetLinkedSecrets() +} + +// GetStorage gets the storage using the storage client of the given pushed component +func (d defaultPushedComponent) GetStorage() ([]storage.Storage, error) { + if d.storage == nil { + if _, ok := d.provider.(*devfileComponent); ok { + storageList, err := d.storageClient.ListFromCluster() + if err != nil { + return nil, err + } + d.storage = storageList.Items + } + } + return d.storage, nil +} + +func (d defaultPushedComponent) GetApplication() string { + return d.application +} + +type devfileComponent struct { + d v1.Deployment +} + +func (d devfileComponent) GetLinkedSecrets() (secretMounts []SecretMount) { + for _, container := range d.d.Spec.Template.Spec.Containers { + for _, env := range container.EnvFrom { + if env.SecretRef != nil { + secretMounts = append(secretMounts, SecretMount{ + SecretName: env.SecretRef.Name, + MountVolume: false, + }) + } + } + } + + for _, volume := range d.d.Spec.Template.Spec.Volumes { + if volume.Secret != nil { + mountPath := "" + for _, container := range d.d.Spec.Template.Spec.Containers { + for _, mount := range container.VolumeMounts { + if mount.Name == volume.Name { + mountPath = mount.MountPath + break + } + } + } + secretMounts = append(secretMounts, SecretMount{ + SecretName: volume.Secret.SecretName, + MountVolume: true, + MountPath: mountPath, + }) + } + } + + return secretMounts +} + +func (d devfileComponent) GetEnvVars() []v12.EnvVar { + var envs []v12.EnvVar + for _, container := range d.d.Spec.Template.Spec.Containers { + envs = append(envs, container.Env...) + } + return envs +} + +func (d devfileComponent) GetLabels() map[string]string { + return d.d.Labels +} +func (d devfileComponent) GetAnnotations() map[string]string { + return d.d.Annotations +} + +func (d devfileComponent) GetName() string { + return odolabels.GetComponentName(d.d.Labels) +} + +func getType(component provider) (string, error) { + res, err := odolabels.GetProjectType(component.GetLabels(), component.GetAnnotations()) + if err != nil { + return "", fmt.Errorf("%s component doesn't provide a type annotation; consider pushing the component again", component.GetName()) + } + return res, nil +} + +func newPushedComponent(applicationName string, p provider, c kclient.ClientInterface, storageClient storage.Client) PushedComponent { + return &defaultPushedComponent{ + application: applicationName, + provider: p, + client: c, + storageClient: storageClient, + } +} + +// GetPushedComponent returns an abstraction over the cluster representation of the component +func GetPushedComponent(c kclient.ClientInterface, componentName, applicationName string) (PushedComponent, error) { + d, err := c.GetOneDeployment(componentName, applicationName) + if err != nil { + if isIgnorableError(err) { + return nil, nil + } + return nil, err + } + storageClient := storage.NewClient(storage.ClientOptions{ + Client: c, + Deployment: d, + }) + + return newPushedComponent(applicationName, &devfileComponent{d: *d}, c, storageClient), nil +} + +func isIgnorableError(err error) bool { + for { + e := errors.Unwrap(err) + if e != nil { + err = e + } else { + break + } + } + + if _, ok := err.(*kclient.DeploymentNotFoundError); ok { + return true + } + return kerrors.IsNotFound(err) || kerrors.IsForbidden(err) || kerrors.IsUnauthorized(err) + +} diff --git a/pkg/deploy/deploy.go b/pkg/deploy/deploy.go index c6269c9ed22..489d3065a91 100644 --- a/pkg/deploy/deploy.go +++ b/pkg/deploy/deploy.go @@ -11,9 +11,9 @@ import ( "k8s.io/klog" "github.com/redhat-developer/odo/pkg/component" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/devfile/image" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" "github.com/redhat-developer/odo/pkg/libdevfile" "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/service" @@ -66,14 +66,13 @@ func (o *deployHandler) ApplyKubernetes(kubernetes v1alpha2.Component) error { // Get the most common labels that's applicable to all resources being deployed. // Set the mode to DEPLOY. Regardless of what Kubernetes resource we are deploying. - labels := componentlabels.GetLabels(o.devfileObj.Data.GetMetadata().Name, o.appName, true) - labels[componentlabels.OdoModeLabel] = componentlabels.ComponentDeployName + labels := odolabels.GetLabels(o.devfileObj.Data.GetMetadata().Name, o.appName, odolabels.ComponentDeployMode) klog.V(4).Infof("Injecting labels: %+v into k8s artifact", labels) // Create the annotations // Retrieve the component type from the devfile and also inject it into the list of annotations annotations := make(map[string]string) - annotations[componentlabels.OdoProjectTypeAnnotation] = component.GetComponentTypeFromDevfileMetadata(o.devfileObj.Data.GetMetadata()) + odolabels.SetProjectType(annotations, component.GetComponentTypeFromDevfileMetadata(o.devfileObj.Data.GetMetadata())) // Get the Kubernetes component u, err := libdevfile.GetK8sComponentAsUnstructured(kubernetes.Kubernetes, o.path, devfilefs.DefaultFs{}) diff --git a/pkg/devfile/adapters/kubernetes/component/adapter.go b/pkg/devfile/adapters/kubernetes/component/adapter.go index 093e507e77e..cb4ef5c6def 100644 --- a/pkg/devfile/adapters/kubernetes/component/adapter.go +++ b/pkg/devfile/adapters/kubernetes/component/adapter.go @@ -12,13 +12,13 @@ import ( "github.com/devfile/library/pkg/devfile/generator" "github.com/redhat-developer/odo/pkg/component" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/devfile" "github.com/redhat-developer/odo/pkg/devfile/adapters/common" "github.com/redhat-developer/odo/pkg/devfile/adapters/kubernetes/storage" "github.com/redhat-developer/odo/pkg/devfile/adapters/kubernetes/utils" "github.com/redhat-developer/odo/pkg/envinfo" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" "github.com/redhat-developer/odo/pkg/libdevfile" "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/preference" @@ -114,9 +114,8 @@ func (a Adapter) Push(parameters common.PushParameters) (err error) { // Get the Dev deployment: // Since `odo deploy` can theoretically deploy a deployment as well with the same instance name // we make sure that we are retrieving the deployment with the Dev mode, NOT Deploy. - selectorLabels := componentlabels.GetLabels(a.ComponentName, a.AppName, false) - selectorLabels[componentlabels.OdoModeLabel] = componentlabels.ComponentDevName - a.deployment, err = a.Client.GetOneDeploymentFromSelector(util.ConvertLabelsToSelector(selectorLabels)) + selectorLabels := odolabels.GetSelector(a.ComponentName, a.AppName, odolabels.ComponentDevMode) + a.deployment, err = a.Client.GetOneDeploymentFromSelector(selectorLabels) if err != nil { if _, ok := err.(*kclient.DeploymentNotFoundError); !ok { @@ -167,12 +166,11 @@ func (a Adapter) Push(parameters common.PushParameters) (err error) { } // Set the mode to Dev since we are using "odo dev" here - labels := componentlabels.GetLabels(a.ComponentName, a.AppName, true) - labels[componentlabels.OdoModeLabel] = componentlabels.ComponentDevName + labels := odolabels.GetLabels(a.ComponentName, a.AppName, odolabels.ComponentDevMode) // Set the annotations for the component type annotations := make(map[string]string) - annotations[componentlabels.OdoProjectTypeAnnotation] = component.GetComponentTypeFromDevfileMetadata(a.AdapterContext.Devfile.Data.GetMetadata()) + odolabels.SetProjectType(annotations, component.GetComponentTypeFromDevfileMetadata(a.AdapterContext.Devfile.Data.GetMetadata())) previousMode := parameters.EnvSpecificInfo.GetRunMode() currentMode := envinfo.Run @@ -423,12 +421,11 @@ func (a *Adapter) createOrUpdateComponent(componentExists bool, ei envinfo.EnvSp } // Set the labels - labels := componentlabels.GetLabels(componentName, a.AppName, true) - labels[componentlabels.OdoModeLabel] = componentlabels.ComponentDevName + labels := odolabels.GetLabels(componentName, a.AppName, odolabels.ComponentDevMode) labels["component"] = componentName annotations := make(map[string]string) - annotations[componentlabels.OdoProjectTypeAnnotation] = component.GetComponentTypeFromDevfileMetadata(a.AdapterContext.Devfile.Data.GetMetadata()) + odolabels.SetProjectType(annotations, component.GetComponentTypeFromDevfileMetadata(a.AdapterContext.Devfile.Data.GetMetadata())) klog.V(4).Infof("We are deploying these annotations: %s", annotations) containers, err := generator.GetContainers(a.Devfile, parsercommon.DevfileOptions{}) diff --git a/pkg/devfile/adapters/kubernetes/component/adapter_test.go b/pkg/devfile/adapters/kubernetes/component/adapter_test.go index ac731bb9133..d5968190b72 100644 --- a/pkg/devfile/adapters/kubernetes/component/adapter_test.go +++ b/pkg/devfile/adapters/kubernetes/component/adapter_test.go @@ -18,11 +18,9 @@ import ( devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" devfileParser "github.com/devfile/library/pkg/devfile/parser" "github.com/devfile/library/pkg/testingutil" - applabels "github.com/redhat-developer/odo/pkg/application/labels" - componentLabels "github.com/redhat-developer/odo/pkg/component/labels" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" adaptersCommon "github.com/redhat-developer/odo/pkg/devfile/adapters/common" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" odoTestingUtil "github.com/redhat-developer/odo/pkg/testingutil" v1 "k8s.io/api/apps/v1" @@ -43,14 +41,9 @@ func TestCreateOrUpdateComponent(t *testing.T) { APIVersion: kclient.DeploymentAPIVersion, }, ObjectMeta: metav1.ObjectMeta{ - Name: testComponentName, - Labels: map[string]string{ - applabels.ApplicationLabel: testAppName, - componentLabels.KubernetesInstanceLabel: testComponentName, - }, - Annotations: map[string]string{ - componentLabels.OdoProjectTypeAnnotation: "", - }, + Name: testComponentName, + Labels: odolabels.Builder().WithComponentName(testComponentName).WithAppName(testAppName).Labels(), + Annotations: odolabels.Builder().WithProjectType("").Labels(), }, } @@ -94,7 +87,7 @@ func TestCreateOrUpdateComponent(t *testing.T) { t.Run(tt.name, func(t *testing.T) { var comp devfilev1.Component if tt.componentType != "" { - deployment.Annotations[componentLabels.OdoProjectTypeAnnotation] = string(tt.componentType) + odolabels.SetProjectType(deployment.Annotations, string(tt.componentType)) comp = testingutil.GetFakeContainerComponent("component") } devObj := devfileParser.DevfileObj{ @@ -374,7 +367,7 @@ func TestDoesComponentExist(t *testing.T) { }) // Verify that a component with the specified name exists - componentExists, err := component.ComponentExists(fkclient, tt.getComponentName, "") + componentExists, err := component.ComponentExists(fkclient, tt.getComponentName, tt.appName) if !tt.wantErr && err != nil { t.Errorf("unexpected error: %v", err) } else if !tt.wantErr && componentExists != tt.want { @@ -543,9 +536,9 @@ func TestAdapter_generateDeploymentObjectMeta(t *testing.T) { }, args: args{ labels: odoTestingUtil.CreateFakeDeployment("nodejs").Labels, - annotations: map[string]string{componentlabels.OdoModeLabel: componentlabels.ComponentDevName}, + annotations: odolabels.Builder().WithMode(odolabels.ComponentDevMode).Labels(), }, - want: generator.GetObjectMeta("nodejs", "project-0", odoTestingUtil.CreateFakeDeployment("nodejs").Labels, map[string]string{componentlabels.OdoModeLabel: componentlabels.ComponentDevName}), + want: generator.GetObjectMeta("nodejs", "project-0", odoTestingUtil.CreateFakeDeployment("nodejs").Labels, odolabels.Builder().WithMode(odolabels.ComponentDevMode).Labels()), wantErr: false, }, } diff --git a/pkg/devfile/adapters/kubernetes/storage/utils.go b/pkg/devfile/adapters/kubernetes/storage/utils.go index 5e542ae351c..567d9091628 100644 --- a/pkg/devfile/adapters/kubernetes/storage/utils.go +++ b/pkg/devfile/adapters/kubernetes/storage/utils.go @@ -9,11 +9,10 @@ import ( parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common" dfutil "github.com/devfile/library/pkg/util" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" "github.com/redhat-developer/odo/pkg/storage" storagepkg "github.com/redhat-developer/odo/pkg/storage" - storagelabels "github.com/redhat-developer/odo/pkg/storage/labels" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" @@ -42,12 +41,13 @@ func GetVolumeInfos(pvcs []corev1.PersistentVolumeClaim) (odoSourcePVCName strin return "", nil, fmt.Errorf("unable to generate volume name from pvc name: %w", e) } - if pvc.Labels[storagelabels.StorageLabel] == storagepkg.OdoSourceVolume { + storageName := odolabels.GetStorageName(pvc.Labels) + if storageName == storagepkg.OdoSourceVolume { odoSourcePVCName = pvc.Name continue } - infos[pvc.Labels[storagelabels.StorageLabel]] = VolumeInfo{ + infos[storageName] = VolumeInfo{ PVCName: pvc.Name, VolumeName: generatedVolumeName, } @@ -187,8 +187,7 @@ func generateVolumeNameFromPVC(pvc string) (volumeName string, err error) { // HandleEphemeralStorage creates or deletes the ephemeral volume based on the preference setting func HandleEphemeralStorage(client kclient.ClientInterface, storageClient storage.Client, componentName string, isEphemeral bool) error { - selector := fmt.Sprintf("%v=%s,%s=%s", componentlabels.KubernetesInstanceLabel, componentName, storagelabels.SourcePVCLabel, storage.OdoSourceVolume) - + selector := odolabels.Builder().WithComponentName(componentName).WithSourcePVC(storage.OdoSourceVolume).Selector() pvcs, err := client.ListPVCs(selector) if err != nil && !kerrors.IsNotFound(err) { return err diff --git a/pkg/kclient/deployments.go b/pkg/kclient/deployments.go index 7db5d518407..1e389f75079 100644 --- a/pkg/kclient/deployments.go +++ b/pkg/kclient/deployments.go @@ -5,9 +5,9 @@ import ( "encoding/json" "errors" "fmt" - "sort" "time" + odolabels "github.com/redhat-developer/odo/pkg/labels" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" @@ -16,11 +16,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/klog" - "github.com/redhat-developer/odo/pkg/util" - apiMachineryWatch "k8s.io/apimachinery/pkg/watch" - - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" ) func boolPtr(b bool) *bool { @@ -47,9 +43,7 @@ func (c *Client) GetDeploymentByName(name string) (*appsv1.Deployment, error) { // GetOneDeployment returns the Deployment object associated with the given component and app func (c *Client) GetOneDeployment(componentName, appName string) (*appsv1.Deployment, error) { - labels := componentlabels.GetLabels(componentName, appName, false) - labels[componentlabels.OdoModeLabel] = componentlabels.ComponentDevName - selector := util.ConvertLabelsToSelector(labels) + selector := odolabels.GetSelector(componentName, appName, odolabels.ComponentDevMode) return c.GetOneDeploymentFromSelector(selector) } @@ -106,14 +100,6 @@ func getDeploymentCondition(status appsv1.DeploymentStatus, condType appsv1.Depl return nil } -// ListDeployments lists all deployments by selector -func (c *Client) ListDeployments(selector string) (*appsv1.DeploymentList, error) { - - return c.KubeClient.AppsV1().Deployments(c.Namespace).List(context.TODO(), metav1.ListOptions{ - LabelSelector: selector, - }) -} - // WaitForPodDeletion waits for the given pod to be deleted func (c *Client) WaitForPodDeletion(name string) error { watch, err := c.KubeClient.CoreV1().Pods(c.Namespace).Watch(context.TODO(), metav1.ListOptions{FieldSelector: "metadata.name=" + name}) @@ -302,117 +288,6 @@ func (c *Client) removeDuplicateEnv(deploymentName string) error { return nil } -// DeleteDeployment deletes the deployments with the given selector -func (c *Client) DeleteDeployment(labels map[string]string) error { - if labels == nil { - return errors.New("labels for deletion are empty") - } - // convert labels to selector - selector := util.ConvertLabelsToSelector(labels) - klog.V(3).Infof("Selectors used for deletion: %s", selector) - - // Delete Deployment - klog.V(3).Info("Deleting Deployment") - - return c.KubeClient.AppsV1().Deployments(c.Namespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: selector}) -} - -// Define a function that is meant to create patch based on the contents of the deployment -type deploymentPatchProvider func(deployment *appsv1.Deployment) (string, error) - -// LinkSecret links a secret to the Deployment of a component -func (c *Client) LinkSecret(secretName, componentName, applicationName string) error { - - var deploymentPatchProvider = func(d *appsv1.Deployment) (string, error) { - if len(d.Spec.Template.Spec.Containers[0].EnvFrom) > 0 { - // we always add the link as the first value in the envFrom array. That way we don't need to know the existing value - return fmt.Sprintf(`[{ "op": "add", "path": "/spec/template/spec/containers/0/envFrom/0", "value": {"secretRef": {"name": "%s"}} }]`, secretName), nil - } - - // in this case we need to add the full envFrom value - return fmt.Sprintf(`[{ "op": "add", "path": "/spec/template/spec/containers/0/envFrom", "value": [{"secretRef": {"name": "%s"}}] }]`, secretName), nil - } - - return c.jsonPatchDeployment(componentlabels.GetSelector(componentName, applicationName), deploymentPatchProvider) -} - -// UnlinkSecret unlinks a secret to the Deployment of a component -func (c *Client) UnlinkSecret(secretName, componentName, applicationName string) error { - // Remove the Secret from the container - var deploymentPatchProvider = func(d *appsv1.Deployment) (string, error) { - indexForRemoval := -1 - for i, env := range d.Spec.Template.Spec.Containers[0].EnvFrom { - if env.SecretRef.Name == secretName { - indexForRemoval = i - break - } - } - - if indexForRemoval == -1 { - return "", fmt.Errorf("deployment does not contain a link to %s", secretName) - } - - return fmt.Sprintf(`[{"op": "remove", "path": "/spec/template/spec/containers/0/envFrom/%d"}]`, indexForRemoval), nil - } - - return c.jsonPatchDeployment(componentlabels.GetSelector(componentName, applicationName), deploymentPatchProvider) -} - -// jsonPatchDeployment will look up the appropriate Deployment, and execute the specified patch -// the whole point of using patch is to avoid race conditions where we try to update -// deployment while it's being simultaneously updated from another source (for example Kubernetes itself) -// this will result in the triggering of a redeployment -func (c *Client) jsonPatchDeployment(deploymentSelector string, deploymentPatchProvider deploymentPatchProvider) error { - - deployment, err := c.GetOneDeploymentFromSelector(deploymentSelector) - if err != nil { - return fmt.Errorf("unable to locate Deployment with selector %q: %w", deploymentSelector, err) - } - - if deploymentPatchProvider != nil { - patch, e := deploymentPatchProvider(deployment) - if e != nil { - return fmt.Errorf("unable to create a patch for the Deployment: %w", e) - } - - // patch the Deployment with the secret - _, e = c.KubeClient.AppsV1().Deployments(c.Namespace).Patch(context.TODO(), deployment.Name, types.JSONPatchType, []byte(patch), metav1.PatchOptions{FieldManager: FieldManager}) - if e != nil { - return fmt.Errorf("deployment not patched %s: %w", deployment.Name, e) - } - } else { - return errors.New("deploymentPatch was not properly set") - } - - return nil -} - -// GetDeploymentLabelValues get label values of given label from objects in project that are matching selector -// returns slice of unique label values -func (c *Client) GetDeploymentLabelValues(label string, selector string) ([]string, error) { - - // List Deployment according to selectors - deploymentList, err := c.appsClient.Deployments(c.Namespace).List(context.TODO(), metav1.ListOptions{LabelSelector: selector}) - if err != nil { - return nil, fmt.Errorf("unable to list DeploymentConfigs: %w", err) - } - - // Grab all the matched strings - var values []string - for _, elem := range deploymentList.Items { - for key, val := range elem.Labels { - if key == label { - values = append(values, val) - } - } - } - - // Sort alphabetically - sort.Strings(values) - - return values, nil -} - // GetDeploymentAPIVersion returns a map with Group, Version, Resource information of Deployment objects // depending on the GVR supported by the cluster func (c *Client) GetDeploymentAPIVersion() (metav1.GroupVersionResource, error) { diff --git a/pkg/kclient/deployments_test.go b/pkg/kclient/deployments_test.go index e696b2c6e1b..7b4b0f7f8c1 100644 --- a/pkg/kclient/deployments_test.go +++ b/pkg/kclient/deployments_test.go @@ -2,8 +2,6 @@ package kclient import ( "errors" - "fmt" - reflect "reflect" "testing" devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" @@ -14,7 +12,6 @@ import ( "github.com/devfile/library/pkg/testingutil" odoTestingUtil "github.com/redhat-developer/odo/pkg/testingutil" - "github.com/redhat-developer/odo/pkg/util" appsv1 "k8s.io/api/apps/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -272,89 +269,3 @@ func TestUpdateDeployment(t *testing.T) { }) } } - -func TestDeleteDeployment(t *testing.T) { - type args struct { - labels map[string]string - } - tests := []struct { - name string - args args - wantErr bool - }{ - { - name: "case 1: normal delete with labels", - args: args{labels: map[string]string{ - "component": "frontend", - }}, - wantErr: false, - }, - { - name: "case 2: delete with empty labels", - args: args{labels: nil}, - wantErr: true, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - // initialising the fakeclient - fkclient, fkclientset := FakeNew() - fkclient.Namespace = "default" - - fkclientset.Kubernetes.PrependReactor("delete-collection", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) { - if util.ConvertLabelsToSelector(tt.args.labels) != action.(ktesting.DeleteCollectionAction).GetListRestrictions().Labels.String() { - return true, nil, fmt.Errorf("collection labels are not matching, wanted: %v, got: %v", util.ConvertLabelsToSelector(tt.args.labels), action.(ktesting.DeleteCollectionAction).GetListRestrictions().Labels.String()) - } - return true, nil, nil - }) - - if err := fkclient.DeleteDeployment(tt.args.labels); (err != nil) != tt.wantErr { - t.Errorf("DeleteDeployment() error = %v, wantErr %v", err, tt.wantErr) - } - }) - } -} - -func TestGetDeploymentLabelValues(t *testing.T) { - fkclient, fkclientset := FakeNew() - fkclient.Namespace = "default" - fkclientset.Kubernetes.PrependReactor("list", "deployments", func(action ktesting.Action) (bool, runtime.Object, error) { - depList := appsv1.DeploymentList{ - Items: []appsv1.Deployment{ - { - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "a-selector": "sel-value", - "a-label": "a-value", - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "a-selector": "sel-value-2", - "a-label": "a-value-2", - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Labels: map[string]string{ - "other-selector": "sel-value", - "a-label": "another-value", - }, - }, - }, - }, - } - return true, &depList, nil - }) - result, err := fkclient.GetDeploymentLabelValues("a-label", "a-selector") - expected := []string{"a-value", "a-value-2"} - if !reflect.DeepEqual(result, expected) { - t.Errorf("Expected %v, got %v", expected, result) - } - if err != nil { - t.Errorf("Expected no error, got %s", err) - } -} diff --git a/pkg/kclient/interface.go b/pkg/kclient/interface.go index a65390b0456..aed7a0665f6 100644 --- a/pkg/kclient/interface.go +++ b/pkg/kclient/interface.go @@ -32,16 +32,11 @@ type ClientInterface interface { GetOneDeployment(componentName, appName string) (*appsv1.Deployment, error) GetOneDeploymentFromSelector(selector string) (*appsv1.Deployment, error) GetDeploymentFromSelector(selector string) ([]appsv1.Deployment, error) - ListDeployments(selector string) (*appsv1.DeploymentList, error) WaitForPodDeletion(name string) error WaitForDeploymentRollout(deploymentName string) (*appsv1.Deployment, error) CreateDeployment(deploy appsv1.Deployment) (*appsv1.Deployment, error) UpdateDeployment(deploy appsv1.Deployment) (*appsv1.Deployment, error) ApplyDeployment(deploy appsv1.Deployment) (*appsv1.Deployment, error) - DeleteDeployment(labels map[string]string) error - LinkSecret(secretName, componentName, applicationName string) error - UnlinkSecret(secretName, componentName, applicationName string) error - GetDeploymentLabelValues(label string, selector string) ([]string, error) GetDeploymentAPIVersion() (metav1.GroupVersionResource, error) IsDeploymentExtensionsV1Beta1() (bool, error) @@ -60,8 +55,6 @@ type ClientInterface interface { GetConfig() clientcmd.ClientConfig GetClientConfig() *rest.Config GetDynamicClient() dynamic.Interface - Delete(labels map[string]string, wait bool) error - WaitForComponentDeletion(selector string) error GeneratePortForwardReq(podName string) *rest.Request SetDiscoveryInterface(client discovery.DiscoveryInterface) IsResourceSupported(apiGroup, apiVersion, resourceName string) (bool, error) diff --git a/pkg/kclient/kclient.go b/pkg/kclient/kclient.go index 535e62b15ae..3bbbad5ab62 100644 --- a/pkg/kclient/kclient.go +++ b/pkg/kclient/kclient.go @@ -1,20 +1,13 @@ package kclient import ( - "context" - "errors" "fmt" "strings" - "time" "github.com/blang/semver" - "github.com/redhat-developer/odo/pkg/util" - - appsv1 "k8s.io/api/apps/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" @@ -40,8 +33,6 @@ Please ensure you have an active kubernetes context to your cluster. Consult your Kubernetes distribution's documentation for more details. Error: %w ` - waitForComponentDeletionTimeout = 120 * time.Second - defaultQPS = 200 defaultBurst = 200 ) @@ -181,79 +172,6 @@ func NewForConfig(config clientcmd.ClientConfig) (client *Client, err error) { return client, nil } -// Delete takes labels as a input and based on it, deletes respective resource -func (c *Client) Delete(labels map[string]string, wait bool) error { - - // convert labels to selector - selector := util.ConvertLabelsToSelector(labels) - klog.V(3).Infof("Selectors used for deletion: %s", selector) - - var errorList []string - var deletionPolicy = metav1.DeletePropagationBackground - - // for --wait flag, it deletes component dependents first and then delete component - if wait { - deletionPolicy = metav1.DeletePropagationForeground - } - // Delete Deployments - klog.V(3).Info("Deleting Deployments") - err := c.appsClient.Deployments(c.Namespace).DeleteCollection(context.TODO(), metav1.DeleteOptions{PropagationPolicy: &deletionPolicy}, metav1.ListOptions{LabelSelector: selector}) - if err != nil { - errorList = append(errorList, "unable to delete deployments") - } - - // for --wait it waits for component to be deleted - // TODO: Need to modify for `odo app delete`, currently wait flag is added only in `odo component delete` - // so only one component gets passed in selector - if wait { - err = c.WaitForComponentDeletion(selector) - if err != nil { - errorList = append(errorList, err.Error()) - } - } - - // Error string - errString := strings.Join(errorList, ",") - if len(errString) != 0 { - return errors.New(errString) - } - return nil - -} - -// WaitForComponentDeletion waits for component to be deleted -func (c *Client) WaitForComponentDeletion(selector string) error { - - klog.V(3).Infof("Waiting for component to get deleted") - - watcher, err := c.appsClient.Deployments(c.Namespace).Watch(context.TODO(), metav1.ListOptions{LabelSelector: selector}) - if err != nil { - return err - } - defer watcher.Stop() - eventCh := watcher.ResultChan() - - for { - select { - case event, ok := <-eventCh: - _, typeOk := event.Object.(*appsv1.Deployment) - if !ok || !typeOk { - return errors.New("unable to watch deployments") - } - if event.Type == watch.Deleted { - klog.V(3).Infof("WaitForComponentDeletion, Event Received:Deleted") - return nil - } else if event.Type == watch.Error { - klog.V(3).Infof("WaitForComponentDeletion, Event Received:Deleted ") - return errors.New("unable to watch deployments") - } - case <-time.After(waitForComponentDeletionTimeout): - klog.V(3).Infof("WaitForComponentDeletion, Timeout") - return errors.New("timed out waiting for component to get deleted") - } - } -} - // GeneratePortForwardReq builds a port forward request func (c *Client) GeneratePortForwardReq(podName string) *rest.Request { return c.KubeClient.CoreV1().RESTClient(). diff --git a/pkg/kclient/kclient_test.go b/pkg/kclient/kclient_test.go index 981950ea71f..61d0f703997 100644 --- a/pkg/kclient/kclient_test.go +++ b/pkg/kclient/kclient_test.go @@ -1,15 +1,12 @@ package kclient import ( - "errors" "fmt" "runtime" "testing" - kruntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/version" "k8s.io/client-go/discovery/fake" - ktesting "k8s.io/client-go/testing" ) func (c *fakeDiscovery) ServerVersion() (*version.Info, error) { @@ -86,22 +83,3 @@ func TestClient_IsSSASupported(t *testing.T) { }) } } - -func TestDelete(t *testing.T) { - fkclient, fkclientset := FakeNew() - fkclient.Namespace = "default" - fkclientset.Kubernetes.PrependReactor("delete-collection", "deployments", func(action ktesting.Action) (bool, kruntime.Object, error) { - if "a-selector=a-value" != action.(ktesting.DeleteCollectionAction).GetListRestrictions().Labels.String() { - return true, nil, errors.New("not found") - } - return true, nil, nil - }) - - selectors := map[string]string{ - "a-selector": "a-value", - } - err := fkclient.Delete(selectors, false) - if err != nil { - t.Errorf("Expected no error, got %s", err) - } -} diff --git a/pkg/kclient/mock_Client.go b/pkg/kclient/mock_Client.go index 46718598637..50b19c851ec 100644 --- a/pkg/kclient/mock_Client.go +++ b/pkg/kclient/mock_Client.go @@ -207,34 +207,6 @@ func (mr *MockClientInterfaceMockRecorder) CreateTLSSecret(tlsCertificate, tlsPr return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateTLSSecret", reflect.TypeOf((*MockClientInterface)(nil).CreateTLSSecret), tlsCertificate, tlsPrivKey, objectMeta) } -// Delete mocks base method. -func (m *MockClientInterface) Delete(labels map[string]string, wait bool) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Delete", labels, wait) - ret0, _ := ret[0].(error) - return ret0 -} - -// Delete indicates an expected call of Delete. -func (mr *MockClientInterfaceMockRecorder) Delete(labels, wait interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockClientInterface)(nil).Delete), labels, wait) -} - -// DeleteDeployment mocks base method. -func (m *MockClientInterface) DeleteDeployment(labels map[string]string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteDeployment", labels) - ret0, _ := ret[0].(error) - return ret0 -} - -// DeleteDeployment indicates an expected call of DeleteDeployment. -func (mr *MockClientInterfaceMockRecorder) DeleteDeployment(labels interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteDeployment", reflect.TypeOf((*MockClientInterface)(nil).DeleteDeployment), labels) -} - // DeleteDynamicResource mocks base method. func (m *MockClientInterface) DeleteDynamicResource(name string, gvr schema.GroupVersionResource, wait bool) error { m.ctrl.T.Helper() @@ -539,21 +511,6 @@ func (mr *MockClientInterfaceMockRecorder) GetDeploymentFromSelector(selector in return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeploymentFromSelector", reflect.TypeOf((*MockClientInterface)(nil).GetDeploymentFromSelector), selector) } -// GetDeploymentLabelValues mocks base method. -func (m *MockClientInterface) GetDeploymentLabelValues(label, selector string) ([]string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetDeploymentLabelValues", label, selector) - ret0, _ := ret[0].([]string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetDeploymentLabelValues indicates an expected call of GetDeploymentLabelValues. -func (mr *MockClientInterfaceMockRecorder) GetDeploymentLabelValues(label, selector interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetDeploymentLabelValues", reflect.TypeOf((*MockClientInterface)(nil).GetDeploymentLabelValues), label, selector) -} - // GetDynamicClient mocks base method. func (m *MockClientInterface) GetDynamicClient() dynamic.Interface { m.ctrl.T.Helper() @@ -927,20 +884,6 @@ func (mr *MockClientInterfaceMockRecorder) IsServiceBindingSupported() *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsServiceBindingSupported", reflect.TypeOf((*MockClientInterface)(nil).IsServiceBindingSupported)) } -// LinkSecret mocks base method. -func (m *MockClientInterface) LinkSecret(secretName, componentName, applicationName string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "LinkSecret", secretName, componentName, applicationName) - ret0, _ := ret[0].(error) - return ret0 -} - -// LinkSecret indicates an expected call of LinkSecret. -func (mr *MockClientInterfaceMockRecorder) LinkSecret(secretName, componentName, applicationName interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LinkSecret", reflect.TypeOf((*MockClientInterface)(nil).LinkSecret), secretName, componentName, applicationName) -} - // ListClusterServiceVersions mocks base method. func (m *MockClientInterface) ListClusterServiceVersions() (*v1alpha1.ClusterServiceVersionList, error) { m.ctrl.T.Helper() @@ -956,21 +899,6 @@ func (mr *MockClientInterfaceMockRecorder) ListClusterServiceVersions() *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListClusterServiceVersions", reflect.TypeOf((*MockClientInterface)(nil).ListClusterServiceVersions)) } -// ListDeployments mocks base method. -func (m *MockClientInterface) ListDeployments(selector string) (*v10.DeploymentList, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListDeployments", selector) - ret0, _ := ret[0].(*v10.DeploymentList) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ListDeployments indicates an expected call of ListDeployments. -func (mr *MockClientInterfaceMockRecorder) ListDeployments(selector interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDeployments", reflect.TypeOf((*MockClientInterface)(nil).ListDeployments), selector) -} - // ListDynamicResources mocks base method. func (m *MockClientInterface) ListDynamicResources(gvr schema.GroupVersionResource) (*unstructured.UnstructuredList, error) { m.ctrl.T.Helper() @@ -1141,20 +1069,6 @@ func (mr *MockClientInterfaceMockRecorder) TryWithBlockOwnerDeletion(ownerRefere return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TryWithBlockOwnerDeletion", reflect.TypeOf((*MockClientInterface)(nil).TryWithBlockOwnerDeletion), ownerReference, exec) } -// UnlinkSecret mocks base method. -func (m *MockClientInterface) UnlinkSecret(secretName, componentName, applicationName string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UnlinkSecret", secretName, componentName, applicationName) - ret0, _ := ret[0].(error) - return ret0 -} - -// UnlinkSecret indicates an expected call of UnlinkSecret. -func (mr *MockClientInterfaceMockRecorder) UnlinkSecret(secretName, componentName, applicationName interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnlinkSecret", reflect.TypeOf((*MockClientInterface)(nil).UnlinkSecret), secretName, componentName, applicationName) -} - // UpdateDeployment mocks base method. func (m *MockClientInterface) UpdateDeployment(deploy v10.Deployment) (*v10.Deployment, error) { m.ctrl.T.Helper() @@ -1277,20 +1191,6 @@ func (mr *MockClientInterfaceMockRecorder) WaitAndGetSecret(name, namespace inte return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitAndGetSecret", reflect.TypeOf((*MockClientInterface)(nil).WaitAndGetSecret), name, namespace) } -// WaitForComponentDeletion mocks base method. -func (m *MockClientInterface) WaitForComponentDeletion(selector string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WaitForComponentDeletion", selector) - ret0, _ := ret[0].(error) - return ret0 -} - -// WaitForComponentDeletion indicates an expected call of WaitForComponentDeletion. -func (mr *MockClientInterfaceMockRecorder) WaitForComponentDeletion(selector interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitForComponentDeletion", reflect.TypeOf((*MockClientInterface)(nil).WaitForComponentDeletion), selector) -} - // WaitForDeploymentRollout mocks base method. func (m *MockClientInterface) WaitForDeploymentRollout(deploymentName string) (*v10.Deployment, error) { m.ctrl.T.Helper() diff --git a/pkg/kclient/services.go b/pkg/kclient/services.go index 48dfe74be57..197835723a0 100644 --- a/pkg/kclient/services.go +++ b/pkg/kclient/services.go @@ -4,8 +4,7 @@ import ( "context" "fmt" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" - "github.com/redhat-developer/odo/pkg/util" + odolabels "github.com/redhat-developer/odo/pkg/labels" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -53,9 +52,7 @@ func (c *Client) DeleteService(serviceName string) error { // GetOneService retrieves the service with the given component and app name // An error is thrown when exactly one service is not found for the selector. func (c *Client) GetOneService(componentName, appName string) (*corev1.Service, error) { - labels := componentlabels.GetLabels(componentName, appName, false) - labels[componentlabels.OdoModeLabel] = componentlabels.ComponentDevName - selector := util.ConvertLabelsToSelector(labels) + selector := odolabels.GetSelector(componentName, appName, odolabels.ComponentDevMode) return c.GetOneServiceFromSelector(selector) } diff --git a/pkg/kclient/services_test.go b/pkg/kclient/services_test.go index 5d2ad99e759..e66cffab06a 100644 --- a/pkg/kclient/services_test.go +++ b/pkg/kclient/services_test.go @@ -12,7 +12,7 @@ import ( devfileParser "github.com/devfile/library/pkg/devfile/parser" parsercommon "github.com/devfile/library/pkg/devfile/parser/data/v2/common" "github.com/devfile/library/pkg/testingutil" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" + odolabels "github.com/redhat-developer/odo/pkg/labels" odoTestingUtil "github.com/redhat-developer/odo/pkg/testingutil" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -211,7 +211,7 @@ func TestListServices(t *testing.T) { { name: "case 1: returned 3 services", args: args{ - selector: componentlabels.GetSelector("nodejs", "app"), + selector: odolabels.GetSelector("nodejs", "app", odolabels.ComponentDevMode), }, returnedServices: corev1.ServiceList{ Items: odoTestingUtil.FakeKubeServices("nodejs"), @@ -221,7 +221,7 @@ func TestListServices(t *testing.T) { { name: "case 2: no service returned", args: args{ - selector: componentlabels.GetSelector("nodejs", "app"), + selector: odolabels.GetSelector("nodejs", "app", odolabels.ComponentDevMode), }, returnedServices: corev1.ServiceList{ Items: nil, @@ -268,7 +268,7 @@ func TestClient_GetOneServiceFromSelector(t *testing.T) { { name: "case 1: returned the correct service", args: args{ - selector: componentlabels.GetSelector("nodejs", "app"), + selector: odolabels.GetSelector("nodejs", "app", odolabels.ComponentDevMode), }, returnedServices: corev1.ServiceList{ Items: []corev1.Service{ @@ -280,7 +280,7 @@ func TestClient_GetOneServiceFromSelector(t *testing.T) { { name: "case 2: no service returned", args: args{ - selector: componentlabels.GetSelector("nodejs", "app"), + selector: odolabels.GetSelector("nodejs", "app", odolabels.ComponentDevMode), }, returnedServices: corev1.ServiceList{ Items: nil, @@ -290,7 +290,7 @@ func TestClient_GetOneServiceFromSelector(t *testing.T) { { name: "case 3: more than one service returned", args: args{ - selector: componentlabels.GetSelector("nodejs", "app"), + selector: odolabels.GetSelector("nodejs", "app", odolabels.ComponentDevMode), }, returnedServices: corev1.ServiceList{ Items: odoTestingUtil.FakeKubeServices("nodejs"), diff --git a/pkg/labels/builder.go b/pkg/labels/builder.go new file mode 100644 index 00000000000..ca6d9cf9c25 --- /dev/null +++ b/pkg/labels/builder.go @@ -0,0 +1,79 @@ +package labels + +import ( + "fmt" + + "k8s.io/apimachinery/pkg/labels" +) + +type builder struct { + m labels.Set +} + +func Builder() builder { + return builder{ + m: make(map[string]string), + } +} + +func (o builder) Labels() map[string]string { + return o.m +} + +func (o builder) Selector() string { + return o.m.String() +} + +func (o builder) SelectorFlag() string { + return fmt.Sprintf("--selector=%s", o.m.String()) +} + +func (o builder) WithComponentName(name string) builder { + o.m[kubernetesInstanceLabel] = name + return o +} + +func (o builder) WithAppName(name string) builder { + o.m[kubernetesPartOfLabel] = name + return o +} + +func (o builder) WithApp(name string) builder { + o.m[appLabel] = name + return o +} + +func (o builder) WithManager(manager string) builder { + o.m[kubernetesManagedByLabel] = manager + return o +} + +func (o builder) WithProjectType(typ string) builder { + o.m[odoProjectTypeAnnotation] = typ + return o +} + +func (o builder) WithMode(mode string) builder { + o.m[odoModeLabel] = mode + return o +} + +func (o builder) WithSourcePVC(s string) builder { + o.m[sourcePVCLabel] = s + return o +} + +func (o builder) WithDevfileStorageName(name string) builder { + o.m[devfileStorageLabel] = name + return o +} + +func (o builder) WithStorageName(name string) builder { + o.m[kubernetesStorageNameLabel] = name + return o +} + +func (o builder) WithComponent(name string) builder { + o.m[componentLabel] = name + return o +} diff --git a/pkg/labels/constants.go b/pkg/labels/constants.go new file mode 100644 index 00000000000..bfc12eb9018 --- /dev/null +++ b/pkg/labels/constants.go @@ -0,0 +1,51 @@ +package labels + +const ( + + // kubernetesInstanceLabel identifies the component name + kubernetesInstanceLabel = "app.kubernetes.io/instance" + + // kubernetesNameLabel identifies the type of the component + // const kubernetesNameLabel = "app.kubernetes.io/name" + + // kubernetesManagedByLabel identifies the manager of the component + kubernetesManagedByLabel = "app.kubernetes.io/managed-by" + + // kubernetesManagedByVersionLabel identifies the version of manager used to deploy the resource + kubernetesManagedByVersionLabel = "app.kubernetes.io/managed-by-version" + + // kubernetesPartOfLabel identifies the application to which the component belongs + kubernetesPartOfLabel = "app.kubernetes.io/part-of" + + // kubernetesStorageNameLabel is applied to all storage resources that are created + kubernetesStorageNameLabel = "app.kubernetes.io/storage-name" + + // odoModeLabel indicates which command were used to create the component, either dev or deploy + odoModeLabel = "odo.dev/mode" + + // odoProjectTypeAnnotation indicates the project type fohe component + odoProjectTypeAnnotation = "odo.dev/project-type" + + appLabel = "app" + + componentLabel = "component" + + // devfileStorageLabel is applied to all storage resources for devfile components that are created + devfileStorageLabel = "storage-name" + + sourcePVCLabel = "odo-source-pvc" +) + +const ( + // ComponentDevMode indicates the resource is deployed using dev command + ComponentDevMode = "Dev" + + // ComponentDeployMode indicates the resource is deployed using deploy command + ComponentDeployMode = "Deploy" + + // ComponentAnyMode is used to search resources deployed using either dev or deploy comamnd + ComponentAnyMode = "" + + // odoManager is the value of the manager when a component is managed by odo + odoManager = "odo" +) diff --git a/pkg/labels/labels.go b/pkg/labels/labels.go new file mode 100644 index 00000000000..56e3b7b8bf4 --- /dev/null +++ b/pkg/labels/labels.go @@ -0,0 +1,104 @@ +package labels + +import ( + "errors" + + "github.com/redhat-developer/odo/pkg/version" + "k8s.io/apimachinery/pkg/labels" +) + +// GetLabels return labels that should be applied to every object for given component in active application +// if you need labels to filter component then use GetSelector instead +func GetLabels(componentName string, applicationName string, mode string) map[string]string { + labels := getLabels(componentName, applicationName, mode, true) + return labels +} + +// AddStorageInfo adds labels for storage resources +func AddStorageInfo(labels map[string]string, storageName string, isSourceVolume bool) { + labels[kubernetesStorageNameLabel] = storageName + labels[componentLabel] = labels[kubernetesInstanceLabel] + labels[devfileStorageLabel] = storageName + if isSourceVolume { + labels[sourcePVCLabel] = storageName + } +} + +func GetStorageName(labels map[string]string) string { + return labels[kubernetesStorageNameLabel] +} + +func GetDevfileStorageName(labels map[string]string) string { + return labels[devfileStorageLabel] +} + +func GetComponentName(labels map[string]string) string { + return labels[kubernetesInstanceLabel] +} + +func GetAppName(labels map[string]string) string { + return labels[kubernetesPartOfLabel] +} + +func GetManagedBy(labels map[string]string) string { + return labels[kubernetesManagedByLabel] +} + +func IsManagedByOdo(labels map[string]string) bool { + return labels[kubernetesManagedByLabel] == odoManager +} + +func GetMode(labels map[string]string) string { + return labels[odoModeLabel] +} + +func GetProjectType(labels map[string]string, annotations map[string]string) (string, error) { + // For backwards compatibility with previously deployed components that could be non-odo, check the annotation first + // then check to see if there is a label with the project type + if typ, ok := annotations[odoProjectTypeAnnotation]; ok { + return typ, nil + } + if typ, ok := labels[odoProjectTypeAnnotation]; ok { + return typ, nil + } + return "", errors.New("component type not found in labels or annotations") +} + +func SetProjectType(annotations map[string]string, value string) { + annotations[odoProjectTypeAnnotation] = value +} + +// GetSelector returns a selector string used for selection of resources which are part of the given component in given mode +func GetSelector(componentName string, applicationName string, mode string) string { + labels := getLabels(componentName, applicationName, mode, false) + return labels.String() +} + +// GetLabels return labels that should be applied to every object for given component in active application +// additional labels are used only for creating object +// if you are creating something use additional=true +// if you need labels to filter component then use additional=false +func getLabels(componentName string, applicationName string, mode string, additional bool) labels.Set { + labels := getApplicationLabels(applicationName, additional) + labels[kubernetesInstanceLabel] = componentName + if mode != ComponentAnyMode { + labels[odoModeLabel] = mode + } + return labels +} + +// GetLabels return labels that identifies given application +// additional labels are used only when creating object +// if you are creating something use additional=true +// if you need labels to filter component then use additional=false +func getApplicationLabels(application string, additional bool) labels.Set { + labels := labels.Set{ + kubernetesPartOfLabel: application, + kubernetesManagedByLabel: odoManager, + } + if additional { + labels[appLabel] = application + labels[kubernetesManagedByVersionLabel] = version.VERSION + } + return labels +} diff --git a/pkg/labels/labels_test.go b/pkg/labels/labels_test.go new file mode 100644 index 00000000000..d5a512f6d2f --- /dev/null +++ b/pkg/labels/labels_test.go @@ -0,0 +1,59 @@ +package labels + +import ( + "reflect" + "testing" + + "github.com/redhat-developer/odo/pkg/version" + "k8s.io/apimachinery/pkg/labels" +) + +func Test_getLabels(t *testing.T) { + type args struct { + componentName string + applicationName string + additional bool + } + tests := []struct { + name string + args args + want labels.Set + }{ + { + name: "everything filled", + args: args{ + componentName: "componentname", + applicationName: "applicationame", + additional: false, + }, + want: labels.Set{ + kubernetesManagedByLabel: "odo", + kubernetesPartOfLabel: "applicationame", + kubernetesInstanceLabel: "componentname", + "odo.dev/mode": "Dev", + }, + }, { + name: "everything with additional", + args: args{ + componentName: "componentname", + applicationName: "applicationame", + additional: true, + }, + want: labels.Set{ + kubernetesPartOfLabel: "applicationame", + appLabel: "applicationame", + kubernetesManagedByLabel: "odo", + kubernetesManagedByVersionLabel: version.VERSION, + kubernetesInstanceLabel: "componentname", + "odo.dev/mode": "Dev", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := getLabels(tt.args.componentName, tt.args.applicationName, ComponentDevMode, tt.args.additional); !reflect.DeepEqual(got, tt.want) { + t.Errorf("GetLabels() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/pkg/labels/selector_builder.go b/pkg/labels/selector_builder.go new file mode 100644 index 00000000000..a31ab2e427e --- /dev/null +++ b/pkg/labels/selector_builder.go @@ -0,0 +1,38 @@ +package labels + +import ( + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" +) + +type selectorBuilder struct { + selector labels.Selector +} + +func SelectorBuilder() selectorBuilder { + return selectorBuilder{ + selector: labels.NewSelector(), + } +} + +func (o selectorBuilder) WithComponent(name string) selectorBuilder { + req, err := labels.NewRequirement(componentLabel, selection.Equals, []string{name}) + if err != nil { + panic(err) + } + o.selector = o.selector.Add(*req) + return o +} + +func (o selectorBuilder) WithoutSourcePVC(s string) selectorBuilder { + req, err := labels.NewRequirement(sourcePVCLabel, selection.NotEquals, []string{s}) + if err != nil { + panic(err) + } + o.selector = o.selector.Add(*req) + return o +} + +func (o selectorBuilder) Selector() string { + return o.selector.String() +} diff --git a/pkg/service/link.go b/pkg/service/link.go index 683aaea847a..37007efa648 100644 --- a/pkg/service/link.go +++ b/pkg/service/link.go @@ -11,6 +11,7 @@ import ( "github.com/devfile/library/pkg/devfile/generator" devfilefs "github.com/devfile/library/pkg/testingutil/filesystem" "github.com/ghodss/yaml" + odolabels "github.com/redhat-developer/odo/pkg/labels" v1 "k8s.io/api/apps/v1" kerrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -20,8 +21,6 @@ import ( "k8s.io/klog/v2" ctrl "sigs.k8s.io/controller-runtime" - applabels "github.com/redhat-developer/odo/pkg/application/labels" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/kclient" sboApi "github.com/redhat-developer/service-binding-operator/apis/binding/v1alpha1" @@ -136,7 +135,7 @@ func pushLinksWithoutOperator(client kclient.ClientInterface, k8sComponents []de return false, err } - secrets, err := client.ListSecrets(componentlabels.GetSelector(labels[componentlabels.KubernetesInstanceLabel], labels[applabels.ApplicationLabel])) + secrets, err := client.ListSecrets(odolabels.GetSelector(odolabels.GetComponentName(labels), odolabels.GetAppName(labels), odolabels.ComponentAnyMode)) if err != nil { return false, err } @@ -246,7 +245,7 @@ func pushLinksWithoutOperator(client kclient.ClientInterface, k8sComponents []de // get the services and get match them against the component serviceCompMap = make(map[string]string) for _, service := range services { - serviceCompMap[service.Name] = service.Labels[componentlabels.KubernetesInstanceLabel] + serviceCompMap[service.Name] = odolabels.GetComponentName(service.Labels) } } diff --git a/pkg/service/service.go b/pkg/service/service.go index 2041fe5733c..2c5e3fb938b 100644 --- a/pkg/service/service.go +++ b/pkg/service/service.go @@ -8,9 +8,8 @@ import ( "github.com/redhat-developer/odo/pkg/libdevfile" - applabels "github.com/redhat-developer/odo/pkg/application/labels" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" "github.com/redhat-developer/odo/pkg/log" devfile "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" @@ -314,7 +313,7 @@ func ListDeployedServices(client kclient.ClientInterface, labels map[string]stri name := svc.GetName() kind := svc.GetKind() deployedLabels := svc.GetLabels() - if deployedLabels[applabels.ManagedBy] == "odo" && deployedLabels[componentlabels.KubernetesInstanceLabel] == labels[componentlabels.KubernetesInstanceLabel] { + if odolabels.IsManagedByOdo(deployedLabels) && odolabels.GetComponentName(deployedLabels) == odolabels.GetComponentName(labels) { deployed[kind+"/"+name] = DeployedInfo{ Kind: kind, Name: name, diff --git a/pkg/storage/kubernetes.go b/pkg/storage/kubernetes.go index 2d06305bb71..edf9af83d92 100644 --- a/pkg/storage/kubernetes.go +++ b/pkg/storage/kubernetes.go @@ -7,7 +7,8 @@ import ( "github.com/devfile/library/pkg/devfile/generator" "github.com/redhat-developer/odo/pkg/kclient" - storagelabels "github.com/redhat-developer/odo/pkg/storage/labels" + "github.com/redhat-developer/odo/pkg/labels" + odolabels "github.com/redhat-developer/odo/pkg/labels" v1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -38,15 +39,8 @@ func (k kubernetesClient) Create(storage Storage) error { return err } - labels := storagelabels.GetLabels(storage.Name, k.componentName, k.appName, true) - - labels["component"] = k.componentName - labels[storagelabels.DevfileStorageLabel] = storage.Name - - if strings.Contains(storage.Name, OdoSourceVolume) { - // Add label for source pvc - labels[storagelabels.SourcePVCLabel] = storage.Name - } + labels := odolabels.GetLabels(k.componentName, k.appName, odolabels.ComponentDevMode) + odolabels.AddStorageInfo(labels, storage.Name, strings.Contains(storage.Name, OdoSourceVolume)) objectMeta := generator.GetObjectMeta(pvcName, k.client.GetCurrentNamespace(), labels, nil) @@ -141,11 +135,10 @@ func (k kubernetesClient) ListFromCluster() (StorageList, error) { return StorageList{}, nil } - selector := fmt.Sprintf("%v=%s,%s!=odo-projects", "component", k.componentName, storagelabels.SourcePVCLabel) - + selector := labels.SelectorBuilder().WithComponent(k.componentName).WithoutSourcePVC(OdoSourceVolume).Selector() pvcs, err := k.client.ListPVCs(selector) if err != nil { - return StorageList{}, fmt.Errorf("unable to get PVC using selector %v: %w", storagelabels.StorageLabel, err) + return StorageList{}, fmt.Errorf("unable to get PVC using selector %q: %w", selector, err) } // to track volume mounts used by a PVC @@ -160,7 +153,7 @@ func (k kubernetesClient) ListFromCluster() (StorageList, error) { found = true size := pvc.Spec.Resources.Requests[corev1.ResourceStorage] - storage = append(storage, NewStorageWithContainer(pvc.Labels[storagelabels.DevfileStorageLabel], size.String(), volumeMount.Spec.Path, volumeMount.Spec.ContainerName, nil)) + storage = append(storage, NewStorageWithContainer(odolabels.GetDevfileStorageName(pvc.Labels), size.String(), volumeMount.Spec.Path, volumeMount.Spec.ContainerName, nil)) } } if !found { diff --git a/pkg/storage/kubernetes_test.go b/pkg/storage/kubernetes_test.go index a20f5381366..666aa2f4038 100644 --- a/pkg/storage/kubernetes_test.go +++ b/pkg/storage/kubernetes_test.go @@ -7,8 +7,8 @@ import ( "github.com/golang/mock/gomock" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" "github.com/redhat-developer/odo/pkg/localConfigProvider" - storageLabels "github.com/redhat-developer/odo/pkg/storage/labels" "github.com/redhat-developer/odo/pkg/testingutil" "github.com/redhat-developer/odo/pkg/util" appsv1 "k8s.io/api/apps/v1" @@ -97,8 +97,8 @@ func Test_kubernetesClient_ListFromCluster(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-0", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-0"}), - *testingutil.FakePVC("volume-1", "10Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-1"}), + *testingutil.FakePVC("volume-0", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-0").Labels()), + *testingutil.FakePVC("volume-1", "10Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-1").Labels()), }, }, want: StorageList{ @@ -132,8 +132,8 @@ func Test_kubernetesClient_ListFromCluster(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-0", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-0"}), - *testingutil.FakePVC("volume-1", "10Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-1"}), + *testingutil.FakePVC("volume-0", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-0").Labels()), + *testingutil.FakePVC("volume-1", "10Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-1").Labels()), }, }, want: StorageList{ @@ -165,8 +165,8 @@ func Test_kubernetesClient_ListFromCluster(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-0", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-0"}), - *testingutil.FakePVC("volume-1", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-1"}), + *testingutil.FakePVC("volume-0", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-0").Labels()), + *testingutil.FakePVC("volume-1", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-1").Labels()), }, }, wantErr: true, @@ -190,7 +190,7 @@ func Test_kubernetesClient_ListFromCluster(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-0-nodejs", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-0"}), + *testingutil.FakePVC("volume-0-nodejs", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-0").Labels()), }, }, want: StorageList{ @@ -224,8 +224,8 @@ func Test_kubernetesClient_ListFromCluster(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-0", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-0"}), - *testingutil.FakePVC("volume-1", "10Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-1"}), + *testingutil.FakePVC("volume-0", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-0").Labels()), + *testingutil.FakePVC("volume-1", "10Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-1").Labels()), }, }, want: StorageList{}, @@ -255,8 +255,8 @@ func Test_kubernetesClient_ListFromCluster(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-0", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-0"}), - *testingutil.FakePVC("volume-1", "10Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-1"}), + *testingutil.FakePVC("volume-0", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-0").Labels()), + *testingutil.FakePVC("volume-1", "10Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-1").Labels()), }, }, want: StorageList{ @@ -436,8 +436,8 @@ func Test_kubernetesClient_List(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-0", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-0"}), - *testingutil.FakePVC("volume-1", "10Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-1"}), + *testingutil.FakePVC("volume-0", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-0").Labels()), + *testingutil.FakePVC("volume-1", "10Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-1").Labels()), }, }, want: NewStorageList([]Storage{ @@ -480,8 +480,8 @@ func Test_kubernetesClient_List(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-00", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-00"}), - *testingutil.FakePVC("volume-11", "10Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-11"}), + *testingutil.FakePVC("volume-00", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-00").Labels()), + *testingutil.FakePVC("volume-11", "10Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-11").Labels()), }, }, want: NewStorageList([]Storage{ @@ -525,7 +525,7 @@ func Test_kubernetesClient_List(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-0", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-0"}), + *testingutil.FakePVC("volume-0", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-0").Labels()), }, }, want: NewStorageList([]Storage{ @@ -564,7 +564,7 @@ func Test_kubernetesClient_List(t *testing.T) { }, returnedPVCs: &corev1.PersistentVolumeClaimList{ Items: []corev1.PersistentVolumeClaim{ - *testingutil.FakePVC("volume-0", "5Gi", map[string]string{"component": "nodejs", storageLabels.DevfileStorageLabel: "volume-0"}), + *testingutil.FakePVC("volume-0", "5Gi", odolabels.Builder().WithComponent("nodejs").WithDevfileStorageName("volume-0").Labels()), }, }, want: NewStorageList([]Storage{ @@ -717,14 +717,8 @@ func Test_kubernetesClient_Create(t *testing.T) { t.Errorf("failed to create quantity by calling resource.ParseQuantity(%v)", tt.args.storage.Spec.Size) } - wantLabels := storageLabels.GetLabels(tt.args.storage.Name, tt.fields.generic.componentName, tt.fields.generic.appName, true) - wantLabels["component"] = tt.fields.generic.componentName - wantLabels[storageLabels.DevfileStorageLabel] = tt.args.storage.Name - - if strings.Contains(tt.args.storage.Name, OdoSourceVolume) { - // Add label for source pvc - wantLabels[storageLabels.SourcePVCLabel] = tt.args.storage.Name - } + wantLabels := odolabels.GetLabels(tt.fields.generic.componentName, tt.fields.generic.appName, odolabels.ComponentDevMode) + odolabels.AddStorageInfo(wantLabels, tt.args.storage.Name, strings.Contains(tt.args.storage.Name, OdoSourceVolume)) // created PVC should be labeled with labels passed to CreatePVC if !reflect.DeepEqual(createdPVC.Labels, wantLabels) { diff --git a/pkg/storage/labels/labels.go b/pkg/storage/labels/labels.go deleted file mode 100644 index fee36451d50..00000000000 --- a/pkg/storage/labels/labels.go +++ /dev/null @@ -1,24 +0,0 @@ -package labels - -import ( - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" -) - -// StorageLabel is the label key that is applied to all storage resources -// that are created -const StorageLabel = "app.kubernetes.io/storage-name" - -// DevfileStorageLabel is the label key that is applied to all storage resources for devfile components -// that are created -const DevfileStorageLabel = "storage-name" - -// SourceStorageLabel -const SourcePVCLabel = "odo-source-pvc" - -// GetLabels gets the labels to be applied to the given storage besides the -// component labels and application labels. -func GetLabels(storageName string, componentName string, applicationName string, additional bool) map[string]string { - labels := componentlabels.GetLabels(componentName, applicationName, additional) - labels[StorageLabel] = storageName - return labels -} diff --git a/pkg/storage/labels/labels_test.go b/pkg/storage/labels/labels_test.go deleted file mode 100644 index ad29eaebd91..00000000000 --- a/pkg/storage/labels/labels_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package labels - -import ( - "reflect" - "testing" - - applabels "github.com/redhat-developer/odo/pkg/application/labels" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" - "github.com/redhat-developer/odo/pkg/version" -) - -func TestGetLabels(t *testing.T) { - type args struct { - storageName string - componentName string - applicationName string - additional bool - } - tests := []struct { - name string - args args - want map[string]string - }{ - { - name: "Case 1: Everything filled", - args: args{ - storageName: "storagename", - componentName: "componentname", - applicationName: "applicationame", - additional: false, - }, - want: map[string]string{ - applabels.ApplicationLabel: "applicationame", - componentlabels.KubernetesInstanceLabel: "componentname", - StorageLabel: "storagename", - }, - }, { - name: "Case 2: No storage name", - args: args{ - storageName: "", - componentName: "componentname", - applicationName: "applicationame", - additional: false, - }, - want: map[string]string{ - applabels.ApplicationLabel: "applicationame", - componentlabels.KubernetesInstanceLabel: "componentname", - StorageLabel: "", - }, - }, { - name: "Case 3: Everything with additional", - args: args{ - storageName: "storagename", - componentName: "componentname", - applicationName: "applicationame", - additional: true, - }, - want: map[string]string{ - applabels.ApplicationLabel: "applicationame", - applabels.App: "applicationame", - applabels.ManagedBy: "odo", - applabels.ManagerVersion: version.VERSION, - componentlabels.KubernetesInstanceLabel: "componentname", - StorageLabel: "storagename", - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := GetLabels(tt.args.storageName, tt.args.componentName, tt.args.applicationName, tt.args.additional); !reflect.DeepEqual(got, tt.want) { - t.Errorf("GetLabels() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/pkg/storage/storage.go b/pkg/storage/storage.go index a72ccb43ec4..66be7a28802 100644 --- a/pkg/storage/storage.go +++ b/pkg/storage/storage.go @@ -3,9 +3,8 @@ package storage import ( "fmt" - applabels "github.com/redhat-developer/odo/pkg/application/labels" - "github.com/redhat-developer/odo/pkg/component/labels" "github.com/redhat-developer/odo/pkg/kclient" + "github.com/redhat-developer/odo/pkg/labels" "github.com/redhat-developer/odo/pkg/localConfigProvider" "github.com/redhat-developer/odo/pkg/log" v1 "k8s.io/api/apps/v1" @@ -55,8 +54,8 @@ func NewClient(options ClientOptions) Client { } if options.Deployment != nil { - genericInfo.appName = options.Deployment.Labels[applabels.ApplicationLabel] - genericInfo.componentName = options.Deployment.Labels[labels.KubernetesInstanceLabel] + genericInfo.appName = labels.GetAppName(options.Deployment.Labels) + genericInfo.componentName = labels.GetComponentName(options.Deployment.Labels) } return kubernetesClient{ diff --git a/pkg/storage/storage_test.go b/pkg/storage/storage_test.go index e273b181cca..4a42ee7514c 100644 --- a/pkg/storage/storage_test.go +++ b/pkg/storage/storage_test.go @@ -5,13 +5,15 @@ import ( "testing" "github.com/golang/mock/gomock" + odolabels "github.com/redhat-developer/odo/pkg/labels" "github.com/redhat-developer/odo/pkg/localConfigProvider" - storageLabels "github.com/redhat-developer/odo/pkg/storage/labels" "github.com/redhat-developer/odo/pkg/util" ) func getStorageLabels(storageName, componentName, applicationName string) map[string]string { - return storageLabels.GetLabels(storageName, componentName, applicationName, true) + labels := odolabels.GetLabels(componentName, applicationName, odolabels.ComponentDevMode) + odolabels.AddStorageInfo(labels, storageName, false) + return labels } func TestPush(t *testing.T) { diff --git a/pkg/storage/utils.go b/pkg/storage/utils.go index f7dce587d27..17b1a1713c1 100644 --- a/pkg/storage/utils.go +++ b/pkg/storage/utils.go @@ -4,17 +4,14 @@ import ( "fmt" "github.com/redhat-developer/odo/pkg/kclient" + odolabels "github.com/redhat-developer/odo/pkg/labels" "github.com/redhat-developer/odo/pkg/localConfigProvider" - storagelabels "github.com/redhat-developer/odo/pkg/storage/labels" "github.com/redhat-developer/odo/pkg/util" ) // getPVCNameFromStorageName returns the PVC associated with the given storage func getPVCNameFromStorageName(client kclient.ClientInterface, storageName string) (string, error) { - var labels = make(map[string]string) - labels[storagelabels.StorageLabel] = storageName - - selector := util.ConvertLabelsToSelector(labels) + var selector = odolabels.Builder().WithStorageName(storageName).Selector() pvcs, err := client.ListPVCNames(selector) if err != nil { return "", fmt.Errorf("unable to get PVC names for selector %v: %w", selector, err) diff --git a/pkg/testingutil/deployments.go b/pkg/testingutil/deployments.go index 662380b5879..888999f8ecf 100644 --- a/pkg/testingutil/deployments.go +++ b/pkg/testingutil/deployments.go @@ -1,8 +1,7 @@ package testingutil import ( - applabels "github.com/redhat-developer/odo/pkg/application/labels" - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" + odolabels "github.com/redhat-developer/odo/pkg/labels" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -21,16 +20,14 @@ func CreateFakeDeployment(podName string) *appsv1.Deployment { ObjectMeta: metav1.ObjectMeta{ Name: podName, UID: fakeUID, - Labels: map[string]string{ - applabels.App: "app", - applabels.ApplicationLabel: "app", - componentlabels.KubernetesInstanceLabel: podName, - applabels.ManagedBy: "odo", - componentlabels.OdoModeLabel: componentlabels.ComponentDevName, - }, - Annotations: map[string]string{ - componentlabels.OdoProjectTypeAnnotation: podName, - }, + Labels: odolabels.Builder(). + WithApp("app"). + WithAppName("app"). + WithComponentName(podName). + WithManager("odo"). + WithMode(odolabels.ComponentDevMode). + Labels(), + Annotations: odolabels.Builder().WithProjectType(podName).Labels(), }, } return &deployment diff --git a/pkg/testingutil/pods.go b/pkg/testingutil/pods.go index 74b343573c8..6e88a84aae3 100644 --- a/pkg/testingutil/pods.go +++ b/pkg/testingutil/pods.go @@ -1,7 +1,7 @@ package testingutil import ( - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" + odolabels "github.com/redhat-developer/odo/pkg/labels" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -11,7 +11,7 @@ func CreateFakePod(componentName, podName string) *corev1.Pod { fakePod := &corev1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name: podName, - Labels: componentlabels.GetLabels(componentName, "app", false), + Labels: odolabels.GetLabels(componentName, "app", odolabels.ComponentDevMode), }, Status: corev1.PodStatus{ Phase: corev1.PodRunning, diff --git a/pkg/testingutil/services.go b/pkg/testingutil/services.go index 9a9cee05382..9b1ae98941f 100644 --- a/pkg/testingutil/services.go +++ b/pkg/testingutil/services.go @@ -1,14 +1,13 @@ package testingutil import ( - componentlabels "github.com/redhat-developer/odo/pkg/component/labels" + odolabels "github.com/redhat-developer/odo/pkg/labels" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func FakeKubeService(componentName, serviceName string) corev1.Service { - labels := componentlabels.GetLabels(componentName, "app", false) - labels[componentlabels.OdoModeLabel] = componentlabels.ComponentDevName + labels := odolabels.GetLabels(componentName, "app", odolabels.ComponentDevMode) return corev1.Service{ ObjectMeta: metav1.ObjectMeta{ Name: serviceName, diff --git a/tests/helper/helper_kubectl.go b/tests/helper/helper_kubectl.go index 617bff7ad0e..806571865a4 100644 --- a/tests/helper/helper_kubectl.go +++ b/tests/helper/helper_kubectl.go @@ -9,9 +9,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" - - applabels "github.com/redhat-developer/odo/pkg/application/labels" - "github.com/redhat-developer/odo/pkg/component/labels" + "github.com/redhat-developer/odo/pkg/labels" ) const ( @@ -188,7 +186,7 @@ func (kubectl KubectlRunner) DeleteNamespaceProject(projectName string) { func (kubectl KubectlRunner) GetEnvsDevFileDeployment(componentName, appName, projectName string) map[string]string { var mapOutput = make(map[string]string) - selector := fmt.Sprintf("--selector=%s=%s,%s=%s", labels.KubernetesInstanceLabel, componentName, applabels.ApplicationLabel, appName) + selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).SelectorFlag() output := Cmd(kubectl.path, "get", ResourceTypeDeployment, selector, "--namespace", projectName, "-o", "jsonpath='{range .items[0].spec.template.spec.containers[0].env[*]}{.name}:{.value}{\"\\n\"}{end}'").ShouldPass().Out() diff --git a/tests/helper/helper_oc.go b/tests/helper/helper_oc.go index 39a2cfb0f79..12dd2a56f30 100644 --- a/tests/helper/helper_oc.go +++ b/tests/helper/helper_oc.go @@ -12,8 +12,7 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" - applabels "github.com/redhat-developer/odo/pkg/application/labels" - "github.com/redhat-developer/odo/pkg/component/labels" + "github.com/redhat-developer/odo/pkg/labels" ) type OcRunner struct { @@ -236,7 +235,7 @@ func (oc OcRunner) GetEnvFromEntry(componentName string, appName string, project func (oc OcRunner) GetEnvsDevFileDeployment(componentName, appName, projectName string) map[string]string { var mapOutput = make(map[string]string) - selector := fmt.Sprintf("--selector=%s=%s,%s=%s", labels.KubernetesInstanceLabel, componentName, applabels.ApplicationLabel, appName) + selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).SelectorFlag() output := Cmd(oc.path, "get", "deployment", selector, "--namespace", projectName, "-o", "jsonpath='{range .items[0].spec.template.spec.containers[0].env[*]}{.name}:{.value}{\"\\n\"}{end}'").ShouldPass().Out() diff --git a/tests/helper/helper_run.go b/tests/helper/helper_run.go index 5f7159c8279..ab4bf78c7b2 100644 --- a/tests/helper/helper_run.go +++ b/tests/helper/helper_run.go @@ -10,8 +10,7 @@ import ( . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" - applabels "github.com/redhat-developer/odo/pkg/application/labels" - "github.com/redhat-developer/odo/pkg/component/labels" + "github.com/redhat-developer/odo/pkg/labels" ) func runningCmd(cmd *exec.Cmd) string { @@ -84,8 +83,7 @@ func WaitAndCheckForTerminatingState(path, resourceType, namespace string, timeo // belonging to the given component, app and project func GetAnnotationsDeployment(path, componentName, appName, projectName string) map[string]string { var mapOutput = make(map[string]string) - - selector := fmt.Sprintf("--selector=%s=%s,%s=%s", labels.KubernetesInstanceLabel, componentName, applabels.ApplicationLabel, appName) + selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).SelectorFlag() output := Cmd(path, "get", "deployment", selector, "--namespace", projectName, "-o", "go-template='{{ range $k, $v := (index .items 0).metadata.annotations}}{{$k}}:{{$v}}{{\"\\n\"}}{{end}}'").ShouldPass().Out() @@ -112,7 +110,7 @@ func GetSecrets(path, project string) string { // GetEnvRefNames gets the ref values from the envFroms of the deployment belonging to the given data func GetEnvRefNames(path, componentName, appName, projectName string) []string { - selector := fmt.Sprintf("--selector=%s=%s,%s=%s", labels.KubernetesInstanceLabel, componentName, applabels.ApplicationLabel, appName) + selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).SelectorFlag() output := Cmd(path, "get", "deployment", selector, "--namespace", projectName, "-o", "jsonpath='{range .items[0].spec.template.spec.containers[0].envFrom[*]}{.secretRef.name}{\"\\n\"}{end}'").ShouldPass().Out() @@ -134,7 +132,7 @@ func GetEnvFromEntry(path string, componentName string, appName string, projectN // GetVolumeNamesFromDeployment gets the volumes from the deployment belonging to the given data func GetVolumeNamesFromDeployment(path, componentName, appName, projectName string) map[string]string { var mapOutput = make(map[string]string) - selector := fmt.Sprintf("--selector=%s=%s,%s=%s", labels.KubernetesInstanceLabel, componentName, applabels.ApplicationLabel, appName) + selector := labels.Builder().WithComponentName(componentName).WithAppName(appName).SelectorFlag() output := Cmd(path, "get", "deployment", selector, "--namespace", projectName, "-o", "jsonpath='{range .items[0].spec.template.spec.volumes[*]}{.name}{\":\"}{.persistentVolumeClaim.claimName}{\"\\n\"}{end}'").ShouldPass().Out()