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

docs: controllers and webhooks for existing resources? #1270

Closed
adampl opened this issue Dec 17, 2019 · 10 comments · Fixed by #1345
Closed

docs: controllers and webhooks for existing resources? #1270

adampl opened this issue Dec 17, 2019 · 10 comments · Fixed by #1345
Assignees
Labels
kind/documentation Categorizes issue or PR as related to documentation. kind/feature Categorizes issue or PR as related to a new feature.

Comments

@adampl
Copy link

adampl commented Dec 17, 2019

I'm going through the book, but it's all about CRDs so I feel a bit lost, because I don't need a CRD.

Is it actually possible to create a custom controller for an existing resource (like built-in Service or Pod) with Kubebuilder?
Is it a good idea to use Kubebuilder for this purpose?
How to do it the simple way?

I think a tutorial should be added covering this topic, or at least a short note answering these questions.

If it's not currently possible, please consider adding such feature.

/kind feature
/kind documentation

@adampl adampl added the kind/feature Categorizes issue or PR as related to a new feature. label Dec 17, 2019
@k8s-ci-robot k8s-ci-robot added the kind/documentation Categorizes issue or PR as related to documentation. label Dec 17, 2019
@gregsidelinger
Copy link

I'm here because of the same thing. I was going to use kubebuilder 2.2.0 to create some mutating webhooks for Pods and Services. I've done this before in v1 and came here after I could not even run make after initializing the project. #1213 states that native objects are not supported.

I would like to see support for native k8s objects added back to kubebuilder. They worked in v1 when it was an alpha feature.

In v1 of kubebuilder this worked.

kubebuilder init --domain example.com --license none --owner "bob"
kubebuilder alpha webhook --group core --version v1 --kind Service --type=validating --operations=create,update

I was hoping this would work in v2 but it does not.

kubebuilder init --domain example.com --license none --owner "bob"
kubebuilder create webhook --group core --version v1 --kind Service --defaulting --programmatic-validation

@droot
Copy link
Contributor

droot commented Dec 18, 2019

@adampl some answers to help you.

Is it actually possible to create a custom controller for an existing resource (like built-in Service or Pod) with Kubebuilder?

Yes absolutely. Only change would be: when you run kubebuilder create api , skip creating resource when it prompts you as shown below. This will skip scaffolding API definitions etc and only create scaffolding for the controller. Rest of the instructions should work.

$ kubebuilder create api --group "core" --kind "Service" --version "v1"
Create Resource [y/n]
n
Create Controller [y/n]
y

Is it a good idea to use Kubebuilder for this purpose?

Yes.

@droot
Copy link
Contributor

droot commented Dec 18, 2019

@mengqiy Can you pl. help @gregsidelinger with the webhook query ?

@mengqiy
Copy link
Member

mengqiy commented Jan 3, 2020

@gregsidelinger Thanks for your feedback. Sorry for the late response.
We have improved our webhook library and tooling for CRD in v2. Now it's super easy for CRD.

At the moment, kubebuilder CLI doesn't provide much scaffolding for built-in types and you have to do it through the low-level library (controller-runtime). It's still doable. Here is an example.

@mengqiy
Copy link
Member

mengqiy commented Jan 3, 2020

We will need to add some document to at least make https://github.com/kubernetes-sigs/controller-runtime/tree/master/examples/builtins more discoverable.

@adampl
Copy link
Author

adampl commented Jan 3, 2020

Personally, this is the best example:
https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/builder#example-Builder

@gregsidelinger
Copy link

I've looked over the docs links. I'm going to work on my validating hook one of these days to see how to do it in v2 of kubebuilder. The part that really bugs me for existing objects is I need to do a bunch of extra work that I did not need to do in v1 back in the alpha days. I have a co-worker who did a mutating webhook for nodes to add AWS tags as labels and he gave up on kubebuilder 2 and use 1 instead because it was much more difficult to work with existing objects in version 2.

@DirectXMan12
Copy link
Contributor

@gregsidelinger can you clarify what you mean? A v1 webhook should look more-or-less identical to a v2 low-level webhook:

compare https://book-v1.book.kubebuilder.io/beyond_basics/sample_webhook.html#implementing-webhook-handler

with

https://github.com/kubernetes-sigs/controller-runtime/blob/master/examples/builtins/mutatingwebhook.go

@harpratap
Copy link
Contributor

@droot Does that method work only for core group? I'm trying to create a controller for an istio CRD and I get errors.

> kubebuilder create api --group networking.istio.io --version v1alpha3 --kind Gateway
Create Resource [y/n]
n
Create Controller [y/n]
y
Writing scaffold for you to edit...
controllers/gateway_controller.go
Running make:
$ make
go: creating new go.mod: module tmp
go: found sigs.k8s.io/controller-tools/cmd/controller-gen in sigs.k8s.io/controller-tools v0.2.5
/Users/harpratap.layal/go/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
main.go:29:2: package gateway-controller/api/v1alpha3 is not in GOROOT (/usr/local/Cellar/go/1.14.2/libexec/src/gateway-controller/api/v1alpha3)
Error: not all generators ran successfully
run `controller-gen object:headerFile=hack/boilerplate.go.txt paths=./... -w` to see all available markers, or `controller-gen object:headerFile=hack/boilerplate.go.txt paths=./... -h` for usage
make: *** [generate] Error 1
2020/06/25 18:05:30 failed to create API: exit status 2

After removing all API related code -

> make run
go: creating new go.mod: module tmp
go: found sigs.k8s.io/controller-tools/cmd/controller-gen in sigs.k8s.io/controller-tools v0.2.5
/Users/harpratap.layal/go/bin/controller-gen object:headerFile="hack/boilerplate.go.txt" paths="./..."
go fmt ./...
go vet ./...
package gateway-controller/controllers (test): package gateway-controller/api/v1alpha3 is not in GOROOT (/usr/local/Cellar/go/1.14.2/libexec/src/gateway-controller/api/v1alpha3)
# sigs.k8s.io/controller-runtime/pkg/metrics
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/metrics/client_go_adapter.go:120:24: too many arguments in call to metrics.Register
	have (*latencyAdapter, *resultAdapter)
	want (metrics.RegisterOpts)
# sigs.k8s.io/controller-runtime/pkg/client
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/typed_client.go:45:62: o.resourceMeta.Interface.Post().NamespaceIfScoped(o.Object.GetNamespace(), o.resourceMeta.isNamespaced()).Resource(o.resourceMeta.resource()).Body(obj).VersionedParams(createOpts.AsCreateOptions(), c.paramCodec).Context undefined (type *rest.Request has no field or method Context)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/typed_client.go:65:62: o.resourceMeta.Interface.Put().NamespaceIfScoped(o.Object.GetNamespace(), o.resourceMeta.isNamespaced()).Resource(o.resourceMeta.resource()).Name(o.Object.GetName()).Body(obj).VersionedParams(updateOpts.AsUpdateOptions(), c.paramCodec).Context undefined (type *rest.Request has no field or method Context)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/typed_client.go:85:37: o.resourceMeta.Interface.Delete().NamespaceIfScoped(o.Object.GetNamespace(), o.resourceMeta.isNamespaced()).Resource(o.resourceMeta.resource()).Name(o.Object.GetName()).Body(deleteOpts.AsDeleteOptions()).Context undefined (type *rest.Request has no field or method Context)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/typed_client.go:105:42: o.resourceMeta.Interface.Delete().NamespaceIfScoped(deleteAllOfOpts.ListOptions.Namespace, o.resourceMeta.isNamespaced()).Resource(o.resourceMeta.resource()).VersionedParams(deleteAllOfOpts.ListOptions.AsListOptions(), c.paramCodec).Body(deleteAllOfOpts.DeleteOptions.AsDeleteOptions()).Context undefined (type *rest.Request has no field or method Context)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/typed_client.go:129:13: o.resourceMeta.Interface.Patch(patch.Type()).NamespaceIfScoped(o.Object.GetNamespace(), o.resourceMeta.isNamespaced()).Resource(o.resourceMeta.resource()).Name(o.Object.GetName()).VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec).Body(data).Context undefined (type *rest.Request has no field or method Context)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/typed_client.go:143:25: r.Interface.Get().NamespaceIfScoped(key.Namespace, r.isNamespaced()).Resource(r.resource()).Context undefined (type *rest.Request has no field or method Context)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/typed_client.go:159:58: r.Interface.Get().NamespaceIfScoped(listOpts.Namespace, r.isNamespaced()).Resource(r.resource()).VersionedParams(listOpts.AsListOptions(), c.paramCodec).Context undefined (type *rest.Request has no field or method Context)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/typed_client.go:181:89: o.resourceMeta.Interface.Put().NamespaceIfScoped(o.Object.GetNamespace(), o.resourceMeta.isNamespaced()).Resource(o.resourceMeta.resource()).Name(o.Object.GetName()).SubResource("status").Body(obj).VersionedParams((&UpdateOptions literal).ApplyOptions(opts).AsUpdateOptions(), c.paramCodec).Context undefined (type *rest.Request has no field or method Context)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/typed_client.go:206:79: o.resourceMeta.Interface.Patch(patch.Type()).NamespaceIfScoped(o.Object.GetNamespace(), o.resourceMeta.isNamespaced()).Resource(o.resourceMeta.resource()).Name(o.Object.GetName()).SubResource("status").Body(data).VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec).Context undefined (type *rest.Request has no field or method Context)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/unstructured_client.go:51:20: not enough arguments in call to r.Create
	have (*unstructured.Unstructured, v1.CreateOptions)
	want (context.Context, *unstructured.Unstructured, v1.CreateOptions, ...string)
../../go/pkg/mod/sigs.k8s.io/controller-runtime@v0.5.0/pkg/client/unstructured_client.go:51:20: too many errors
make: *** [vet] Error 2

@camilamacedo86
Copy link
Member

Hi @harpratap,

This issue is close, could you please raise a new one with your questions and specific scenario?
Also, please provide the version of kb used and etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/documentation Categorizes issue or PR as related to documentation. kind/feature Categorizes issue or PR as related to a new feature.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

8 participants