diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index 7f26c5c..e84e54b 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -26,14 +26,14 @@ jobs: run: | expected_file=./test-data/analysis-output.yaml actual_file=./output/output.yaml - sed 's/^[ \t-]*//' $expected_file | sort > /tmp/expected_file - sed 's/^[ \t-]*//' $actual_file | sort > /tmp/actual_file + sed 's/^[ \t-]*//' $expected_file | sort -s > /tmp/expected_file + sed 's/^[ \t-]*//' $actual_file | sort -s > /tmp/actual_file diff /tmp/expected_file /tmp/actual_file || diff $expected_file $actual_file - name: Fail if dependencies output does not match expected run: | expected_file=./test-data/deps-output.yaml actual_file=./output/dependencies.yaml - sed 's/^[ \t-]*//' $expected_file | sort > /tmp/expected_file - sed 's/^[ \t-]*//' $actual_file | sort > /tmp/actual_file + sed 's/^[ \t-]*//' $expected_file | sort -s > /tmp/expected_file + sed 's/^[ \t-]*//' $actual_file | sort -s > /tmp/actual_file diff /tmp/expected_file /tmp/actual_file || diff $expected_file $actual_file \ No newline at end of file diff --git a/cmd/analyze.go b/cmd/analyze.go index 2cfeac5..3386ecd 100644 --- a/cmd/analyze.go +++ b/cmd/analyze.go @@ -16,7 +16,6 @@ import ( "sort" "strings" - "github.com/apex/log" "github.com/go-logr/logr" "github.com/konveyor/analyzer-lsp/engine" outputv1 "github.com/konveyor/analyzer-lsp/output/v1/konveyor" @@ -82,6 +81,7 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command { } err := analyzeCmd.Validate() if err != nil { + log.Error(err, "failed to validate flags") return err } return nil @@ -90,31 +90,35 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command { if analyzeCmd.listSources || analyzeCmd.listTargets { err := analyzeCmd.ListLabels(cmd.Context()) if err != nil { - log.V(5).Error(err, "failed to list rule labels") + log.Error(err, "failed to list rule labels") return err } return nil } xmlOutputDir, err := analyzeCmd.ConvertXML(cmd.Context()) if err != nil { - log.V(5).Error(err, "failed to convert XML rules") + log.Error(err, "failed to convert xml rules") return err } err = analyzeCmd.RunAnalysis(cmd.Context(), xmlOutputDir) if err != nil { - log.V(5).Error(err, "failed to execute analysis") + log.Error(err, "failed to run analysis") return err } err = analyzeCmd.GenerateStaticReport(cmd.Context()) if err != nil { - log.V(5).Error(err, "failed to generate static report") + log.Error(err, "failed to generate static report") return err } return nil }, PostRunE: func(cmd *cobra.Command, args []string) error { + if cmd.PersistentFlags().Changed(noCleanupFlag) { + return nil + } err := analyzeCmd.Clean(cmd.Context()) if err != nil { + log.Error(err, "failed to generate static report") return err } return nil @@ -143,7 +147,7 @@ func (a *analyzeCommand) Validate() error { if errors.Is(err, os.ErrNotExist) { err = os.MkdirAll(a.output, os.ModePerm) if err != nil { - return fmt.Errorf("failed to create output dir %s", a.output) + return fmt.Errorf("%w failed to create output dir %s", err, a.output) } } else { return fmt.Errorf("failed to stat output directory %s", a.output) @@ -154,14 +158,14 @@ func (a *analyzeCommand) Validate() error { } stat, err = os.Stat(a.input) if err != nil { - return fmt.Errorf("failed to stat input path %s", a.input) + return fmt.Errorf("%w failed to stat input path %s", err, a.input) } // when input isn't a dir, it's pointing to a binary // we need abs path to mount the file correctly if !stat.Mode().IsDir() { a.input, err = filepath.Abs(a.input) if err != nil { - return fmt.Errorf("failed to get absolute path for input file %s", a.input) + return fmt.Errorf("%w failed to get absolute path for input file %s", err, a.input) } // make sure we mount a file and not a dir SourceMountPath = filepath.Join(SourceMountPath, filepath.Base(a.input)) @@ -191,7 +195,7 @@ func (a *analyzeCommand) ListLabels(ctx context.Context) error { if a.listSources { sourceSlice, err := readRuleFilesForLabels(sourceLabel) if err != nil { - a.log.V(5).Error(err, "failed to read rule labels") + a.log.Error(err, "failed to read rule labels") return err } listOptionsFromLabels(sourceSlice, sourceLabel) @@ -200,7 +204,7 @@ func (a *analyzeCommand) ListLabels(ctx context.Context) error { if a.listTargets { targetsSlice, err := readRuleFilesForLabels(targetLabel) if err != nil { - a.log.V(5).Error(err, "failed to read rule labels") + a.log.Error(err, "failed to read rule labels") return err } listOptionsFromLabels(targetsSlice, targetLabel) @@ -209,6 +213,7 @@ func (a *analyzeCommand) ListLabels(ctx context.Context) error { } else { volumes, err := a.getRulesVolumes() if err != nil { + a.log.Error(err, "failed getting rules volumes") return err } args := []string{"analyze"} @@ -217,7 +222,7 @@ func (a *analyzeCommand) ListLabels(ctx context.Context) error { } else { args = append(args, "--list-targets") } - err = NewContainer().Run( + err = NewContainer(a.log).Run( ctx, WithEnv(runMode, runModeContainer), WithVolumes(volumes), @@ -225,6 +230,7 @@ func (a *analyzeCommand) ListLabels(ctx context.Context) error { WithEntrypointArgs(args...), ) if err != nil { + a.log.Error(err, "failed listing labels") return err } } @@ -308,9 +314,10 @@ func listOptionsFromLabels(sl []string, label string) { func (a *analyzeCommand) getConfigVolumes() (map[string]string, error) { tempDir, err := os.MkdirTemp("", "analyze-config-") if err != nil { + a.log.V(1).Error(err, "failed creating temp dir", "dir", tempDir) return nil, err } - a.log.V(5).Info("created directory for provider settings", "dir", tempDir) + a.log.V(1).Info("created directory for provider settings", "dir", tempDir) a.tempDirs = append(a.tempDirs, tempDir) otherProvsMountPath := SourceMountPath @@ -364,10 +371,12 @@ func (a *analyzeCommand) getConfigVolumes() (map[string]string, error) { } jsonData, err := json.MarshalIndent(&provConfig, "", " ") if err != nil { + a.log.V(1).Error(err, "failed to marshal provider config") return nil, err } err = ioutil.WriteFile(filepath.Join(tempDir, "settings.json"), jsonData, os.ModePerm) if err != nil { + a.log.V(1).Error(err, "failed to write provider config", "dir", tempDir, "file", "settings.json") return nil, err } return map[string]string{ @@ -383,14 +392,15 @@ func (a *analyzeCommand) getRulesVolumes() (map[string]string, error) { rulesetNeeded := false tempDir, err := os.MkdirTemp("", "analyze-rules-") if err != nil { + a.log.V(1).Error(err, "failed to create temp dir", "path", tempDir) return nil, err } - a.log.V(5).Info("created directory for rules", "dir", tempDir) + a.log.V(1).Info("created directory for rules", "dir", tempDir) a.tempDirs = append(a.tempDirs, tempDir) for i, r := range a.rules { stat, err := os.Stat(r) if err != nil { - log.Errorf("failed to stat rules %s", r) + a.log.V(1).Error(err, "failed to stat rules", "path", r) return nil, err } // move rules files passed into dir to mount @@ -403,7 +413,7 @@ func (a *analyzeCommand) getRulesVolumes() (map[string]string, error) { destFile := filepath.Join(tempDir, fmt.Sprintf("rules%d.yaml", i)) err := copyFileContents(r, destFile) if err != nil { - log.Errorf("failed to move rules file from %s to %s", r, destFile) + a.log.V(1).Error(err, "failed to move rules file", "src", r, "dest", destFile) return nil, err } @@ -412,9 +422,10 @@ func (a *analyzeCommand) getRulesVolumes() (map[string]string, error) { } } if rulesetNeeded { - err = createTempRuleSet(filepath.Join(tempDir, "ruleset.yaml")) + tempRulesetPath := filepath.Join(tempDir, "ruleset.yaml") + err = createTempRuleSet(tempRulesetPath) if err != nil { - log.Error("failed to create ruleset for custom rules") + a.log.V(1).Error(err, "failed to create temp ruleset", "path", tempRulesetPath) return nil, err } rulesVolumes[tempDir] = filepath.Join(RulesMountPath, filepath.Base(tempDir)) @@ -473,7 +484,7 @@ func (a *analyzeCommand) RunAnalysis(ctx context.Context, xmlOutputDir string) e configVols, err := a.getConfigVolumes() if err != nil { - a.log.V(5).Error(err, "failed to get config volumes for analysis") + a.log.V(1).Error(err, "failed to get config volumes for analysis") return err } maps.Copy(volumes, configVols) @@ -481,7 +492,7 @@ func (a *analyzeCommand) RunAnalysis(ctx context.Context, xmlOutputDir string) e if len(a.rules) > 0 { ruleVols, err := a.getRulesVolumes() if err != nil { - a.log.V(5).Error(err, "failed to get rule volumes for analysis") + a.log.V(1).Error(err, "failed to get rule volumes for analysis") return err } maps.Copy(volumes, ruleVols) @@ -491,6 +502,7 @@ func (a *analyzeCommand) RunAnalysis(ctx context.Context, xmlOutputDir string) e fmt.Sprintf("--provider-settings=%s", ProviderSettingsMountPath), fmt.Sprintf("--rules=%s/", RulesetPath), fmt.Sprintf("--output-file=%s", AnalysisOutputMountPath), + fmt.Sprintf("--context-lines=%d", 100), } if !a.analyzeKnownLibraries { args = append(args, @@ -518,7 +530,7 @@ func (a *analyzeCommand) RunAnalysis(ctx context.Context, xmlOutputDir string) e a.log.Info("running source code analysis", "log", analysisLogFilePath, "input", a.input, "output", a.output, "args", strings.Join(args, " "), "volumes", volumes) // TODO (pgaikwad): run analysis & deps in parallel - err = NewContainer().Run( + err = NewContainer(a.log).Run( ctx, WithVolumes(volumes), WithStdout(os.Stdout, analysisLog), @@ -532,7 +544,7 @@ func (a *analyzeCommand) RunAnalysis(ctx context.Context, xmlOutputDir string) e a.log.Info("running dependency analysis", "log", depsLogFilePath, "input", a.input, "output", a.output, "args", strings.Join(args, " ")) - err = NewContainer().Run( + err = NewContainer(a.log).Run( ctx, WithStdout(os.Stdout, dependencyLog), WithStderr(os.Stderr, dependencyLog), @@ -569,7 +581,7 @@ func (a *analyzeCommand) GenerateStaticReport(ctx context.Context) error { a.log.Info("generating static report", "output", a.output, "args", strings.Join(args, " ")) - container := NewContainer() + container := NewContainer(a.log) err := container.Run( ctx, WithEntrypointBin("/usr/local/bin/js-bundle-generator"), @@ -599,7 +611,7 @@ func (a *analyzeCommand) Clean(ctx context.Context) error { for _, path := range a.tempDirs { err := os.RemoveAll(path) if err != nil { - a.log.V(5).Error(err, "failed to delete temporary dir", "dir", path) + a.log.V(1).Error(err, "failed to delete temporary dir", "dir", path) continue } } @@ -665,7 +677,7 @@ func (a *analyzeCommand) getXMLRulesVolumes(tempRuleDir string) (map[string]stri for _, r := range a.rules { stat, err := os.Stat(r) if err != nil { - a.log.V(5).Error(err, "failed to stat rules") + a.log.V(1).Error(err, "failed to stat rules") return nil, err } // move xml rule files from user into dir to mount @@ -678,7 +690,7 @@ func (a *analyzeCommand) getXMLRulesVolumes(tempRuleDir string) (map[string]stri destFile := filepath.Join(tempRuleDir, xmlFileName) err := copyFileContents(r, destFile) if err != nil { - a.log.Error(err, "failed to move rules file from source to destination", "src", r, "dest", destFile) + a.log.V(1).Error(err, "failed to move rules file from source to destination", "src", r, "dest", destFile) return nil, err } } else { @@ -697,16 +709,16 @@ func (a *analyzeCommand) ConvertXML(ctx context.Context) (string, error) { } tempDir, err := os.MkdirTemp("", "transform-rules-") if err != nil { - a.log.V(5).Error(err, "failed to create temp dir for rules") + a.log.V(1).Error(err, "failed to create temp dir for rules") return "", err } - a.log.V(5).Info("created directory for XML rules", "dir", tempDir) + a.log.V(1).Info("created directory for XML rules", "dir", tempDir) tempOutputDir, err := os.MkdirTemp("", "transform-output-") if err != nil { - a.log.V(5).Error(err, "failed to create temp dir for rules") + a.log.V(1).Error(err, "failed to create temp dir for rules") return "", err } - a.log.V(5).Info("created directory for converted XML rules", "dir", tempDir) + a.log.V(1).Info("created directory for converted XML rules", "dir", tempDir) defer os.RemoveAll(tempDir) volumes := map[string]string{ tempOutputDir: ShimOutputPath, @@ -714,16 +726,17 @@ func (a *analyzeCommand) ConvertXML(ctx context.Context) (string, error) { ruleVols, err := a.getXMLRulesVolumes(tempDir) if err != nil { - a.log.V(5).Error(err, "failed to get XML rule volumes for analysis") + a.log.V(1).Error(err, "failed to get XML rule volumes for analysis") return "", err } maps.Copy(volumes, ruleVols) + a.log.Info("running windup shim", "output", a.output) args := []string{"convert", fmt.Sprintf("--outputdir=%v", ShimOutputPath), XMLRulePath, } - err = NewContainer().Run( + err = NewContainer(a.log).Run( ctx, WithVolumes(volumes), WithEntrypointArgs(args...), diff --git a/cmd/container.go b/cmd/container.go index f73322b..0e2ead8 100644 --- a/cmd/container.go +++ b/cmd/container.go @@ -12,6 +12,8 @@ import ( "runtime" "strings" "time" + + "github.com/go-logr/logr" ) type container struct { @@ -27,6 +29,7 @@ type container struct { cleanup bool // map of source -> dest paths to mount volumes map[string]string + log logr.Logger } type Option func(c *container) @@ -101,7 +104,7 @@ func randomName() string { return string(b) } -func NewContainer() *container { +func NewContainer(log logr.Logger) *container { return &container{ image: Settings.RunnerImage, entrypointArgs: []string{}, @@ -112,6 +115,7 @@ func NewContainer() *container { name: randomName(), // by default, remove the container after run() cleanup: true, + log: log, } } @@ -121,7 +125,7 @@ func (c *container) Exists(ctx context.Context) (bool, error) { "ps", "-a", "--format", "{{.Names}}") output, err := cmd.CombinedOutput() if err != nil { - return false, fmt.Errorf("failed checking status of container %s", c.name) + return false, fmt.Errorf("%w failed checking status of container %s", err, c.name) } for _, found := range strings.Split(string(output), "\n") { if found == c.name { @@ -138,20 +142,16 @@ func (c *container) Run(ctx context.Context, opts ...Option) error { } exists, err := c.Exists(ctx) if err != nil { - return fmt.Errorf("failed to check status of container %s", c.name) + return fmt.Errorf("%w failed to check status of container %s", err, c.name) } if exists { return fmt.Errorf("container %s already exists, must remove existing before running", c.name) } - if c.cleanup { - defer func() { - if rmErr := c.Rm(ctx); rmErr != nil { - err = rmErr - } - }() - } args := []string{"run"} os := runtime.GOOS + if c.cleanup { + args = append(args, "--rm") + } if c.name != "" { args = append(args, "--name") args = append(args, c.name) @@ -194,8 +194,11 @@ func (c *container) Run(ctx context.Context, opts ...Option) error { cmd.Stderr = io.MultiWriter( append(c.stderr, errBytes)...) } + c.log.V(1).Info("executing podman command", + "podman", Settings.PodmanBinary, "cmd", c.entrypointBin, "args", strings.Join(args, " ")) err = cmd.Run() if err != nil { + c.log.V(1).Error(err, "container run error") if _, ok := err.(*exec.ExitError); ok { return fmt.Errorf(errBytes.String()) } @@ -210,7 +213,7 @@ func (c *container) Cp(ctx context.Context, src string, dest string) error { } exists, err := c.Exists(ctx) if err != nil { - return fmt.Errorf("failed to check status of container %s", c.name) + return err } if !exists { return fmt.Errorf("container %s does not exist, cannot copy from non-existing container", c.name) @@ -219,13 +222,15 @@ func (c *container) Cp(ctx context.Context, src string, dest string) error { ctx, Settings.PodmanBinary, "cp", fmt.Sprintf("%s:%s", c.name, src), dest) + c.log.V(1).Info("copying files from container", + "podman", Settings.PodmanBinary, "src", src, "dest", dest) return cmd.Run() } func (c *container) Rm(ctx context.Context) error { exists, err := c.Exists(ctx) if err != nil { - return fmt.Errorf("failed to check status of container %s", c.name) + return err } if !exists { return nil @@ -234,5 +239,7 @@ func (c *container) Rm(ctx context.Context) error { ctx, Settings.PodmanBinary, "rm", c.name) + c.log.V(1).Info("removing container", + "podman", Settings.PodmanBinary, "name", c.name) return cmd.Run() } diff --git a/cmd/openrewrite.go b/cmd/openrewrite.go index babdd7c..633affa 100644 --- a/cmd/openrewrite.go +++ b/cmd/openrewrite.go @@ -38,12 +38,12 @@ func NewOpenRewriteCommand(log logr.Logger) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { err := openRewriteCmd.Validate() if err != nil { - log.V(5).Error(err, "failed validating input args") + log.Error(err, "failed validating input args") return err } err = openRewriteCmd.Run(cmd.Context()) if err != nil { - log.V(5).Error(err, "failed executing openrewrite recipe") + log.Error(err, "failed executing openrewrite recipe") return err } return nil @@ -63,7 +63,7 @@ func (o *openRewriteCommand) Validate() error { } stat, err := os.Stat(o.input) if err != nil { - return fmt.Errorf("failed to stat input directory %s", o.input) + return fmt.Errorf("%w failed to stat input directory %s", err, o.input) } if !stat.IsDir() { return fmt.Errorf("input path %s is not a directory", o.input) @@ -138,7 +138,7 @@ func (o *openRewriteCommand) Run(ctx context.Context) error { } o.log.Info("executing openrewrite recipe", "recipe", o.target, "input", o.input, "args", strings.Join(args, " ")) - err := NewContainer().Run( + err := NewContainer(o.log).Run( ctx, WithEntrypointArgs(args...), WithEntrypointBin("/usr/bin/mvn"), @@ -146,6 +146,7 @@ func (o *openRewriteCommand) Run(ctx context.Context) error { WithWorkDir(InputPath), ) if err != nil { + o.log.V(1).Error(err, "error running openrewrite") return err } return nil diff --git a/cmd/root.go b/cmd/root.go index c222cfe..03ffd37 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -13,27 +13,39 @@ import ( "github.com/spf13/cobra" ) +const ( + noCleanupFlag = "no-cleanup" +) + +var logLevel uint32 +var logrusLog *logrus.Logger +var noCleanup bool + // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ // TODO: better descriptions Short: "A cli tool for analysis and transformation of applications", Long: ``, SilenceUsage: true, + PersistentPreRun: func(cmd *cobra.Command, args []string) { + // TODO (pgaikwad): this is a hack to set log level + // this won't work if any subcommand ovverrides this func + _ = cmd.ParseFlags(args) + logrusLog.SetLevel(logrus.Level(logLevel)) + }, } -var logLevel int - func init() { - rootCmd.PersistentFlags().IntVar(&logLevel, "log-level", 5, "log level") + rootCmd.PersistentFlags().Uint32Var(&logLevel, "log-level", 4, "log level") + rootCmd.PersistentFlags().BoolVar(&noCleanup, noCleanupFlag, false, "do not cleanup temporary resources") - logrusLog := logrus.New() + logrusLog = logrus.New() logrusLog.SetOutput(os.Stdout) logrusLog.SetFormatter(&logrus.TextFormatter{}) - logrusLog.SetLevel(logrus.InfoLevel) - log := logrusr.New(logrusLog) - rootCmd.AddCommand(NewTransformCommand(log)) - rootCmd.AddCommand(NewAnalyzeCmd(log)) + logger := logrusr.New(logrusLog) + rootCmd.AddCommand(NewTransformCommand(logger)) + rootCmd.AddCommand(NewAnalyzeCmd(logger)) } // Execute adds all child commands to the root command and sets flags appropriately. @@ -41,7 +53,8 @@ func init() { func Execute() { err := Settings.Load() if err != nil { - log.Fatal("failed to load global settings") + log.Fatal(err, "failed to load global settings") + os.Exit(1) } ctx, cancelFunc := context.WithCancel(context.Background()) diff --git a/cmd/settings.go b/cmd/settings.go index 09d332d..379cde0 100644 --- a/cmd/settings.go +++ b/cmd/settings.go @@ -26,10 +26,10 @@ type Config struct { func (c *Config) Load() error { podmanPath, _ := exec.LookPath("podman") - if podmanPath != Settings.PodmanBinary && (podmanPath != "" || len(podmanPath) > 0) { + if podmanPath != c.PodmanBinary && (podmanPath != "" || len(podmanPath) > 0) { os.Setenv("PODMAN_BIN", podmanPath) } - err := env.Set(Settings) + err := env.Set(c) if err != nil { return err } diff --git a/cmd/shimconvert.go b/cmd/shimconvert.go index f2c0c1c..a54333e 100644 --- a/cmd/shimconvert.go +++ b/cmd/shimconvert.go @@ -8,7 +8,6 @@ import ( "path/filepath" "strings" - "github.com/apex/log" "github.com/go-logr/logr" "github.com/spf13/cobra" "golang.org/x/exp/maps" @@ -39,6 +38,7 @@ func NewWindupShimCommand(log logr.Logger) *cobra.Command { err := windupShimCmd.Validate() if err != nil { + log.Error(err, "failed to validate flags") return err } return nil @@ -46,6 +46,7 @@ func NewWindupShimCommand(log logr.Logger) *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { err := windupShimCmd.Run(cmd.Context()) if err != nil { + log.Error(err, "failed to execute windup shim") return err } return nil @@ -63,15 +64,14 @@ func (w *windupShimCommand) Validate() error { if errors.Is(err, os.ErrNotExist) { err = os.MkdirAll(w.output, os.ModePerm) if err != nil { - return fmt.Errorf("failed to create output dir %s", w.output) + return fmt.Errorf("%w failed to create output dir %s", err, w.output) } } else { return fmt.Errorf("failed to stat output directory %s", w.output) } } if outputStat != nil && !outputStat.IsDir() { - log.Errorf("output path %s is not a directory", w.output) - return err + return fmt.Errorf("output path %s is not a directory", w.output) } if w.input == nil || len(w.input) == 0 { return fmt.Errorf("input for rule file or directory must not be empty") @@ -94,7 +94,7 @@ func (w *windupShimCommand) getRulesVolumes(tempRuleDir string) (map[string]stri for _, r := range w.input { stat, err := os.Stat(r) if err != nil { - w.log.V(5).Error(err, "failed to stat rules") + w.log.V(1).Error(err, "failed to stat rules") return nil, err } // move xml rule files from user into dir to mount @@ -104,7 +104,7 @@ func (w *windupShimCommand) getRulesVolumes(tempRuleDir string) (map[string]stri destFile := filepath.Join(tempRuleDir, xmlFileName) err := copyFileContents(r, destFile) if err != nil { - w.log.Error(err, "failed to move rules file from source to destination", "src", r, "dest", destFile) + w.log.V(1).Error(err, "failed to move rules file from source to destination", "src", r, "dest", destFile) return nil, err } } else { @@ -120,7 +120,7 @@ func (w *windupShimCommand) getRulesVolumes(tempRuleDir string) (map[string]stri func (w *windupShimCommand) Run(ctx context.Context) error { tempDir, err := os.MkdirTemp("", "transform-rules-") if err != nil { - w.log.V(5).Error(err, "failed to create temp dir for rules") + w.log.V(1).Error(err, "failed to create temp dir for rules") return err } defer os.RemoveAll(tempDir) @@ -129,7 +129,7 @@ func (w *windupShimCommand) Run(ctx context.Context) error { } ruleVols, err := w.getRulesVolumes(tempDir) if err != nil { - w.log.V(5).Error(err, "failed to get xml rules for conversion") + w.log.V(1).Error(err, "failed to get xml rules for conversion") return err } maps.Copy(volumes, ruleVols) @@ -140,13 +140,14 @@ func (w *windupShimCommand) Run(ctx context.Context) error { } w.log.Info("running windup-shim convert command", "args", strings.Join(args, " "), "volumes", volumes, "output", w.output, "inputs", strings.Join(w.input, ",")) - err = NewContainer().Run( + err = NewContainer(w.log).Run( ctx, WithVolumes(volumes), WithEntrypointArgs(args...), WithEntrypointBin("/usr/local/bin/windup-shim"), ) if err != nil { + w.log.V(1).Error(err, "failed to run convert command") return err } return nil diff --git a/cmd/transform.go b/cmd/transform.go index 5973ee3..2a22cd0 100644 --- a/cmd/transform.go +++ b/cmd/transform.go @@ -7,12 +7,8 @@ import ( func NewTransformCommand(log logr.Logger) *cobra.Command { cmd := &cobra.Command{ - Use: "transform", - + Use: "transform", Short: "Transform application source code or windup XML rules", - PreRunE: func(cmd *cobra.Command, args []string) error { - return nil - }, Run: func(cmd *cobra.Command, args []string) { cmd.Help() }, diff --git a/test-data/analysis-output.yaml b/test-data/analysis-output.yaml index 5ef740a..c9f0c89 100644 --- a/test-data/analysis-output.yaml +++ b/test-data/analysis-output.yaml @@ -142,24 +142,24 @@ - uri: file:///opt/input/source/target/classes/persistence.properties message: When migrating environments, hard-coded IP addresses may need to be modified or eliminated. codeSnip: |2 - 1 jdbc.driverClassName=oracle.jdbc.driver.OracleDriver - 2 jdbc.url=jdbc:oracle:thin:@169.60.225.216:1521/XEPDB1 - 3 jdbc.user=customers - 4 jdbc.password=customers - 5 hibernate.hbm2ddl.auto=create-drop - 6 hibernate.dialect=org.hibernate.dialect.OracleDialect + 1 jdbc.driverClassName=oracle.jdbc.driver.OracleDriver + 2 jdbc.url=jdbc:oracle:thin:@169.60.225.216:1521/XEPDB1 + 3 jdbc.user=customers + 4 jdbc.password=customers + 5 hibernate.hbm2ddl.auto=create-drop + 6 hibernate.dialect=org.hibernate.dialect.OracleDialect lineNumber: 2 variables: matchingText: 169.60.225.216 - uri: file:///opt/input/source/src/main/resources/persistence.properties message: When migrating environments, hard-coded IP addresses may need to be modified or eliminated. codeSnip: |2 - 1 jdbc.driverClassName=oracle.jdbc.driver.OracleDriver - 2 jdbc.url=jdbc:oracle:thin:@169.60.225.216:1521/XEPDB1 - 3 jdbc.user=customers - 4 jdbc.password=customers - 5 hibernate.hbm2ddl.auto=create-drop - 6 hibernate.dialect=org.hibernate.dialect.OracleDialect + 1 jdbc.driverClassName=oracle.jdbc.driver.OracleDriver + 2 jdbc.url=jdbc:oracle:thin:@169.60.225.216:1521/XEPDB1 + 3 jdbc.user=customers + 4 jdbc.password=customers + 5 hibernate.hbm2ddl.auto=create-drop + 6 hibernate.dialect=org.hibernate.dialect.OracleDialect lineNumber: 2 variables: matchingText: 169.60.225.216 @@ -1433,8 +1433,8 @@ description: This ruleset detects the Java Mail API, which may be problematic when migrating an application to a cloud environment. tags: - Java Remote Method Invocation (RMI) service - - Java Remote Method Invocation (RMI) API - rmi + - Java Remote Method Invocation (RMI) API violations: jni-native-code-00000: description: |- @@ -1448,7 +1448,7 @@ incidents: - uri: konveyor-jdt://contents/root/.m2/repository/io/konveyor/demo/config-utils/1.0.0/config-utils-1.0.0.jar?packageName=io.konveyor.demo.config.ApplicationConfiguration.class&source-range=true message: Java native libraries might not run in a cloud or container environment.. Recommendations. * Review the purpose of the native library in your application.. * Check whether the native library is compatible with a cloud environment.. * Reuse or embed the native library or application in a cloud environment, for example, in a JBoss module.. * Replace, remove, or rewrite the native library or application using a cloud-compatible equivalent. - codeSnip: " 3 import java.io.FileInputStream;\n 4 import java.io.InputStream;\n 5 import java.util.Properties;\n 6 \n 7 public class ApplicationConfiguration {\n 8 \n 9 \tprivate Properties config;\n10 \n11 \tpublic ApplicationConfiguration() {\n12 \t\tsuper();\n13 \t\tthis.config = loadProperties();\n14 \n15 \t}\n16 \n17 \tprivate Properties loadProperties() {\n18 \t\tProperties properties = new Properties();\n19 \n20 \t\ttry (InputStream inputStream = new FileInputStream(\"/opt/config/persistence.properties\")) {\n21 \n22 \t\t\tproperties.load(inputStream);\n23 " + codeSnip: " 1 package io.konveyor.demo.config;\n 2 \n 3 import java.io.FileInputStream;\n 4 import java.io.InputStream;\n 5 import java.util.Properties;\n 6 \n 7 public class ApplicationConfiguration {\n 8 \n 9 \tprivate Properties config;\n 10 \n 11 \tpublic ApplicationConfiguration() {\n 12 \t\tsuper();\n 13 \t\tthis.config = loadProperties();\n 14 \n 15 \t}\n 16 \n 17 \tprivate Properties loadProperties() {\n 18 \t\tProperties properties = new Properties();\n 19 \n 20 \t\ttry (InputStream inputStream = new FileInputStream(\"/opt/config/persistence.properties\")) {\n 21 \n 22 \t\t\tproperties.load(inputStream);\n 23 \n 24 \t\t} catch (Exception e) {\n 25 \t\t\tSystem.out.println(\"Exception: \" + e);\n 26 \t\t}\n 27 \n 28 \t\treturn properties;\n 29 \t}\n 30 \n 31 \tpublic String getProperty (String name) {\n 32 \t\treturn config.getProperty(name);\n 33 \t}\n 34 \n 35 \n 36 \n 37 }\n" lineNumber: 12 variables: file: konveyor-jdt://contents/root/.m2/repository/io/konveyor/demo/config-utils/1.0.0/config-utils-1.0.0.jar?packageName=io.konveyor.demo.config.ApplicationConfiguration.class&source-range=true @@ -1456,7 +1456,7 @@ name: ApplicationConfiguration - uri: konveyor-jdt://contents/root/.m2/repository/io/konveyor/demo/config-utils/1.0.0/config-utils-1.0.0.jar?packageName=io.konveyor.demo.config.ApplicationConfiguration.class&source-range=true message: Java native libraries might not run in a cloud or container environment.. Recommendations. * Review the purpose of the native library in your application.. * Check whether the native library is compatible with a cloud environment.. * Reuse or embed the native library or application in a cloud environment, for example, in a JBoss module.. * Replace, remove, or rewrite the native library or application using a cloud-compatible equivalent. - codeSnip: "12 \t\tsuper();\n13 \t\tthis.config = loadProperties();\n14 \n15 \t}\n16 \n17 \tprivate Properties loadProperties() {\n18 \t\tProperties properties = new Properties();\n19 \n20 \t\ttry (InputStream inputStream = new FileInputStream(\"/opt/config/persistence.properties\")) {\n21 \n22 \t\t\tproperties.load(inputStream);\n23 \n24 \t\t} catch (Exception e) {\n25 \t\t\tSystem.out.println(\"Exception: \" + e);\n26 \t\t}\n27 \n28 \t\treturn properties;\n29 \t}\n30 \n31 \tpublic String getProperty (String name) {\n32 \t\treturn config.getProperty(name);" + codeSnip: " 1 package io.konveyor.demo.config;\n 2 \n 3 import java.io.FileInputStream;\n 4 import java.io.InputStream;\n 5 import java.util.Properties;\n 6 \n 7 public class ApplicationConfiguration {\n 8 \n 9 \tprivate Properties config;\n 10 \n 11 \tpublic ApplicationConfiguration() {\n 12 \t\tsuper();\n 13 \t\tthis.config = loadProperties();\n 14 \n 15 \t}\n 16 \n 17 \tprivate Properties loadProperties() {\n 18 \t\tProperties properties = new Properties();\n 19 \n 20 \t\ttry (InputStream inputStream = new FileInputStream(\"/opt/config/persistence.properties\")) {\n 21 \n 22 \t\t\tproperties.load(inputStream);\n 23 \n 24 \t\t} catch (Exception e) {\n 25 \t\t\tSystem.out.println(\"Exception: \" + e);\n 26 \t\t}\n 27 \n 28 \t\treturn properties;\n 29 \t}\n 30 \n 31 \tpublic String getProperty (String name) {\n 32 \t\treturn config.getProperty(name);\n 33 \t}\n 34 \n 35 \n 36 \n 37 }\n" lineNumber: 21 variables: file: konveyor-jdt://contents/root/.m2/repository/io/konveyor/demo/config-utils/1.0.0/config-utils-1.0.0.jar?packageName=io.konveyor.demo.config.ApplicationConfiguration.class&source-range=true @@ -1481,7 +1481,7 @@ incidents: - uri: konveyor-jdt://contents/root/.m2/repository/io/konveyor/demo/config-utils/1.0.0/config-utils-1.0.0.jar?packageName=io.konveyor.demo.config.ApplicationConfiguration.class&source-range=true message: 'An application running inside a container could lose access to a file in local storage.. Recommendations. The following recommendations depend on the function of the file in local storage:. * Logging: Log to standard output and use a centralized log collector to analyze the logs.. * Caching: Use a cache backing service.. * Configuration: Store configuration settings in environment variables so that they can be updated without code changes.. * Data storage: Use a database backing service for relational data or use a persistent data storage system.. * Temporary data storage: Use the file system of a running container as a brief, single-transaction cache.' - codeSnip: "10 \n11 \tpublic ApplicationConfiguration() {\n12 \t\tsuper();\n13 \t\tthis.config = loadProperties();\n14 \n15 \t}\n16 \n17 \tprivate Properties loadProperties() {\n18 \t\tProperties properties = new Properties();\n19 \n20 \t\ttry (InputStream inputStream = new FileInputStream(\"/opt/config/persistence.properties\")) {\n21 \n22 \t\t\tproperties.load(inputStream);\n23 \n24 \t\t} catch (Exception e) {\n25 \t\t\tSystem.out.println(\"Exception: \" + e);\n26 \t\t}\n27 \n28 \t\treturn properties;\n29 \t}\n30 " + codeSnip: " 1 package io.konveyor.demo.config;\n 2 \n 3 import java.io.FileInputStream;\n 4 import java.io.InputStream;\n 5 import java.util.Properties;\n 6 \n 7 public class ApplicationConfiguration {\n 8 \n 9 \tprivate Properties config;\n 10 \n 11 \tpublic ApplicationConfiguration() {\n 12 \t\tsuper();\n 13 \t\tthis.config = loadProperties();\n 14 \n 15 \t}\n 16 \n 17 \tprivate Properties loadProperties() {\n 18 \t\tProperties properties = new Properties();\n 19 \n 20 \t\ttry (InputStream inputStream = new FileInputStream(\"/opt/config/persistence.properties\")) {\n 21 \n 22 \t\t\tproperties.load(inputStream);\n 23 \n 24 \t\t} catch (Exception e) {\n 25 \t\t\tSystem.out.println(\"Exception: \" + e);\n 26 \t\t}\n 27 \n 28 \t\treturn properties;\n 29 \t}\n 30 \n 31 \tpublic String getProperty (String name) {\n 32 \t\treturn config.getProperty(name);\n 33 \t}\n 34 \n 35 \n 36 \n 37 }\n" lineNumber: 19 variables: file: konveyor-jdt://contents/root/.m2/repository/io/konveyor/demo/config-utils/1.0.0/config-utils-1.0.0.jar?packageName=io.konveyor.demo.config.ApplicationConfiguration.class&source-range=true @@ -1521,8 +1521,8 @@ - logging-0000 - logging-0001 - jca-00000 - - local-storage-00004 - local-storage-00003 + - local-storage-00004 - session-00000 - java-rmi-00000 - logging-0001 @@ -1531,8 +1531,8 @@ - socket-communication-00001 - mail-00000 - session-00001 - - local-storage-00005 - local-storage-00002 + - local-storage-00005 - socket-communication-00000 - name: os/windows description: This is a ruleset for Windows operating system specific rules while migrating to Linux operating system.