Skip to content

Conversation

@AlexNPavel
Copy link
Contributor

Description of the change: Implement new file based configuration system for the operator-sdk scorecard as detailed in the proposal made via PR #1558. It is a large PR, but a large majority of the new/changed lines are from 3 new scorecard subcommand tests and the related JSON assets and configs for the tests, as well as replacing all usages of viper in the internal plugins to a config struct built by unmarshalling the user provided configs. Documentation will be added in a separate PR that should be ready soon

Motivation for the change: Implement PR #1558

Based on ./doc/proposals/improved-scorecard-config.md
@AlexNPavel AlexNPavel added kind/feature Categorizes issue or PR as related to a new feature. scorecard Issue relates to the scorecard subcomponent labels Jul 3, 2019
@openshift-ci-robot openshift-ci-robot requested a review from lilic July 3, 2019 21:14
@openshift-ci-robot openshift-ci-robot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label Jul 3, 2019
@AlexNPavel
Copy link
Contributor Author

Documentation PR is now open: #1648

Co-Authored-By: Ish Shah <ish@ishshah.me>
Copy link
Contributor

@theishshah theishshah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, let's wait for another set of eyes before merging

Copy link
Member

@estroz estroz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good on a first pass. A few questions and suggestions.

if err != nil {
return err
}
log.Warn("Could not load config file; using flags")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now users always need a config file? Can they not run only their plugins with global CLI args? If a config is always required, mark --config as required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure. It might make sense to make a slight behavior change here. Currently, if you don't provide a config file, the scorecard will attempt to run all plugins. It will fail for the olm and basic plugins (as it did before due to missing cr-manifest; I intentionally kept that behavior for this PR), but for external plugins that don't need extra configuration it should work.

It might make sense to run all external plugins without configuration and ignore the internal plugins if a config file is not provided, but I feel like that might kinda hide the internal plugins from the users a bit, which is not ideal. This might need further discussion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we should run only external plugins if no configuration file is provided, but log an info statement before doing so. Something similar to:

No internal plugin configuration detected. Skipping Basic and OLM Plugins and running all external plugins.

@joelanford @hasbro17 @lilic @shawn-hurley @theishshah WDYT about handling this case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think that skipping them and logging an info statement would be a better behavior

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So it seems like the options are:

  1. Skip internal plugins and log a message that they were skipped
  2. Fail/do nothing without a config file. Don't even run external plugins.
  3. If we don't find a config file, initialize one and attempt to use sane defaults, even for the internal plugins. Would this be possible using CR manifests from the deploy/crds directory? Perhaps we need full support for multiple CRs first?

I kind of prefer option 2 to force the user to be explicit about what to run. Or option 3 if we think the defaulting is possible/sane.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK option 3 could work only if we assume all CR's in deploy/crds that also have accompanying CRD's should be tested, which is a bad idea. I agree we need to be explicit about what is being run.

Users should still be able to run internal plugins without a config, as they can do now, which is why I'm against option 2 and in favor of 1.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK option 3 could work only if we assume all CR's in deploy/crds that also have accompanying CRD's should be tested, which is a bad idea. I agree we need to be explicit about what is being run.

That's a good point. I know we don't do this anywhere else, but I know kubebuilder does - we could use interactive prompts in that case to have the user answer yes/no questions about including a CR in the config file. I'm not personally sold on that, but just throwing it out there.

Users should still be able to run internal plugins without a config, as they can do now, which is why I'm against option 2 and in favor of 1.

With option 1, aren't we saying that a config file has to be present to run internal plugins? Otherwise, they'll be skipped, a message will be logged, and the results will not contain anything about them?

For interactive use cases, I think option 1 is fine. But for non-interactive use cases, it seems like that message will get buried and results that don't include the basic and OLM tests may be misleading. I guess it depends on how the thing interpreting the JSON results is implemented.

Copy link
Member

@estroz estroz Jul 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'm backtracking on my opinion of option 1. To align our UX I'm now thinking we should go with option 2, and scaffold a scorecard config when running operator-sdk new.

description := fmt.Sprintf("Plugin with file name `%s` failed", filepath.Base(p.binPath))
if err := os.Chdir(filepath.Join(rootDir, scViper.GetString(PluginDirOpt))); err != nil {
name := fmt.Sprintf("Failed Plugin: %s", p.name)
description := fmt.Sprintf("Plugin with file name `%s` failed", filepath.Base(p.config.Command))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably out of scope for this PR since we're not changing it here, but it seems odd to me that we're changing the name and description of the test based on the test outcome.

It seems like those should always stay the same, since there are other indicators of the outcome (e.g. "error": 1 and "log": "failed to chdir into scorecard plugin directory...")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a new problem since we define a name for the plugins with this config design. However, the plugin also returns a name field, and in a successful run, we return the name that the plugin gave us, not the name from the config. This is a bit confusing, because this means we only ever use the config provided name during a failure, where we specify the name. I'm not quite sure how we should handle the name specified in the config file, or if we should even have one at all now...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm that's an interesting question. These end up being the suite names right? So going through various options:

  1. Plugin provides name in output, config name field is removed
    • Plugin fails to execute or does not return name in output => use basename of plugin executable
    • Plugin returns name in output => use name provided by plugin
  2. Plugin provides name, but can be overridden by config
    • Plugin fails to execute or does not return name in output => use config name if present, fallback to basename of plugin executable
    • Plugin returns name in output => use config name if present, fallback to name provided by plugin
  3. Plugin name is always basename of plugin executable
  4. Plugin name is always provided by config

None of these are perfect IMO.

Option 1 gives control to the plugin author. Plugin authors could do something weird, but generally I'd imagine this would be static or based on flags/input. This property is nice because shared plugins will generally result in the same name when run against different projects, which makes it easier to compare apples-to-apples.

Option 2 is probably my least favorite option, since its the \_(ツ)_/ of the group.

Option 3 and 4 are nice because duplicates can be found without executing the plugins, and they're very straightforward. Not sure if/how we handle duplicate names? Con: the same plugin might be renamed or configured with a different name, making comparison across projects a no-go.

I think I lean towards option 1. Thoughts? Any other options I'm not thinking of?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A plugin could return multiple suites. This would mean that there would be multiple names (each suite has a name), so changing the name(s) of the suite using the scorecard config can get messy.

Option 1 is good, but there is the issue that people may want to run the same plugin with different arguments or environment. If we only print the command's basename, a user may have difficulty identifying which test failed. By also providing the name that a user provided in their config, it makes it a lot easier to identify which plugin/configuration failed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could go with option 1 and append an md5 digest of all arguments/environment data to the plugin name, so you can run the same plugin with different configurations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A plugin could return multiple suites. This would mean that there would be multiple names (each suite has a name), so changing the name(s) of the suite using the scorecard config can get messy.

Maybe having a plugin return multiple suites is worth revisiting in scorecard 2.0. In the current output, is it possible to know which suites came from which plugin? If plugins ran only one suite, the plugin name would be the suite name, which seems like a decent way to handle plugins.

Either way, that isn't the case now. So in the meantime, it sounds like we're in agreement on not allowing user-overrideable test names?

Option 1 is good, but there is the issue that people may want to run the same plugin with different arguments or environment. If we only print the command's basename, a user may have difficulty identifying which test failed. By also providing the name that a user provided in their config, it makes it a lot easier to identify which plugin/configuration failed.

True, but it sounds like the only time the basename would be used is when the plugin fails. In that case, can we populate the log output with the full path, args, env of the failed plugin, along with whatever the stdout/err was.

}

type internalPlugin struct {
type basicOrOLMPlugin struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also probably out of scope for this PR since the API is what matters most, but did you consider defining separate basicPlugin and olmPlugin structs such that each could have its own Run() implementation?

It might be cleaner to extract the shared code from basicOrOLMPlugin.Run() and plugins.RunInternalPlugin into separate functions or packages so that we wouldn't have to support both plugin types with one function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we discussed separating the Run functions in another PR. They are very similar and would only differ by about 5-10 lines out of a very large function. They also have all the same configuration fields (and they both use all of them except for csv-path in the basic plugins). Splitting up the Run function into multiple smaller functions would be good to make it clearer as to what's actually going on in the function and is something we definitely should do, but we still would essentially be running the same functions for both plugins.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't to say that no future internal plugins would be separate. For the proposed YAML-defined scorecard tests, we would have a completely separate Run: #1241

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right. Sorry I'm harping on it 🙂

They also have all the same configuration fields (and they both use all of them except for csv-path in the basic plugins)

For this we could use struct embedding where the common fields go in a basicPlugin struct and an olmPlugin struct embeds basicPlugin and adds csv-path.

Splitting up the Run function into multiple smaller functions would be good to make it clearer as to what's actually going on in the function and is something we definitely should do

Yeah that's pretty much what I'm suggesting.

but we still would essentially be running the same functions for both plugins.

Which is totally fine. I'm basically saying that code that runs based on a pluginType conditional could be extracted into the plugin's run function, and all other code could be shared in smaller split-out functions.

And again, probably not in scope for this PR, but something like this would be good to do in a follow-up depending on direction from CVP requirements.

@openshift-ci-robot openshift-ci-robot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Aug 12, 2019
@AlexNPavel AlexNPavel closed this Aug 13, 2019
@AlexNPavel AlexNPavel reopened this Aug 13, 2019
@AlexNPavel
Copy link
Contributor Author

/test e2e-aws-subcommand

@AlexNPavel
Copy link
Contributor Author

/test e2e-aws-go
/test e2e-aws-helm

@openshift-ci-robot openshift-ci-robot added size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. and removed size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. labels Aug 13, 2019
Copy link
Member

@joelanford joelanford left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks pretty close. Hopefully just the one last question.

Copy link
Member

@estroz estroz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs a changelog entry, otherwise LGTM.

Also there should be a follow-up PR that scaffolds a scorecard config on operator-sdk new as per #1641 (comment).

Copy link
Member

@joelanford joelanford left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @estroz. LGTM after CHANGELOG update.

@AlexNPavel
Copy link
Contributor Author

Updated CHANGELOG. Will work on updating the docs PR now (#1648)

@AlexNPavel
Copy link
Contributor Author

/test e2e-aws-ansible

1 similar comment
@AlexNPavel
Copy link
Contributor Author

/test e2e-aws-ansible

@AlexNPavel
Copy link
Contributor Author

/retest

@AlexNPavel
Copy link
Contributor Author

/test e2e-aws-ansible

@AlexNPavel
Copy link
Contributor Author

/retest

@AlexNPavel AlexNPavel merged commit 2c8f211 into operator-framework:master Aug 28, 2019
@AlexNPavel AlexNPavel deleted the scorecard-config branch August 28, 2019 00:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Categorizes issue or PR as related to a new feature. scorecard Issue relates to the scorecard subcomponent size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants