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

🌱 Plugin resolution enhancement proposal #1942

Closed
Closed
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
88 changes: 88 additions & 0 deletions designs/plugin-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Plugin and project version resolution

Adirio marked this conversation as resolved.
Show resolved Hide resolved
## Old behavior

The same process is followed for all commands, without distinction between `init` and the rest. The only difference is
that, for `init`, the configuration file will not be present.

1. Obtain the project version from project configuration file's `version` field, `--project-verison` flag, or default
project version configured during CLI creation (`cli.New(cli.WithDefaultProjectVersion(...))`).
* In case both a project configuration file and the flag are found, fail if they are different.
2. Obtain the plugin keys from the project configuration file's `layout` field, `--plugins` flag, or default plugins
configured during CLI creation for the above project version (`cli.New(cli.WithDefaultPlugins(...))`).
* In case both a project configuration file and the flag are found, fail if they are different.
camilamacedo86 marked this conversation as resolved.
Show resolved Hide resolved
3. In case any of the plugin keys is not fully qualified (full name and version), check if there is only one plugin that
fits that unqualified plugin key.
4. Resolve the plugins with the list of qualified keys above.
5. Verify the plugins support the project version.


### Flaws

* Default plugins need to be provided per project version
* Project version can't be resolved (e.g., when a single project version is supported by the provided plugins).
* Command calls are not allowed to override plugin keys.

## Proposal

The following plugin resolution algorithm solves the flaws described above:

1. [All commands but Init] Obtain the project version and plugin keys from the project configuration if available.
* If they are available, plugin keys will be fully qualified.
2. [Init command only] Obtain the project version from `--project-version` flag.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

One of the advantages implementation-wise of this new approach is that --project-version stops being a global variable for all commands that need to be special cased. It will just be a local variable of the Init command.

* The flag is optional, we will try to resolve project version later in case it is not provided.
Copy link
Contributor

Choose a reason for hiding this comment

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

There will always be a default project version. If no default plugins support the default project version, then an error should be returned.

Copy link
Contributor Author

@Adirio Adirio Mar 11, 2021

Choose a reason for hiding this comment

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

The idea here is, in case they provide a project version, make decissions knowing it, but in case it wasn't provide, just make decissions as if it was unknown and try to resolve it later.

Imagine I have the following plugins resolved:

Plugin Supported project version
go/v2 2, 3
go/v3 3
declarative/v1 2, 3

If the user provides a --plugins=go/v3,declarative flag, we would resolve to the last two plugins, and the only supported project version by both of them is 3 so we can implicitly resolve the project version.
If the user provides a --plugins=go/v2,declarative flag, we would resolve to the first and last plugin, and two different project versions are supported. If any of those is the default project version configured for the CLI, that will be used.

So we will have 3 ways of resolving the project version:

  • Explicitly by providing --project-version flag or having an already present config file (version field).
  • Implicitly by providing a set of plugins that only support a single common project version.
  • Default in case all resolved plugins support the default project version defined in the CLI.

In case none of the three above cases applies, an error ambiguous-project-version will be returned.

3. Obtain the optional plugin keys from `--plugins` flag.
* [Init command only] If not present, use default plugins.
* [All commands but Init] If not present, use plugin keys from configuration file (step 1).
4. Qualify the unqualified keys from step 3.
* If we know the project version, use this info to filter the available plugins so that we can be more accurate.
5. Resolve the plugins with the list of qualified keys above.
6. [Init command only] Resolve the project version in case it wasn't provided and there is only one project version
Copy link
Contributor

@estroz estroz Mar 11, 2021

Choose a reason for hiding this comment

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

What if two default plugins support the same project version? Which will be chosen?

Copy link
Contributor

@estroz estroz Mar 11, 2021

Choose a reason for hiding this comment

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

Actually this doesn't seem to be a problem if default plugins are forced to have a disjoint set of supported project versions.

Copy link
Contributor

Choose a reason for hiding this comment

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

However, I may want to specify a plugin for a particular project version, not just the project versions it supports. These changes take my ability to do that away.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What if two default plugins support the same project version? Which will be chosen?

This proposal takes into account that we will support plugin chains. Having multiple plugins set as default means that it is a default chain. This proposal removes the ability to provide different plugin/plugin-chains for each project version, but I guess we could try to keep this behavior.

supported by all the resolved plugins.

Adirio marked this conversation as resolved.
Show resolved Hide resolved
### Example

Based on the following main.go file:
```go
package main

import (
"log"

"sigs.k8s.io/kubebuilder/v2/pkg/cli"
"sigs.k8s.io/kubebuilder/v2/pkg/model/config"
pluginv2 "sigs.k8s.io/kubebuilder/v2/pkg/plugins/golang/v2"
pluginv3 "sigs.k8s.io/kubebuilder/v2/pkg/plugins/golang/v3"
)

func main() {
c, err := cli.New(
cli.WithCommandName("kubebuilder"),
cli.WithVersion(versionString()),
cli.WithPlugins(
&pluginv2.Plugin{},
&pluginv3.Plugin{},
),
cli.WithDefaultPlugins(&pluginv3.Plugin{}),
cli.WithCompletion,
)
if err != nil {
log.Fatal(err)
}
if err := c.Run(); err != nil {
log.Fatal(err)
}
}
```

As the `go.kubebuilder.io/v3` only supports project version "3", the project version can be resolved and doesn't
need to be specified in the flags.
```
kubebuilder init --plugins=go.kubebuilder.io/v3
```

camilamacedo86 marked this conversation as resolved.
Show resolved Hide resolved
```
kuebebuilder create api --plugins=declarative.kubebuilder.io/v1 ...
```
For this command, the declarative plugin will be used instead of the base plugin,
but following command calls won't use it unless provided again.
Adirio marked this conversation as resolved.
Show resolved Hide resolved