mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-14 11:57:48 +00:00
feat: add resource migration command (#9296)
* 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>
This commit is contained in:
parent
a045c4923b
commit
cad231fc15
6 changed files with 189 additions and 2 deletions
|
@ -7,6 +7,7 @@ import (
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/docs"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/docs"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/fix"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/fix"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/jp"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/jp"
|
||||||
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/migrate"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/oci"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/oci"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/test"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/test"
|
||||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/version"
|
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/commands/version"
|
||||||
|
@ -28,6 +29,7 @@ func RootCommand(experimental bool) *cobra.Command {
|
||||||
create.Command(),
|
create.Command(),
|
||||||
docs.Command(cmd),
|
docs.Command(cmd),
|
||||||
jp.Command(),
|
jp.Command(),
|
||||||
|
migrate.Command(),
|
||||||
test.Command(),
|
test.Command(),
|
||||||
version.Command(),
|
version.Command(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
func TestRootCommand(t *testing.T) {
|
func TestRootCommand(t *testing.T) {
|
||||||
cmd := RootCommand(false)
|
cmd := RootCommand(false)
|
||||||
assert.NotNil(t, cmd)
|
assert.NotNil(t, cmd)
|
||||||
assert.Len(t, cmd.Commands(), 6)
|
assert.Len(t, cmd.Commands(), 7)
|
||||||
err := cmd.Execute()
|
err := cmd.Execute()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ func TestRootCommand(t *testing.T) {
|
||||||
func TestRootCommandExperimental(t *testing.T) {
|
func TestRootCommandExperimental(t *testing.T) {
|
||||||
cmd := RootCommand(true)
|
cmd := RootCommand(true)
|
||||||
assert.NotNil(t, cmd)
|
assert.NotNil(t, cmd)
|
||||||
assert.Len(t, cmd.Commands(), 8)
|
assert.Len(t, cmd.Commands(), 9)
|
||||||
err := cmd.Execute()
|
err := cmd.Execute()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
119
cmd/cli/kubectl-kyverno/commands/migrate/command.go
Normal file
119
cmd/cli/kubectl-kyverno/commands/migrate/command.go
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
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
|
||||||
|
}
|
15
cmd/cli/kubectl-kyverno/commands/migrate/doc.go
Normal file
15
cmd/cli/kubectl-kyverno/commands/migrate/doc.go
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
package migrate
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
var websiteUrl = ``
|
||||||
|
|
||||||
|
var description = []string{
|
||||||
|
`Migrate one or more resources to the stored version.`,
|
||||||
|
}
|
||||||
|
|
||||||
|
var examples = [][]string{
|
||||||
|
{
|
||||||
|
`# Migrate policy exceptions`,
|
||||||
|
`kyverno migrate --resource policyexceptions.kyverno.io`,
|
||||||
|
},
|
||||||
|
}
|
|
@ -46,6 +46,7 @@ kyverno [flags]
|
||||||
* [kyverno docs](kyverno_docs.md) - Generates reference documentation.
|
* [kyverno docs](kyverno_docs.md) - Generates reference documentation.
|
||||||
* [kyverno fix](kyverno_fix.md) - Fix inconsistencies and deprecated usage of Kyverno resources.
|
* [kyverno fix](kyverno_fix.md) - Fix inconsistencies and deprecated usage of Kyverno resources.
|
||||||
* [kyverno jp](kyverno_jp.md) - Provides a command-line interface to JMESPath, enhanced with Kyverno specific custom functions.
|
* [kyverno jp](kyverno_jp.md) - Provides a command-line interface to JMESPath, enhanced with Kyverno specific custom functions.
|
||||||
|
* [kyverno migrate](kyverno_migrate.md) - Migrate one or more resources to the stored version.
|
||||||
* [kyverno oci](kyverno_oci.md) - Pulls/pushes images that include policie(s) from/to OCI registries.
|
* [kyverno oci](kyverno_oci.md) - Pulls/pushes images that include policie(s) from/to OCI registries.
|
||||||
* [kyverno test](kyverno_test.md) - Run tests from a local filesystem or a remote git repository.
|
* [kyverno test](kyverno_test.md) - Run tests from a local filesystem or a remote git repository.
|
||||||
* [kyverno version](kyverno_version.md) - Prints the version of Kyverno CLI.
|
* [kyverno version](kyverno_version.md) - Prints the version of Kyverno CLI.
|
||||||
|
|
50
docs/user/cli/commands/kyverno_migrate.md
Normal file
50
docs/user/cli/commands/kyverno_migrate.md
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
## kyverno migrate
|
||||||
|
|
||||||
|
Migrate one or more resources to the stored version.
|
||||||
|
|
||||||
|
### Synopsis
|
||||||
|
|
||||||
|
Migrate one or more resources to the stored version.
|
||||||
|
|
||||||
|
```
|
||||||
|
kyverno migrate [flags]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
```
|
||||||
|
# Migrate policy exceptions
|
||||||
|
kyverno migrate --resource policyexceptions.kyverno.io
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options
|
||||||
|
|
||||||
|
```
|
||||||
|
--context string The name of the kubeconfig context to use
|
||||||
|
-h, --help help for migrate
|
||||||
|
--kubeconfig string path to kubeconfig file with authorization and master location information
|
||||||
|
--resource strings The resource to migrate
|
||||||
|
```
|
||||||
|
|
||||||
|
### Options inherited from parent commands
|
||||||
|
|
||||||
|
```
|
||||||
|
--add_dir_header If true, adds the file directory to the header of the log messages
|
||||||
|
--alsologtostderr log to standard error as well as files (no effect when -logtostderr=true)
|
||||||
|
--log_backtrace_at traceLocation when logging hits line file:N, emit a stack trace (default :0)
|
||||||
|
--log_dir string If non-empty, write log files in this directory (no effect when -logtostderr=true)
|
||||||
|
--log_file string If non-empty, use this log file (no effect when -logtostderr=true)
|
||||||
|
--log_file_max_size uint Defines the maximum size a log file can grow to (no effect when -logtostderr=true). Unit is megabytes. If the value is 0, the maximum file size is unlimited. (default 1800)
|
||||||
|
--logtostderr log to standard error instead of files (default true)
|
||||||
|
--one_output If true, only write logs to their native severity level (vs also writing to each lower severity level; no effect when -logtostderr=true)
|
||||||
|
--skip_headers If true, avoid header prefixes in the log messages
|
||||||
|
--skip_log_headers If true, avoid headers when opening log files (no effect when -logtostderr=true)
|
||||||
|
--stderrthreshold severity logs at or above this threshold go to stderr when writing to files and stderr (no effect when -logtostderr=true or -alsologtostderr=true) (default 2)
|
||||||
|
-v, --v Level number for the log level verbosity
|
||||||
|
--vmodule moduleSpec comma-separated list of pattern=N settings for file-filtered logging
|
||||||
|
```
|
||||||
|
|
||||||
|
### SEE ALSO
|
||||||
|
|
||||||
|
* [kyverno](kyverno.md) - Kubernetes Native Policy Management.
|
||||||
|
|
Loading…
Reference in a new issue