Skip to content

Commit

Permalink
feat: implement cleanup command
Browse files Browse the repository at this point in the history
  • Loading branch information
Telemaco019 committed Aug 24, 2024
1 parent 9077d4c commit 556f7bd
Show file tree
Hide file tree
Showing 8 changed files with 153 additions and 28 deletions.
15 changes: 13 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,22 @@

### New features

* Add command `list` for showing duplicated resources.
* Add command `list` for showing duplicated resources. Example:

```shell
kubectl duplicate list -n my-namespace
```

* Add command `cleanup` for deleting duplicated resources. Example:

```shell
kubectl duplicate cleanup -n my-namespace
```

### Chores

* Switch to [Dynamic Client](https://github.com/kubernetes/client-go/blob/master/examples/dynamic-create-update-delete-deployment/README.md),
* Switch
to [Dynamic Client](https://github.com/kubernetes/client-go/blob/master/examples/dynamic-create-update-delete-deployment/README.md),
opening the door for duplicating any resource type.

## v0.2.1
Expand Down
24 changes: 24 additions & 0 deletions pkg/clients/duplik8s_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/discovery"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/restmapper"
"slices"
"strings"
)
Expand Down Expand Up @@ -68,6 +69,29 @@ func (c Duplik8sClient) ListDuplicable(
return objs, nil
}

func (c Duplik8sClient) Delete(
ctx context.Context,
obj core.DuplicatedObject,
) error {
// Get a RESTMapper
resources, err := restmapper.GetAPIGroupResources(c.discovery)
if err != nil {
panic(err.Error())
}
restMapper := restmapper.NewDiscoveryRESTMapper(resources)

// Convert GroupVersionKind to GroupVersionResource
mapping, err := restMapper.RESTMapping(
obj.ObjectKind.GroupVersionKind().GroupKind(),
obj.ObjectKind.GroupVersionKind().Version,
)
if err != nil {
panic(err.Error())
}

return c.dynamic.Resource(mapping.Resource).Namespace(obj.Namespace).Delete(ctx, obj.Name, metav1.DeleteOptions{})
}

func (c Duplik8sClient) ListDuplicated(
ctx context.Context,
namespace string,
Expand Down
81 changes: 81 additions & 0 deletions pkg/cmd/cleanup.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/*
* Copyright 2024 Michele Zanotti <[email protected]>
*
* 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 cmd

import (
"context"
"fmt"
"github.com/charmbracelet/huh"
"github.com/spf13/cobra"
"github.com/telemaco019/duplik8s/pkg/clients"
"github.com/telemaco019/duplik8s/pkg/core"
)

func cleanup(client core.Client, namespace string) error {
duplicated, err := client.ListDuplicated(context.Background(), namespace)
if err != nil {
return err
}
if len(duplicated) == 0 {
fmt.Printf("No duplicated resources found in namespace %q\n", namespace)
return nil
}

renderDuplicatedObjects(duplicated)

var shouldDelete bool
err = huh.NewConfirm().Title("Do you want to delete the following resources?").Value(&shouldDelete).Run()
if err != nil {
return err
}

if shouldDelete {
for _, obj := range duplicated {
err = client.Delete(context.Background(), obj)
if err != nil {
return err
}
fmt.Printf("deleted %s %s/%s\n", obj.ObjectKind.GroupVersionKind().Kind, obj.Namespace, obj.Name)
}
}

return nil
}

func NewCleanupCmd(client core.Client) *cobra.Command {
podCmd := &cobra.Command{
Use: "cleanup",
Short: "Cleanup duplicated resources.",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cmd.SilenceUsage = true
opts, err := NewKubeOptions(cmd, args)
if err != nil {
return err
}
if client == nil {
client, err = clients.NewDuplik8sClient(opts)
if err != nil {
return err
}
}
return cleanup(client, opts.Namespace)
},
}
addOverrideFlags(podCmd)
return podCmd
}
27 changes: 2 additions & 25 deletions pkg/cmd/list_duplicated.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,46 +19,23 @@ package cmd
import (
"context"
"fmt"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
"github.com/spf13/cobra"
"github.com/telemaco019/duplik8s/pkg/clients"
"github.com/telemaco019/duplik8s/pkg/core"
"github.com/telemaco019/duplik8s/pkg/utils"
)

func listDuplicatedResources(client core.Client, namespace string) error {
duplicatedObjs, err := client.ListDuplicated(context.Background(), namespace)
if err != nil {
return err
}

if len(duplicatedObjs) == 0 {
fmt.Printf("No duplicated resources found in namespace %q\n", namespace)
return nil
}
headerStyle := lipgloss.NewStyle().Bold(true).Padding(0, 1)
defaultStyle := lipgloss.NewStyle().Padding(0, 1)
t := table.New().Border(lipgloss.HiddenBorder()).
StyleFunc(func(row, col int) lipgloss.Style {
switch {
case row == 0:
return headerStyle
default:
return defaultStyle
}
}).
Headers("Namespace", "Kind", "Name", "Age")
for _, obj := range duplicatedObjs {
t.Row(
obj.Namespace,
obj.ObjectKind.GroupVersionKind().Kind,
obj.Name,
utils.FormatAge(obj.CreationTimestamp),
)
}
fmt.Print(t.Render() + "\n")
renderDuplicatedObjects(duplicatedObjs)
return nil

}

func NewListDuplicatedCmd(client core.Client) *cobra.Command {
Expand Down
3 changes: 2 additions & 1 deletion pkg/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@ func NewRootCmd(

// add subcommands
rootCmd.AddCommand(NewPodCmd(duplicator, client))
rootCmd.AddCommand(NewListDuplicatedCmd(client))
rootCmd.AddCommand(NewDeployCmd(duplicator, client))
rootCmd.AddCommand(NewStatefulSetCmd(duplicator, client))
rootCmd.AddCommand(NewListDuplicatedCmd(client))
rootCmd.AddCommand(NewCleanupCmd(client))

return rootCmd
}
26 changes: 26 additions & 0 deletions pkg/cmd/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package cmd
import (
"context"
"fmt"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/lipgloss/table"
"github.com/spf13/cobra"
"github.com/telemaco019/duplik8s/pkg/clients"
"github.com/telemaco019/duplik8s/pkg/cmd/flags"
Expand Down Expand Up @@ -109,3 +111,27 @@ func addOverrideFlags(cmd *cobra.Command) {
"Override the command of each container in the Pod.",
)
}

func renderDuplicatedObjects(duplicatedObjs []core.DuplicatedObject) {
headerStyle := lipgloss.NewStyle().Bold(true).Padding(0, 1)
defaultStyle := lipgloss.NewStyle().Padding(0, 1)
t := table.New().Border(lipgloss.HiddenBorder()).
StyleFunc(func(row, col int) lipgloss.Style {
switch {
case row == 0:
return headerStyle
default:
return defaultStyle
}
}).
Headers("Namespace", "Kind", "Name", "Age")
for _, obj := range duplicatedObjs {
t.Row(
obj.Namespace,
obj.ObjectKind.GroupVersionKind().Kind,
obj.Name,
utils.FormatAge(obj.CreationTimestamp),
)
}
fmt.Print(t.Render() + "\n")
}
1 change: 1 addition & 0 deletions pkg/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ type Client interface {
namespace string,
) ([]DuplicableObject, error)
ListDuplicated(ctx context.Context, namespace string) ([]DuplicatedObject, error)
Delete(ctx context.Context, obj DuplicatedObject) error
}

type PodOverrideOptions struct {
Expand Down
4 changes: 4 additions & 0 deletions pkg/test/mocks/pod_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,7 @@ func (c *PodClient) ListDuplicated(
) ([]core.DuplicatedObject, error) {
return c.ListDuplicatedResult, nil
}

func (c *PodClient) Delete(ctx context.Context, obj core.DuplicatedObject) error {
return nil
}

0 comments on commit 556f7bd

Please sign in to comment.