Skip to content

Commit

Permalink
merge provider config options with default config options
Browse files Browse the repository at this point in the history
Signed-off-by: Emily McMullan <[email protected]>
  • Loading branch information
eemcmullan committed May 30, 2024
1 parent 52f87d7 commit 4c3ba6f
Show file tree
Hide file tree
Showing 5 changed files with 184 additions and 36 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ See different ways to run the test command in the [test runner doc](./docs/testr
## References

- [Example usage scenarios](./docs/examples.md)
- [Using provider options](./docs/usage.md)
- [Test runner for YAML rules](./docs/testrunner.md)

## Code of Conduct
Expand Down
165 changes: 130 additions & 35 deletions cmd/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@ const (
nodeJSProvider = "javascript"
)

// provider config options
const (
mavenSettingsFile = "mavenSettingsFile"
lspServerPath = "lspServerPath"
lspServerName = "lspServerName"
workspaceFolders = "workspaceFolders"
dependencyProviderPath = "dependencyProviderPath"
)

// kantra analyze flags
type analyzeCommand struct {
listSources bool
Expand All @@ -74,9 +83,6 @@ type analyzeCommand struct {
rules []string
jaegerEndpoint string
enableDefaultRulesets bool
httpProxy string
httpsProxy string
noProxy string
contextLines int
incidentSelector string
depFolders []string
Expand Down Expand Up @@ -216,9 +222,6 @@ func NewAnalyzeCmd(log logr.Logger) *cobra.Command {
analyzeCommand.Flags().BoolVar(&analyzeCmd.overwrite, "overwrite", false, "overwrite output directory")
analyzeCommand.Flags().StringVar(&analyzeCmd.jaegerEndpoint, "jaeger-endpoint", "", "jaeger endpoint to collect traces")
analyzeCommand.Flags().BoolVar(&analyzeCmd.enableDefaultRulesets, "enable-default-rulesets", true, "run default rulesets with analysis")
analyzeCommand.Flags().StringVar(&analyzeCmd.httpProxy, "http-proxy", loadEnvInsensitive("http_proxy"), "HTTP proxy string URL")
analyzeCommand.Flags().StringVar(&analyzeCmd.httpsProxy, "https-proxy", loadEnvInsensitive("https_proxy"), "HTTPS proxy string URL")
analyzeCommand.Flags().StringVar(&analyzeCmd.noProxy, "no-proxy", loadEnvInsensitive("no_proxy"), "proxy excluded URLs (relevant only with proxy)")
analyzeCommand.Flags().IntVar(&analyzeCmd.contextLines, "context-lines", 100, "number of lines of source code to include in the output for each incident")
analyzeCommand.Flags().StringVar(&analyzeCmd.incidentSelector, "incident-selector", "", "an expression to select incidents based on custom variables. ex: (!package=io.konveyor.demo.config-utils)")
analyzeCommand.Flags().StringArrayVarP(&analyzeCmd.depFolders, "dependency-folders", "d", []string{}, "directory for dependencies")
Expand Down Expand Up @@ -363,7 +366,7 @@ func (a *analyzeCommand) CheckOverwriteOutput() error {
return nil
}

func (a *analyzeCommand) ListLabels(ctx context.Context) error {
func (a *analyzeCommand) ListLabels(ctx context.Context) error {
return a.fetchLabels(ctx, a.listSources, a.listTargets, os.Stdout)
}

Expand Down Expand Up @@ -544,8 +547,6 @@ func (a *analyzeCommand) getConfigVolumes(providers []string, ports map[string]i
default:
return nil, fmt.Errorf("unable to find config for provider %v", providers[0])
}

// TODO (pgaikwad): binaries don't work with alizer right now, we need to revisit this
if !foundJava && a.isFileInput {
foundJava = true
}
Expand Down Expand Up @@ -574,6 +575,7 @@ func (a *analyzeCommand) getConfigVolumes(providers []string, ports map[string]i
},
},
}

if a.mavenSettingsFile != "" {
err := copyFileContents(a.mavenSettingsFile, filepath.Join(tempDir, "settings.xml"))
if err != nil {
Expand All @@ -582,9 +584,6 @@ func (a *analyzeCommand) getConfigVolumes(providers []string, ports map[string]i
}
javaConfig.InitConfig[0].ProviderSpecificConfig["mavenSettingsFile"] = fmt.Sprintf("%s/%s", ConfigMountPath, "settings.xml")
}
if Settings.JvmMaxMem != "" {
javaConfig.InitConfig[0].ProviderSpecificConfig["jvmMaxMem"] = Settings.JvmMaxMem
}

goConfig := provider.Config{
Name: goProvider,
Expand Down Expand Up @@ -653,7 +652,6 @@ func (a *analyzeCommand) getConfigVolumes(providers []string, ports map[string]i
},
},
}

switch {
case foundJava:
provConfig = append(provConfig, javaConfig)
Expand All @@ -665,30 +663,18 @@ func (a *analyzeCommand) getConfigVolumes(providers []string, ports map[string]i
provConfig = append(provConfig, nodeJSConfig)
}

// Set proxy to providers
if a.httpProxy != "" || a.httpsProxy != "" {
proxy := provider.Proxy{
HTTPProxy: a.httpProxy,
HTTPSProxy: a.httpsProxy,
NoProxy: a.noProxy,
}
for i := range provConfig {
provConfig[i].Proxy = &proxy
}
}

jsonData, err := json.MarshalIndent(&provConfig, "", " ")
err = a.getProviderOptions(tempDir, provConfig)
if err != nil {
a.log.V(1).Error(err, "failed to marshal provider config")
return nil, err
}
err = os.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
if errors.Is(err, os.ErrNotExist) {
a.log.V(5).Info("provider options config not found, using default options")
err := a.writeProvConfig(tempDir, provConfig)
if err != nil {
return nil, err
}
} else {
return nil, err
}
}

settingsVols := map[string]string{
tempDir: ConfigMountPath,
}
Expand Down Expand Up @@ -1366,6 +1352,115 @@ func (a *analyzeCommand) ConvertXML(ctx context.Context) (string, error) {
return tempOutputDir, nil
}

func (a *analyzeCommand) writeProvConfig(tempDir string, config []provider.Config) error {
jsonData, err := json.MarshalIndent(&config, "", " ")
if err != nil {
a.log.V(1).Error(err, "failed to marshal provider config")
return err
}
err = os.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 err
}
return nil
}

func (a *analyzeCommand) getProviderOptions(tempDir string, provConfig []provider.Config) error {
// get provider options from provider settings file
home := os.Getenv("HOME")
data, err := os.ReadFile(filepath.Join(home, ".kantra", "provider_options.json"))
if err != nil {
return err
}
optionsConfig := &[]provider.Config{}
err = yaml.Unmarshal(data, optionsConfig)
if err != nil {
a.log.V(1).Error(err, "failed to unmarshal provider options file")
return err
}
mergedConfig, err := a.mergeProviderConfig(provConfig, *optionsConfig, tempDir)
if err != nil {
return err
}
err = a.writeProvConfig(tempDir, mergedConfig)
if err != nil {
return err
}
return nil
}

func (a *analyzeCommand) mergeProviderConfig(defaultConf, optionsConf []provider.Config, tempDir string) ([]provider.Config, error) {
merged := []provider.Config{}
seen := map[string]*provider.Config{}

// find options used for supported providers
for idx, conf := range defaultConf {
seen[conf.Name] = &defaultConf[idx]
}

for _, conf := range optionsConf {
if _, ok := seen[conf.Name]; ok {
// set provider config options
if conf.ContextLines != 0 {
seen[conf.Name].ContextLines = conf.ContextLines
}
if conf.Proxy != nil {
seen[conf.Name].Proxy = conf.Proxy
}
// set init config options
for i, init := range conf.InitConfig {
if len(init.AnalysisMode) != 0 {
seen[conf.Name].InitConfig[i].AnalysisMode = init.AnalysisMode
}
if len(init.ProviderSpecificConfig) != 0 {
provSpecificConf, err := a.mergeProviderSpecificConfig(init.ProviderSpecificConfig, seen[conf.Name].InitConfig[i].ProviderSpecificConfig, tempDir)
if err != nil {
return nil, err
}
seen[conf.Name].InitConfig[i].ProviderSpecificConfig = provSpecificConf
}
}
}
}
for _, v := range seen {
merged = append(merged, *v)
}
return merged, nil
}

func (a *analyzeCommand) mergeProviderSpecificConfig(optionsConf, seenConf map[string]interface{}, tempDir string) (map[string]interface{}, error) {
for k, v := range optionsConf {
switch {
case optionsConf[k] == "":
continue
// special case for maven settings file to mount correctly
case k == mavenSettingsFile:
// validate maven settings file
if _, err := os.Stat(v.(string)); err != nil {
return nil, fmt.Errorf("%w failed to stat maven settings file at path %s", err, v)
}
if absPath, err := filepath.Abs(v.(string)); err == nil {
seenConf[k] = absPath
}
// copy file to mount path
err := copyFileContents(v.(string), filepath.Join(tempDir, "settings.xml"))
if err != nil {
a.log.V(1).Error(err, "failed copying maven settings file", "path", v)
return nil, err
}
seenConf[k] = fmt.Sprintf("%s/%s", ConfigMountPath, "settings.xml")
continue
// we don't want users to override these options here
// use --overrideProviderSettings to do so
case k != lspServerPath && k != lspServerName && k != workspaceFolders && k != dependencyProviderPath:
seenConf[k] = v
}
}
return seenConf, nil
}

func (a *analyzeCommand) CleanAnalysisResources(ctx context.Context) error {
if !a.cleanup {
return nil
Expand Down
1 change: 0 additions & 1 deletion cmd/settings.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ type Config struct {
RootCommandName string `env:"CMD_NAME" default:"kantra"`
PodmanBinary string `env:"PODMAN_BIN" default:"/usr/bin/podman"`
RunnerImage string `env:"RUNNER_IMG" default:"quay.io/konveyor/kantra"`
JvmMaxMem string `env:"JVM_MAX_MEM" default:""`
RunLocal bool `env:"RUN_LOCAL"`
JavaProviderImage string `env:"JAVA_PROVIDER_IMG" default:"quay.io/konveyor/java-external-provider:latest"`
GenericProviderImage string `env:"GENERIC_PROVIDER_IMG" default:"quay.io/konveyor/generic-external-provider:latest"`
Expand Down
9 changes: 9 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,12 @@
label, the given rule will not match.
- You must add the target label to the custom rule and specify the `--target`
in order to run this rule.


## Provider Options

The supported providers have several options to utilize. Examples of the available
options can be found [here](../provider_options.json.sample). To read about each of these options,
see the analyzer provider [documentation](https://github.com/konveyor/analyzer-lsp/blob/main/docs/providers.md).

Kantra will look for these options at `$HOME/.kantra/provider_options.json`
44 changes: 44 additions & 0 deletions provider_options.json.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[
{
"name": "go",
"initConfig": [{
"analysisMode": "full",
"providerSpecificConfig": {
"lspServerArgs": [],
"lspServerInitializationOptions": ""
}
}]
},
{
"name": "java",
"initConfig": [{
"providerSpecificConfig": {
"bundles": "",
"depOpenSourceLabelsFile": "",
"jvmMaxMem": "",
"mavenSettingsFile": ""
},
"analysisMode": "source-only"
}]
},
{
"name": "python",
"initConfig": [{
"analysisMode": "full",
"providerSpecificConfig": {
"lspServerArgs": [""],
"lspServerInitializationOptions": ""
}
}]
},
{
"name": "nodejs",
"initConfig": [{
"analysisMode": "full",
"providerSpecificConfig": {
"lspServerArgs": [""],
"lspServerInitializationOptions": ""
}
}]
}
]

0 comments on commit 4c3ba6f

Please sign in to comment.