Skip to content

Commit

Permalink
(manifests/v2) add support for webhooks by default and docs (#4623)
Browse files Browse the repository at this point in the history
Signed-off-by: Eric Stroczynski <ericstroczynski@gmail.com>
  • Loading branch information
Eric Stroczynski committed Mar 19, 2021
1 parent 640ddc7 commit 163c657
Show file tree
Hide file tree
Showing 18 changed files with 419 additions and 93 deletions.
32 changes: 32 additions & 0 deletions changelog/fragments/bugfix-csv-webhooks.yaml
@@ -0,0 +1,32 @@
entries:
- description: >
(manifests/v2) Added a `config/manifests` kustomize patch to remove the cert-manager
volume and volumeMount from manifests destined for `generate <bundle|packagemanifests>`
kind: bugfix
migration:
header: (manifests/v2) Add a kustomize patch to remove the cert-manager volume/volumeMount from your CSV
body: >
OLM does [not yet support cert-manager](https://olm.operatorframework.io/docs/advanced-tasks/adding-admission-and-conversion-webhooks/#certificate-authority-requirements),
so a JSON patch was added to remove this volume and mount such that
OLM can itself create and manage certs for your Operator.
In `config/manifests/kustomization.yaml`, add the following:
```yaml
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: controller-manager
namespace: system
patch: |-
# Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs.
# Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment.
- op: remove
path: /spec/template/spec/containers/1/volumeMounts/0
# Remove the "cert" volume, since OLM will create and mount a set of certs.
# Update the indices in this path if adding or removing volumes in the manager's Deployment.
- op: remove
path: /spec/template/spec/volumes/0
```
62 changes: 41 additions & 21 deletions hack/generate/samples/internal/go/v2/memcached_with_webhooks.go
Expand Up @@ -90,7 +90,8 @@ func (mh *MemcachedGoWithWebhooks) Run() {
pkg.CheckError("scaffolding webhook", err)

mh.implementingWebhooks()
mh.uncommentKustomizationFile()
mh.uncommentDefaultKustomization()
mh.uncommentManifestsKustomization()

log.Infof("creating the bundle")
err = mh.ctx.GenerateBundle()
Expand All @@ -106,35 +107,28 @@ func (mh *MemcachedGoWithWebhooks) Run() {
pkg.CheckError("cleaning up", os.RemoveAll(filepath.Join(mh.ctx.Dir, "bin")))
}

// uncommentKustomizationFile will uncomment the file kustomization.yaml
func (mh *MemcachedGoWithWebhooks) uncommentKustomizationFile() {
log.Infof("uncomment kustomization.yaml to enable webhook and ca injection")
err := testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- ../webhook", "#")
// uncommentDefaultKustomization will uncomment code in config/default/kustomization.yaml
func (mh *MemcachedGoWithWebhooks) uncommentDefaultKustomization() {
var err error
kustomization := filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml")
log.Info("uncommenting config/default/kustomization.yaml to enable webhooks and ca injection")

err = testutils.UncommentCode(kustomization, "#- ../webhook", "#")
pkg.CheckError("uncomment webhook", err)

err = testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- ../certmanager", "#")
err = testutils.UncommentCode(kustomization, "#- ../certmanager", "#")
pkg.CheckError("uncomment certmanager", err)

err = testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- ../prometheus", "#")
err = testutils.UncommentCode(kustomization, "#- ../prometheus", "#")
pkg.CheckError("uncomment prometheus", err)

err = testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- manager_webhook_patch.yaml", "#")
err = testutils.UncommentCode(kustomization, "#- manager_webhook_patch.yaml", "#")
pkg.CheckError("uncomment manager_webhook_patch.yaml", err)

err = testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- webhookcainjection_patch.yaml", "#")
err = testutils.UncommentCode(kustomization, "#- webhookcainjection_patch.yaml", "#")
pkg.CheckError("uncomment webhookcainjection_patch.yaml", err)

err = testutils.UncommentCode(filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
err = testutils.UncommentCode(kustomization,
`#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
# objref:
# kind: Certificate
Expand Down Expand Up @@ -164,6 +158,32 @@ func (mh *MemcachedGoWithWebhooks) uncommentKustomizationFile() {
pkg.CheckError("uncommented certificate CR", err)
}

// uncommentManifestsKustomization will uncomment code in config/manifests/kustomization.yaml
func (mh *MemcachedGoWithWebhooks) uncommentManifestsKustomization() {
var err error
kustomization := filepath.Join(mh.ctx.Dir, "config", "manifests", "kustomization.yaml")
log.Info("uncommenting config/manifests/kustomization.yaml to enable webhooks in OLM")

err = testutils.UncommentCode(kustomization,
`#patchesJson6902:
#- target:
# group: apps
# version: v1
# kind: Deployment
# name: controller-manager
# namespace: system
# patch: |-
# # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs.
# # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment.
# - op: remove
# path: /spec/template/spec/containers/1/volumeMounts/0
# # Remove the "cert" volume, since OLM will create and mount a set of certs.
# # Update the indices in this path if adding or removing volumes in the manager's Deployment.
# - op: remove
# path: /spec/template/spec/volumes/0`, "#")
pkg.CheckError("uncommented webhook volume removal patch", err)
}

// implementingWebhooks will customize the kind wekbhok file
func (mh *MemcachedGoWithWebhooks) implementingWebhooks() {
log.Infof("implementing webhooks")
Expand Down Expand Up @@ -327,7 +347,7 @@ const reconcileFragment = `// Fetch the Memcached instance
return ctrl.Result{}, err
}
// Ask to requeue after 1 minute in order to give enough time for the
// pods be created on the cluster side and the operand be able
// pods be created on the cluster side and the operand be able
// to do the next update step accurately.
return ctrl.Result{RequeueAfter: time.Minute }, nil
}
Expand Down
62 changes: 41 additions & 21 deletions hack/generate/samples/internal/go/v3/memcached_with_webhooks.go
Expand Up @@ -90,7 +90,8 @@ func (mh *MemcachedGoWithWebhooks) Run() {
pkg.CheckError("scaffolding webhook", err)

mh.implementingWebhooks()
mh.uncommentKustomizationFile()
mh.uncommentDefaultKustomization()
mh.uncommentManifestsKustomization()

log.Infof("creating the bundle")
err = mh.ctx.GenerateBundle()
Expand All @@ -106,35 +107,28 @@ func (mh *MemcachedGoWithWebhooks) Run() {
pkg.CheckError("cleaning up", os.RemoveAll(filepath.Join(mh.ctx.Dir, "bin")))
}

// uncommentKustomizationFile will uncomment the file kustomization.yaml
func (mh *MemcachedGoWithWebhooks) uncommentKustomizationFile() {
log.Infof("uncomment kustomization.yaml to enable webhook and ca injection")
err := testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- ../webhook", "#")
// uncommentDefaultKustomization will uncomment code in config/default/kustomization.yaml
func (mh *MemcachedGoWithWebhooks) uncommentDefaultKustomization() {
var err error
kustomization := filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml")
log.Info("uncommenting config/default/kustomization.yaml to enable webhooks and ca injection")

err = testutils.UncommentCode(kustomization, "#- ../webhook", "#")
pkg.CheckError("uncomment webhook", err)

err = testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- ../certmanager", "#")
err = testutils.UncommentCode(kustomization, "#- ../certmanager", "#")
pkg.CheckError("uncomment certmanager", err)

err = testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- ../prometheus", "#")
err = testutils.UncommentCode(kustomization, "#- ../prometheus", "#")
pkg.CheckError("uncomment prometheus", err)

err = testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- manager_webhook_patch.yaml", "#")
err = testutils.UncommentCode(kustomization, "#- manager_webhook_patch.yaml", "#")
pkg.CheckError("uncomment manager_webhook_patch.yaml", err)

err = testutils.UncommentCode(
filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
"#- webhookcainjection_patch.yaml", "#")
err = testutils.UncommentCode(kustomization, "#- webhookcainjection_patch.yaml", "#")
pkg.CheckError("uncomment webhookcainjection_patch.yaml", err)

err = testutils.UncommentCode(filepath.Join(mh.ctx.Dir, "config", "default", "kustomization.yaml"),
err = testutils.UncommentCode(kustomization,
`#- name: CERTIFICATE_NAMESPACE # namespace of the certificate CR
# objref:
# kind: Certificate
Expand Down Expand Up @@ -164,6 +158,32 @@ func (mh *MemcachedGoWithWebhooks) uncommentKustomizationFile() {
pkg.CheckError("uncommented certificate CR", err)
}

// uncommentManifestsKustomization will uncomment code in config/manifests/kustomization.yaml
func (mh *MemcachedGoWithWebhooks) uncommentManifestsKustomization() {
var err error
kustomization := filepath.Join(mh.ctx.Dir, "config", "manifests", "kustomization.yaml")
log.Info("uncommenting config/manifests/kustomization.yaml to enable webhooks in OLM")

err = testutils.UncommentCode(kustomization,
`#patchesJson6902:
#- target:
# group: apps
# version: v1
# kind: Deployment
# name: controller-manager
# namespace: system
# patch: |-
# # Remove the manager container's "cert" volumeMount, since OLM will create and mount a set of certs.
# # Update the indices in this path if adding or removing containers/volumeMounts in the manager's Deployment.
# - op: remove
# path: /spec/template/spec/containers/1/volumeMounts/0
# # Remove the "cert" volume, since OLM will create and mount a set of certs.
# # Update the indices in this path if adding or removing volumes in the manager's Deployment.
# - op: remove
# path: /spec/template/spec/volumes/0`, "#")
pkg.CheckError("uncommented webhook volume removal patch", err)
}

// implementingWebhooks will customize the kind wekbhok file
func (mh *MemcachedGoWithWebhooks) implementingWebhooks() {
log.Infof("implementing webhooks")
Expand Down Expand Up @@ -321,7 +341,7 @@ const reconcileFragment = `// Fetch the Memcached instance
return ctrl.Result{}, err
}
// Ask to requeue after 1 minute in order to give enough time for the
// pods be created on the cluster side and the operand be able
// pods be created on the cluster side and the operand be able
// to do the next update step accurately.
return ctrl.Result{RequeueAfter: time.Minute }, nil
}
Expand Down
25 changes: 13 additions & 12 deletions internal/cmd/operator-sdk/generate/kustomize/manifests.go
Expand Up @@ -22,17 +22,20 @@ import (
"strings"

log "github.com/sirupsen/logrus"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/validation"
"sigs.k8s.io/kubebuilder/v3/pkg/config"
cfgv2 "sigs.k8s.io/kubebuilder/v3/pkg/config/v2"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/model/file"
"sigs.k8s.io/yaml"

genutil "github.com/operator-framework/operator-sdk/internal/cmd/operator-sdk/generate/internal"
"github.com/operator-framework/operator-sdk/internal/generate/clusterserviceversion/bases"
"github.com/operator-framework/operator-sdk/internal/plugins/util/kustomize"
manifestsv2 "github.com/operator-framework/operator-sdk/internal/plugins/manifests/v2"
"github.com/operator-framework/operator-sdk/internal/util/k8sutil"
"github.com/operator-framework/operator-sdk/internal/util/projutil"
)
Expand Down Expand Up @@ -161,14 +164,6 @@ func (c *manifestsCmd) setDefaults(cfg config.Config) error {
return nil
}

// kustomization.yaml file contents for manifests. this should always be written to
// config/manifests/kustomization.yaml since it only references files in config.
const manifestsKustomization = `resources:
- ../default
- ../samples
- ../scorecard
`

// run generates kustomize bundle bases and a kustomization.yaml if one does not exist.
func (c manifestsCmd) run(cfg config.Config) error {

Expand All @@ -188,6 +183,7 @@ func (c manifestsCmd) run(cfg config.Config) error {
}
}

operatorType := projutil.PluginKeyToOperatorType(cfg.GetPluginChain())
relBasePath := filepath.Join("bases", c.packageName+".clusterserviceversion.yaml")
basePath := filepath.Join(c.inputDir, relBasePath)
gvks, err := getGVKs(cfg)
Expand All @@ -196,7 +192,7 @@ func (c manifestsCmd) run(cfg config.Config) error {
}
base := bases.ClusterServiceVersion{
OperatorName: c.packageName,
OperatorType: projutil.PluginKeyToOperatorType(cfg.GetPluginChain()),
OperatorType: operatorType,
APIsDir: c.apisDir,
Interactive: requiresInteraction(basePath, c.interactiveLevel),
GVKs: gvks,
Expand Down Expand Up @@ -224,8 +220,13 @@ func (c manifestsCmd) run(cfg config.Config) error {
}

// Write a kustomization.yaml to outputDir if one does not exist.
if err := kustomize.WriteIfNotExist(c.outputDir, manifestsKustomization); err != nil {
return fmt.Errorf("error writing kustomization.yaml: %v", err)
kustomization := manifestsv2.Kustomization{SupportsWebhooks: operatorType == projutil.OperatorTypeGo}
kustomization.IfExistsAction = file.Skip
err = machinery.NewScaffold(machinery.Filesystem{FS: afero.NewOsFs()}, machinery.WithConfig(cfg)).Execute(
&kustomization,
)
if err != nil {
return fmt.Errorf("error scaffolding manifests: %v", err)
}

if !c.quiet {
Expand Down
6 changes: 3 additions & 3 deletions internal/plugins/ansible/v1/init.go
Expand Up @@ -133,7 +133,7 @@ func (p *initSubcommand) Run(fs machinery.Filesystem) error {
}

// Run SDK phase 2 plugins.
if err := p.runPhase2(); err != nil {
if err := p.runPhase2(fs); err != nil {
return err
}

Expand All @@ -149,8 +149,8 @@ func (p *initSubcommand) Run(fs machinery.Filesystem) error {
}

// SDK phase 2 plugins.
func (p *initSubcommand) runPhase2() error {
if err := manifestsv2.RunInit(p.config); err != nil {
func (p *initSubcommand) runPhase2(fs machinery.Filesystem) error {
if err := manifestsv2.RunInit(p.config, fs); err != nil {
return err
}
if err := scorecardv2.RunInit(p.config); err != nil {
Expand Down
6 changes: 3 additions & 3 deletions internal/plugins/golang/v2/init.go
Expand Up @@ -47,19 +47,19 @@ func (p *initSubcommand) Run(fs machinery.Filesystem) error {
}

// Run SDK phase 2 plugins.
if err := p.runPhase2(); err != nil {
if err := p.runPhase2(fs); err != nil {
return err
}

return nil
}

// SDK phase 2 plugins.
func (p *initSubcommand) runPhase2() error {
func (p *initSubcommand) runPhase2(fs machinery.Filesystem) error {
if err := envtest.RunInit(p.config); err != nil {
return err
}
if err := manifestsv2.RunInit(p.config); err != nil {
if err := manifestsv2.RunInit(p.config, fs); err != nil {
return err
}
if err := scorecardv2.RunInit(p.config); err != nil {
Expand Down
6 changes: 3 additions & 3 deletions internal/plugins/golang/v3/init.go
Expand Up @@ -46,16 +46,16 @@ func (p *initSubcommand) Run(fs machinery.Filesystem) error {
}

// Run SDK phase 2 plugins.
if err := p.runPhase2(); err != nil {
if err := p.runPhase2(fs); err != nil {
return err
}

return nil
}

// SDK phase 2 plugins.
func (p *initSubcommand) runPhase2() error {
if err := manifestsv2.RunInit(p.config); err != nil {
func (p *initSubcommand) runPhase2(fs machinery.Filesystem) error {
if err := manifestsv2.RunInit(p.config, fs); err != nil {
return err
}
if err := scorecardv2.RunInit(p.config); err != nil {
Expand Down
6 changes: 3 additions & 3 deletions internal/plugins/helm/v1/init.go
Expand Up @@ -161,7 +161,7 @@ func (p *initSubcommand) Run(fs machinery.Filesystem) error {
}

// Run SDK phase 2 plugins.
if err := p.runPhase2(); err != nil {
if err := p.runPhase2(fs); err != nil {
return err
}

Expand All @@ -177,8 +177,8 @@ func (p *initSubcommand) Run(fs machinery.Filesystem) error {
}

// SDK phase 2 plugins.
func (p *initSubcommand) runPhase2() error {
if err := manifestsv2.RunInit(p.config); err != nil {
func (p *initSubcommand) runPhase2(fs machinery.Filesystem) error {
if err := manifestsv2.RunInit(p.config, fs); err != nil {
return err
}
if err := scorecardv2.RunInit(p.config); err != nil {
Expand Down

0 comments on commit 163c657

Please sign in to comment.