cmd/nodeadm/uninstall/uninstall.go (122 lines of code) (raw):
package uninstall
import (
"context"
"fmt"
"os"
"github.com/integrii/flaggy"
"go.uber.org/zap"
"k8s.io/utils/strings/slices"
"github.com/aws/eks-hybrid/internal/cleanup"
"github.com/aws/eks-hybrid/internal/cli"
"github.com/aws/eks-hybrid/internal/cni"
"github.com/aws/eks-hybrid/internal/containerd"
"github.com/aws/eks-hybrid/internal/daemon"
"github.com/aws/eks-hybrid/internal/flows"
"github.com/aws/eks-hybrid/internal/kubelet"
"github.com/aws/eks-hybrid/internal/logger"
"github.com/aws/eks-hybrid/internal/node"
"github.com/aws/eks-hybrid/internal/packagemanager"
"github.com/aws/eks-hybrid/internal/tracker"
)
const (
skipPodPreflightCheck = "pod-validation"
skipNodePreflightCheck = "node-validation"
)
const uninstallHelpText = `Examples:
# Uninstall all components
nodeadm uninstall
# Uninstall all components and skip pod-validation and node-validation pre-flight validation
nodeadm uninstall --skip node-validation,pod-validation
Documentation:
https://docs.aws.amazon.com/eks/latest/userguide/hybrid-nodes-nodeadm.html#_uninstall`
func NewCommand() cli.Command {
cmd := command{}
fc := flaggy.NewSubcommand("uninstall")
fc.Description = "Uninstall components installed using the install sub-command"
fc.AdditionalHelpAppend = uninstallHelpText
fc.StringSlice(&cmd.skipPhases, "s", "skip", "Phases of uninstall to skip. Allowed values: [pod-validation, node-validation].")
fc.Bool(&cmd.force, "f", "force", "Force delete additional directories that might contain leftovers from the node process. WARNING: This will delete all contents in default Kubernetes and CNI directories (/var/lib/kubelet, /var/lib/cni, etc). Do not use this flag if you store your own data in these locations.")
cmd.flaggy = fc
return &cmd
}
type command struct {
flaggy *flaggy.Subcommand
skipPhases []string
force bool
}
func (c *command) Flaggy() *flaggy.Subcommand {
return c.flaggy
}
func (c *command) Run(log *zap.Logger, opts *cli.GlobalOptions) error {
ctx := context.Background()
ctx = logger.NewContext(ctx, log)
root, err := cli.IsRunningAsRoot()
if err != nil {
return err
}
if !root {
return cli.ErrMustRunAsRoot
}
log.Info("Loading installed components")
installed, err := tracker.GetInstalledArtifacts()
if err != nil && os.IsNotExist(err) {
log.Info("Nodeadm components are already uninstalled")
return nil
} else if err != nil {
return err
}
log.Info("Creating daemon manager..")
daemonManager, err := daemon.NewDaemonManager()
if err != nil {
return err
}
defer daemonManager.Close()
if installed.Artifacts.Kubelet {
kubeletStatus, err := daemonManager.GetDaemonStatus(kubelet.KubeletDaemonName)
if err != nil {
return err
}
if kubeletStatus == daemon.DaemonStatusRunning {
if !slices.Contains(c.skipPhases, skipPodPreflightCheck) {
log.Info("Validating if node has been drained...")
if drained, err := node.IsDrained(ctx); err != nil {
return fmt.Errorf("validating if node has been drained: %w", err)
} else if !drained {
return fmt.Errorf("only static pods and pods controlled by daemon-sets can be running on the node. Please move pods " +
"to different node or use --skip pod-validation")
}
}
if !slices.Contains(c.skipPhases, skipNodePreflightCheck) {
log.Info("Validating if node has been marked unschedulable...")
if err := node.IsUnscheduled(ctx); err != nil {
return fmt.Errorf("please drain or cordon node to mark it unschedulable or use --skip node-validation: %w", err)
}
}
}
}
log.Info("Creating package manager...")
containerdSource := containerd.GetContainerdSource(installed.Artifacts.Containerd)
log.Info("Configuring package manager with", zap.Reflect("containerd source", string(containerdSource)))
packageManager, err := packagemanager.New(containerdSource, log)
if err != nil {
return err
}
uninstaller := &flows.Uninstaller{
Artifacts: installed.Artifacts,
DaemonManager: daemonManager,
PackageManager: packageManager,
Logger: log,
CNIUninstall: cni.Uninstall,
}
if err := uninstaller.Run(ctx); err != nil {
return err
}
if c.force {
log.Info("Force mode enabled, cleaning up additional directories...")
cleanupManager := cleanup.New(log)
if err := cleanupManager.Cleanup(); err != nil {
return fmt.Errorf("cleaning up additional directories: %w", err)
}
}
return nil
}