Skip to content

Commit

Permalink
metalctl move CRDs
Browse files Browse the repository at this point in the history
  • Loading branch information
Nuckal777 committed Oct 29, 2024
1 parent 65a4530 commit 0a325e6
Show file tree
Hide file tree
Showing 5 changed files with 190 additions and 1 deletion.
40 changes: 40 additions & 0 deletions cmd/metalctl/app/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package app

import (
"path/filepath"

"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"

metalv1alphav1 "github.com/ironcore-dev/metal-operator/api/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 = "metalctl"

var scheme = runtime.NewScheme()

func init() {
utilruntime.Must(apiextensionsv1.AddToScheme(scheme))
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(metalv1alphav1.AddToScheme(scheme))
}

func NewCommand() *cobra.Command {
root := &cobra.Command{
Use: Name,
Short: "CLI client for metal-operator",
Args: cobra.NoArgs,
}
root.AddCommand(NewMoveCommand())
return root
}

func GetKubeconfig() (*rest.Config, error) {
return clientcmd.BuildConfigFromFlags("", filepath.Join(homedir.HomeDir(), ".kube", "config"))
}
125 changes: 125 additions & 0 deletions cmd/metalctl/app/move.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package app

import (
"context"
"errors"
"fmt"

metalv1alphav1 "github.com/ironcore-dev/metal-operator/api/v1alpha1"
"github.com/spf13/cobra"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/client-go/tools/clientcmd"
"sigs.k8s.io/controller-runtime/pkg/client"
)

var (
targetKubeconfig string
errCrdCreate error = errors.New("failed to create metal CRDs")
)

func NewMoveCommand() *cobra.Command {
move := &cobra.Command{
Use: "move",
Short: "Move metal-operator CRDs and CRs from one cluster to another",
RunE: runMove,
}
move.Flags().StringVar(&targetKubeconfig, "target-kubeconfig", "", "Kubeconfig pointing to the target cluster")
move.MarkFlagRequired("target-kubeconfig")
return move
}

type clients struct {
source client.Client
target client.Client
}

func makeClients() (clients, error) {
var clients clients
sourceCfg, err := GetKubeconfig()
if err != nil {
return clients, fmt.Errorf("failed to load source cluster kubeconfig: %w", err)
}
clients.source, err = client.New(sourceCfg, client.Options{Scheme: scheme})
if err != nil {
return clients, fmt.Errorf("failed to construct source cluster client: %w", err)
}
targetCfg, err := clientcmd.BuildConfigFromFlags("", targetKubeconfig)
if err != nil {
return clients, fmt.Errorf("failed to load target cluster kubeconfig: %w", err)
}
clients.target, err = client.New(targetCfg, client.Options{Scheme: scheme})
if err != nil {
return clients, fmt.Errorf("failed to construct target cluster client: %w", err)
}
return clients, nil
}

func moveCRDs(ctx context.Context, clients clients) error {
var crds apiextensionsv1.CustomResourceDefinitionList
if err := clients.source.List(ctx, &crds); err != nil {
return err
}
metalCrds := make([]apiextensionsv1.CustomResourceDefinition, 0)
for _, crd := range crds.Items {
if crd.Spec.Group == metalv1alphav1.GroupVersion.Group {
metalCrds = append(metalCrds, crd)
}
}
// it may be better to compare on semantics instead of CRD name
for _, sourceCrd := range metalCrds {
var targetCrd apiextensionsv1.CustomResourceDefinition
err := clients.target.Get(ctx, client.ObjectKeyFromObject(&sourceCrd), &targetCrd)
if apierrors.IsNotFound(err) {
continue
}
if err != nil {
return fmt.Errorf("failed to check CRD existence in target cluster: %w", err)
}
return fmt.Errorf("CRD for %s/%s already exists in the target cluster", sourceCrd.Spec.Group, sourceCrd.Spec.Names.Plural)
}
for _, crd := range metalCrds {
crd.ResourceVersion = ""
if err := clients.target.Create(ctx, &crd); err != nil {
return errCrdCreate
}
}
return nil
}

func cleanupCRDs(ctx context.Context, clients clients) error {
var crds apiextensionsv1.CustomResourceDefinitionList
if err := clients.target.List(ctx, &crds); err != nil {
return err
}
metalCrds := make([]apiextensionsv1.CustomResourceDefinition, 0)
for _, crd := range crds.Items {
if crd.Spec.Group == metalv1alphav1.GroupVersion.Group {
metalCrds = append(metalCrds, crd)
}
}
errs := make([]error, 0)
for _, crd := range metalCrds {
crd.ResourceVersion = ""
if err := clients.target.Delete(ctx, &crd); err != nil {
errs = append(errs, err)
}
}
return errors.Join(errs...)
}

func runMove(cmd *cobra.Command, args []string) error {
clients, err := makeClients()
if err != nil {
return err
}
ctx := cmd.Context()
err = moveCRDs(ctx, clients)
switch {
case errors.Is(err, errCrdCreate):
return cleanupCRDs(ctx, clients)
case err != nil:
return err
}
return nil
}
16 changes: 16 additions & 0 deletions cmd/metalctl/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

import (
"fmt"
"os"

"github.com/ironcore-dev/metal-operator/cmd/metalctl/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)
}
}
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ require (
github.com/ironcore-dev/controller-utils v0.9.4
github.com/onsi/ginkgo/v2 v2.20.2
github.com/onsi/gomega v1.34.2
github.com/spf13/cobra v1.8.1
github.com/stmcginnis/gofish v0.19.0
k8s.io/api v0.31.1
k8s.io/apiextensions-apiserver v0.31.0
k8s.io/apimachinery v0.31.1
k8s.io/client-go v0.31.1
k8s.io/utils v0.0.0-20240711033017-18e509b52bc8
Expand Down Expand Up @@ -38,6 +40,7 @@ require (
github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/imdario/mergo v0.3.13 // 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
Expand Down Expand Up @@ -66,7 +69,6 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/apiextensions-apiserver v0.31.0 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
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.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down Expand Up @@ -50,6 +51,8 @@ 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/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
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.9.4 h1:l+lXzDyTfDEvAn0o9KOX0JdeTf6uI0VKN9yVnl9jLM4=
github.com/ironcore-dev/controller-utils v0.9.4/go.mod h1:0MS4W51EAEQo/nfajSaCj4RClju4MXv6IFGb+nDv2AA=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
Expand Down Expand Up @@ -93,6 +96,9 @@ github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0leargg
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stmcginnis/gofish v0.19.0 h1:fmxdRZ5WHfs+4ExArMYoeRfoh+SAxLELKtmoVplBkU4=
Expand Down

0 comments on commit 0a325e6

Please sign in to comment.