Skip to content
This repository has been archived by the owner on Feb 6, 2024. It is now read-only.

Add ParseTagOption to k8s/go/pkg/resolver #698

Merged
merged 2 commits into from
Jun 17, 2022
Merged

Conversation

gonzojive
Copy link
Contributor

No description provided.

@k8s-ci-robot
Copy link

Hi @gonzojive. Thanks for your PR.

I'm waiting for a bazelbuild member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

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.

@fejta
Copy link
Contributor

fejta commented Jun 15, 2022

/test all

@fejta
Copy link
Contributor

fejta commented Jun 15, 2022

Can you please get this to pass tests?

@gonzojive
Copy link
Contributor Author

Can you please get this to pass tests?

Done.

@fejta
Copy link
Contributor

fejta commented Jun 17, 2022

/ok-to-test

parseTag func(name string, opts ...name.Option) (name.Tag, error)
}

// ParseTagOption specifies a function to be used instead of name.NewTag to parse image tags.
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason to add a hook here vs just replacing the resolver binary?

default = Label("//k8s/go/cmd/resolver"),

Copy link
Contributor Author

@gonzojive gonzojive Jun 17, 2022

Choose a reason for hiding this comment

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

Yes, this is needed to override the name resolution heuristics. Please see the example program below. A custom binary is still needed. However, the binary can reuse all the work done in the resolver library.

@@ -58,14 +58,41 @@ func RegisterFlags(flagset *flag.FlagSet) *Flags {
return &flags
}

// Option can be passed to NewResolver to configure the resolver.
type Option struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm a bit confused about why we're exporting the struct to other packages but not the methods?

Can you show me a concrete use case for how you want to use this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The Option pattern is pretty common in Go to parameterize a function with optional arguments.

By using your library within a custom resolver binary, it's possible to replace the heuristics built into the resolver library with custom logic without needing to fork the library.

var (
	insecureRegistries = map[string]struct{}{
		"localhost:32000":      {},
		"othermachine:32000":       {},
	}
)

func main() {
	flagset := flag.NewFlagSet(os.Args[0], flag.ExitOnError)
	flags := lib.RegisterFlags(flagset)
	flagset.Parse(os.Args[1:])

	resolver := lib.NewResolver(flags, lib.ParseTagOption(parseImageTag))
	resolved, err := resolver.Resolve()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(resolved)
}

func parseImageTag(t string, opts ...name.Option) (name.Tag, error) {
	got, err := name.NewTag(t, opts...)
	if err != nil {
		return got, err
	}

	regName := got.Context().Registry.Name()
	if _, isInsecure := insecureRegistries[regName]; isInsecure {
		var allOpts []name.Option
		allOpts = append(allOpts, opts...)
		allOpts = append(allOpts, name.Insecure)
		return name.NewTag(t, allOpts...)
	}
	return got, fmt.Errorf("unknown registry name %q", regName)
}

Copy link
Contributor

@fejta fejta Jun 17, 2022

Choose a reason for hiding this comment

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

I don't see how that is possible when Options struct rather than an interface. No one will be able to provide an alternative implementation of apply() (which by being lower case is also inaccessible to other packages)

Copy link
Contributor Author

@gonzojive gonzojive Jun 17, 2022

Choose a reason for hiding this comment

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

The resolver library provides the only means of constructing an Option, like ParseTagOption. I don't see a need for any other option types at a this time, so I kept the type private to the package. You can always open it up later.

This pattern is used by the cmp library, though it uses an interface with unexported methods rather than a struct. Either works. https://pkg.go.dev/github.com/google/go-cmp/cmp#Option

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not a huge fan of this API design, but I guess we can change it later if necessary.

@fejta
Copy link
Contributor

fejta commented Jun 17, 2022

PS: mostly trying to better understand the need here (aka make it easier to configure if an image is secure) and why this is a good approach for addressing that need.

@@ -58,14 +58,41 @@ func RegisterFlags(flagset *flag.FlagSet) *Flags {
return &flags
}

// Option can be passed to NewResolver to configure the resolver.
type Option struct {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not a huge fan of this API design, but I guess we can change it later if necessary.

@k8s-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: fejta, gonzojive

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

@fejta fejta merged commit fee80eb into bazelbuild:master Jun 17, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants