From 7617f8aee9352d192810a378225955256b05591c Mon Sep 17 00:00:00 2001 From: Emily McMullan Date: Tue, 20 Aug 2024 14:38:10 -0400 Subject: [PATCH] handle cleanup for interrupt Signed-off-by: Emily McMullan --- cmd/analyze.go | 98 +++++++------------------------------------------- cmd/cleanup.go | 85 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 85 deletions(-) create mode 100644 cmd/cleanup.go diff --git a/cmd/analyze.go b/cmd/analyze.go index cfdd3bd..323ef4f 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -11,6 +11,7 @@ import ( "io/fs" "os" "os/exec" + "os/signal" "path" "runtime" @@ -181,6 +182,9 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command { if val, err := cmd.Flags().GetBool(noCleanupFlag); err == nil { analyzeCmd.cleanup = !val } + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt) + defer stop() + if analyzeCmd.overrideProviderSettings == "" { if analyzeCmd.listSources || analyzeCmd.listTargets { err := analyzeCmd.ListLabels(cmd.Context()) @@ -222,7 +226,7 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command { } } if len(foundProviders) == 1 && foundProviders[0] == dotnetFrameworkProvider { - return analyzeCmd.analyzeDotnetFramework(cmd.Context()) + return analyzeCmd.analyzeDotnetFramework(ctx) } // default rulesets are only java rules @@ -231,7 +235,7 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command { return fmt.Errorf("No providers found with default rules. Use --rules option") } - xmlOutputDir, err := analyzeCmd.ConvertXML(cmd.Context()) + xmlOutputDir, err := analyzeCmd.ConvertXML(ctx) if err != nil { log.Error(err, "failed to convert xml rules") return err @@ -240,7 +244,7 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command { // in this case we need to run only the analyzer to use builtin provider if len(foundProviders) == 0 { analyzeCmd.needsBuiltin = true - return analyzeCmd.RunAnalysis(cmd.Context(), xmlOutputDir, analyzeCmd.input) + return analyzeCmd.RunAnalysis(ctx, xmlOutputDir, analyzeCmd.input) } err = analyzeCmd.setProviderInitInfo(foundProviders) @@ -251,7 +255,8 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command { // defer cleaning created resources here instead of PostRun // if Run returns an error, PostRun does not run defer func() { - if err := analyzeCmd.CleanAnalysisResources(cmd.Context()); err != nil { + // start other context here to cleanup in case of program interrupt + if err := analyzeCmd.CleanAnalysisResources(context.TODO()); err != nil { log.Error(err, "failed to clean temporary directories") } }() @@ -267,18 +272,18 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command { return err } // allow for 5 retries of running provider in the case of port in use - err = analyzeCmd.RunProviders(cmd.Context(), containerNetworkName, containerVolName, 5) + err = analyzeCmd.RunProviders(ctx, containerNetworkName, containerVolName, 5) if err != nil { log.Error(err, "failed to run provider") return err } - err = analyzeCmd.RunAnalysis(cmd.Context(), xmlOutputDir, containerVolName) + err = analyzeCmd.RunAnalysis(ctx, xmlOutputDir, containerVolName) if err != nil { log.Error(err, "failed to run analysis") return err } } else { - err := analyzeCmd.RunAnalysisOverrideProviderSettings(cmd.Context()) + err := analyzeCmd.RunAnalysisOverrideProviderSettings(ctx) if err != nil { log.Error(err, "failed to run analysis") return err @@ -290,7 +295,7 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command { return err } - err = analyzeCmd.GenerateStaticReport(cmd.Context()) + err = analyzeCmd.GenerateStaticReport(ctx) if err != nil { log.Error(err, "failed to generate static report") return err @@ -1949,83 +1954,6 @@ func (a *analyzeCommand) mergeProviderSpecificConfig(optionsConf, seenConf map[s return seenConf, nil } -func (a *analyzeCommand) CleanAnalysisResources(ctx context.Context) error { - if !a.cleanup || a.needsBuiltin { - return nil - } - a.log.V(1).Info("removing temp dirs") - for _, path := range a.tempDirs { - err := os.RemoveAll(path) - if err != nil { - a.log.V(1).Error(err, "failed to delete temporary dir", "dir", path) - continue - } - } - err := a.RmProviderContainers(ctx) - if err != nil { - a.log.Error(err, "failed to remove provider container") - } - err = a.RmNetwork(ctx) - if err != nil { - a.log.Error(err, "failed to remove network", "network", a.networkName) - } - err = a.RmVolumes(ctx) - if err != nil { - a.log.Error(err, "failed to remove volume", "volume", a.volumeName) - } - return nil -} - -func (a *analyzeCommand) RmNetwork(ctx context.Context) error { - if a.networkName == "" { - return nil - } - cmd := exec.CommandContext( - ctx, - Settings.ContainerBinary, - "network", - "rm", a.networkName) - a.log.V(1).Info("removing container network", - "network", a.networkName) - return cmd.Run() -} - -func (a *analyzeCommand) RmVolumes(ctx context.Context) error { - if a.volumeName == "" { - return nil - } - cmd := exec.CommandContext( - ctx, - Settings.ContainerBinary, - "volume", - "rm", a.volumeName) - a.log.V(1).Info("removing created volume", - "volume", a.volumeName) - return cmd.Run() -} - -func (a *analyzeCommand) RmProviderContainers(ctx context.Context) error { - // if multiple provider containers, we need to remove the first created provider container last - for i := len(a.providerContainerNames) - 1; i >= 0; i-- { - con := a.providerContainerNames[i] - // because we are using the --rm option when we start the provider container, - // it will immediately be removed after it stops - cmd := exec.CommandContext( - ctx, - Settings.ContainerBinary, - "stop", con) - a.log.V(1).Info("stopping container", "container", con) - err := cmd.Run() - if err != nil { - a.log.V(1).Error(err, "failed to stop container", - "container", con) - continue - } - } - - return nil -} - func (a *analyzeCommand) getProviderLogs(ctx context.Context) error { if len(a.providerContainerNames) == 0 || a.needsBuiltin { return nil diff --git a/cmd/cleanup.go b/cmd/cleanup.go new file mode 100644 index 0000000..04f448e --- /dev/null +++ b/cmd/cleanup.go @@ -0,0 +1,85 @@ +package cmd + +import ( + "context" + "os" + "os/exec" +) + +func (a *analyzeCommand) CleanAnalysisResources(ctx context.Context) error { + if !a.cleanup || a.needsBuiltin { + return nil + } + a.log.V(1).Info("removing temp dirs") + for _, path := range a.tempDirs { + err := os.RemoveAll(path) + if err != nil { + a.log.V(1).Error(err, "failed to delete temporary dir", "dir", path) + continue + } + } + err := a.RmProviderContainers(ctx) + if err != nil { + a.log.Error(err, "failed to remove provider container") + } + err = a.RmNetwork(ctx) + if err != nil { + a.log.Error(err, "failed to remove network", "network", a.networkName) + } + err = a.RmVolumes(ctx) + if err != nil { + a.log.Error(err, "failed to remove volume", "volume", a.volumeName) + } + return nil +} + +func (a *analyzeCommand) RmNetwork(ctx context.Context) error { + if a.networkName == "" { + return nil + } + a.log.V(1).Info("removing container network", + "network", a.networkName) + cmd := exec.CommandContext( + ctx, + Settings.ContainerBinary, + "network", + "rm", a.networkName) + a.log.V(1).Info("removing container network", + "network", a.networkName) + return cmd.Run() +} + +func (a *analyzeCommand) RmVolumes(ctx context.Context) error { + if a.volumeName == "" { + return nil + } + cmd := exec.CommandContext( + ctx, + Settings.ContainerBinary, + "volume", + "rm", a.volumeName) + a.log.V(1).Info("removing created volume", + "volume", a.volumeName) + return cmd.Run() +} + +func (a *analyzeCommand) RmProviderContainers(ctx context.Context) error { + // if multiple provider containers, we need to remove the first created provider container last + for i := len(a.providerContainerNames) - 1; i >= 0; i-- { + con := a.providerContainerNames[i] + // because we are using the --rm option when we start the provider container, + // it will immediately be removed after it stops + cmd := exec.CommandContext( + ctx, + Settings.ContainerBinary, + "stop", con) + a.log.V(1).Info("stopping provider container", "container", con) + err := cmd.Run() + if err != nil { + a.log.V(1).Error(err, "failed to stop container", + "container", con) + continue + } + } + return nil +}