Skip to content

Commit

Permalink
Merge pull request #65 from portainer/feat64-reset
Browse files Browse the repository at this point in the history
feat: introduce reset flag and routine
  • Loading branch information
deviantony authored Sep 21, 2023
2 parents 5464ef2 + ce8660f commit 5de030b
Show file tree
Hide file tree
Showing 5 changed files with 324 additions and 55 deletions.
7 changes: 5 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ARCH="$(shell go env GOARCH)"
ARM=""
VERSION="latest"

.PHONY: pre dev build release image image-arm-6 image-arm-7 image-multiarch clean
.PHONY: pre dev build release image image-arm-6 image-arm-7 image-multiarch clean reset

dist := dist
bin := $(shell basename $(CURDIR))
Expand Down Expand Up @@ -53,4 +53,7 @@ image-multiarch:
clean:
rm -rf $(dist)/*
rm -rf /opt/dev-toolkit/k2d/*
rm -rf /var/lib/k2d
rm -rf /var/lib/k2d

reset: build
$(dist)/$(bin) -reset
34 changes: 34 additions & 0 deletions cmd/k2d.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package main

import (
"context"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"path"

restfulspec "github.com/emicklei/go-restful-openapi/v2"
Expand All @@ -24,6 +26,7 @@ import (
"github.com/portainer/k2d/internal/token"
"github.com/portainer/k2d/internal/types"
"github.com/portainer/k2d/pkg/network"
"github.com/portainer/k2d/pkg/prompt"
"github.com/sethvargo/go-envconfig"
)

Expand All @@ -38,6 +41,9 @@ func getAdvertiseIpAddr(advertiseAddr string) (net.IP, error) {
func main() {
ctx := context.Background()

resetMode := flag.Bool("reset", false, "Reset this host by removing all resources created by k2d and created via k2d")
flag.Parse()

var cfg config.Config
if err := envconfig.Process(ctx, &cfg); err != nil {
log.Fatalf("unable to parse configuration: %s", err)
Expand All @@ -49,6 +55,34 @@ func main() {
}
defer logger.Sync()

if *resetMode {
fmt.Println("Are you sure you want to this host? This will remove everything created by or via k2d including workload and data. y/N")
confirm, err := prompt.AskForConfirmation()
if err != nil {
logger.Fatalf("unable to ask for confirmation: %s", err)
}

if confirm {
kubeDockerAdapterOptions := &adapter.KubeDockerAdapterOptions{
K2DConfig: &cfg,
Logger: logger,
ServerConfiguration: nil,
}

kubeDockerAdapter, err := adapter.NewKubeDockerAdapter(kubeDockerAdapterOptions)
if err != nil {
logger.Fatalf("unable to create docker adapter: %s", err)
}

err = kubeDockerAdapter.ExecuteResetRoutine(ctx, cfg.DataPath)
if err != nil {
logger.Fatalf("an error occured during reset routine: %s", err)
}
}

os.Exit(0)
}

// We add the logger to the main context
ctx = logging.ContextWithLogger(ctx, logger)

Expand Down
177 changes: 177 additions & 0 deletions internal/adapter/reset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
package adapter

import (
"context"
"fmt"

"github.com/portainer/k2d/pkg/filesystem"
"k8s.io/apimachinery/pkg/labels"
)

// ExecuteResetRoutine performs a cleanup routine that removes all k2d resources from the host,
// as well as content within the specified k2d data directory.
// This function is intended to be used as a "reset mode" operation for cleaning up any resources
// managed by k2d on the host.
//
// Parameters:
// - ctx context.Context: The context for carrying out the reset routine.
// - k2dDataPath string: The path to the k2d data directory that needs to be cleaned up.
//
// Returns:
// - error: Returns an error if any of the resource removal or file system operations fail.
//
// Steps:
// 1. Removes all workload resources (like deployments, pods) by invoking removeAllWorkloads.
// 2. Removes all Persistent Volumes and Persistent Volume Claims by invoking removeAllPersistentVolumeAndClaims.
// 3. Removes all ConfigMaps and Secrets by invoking removeAllConfigMapsAndSecrets.
// 4. Removes all namespaces by invoking removeAllNamespaces.
// 5. Removes all content in the k2d data directory by invoking filesystem.RemoveAllContent.
func (adapter *KubeDockerAdapter) ExecuteResetRoutine(ctx context.Context, k2dDataPath string) error {
adapter.logger.Infoln("reset mode enabled, removing all k2d resources on this host")

err := adapter.removeAllWorkloads(ctx)
if err != nil {
return fmt.Errorf("unable to remove workloads: %w", err)
}

err = adapter.removeAllPersistentVolumeAndClaims(ctx)
if err != nil {
return fmt.Errorf("unable to remove persistent volumes and persistent volume claims: %w", err)
}

err = adapter.removeAllConfigMapsAndSecrets(ctx)
if err != nil {
return fmt.Errorf("unable to remove configmaps and secrets: %w", err)
}

err = adapter.removeAllNamespaces(ctx)
if err != nil {
return fmt.Errorf("unable to remove namespaces: %w", err)
}

adapter.logger.Infoln("removing k2d data directory content...")

err = filesystem.RemoveAllContent(k2dDataPath)
if err != nil {
return fmt.Errorf("unable to remove k2d data directory content: %w", err)
}

adapter.logger.Infoln("reset routine completed")
return nil
}

func (adapter *KubeDockerAdapter) removeAllWorkloads(ctx context.Context) error {
adapter.logger.Infoln("removing all workloads (deployments, pods)...")

deployments, err := adapter.ListDeployments(ctx, "")
if err != nil {
return fmt.Errorf("unable to list deployments: %w", err)
}

for _, deployment := range deployments.Items {
adapter.logger.Infof("removing deployment %s/%s", deployment.Namespace, deployment.Name)
adapter.DeleteContainer(ctx, deployment.Name, deployment.Namespace)
}

pods, err := adapter.ListPods(ctx, "")
if err != nil {
return fmt.Errorf("unable to list pods: %w", err)
}

for _, pod := range pods.Items {
adapter.logger.Infof("removing pod %s/%s", pod.Namespace, pod.Name)
adapter.DeleteContainer(ctx, pod.Name, pod.Namespace)
}

return nil
}

func (adapter *KubeDockerAdapter) removeAllPersistentVolumeAndClaims(ctx context.Context) error {
adapter.logger.Infoln("removing all persistent volumes and persistent volume claims...")

persistentVolumes, err := adapter.ListPersistentVolumes(ctx)
if err != nil {
return fmt.Errorf("unable to list persistent volumes: %w", err)
}

for _, persistentVolume := range persistentVolumes.Items {
adapter.logger.Infof("removing persistent volume %s", persistentVolume.Name)

err = adapter.DeletePersistentVolume(ctx, persistentVolume.Name)
if err != nil {
adapter.logger.Warnf("unable to remove persistent volume %s: %s", persistentVolume.Name, err)
}
}

persistentVolumeClaims, err := adapter.ListPersistentVolumeClaims(ctx, "")
if err != nil {
return fmt.Errorf("unable to list persistent volume claims: %w", err)
}

for _, persistentVolumeClaim := range persistentVolumeClaims.Items {
adapter.logger.Infof("removing persistent volume claim %s/%s", persistentVolumeClaim.Namespace, persistentVolumeClaim.Name)

err = adapter.DeletePersistentVolumeClaim(ctx, persistentVolumeClaim.Name, persistentVolumeClaim.Namespace)
if err != nil {
adapter.logger.Warnf("unable to remove persistent volume claim %s/%s: %s", persistentVolumeClaim.Namespace, persistentVolumeClaim.Name, err)
}
}

return nil
}

func (adapter *KubeDockerAdapter) removeAllConfigMapsAndSecrets(ctx context.Context) error {
adapter.logger.Infoln("removing all configmaps...")

configMaps, err := adapter.ListConfigMaps("")
if err != nil {
return fmt.Errorf("unable to list configmaps: %w", err)
}

for _, configMap := range configMaps.Items {
adapter.logger.Infof("removing configmap %s/%s", configMap.Namespace, configMap.Name)

err = adapter.DeleteConfigMap(configMap.Name, configMap.Namespace)
if err != nil {
adapter.logger.Warnf("unable to remove configmap %s/%s: %s", configMap.Namespace, configMap.Name, err)
}
}

adapter.logger.Infoln("removing all secrets...")

secrets, err := adapter.ListSecrets("", labels.NewSelector())
if err != nil {
return fmt.Errorf("unable to list secrets: %w", err)
}

for _, secret := range secrets.Items {
adapter.logger.Infof("removing secret %s/%s", secret.Namespace, secret.Name)

err = adapter.DeleteSecret(secret.Name, secret.Namespace)
if err != nil {
adapter.logger.Warnf("unable to remove secret %s/%s: %s", secret.Namespace, secret.Name, err)
}
}

return nil
}

func (adapter *KubeDockerAdapter) removeAllNamespaces(ctx context.Context) error {
adapter.logger.Infoln("removing all namespaces...")

namespaces, err := adapter.ListNamespaces(ctx)
if err != nil {
return fmt.Errorf("unable to list namespaces: %w", err)
}

for _, namespace := range namespaces.Items {
adapter.logger.Infof("removing namespace %s", namespace.Name)

err = adapter.DeleteNamespace(ctx, namespace.Name)
if err != nil {
adapter.logger.Warnf("unable to remove namespace %s: %s", namespace.Name, err)
}
}

return nil
}
Loading

0 comments on commit 5de030b

Please sign in to comment.