diff --git a/Dockerfile b/Dockerfile index 12aa295..a7adb19 100644 --- a/Dockerfile +++ b/Dockerfile @@ -12,7 +12,7 @@ COPY go.sum go.sum RUN go mod download # Copy the go source -COPY cmd/main.go cmd/main.go +COPY cmd/manager/main.go cmd/manager/main.go COPY api/ api/ COPY internal/ internal/ @@ -24,7 +24,7 @@ COPY internal/ internal/ # Build RUN --mount=type=cache,target=/root/.cache/go-build \ --mount=type=cache,target=/go/pkg \ - CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/main.go + CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build -a -o manager cmd/manager/main.go # Use distroless as minimal base image to package the manager binary # Refer to https://github.com/GoogleContainerTools/distroless for more details diff --git a/Makefile b/Makefile index 136652b..b5e690e 100644 --- a/Makefile +++ b/Makefile @@ -109,11 +109,11 @@ lint-config: golangci-lint ## Verify golangci-lint linter configuration .PHONY: build build: manifests generate fmt vet ## Build manager binary. - go build -o bin/manager cmd/main.go + go build -o bin/manager cmd/manager/main.go .PHONY: run run: manifests generate fmt vet ## Run a controller from your host. - go run ./cmd/main.go + go run ./cmd/manager/main.go # If you wish built the manager image targeting other platforms you can use the --platform flag. # (i.e. docker build --platform linux/arm64 ). However, you must enable docker buildKit for it. diff --git a/README.md b/README.md index 8b43ebe..c654620 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ With this operator it is possible to: To find out more, please refer to: - [installation and deployment](/docs/installation.md) - [usage](/docs/usage.md) +- [ipamctl](/docs/ipamctl.md) - [consuming api](docs/consuming_api.md) - [development](/docs/development.md) - [contribution guide](/docs/contribution.md) diff --git a/REUSE.toml b/REUSE.toml index b5fb662..c0de7bf 100644 --- a/REUSE.toml +++ b/REUSE.toml @@ -15,21 +15,21 @@ path = [ "README.md", "api/**", "charts/**", + "cmd/**", + "cmdutils/**", "config/**", - "controllers/**", - "clientset/**", - "clientgo/**", "go.mod", "go.sum", "hack/**","main.go", + "internal/**", "REUSE.toml" ] precedence = "aggregate" -SPDX-FileCopyrightText = "2024 SAP SE or an SAP affiliate company and IronCore contributors" +SPDX-FileCopyrightText = "2025 SAP SE or an SAP affiliate company and IronCore contributors" SPDX-License-Identifier = "Apache-2.0" [[annotations]] path = ["docs/**", "README.md"] precedence = "aggregate" -SPDX-FileCopyrightText = "2024 SAP SE or an SAP affiliate company and IronCore contributors" +SPDX-FileCopyrightText = "2025 SAP SE or an SAP affiliate company and IronCore contributors" SPDX-License-Identifier = "Apache-2.0" diff --git a/api/ipam/v1alpha1/cidr_types.go b/api/ipam/v1alpha1/cidr_types.go index ef6b578..e31aaa6 100644 --- a/api/ipam/v1alpha1/cidr_types.go +++ b/api/ipam/v1alpha1/cidr_types.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/cidr_types_test.go b/api/ipam/v1alpha1/cidr_types_test.go index e354e09..7dc301a 100644 --- a/api/ipam/v1alpha1/cidr_types_test.go +++ b/api/ipam/v1alpha1/cidr_types_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/cidrutils.go b/api/ipam/v1alpha1/cidrutils.go index 1a074c6..0a89083 100644 --- a/api/ipam/v1alpha1/cidrutils.go +++ b/api/ipam/v1alpha1/cidrutils.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/doc.go b/api/ipam/v1alpha1/doc.go index 46255c0..880c605 100644 --- a/api/ipam/v1alpha1/doc.go +++ b/api/ipam/v1alpha1/doc.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 // +k8s:deepcopy-gen=package diff --git a/api/ipam/v1alpha1/groupversion_info.go b/api/ipam/v1alpha1/groupversion_info.go index 58c90c3..fe2bc5d 100644 --- a/api/ipam/v1alpha1/groupversion_info.go +++ b/api/ipam/v1alpha1/groupversion_info.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 // Package v1alpha1 contains API Schema definitions for the ipam v1alpha1 API group diff --git a/api/ipam/v1alpha1/ip_types.go b/api/ipam/v1alpha1/ip_types.go index 53421b9..100801c 100644 --- a/api/ipam/v1alpha1/ip_types.go +++ b/api/ipam/v1alpha1/ip_types.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/ipaddr_types.go b/api/ipam/v1alpha1/ipaddr_types.go index 3134095..65a00d0 100644 --- a/api/ipam/v1alpha1/ipaddr_types.go +++ b/api/ipam/v1alpha1/ipaddr_types.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/ipaddr_types_test.go b/api/ipam/v1alpha1/ipaddr_types_test.go index 0e43ef9..74d1b65 100644 --- a/api/ipam/v1alpha1/ipaddr_types_test.go +++ b/api/ipam/v1alpha1/ipaddr_types_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/network_types.go b/api/ipam/v1alpha1/network_types.go index f65216e..715bc07 100644 --- a/api/ipam/v1alpha1/network_types.go +++ b/api/ipam/v1alpha1/network_types.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/network_types_test.go b/api/ipam/v1alpha1/network_types_test.go index b94649b..4df8dda 100644 --- a/api/ipam/v1alpha1/network_types_test.go +++ b/api/ipam/v1alpha1/network_types_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/networkcounter_test.go b/api/ipam/v1alpha1/networkcounter_test.go index 691c049..05dc2c5 100644 --- a/api/ipam/v1alpha1/networkcounter_test.go +++ b/api/ipam/v1alpha1/networkcounter_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/networkcounter_types.go b/api/ipam/v1alpha1/networkcounter_types.go index 3d25b0c..6207730 100644 --- a/api/ipam/v1alpha1/networkcounter_types.go +++ b/api/ipam/v1alpha1/networkcounter_types.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/networkid_types.go b/api/ipam/v1alpha1/networkid_types.go index 6ab5db3..f1ffa4f 100644 --- a/api/ipam/v1alpha1/networkid_types.go +++ b/api/ipam/v1alpha1/networkid_types.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/networkid_types_test.go b/api/ipam/v1alpha1/networkid_types_test.go index 60f1075..9255d00 100644 --- a/api/ipam/v1alpha1/networkid_types_test.go +++ b/api/ipam/v1alpha1/networkid_types_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/networkidinterval_types.go b/api/ipam/v1alpha1/networkidinterval_types.go index 50371cf..cc0d096 100644 --- a/api/ipam/v1alpha1/networkidinterval_types.go +++ b/api/ipam/v1alpha1/networkidinterval_types.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/resourcereference_types.go b/api/ipam/v1alpha1/resourcereference_types.go index 92c6a85..4a2c4ae 100644 --- a/api/ipam/v1alpha1/resourcereference_types.go +++ b/api/ipam/v1alpha1/resourcereference_types.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/subnet_types.go b/api/ipam/v1alpha1/subnet_types.go index f1a107e..0b55690 100644 --- a/api/ipam/v1alpha1/subnet_types.go +++ b/api/ipam/v1alpha1/subnet_types.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/subnet_types_test.go b/api/ipam/v1alpha1/subnet_types_test.go index f3d21b0..85d7b30 100644 --- a/api/ipam/v1alpha1/subnet_types_test.go +++ b/api/ipam/v1alpha1/subnet_types_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/api/ipam/v1alpha1/zz_generated.deepcopy.go b/api/ipam/v1alpha1/zz_generated.deepcopy.go index a62ca76..ba3a0d1 100644 --- a/api/ipam/v1alpha1/zz_generated.deepcopy.go +++ b/api/ipam/v1alpha1/zz_generated.deepcopy.go @@ -1,6 +1,6 @@ //go:build !ignore_autogenerated -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 // Code generated by controller-gen. DO NOT EDIT. diff --git a/cmd/ipamctl/app/app.go b/cmd/ipamctl/app/app.go new file mode 100644 index 0000000..7885587 --- /dev/null +++ b/cmd/ipamctl/app/app.go @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package app + +import ( + "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/runtime" + + ipamv1alphav1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1" + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + clientgoscheme "k8s.io/client-go/kubernetes/scheme" +) + +const Name string = "ipamctl" + +var scheme = runtime.NewScheme() + +func init() { + utilruntime.Must(apiextensionsv1.AddToScheme(scheme)) + utilruntime.Must(clientgoscheme.AddToScheme(scheme)) + utilruntime.Must(ipamv1alphav1.AddToScheme(scheme)) +} + +func NewCommand() *cobra.Command { + root := &cobra.Command{ + Use: Name, + Short: "CLI client for ipam", + Args: cobra.NoArgs, + } + root.AddCommand(NewMoveCommand()) + return root +} diff --git a/cmd/ipamctl/app/move.go b/cmd/ipamctl/app/move.go new file mode 100644 index 0000000..5b55781 --- /dev/null +++ b/cmd/ipamctl/app/move.go @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package app + +import ( + "fmt" + "log/slog" + + apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + + "github.com/spf13/cobra" + "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client" + + ipamv1alpha1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1" + utils "github.com/ironcore-dev/ipam/cmdutils" +) + +var ( + sourceKubeconfig string + targetKubeconfig string + namespace string + requireOwners bool + dryRun bool + verbose bool +) + +func NewMoveCommand() *cobra.Command { + move := &cobra.Command{ + Use: "move", + Short: "Move IPAM CRs from one cluster to another", + RunE: runMove, + } + move.Flags().StringVar(&sourceKubeconfig, "source-kubeconfig", "", "Kubeconfig pointing to the source cluster") + move.Flags().StringVar(&targetKubeconfig, "target-kubeconfig", "", "Kubeconfig pointing to the target cluster") + move.Flags().StringVar(&namespace, "namespace", "", + "namespace to filter CRs to migrate. Defaults to all namespaces if not specified") + move.Flags().BoolVar(&requireOwners, "require-owners", false, + "if set to true, an error will be returned if for any custom resource an owner ServerBootConfiguration") //nolint:lll + move.Flags().BoolVar(&dryRun, "dry-run", false, "show what would be moved without executing the migration") + move.Flags().BoolVar(&verbose, "verbose", false, "enable verbose logging for detailed output during migration") + _ = move.MarkFlagRequired("source-kubeconfig") + _ = move.MarkFlagRequired("target-kubeconfig") + + if verbose { + slog.SetLogLoggerLevel(slog.LevelDebug) + } + return move +} + +func makeClient(kubeconfig string) (client.Client, error) { + cfg, err := clientcmd.BuildConfigFromFlags("", kubeconfig) + if err != nil { + return nil, fmt.Errorf("failed to load cluster kubeconfig: %w", err) + } + return client.New(cfg, client.Options{Scheme: scheme}) +} + +func makeClients() (utils.Clients, error) { + var clients utils.Clients + var err error + + clients.Source, err = makeClient(sourceKubeconfig) + if err != nil { + return clients, fmt.Errorf("failed to construct a source cluster client: %w", err) + } + clients.Target, err = makeClient(targetKubeconfig) + if err != nil { + return clients, fmt.Errorf("failed to construct a target cluster client: %w", err) + } + return clients, nil +} + +func runMove(cmd *cobra.Command, args []string) error { + clients, err := makeClients() + if err != nil { + return err + } + ctx := cmd.Context() + + crdList := &apiextensionsv1.CustomResourceDefinitionList{} + if err := clients.Source.List(ctx, crdList); err != nil { + return err + } + crsSchema := []schema.GroupVersionKind{} + for _, crd := range crdList.Items { + if crd.Spec.Group == ipamv1alpha1.SchemeGroupVersion.Group { + crsSchema = append(crsSchema, schema.GroupVersionKind{ + Group: crd.Spec.Group, + Version: crd.Spec.Versions[0].Name, + Kind: crd.Spec.Names.Kind, + }) + } + } + return utils.Move(ctx, clients, crsSchema, namespace, dryRun) +} diff --git a/cmd/ipamctl/main.go b/cmd/ipamctl/main.go new file mode 100644 index 0000000..432be93 --- /dev/null +++ b/cmd/ipamctl/main.go @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package main + +import ( + "fmt" + "os" + + "github.com/ironcore-dev/ipam/cmd/ipamctl/app" + "sigs.k8s.io/controller-runtime/pkg/manager/signals" +) + +func main() { + if err := app.NewCommand().ExecuteContext(signals.SetupSignalHandler()); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} diff --git a/cmd/main.go b/cmd/manager/main.go similarity index 99% rename from cmd/main.go rename to cmd/manager/main.go index 610cd93..b1b095d 100644 --- a/cmd/main.go +++ b/cmd/manager/main.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package main diff --git a/cmdutils/clients.go b/cmdutils/clients.go new file mode 100644 index 0000000..09a2f59 --- /dev/null +++ b/cmdutils/clients.go @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package cmdutils + +import "sigs.k8s.io/controller-runtime/pkg/client" + +type Clients struct { + Source client.Client + Target client.Client +} diff --git a/cmdutils/move.go b/cmdutils/move.go new file mode 100644 index 0000000..6d27126 --- /dev/null +++ b/cmdutils/move.go @@ -0,0 +1,229 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package cmdutils + +import ( + "context" + "errors" + "fmt" + "log/slog" + "reflect" + "slices" + "time" + + ipamv1alphav1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +const ( + pollInterval = time.Second / 10 + pollTimeout = time.Second * 30 +) + +func getCrs( + ctx context.Context, + cl client.Client, + crsGvk []schema.GroupVersionKind, + namespace string, +) ([]*unstructured.Unstructured, error) { + crs := make([]*unstructured.Unstructured, 0) + + for _, crGvk := range crsGvk { + crsList := &unstructured.UnstructuredList{} + crsList.SetGroupVersionKind(crGvk) + + if err := cl.List(ctx, crsList, &client.ListOptions{Namespace: namespace}); err != nil { + return nil, fmt.Errorf("couldn't list CRs: %w", err) + } + for _, cr := range crsList.Items { // won't work with go version <1.22 + crs = append(crs, &cr) + } + } + + return crs, nil +} + +func clearFields(obj client.Object) map[string]any { + so, _ := runtime.DefaultUnstructuredConverter.ToUnstructured(obj) + + for _, field := range []string{"creationTimestamp", "resourceVersion", "uid", "generation", "managedFields"} { + delete(so["metadata"].(map[string]any), field) + } + + if so["status"] != nil && so["status"].(map[string]any)["conditions"] != nil { + for _, field := range so["status"].(map[string]any)["conditions"].([]interface{}) { + delete(field.(map[string]any), "lastTransitionTime") + } + } + + return so +} + +func getCrsToBeMoved( + ctx context.Context, + targetClient client.Client, + sourceCrs []*unstructured.Unstructured, +) ([]*unstructured.Unstructured, error) { + crsToMove := make([]*unstructured.Unstructured, 0, len(sourceCrs)) + for _, sourceCr := range sourceCrs { + targetCr := sourceCr.DeepCopy() + err := targetClient.Get(ctx, client.ObjectKeyFromObject(sourceCr), targetCr) + if apierrors.IsNotFound(err) { + crsToMove = append(crsToMove, sourceCr) + continue + } + + if err != nil { + return nil, fmt.Errorf("failed to check CR existence in the target cluster: %w", err) + } + + if reflect.DeepEqual(clearFields(sourceCr), clearFields(targetCr)) { + slog.Debug("source and target CRs are the same", slog.String("CR", crName(sourceCr))) + continue + } + return nil, fmt.Errorf( + "a CR %s/%s already exists in the target cluster and is different then in the source cluster", + sourceCr.GetNamespace(), sourceCr.GetName()) + } + return crsToMove, nil +} + +type Node struct { + Cr *unstructured.Unstructured + Children []*Node +} + +func crsOwnerReferenceTrees(crs []*unstructured.Unstructured) []*Node { + nodeMap := make(map[types.UID]*Node) + + for _, cr := range crs { + nodeMap[cr.GetUID()] = &Node{Cr: cr} + } + roots := []*Node{} + for _, cr := range crs { + if len(cr.GetOwnerReferences()) == 0 || nodeMap[cr.GetOwnerReferences()[0].UID] == nil { + roots = append(roots, nodeMap[cr.GetUID()]) + } else { + owner := nodeMap[cr.GetOwnerReferences()[0].UID] + owner.Children = append(owner.Children, nodeMap[cr.GetUID()]) + } + } + return roots +} + +func cleanup(ctx context.Context, cl client.Client, crs []*unstructured.Unstructured) error { + cleanupErrs := make([]error, 0) + for _, cr := range crs { + if err := cl.Delete(ctx, cr); err != nil { + cleanupErrs = append(cleanupErrs, err) + } + } + return errors.Join(cleanupErrs...) +} + +func moveCrs( + ctx context.Context, + cl client.Client, + crsTrees []*Node, + ownerUid ...types.UID, +) ([]*unstructured.Unstructured, error) { + movedCrs := make([]*unstructured.Unstructured, 0) + + for _, crsTree := range crsTrees { + cr := crsTree.Cr.DeepCopy() + ownerReferences := cr.GetOwnerReferences() + if len(ownerReferences) == 1 && len(ownerUid) == 1 { + ownerReferences[0].UID = ownerUid[0] + cr.SetOwnerReferences(ownerReferences) + } + cr.SetResourceVersion("") + if err := cl.Create(ctx, cr); err != nil { + err = fmt.Errorf("CR %s couldn't be created in the target cluster: %w", crName(cr), err) + return movedCrs, err + } + movedCrs = append(movedCrs, cr) + } + + for _, crsTree := range crsTrees { + err := wait.PollUntilContextTimeout(ctx, pollInterval, pollTimeout, true, func(ctx context.Context) (bool, error) { + // get CR from target cluster + cr := crsTree.Cr.DeepCopy() + if err := cl.Get(ctx, client.ObjectKeyFromObject(cr), cr); err != nil { + return false, client.IgnoreNotFound(err) + } + + if err := copyStatus(ctx, cl, crsTree.Cr, cr); err != nil { + return false, err + } + + // create children CRs + movedChildrenCrs, err := moveCrs(ctx, cl, crsTree.Children, cr.GetUID()) + movedCrs = slices.Concat(movedCrs, movedChildrenCrs) + return true, err + }) + if err != nil { + return movedCrs, err + } + } + + return movedCrs, nil +} + +func copyStatus(ctx context.Context, cl client.Client, sourceCr, targetCr *unstructured.Unstructured) error { + status, found, err := unstructured.NestedMap(sourceCr.Object, "status") + if err != nil { + return err + } + if !found { + return nil + } + + if err := unstructured.SetNestedField(targetCr.Object, status, "status"); err != nil { + return err + } + return cl.Status().Update(ctx, targetCr) +} + +func Move( + ctx context.Context, + clients Clients, + crsGvk []schema.GroupVersionKind, + namespace string, + dryRun bool, +) error { + sourceCrs, err := getCrs(ctx, clients.Source, crsGvk, namespace) + if err != nil { + return err + } + slog.Debug(fmt.Sprintf("found %s CRs in the source cluster", ipamv1alphav1.SchemeGroupVersion.Group), + slog.Any("CRs", transform(sourceCrs, crName))) + + crsToMove, err := getCrsToBeMoved(ctx, clients.Target, sourceCrs) + if err != nil { + return err + } + slog.Debug("moving", slog.Any("CRs", transform(crsToMove, crName))) + + if !dryRun { + crsTrees := crsOwnerReferenceTrees(crsToMove) + var movedCrs []*unstructured.Unstructured + if movedCrs, err = moveCrs(ctx, clients.Target, crsTrees); err != nil { + cleanupErr := cleanup(ctx, clients.Target, movedCrs) + err = errors.Join(err, + fmt.Errorf("clean up of CRs was performed to restore a target cluster's state with error result: %w", + cleanupErr)) + } else { + slog.Debug(fmt.Sprintf("all %s CRs from the source cluster were moved to the target cluster", + ipamv1alphav1.SchemeGroupVersion.Group)) + } + } + + return err +} diff --git a/cmdutils/move_test.go b/cmdutils/move_test.go new file mode 100644 index 0000000..7a43f80 --- /dev/null +++ b/cmdutils/move_test.go @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package cmdutils + +import ( + "context" + "log/slog" + + ipamv1alphav1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/client" + . "sigs.k8s.io/controller-runtime/pkg/envtest/komega" +) + +const ( + ns = "test-namespace" +) + +func namedObj[T client.Object](obj T, name string) T { + obj.SetName(name) + obj.SetNamespace(ns) + return obj +} + +func create[T client.Object](ctx SpecContext, cl client.Client, obj T) T { + Expect(cl.Create(ctx, obj)).To(Succeed()) + Eventually(func(g Gomega) error { + return clients.Source.Get(ctx, client.ObjectKeyFromObject(obj), obj) + }).Should(Succeed()) + return obj +} + +var _ = Describe("ipamctl move", func() { + It("Should successfully move IPAM CRs with from a source cluster on a target cluster", func(ctx SpecContext) { + slog.SetLogLoggerLevel(slog.LevelDebug) + + // source cluster setup + create(ctx, clients.Source, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}) + + testIP := "192.168.0.0" + testCidr, _ := ipamv1alphav1.CIDRFromString(testIP + "/24") + + sourceNetwork := create(ctx, clients.Source, namedObj(&ipamv1alphav1.Network{}, "network")) + + sourceSubnet := namedObj(&ipamv1alphav1.Subnet{}, "subnet") + sourceSubnet.Spec.Network.Name = sourceNetwork.Name + sourceSubnet.Spec.CIDR = testCidr + sourceSubnet = create(ctx, clients.Source, sourceSubnet) + + sourceIP := namedObj(&ipamv1alphav1.IP{}, "ip") + sourceIP.Spec.Subnet.Name = sourceSubnet.Name + sourceIP.Spec.IP = ipamv1alphav1.IPMustParse(testIP) + sourceIP = create(ctx, clients.Source, sourceIP) + + // target cluster setup + create(ctx, clients.Target, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}) + targetNetwork := namedObj(&ipamv1alphav1.Network{}, sourceNetwork.Name) + targetSubnet := namedObj(&ipamv1alphav1.Subnet{}, sourceSubnet.Name) + targetIP := namedObj(&ipamv1alphav1.IP{}, sourceIP.Name) + + // TEST + crsSchema := []schema.GroupVersionKind{} + for _, crdKind := range []string{"Network", "Subnet", "IP"} { + crsSchema = append(crsSchema, + schema.GroupVersionKind{Group: "ipam.metal.ironcore.dev", Version: "v1alpha1", Kind: crdKind}) + } + err := Move(context.TODO(), clients, crsSchema, "", false) + Expect(err).ToNot(HaveOccurred()) + + SetClient(clients.Target) + + Eventually(Get(targetNetwork)).Should(Succeed()) + + Eventually(Get(targetSubnet)).Should(Succeed()) + Expect(targetSubnet.Spec.Network.Name).To(Equal(targetNetwork.Name)) + Expect(targetSubnet.Spec.CIDR).To(Equal(testCidr)) + + Eventually(Get(targetIP)).Should(Succeed()) + Expect(targetIP.Spec.Subnet.Name).To(Equal(targetSubnet.Name)) + Expect(targetIP.Spec.IP).To(Equal(ipamv1alphav1.IPMustParse(testIP))) + }) +}) diff --git a/cmdutils/suite_test.go b/cmdutils/suite_test.go new file mode 100644 index 0000000..7f0f751 --- /dev/null +++ b/cmdutils/suite_test.go @@ -0,0 +1,103 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package cmdutils + +import ( + "fmt" + "path/filepath" + "runtime" + "testing" + "time" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + k8sSchema "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/log/zap" + + "github.com/ironcore-dev/controller-utils/modutils" + ipamv1alphav1 "github.com/ironcore-dev/ipam/api/ipam/v1alpha1" + //+kubebuilder:scaffold:imports +) + +const ( + pollingInterval = 50 * time.Millisecond + eventuallyTimeout = 3 * time.Second + consistentlyDuration = 1 * time.Second +) + +var ( + clients Clients +) + +func TestBootctl(t *testing.T) { + SetDefaultConsistentlyPollingInterval(pollingInterval) + SetDefaultEventuallyPollingInterval(pollingInterval) + SetDefaultEventuallyTimeout(eventuallyTimeout) + SetDefaultConsistentlyDuration(consistentlyDuration) + RegisterFailHandler(Fail) + + RunSpecs(t, "Controller Suite") +} + +var _ = BeforeSuite(func() { + logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true))) + + sourceEnv := &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases"), + filepath.Join(modutils.Dir("github.com/ironcore-dev/ipam", "config", "crd", "bases")), + }, + ErrorIfCRDPathMissing: true, + + // The BinaryAssetsDirectory is only required if you want to run the tests directly + // without call the makefile target test. If not informed it will look for the + // default path defined in controller-runtime which is /usr/local/kubebuilder/. + // Note that you must have the required binaries setup under the bin directory to perform + // the tests directly. When we run make test it will be setup and used automatically. + BinaryAssetsDirectory: filepath.Join("..", "bin", "k8s", + fmt.Sprintf("1.34.0-%s-%s", runtime.GOOS, runtime.GOARCH)), + } + + sourceCfg, err := sourceEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(sourceCfg).NotTo(BeNil()) + + DeferCleanup(sourceEnv.Stop) + + Expect(ipamv1alphav1.AddToScheme(k8sSchema.Scheme)).NotTo(HaveOccurred()) + + //+kubebuilder:scaffold:scheme + + clients.Source, err = client.New(sourceCfg, client.Options{Scheme: k8sSchema.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(clients.Source).NotTo(BeNil()) + + targetEnv := &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases"), + filepath.Join(modutils.Dir("github.com/ironcore-dev/ipam", "config", "crd", "bases")), + }, + ErrorIfCRDPathMissing: true, + + // The BinaryAssetsDirectory is only required if you want to run the tests directly + // without call the makefile target test. If not informed it will look for the + // default path defined in controller-runtime which is /usr/local/kubebuilder/. + // Note that you must have the required binaries setup under the bin directory to perform + // the tests directly. When we run make test it will be setup and used automatically. + BinaryAssetsDirectory: filepath.Join("..", "bin", "k8s", + fmt.Sprintf("1.34.0-%s-%s", runtime.GOOS, runtime.GOARCH)), + } + + // cfg is defined in this file globally. + targetCfg, err := targetEnv.Start() + Expect(err).NotTo(HaveOccurred()) + Expect(targetCfg).NotTo(BeNil()) + + DeferCleanup(targetEnv.Stop) + + clients.Target, err = client.New(targetCfg, client.Options{Scheme: k8sSchema.Scheme}) + Expect(err).NotTo(HaveOccurred()) + Expect(clients.Target).NotTo(BeNil()) +}) diff --git a/cmdutils/utils.go b/cmdutils/utils.go new file mode 100644 index 0000000..9697408 --- /dev/null +++ b/cmdutils/utils.go @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-License-Identifier: Apache-2.0 + +package cmdutils + +import ( + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" +) + +// transform returns a list of transformed list elements with function f. +func transform[L ~[]E, E any, T any](list L, f func(E) T) []T { + ret := make([]T, len(list)) + for i, elem := range list { + ret[i] = f(elem) + } + return ret +} + +func crName(cr *unstructured.Unstructured) string { + return cr.GetObjectKind().GroupVersionKind().Kind + ":" + cr.GetNamespace() + "/" + cr.GetName() +} diff --git a/docs/ipamctl.md b/docs/ipamctl.md new file mode 100644 index 0000000..f1a463f --- /dev/null +++ b/docs/ipamctl.md @@ -0,0 +1,60 @@ +# ipamctl + +## Installation + +Install the `ipamctl` CLI from source without cloning the repository. Requires [Go](https://go.dev) to be installed. + +```bash +go install https://github.com/ironcore-dev/ipam/cmd/ipamctl@latest +``` + +## Commands + +### move + +The `ipamctl move` command allows to move the ipam Custom Resources, like e.g. `Network`, `Subnet`, `IP`, etc. from one +cluster to another. + +> Warning!: +> Before running `ipamctl move`, the user should take care of preparing the target cluster, including also installing +> all the required Custom Resources Definitions. + +You can use: + +```bash +ipamctl move --source-kubeconfig="path-to-source-kubeconfig.yaml" --target-kubeconfig="path-to-target-kubeconfig.yaml" +``` +to move the ipam Custom Resources existing in all namespaces of the source cluster. In case you want to move the ipam +Custom Resources defined in a single namespace, you can use the `--namespace` flag. + +Status and ownership of a ipam Custom Resource is also moved. If a ipam Custom Resource present on the source cluster +exists on the target cluster with identical specification it won't be moved and no ownership of this object will be +set. In case of any errors during the process there will be performed a cleanup and the target cluster will be restored +to its previous state. + +> Warning!: +`ipamctl move` has been designed and developed around the bootstrap use case described below, and currently this is +the only use case verified . +> +>If someone intends to use `ipamctl move` outside of this scenario, it's recommended to set up a custom validation +pipeline of it before using the command on a production environment. +> +>Also, it is important to notice that move has not been designed for being used as a backup/restore solution and it has +several limitation for this scenario, like e.g. the implementation assumes the cluster must be stable while doing the +move operation, and possible race conditions happening while the cluster is upgrading, scaling up, remediating etc. has +never been investigated nor addressed. + +#### Pivot + +Pivoting is a process for moving the Custom Resources and install Custom Resource Definitions from a source cluster to +a target cluster. + +This can now be achieved with the following procedure: + +1. Use `make install` to install the ipam Custom Resource Definitions into the target cluster +2. Use `ipamctl move` to move the ipam Custom Resources from a source cluster to a target cluster + +#### Dry run + +With `--dry-run` option you can dry-run the move action by only printing logs without taking any actual actions. Use +`--verbose` flag to enable verbose logging. diff --git a/go.mod b/go.mod index 6d9c02d..6db38e2 100644 --- a/go.mod +++ b/go.mod @@ -7,12 +7,15 @@ toolchain go1.24.1 require ( github.com/go-logr/logr v1.4.3 github.com/google/addlicense v1.2.0 + github.com/ironcore-dev/controller-utils v0.10.0 github.com/onsi/ginkgo/v2 v2.26.0 github.com/onsi/gomega v1.38.2 github.com/pkg/errors v0.9.1 + github.com/spf13/cobra v1.9.1 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba gopkg.in/inf.v0 v0.9.1 k8s.io/api v0.34.1 + k8s.io/apiextensions-apiserver v0.34.1 k8s.io/apimachinery v0.34.1 k8s.io/client-go v0.34.1 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 @@ -26,7 +29,7 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/bmatcuk/doublestar/v4 v4.0.2 // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.2 // indirect @@ -37,43 +40,42 @@ require ( github.com/fxamacker/cbor/v2 v2.9.0 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/zapr v1.3.0 // indirect - github.com/go-openapi/jsonpointer v0.21.0 // indirect - github.com/go-openapi/jsonreference v0.20.4 // indirect - github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/jsonpointer v0.21.1 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/swag v0.23.1 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/btree v1.1.3 // indirect github.com/google/cel-go v0.26.0 // indirect github.com/google/gnostic-models v0.7.0 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect + github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/prometheus/client_golang v1.22.0 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.62.0 // indirect - github.com/prometheus/procfs v0.15.1 // indirect - github.com/spf13/cobra v1.9.1 // indirect - github.com/spf13/pflag v1.0.6 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.64.0 // indirect + github.com/prometheus/procfs v0.16.1 // indirect + github.com/spf13/pflag v1.0.7 // indirect github.com/stoewer/go-strcase v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 // indirect - go.opentelemetry.io/otel v1.35.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 // indirect - go.opentelemetry.io/otel/metric v1.35.0 // indirect - go.opentelemetry.io/otel/sdk v1.34.0 // indirect - go.opentelemetry.io/otel/trace v1.35.0 // indirect - go.opentelemetry.io/proto/otlp v1.5.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect + go.opentelemetry.io/otel v1.36.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 // indirect + go.opentelemetry.io/otel/metric v1.36.0 // indirect + go.opentelemetry.io/otel/sdk v1.36.0 // indirect + go.opentelemetry.io/otel/trace v1.36.0 // indirect + go.opentelemetry.io/proto/otlp v1.7.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect @@ -82,26 +84,25 @@ require ( golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.27.0 // indirect golang.org/x/net v0.43.0 // indirect - golang.org/x/oauth2 v0.27.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.16.0 // indirect golang.org/x/sys v0.35.0 // indirect golang.org/x/term v0.34.0 // indirect golang.org/x/text v0.28.0 // indirect - golang.org/x/time v0.9.0 // indirect + golang.org/x/time v0.11.0 // indirect golang.org/x/tools v0.36.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect - google.golang.org/grpc v1.72.1 // indirect + gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // indirect + google.golang.org/grpc v1.72.2 // indirect google.golang.org/protobuf v1.36.7 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/apiextensions-apiserver v0.34.1 // indirect k8s.io/apiserver v0.34.1 // indirect k8s.io/component-base v0.34.1 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect - sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 // indirect + sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect sigs.k8s.io/randfill v1.0.0 // indirect sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect diff --git a/go.sum b/go.sum index 9145f50..9323c84 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,8 @@ github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar/v4 v4.0.2 h1:X0krlUVAVmtr2cRoTqR8aDMrDqnB36ht8wpWTiQ3jsA= github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v5 v5.0.2 h1:rIfFVxEf1QsI7E1ZHfp/B4DF/6QBAUhmgkxc0H7Zss8= +github.com/cenkalti/backoff/v5 v5.0.2/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= @@ -44,12 +44,12 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= github.com/go-logr/zapr v1.3.0/go.mod h1:YKepepNBd1u/oyhd/yQmtjVXmm9uML4IXUgMOwR8/Gg= -github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= -github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= -github.com/go-openapi/jsonreference v0.20.4 h1:bKlDxQxQJgwpUSgOENiMPzCTBVuc7vTdXSSgNeAhojU= -github.com/go-openapi/jsonreference v0.20.4/go.mod h1:5pZJyJP2MnYCpoeoMAql78cCHauHj0V9Lhc506VOpw4= -github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= -github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic= +github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= +github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= @@ -71,14 +71,16 @@ github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8= -github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= +github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e h1:FJta/0WsADCe1r9vQjdHbd3KuiLPu7Y9WlyLGwMUNyE= +github.com/google/pprof v0.0.0-20250602020802-c6617b811d0e/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/ironcore-dev/controller-utils v0.10.0 h1:nG+TsVMtxt6PLJrlLr2LePYd8cOxud+z76rhuy5gCOs= +github.com/ironcore-dev/controller-utils v0.10.0/go.mod h1:ZGv1A78M0X2G20ex/7F5BbyHoG0+7U2IWfqvzHh8T+4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/joshdk/go-junit v1.0.0 h1:S86cUKIdwBHWwA6xCmFlf3RTLfVXYQfvanM5Uh+K6GE= @@ -95,8 +97,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/maruel/natural v1.1.1 h1:Hja7XhhmvEFhcByqDoHz9QZbkWey+COd9xWfCfn1ioo= github.com/maruel/natural v1.1.1/go.mod h1:v+Rfd79xlw1AgVBjbO0BEQmptqb5HvL/k9GRHB7ZKEg= github.com/mfridman/tparse v0.18.0 h1:wh6dzOKaIwkUGyKgOntDW4liXSo37qg5AXbIhkMV3vE= @@ -115,25 +117,27 @@ github.com/onsi/gomega v1.38.2 h1:eZCjf2xjZAqe+LeWvKb5weQ+NcPwX84kqJ0cZNxok2A= github.com/onsi/gomega v1.38.2/go.mod h1:W2MJcYxRGV63b418Ai34Ud0hEdTVXq9NW9+Sx6uXf3k= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= -github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= -github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= -github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= +github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE= +github.com/prometheus/common v0.64.0 h1:pdZeA+g617P7oGv1CzdTzyeShxAGrTBsolKNOLQPGO4= +github.com/prometheus/common v0.64.0/go.mod h1:0gZns+BLRQ3V6NdaerOhMbwwRbNh9hkGINtQAsP5GS8= +github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzMyRg= +github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is= github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= -github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/pflag v1.0.7 h1:vN6T9TfwStFPFM5XzjsvmzZkLuaLX+HS+0SeFLRgU6M= +github.com/spf13/pflag v1.0.7/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -161,24 +165,24 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0 h1:yd02MEjBdJkG3uabWP9apV+OuWRIXGDuJEUJbOHmCFU= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q= -go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0 h1:OeNbIYk/2C15ckl7glBlOBp5+WlYsOElzTNmiPW/x60= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.34.0/go.mod h1:7Bept48yIeqxP2OZ9/AqIpYS94h2or0aB4FypJTc8ZM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0 h1:tgJ0uaNS4c98WRNUEx5U3aDlrDOI5Rs+1Vifcw4DJ8U= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.34.0/go.mod h1:U7HYyW0zt/a9x5J1Kjs+r1f/d4ZHnYFclhYY2+YbeoE= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= -go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= -go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= -go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= -go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0 h1:dNzwXjZKpMpE2JhmO+9HsPl42NIXFIFSUSSs0fiqra0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.36.0/go.mod h1:90PoxvaEB5n6AOdZvi+yWJQoE95U8Dhhw2bSyRqnTD0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0 h1:JgtbA0xkWHnTmYk7YusopJFX6uleBmAuZ8n05NEh8nQ= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.36.0/go.mod h1:179AK5aar5R3eS9FucPy6rggvU0g52cvKId8pv4+v0c= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os= +go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo= go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs= go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -208,8 +212,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= -golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M= -golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -226,8 +230,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -238,14 +242,14 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= -gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= -google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= -google.golang.org/grpc v1.72.1 h1:HR03wO6eyZ7lknl75XlxABNVLLFc2PAb6mHlYh756mA= -google.golang.org/grpc v1.72.1/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= +gomodules.xyz/jsonpatch/v2 v2.5.0 h1:JELs8RLM12qJGXU4u/TO3V25KW8GreMKl9pdkk14RM0= +gomodules.xyz/jsonpatch/v2 v2.5.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a h1:SGktgSolFCo75dnHJF2yMvnns6jCmHFJ0vE4Vn2JKvQ= +google.golang.org/genproto/googleapis/api v0.0.0-20250528174236-200df99c418a/go.mod h1:a77HrdMjoeKbnd2jmgcWdaS++ZLZAEq3orIOAEIKiVw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.72.2 h1:TdbGzwb82ty4OusHWepvFWGLgIbNo1/SUynEN0ssqv8= +google.golang.org/grpc v1.72.2/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM= google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -276,8 +280,10 @@ k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOP k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y= k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2 h1:jpcvIRr3GLoUoEKRkHKSmGjxb6lWwrBlJsXc+eUYQHM= -sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.2/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0 h1:qPrZsv1cwQiFeieFlRqT627fVZ+tyfou/+S5S0H5ua0= +sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.33.0/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw= +sigs.k8s.io/controller-runtime v0.22.2 h1:cK2l8BGWsSWkXz09tcS4rJh95iOLney5eawcK5A33r4= +sigs.k8s.io/controller-runtime v0.22.2/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= sigs.k8s.io/controller-runtime v0.22.3 h1:I7mfqz/a/WdmDCEnXmSPm8/b/yRTy6JsKKENTijTq8Y= sigs.k8s.io/controller-runtime v0.22.3/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8= sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE= diff --git a/hack/boilerplate.go.txt b/hack/boilerplate.go.txt index 20ebd9a..1fb47b5 100644 --- a/hack/boilerplate.go.txt +++ b/hack/boilerplate.go.txt @@ -1,2 +1,2 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 diff --git a/hack/license-header.txt b/hack/license-header.txt index 86ca2c5..3ceae8e 100644 --- a/hack/license-header.txt +++ b/hack/license-header.txt @@ -1,2 +1,2 @@ -SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors SPDX-License-Identifier: Apache-2.0 diff --git a/hack/tools.go b/hack/tools.go index f6431dd..42fa6b8 100644 --- a/hack/tools.go +++ b/hack/tools.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 // Package tools diff --git a/internal/controller/ip_controller.go b/internal/controller/ip_controller.go index 9249af7..b415276 100644 --- a/internal/controller/ip_controller.go +++ b/internal/controller/ip_controller.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package controllers diff --git a/internal/controller/ip_controller_test.go b/internal/controller/ip_controller_test.go index 2248c26..41734ce 100644 --- a/internal/controller/ip_controller_test.go +++ b/internal/controller/ip_controller_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package controllers diff --git a/internal/controller/network_controller.go b/internal/controller/network_controller.go index 31d3f4f..19d905b 100644 --- a/internal/controller/network_controller.go +++ b/internal/controller/network_controller.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package controllers diff --git a/internal/controller/network_controller_test.go b/internal/controller/network_controller_test.go index 91fbda5..119acdd 100644 --- a/internal/controller/network_controller_test.go +++ b/internal/controller/network_controller_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package controllers diff --git a/internal/controller/networkcounter_controller.go b/internal/controller/networkcounter_controller.go index 68fe3ea..2257682 100644 --- a/internal/controller/networkcounter_controller.go +++ b/internal/controller/networkcounter_controller.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package controllers diff --git a/internal/controller/networkcounter_controller_test.go b/internal/controller/networkcounter_controller_test.go index baa831c..73af41f 100644 --- a/internal/controller/networkcounter_controller_test.go +++ b/internal/controller/networkcounter_controller_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package controllers diff --git a/internal/controller/subnet_controller.go b/internal/controller/subnet_controller.go index cc389b8..dd80690 100644 --- a/internal/controller/subnet_controller.go +++ b/internal/controller/subnet_controller.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package controllers diff --git a/internal/controller/subnet_controller_test.go b/internal/controller/subnet_controller_test.go index 43275c0..fb6b29f 100644 --- a/internal/controller/subnet_controller_test.go +++ b/internal/controller/subnet_controller_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package controllers diff --git a/internal/controller/suite_test.go b/internal/controller/suite_test.go index bed8bb0..d82b498 100644 --- a/internal/controller/suite_test.go +++ b/internal/controller/suite_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package controllers diff --git a/internal/webhook/v1alpha1/ip_webhook.go b/internal/webhook/v1alpha1/ip_webhook.go index 31d459b..d24c035 100644 --- a/internal/webhook/v1alpha1/ip_webhook.go +++ b/internal/webhook/v1alpha1/ip_webhook.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/internal/webhook/v1alpha1/ip_webhook_test.go b/internal/webhook/v1alpha1/ip_webhook_test.go index 1d31591..ade4ed2 100644 --- a/internal/webhook/v1alpha1/ip_webhook_test.go +++ b/internal/webhook/v1alpha1/ip_webhook_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/internal/webhook/v1alpha1/network_webhook.go b/internal/webhook/v1alpha1/network_webhook.go index 3c95e14..4694818 100644 --- a/internal/webhook/v1alpha1/network_webhook.go +++ b/internal/webhook/v1alpha1/network_webhook.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/internal/webhook/v1alpha1/network_webhook_test.go b/internal/webhook/v1alpha1/network_webhook_test.go index 856a7db..c37c3ea 100644 --- a/internal/webhook/v1alpha1/network_webhook_test.go +++ b/internal/webhook/v1alpha1/network_webhook_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/internal/webhook/v1alpha1/networkcounter_webhook.go b/internal/webhook/v1alpha1/networkcounter_webhook.go index 4b25e0b..d1f1eb3 100644 --- a/internal/webhook/v1alpha1/networkcounter_webhook.go +++ b/internal/webhook/v1alpha1/networkcounter_webhook.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/internal/webhook/v1alpha1/networkcounter_webhook_test.go b/internal/webhook/v1alpha1/networkcounter_webhook_test.go index 6bbffa7..6278de4 100644 --- a/internal/webhook/v1alpha1/networkcounter_webhook_test.go +++ b/internal/webhook/v1alpha1/networkcounter_webhook_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/internal/webhook/v1alpha1/subnet_webhook.go b/internal/webhook/v1alpha1/subnet_webhook.go index dcb3078..fe10c18 100644 --- a/internal/webhook/v1alpha1/subnet_webhook.go +++ b/internal/webhook/v1alpha1/subnet_webhook.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/internal/webhook/v1alpha1/subnet_webhook_test.go b/internal/webhook/v1alpha1/subnet_webhook_test.go index 2ab50b7..e2a9706 100644 --- a/internal/webhook/v1alpha1/subnet_webhook_test.go +++ b/internal/webhook/v1alpha1/subnet_webhook_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/internal/webhook/v1alpha1/webhook_suite_test.go b/internal/webhook/v1alpha1/webhook_suite_test.go index e9ff653..f775608 100644 --- a/internal/webhook/v1alpha1/webhook_suite_test.go +++ b/internal/webhook/v1alpha1/webhook_suite_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package v1alpha1 diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index df2e78d..af02ebc 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package e2e diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index f5c0004..be09c88 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package e2e diff --git a/test/utils/utils.go b/test/utils/utils.go index 5602f6e..d30158c 100644 --- a/test/utils/utils.go +++ b/test/utils/utils.go @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2024 SAP SE or an SAP affiliate company and IronCore contributors +// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and IronCore contributors // SPDX-License-Identifier: Apache-2.0 package utils