Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use provider config options with default configs #240

Merged
merged 2 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,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
176 changes: 142 additions & 34 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 @@ -225,9 +231,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 @@ -583,8 +586,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 @@ -613,6 +614,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 @@ -621,9 +623,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 @@ -692,7 +691,6 @@ func (a *analyzeCommand) getConfigVolumes(providers []string, ports map[string]i
},
},
}

switch {
case foundJava:
provConfig = append(provConfig, javaConfig)
Expand All @@ -704,30 +702,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, providers[0])
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 @@ -1503,6 +1489,128 @@ 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, prov string) error {
var confDir string
var set bool
ops := runtime.GOOS
if ops == "linux" {
confDir, set = os.LookupEnv("XDG_CONFIG_HOME")
}
if ops != "linux" || confDir == "" || !set {
// on Unix, including macOS, this returns the $HOME environment variable. On Windows, it returns %USERPROFILE%
var err error
confDir, err = os.UserHomeDir()
if err != nil {
return err
}
}
// get provider options from provider settings file
data, err := os.ReadFile(filepath.Join(confDir, ".kantra", fmt.Sprintf("%v.json", prov)))
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 {
eemcmullan marked this conversation as resolved.
Show resolved Hide resolved
// 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 {
shawn-hurley marked this conversation as resolved.
Show resolved Hide resolved
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
18 changes: 18 additions & 0 deletions docs/usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,21 @@
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](../java.json.sample) and [here](../golang.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:
- Linux: `$XDG_CONFIG_HOME/.kantra/<provider_name>.json` and then `$HOME/.kantra/<provider_name>.json`
- MacOS: `$HOME/.kantra/<provider_name>.json`
- Windows: `%USERPROFILE%/.kantra/<provider_name>.json`

Current supported providers are:
- java
- golang
- python
- nodejs
12 changes: 12 additions & 0 deletions golang.json.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"name": "go",
"initConfig": [{
"analysisMode": "full",
"providerSpecificConfig": {
"lspServerArgs": [],
"lspServerInitializationOptions": ""
}
}]
}
]
14 changes: 14 additions & 0 deletions java.json.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
[
{
"name": "java",
"initConfig": [{
"providerSpecificConfig": {
"bundles": "",
"depOpenSourceLabelsFile": "",
"jvmMaxMem": "",
"mavenSettingsFile": ""
},
"analysisMode": "source-only"
}]
}
]
Loading