mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-09 01:16:55 +00:00
* feat: add resource migration command Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * finalize PR Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix unit tests Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
119 lines
3.7 KiB
Go
119 lines
3.7 KiB
Go
package migrate
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/command"
|
|
"github.com/kyverno/kyverno/pkg/config"
|
|
"github.com/spf13/cobra"
|
|
v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
|
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
"k8s.io/client-go/dynamic"
|
|
)
|
|
|
|
type options struct {
|
|
KubeConfig string
|
|
Context string
|
|
Resources []string
|
|
}
|
|
|
|
func Command() *cobra.Command {
|
|
var options options
|
|
cmd := &cobra.Command{
|
|
Use: "migrate",
|
|
Short: command.FormatDescription(true, websiteUrl, false, description...),
|
|
Long: command.FormatDescription(false, websiteUrl, false, description...),
|
|
Example: command.FormatExamples(examples...),
|
|
Args: cobra.NoArgs,
|
|
SilenceUsage: true,
|
|
RunE: func(cmd *cobra.Command, _ []string) error {
|
|
clientConfig, err := config.CreateClientConfigWithContext(options.KubeConfig, options.Context)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
apiServerClient, err := clientset.NewForConfig(clientConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
dynamicClient, err := dynamic.NewForConfig(clientConfig)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, resource := range options.Resources {
|
|
fmt.Println("migrating resource:", resource, "...")
|
|
ctx := context.Background()
|
|
crd, err := apiServerClient.ApiextensionsV1().CustomResourceDefinitions().Get(ctx, resource, metav1.GetOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := migrate(ctx, crd, dynamicClient, apiServerClient); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
cmd.Flags().StringVar(&options.KubeConfig, "kubeconfig", "", "path to kubeconfig file with authorization and master location information")
|
|
cmd.Flags().StringVar(&options.Context, "context", "", "The name of the kubeconfig context to use")
|
|
cmd.Flags().StringSliceVar(&options.Resources, "resource", nil, "The resource to migrate")
|
|
return cmd
|
|
}
|
|
|
|
func migrate(ctx context.Context, crd *v1.CustomResourceDefinition, dynamicClient dynamic.Interface, apiServerClient clientset.Interface) error {
|
|
var storedVersion *v1.CustomResourceDefinitionVersion
|
|
for i := range crd.Spec.Versions {
|
|
if crd.Spec.Versions[i].Storage {
|
|
storedVersion = &crd.Spec.Versions[i]
|
|
}
|
|
}
|
|
if storedVersion == nil {
|
|
return errors.New("stored version not found")
|
|
} else {
|
|
fmt.Println("stored version:", storedVersion.Name)
|
|
if len(crd.Status.StoredVersions) == 1 {
|
|
if crd.Status.StoredVersions[0] == storedVersion.Name {
|
|
fmt.Println("stored version is already up to date, nothing to do")
|
|
return nil
|
|
}
|
|
}
|
|
gvr := schema.GroupVersionResource{
|
|
Group: crd.Spec.Group,
|
|
Version: storedVersion.Name,
|
|
Resource: crd.Spec.Names.Plural,
|
|
}
|
|
resource := dynamicClient.Resource(gvr)
|
|
var client dynamic.ResourceInterface
|
|
if crd.Spec.Scope == v1.NamespaceScoped {
|
|
client = resource.Namespace(metav1.NamespaceAll)
|
|
} else {
|
|
client = resource
|
|
}
|
|
fmt.Println("migrating resources...")
|
|
list, err := client.List(ctx, metav1.ListOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for i := range list.Items {
|
|
var client dynamic.ResourceInterface
|
|
if crd.Spec.Scope == v1.NamespaceScoped {
|
|
client = resource.Namespace(list.Items[i].GetNamespace())
|
|
} else {
|
|
client = resource
|
|
}
|
|
_, err := client.Update(ctx, &list.Items[i], metav1.UpdateOptions{})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
fmt.Println("patching status...")
|
|
crd.Status.StoredVersions = []string{storedVersion.Name}
|
|
if _, err := apiServerClient.ApiextensionsV1().CustomResourceDefinitions().UpdateStatus(ctx, crd, metav1.UpdateOptions{}); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|