From a2382c4cccb10f2eae48d837d5d11512619d9546 Mon Sep 17 00:00:00 2001 From: klaskosk <162511147+klaskosk@users.noreply.github.com> Date: Mon, 27 Apr 2026 01:21:23 +0000 Subject: [PATCH] deps: bump github.com/rh-ecosystem-edge/eco-goinfra --- go.mod | 2 +- go.sum | 4 +- .../eco-goinfra/pkg/clients/clients.go | 2 - .../eco-goinfra/pkg/configmap/configmap.go | 252 +------ .../eco-goinfra/pkg/configmap/list.go | 29 +- .../eco-goinfra/pkg/internal/common/common.go | 644 ++++++++++++++++++ .../eco-goinfra/pkg/internal/common/doc.go | 7 + .../pkg/internal/common/embeddable_builder.go | 97 +++ .../pkg/internal/common/embeddable_creator.go | 21 + .../pkg/internal/common/embeddable_deleter.go | 45 ++ .../pkg/internal/common/embeddable_updater.go | 42 ++ .../internal/common/embeddable_withoptions.go | 22 + .../pkg/internal/common/errors/errors.go | 209 ++++++ .../pkg/internal/common/key/key.go | 29 + .../pkg/internal/logging/context.go | 6 + .../eco-goinfra/pkg/network/operator.go | 117 +++- .../eco-goinfra/pkg/route/route.go | 257 ++----- .../argocd/argocdoperator/argocd_types.go | 39 +- .../argocdoperator/zz_generated.deepcopy.go | 60 ++ .../argocdoperatorcommon/annotations.go | 4 + .../argocd/argocdoperatorcommon/keys.go | 3 + .../nvidiagputypes/clusterpolicy_types.go | 10 + .../nvidiagputypes/zz_generated.deepcopy.go | 7 + .../schemes/ovn/routeadvertisement/v1/doc.go | 3 + .../ovn/routeadvertisement/v1/register.go | 3 + .../ovn/routeadvertisement/v1/types.go | 3 + .../v1/zz_generated.deepcopy.go | 16 +- .../eco-goinfra/pkg/schemes/ovn/types/doc.go | 3 + .../pkg/schemes/ovn/types/networkselector.go | 3 + .../ovn/types/zz_generated.deepcopy.go | 16 +- vendor/modules.txt | 5 +- 31 files changed, 1461 insertions(+), 499 deletions(-) create mode 100644 vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/common.go create mode 100644 vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/doc.go create mode 100644 vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_builder.go create mode 100644 vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_creator.go create mode 100644 vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_deleter.go create mode 100644 vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_updater.go create mode 100644 vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_withoptions.go create mode 100644 vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/errors/errors.go create mode 100644 vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/key/key.go diff --git a/go.mod b/go.mod index 68314434b..191dd22bd 100644 --- a/go.mod +++ b/go.mod @@ -292,7 +292,7 @@ require ( ) require ( - github.com/rh-ecosystem-edge/eco-goinfra v0.0.0-20260414203002-e8968ddfde1a + github.com/rh-ecosystem-edge/eco-goinfra v0.0.0-20260424200316-f32d939b08da k8s.io/apiextensions-apiserver v0.34.5 ) diff --git a/go.sum b/go.sum index 59581edec..aa0848c04 100644 --- a/go.sum +++ b/go.sum @@ -739,8 +739,8 @@ github.com/red-hat-storage/odf-operator v0.0.0-20260226164309-08c71191d483 h1:I8 github.com/red-hat-storage/odf-operator v0.0.0-20260226164309-08c71191d483/go.mod h1:ezzeJZeZyinngGE5Ox4wAZg6w+Bdu7/9PtdQeV3fXUk= github.com/redhat-cne/sdk-go v1.23.6 h1:L+Rs12UihwDBJc/tj1eEMc4Otf7Lxf0bkFjdsg7FPGA= github.com/redhat-cne/sdk-go v1.23.6/go.mod h1:5hK1sILdB33pdMsNYTyBKV/v5GjjibmQZcyRtVrVfvs= -github.com/rh-ecosystem-edge/eco-goinfra v0.0.0-20260414203002-e8968ddfde1a h1:5DMrHRxZZoHl/LP7sAXXUhZnCNh9oFqttdimoyVuyUc= -github.com/rh-ecosystem-edge/eco-goinfra v0.0.0-20260414203002-e8968ddfde1a/go.mod h1:rxPzQh+1NKE5Kj5ez2xSmZ6jWRNJSGkYtFvJJDySc8s= +github.com/rh-ecosystem-edge/eco-goinfra v0.0.0-20260424200316-f32d939b08da h1:/ATdY8iuSKYMkaxv6JB/i9+9JVTb5ZR9rgh0KFBKm/A= +github.com/rh-ecosystem-edge/eco-goinfra v0.0.0-20260424200316-f32d939b08da/go.mod h1:rxPzQh+1NKE5Kj5ez2xSmZ6jWRNJSGkYtFvJJDySc8s= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/clients/clients.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/clients/clients.go index 4c9b944e2..1d5017350 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/clients/clients.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/clients/clients.go @@ -282,8 +282,6 @@ func GetModifiableTestClients(tcp TestClientParams) (*Settings, *fakeRuntimeClie genericClientObjects = append(genericClientObjects, v) case *operatorv1.OpenShiftAPIServer: genericClientObjects = append(genericClientObjects, v) - case *routev1.Route: - genericClientObjects = append(genericClientObjects, v) case *configV1.Node: genericClientObjects = append(genericClientObjects, v) case *operatorv1.IngressController: diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/configmap/configmap.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/configmap/configmap.go index 59e1ed9c4..42477c2d4 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/configmap/configmap.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/configmap/configmap.go @@ -1,195 +1,55 @@ package configmap import ( + "context" "fmt" "github.com/rh-ecosystem-edge/eco-goinfra/pkg/clients" - "github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/logging" - "github.com/rh-ecosystem-edge/eco-goinfra/pkg/msg" + "github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common" corev1 "k8s.io/api/core/v1" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" - corev1Typed "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/klog/v2" ) -// Builder provides struct for configmap object containing connection to the cluster and the configmap definitions. -type Builder struct { - // ConfigMap definition. Used to create configmap object. - Definition *corev1.ConfigMap - // Created configmap object. - Object *corev1.ConfigMap - // Used in functions that defines or mutates configmap definition. errorMsg is processed before the configmap - // object is created. - errorMsg string - apiClient corev1Typed.CoreV1Interface -} - -// AdditionalOptions additional options for configmap object. +// AdditionalOptions are optional mutations applied via WithOptions. type AdditionalOptions func(builder *Builder) (*Builder, error) -// Pull retrieves an existing configmap object from the cluster. -func Pull(apiClient *clients.Settings, name, nsname string) (*Builder, error) { - builder := Builder{ - apiClient: apiClient.CoreV1Interface, - Definition: &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: nsname, - }, - }, - } - - if name == "" { - klog.V(100).Info("The name of the configmap is empty") - - return nil, fmt.Errorf("configmap 'name' cannot be empty") - } - - if nsname == "" { - klog.V(100).Info("The namespace of the configmap is empty") - - return nil, fmt.Errorf("configmap 'nsname' cannot be empty") - } - - klog.V(100).Infof( - "Pulling configmap object name:%s in namespace: %s", name, nsname) - - if !builder.Exists() { - return nil, fmt.Errorf("configmap object %s does not exist in namespace %s", name, nsname) - } - - builder.Definition = builder.Object - - return &builder, nil +// Builder provides a configmap builder backed by the shared common builder framework. +type Builder struct { + common.EmbeddableBuilder[corev1.ConfigMap, *corev1.ConfigMap] + common.EmbeddableWithOptions[corev1.ConfigMap, Builder, *corev1.ConfigMap, *Builder, AdditionalOptions] + common.EmbeddableCreator[corev1.ConfigMap, Builder, *corev1.ConfigMap, *Builder] + common.EmbeddableDeleter[corev1.ConfigMap, *corev1.ConfigMap] + common.EmbeddableUpdater[corev1.ConfigMap, Builder, *corev1.ConfigMap, *Builder] } -// NewBuilder creates a new instance of Builder. -func NewBuilder(apiClient *clients.Settings, name, nsname string) *Builder { - klog.V(100).Infof( - "Initializing new configmap structure with the following params: %s, %s", name, nsname) - - builder := &Builder{ - apiClient: apiClient.CoreV1Interface, - Definition: &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: nsname, - }, - }, - } - - if name == "" { - klog.V(100).Info("The name of the configmap is empty") - - builder.errorMsg = "configmap 'name' cannot be empty" - - return builder - } - - if nsname == "" { - klog.V(100).Info("The namespace of the configmap is empty") - - builder.errorMsg = "configmap 'nsname' cannot be empty" - - return builder - } - - return builder +// AttachMixins wires the embedded CRUD mixins to this builder instance. +func (builder *Builder) AttachMixins() { + builder.EmbeddableWithOptions.SetBase(builder) + builder.EmbeddableCreator.SetBase(builder) + builder.EmbeddableDeleter.SetBase(builder) + builder.EmbeddableUpdater.SetBase(builder) } -// Create makes a configmap in cluster and stores the created object in struct. -func (builder *Builder) Create() (*Builder, error) { - if valid, err := builder.validate(); !valid { - return builder, err - } - - klog.V(100).Infof("Creating the configmap %s in namespace %s", builder.Definition.Name, builder.Definition.Namespace) - - var err error - if !builder.Exists() { - builder.Object, err = builder.apiClient.ConfigMaps(builder.Definition.Namespace).Create( - logging.DiscardContext(), builder.Definition, metav1.CreateOptions{}) - } - - return builder, err +// GetGVK returns the ConfigMap GVK for this builder. +func (builder *Builder) GetGVK() schema.GroupVersionKind { + return corev1.SchemeGroupVersion.WithKind("ConfigMap") } -// Delete removes a configmap. -func (builder *Builder) Delete() error { - if valid, err := builder.validate(); !valid { - return err - } - - klog.V(100).Infof("Deleting the configmap %s from namespace %s", - builder.Definition.Name, builder.Definition.Namespace) - - if !builder.Exists() { - klog.V(100).Infof("configmap %s in namespace %s does not exist", - builder.Definition.Name, builder.Definition.Namespace) - - builder.Object = nil - - return nil - } - - err := builder.apiClient.ConfigMaps(builder.Definition.Namespace).Delete( - logging.DiscardContext(), builder.Object.Name, metav1.DeleteOptions{}) - if err != nil { - return err - } - - builder.Object = nil - - return nil -} - -// Exists checks whether the given configmap exists. -func (builder *Builder) Exists() bool { - if valid, _ := builder.validate(); !valid { - return false - } - - klog.V(100).Infof( - "Checking if configmap %s exists in namespace %s", - builder.Definition.Name, builder.Definition.Namespace) - - var err error - - builder.Object, err = builder.apiClient.ConfigMaps(builder.Definition.Namespace).Get( - logging.DiscardContext(), builder.Definition.Name, metav1.GetOptions{}) - - return err == nil || !k8serrors.IsNotFound(err) +// Pull retrieves an existing configmap object from the cluster. +func Pull(apiClient *clients.Settings, name, nsname string) (*Builder, error) { + return common.PullNamespacedBuilder[corev1.ConfigMap, Builder]( + context.TODO(), apiClient, corev1.AddToScheme, name, nsname) } -// Update renovates the existing configmap object with configmap definition in builder. -func (builder *Builder) Update() (*Builder, error) { - if valid, err := builder.validate(); !valid { - return builder, err - } - - klog.V(100).Infof("Updating configmap %s in namespace %s", - builder.Definition.Name, builder.Definition.Namespace) - - var err error - - builder.Object, err = builder.apiClient.ConfigMaps(builder.Definition.Namespace). - Update(logging.DiscardContext(), builder.Definition, metav1.UpdateOptions{}) - if err != nil { - klog.V(100).Infof("%v", msg.FailToUpdateError("configmap", builder.Definition.Name, builder.Definition.Namespace)) - - return nil, err - } - - builder.Object = builder.Definition - - return builder, nil +// NewBuilder creates a new instance of Builder. +func NewBuilder(apiClient *clients.Settings, name, nsname string) *Builder { + return common.NewNamespacedBuilder[corev1.ConfigMap, Builder](apiClient, corev1.AddToScheme, name, nsname) } // WithData defines the data placed in the configmap. func (builder *Builder) WithData(data map[string]string) *Builder { - if valid, _ := builder.validate(); !valid { + if err := common.Validate(builder); err != nil { return builder } @@ -198,7 +58,7 @@ func (builder *Builder) WithData(data map[string]string) *Builder { builder.Definition.Name, builder.Definition.Namespace, data) if len(data) == 0 { - builder.errorMsg = "'data' cannot be empty" + builder.SetError(fmt.Errorf("'data' cannot be empty")) return builder } @@ -208,65 +68,9 @@ func (builder *Builder) WithData(data map[string]string) *Builder { return builder } -// WithOptions creates configmap with generic mutation options. -func (builder *Builder) WithOptions(options ...AdditionalOptions) *Builder { - if valid, _ := builder.validate(); !valid { - return builder - } - - klog.V(100).Info("Setting configmap additional options") - - for _, option := range options { - if option != nil { - builder, err := option(builder) - if err != nil { - klog.V(100).Info("Error occurred in mutation function") - - builder.errorMsg = err.Error() - - return builder - } - } - } - - return builder -} - // GetGVR returns configmap's GroupVersionResource which could be used for Clean function. func GetGVR() schema.GroupVersionResource { return schema.GroupVersionResource{ Group: "", Version: "v1", Resource: "configmaps", } } - -// validate will check that the builder and builder definition are properly initialized before -// accessing any member fields. -func (builder *Builder) validate() (bool, error) { - resourceCRD := "ConfigMap" - - if builder == nil { - klog.V(100).Infof("The %s builder is uninitialized", resourceCRD) - - return false, fmt.Errorf("error: received nil %s builder", resourceCRD) - } - - if builder.Definition == nil { - klog.V(100).Infof("The %s is undefined", resourceCRD) - - return false, fmt.Errorf("%s", msg.UndefinedCrdObjectErrString(resourceCRD)) - } - - if builder.apiClient == nil { - klog.V(100).Infof("The %s builder apiclient is nil", resourceCRD) - - return false, fmt.Errorf("%s builder cannot have nil apiClient", resourceCRD) - } - - if builder.errorMsg != "" { - klog.V(100).Infof("The %s builder has error message: %s", resourceCRD, builder.errorMsg) - - return false, fmt.Errorf("%s", builder.errorMsg) - } - - return true, nil -} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/configmap/list.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/configmap/list.go index d062056b2..0c3c8941c 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/configmap/list.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/configmap/list.go @@ -5,6 +5,7 @@ import ( "github.com/rh-ecosystem-edge/eco-goinfra/pkg/clients" "github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/logging" + corev1 "k8s.io/api/core/v1" "k8s.io/klog/v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -51,13 +52,7 @@ func List(apiClient *clients.Settings, nsname string, options ...metav1.ListOpti for _, runningConfigmap := range configmapList.Items { copiedConfigmap := runningConfigmap - configmapBuilder := &Builder{ - apiClient: apiClient.CoreV1Interface, - Object: &copiedConfigmap, - Definition: &copiedConfigmap, - } - - configmapObjects = append(configmapObjects, configmapBuilder) + configmapObjects = append(configmapObjects, newListedBuilder(apiClient, &copiedConfigmap)) } return configmapObjects, nil @@ -98,14 +93,20 @@ func ListInAllNamespaces(apiClient *clients.Settings, options ...metav1.ListOpti for _, runningConfigmap := range configmapList.Items { copiedConfigmap := runningConfigmap - configmapBuilder := &Builder{ - apiClient: apiClient.CoreV1Interface, - Object: &copiedConfigmap, - Definition: &copiedConfigmap, - } - - configmapObjects = append(configmapObjects, configmapBuilder) + configmapObjects = append(configmapObjects, newListedBuilder(apiClient, &copiedConfigmap)) } return configmapObjects, nil } + +// newListedBuilder returns a fully initialized builder for a configmap obtained through a list call. +func newListedBuilder(apiClient *clients.Settings, configMap *corev1.ConfigMap) *Builder { + builder := &Builder{} + builder.AttachMixins() + builder.SetClient(apiClient) + builder.SetGVK(builder.GetGVK()) + builder.SetObject(configMap) + builder.SetDefinition(configMap) + + return builder +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/common.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/common.go new file mode 100644 index 000000000..ce91e3d72 --- /dev/null +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/common.go @@ -0,0 +1,644 @@ +package common + +import ( + "context" + "fmt" + "reflect" + + "github.com/rh-ecosystem-edge/eco-goinfra/pkg/clients" + "github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/errors" + "github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/key" + "github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/logging" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/klog/v2" + runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +// ObjectPointer is a type constraint that requires a type be a pointer to O and implement the runtimeclient.Object +// interface. The type parameter O is meant to be a K8s resource, such as corev1.Namespace. In that case, +// *corev1.Namespace would satisfy the constraint ObjectPointer[corev1.Namespace]. +type ObjectPointer[O any] interface { + *O + runtimeclient.Object +} + +// Builder represents the set of methods that must be present to use the common versions of CRUD and other methods. +// Since each builder struct is a different type, this interface allows common functions to update fields on the +// builder. Generally, consumers of eco-goinfra should not call these methods. +// +// The type parameter O (short for object) is expected to be the struct that represents a K8s resource, such as +// corev1.Namespace. SO (short for star O) is the pointer to O, with the additional constraint of that pointer +// implementing runtimeclient.Object. To continue the example, this would be *corev1.Namespace. +// +// Although only SO appears in the interface definition, it is important to have access to the derefenced form of the +// type so we may do new(O) and get a runtimeclient.Object. +type Builder[O any, SO ObjectPointer[O]] interface { + // GetDefinition allows for getting the desired form of a K8s resource from the builder. + GetDefinition() SO + // SetDefinition allows for updating the desired form of the K8s resource. + SetDefinition(SO) + + // GetObject allows for getting the form of a K8s resource, as last pulled from the cluster. + GetObject() SO + // SetObject allows for updating what the K8s resource last was on the cluster. + SetObject(SO) + + // GetError returns the error stored in the builder. Methods which do not return errors, such as the builder + // modifiers, will store the error in the builder. + GetError() error + // SetError allows for updating the error stored in the builder. It should not be used by consumers of the + // builder, but rather by methods which do not return errors. + SetError(error) + + // GetClient returns the client used for connecting with the K8s cluster. + GetClient() runtimeclient.Client + // SetClient allows for updating the client used to connect to the K8s cluster. Since this is a simple setter, + // it will not handle updating the scheme of the client and should generally be avoided outside of creating the + // builder. + SetClient(runtimeclient.Client) + + // GetGVK returns the GVK for the resource the builder represents, even if the builder is zero-valued. + // + // It is meant to be defined by resource-specific builders as a function returning a constant GVK. An embeddable + // builder is expected to return from GetGVK the GVK provided through SetGVK when initializing the builder. + GetGVK() schema.GroupVersionKind + // SetGVK allows for updating the GVK for the resource the builder represents. This method is not intended to be + // used by consumers of the builder, but internally as part of initializing the builder. + // + // It is expected that an embeddable builder will store the GVK passed to this method and return it from GetGVK. + SetGVK(schema.GroupVersionKind) +} + +// NewResourceKeyFromBuilder creates a new ResourceKey from the given builder. It does not validate the builder, so +// should only be used after validating the builder, or at least ensuring the builder and its definition are not nil. +func NewResourceKeyFromBuilder[O any, SO ObjectPointer[O]](builder Builder[O, SO]) key.ResourceKey { + return key.ResourceKey{ + Kind: builder.GetGVK().Kind, + Name: builder.GetDefinition().GetName(), + Namespace: builder.GetDefinition().GetNamespace(), + } +} + +// MixinAttacher is an interface for types which require a step during initialization of a builder to ensure mixins are +// all attached. In practice, this is meant to be implemented by the resource-specific builders so that any mixins they +// embed can be connected to the EmbeddableBuilder. +// +// This interface is defined separately from the Builder interface since while the resource-specific builders must +// implement the Builder interface, they do not need to implement the MixinAttacher interface. Similarly, +// EmbeddableBuilder should not implement this interface even though it is a Builder. +type MixinAttacher interface { + // AttachMixins ensures that all mixins are attached to their base builders. This method will be called on the + // zero-value of builder pointers right after allocation, provided the builder also implements MixinAttacher. + AttachMixins() +} + +// BuilderPointer is similar to objectPointer and is a constraint that is satisfied by a Builder that is a pointer. It +// exists for the same reason as objectPointer: needing access to the dereferenced form of builders to construct new +// ones. +type BuilderPointer[B, O any, SO ObjectPointer[O]] interface { + *B + Builder[O, SO] +} + +// NewClusterScopedBuilder creates a new builder for a cluster-scoped resource. It is generic over the actual builder +// type and uses the methods from the Builder interface to create the actual builder. Generic parameters are ordered so +// that SO and SB can be elided and only O and B must be provided. +func NewClusterScopedBuilder[O, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO]]( + apiClient runtimeclient.Client, schemeAttacher clients.SchemeAttacher, name string) SB { + var builder SB = new(B) + + if mixinAttacher, ok := any(builder).(MixinAttacher); ok { + mixinAttacher.AttachMixins() + } + + builder.SetGVK(builder.GetGVK()) + builder.SetClient(apiClient) + builder.SetDefinition(new(O)) + builder.GetDefinition().SetName(name) + + resourceKey := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Initializing new builder for %s", resourceKey.String()) + + if isInterfaceNil(apiClient) { + klog.V(100).Infof("The apiClient provided for %s is nil", resourceKey.String()) + + builder.SetError(errors.NewAPIClientNil(resourceKey)) + + return builder + } + + err := schemeAttacher(apiClient.Scheme()) + if err != nil { + klog.V(100).Infof("Failed to attach scheme for %s: %v", resourceKey.String(), err) + + builder.SetError(errors.NewSchemeAttacherFailed(resourceKey, err)) + + return builder + } + + if name == "" { + klog.V(100).Infof("The name of the builder for %s is empty", resourceKey.String()) + + builder.SetError(errors.NewBuilderFieldEmpty(resourceKey, errors.BuilderFieldName)) + + return builder + } + + return builder +} + +// NewNamespacedBuilder creates a new builder for a namespaced resource. It is generic over the actual builder type and +// uses the methods from the Builder interface to create the actual builder. Generic parameters are ordered so that SO +// and SB can be elided and only O and B must be provided. +func NewNamespacedBuilder[O, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO]]( + apiClient runtimeclient.Client, schemeAttacher clients.SchemeAttacher, name, nsname string) SB { + var builder SB = new(B) + + if mixinAttacher, ok := any(builder).(MixinAttacher); ok { + mixinAttacher.AttachMixins() + } + + builder.SetGVK(builder.GetGVK()) + builder.SetClient(apiClient) + builder.SetDefinition(new(O)) + builder.GetDefinition().SetName(name) + builder.GetDefinition().SetNamespace(nsname) + + resourceKey := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Initializing new builder for %s", resourceKey.String()) + + if isInterfaceNil(apiClient) { + klog.V(100).Infof("The apiClient provided for %s is nil", resourceKey.String()) + + builder.SetError(errors.NewAPIClientNil(resourceKey)) + + return builder + } + + err := schemeAttacher(apiClient.Scheme()) + if err != nil { + klog.V(100).Infof("Failed to attach scheme for %s: %v", resourceKey.String(), err) + + builder.SetError(errors.NewSchemeAttacherFailed(resourceKey, err)) + + return builder + } + + if name == "" { + klog.V(100).Infof("The name of the builder for %s is empty", resourceKey.String()) + + builder.SetError(errors.NewBuilderFieldEmpty(resourceKey, errors.BuilderFieldName)) + + return builder + } + + if nsname == "" { + klog.V(100).Infof("The namespace of the builder for %s is empty", resourceKey.String()) + + builder.SetError(errors.NewBuilderFieldEmpty(resourceKey, errors.BuilderFieldNamespace)) + + return builder + } + + return builder +} + +// PullClusterScopedBuilder creates a new Builder for a cluster-scoped resource, pulling the resource from the cluster. +// It is generic over the actual builder type and uses the methods from the Builder interface to create the actual +// builder. Generic parameters are ordered so that SO and SB can be elided and only O and B must be provided. +func PullClusterScopedBuilder[O, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO]]( + ctx context.Context, apiClient runtimeclient.Client, schemeAttacher clients.SchemeAttacher, name string) (SB, error) { + var builder SB = new(B) + + if mixinAttacher, ok := any(builder).(MixinAttacher); ok { + mixinAttacher.AttachMixins() + } + + builder.SetGVK(builder.GetGVK()) + builder.SetClient(apiClient) + builder.SetDefinition(new(O)) + builder.GetDefinition().SetName(name) + + resourceKey := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Pulling builder for %s", resourceKey.String()) + + if isInterfaceNil(apiClient) { + klog.V(100).Infof("The apiClient provided for %s is nil", resourceKey.String()) + + return nil, errors.NewAPIClientNil(resourceKey) + } + + err := schemeAttacher(apiClient.Scheme()) + if err != nil { + klog.V(100).Infof("Failed to attach scheme for %s: %v", resourceKey.String(), err) + + return nil, errors.NewSchemeAttacherFailed(resourceKey, err) + } + + if name == "" { + klog.V(100).Infof("The name of the builder for %s is empty", resourceKey.String()) + + return nil, errors.NewBuilderFieldEmpty(resourceKey, errors.BuilderFieldName) + } + + object, err := Get(ctx, builder) + if err != nil { + klog.V(100).Infof("Failed to pull the builder for %s: %v", resourceKey.String(), err) + + return nil, fmt.Errorf("failed to pull builder: %w", err) + } + + builder.SetObject(object) + builder.SetDefinition(object) + + return builder, nil +} + +// PullNamespacedBuilder creates a new Builder for a namespaced resource, pulling the resource from the cluster. +// It is generic over the actual builder type and uses the methods from the Builder interface to create the actual +// builder. Generic parameters are ordered so that SO and SB can be elided and only O and B must be provided. +func PullNamespacedBuilder[O, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO]]( + ctx context.Context, apiClient runtimeclient.Client, schemeAttacher clients.SchemeAttacher, name, nsname string) (SB, error) { + var builder SB = new(B) + + if mixinAttacher, ok := any(builder).(MixinAttacher); ok { + mixinAttacher.AttachMixins() + } + + builder.SetGVK(builder.GetGVK()) + builder.SetClient(apiClient) + builder.SetDefinition(new(O)) + builder.GetDefinition().SetName(name) + builder.GetDefinition().SetNamespace(nsname) + + resourceKey := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Pulling builder for %s", resourceKey.String()) + + if isInterfaceNil(apiClient) { + klog.V(100).Infof("The apiClient provided for %s is nil", resourceKey.String()) + + return nil, errors.NewAPIClientNil(resourceKey) + } + + err := schemeAttacher(apiClient.Scheme()) + if err != nil { + klog.V(100).Infof("Failed to attach scheme for %s: %v", resourceKey.String(), err) + + return nil, errors.NewSchemeAttacherFailed(resourceKey, err) + } + + if name == "" { + klog.V(100).Infof("The name of the builder for %s is empty", resourceKey.String()) + + return nil, errors.NewBuilderFieldEmpty(resourceKey, errors.BuilderFieldName) + } + + if nsname == "" { + klog.V(100).Infof("The namespace of the builder for %s is empty", resourceKey.String()) + + return nil, errors.NewBuilderFieldEmpty(resourceKey, errors.BuilderFieldNamespace) + } + + object, err := Get(ctx, builder) + if err != nil { + klog.V(100).Infof("Failed to pull the builder for %s: %v", resourceKey.String(), err) + + return nil, fmt.Errorf("failed to pull builder: %w", err) + } + + builder.SetObject(object) + builder.SetDefinition(object) + + return builder, nil +} + +// Get pulls the resource from the cluster and returns it. It does not modify the builder. +func Get[O any, SO ObjectPointer[O]](ctx context.Context, builder Builder[O, SO]) (SO, error) { + if err := Validate(builder); err != nil { + return nil, err + } + + key := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Getting %s", key.String()) + + var object SO = new(O) + + err := builder.GetClient().Get(logging.WithDiscardLogger(ctx), runtimeclient.ObjectKeyFromObject(builder.GetDefinition()), object) + if err != nil { + return nil, errors.NewAPICallFailed("get", key, err) + } + + return object, nil +} + +// Exists checks if the resource exists in the cluster. If the resource does exist, the builder's object is updated with +// the resource and this returns true. If the resource does not exist or an error was encountered getting the resource, +// this returns false without modifying the builder. +func Exists[O any, SO ObjectPointer[O]](ctx context.Context, builder Builder[O, SO]) bool { + if err := Validate(builder); err != nil { + return false + } + + key := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Checking if %s exists", key.String()) + + object, err := Get(ctx, builder) + if err != nil { + klog.V(100).Infof("Failed to get %s: %v", key.String(), err) + + return false + } + + builder.SetObject(object) + + return true +} + +// Delete deletes the resource from the cluster. It immediately tries to delete the resource and if successful, or the +// resource did not exist, the builder's object is set to nil. Otherwise, the error is wrapped and returned without +// modifying the builder. +func Delete[O any, SO ObjectPointer[O]](ctx context.Context, builder Builder[O, SO]) error { + if err := Validate(builder); err != nil { + return err + } + + key := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Deleting %s", key.String()) + + err := builder.GetClient().Delete(logging.WithDiscardLogger(ctx), builder.GetDefinition()) + if err == nil || k8serrors.IsNotFound(err) { + builder.SetObject(nil) + + return nil + } + + klog.V(100).Infof("Failed to delete %s: %v", key.String(), err) + + return errors.NewAPICallFailed("delete", key, err) +} + +// Update updates the resource on the cluster using the builder's definition. It immediately tries to update the +// resource and if successful, will update the builder's object to be the definition. Otherwise, it checks to see if the +// error is because the resource did not exist, returning with an error if so. If the error is for any other reason, the +// behavior depends on the force flag. +// +// If force is true, the resource will be deleted and recreated. Otherwise, the error is wrapped and returned without +// modifying the builder. It is generally discouraged to use the force flag since finalizers may cause unexpected side +// effects and most update errors can be resolved by retrying on conflict. +func Update[O any, SO ObjectPointer[O]](ctx context.Context, builder Builder[O, SO], force bool) error { + if err := Validate(builder); err != nil { + return err + } + + key := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Updating %s with force %t", key.String(), force) + + latestObject, err := Get(ctx, builder) + if err != nil { + klog.V(100).Infof("Failed to get latest object for %s: %v", key.String(), err) + + return fmt.Errorf("failed get latest object for update: %w", err) + } + + builder.GetDefinition().SetResourceVersion(latestObject.GetResourceVersion()) + + err = builder.GetClient().Update(logging.WithDiscardLogger(ctx), builder.GetDefinition()) + if err == nil { + builder.SetObject(builder.GetDefinition()) + + return nil + } + + if !force { + klog.V(100).Infof("Failed to update %s without force: %v", key.String(), err) + + return errors.NewAPICallFailed("update", key, err) + } + + err = Delete(ctx, builder) + if err != nil { + klog.V(100).Infof("Failed to delete %s during force update: %v", key.String(), err) + + return fmt.Errorf("failed to force update: %w", err) + } + + err = Create(ctx, builder) + if err != nil { + klog.V(100).Infof("Failed to create %s during force update: %v", key.String(), err) + + return fmt.Errorf("failed to force update: %w", err) + } + + return nil +} + +// Create creates the definition on the cluster. If the resource already exists, this is a no-op. +func Create[O any, SO ObjectPointer[O]](ctx context.Context, builder Builder[O, SO]) error { + if err := Validate(builder); err != nil { + return err + } + + key := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Creating %s", key.String()) + + // Create requests will be rejected if the resource version is set, so we clear it. + builder.GetDefinition().SetResourceVersion("") + + err := builder.GetClient().Create(logging.WithDiscardLogger(ctx), builder.GetDefinition()) + if err == nil { + builder.SetObject(builder.GetDefinition()) + + return nil + } + + if k8serrors.IsAlreadyExists(err) { + klog.V(100).Infof("The resource %s already exists and cannot be created", key.String()) + + return nil + } + + klog.V(100).Infof("Failed to create %s: %v", key.String(), err) + + return errors.NewAPICallFailed("create", key, err) +} + +// Validate checks that the builder is valid, that is, it is non-nil, has a non-nil definition, has a non-nil client, +// and has no error message. Additional checks are performed on any interface so that we know it is not nil and its +// concrete type is not nil. +func Validate[O any, SO ObjectPointer[O]](builder Builder[O, SO]) error { + if isInterfaceNil(builder) { + klog.V(100).Infof("The builder is nil") + + return errors.NewBuilderNil() + } + + if builder.GetDefinition() == nil { + klog.V(100).Infof("The %s builder definition is nil", builder.GetGVK().Kind) + + return errors.NewBuilderDefinitionNil(builder.GetGVK().Kind) + } + + key := NewResourceKeyFromBuilder(builder) + + if isInterfaceNil(builder.GetClient()) { + klog.V(100).Infof("The apiClient provided for %s is nil", key.String()) + + return errors.NewAPIClientNil(key) + } + + err := builder.GetError() + if err != nil { + klog.V(100).Infof("The builder for %s has an error: %v", key.String(), err) + + return fmt.Errorf("failed to validate: %w", err) + } + + return nil +} + +// ListPointer is a type constraint that requires a type be a pointer to L and implement the runtimeclient.ObjectList +// interface. The type parameter L is meant to be a K8s resource list, such as corev1.NamespaceList. In that case, +// *corev1.NamespaceList would satisfy the constraint ListPointer[corev1.NamespaceList]. +// +// This is the list equivalent of [ObjectPointer]. +type ListPointer[L any] interface { + *L + runtimeclient.ObjectList +} + +// List lists the resources in the cluster and returns a list of builders for each resource. +func List[O, L, B any, SO ObjectPointer[O], SL ListPointer[L], SB BuilderPointer[B, O, SO]]( + ctx context.Context, + apiClient runtimeclient.Client, + schemeAttacher clients.SchemeAttacher, + options ...runtimeclient.ListOption) ([]SB, error) { + var dummyBuilder SB = new(B) + + resourceKey := key.NewResourceKey(dummyBuilder.GetGVK().Kind, "", "") + + if isInterfaceNil(apiClient) { + klog.V(100).Infof("The apiClient provided for listing %s is nil", resourceKey.String()) + + return nil, errors.NewAPIClientNil(resourceKey) + } + + err := schemeAttacher(apiClient.Scheme()) + if err != nil { + klog.V(100).Infof("Failed to attach scheme for listing %s: %v", resourceKey.String(), err) + + return nil, errors.NewSchemeAttacherFailed(resourceKey, err) + } + + var list SL = new(L) + + err = apiClient.List(logging.WithDiscardLogger(ctx), list, options...) + if err != nil { + klog.V(100).Infof("Failed to list %s: %v", resourceKey.String(), err) + + return nil, errors.NewAPICallFailed("list", resourceKey, err) + } + + items, err := meta.ExtractList(list) + if err != nil { + klog.V(100).Infof("Failed to extract list for %s: %v", resourceKey.String(), err) + + return nil, fmt.Errorf("failed to extract list: %w", err) + } + + var builders []SB + + for _, item := range items { + typedItem, ok := item.(SO) + if !ok { + klog.V(100).Infof("Item with type %T does not match expected type %s", item, resourceKey.String()) + + return nil, errors.NewItemTypeMismatch(resourceKey.Kind, reflect.TypeOf(item)) + } + + var builder SB = new(B) + + if mixinAttacher, ok := any(builder).(MixinAttacher); ok { + mixinAttacher.AttachMixins() + } + + builder.SetDefinition(typedItem) + builder.SetObject(typedItem) + builder.SetClient(apiClient) + builder.SetGVK(builder.GetGVK()) + + builders = append(builders, builder) + } + + return builders, nil +} + +// ConvertListOptionsToOptions converts a slice of runtimeclient.ListOptions to a slice of runtimeclient.ListOption. +// This is to allow for compatibility with existing functions which used ListOptions instead of ListOption. +func ConvertListOptionsToOptions(options []runtimeclient.ListOptions) []runtimeclient.ListOption { + listOptions := make([]runtimeclient.ListOption, len(options)) + + for i, option := range options { + listOptions[i] = &option + } + + return listOptions +} + +// AdditionalOption is a constraint satisfied by any named function type whose underlying type is +// func(SB) (SB, error). This allows resource-specific option types (e.g. configmap.AdditionalOptions) to be passed +// directly to WithOptions without conversion. +type AdditionalOption[SB any] interface { + ~func(SB) (SB, error) +} + +// WithOptions applies the provided functional options to the builder. If the builder is invalid, it is returned as is. +// If any option returns an error, the error is set on the builder and the builder is returned immediately without +// applying subsequent options. Nil options are skipped. +func WithOptions[O, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO], AO AdditionalOption[SB]]( + builder SB, options ...AO) SB { + if err := Validate(builder); err != nil { + return builder + } + + resourceKey := NewResourceKeyFromBuilder(builder) + + klog.V(100).Infof("Applying %d options to %s", len(options), resourceKey.String()) + + for _, option := range options { + if option == nil { + continue + } + + nextBuilder, err := option(builder) + if nextBuilder != nil { + builder = nextBuilder + } + + if err != nil { + klog.V(100).Infof("Error occurred while applying option to %s: %v", resourceKey.String(), err) + + builder.SetError(err) + + return builder + } + } + + return builder +} + +// isInterfaceNil checks if the interface is nil. It checks both equality against nil and the reflect.Value.IsNil +// method. This ensures that neither the interface nor its concrete value are nil. +func isInterfaceNil(v any) bool { + return v == nil || reflect.ValueOf(v).IsNil() +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/doc.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/doc.go new file mode 100644 index 000000000..f190842c2 --- /dev/null +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/doc.go @@ -0,0 +1,7 @@ +// Package common provides a set of common functionality that can be used to reduce the boilerplate required for adding +// builders for new resources. +// +// The Builder interface is mainly for use within the common package and describes the methods that builders must +// implement to take advantage of the common functions. These common functions may be used to implement the typical CRUD +// methods of a builder. +package common diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_builder.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_builder.go new file mode 100644 index 000000000..1e913762c --- /dev/null +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_builder.go @@ -0,0 +1,97 @@ +package common + +import ( + "context" + + "k8s.io/apimachinery/pkg/runtime/schema" + runtimeclient "sigs.k8s.io/controller-runtime/pkg/client" +) + +// EmbeddableBuilder is a struct implementing the Builder interface that can be embedded in existing builder structs. It +// provides the basic fields and methods for CRUD functions that builders need. +type EmbeddableBuilder[O any, SO ObjectPointer[O]] struct { + // Definition is the desired form of the resource. + Definition SO + // Object is the last pulled form of the resource. + Object SO + // err is the error stored in the builder. + err error + // apiClient is the client used for connecting with the K8s cluster. + apiClient runtimeclient.Client + // gvk is the GVK of the resource the builder represents. It is set by [SetGVK] and then returned by all + // subsequent [GetGVK] calls. + gvk schema.GroupVersionKind +} + +// GetDefinition returns the desired form of the resource. This method returns a pointer to the definition, which can be +// modified directly. +func (b *EmbeddableBuilder[O, SO]) GetDefinition() SO { + return b.Definition +} + +// SetDefinition updates the desired form of the resource. In general, end users would want to use either the builder +// modifiers or make changes to the definition returned from [GetDefinition]. +func (b *EmbeddableBuilder[O, SO]) SetDefinition(definition SO) { + b.Definition = definition +} + +// GetObject returns the last pulled form of the resource. +func (b *EmbeddableBuilder[O, SO]) GetObject() SO { + return b.Object +} + +// SetObject updates the last pulled form of the resource. End users should not call this method directly since the +// object is automatically updated when the resource is pulled from the cluster. +func (b *EmbeddableBuilder[O, SO]) SetObject(object SO) { + b.Object = object +} + +// GetError returns the error stored in the builder. End users should not call this method directly since the error is +// returned during validation. +func (b *EmbeddableBuilder[O, SO]) GetError() error { + return b.err +} + +// SetError updates the error stored in the builder. End users should not call this method directly since the error is +// automatically set by the builder modifiers. +func (b *EmbeddableBuilder[O, SO]) SetError(err error) { + b.err = err +} + +// GetClient returns the client used for connecting with the K8s cluster. +func (b *EmbeddableBuilder[O, SO]) GetClient() runtimeclient.Client { + return b.apiClient +} + +// SetClient updates the client used for connecting with the K8s cluster. End users should not call this method directly +// since the client is automatically set when the builder is created. +func (b *EmbeddableBuilder[O, SO]) SetClient(apiClient runtimeclient.Client) { + b.apiClient = apiClient +} + +// GetGVK returns the GVK for the resource the builder represents, even if the builder is zero-valued. However, +// embedders should override this method to return the proper GVK for the embedding builder. +// +// During builder initialization, the [SetGVK] method is called to set the GVK for the builder. This method returns the +// value provided through [SetGVK]. +func (b *EmbeddableBuilder[O, SO]) GetGVK() schema.GroupVersionKind { + return b.gvk +} + +// SetGVK updates the GVK for the resource the builder represents. Embedders should not override this method since it +// will be called when initializing the builder to ensure that [GetGVK] returns the proper GVK. +func (b *EmbeddableBuilder[O, SO]) SetGVK(gvk schema.GroupVersionKind) { + b.gvk = gvk +} + +// Get pulls the resource from the cluster and returns it. It does not modify the builder. +func (b *EmbeddableBuilder[O, SO]) Get() (SO, error) { + return Get(context.TODO(), b) +} + +// Exists checks whether the resource exists on the cluster. If the resource does exist, the builder's object is updated +// with the resource and this returns true. If the builder is invalid, or the resource cannot be retrieved, this returns +// false without modifying the builder. +func (b *EmbeddableBuilder[O, SO]) Exists() bool { + return Exists(context.TODO(), b) +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_creator.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_creator.go new file mode 100644 index 000000000..54d5f84e1 --- /dev/null +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_creator.go @@ -0,0 +1,21 @@ +package common + +import "context" + +// EmbeddableCreator is a mixin which provides the Create method to the embedding builder. The Create method immediately +// creates the resource in the cluster and returns the builder and the error from the Create method. +type EmbeddableCreator[O any, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO]] struct { + base SB +} + +// SetBase sets the base builder for the mixin. When the Create method is called, the common Create method will be +// called on the base builder. This base is also what gets returned by the Create method. +func (creator *EmbeddableCreator[O, B, SO, SB]) SetBase(base SB) { + creator.base = base +} + +// Create creates the resource in the cluster. It first checks if the resource already exists and if so, does nothing. +// Otherwise, it tries to create the resource and returns the builder and the error from the Create method. +func (creator *EmbeddableCreator[O, B, SO, SB]) Create() (SB, error) { + return creator.base, Create(context.TODO(), creator.base) +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_deleter.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_deleter.go new file mode 100644 index 000000000..f7e02a97d --- /dev/null +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_deleter.go @@ -0,0 +1,45 @@ +package common + +import "context" + +// EmbeddableDeleter is a mixin which provides the Delete method to the embedding builder. +type EmbeddableDeleter[O any, SO ObjectPointer[O]] struct { + base Builder[O, SO] +} + +// SetBase sets the base builder for the mixin. When the Delete method is called, the common Delete method will be +// called on the base builder. In practice, this can be either the EmbeddableBuilder or the resource-specific builder. +func (deleter *EmbeddableDeleter[O, SO]) SetBase(base Builder[O, SO]) { + deleter.base = base +} + +// Delete deletes the resource from the cluster. It immediately tries to delete the resource and if successful, or the +// resource did not exist, the builder's object is set to nil. Otherwise, the error is wrapped and returned without +// modifying the builder. +func (deleter *EmbeddableDeleter[O, SO]) Delete() error { + return Delete(context.TODO(), deleter.base) +} + +// EmbeddableDeleteReturner is a mixin which provides the Delete method to the embedding builder. The Delete method +// returns the builder and the error from the Delete method. To maintain compatibility with existing Delete methods +// which return the builder, this struct has more complicated type parameters than the EmbeddableDeleter. +// +// Consumers of this mixin should set the base to the embedding builder rather than the EmbeddableBuilder so that Delete +// returns the correct type. +type EmbeddableDeleteReturner[O any, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO]] struct { + base SB +} + +// SetBase sets the base builder for the mixin. When the Delete method is called, the common Delete method will be +// called on the base builder. For EmbeddableDeleteReturner, the base should be the resource-specific builder rather +// than EmbeddableBuilder. +func (deleter *EmbeddableDeleteReturner[O, B, SO, SB]) SetBase(base SB) { + deleter.base = base +} + +// Delete deletes the resource from the cluster. It immediately tries to delete the resource and if successful, or the +// resource did not exist, the builder's object is set to nil. Otherwise, the error is wrapped and returned without +// modifying the builder. Regardless of the error, the builder is returned. +func (deleter *EmbeddableDeleteReturner[O, B, SO, SB]) Delete() (SB, error) { + return deleter.base, Delete(context.TODO(), deleter.base) +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_updater.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_updater.go new file mode 100644 index 000000000..0edc6459d --- /dev/null +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_updater.go @@ -0,0 +1,42 @@ +package common + +import "context" + +// EmbeddableUpdater is a mixin which provides the Update method to the embedding builder. The Update method does not +// force the update and will return an error if the resource could not be updated. +type EmbeddableUpdater[O any, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO]] struct { + base SB +} + +// SetBase sets the base builder for the mixin. When the Update method is called, the common Update method will be +// called on the base builder. This base is also what gets returned by the Update method. +func (updater *EmbeddableUpdater[O, B, SO, SB]) SetBase(base SB) { + updater.base = base +} + +// Update updates the resource in the cluster. It does not force the update and will return an error if the resource +// could not be updated. It checks for the resource's existence and attempts to align resource versions to avoid +// conflict. +func (updater *EmbeddableUpdater[O, B, SO, SB]) Update() (SB, error) { + return updater.base, Update(context.TODO(), updater.base, false) +} + +// EmbeddableForceUpdater is a mixin which provides the Update method to the embedding builder. The Update method +// provides the option to force an update by deleting and recreating the resource. +type EmbeddableForceUpdater[O any, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO]] struct { + base SB +} + +// SetBase sets the base builder for the mixin. When the Update method is called, the common Update method will be +// called on the base builder. This base is also what gets returned by the Update method. +func (updater *EmbeddableForceUpdater[O, B, SO, SB]) SetBase(base SB) { + updater.base = base +} + +// Update updates the resource in the cluster. It provides the option to force an update by deleting and recreating the +// resource. It checks for the resource's existence and attempts to align resource versions to avoid conflict. +// Regardless of the force flag, this function returns an error if the resource does not exist. When it exists, the +// resource version just pulled from the cluster is used to avoid conflicts. +func (updater *EmbeddableForceUpdater[O, B, SO, SB]) Update(force bool) (SB, error) { + return updater.base, Update(context.TODO(), updater.base, force) +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_withoptions.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_withoptions.go new file mode 100644 index 000000000..befef00c5 --- /dev/null +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/embeddable_withoptions.go @@ -0,0 +1,22 @@ +package common + +// EmbeddableWithOptions is a mixin which provides the WithOptions method to the embedding builder. It allows applying +// functional options to the builder in a chainable manner. The AO type parameter accepts named option types (e.g. +// configmap.AdditionalOptions) that satisfy the AdditionalOption constraint. +type EmbeddableWithOptions[O, B any, SO ObjectPointer[O], SB BuilderPointer[B, O, SO], AO AdditionalOption[SB]] struct { + base SB +} + +// SetBase sets the base builder for the mixin. When the WithOptions method is called, the common WithOptions function +// will be called on the base builder. For EmbeddableWithOptions, the base should be the resource-specific builder +// rather than EmbeddableBuilder so that WithOptions returns the correct type. +func (mixin *EmbeddableWithOptions[O, B, SO, SB, AO]) SetBase(base SB) { + mixin.base = base +} + +// WithOptions applies the provided functional options to the builder. If the builder is invalid, it is returned as is. +// If any option returns an error, the error is set on the builder and the builder is returned immediately without +// applying subsequent options. Nil options are skipped. +func (mixin *EmbeddableWithOptions[O, B, SO, SB, AO]) WithOptions(options ...AO) SB { + return WithOptions[O, B, SO, SB, AO](mixin.base, options...) +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/errors/errors.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/errors/errors.go new file mode 100644 index 000000000..88aebccb1 --- /dev/null +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/errors/errors.go @@ -0,0 +1,209 @@ +// Package errors provides the error types for the common package. It is currently meant just for use in the common +// package and therefore focuses on the errors encountered in the common package. +package errors + +import ( + "errors" + "fmt" + "reflect" + + "github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/key" +) + +type apiClientNilError struct { + resourceKey key.ResourceKey +} + +var _ error = (*apiClientNilError)(nil) + +// NewAPIClientNil creates a new error that indicates that the apiClient for a builder is nil. +func NewAPIClientNil(resourceKey key.ResourceKey) *apiClientNilError { + return &apiClientNilError{resourceKey: resourceKey} +} + +func (e *apiClientNilError) Error() string { + return fmt.Sprintf("apiClient for %s is nil", e.resourceKey.String()) +} + +// IsAPIClientNil returns true if an error, or any error in the error's tree, is due to the apiClient being nil. +func IsAPIClientNil(err error) bool { + var apiClientNilError *apiClientNilError + + return errors.As(err, &apiClientNilError) +} + +type schemeAttacherFailedError struct { + resourceKey key.ResourceKey + err error +} + +var _ error = (*schemeAttacherFailedError)(nil) + +// NewSchemeAttacherFailed creates a new error that indicates that the scheme attacher failed to attach. It wraps the +// error returned by the scheme attacher function. +func NewSchemeAttacherFailed(resourceKey key.ResourceKey, err error) *schemeAttacherFailedError { + return &schemeAttacherFailedError{resourceKey: resourceKey, err: err} +} + +func (e *schemeAttacherFailedError) Error() string { + return fmt.Sprintf("failed to attach scheme for %s: %v", e.resourceKey.String(), e.err) +} + +func (e *schemeAttacherFailedError) Unwrap() error { + return e.err +} + +// IsSchemeAttacherFailed returns true if an error, or any error in the error's tree, is due to the scheme attacher +// failing to attach. +func IsSchemeAttacherFailed(err error) bool { + var schemeAttacherFailed *schemeAttacherFailedError + + return errors.As(err, &schemeAttacherFailed) +} + +type builderFieldEmptyError struct { + resourceKey key.ResourceKey + field BuilderField +} + +var _ error = (*builderFieldEmptyError)(nil) + +// BuilderField is a type that represents a field for a builder. +type BuilderField string + +const ( + // BuilderFieldName is the name of the field for a builder's name. This corresponds to the Name field of the + // ObjectMeta. + BuilderFieldName BuilderField = "name" + // BuilderFieldNamespace is the namespace of the field for a builder's namespace. This corresponds to the + // Namespace field of the ObjectMeta. + BuilderFieldNamespace BuilderField = "namespace" +) + +// NewBuilderFieldEmpty creates a new error that indicates that a field for a builder is empty. +func NewBuilderFieldEmpty(resourceKey key.ResourceKey, field BuilderField) *builderFieldEmptyError { + return &builderFieldEmptyError{resourceKey: resourceKey, field: field} +} + +func (e *builderFieldEmptyError) Error() string { + return fmt.Sprintf("%s of the builder for %s is empty", e.field, e.resourceKey.String()) +} + +// IsBuilderNameEmpty returns true if an error, or any error in the error's tree, is due to the builder's name being +// empty. +func IsBuilderNameEmpty(err error) bool { + var builderFieldEmpty *builderFieldEmptyError + + return errors.As(err, &builderFieldEmpty) && builderFieldEmpty.field == BuilderFieldName +} + +// IsBuilderNamespaceEmpty returns true if an error, or any error in the error's tree, is due to the builder's namespace +// being empty. +func IsBuilderNamespaceEmpty(err error) bool { + var builderFieldEmpty *builderFieldEmptyError + + return errors.As(err, &builderFieldEmpty) && builderFieldEmpty.field == BuilderFieldNamespace +} + +type apiCallFailedError struct { + verb string + resourceKey key.ResourceKey + err error +} + +var _ error = (*apiCallFailedError)(nil) + +// NewAPICallFailed creates a new error that indicates that an API call failed. The verb is not validated, but intended +// to correspond to the basic methods in the Kubernetes interface, such as Get, List, Create, etc. +func NewAPICallFailed(verb string, resourceKey key.ResourceKey, err error) *apiCallFailedError { + return &apiCallFailedError{verb: verb, resourceKey: resourceKey, err: err} +} + +func (e *apiCallFailedError) Error() string { + return fmt.Sprintf("failed to %s %s: %v", e.verb, e.resourceKey.String(), e.err) +} + +func (e *apiCallFailedError) Unwrap() error { + return e.err +} + +// IsAPICallFailed returns true if an error, or any error in the error's tree, is due to an API call failing. +func IsAPICallFailed(err error) bool { + var apiCallFailed *apiCallFailedError + + return errors.As(err, &apiCallFailed) +} + +// IsAPICallFailedWithVerb returns true if an error, or any error in the error's tree, is due to an API call failing +// with the given verb. +func IsAPICallFailedWithVerb(err error, verb string) bool { + var apiCallFailed *apiCallFailedError + + return errors.As(err, &apiCallFailed) && apiCallFailed.verb == verb +} + +type builderNilError struct{} + +var _ error = (*builderNilError)(nil) + +// NewBuilderNil creates a new error that indicates that the builder is nil. +func NewBuilderNil() *builderNilError { + return &builderNilError{} +} + +func (e *builderNilError) Error() string { + return "builder is nil" +} + +// IsBuilderNil returns true if an error, or any error in the error's tree, is due to the builder being nil. +func IsBuilderNil(err error) bool { + var builderNil *builderNilError + + return errors.As(err, &builderNil) +} + +type builderDefinitionNilError struct { + kind string +} + +var _ error = (*builderDefinitionNilError)(nil) + +// NewBuilderDefinitionNil creates a new error that indicates that the builder's definition is nil. +func NewBuilderDefinitionNil(kind string) *builderDefinitionNilError { + return &builderDefinitionNilError{kind: kind} +} + +func (e *builderDefinitionNilError) Error() string { + return fmt.Sprintf("%s builder definition is nil", e.kind) +} + +// IsBuilderDefinitionNil returns true if an error, or any error in the error's tree, is due to the builder's definition +// being nil. +func IsBuilderDefinitionNil(err error) bool { + var builderDefinitionNil *builderDefinitionNilError + + return errors.As(err, &builderDefinitionNil) +} + +type itemTypeMismatchError struct { + kind string + itemType reflect.Type +} + +var _ error = (*itemTypeMismatchError)(nil) + +// NewItemTypeMismatch creates a new error that indicates that an item type mismatch occurred. +func NewItemTypeMismatch(kind string, itemType reflect.Type) *itemTypeMismatchError { + return &itemTypeMismatchError{kind: kind, itemType: itemType} +} + +func (e *itemTypeMismatchError) Error() string { + return fmt.Sprintf("item has kind %s but type %s", e.kind, e.itemType.String()) +} + +// IsItemTypeMismatch returns true if an error, or any error in the error's tree, is due to an item type mismatch. +func IsItemTypeMismatch(err error) bool { + var itemTypeMismatch *itemTypeMismatchError + + return errors.As(err, &itemTypeMismatch) +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/key/key.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/key/key.go new file mode 100644 index 000000000..74740d838 --- /dev/null +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/key/key.go @@ -0,0 +1,29 @@ +package key + +import ( + "fmt" +) + +// ResourceKey is a standard set of information required to uniquely identify a resource in a cluster. +type ResourceKey struct { + Kind string + Name string + Namespace string +} + +func (k ResourceKey) String() string { + if k.Name == "" { + return k.Kind + } + + if k.Namespace == "" { + return fmt.Sprintf("%s %s", k.Kind, k.Name) + } + + return fmt.Sprintf("%s %s/%s", k.Kind, k.Namespace, k.Name) +} + +// NewResourceKey creates a new ResourceKey from the given kind, name, and namespace. It does not validate the input. +func NewResourceKey(kind string, name string, namespace string) ResourceKey { + return ResourceKey{Kind: kind, Name: name, Namespace: namespace} +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/logging/context.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/logging/context.go index 047e33f40..909fade7c 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/logging/context.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/logging/context.go @@ -11,3 +11,9 @@ import ( func DiscardContext() context.Context { return logr.NewContext(context.TODO(), logr.Discard()) } + +// WithDiscardLogger returns a copy of ctx with a logr.Discard logger attached, suppressing verbose logging from +// functions that extract a logger from the context. +func WithDiscardLogger(ctx context.Context) context.Context { + return logr.NewContext(ctx, logr.Discard()) +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/network/operator.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/network/operator.go index 72c5933a2..9e20e16c2 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/network/operator.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/network/operator.go @@ -2,6 +2,7 @@ package network import ( "context" + "errors" "fmt" "time" @@ -203,7 +204,13 @@ func (builder *OperatorBuilder) SetIPForwarding( return builder, err } -// SetMultiNetworkPolicy enables network.operator multinetworkpolicy feature. +// SetMultiNetworkPolicy enables or disables the network.operator multinetworkpolicy feature. +// When disabling, the Cluster Network Operator often does not set Progressing=True; the initial +// wait for Progressing=True is skipped in that case only. Enabling keeps the original sequence. +// On disable, we wait until status.observedGeneration catches metadata.generation from the update +// so condition polling is not satisfied from stale status from before this change. +// The wait for Progressing=False uses a disable-specific path: CNO may omit the Progressing +// condition when idle, which would otherwise never match WaitUntilInCondition(..., False). func (builder *OperatorBuilder) SetMultiNetworkPolicy(state bool, timeout time.Duration) (*OperatorBuilder, error) { if valid, err := builder.validate(); !valid { return builder, err @@ -221,20 +228,34 @@ func (builder *OperatorBuilder) SetMultiNetworkPolicy(state bool, timeout time.D return nil, err } - err = builder.WaitUntilInCondition( - operatorv1.OperatorStatusTypeProgressing, 60*time.Second, operatorv1.ConditionTrue) - if err != nil { - return nil, err + targetGeneration := builder.Definition.Generation + + if state { + err = builder.WaitUntilInCondition( + operatorv1.OperatorStatusTypeProgressing, 60*time.Second, operatorv1.ConditionTrue) + if err != nil { + return nil, err + } + } else { + err = builder.waitUntilObservedGeneration(targetGeneration, timeout) + if err != nil { + return nil, err + } + } + + if state { + err = builder.WaitUntilInCondition( + operatorv1.OperatorStatusTypeProgressing, timeout, operatorv1.ConditionFalse) + } else { + err = builder.waitUntilProgressingSettledOnDisable(timeout) } - err = builder.WaitUntilInCondition( - operatorv1.OperatorStatusTypeProgressing, timeout, operatorv1.ConditionFalse) if err != nil { return nil, err } return builder, builder.WaitUntilInCondition( - operatorv1.OperatorStatusTypeAvailable, 60*time.Second, operatorv1.ConditionTrue) + operatorv1.OperatorStatusTypeAvailable, timeout, operatorv1.ConditionTrue) } return builder, err @@ -288,8 +309,8 @@ func (builder *OperatorBuilder) WaitUntilInCondition( return err } - klog.V(100).Infof("Wait until network.operator object %s is in condition %v", - builder.Definition.Name, condition) + klog.V(100).Infof("Wait until network.operator object %s has condition %s=%s", + builder.Definition.Name, condition, status) err := wait.PollUntilContextTimeout( context.TODO(), 3*time.Second, timeout, true, func(ctx context.Context) (bool, error) { @@ -306,9 +327,85 @@ func (builder *OperatorBuilder) WaitUntilInCondition( return false, nil }) + if err != nil && errors.Is(err, context.DeadlineExceeded) && builder.Object != nil { + klog.V(100).Infof("timeout waiting for network.operator %s condition %s=%s; last status conditions: %#v", + builder.Definition.Name, condition, status, builder.Object.Status.Conditions) + } + return err } +// waitUntilObservedGeneration waits until status.observedGeneration reflects the given metadata.generation, +// indicating the operator has reconciled that spec revision. +func (builder *OperatorBuilder) waitUntilObservedGeneration(targetGeneration int64, timeout time.Duration) error { + if valid, err := builder.validate(); !valid { + return err + } + + klog.V(100).Infof("Wait until network.operator %s observedGeneration >= %d", + builder.Definition.Name, targetGeneration) + + return wait.PollUntilContextTimeout( + context.TODO(), 3*time.Second, timeout, true, func(ctx context.Context) (bool, error) { + if !builder.Exists() { + return false, fmt.Errorf("network.operator object %s does not exist", builder.Definition.Name) + } + + return builder.Object.Status.ObservedGeneration >= targetGeneration, nil + }) +} + +// waitUntilProgressingSettledOnDisable waits until Progressing is False, or until the operator +// reports available and not degraded while Progressing is absent (CNO may omit Progressing when idle). +func (builder *OperatorBuilder) waitUntilProgressingSettledOnDisable(timeout time.Duration) error { + if valid, err := builder.validate(); !valid { + return err + } + + klog.V(100).Infof("Wait until network.operator %s is settled after disabling MultiNetworkPolicy", + builder.Definition.Name) + + return wait.PollUntilContextTimeout( + context.TODO(), 3*time.Second, timeout, true, func(ctx context.Context) (bool, error) { + if !builder.Exists() { + return false, fmt.Errorf("network.operator object %s does not exist", builder.Definition.Name) + } + + for _, c := range builder.Object.Status.Conditions { + if c.Type != operatorv1.OperatorStatusTypeProgressing { + continue + } + + return c.Status == operatorv1.ConditionFalse, nil + } + + return operatorAvailableAndNotDegraded(builder.Object.Status.Conditions), nil + }) +} + +func operatorAvailableAndNotDegraded(conditions []operatorv1.OperatorCondition) bool { + var available, degraded *operatorv1.OperatorCondition + + for i := range conditions { + switch conditions[i].Type { + case operatorv1.OperatorStatusTypeAvailable: + available = &conditions[i] + case operatorv1.OperatorStatusTypeDegraded: + degraded = &conditions[i] + } + } + + if available == nil || available.Status != operatorv1.ConditionTrue { + return false + } + + if degraded != nil && degraded.Status == operatorv1.ConditionTrue { + return false + } + + return len(conditions) > 0 +} + // validate will check that the builder and builder definition are properly initialized before // accessing any member fields. func (builder *OperatorBuilder) validate() (bool, error) { diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/route/route.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/route/route.go index 75e6f453c..07d02e18a 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/route/route.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/route/route.go @@ -1,32 +1,35 @@ package route import ( + "context" "fmt" "slices" routev1 "github.com/openshift/api/route/v1" "github.com/rh-ecosystem-edge/eco-goinfra/pkg/clients" - "github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/logging" - "github.com/rh-ecosystem-edge/eco-goinfra/pkg/msg" - k8serrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common" + "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/klog/v2" - - goclient "sigs.k8s.io/controller-runtime/pkg/client" ) // Builder provides struct for route object containing connection to the cluster and the route definitions. type Builder struct { - // Route definition. Used to create a route object - Definition *routev1.Route - // Created route object - Object *routev1.Route - // Used in functions that define or mutate the route definition. - // errorMsg is processed before the route object is created - errorMsg string - apiClient goclient.Client + common.EmbeddableBuilder[routev1.Route, *routev1.Route] + common.EmbeddableCreator[routev1.Route, Builder, *routev1.Route, *Builder] + common.EmbeddableDeleteReturner[routev1.Route, Builder, *routev1.Route, *Builder] +} + +// AttachMixins attaches the mixins to the builder. This is called automatically when the builder is initialized. +func (builder *Builder) AttachMixins() { + builder.EmbeddableCreator.SetBase(builder) + builder.EmbeddableDeleteReturner.SetBase(builder) +} + +// GetGVK returns the GVK for the Route resource. +func (builder *Builder) GetGVK() schema.GroupVersionKind { + return routev1.GroupVersion.WithKind("Route") } // NewBuilder creates a new instance of Builder. @@ -35,52 +38,24 @@ func NewBuilder(apiClient *clients.Settings, name, nsname, serviceName string) * "Initializing new route structure with the following params: name: %s, namespace: %s, serviceName: %s", name, nsname, serviceName) - if apiClient == nil { - klog.V(100).Info("The apiClient is nil") - - return nil - } - - builder := &Builder{ - apiClient: apiClient.Client, - Definition: &routev1.Route{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: nsname, - }, - Spec: routev1.RouteSpec{ - To: routev1.RouteTargetReference{ - Kind: "Service", - Name: serviceName, - }, - }, - }, - } - - if name == "" { - klog.V(100).Info("The name of the route is empty") - - builder.errorMsg = "route 'name' cannot be empty" - - return builder - } - - if nsname == "" { - klog.V(100).Info("The namespace of the route is empty") - - builder.errorMsg = "route 'nsname' cannot be empty" - + builder := common.NewNamespacedBuilder[routev1.Route, Builder](apiClient, routev1.AddToScheme, name, nsname) + if builder.GetError() != nil { return builder } if serviceName == "" { klog.V(100).Info("The serviceName of the route is empty") - builder.errorMsg = "route 'serviceName' cannot be empty" + builder.SetError(fmt.Errorf("route 'serviceName' cannot be empty")) return builder } + builder.Definition.Spec.To = routev1.RouteTargetReference{ + Kind: "Service", + Name: serviceName, + } + return builder } @@ -88,46 +63,13 @@ func NewBuilder(apiClient *clients.Settings, name, nsname, serviceName string) * func Pull(apiClient *clients.Settings, name, nsname string) (*Builder, error) { klog.V(100).Infof("Pulling existing route name %s under namespace %s from cluster", name, nsname) - if apiClient == nil { - klog.V(100).Info("The apiClient is nil") - - return nil, fmt.Errorf("the apiClient cannot be nil") - } - - builder := &Builder{ - apiClient: apiClient.Client, - Definition: &routev1.Route{ - ObjectMeta: metav1.ObjectMeta{ - Name: name, - Namespace: nsname, - }, - }, - } - - if name == "" { - klog.V(100).Info("The name of the route is empty") - - return nil, fmt.Errorf("route 'name' cannot be empty") - } - - if nsname == "" { - klog.V(100).Info("The namespace of the route is empty") - - return nil, fmt.Errorf("route 'namespace' cannot be empty") - } - - if !builder.Exists() { - return nil, fmt.Errorf("route object %s does not exist in namespace %s", name, nsname) - } - - builder.Definition = builder.Object - - return builder, nil + return common.PullNamespacedBuilder[routev1.Route, Builder]( + context.TODO(), apiClient, routev1.AddToScheme, name, nsname) } // WithTargetPortNumber adds a target port to the route by number. func (builder *Builder) WithTargetPortNumber(port int32) *Builder { - if valid, _ := builder.validate(); !valid { + if err := common.Validate(builder); err != nil { return builder } @@ -145,7 +87,7 @@ func (builder *Builder) WithTargetPortNumber(port int32) *Builder { // WithTargetPortName adds a target port to the route by name. func (builder *Builder) WithTargetPortName(portName string) *Builder { - if valid, _ := builder.validate(); !valid { + if err := common.Validate(builder); err != nil { return builder } @@ -155,10 +97,10 @@ func (builder *Builder) WithTargetPortName(portName string) *Builder { if portName == "" { klog.V(100).Info("Received empty route portName") - builder.errorMsg = "route target port name cannot be empty string" + builder.SetError(fmt.Errorf("route target port name cannot be empty string")) } - if builder.errorMsg != "" { + if builder.GetError() != nil { return builder } @@ -173,7 +115,7 @@ func (builder *Builder) WithTargetPortName(portName string) *Builder { // WithHostDomain adds a route host domain to the route. func (builder *Builder) WithHostDomain(hostDomain string) *Builder { - if valid, _ := builder.validate(); !valid { + if err := common.Validate(builder); err != nil { return builder } @@ -183,7 +125,7 @@ func (builder *Builder) WithHostDomain(hostDomain string) *Builder { if hostDomain == "" { klog.V(100).Info("Received empty route hostDomain") - builder.errorMsg = "route host domain cannot be empty string" + builder.SetError(fmt.Errorf("route host domain cannot be empty string")) return builder } @@ -195,7 +137,7 @@ func (builder *Builder) WithHostDomain(hostDomain string) *Builder { // WithWildCardPolicy adds the specified wildCardPolicy to the route. func (builder *Builder) WithWildCardPolicy(wildcardPolicy string) *Builder { - if valid, _ := builder.validate(); !valid { + if err := common.Validate(builder); err != nil { return builder } @@ -203,10 +145,9 @@ func (builder *Builder) WithWildCardPolicy(wildcardPolicy string) *Builder { wildcardPolicy, builder.Definition.Name, builder.Definition.Namespace) if !slices.Contains(supportedWildCardPolicies(), wildcardPolicy) { - klog.V(100).Infof("Received unsupported route wildcardPolicy, supported policies: %v", supportedWildCardPolicies()) + klog.V(100).Infof("Received unsupported route wildcardPolicy, expected one of %v", supportedWildCardPolicies()) - builder.errorMsg = fmt.Sprintf("received unsupported route wildcardPolicy: supported policies %v", - supportedWildCardPolicies()) + builder.SetError(getUnsupportedWildCardPoliciesError()) return builder } @@ -216,129 +157,15 @@ func (builder *Builder) WithWildCardPolicy(wildcardPolicy string) *Builder { return builder } -// Exists checks whether the given route exists. -func (builder *Builder) Exists() bool { - if valid, _ := builder.validate(); !valid { - return false - } - - klog.V(100).Infof( - "Checking if route %s exists in namespace %s", - builder.Definition.Name, builder.Definition.Namespace) - - var err error - - builder.Object, err = builder.Get() - - return err == nil || !k8serrors.IsNotFound(err) -} - -// Get returns route object if found. -func (builder *Builder) Get() (*routev1.Route, error) { - if valid, err := builder.validate(); !valid { - return nil, err - } - - klog.V(100).Infof( - "Getting route %s in namespace %s", - builder.Definition.Name, builder.Definition.Namespace) - - route := &routev1.Route{} - - err := builder.apiClient.Get(logging.DiscardContext(), goclient.ObjectKey{ - Name: builder.Definition.Name, - Namespace: builder.Definition.Namespace, - }, route) - if err != nil { - return nil, err - } - - return route, nil -} - -// Create makes a route according to the route definition and stores the created object in the route builder. -func (builder *Builder) Create() (*Builder, error) { - if valid, err := builder.validate(); !valid { - return builder, err - } - - klog.V(100).Infof("Creating the route %s in namespace %s", - builder.Definition.Name, builder.Definition.Namespace) - - var err error - if !builder.Exists() { - err = builder.apiClient.Create(logging.DiscardContext(), builder.Definition) - if err == nil { - builder.Object = builder.Definition - } - } - - return builder, err -} - -// Delete removes the route object and resets the builder object. -func (builder *Builder) Delete() (*Builder, error) { - if valid, err := builder.validate(); !valid { - return builder, err - } - - klog.V(100).Infof("Deleting the route %s in namespace %s", - builder.Definition.Name, builder.Definition.Namespace) - - if !builder.Exists() { - klog.V(100).Infof("Route %s does not exist in namespace %s", - builder.Definition.Name, builder.Definition.Namespace) - - builder.Object = nil - - return builder, nil - } - - err := builder.apiClient.Delete(logging.DiscardContext(), builder.Definition) - if err != nil { - return builder, fmt.Errorf("cannot delete route: %w", err) - } - - builder.Object = nil - - return builder, nil -} - -// validate will check that the builder and builder definition are properly initialized before -// accessing any member fields. -func (builder *Builder) validate() (bool, error) { - resourceCRD := "Route" - - if builder == nil { - klog.V(100).Infof("The %s builder is uninitialized", resourceCRD) - - return false, fmt.Errorf("error: received nil %s builder", resourceCRD) - } - - if builder.Definition == nil { - klog.V(100).Infof("The %s is undefined", resourceCRD) - - return false, fmt.Errorf("%s", msg.UndefinedCrdObjectErrString(resourceCRD)) - } - - if builder.apiClient == nil { - klog.V(100).Infof("The %s builder apiclient is nil", resourceCRD) - - return false, fmt.Errorf("%s builder cannot have nil apiClient", resourceCRD) - } - - if builder.errorMsg != "" { - klog.V(100).Infof("The %s builder has error message: %s", resourceCRD, builder.errorMsg) - - return false, fmt.Errorf("%s", builder.errorMsg) - } - - return true, nil -} - func supportedWildCardPolicies() []string { return []string{ "Subdomain", "None", } } + +func getUnsupportedWildCardPoliciesError() error { + return fmt.Errorf( + "received unsupported route wildcardPolicy: expected one of %v", + supportedWildCardPolicies()) +} diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperator/argocd_types.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperator/argocd_types.go index 79fccce5d..2038da859 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperator/argocd_types.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperator/argocd_types.go @@ -217,9 +217,12 @@ type ArgoCDApplicationSet struct { // VolumeMounts adds volumeMounts to the Argo CD ApplicationSet Controller container. VolumeMounts []corev1.VolumeMount `json:"volumeMounts,omitempty"` + // Deprecated: use LogFormat instead. + Logformat string `json:"logformat,omitempty"` + // LogFormat refers to the log format used by the ApplicationSet component. Defaults to ArgoCDDefaultLogFormat if not configured. Valid options are text or json. // +kubebuilder:validation:Enum=text;json - LogFormat string `json:"logformat,omitempty"` + LogFormat string `json:"logFormat,omitempty"` } func (a *ArgoCDApplicationSet) IsEnabled() bool { @@ -429,9 +432,12 @@ type ArgoCDNotifications struct { // LogLevel describes the log level that should be used by the argocd-notifications. Defaults to ArgoCDDefaultLogLevel if not set. Valid options are debug,info, error, and warn. LogLevel string `json:"logLevel,omitempty"` + // Deprecated: use LogFormat instead. + Logformat string `json:"logformat,omitempty"` + // LogFormat refers to the log format used by the argocd-notifications. Defaults to ArgoCDDefaultLogFormat if not configured. Valid options are text or json. // +kubebuilder:validation:Enum=text;json - LogFormat string `json:"logformat,omitempty"` + LogFormat string `json:"logFormat,omitempty"` } // ArgoCDPrometheusSpec defines the desired state for the Prometheus component. @@ -1069,6 +1075,10 @@ type ArgoCDSpec struct { // NamespaceManagement defines the list of namespaces that Argo CD is allowed to manage. NamespaceManagement []ManagedNamespaces `json:"namespaceManagement,omitempty"` + + // WebhookSecrets references Kubernetes Secrets that supply webhook credentials per provider. + // The operator syncs values into argocd-secret under the keys Argo CD expects. + WebhookSecrets *ArgoCDWebhookSecretsSpec `json:"webhookSecrets,omitempty"` } // NamespaceManagement defines the namespace management settings @@ -1080,6 +1090,31 @@ type ManagedNamespaces struct { AllowManagedBy bool `json:"allowManagedBy"` } +// ArgoCDWebhookSecretsSpec holds declarative references to Secrets for Git provider webhook credentials. +// +k8s:openapi-gen=true +type ArgoCDWebhookSecretsSpec struct { + // GitHub: Secret key reference for the webhook secret used to verify incoming webhook requests. + GitHub *ArgoCDWebhookSecretsGitHub `json:"github,omitempty"` +} + +// ArgoCDWebhookSecretsGitHub declares where to read the GitHub webhook secret. +// +k8s:openapi-gen=true +type ArgoCDWebhookSecretsGitHub struct { + // SecretRef points to the key holding the webhook secret value. + SecretRef *WebhookSecretKeySelector `json:"secretRef,omitempty"` +} + +// WebhookSecretKeySelector references one key within a Secret. +// +k8s:openapi-gen=true +type WebhookSecretKeySelector struct { + // Name of the Secret. + // +kubebuilder:validation:Required + Name string `json:"name"` + // Key in the Secret whose value should be used. + // +kubebuilder:validation:Required + Key string `json:"key"` +} + const OpenShiftOAuthErrorMessage = "OpenShiftOAuth is not supported when external authentication is enabled on cluster, please provide OIDC config" const ( ArgoCDConditionType = "Reconciled" diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperator/zz_generated.deepcopy.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperator/zz_generated.deepcopy.go index 03d8c67da..64b6b91c5 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperator/zz_generated.deepcopy.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperator/zz_generated.deepcopy.go @@ -1280,6 +1280,11 @@ func (in *ArgoCDSpec) DeepCopyInto(out *ArgoCDSpec) { *out = make([]ManagedNamespaces, len(*in)) copy(*out, *in) } + if in.WebhookSecrets != nil { + in, out := &in.WebhookSecrets, &out.WebhookSecrets + *out = new(ArgoCDWebhookSecretsSpec) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArgoCDSpec. @@ -1373,6 +1378,46 @@ func (in *ArgoCDTLSSpec) DeepCopy() *ArgoCDTLSSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ArgoCDWebhookSecretsGitHub) DeepCopyInto(out *ArgoCDWebhookSecretsGitHub) { + *out = *in + if in.SecretRef != nil { + in, out := &in.SecretRef, &out.SecretRef + *out = new(WebhookSecretKeySelector) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArgoCDWebhookSecretsGitHub. +func (in *ArgoCDWebhookSecretsGitHub) DeepCopy() *ArgoCDWebhookSecretsGitHub { + if in == nil { + return nil + } + out := new(ArgoCDWebhookSecretsGitHub) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ArgoCDWebhookSecretsSpec) DeepCopyInto(out *ArgoCDWebhookSecretsSpec) { + *out = *in + if in.GitHub != nil { + in, out := &in.GitHub, &out.GitHub + *out = new(ArgoCDWebhookSecretsGitHub) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArgoCDWebhookSecretsSpec. +func (in *ArgoCDWebhookSecretsSpec) DeepCopy() *ArgoCDWebhookSecretsSpec { + if in == nil { + return nil + } + out := new(ArgoCDWebhookSecretsSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Banner) DeepCopyInto(out *Banner) { *out = *in @@ -1871,6 +1916,21 @@ func (in *SSHHostsSpec) DeepCopy() *SSHHostsSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WebhookSecretKeySelector) DeepCopyInto(out *WebhookSecretKeySelector) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WebhookSecretKeySelector. +func (in *WebhookSecretKeySelector) DeepCopy() *WebhookSecretKeySelector { + if in == nil { + return nil + } + out := new(WebhookSecretKeySelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WebhookServerSpec) DeepCopyInto(out *WebhookServerSpec) { *out = *in diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperatorcommon/annotations.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperatorcommon/annotations.go index 451538366..7510173bf 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperatorcommon/annotations.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperatorcommon/annotations.go @@ -12,4 +12,8 @@ const ( // AnnotationOpenShiftServiceCA is the annotation on services used to // request a TLS certificate from OpenShift's Service CA for AutoTLS AnnotationOpenShiftServiceCA = "service.beta.openshift.io/serving-cert-secret-name" + + // AnnotationOpenShiftOriginatingServiceName is the annotation on secrets used to + // identify the service that created the secret. + AnnotationOpenShiftOriginatingServiceName = "service.beta.openshift.io/originating-service-name" ) diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperatorcommon/keys.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperatorcommon/keys.go index 20a65d263..067b4b9e3 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperatorcommon/keys.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/argocd/argocdoperatorcommon/keys.go @@ -131,6 +131,9 @@ const ( // ArgoCDKeyServerSecretKey is the server secret key property name for the Argo secret. ArgoCDKeyServerSecretKey = "server.secretkey" + // ArgoCDKeyGitHubWebhookSecret is the key in argocd-secret for the GitHub webhook shared secret (see Argo CD settings). + ArgoCDKeyGitHubWebhookSecret = "webhook.github.secret" // #nosec G101 + // ArgoCDKeyServerURL is the key for server url. ArgoCDKeyServerURL = "url" diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/nvidiagpu/nvidiagputypes/clusterpolicy_types.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/nvidiagpu/nvidiagputypes/clusterpolicy_types.go index 907cd39e9..9d1b73f4f 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/nvidiagpu/nvidiagputypes/clusterpolicy_types.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/nvidiagpu/nvidiagputypes/clusterpolicy_types.go @@ -174,6 +174,11 @@ type HostPathsSpec struct { // DriverInstallDir represents the root at which driver files including libraries, // config files, and executables can be found. DriverInstallDir string `json:"driverInstallDir,omitempty"` + + // KubeletRootDir represents the location of the kubelet root directory. + // If empty, it will default to "/var/lib/kubelet". + // +kubebuilder:default="/var/lib/kubelet" + KubeletRootDir string `json:"kubeletRootDir,omitempty"` } // EnvVar represents an environment variable present in a Container. @@ -970,6 +975,11 @@ type DCGMExporterSpec struct { // +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.x-descriptors="urn:alm:descriptor:com.tectonic.ui:advanced,urn:alm:descriptor:com.tectonic.ui:text" Args []string `json:"args,omitempty"` + // Optional: Annotations is an unstructured key value map stored with a resource that may be + // set by external tools to store and retrieve arbitrary metadata. They are not + // queryable and should be preserved when modifying objects. + Annotations map[string]string `json:"annotations,omitempty"` + // Optional: List of environment variables // +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors=true // +operator-sdk:gen-csv:customresourcedefinitions.specDescriptors.displayName="Environment Variables" diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/nvidiagpu/nvidiagputypes/zz_generated.deepcopy.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/nvidiagpu/nvidiagputypes/zz_generated.deepcopy.go index e0c8da4a5..067dd72ae 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/nvidiagpu/nvidiagputypes/zz_generated.deepcopy.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/nvidiagpu/nvidiagputypes/zz_generated.deepcopy.go @@ -430,6 +430,13 @@ func (in *DCGMExporterSpec) DeepCopyInto(out *DCGMExporterSpec) { *out = make([]string, len(*in)) copy(*out, *in) } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } if in.Env != nil { in, out := &in.Env, &out.Env *out = make([]EnvVar, len(*in)) diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/doc.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/doc.go index e7024fd4f..b938ecfb4 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/doc.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/doc.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright The OVN-Kubernetes Contributors +// SPDX-License-Identifier: Apache-2.0 + // Package v1 contains API Schema definitions for the RouteAdvertisements v1 API // group // +k8s:deepcopy-gen=package diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/register.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/register.go index c2e482246..cf4c76aec 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/register.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/register.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright The OVN-Kubernetes Contributors +// SPDX-License-Identifier: Apache-2.0 + package v1 import ( diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/types.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/types.go index cf4fa107d..51c1e7fca 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/types.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/types.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright The OVN-Kubernetes Contributors +// SPDX-License-Identifier: Apache-2.0 + package v1 import ( diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/zz_generated.deepcopy.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/zz_generated.deepcopy.go index 71d45cb71..bc6e2f49c 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/zz_generated.deepcopy.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/routeadvertisement/v1/zz_generated.deepcopy.go @@ -1,21 +1,9 @@ //go:build !ignore_autogenerated // +build !ignore_autogenerated -/* +// SPDX-FileCopyrightText: Copyright The OVN-Kubernetes Contributors +// SPDX-License-Identifier: Apache-2.0 - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ // Code generated by deepcopy-gen. DO NOT EDIT. package v1 diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/doc.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/doc.go index 56fd2e5e2..4ffb829c9 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/doc.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/doc.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright The OVN-Kubernetes Contributors +// SPDX-License-Identifier: Apache-2.0 + // Package types contains shared types accrorss API Schema definitions // +k8s:deepcopy-gen=package package types diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/networkselector.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/networkselector.go index d54dcf476..b2ecf7e46 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/networkselector.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/networkselector.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright The OVN-Kubernetes Contributors +// SPDX-License-Identifier: Apache-2.0 + package types import ( diff --git a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/zz_generated.deepcopy.go b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/zz_generated.deepcopy.go index 0e4e780d5..8ff334e7a 100644 --- a/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/zz_generated.deepcopy.go +++ b/vendor/github.com/rh-ecosystem-edge/eco-goinfra/pkg/schemes/ovn/types/zz_generated.deepcopy.go @@ -1,21 +1,9 @@ //go:build !ignore_autogenerated // +build !ignore_autogenerated -/* +// SPDX-FileCopyrightText: Copyright The OVN-Kubernetes Contributors +// SPDX-License-Identifier: Apache-2.0 - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ // Code generated by deepcopy-gen. DO NOT EDIT. package types diff --git a/vendor/modules.txt b/vendor/modules.txt index 31f6a2240..4f62869a2 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1146,7 +1146,7 @@ github.com/redhat-cne/sdk-go/pkg/event/ptp github.com/redhat-cne/sdk-go/pkg/event/redfish github.com/redhat-cne/sdk-go/pkg/pubsub github.com/redhat-cne/sdk-go/pkg/types -# github.com/rh-ecosystem-edge/eco-goinfra v0.0.0-20260414203002-e8968ddfde1a +# github.com/rh-ecosystem-edge/eco-goinfra v0.0.0-20260424200316-f32d939b08da ## explicit; go 1.26 github.com/rh-ecosystem-edge/eco-goinfra/pkg/amdgpu github.com/rh-ecosystem-edge/eco-goinfra/pkg/apiservers @@ -1174,6 +1174,9 @@ github.com/rh-ecosystem-edge/eco-goinfra/pkg/imageregistry github.com/rh-ecosystem-edge/eco-goinfra/pkg/imagestream github.com/rh-ecosystem-edge/eco-goinfra/pkg/infrastructure github.com/rh-ecosystem-edge/eco-goinfra/pkg/ingress +github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common +github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/errors +github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/common/key github.com/rh-ecosystem-edge/eco-goinfra/pkg/internal/logging github.com/rh-ecosystem-edge/eco-goinfra/pkg/keda github.com/rh-ecosystem-edge/eco-goinfra/pkg/kmm