-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
✨ Add kubebuilder alpha config-gen
command to explore generating configuration with kustomize functions
#1831
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
/* | ||
Copyright 2020 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
//go:generate go run github.com/markbates/pkger/cmd/pkger | ||
|
||
// Package kubebuilder contains pkged files compiled into the | ||
// go binaries. | ||
package kubebuilder | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,12 +3,21 @@ module sigs.k8s.io/kubebuilder/v3 | |
go 1.15 | ||
|
||
require ( | ||
github.com/cloudflare/cfssl v1.5.0 // for `kubebuilder alpha config-gen` | ||
github.com/gobuffalo/flect v0.2.2 | ||
// TODO: remove this in favor of embed once using 1.16 | ||
github.com/markbates/pkger v0.17.1 // for `kubebuilder alpha config-gen` | ||
github.com/onsi/ginkgo v1.15.0 | ||
github.com/onsi/gomega v1.10.5 | ||
github.com/spf13/afero v1.2.2 | ||
github.com/spf13/cobra v0.0.7 | ||
github.com/spf13/cobra v1.1.1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you need to update cobra for this PR? I definetely think that bumping cobra is somethign we need to do, but if it is not needed forn this PR we should probably do it in a separate PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No, this is just what happened with I ran There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checking if it works with v0.0.7 and if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Running either There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is ok. |
||
github.com/spf13/pflag v1.0.5 | ||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e | ||
// for `kubebuilder alpha config-gen` | ||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 // indirect | ||
camilamacedo86 marked this conversation as resolved.
Show resolved
Hide resolved
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Which import requires this? Just curious if we could somehow prevent using two different YAML parsers as we are using There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the kustomize fn framework uses this -- it is quite different as it parses the yaml into a tree and keeps comments, formatting, etc There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are the output changes considerable or breaking? Or can we just update the test and remove this indirect require? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. They aren't breaking, but |
||
k8s.io/apimachinery v0.20.2 // for `kubebuilder alpha config-gen` | ||
k8s.io/utils v0.0.0-20210111153108-fddb29f9d009 // indirect | ||
sigs.k8s.io/controller-tools v0.3.0 // for `kubebuilder alpha config-gen` | ||
sigs.k8s.io/kustomize/kyaml v0.10.10 // for `kubebuilder alpha config-gen` | ||
sigs.k8s.io/yaml v1.2.0 | ||
) |
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
/* | ||
Copyright 2021 The Kubernetes Authors. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package cli | ||
|
||
import ( | ||
"strings" | ||
|
||
"github.com/spf13/cobra" | ||
configgen "sigs.k8s.io/kubebuilder/v3/pkg/cli/alpha/config-gen" | ||
) | ||
|
||
var alphaCommands = []*cobra.Command{ | ||
configgen.NewCommand(), | ||
} | ||
|
||
func (c *CLI) newAlphaCmd() *cobra.Command { | ||
alpha := &cobra.Command{ | ||
Use: "alpha", | ||
SuggestFor: []string{"experimental"}, | ||
Short: "Alpha kubebuilder subcommands", | ||
Long: strings.TrimSpace(` | ||
Alpha kubebuilder commands are for unstable features. | ||
|
||
- Alpha commands are exploratory and may be removed without warning. | ||
- No backwards compatibility is provided for any alpha commands. | ||
`), | ||
} | ||
for i := range alphaCommands { | ||
alpha.AddCommand(alphaCommands[i]) | ||
} | ||
return alpha | ||
} | ||
|
||
func (c *CLI) addAlphaCmd() { | ||
if len(alphaCommands) > 0 { | ||
c.cmd.AddCommand(c.newAlphaCmd()) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Config-gen | ||
|
||
`kubebuilder alpha config-gen` is a subcommand that generates configuration for kubebuilder projects as a configuration function. | ||
|
||
Supports: | ||
|
||
- Generating CRDs and RBAC from code | ||
- Generating webhook certificates for development | ||
- Selectively enabling / disabling components such as prometheus and webhooks | ||
- See [types.go](apis/v1alpha1/types.go) for a list of components | ||
|
||
## Usage | ||
|
||
`config-gen` may be run as a standalone command or from kustomize as a transformer plugin. | ||
|
||
### Standalone command | ||
|
||
config-gen may be run as a standalone program on the commandline. | ||
|
||
See [examples/standalone](examples/standalone/README.md) | ||
|
||
### From kustomize | ||
|
||
config-gen may be run as a Kustomize plugin using kustomize. | ||
|
||
See [examples/kustomize](examples/kustomize/README.md) | ||
|
||
### Extending `config-gen` | ||
|
||
config-gen may be extended by composing additional functions on top of it. | ||
|
||
See examples of layering additional functions on: | ||
|
||
- [examples/basicextension](examples/basicextension/README.md) | ||
- [examples/advancedextension](examples/advancedextension/README.md) | ||
|
||
## `KubebuilderConfigGen` | ||
|
||
See [types.go](apis/v1alpha1/types.go) for KubebuilderConfigGen schema. | ||
|
||
See [testdata](apis/v1alpha1/testdata) for examples of configuration options. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
/* | ||
Copyright 2021 The Kubernetes Authors. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package configgen | ||
|
||
import ( | ||
"encoding/base64" | ||
"fmt" | ||
|
||
"github.com/cloudflare/cfssl/cli/genkey" | ||
"github.com/cloudflare/cfssl/config" | ||
"github.com/cloudflare/cfssl/csr" | ||
"github.com/cloudflare/cfssl/helpers" | ||
"github.com/cloudflare/cfssl/selfsign" | ||
"sigs.k8s.io/kustomize/kyaml/fn/framework" | ||
"sigs.k8s.io/kustomize/kyaml/kio" | ||
"sigs.k8s.io/kustomize/kyaml/yaml" | ||
) | ||
|
||
var _ kio.Filter = &CertFilter{} | ||
|
||
// CertFilter generates and injects certificates into webhook | ||
type CertFilter struct { | ||
*KubebuilderConfigGen | ||
} | ||
|
||
// Filter implements kio.Filter | ||
func (c CertFilter) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { | ||
|
||
if c.Spec.Webhooks.CertificateSource.Type != "dev" { | ||
return input, nil | ||
} | ||
if err := c.generateCert(); err != nil { | ||
return nil, err | ||
} | ||
|
||
s := &framework.Selector{ | ||
Kinds: []string{ | ||
"ValidatingWebhookConfiguration", | ||
"MutatingWebhookConfiguration", | ||
}, | ||
} | ||
matches, err := s.GetMatches(&framework.ResourceList{Items: input}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for i := range matches { | ||
wh := matches[i].Field("webhooks") | ||
if wh.IsNilOrEmpty() { | ||
continue | ||
} | ||
err := wh.Value.VisitElements(func(node *yaml.RNode) error { | ||
err := node.PipeE(yaml.LookupCreate(yaml.ScalarNode, "clientConfig", "caBundle"), | ||
yaml.FieldSetter{StringValue: c.Status.CertCA}) | ||
if err != nil { | ||
return err | ||
} | ||
err = node.PipeE(yaml.LookupCreate(yaml.ScalarNode, "clientConfig", "service", "namespace"), | ||
yaml.FieldSetter{StringValue: c.Namespace}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
s = &framework.Selector{ | ||
Filter: func(n *yaml.RNode) bool { | ||
// Allow-list conversion webhooks | ||
m, _ := n.GetMeta() | ||
if m.Kind != "CustomResourceDefinition" { | ||
return true | ||
} | ||
return c.Spec.Webhooks.Conversions[m.Name] | ||
}, | ||
} | ||
matches, err = s.GetMatches(&framework.ResourceList{Items: input}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
for i := range matches { | ||
err := matches[i].PipeE(yaml.LookupCreate(yaml.ScalarNode, "spec", "conversion", "strategy"), | ||
yaml.FieldSetter{StringValue: "Webhook"}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
err = matches[i].PipeE(yaml.LookupCreate( | ||
yaml.ScalarNode, "spec", "conversion", "webhookClientConfig", "caBundle"), | ||
yaml.FieldSetter{StringValue: c.Status.CertCA}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
err = matches[i].PipeE(yaml.LookupCreate( | ||
yaml.ScalarNode, "spec", "conversion", "webhookClientConfig", "service", "name"), | ||
yaml.FieldSetter{StringValue: "webhook-service"}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
err = matches[i].PipeE(yaml.LookupCreate( | ||
yaml.ScalarNode, "spec", "conversion", "webhookClientConfig", "service", "namespace"), | ||
yaml.FieldSetter{StringValue: c.Namespace}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
err = matches[i].PipeE(yaml.LookupCreate( | ||
yaml.ScalarNode, "spec", "conversion", "webhookClientConfig", "service", "path"), | ||
yaml.FieldSetter{StringValue: "/convert"}) | ||
if err != nil { | ||
return nil, err | ||
} | ||
} | ||
|
||
return input, nil | ||
} | ||
|
||
func (c CertFilter) generateCert() error { | ||
var err error | ||
var req = csr.New() | ||
req.Hosts = []string{ | ||
fmt.Sprintf("webhook-service.%s.svc", c.Namespace), | ||
fmt.Sprintf("webhook-service.%s.svc.cluster.local", c.Namespace), | ||
} | ||
req.CN = "kb-dev-controller-manager" | ||
|
||
var key, csrPEM []byte | ||
g := &csr.Generator{Validator: genkey.Validator} | ||
csrPEM, key, err = g.ProcessRequest(req) | ||
if err != nil { | ||
return err | ||
} | ||
priv, err := helpers.ParsePrivateKeyPEM(key) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
profile := config.DefaultConfig() | ||
profile.Expiry = c.Spec.Webhooks.CertificateSource.DevCertificate.CertDuration | ||
cert, err := selfsign.Sign(priv, csrPEM, profile) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
c.Status.CertCA = base64.StdEncoding.EncodeToString(cert) | ||
c.Status.CertKey = base64.StdEncoding.EncodeToString(key) | ||
return nil | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/* | ||
Copyright 2021 The Kubernetes Authors. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package configgen | ||
|
||
import ( | ||
"github.com/markbates/pkger" | ||
"sigs.k8s.io/kustomize/kyaml/fn/framework" | ||
) | ||
|
||
// CertManagerPatchTemplate returns the PatchTemplate for cert-manager | ||
func CertManagerPatchTemplate(_ *KubebuilderConfigGen) framework.PT { | ||
return framework.PT{ | ||
// keep casting -- required by pkger to find the directory | ||
Dir: pkger.Dir("/pkg/cli/alpha/config-gen/templates/patches/cert-manager"), | ||
Selector: func() *framework.Selector { | ||
return &framework.Selector{ | ||
Kinds: []string{ | ||
"CustomResourceDefinition", | ||
"ValidatingWebhookConfiguration", | ||
"MutatingWebhookConfiguration", | ||
}, | ||
} | ||
}, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is
pkger
being used for?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To include the templates statically in the binary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be achieved with
embed
in 1.16?(I'm not suggesting to change it, we are not supporting 1.16 yet)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I believe so. :). (Yay)