1
0
mirror of synced 2026-02-06 19:05:55 +00:00

Add delete image-policy and refactor

This adds a command for deleting ImagePolicy objects. Since the
control flow for the command needs only a runtime.Object (and a name
for the type), it can be factored out.

I have made the argument (field in the deleteCommand struct) an
interface `objectContainer`, through which the command code gets a
`runtime.Object` to deserialise into (and delete). It could be simply
a `runtime.Object` here; however things like `getCommand` require
other methods, so it's convenient to have an interface for it.

Signed-off-by: Michael Bridgen <michael@weave.works>
This commit is contained in:
Michael Bridgen
2020-12-07 10:51:14 +00:00
parent 512761080e
commit 52145c045d
9 changed files with 186 additions and 57 deletions

View File

@@ -17,7 +17,14 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
)
var deleteCmd = &cobra.Command{
@@ -36,3 +43,52 @@ func init() {
rootCmd.AddCommand(deleteCmd)
}
type deleteCommand struct {
humanKind string // the kind being deleted, lowercase and spaced e.g., "image policy"
container objectContainer // for getting the value, and later deleting it
}
func (del deleteCommand) run(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("%s name is required", del.humanKind)
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
err = kubeClient.Get(ctx, namespacedName, del.container.AsClientObject())
if err != nil {
return err
}
if !deleteSilent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this " + del.humanKind,
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting %s %s in %s namespace", del.humanKind, name, namespace)
err = kubeClient.Delete(ctx, del.container.AsClientObject())
if err != nil {
return err
}
logger.Successf("%s deleted", del.humanKind)
return nil
}

View File

@@ -0,0 +1,40 @@
/*
Copyright 2020 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"github.com/spf13/cobra"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
)
var deleteImagePolicyCmd = &cobra.Command{
Use: "image-policy [name]",
Short: "Delete an ImagePolicy object",
Long: "The delete auto image-policy command deletes the given ImagePolicy from the cluster.",
Example: ` # Delete an image policy
flux delete auto image-policy alpine3.x
`,
RunE: deleteCommand{
humanKind: "image policy",
container: genericContainer{&imagev1.ImagePolicy{}},
}.run,
}
func init() {
deleteAutoCmd.AddCommand(deleteImagePolicyCmd)
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package main
import (
"context"
"fmt"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
"github.com/fluxcd/flux2/internal/utils"
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
)
@@ -35,54 +29,12 @@ var deleteImageRepositoryCmd = &cobra.Command{
Example: ` # Delete an image repository
flux delete auto image-repository alpine
`,
RunE: deleteImageRepositoryRun,
RunE: deleteCommand{
humanKind: "image repository",
container: genericContainer{&imagev1.ImageRepository{}},
}.run,
}
func init() {
deleteAutoCmd.AddCommand(deleteImageRepositoryCmd)
}
func deleteImageRepositoryRun(cmd *cobra.Command, args []string) error {
if len(args) < 1 {
return fmt.Errorf("image repository name is required")
}
name := args[0]
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
kubeClient, err := utils.KubeClient(kubeconfig, kubecontext)
if err != nil {
return err
}
namespacedName := types.NamespacedName{
Namespace: namespace,
Name: name,
}
var repo imagev1.ImageRepository
err = kubeClient.Get(ctx, namespacedName, &repo)
if err != nil {
return err
}
if !deleteSilent {
prompt := promptui.Prompt{
Label: "Are you sure you want to delete this image repository",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return fmt.Errorf("aborting")
}
}
logger.Actionf("deleting image repository %s in %s namespace", name, namespace)
err = kubeClient.Delete(ctx, &repo)
if err != nil {
return err
}
logger.Successf("image repository deleted")
return nil
}

View File

@@ -23,7 +23,6 @@ import (
"github.com/spf13/cobra"
apimeta "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/fluxcd/pkg/apis/meta"
@@ -46,7 +45,7 @@ func init() {
}
type summarisable interface {
AsObject() runtime.Object
objectContainer
Len() int
SummariseAt(i int, includeNamespace bool) []string
Headers(includeNamespace bool) []string
@@ -93,7 +92,7 @@ func (get getCommand) run(cmd *cobra.Command, args []string) error {
if !allNamespaces {
listOpts = append(listOpts, client.InNamespace(namespace))
}
err = kubeClient.List(ctx, get.list.AsObject(), listOpts...)
err = kubeClient.List(ctx, get.list.AsClientObject(), listOpts...)
if err != nil {
return err
}

View File

@@ -64,6 +64,6 @@ func (s imagePolicySummary) Headers(includeNamespace bool) []string {
return headers
}
func (s imagePolicySummary) AsObject() runtime.Object {
func (s imagePolicySummary) AsClientObject() runtime.Object {
return s.ImagePolicyList
}

View File

@@ -73,6 +73,6 @@ func (s imageRepositorySummary) Headers(includeNamespace bool) []string {
return headers
}
func (s imageRepositorySummary) AsObject() runtime.Object {
func (s imageRepositorySummary) AsClientObject() runtime.Object {
return s.ImageRepositoryList
}

40
cmd/flux/object.go Normal file
View File

@@ -0,0 +1,40 @@
/*
Copyright 2020 The Flux authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main
import (
"k8s.io/apimachinery/pkg/runtime"
)
// objectContainer is an interface for a wrapper or alias from which we
// can get a controller-runtime deserialisable value. This is used so
// that you can wrap an API type to give it other useful methods, but
// still use values of the wrapper with `client.Client`, which only
// deals with types that have been added to the schema.
type objectContainer interface {
AsClientObject() runtime.Object
}
// genericContainer is an objectContainer for any runtime.Object. Use
// this if there are no other methods needed.
type genericContainer struct {
obj runtime.Object
}
func (c genericContainer) AsClientObject() runtime.Object {
return c.obj
}