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

feature: implement plugin proposal in #1250 #1290

Conversation

estroz
Copy link
Contributor

@estroz estroz commented Jan 8, 2020

Implements #1250 except for version format enforcement and plugin name resolution (will be done in follow-ups).

TODO:

  • finalize plugin interface set
  • discuss pro's/con's of this implementation, smooth over rough edges

/cc @DirectXMan12 @droot @Adirio @joelanford @shawn-hurley @camilamacedo86

@k8s-ci-robot k8s-ci-robot added the cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. label Jan 8, 2020
@k8s-ci-robot
Copy link
Contributor

@estroz: GitHub didn't allow me to request PR reviews from the following users: Adirio.

Note that only kubernetes-sigs members and repo collaborators can review this PR, and authors cannot review their own PRs.

In response to this:

First pass at implementing #1250.

TODO:

  • [] finalize plugin interface set
  • discuss pro's/con's of this implementation, smooth over rough edges

/cc @DirectXMan12 @droot @Adirio @joelanford @shawn-hurley @camilamacedo86

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Jan 8, 2020
@estroz estroz changed the title feature: implement plugin proposal in #1250 [WIP] feature: implement plugin proposal in #1250 Jan 8, 2020
@k8s-ci-robot k8s-ci-robot added the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Jan 8, 2020
pkg/cli/create.go Outdated Show resolved Hide resolved
pkg/cli/cli.go Outdated Show resolved Hide resolved
pkg/cli/alpha.go Outdated Show resolved Hide resolved
pkg/cli/cli.go Outdated
func New(opts ...Option) (*CLI, error) {
c := &CLI{
commandName: "kubebuilder",
defProjVersion: project.Version2,
Copy link
Member

Choose a reason for hiding this comment

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

Given the seeming consensus around name and version, we may need to re-think the --project-version flag and this defProjVersion field.

If we care about backward compatibility, we could keep and deprecate the --project-version flag, and make it automatically choose the "go" plugins. Maybe we don't care since --project-version is used during project initialization only (I think?).

We probably need a new init flag, maybe --plugin, that takes something like <name>/<version>. So for the existing kubebuilder plugins, it would understand go/v1 and go/v2.

Lastly, do we want to have a convention to make it easier to distinguish similar plugins from different authors? Consider two different plugins named foo. Should we include a domain component (e.g. foo.kubebuilder.io and foo.operator-framework.io)? If so, this field starts to look a lot like a Kubernetes group version string (maybe more familiar for users) and it would make it more apparent which binary a given KB project would require. One thing I don't like about this is that it requires more typing from users.

Copy link
Contributor Author

@estroz estroz Jan 10, 2020

Choose a reason for hiding this comment

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

Having name + version for a plugin changes how plugins are accessed, since you can have multiple names for the same plugin version. This is fine and desired, ex. helm/v1 and go/v1 should return different plugins. Name + version needs to be recorded in PROJECT, so after running init the --plugin/--project-version flag is no longer needed.

@DirectXMan12 @droot thoughts on ^?

Copy link
Contributor

Choose a reason for hiding this comment

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

I kinda imagined it'd go like this:

  • kubebuilder init --project-version v{1,2} are mostly an alias for kubebuilder init --plugin go:v{1,2} (see below)
  • kubebuilder init --plugin NAME:VERSION (or NAME/VERSION) initializes a project with the given plugin, writing that to the project file with the special project version of 3x or something. We might want special handling if you actually used --project-version to write 1 or 2
  • After init, you never specify project version or base plugin again

As for suffixes, might not be a bad idea to encourage it, but I don't expect it'll be a big issue (famous last words) and it is a lot of extra typing. Maybe allow it as a disambiguation form, but don't require it?

Copy link
Contributor

@Adirio Adirio Jan 22, 2020

Choose a reason for hiding this comment

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

@DirectXMan12 Why do you want to upgrade to v3x? I think we can acheive this being fully compatible with v1 and v2 so we wouldn't need to upgrade to v3 as the scaffold won't be modified.

Copy link
Contributor

Choose a reason for hiding this comment

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

The intention was at least that 3x would indicate to aware things that plugins are involved -- if you try to work with a project scaffolded with a particular set of plugins and aren't aware, things could go awry.

We might want to punt on that for later, though.

cmd/main.go Outdated Show resolved Hide resolved
Copy link
Contributor

@DirectXMan12 DirectXMan12 left a comment

Choose a reason for hiding this comment

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

initial pass. A few questions. Doesn't look too bad. The hacks fancy footwork working around cobra doesn't make me feel warm and fuzzy inside, but that what's hot cocoa is for I guess.

pkg/cli/cli.go Outdated Show resolved Hide resolved
pkg/cli/cli.go Outdated Show resolved Hide resolved
pkg/cli/cli.go Outdated
// empty string and true. Otherwise, getBaseFlags returns the project version
// and false.
func (c CLI) getBaseFlags() (string, bool) {
fs := pflag.NewFlagSet("base", pflag.ExitOnError)
Copy link
Contributor

Choose a reason for hiding this comment

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

FYI, this logic yields "unknown flag: project-version" when we get to the main flag parsing logic. We prob want this defined on the main command too.

pkg/cli/create.go Outdated Show resolved Hide resolved
pkg/plugin/plugin.go Outdated Show resolved Hide resolved

// If only the help flag was set, return the command as is.
if isHelpOnly {
return cmd
Copy link
Contributor

Choose a reason for hiding this comment

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

doesn't this mean that a plugin doesn't get to modify help?

Copy link
Member

Choose a reason for hiding this comment

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

The intent with this was to handle kubebuilder init --help, in which case we could print out a general help. In this case, we don't know which plugin to use for help output.

Copy link
Contributor

Choose a reason for hiding this comment

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

Does this have something to do with the use of log.Fatal where you were using cdmErr and return in create api and webhook commands?

pkg/cli/webhook.go Outdated Show resolved Hide resolved
pkg/cli/alpha.go Outdated Show resolved Hide resolved
Copy link
Contributor

@Adirio Adirio left a comment

Choose a reason for hiding this comment

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

Quite complete review: I requested some changes, suggested others, and asked some doubts. Hope it helps.

By the way, this needs a rebase as https://travis-ci.org/kubernetes-sigs/kubebuilder/jobs/635475321#L637-L644 was solved as a side effect of #1287 (more info in #1288) a couple weeks ago. The rebase will include multiple new lint checks aside from those that are already yielding errors in the current state (https://travis-ci.org/kubernetes-sigs/kubebuilder/jobs/635475321#L253-L350).

pkg/cli/cli.go Outdated
func New(opts ...Option) (*CLI, error) {
c := &CLI{
commandName: "kubebuilder",
defProjVersion: project.Version2,
Copy link
Contributor

@Adirio Adirio Jan 22, 2020

Choose a reason for hiding this comment

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

@DirectXMan12 Why do you want to upgrade to v3x? I think we can acheive this being fully compatible with v1 and v2 so we wouldn't need to upgrade to v3 as the scaffold won't be modified.

pkg/cli/cli.go Outdated
Comment on lines 68 to 91
// Run runs the CLI.
func (c CLI) Run() error {
return c.cmd.Execute()
}
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: Is Run a good method name in this case? I would say that the user executes or runs a command but we are building the CLI. Some ideas (brainstorming): Build, Deploy, Make, Create, Generate, Finish, End. I think I like Deploy the most.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If not Run, Execute would make sense. The CLI isn't really deploying anything, ex. resources, it is a program that is running/executing.

pkg/cli/cli.go Outdated Show resolved Hide resolved
pkg/plugin/plugin.go Outdated Show resolved Hide resolved
pkg/cli/create.go Outdated Show resolved Hide resolved
pkg/cli/webhook.go Outdated Show resolved Hide resolved
pkg/plugin/util/util.go Outdated Show resolved Hide resolved
pkg/plugin/v1/api.go Outdated Show resolved Hide resolved
pkg/plugin/v1/init.go Outdated Show resolved Hide resolved
pkg/plugin/v2/init.go Outdated Show resolved Hide resolved
pkg/cli/cli.go Outdated Show resolved Hide resolved
}

func (_ Plugin) Version() string {
return "1"

Choose a reason for hiding this comment

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

Is anyone else concerned about versions as strings and the ability to put anything here?

I guess this could be a feature so you could do init --plugin Foo:Bar to have a composable set of plugins by "version" but the same overall plugin? If that is the use case maybe this is not a version field?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that may rise a lot of issues as we are expecting the default go plugin to exist for every version and using Bar as version would break that.

Copy link
Contributor Author

@estroz estroz Jan 22, 2020

Choose a reason for hiding this comment

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

Version formatting and plugin composition go hand-in-hand, so we should follow up this PR with a discussion on both. For now we could enforce _, err := strconv.Atoi(p.Version()); err != nil.

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah. I think for the moment: add a TODO for this, and we'll track them all down before final merge.

We can do the "move fast and break things" strategy on this branch.

@shawn-hurley
Copy link

Overall I think that this good

some points:

I think we need to discuss the version more.
We need an interface for CLI instead of a struct with hidden fields.

Want to see what folks think about the default for help will show the plugins that can be used as well as the default flags and such? Is that possible or is that already working and I just can't see it?

@Adirio
Copy link
Contributor

Adirio commented Jan 22, 2020

@estroz merging Master wasn't the best idea IMHO. I think you need to rebase your branch to Master, 257 files changed, and 10k lines modified seem to be a bit too much.

@estroz
Copy link
Contributor Author

estroz commented Jan 22, 2020

@Adirio its because the target feature branch isn't up to date with master. It needs to be updated.

Copy link
Contributor

@Adirio Adirio left a comment

Choose a reason for hiding this comment

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

its because the target feature branch isn't up to date with master. It needs to be updated.

Oh, right, you are not PR-ing against master. Reviewing right now is quite complex. Would it be better if we change the target branch to master until this is ready to ship, then update the current target branch to that point and swap again this PR to point to it?

pkg/cli/alpha.go Outdated
Comment on lines 32 to 34
Example: fmt.Sprintf(`
# scaffolds webhook server
%s alpha webhook <params>
`, c.commandName),
%s alpha webhook <params>`, c.commandName),
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT: From an style point of view I may like more

		Example: fmt.Sprintf(
			`
# scaffolds webhook server
%s alpha webhook <params>`,
			c.commandName,
		),

I feel like using backquotes vs \n helps visualizing how it will look like but messes with the indentation. At least in this case we only mess with the indentation of the text itself, the params are well indented.

P.S.: applies to several other parts of the code.

pkg/plugin/v1/init.go Outdated Show resolved Hide resolved
pkg/plugin/v2/init.go Outdated Show resolved Hide resolved
"sigs.k8s.io/kubebuilder/pkg/plugin/v1"
v1 "sigs.k8s.io/kubebuilder/pkg/plugin/v1"
Copy link
Contributor

@Adirio Adirio Jan 23, 2020

Choose a reason for hiding this comment

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

I think this is because it expects packages v1 and v2 to be different versions of the pkg/plugin package. It made me think that we may want to include the plugin name in the package name, either pkg/plugin/govX or pkg/plugin/go/vX. The second will still be interpreted as a version but this time of pkg/plugin/go which would be technichally correct.

@estroz
Copy link
Contributor Author

estroz commented Jan 23, 2020

@Adirio if we can update the target feature branch with master, we should be ok since we don't need to merge CI fixes going forward. The only following merge will be your changes in #1325.

@DirectXMan12 @droot @mengqiy I don't have access to the feature branch. Can you merge it with master?

@Adirio
Copy link
Contributor

Adirio commented Jan 23, 2020

The only following merge will be your changes in #1325.

I think that #1330 may also be a good idea to merge before, as it targets cmd package. Basically it is making the separation between cmd and pkg/scaffold clearer. This way I can keep working on enhancing the pkg/scaffold while the plugin system gets implemented without requiring too many rebases and conflict resolution from any of the two sides.

@DirectXMan12
Copy link
Contributor

Hey, sorry about that. I'll fast-forward as needed. Feel free to ping me on Slack if I'm not responding here.

@DirectXMan12
Copy link
Contributor

should be up-to-date now

@DirectXMan12
Copy link
Contributor

please do pull out the merge commit though

@DirectXMan12
Copy link
Contributor

approved or almost approved a couple of those PRs from @Adirio. LMK if there's another one blocking, but I think if we rebase on that we can probably merge this as a "here's a working step" and keep iterating.

Copy link
Contributor

@Adirio Adirio left a comment

Choose a reason for hiding this comment

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

NITs: a function movement suggestion and some non-needed variables removals.

Otherwise, LGTM.

cmd/main.go Outdated
func main() {
if err := buildCmdTree().Execute(); err != nil {
log.Fatal(err)
func loadExistingConfig() (*config.Config, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you think about moving this to internal/config and calling it MustLoad?

The subcommands under plugin would also be able to use this function if we move it there.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Must implies that the function exits if the operation fails. Is this the behavior you intend MustLoad to have? Otherwise LoadExisting makes more sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

Must usually means that errors will be handled with a panic, I guess another name could be better. But moving it there seems like a good thing to do.

pkg/cli/alpha.go Outdated Show resolved Hide resolved
pkg/cli/alpha.go Outdated Show resolved Hide resolved
pkg/cli/cli.go Outdated Show resolved Hide resolved
pkg/cli/cli.go Outdated Show resolved Hide resolved
pkg/cli/cli.go Outdated Show resolved Hide resolved
pkg/cli/create.go Outdated Show resolved Hide resolved
pkg/cli/create.go Outdated Show resolved Hide resolved
Copy link
Member

@camilamacedo86 camilamacedo86 left a comment

Choose a reason for hiding this comment

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

IHMO: it still has a hall to changes and improvements. However, it will also easier to be done properly during and after the phase2 of its implementation. So, it shows ok for me to attend as first step the proposal made which is the goal of this PR.

@mengqiy @DirectXMan12 wdyt?

/lgtm

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 10, 2020
These changes are the implementation of concepts outlined in
designs/extensible-cli-and-scaffolding-plugins-phase-1.md

* cmd/: remove all but 'edit' and 'update' subcommands in favor
of plugins that implement removed commands

* internal/cmdutil: RunOptions configure Run() to execute a command
in a generic manner

* pkg/cli: CLI interface and cobra CLI constructors. Most commands
from cmd/ were move here and modified to initialize plugins

* pkg/plugin: Plugin and PluginGetter interfaces for v1 and v2
scaffolds. These are kubebuilider's base Go plugins consumed by
pkg/cli.CLI
@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 13, 2020
@camilamacedo86
Copy link
Member

@estroz @DirectXMan12.

Should not it be an issue in https://github.com/kubernetes-sigs/kubebuilder/projects/7? as well?
WDYT?
c/c @hasbro17

Copy link
Member

@camilamacedo86 camilamacedo86 left a comment

Choose a reason for hiding this comment

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

.

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 20, 2020
@camilamacedo86
Copy link
Member

/ok-to-test

@k8s-ci-robot k8s-ci-robot added the ok-to-test Indicates a non-member PR verified by an org member that is safe to test. label Feb 20, 2020
"sigs.k8s.io/kubebuilder/internal/config"
"sigs.k8s.io/kubebuilder/pkg/scaffold"
"sigs.k8s.io/kubebuilder/pkg/cli"
pluginv1 "sigs.k8s.io/kubebuilder/pkg/plugin/v1"
Copy link
Member

@camilamacedo86 camilamacedo86 Feb 20, 2020

Choose a reason for hiding this comment

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

IHMO: We should not care about V1 since it is deprecated and should no longer be used.
Also, we need to remove the V1 code in order to keep things simple.
However, since it is already done in the PR we can merge with. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removing v1 may be easier after merging the feature branch with master. @DirectXMan12 @mengqiy thoughts on this? Regardless, out of scope for this PR.

Copy link
Member

Choose a reason for hiding this comment

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

Just to track here: We have a PR for that already: #1355

c.projectVersion = projectConfig.Version
} else {
return fmt.Errorf("failed to read config: %v", err)
}
Copy link
Member

Choose a reason for hiding this comment

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

Just a nit. Suggestion ( I think make more clear when has an error and not what should be done )

if err != nil {
      if os.IsNotExist(err) {
            c.configured = false
	    c.projectVersion = c.defaultProjectVersion
      } else {
           return fmt.Errorf("failed to read config: %v", err)
      }
} else {
     c.configured = true
     c.projectVersion = projectConfig.Version
}

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 less clear IMO.

tmpGetter, isGetter := p.(plugin.CreateAPIPluginGetter)
if isGetter {
if hasGetter {
err := fmt.Errorf("duplicate API creation plugins for project version %q: %s, %s",
Copy link
Member

@camilamacedo86 camilamacedo86 Feb 20, 2020

Choose a reason for hiding this comment

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

Could not the API be called/used more than once to create different resources?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Each create command is associated with exactly one versioned plugin, otherwise plugin behavior can conflict. If you want to create more than one resource, call create api for each resource.

tmpGetter, isGetter := p.(plugin.CreateWebhookPluginGetter)
if isGetter {
if hasGetter {
err := fmt.Errorf("duplicate webhook creation plugins for project version %q: %s, %s",
Copy link
Member

Choose a reason for hiding this comment

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

Can we just use/call the webhook just once as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See my create api comment.

Copy link
Member

@camilamacedo86 camilamacedo86 left a comment

Choose a reason for hiding this comment

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

HI @estroz,

Just a few questions and nits, otherwise it shows ok for me as phase 1 and I still thinking that will be easier we check more changes and improvements after phase 2 and its implementations.

However, I have not seen the prow jobs called here. So, /lgtm cancel

Screenshot 2020-02-20 at 12 15 54

Could you please check?

@camilamacedo86
Copy link
Member

/lgtm cancel

@k8s-ci-robot k8s-ci-robot removed the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 20, 2020
@Adirio
Copy link
Contributor

Adirio commented Feb 20, 2020

However, I have not seen the prow jobs called here. So, /lgtm cancel

Could you please check?

This is being merged in a branch that is not Master and thus the tests are not being run.

Copy link
Contributor

@DirectXMan12 DirectXMan12 left a comment

Choose a reason for hiding this comment

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

really minor (non-blocking) nits. Fix them in a follow-up.

Are we doing the "layout" field in a follow-up?

/lgtm
/approve

Run: func(_ *cobra.Command, _ []string) {
if err := run(options); err != nil {
Example: fmt.Sprintf(` # Update the vendor dependencies:
kubebuiler update vendor`),
Copy link
Contributor

Choose a reason for hiding this comment

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

why is this still fmt.Sprintf

return &cobra.Command{
Use: "alpha",
Short: "Expose commands which are in experimental or early stages of development",
Long: `Command group for commands which are either experimental or in early stages of development`,
Example: fmt.Sprintf(`
# scaffolds webhook server
%s alpha webhook <params>`,
Copy link
Contributor

Choose a reason for hiding this comment

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

opposite side of same question here

),
}

// Lookup the plugin for projectVersion and bind it to the command.
Copy link
Contributor

Choose a reason for hiding this comment

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

is this comment correct any more?

@k8s-ci-robot k8s-ci-robot added the lgtm "Looks good to me", indicates that a PR is ready to be merged. label Feb 20, 2020
@k8s-ci-robot
Copy link
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: DirectXMan12, estroz

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Feb 20, 2020
@k8s-ci-robot k8s-ci-robot merged commit e322071 into kubernetes-sigs:feature/plugins-part-2-electric-boogaloo Feb 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
approved Indicates a PR has been approved by an approver from all required OWNERS files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. lgtm "Looks good to me", indicates that a PR is ready to be merged. ok-to-test Indicates a non-member PR verified by an org member that is safe to test. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants