diff --git a/internal/plugins/golang/v2/api.go b/internal/plugins/golang/v2/api.go index 0af4da5382..27ca5278dc 100644 --- a/internal/plugins/golang/v2/api.go +++ b/internal/plugins/golang/v2/api.go @@ -15,21 +15,12 @@ package v2 import ( - "fmt" - "path/filepath" - "strings" - - "github.com/operator-framework/operator-sdk/internal/scaffold/kustomize" - "github.com/spf13/pflag" "sigs.k8s.io/kubebuilder/pkg/model/config" "sigs.k8s.io/kubebuilder/pkg/plugin" -) -// sampleKustomizationFragment is a template for samples/kustomization.yaml. -const sampleKustomizationFragment = `## This file is auto-generated, do not modify ## -resources: -` + utilplugins "github.com/operator-framework/operator-sdk/internal/util/plugins" +) type createAPIPlugin struct { plugin.CreateAPI @@ -63,23 +54,5 @@ func (p *createAPIPlugin) Run() error { // SDK plugin-specific scaffolds. func (p *createAPIPlugin) run() error { - - // Write CR paths to the samples' kustomization file. This file has a - // "do not modify" comment so it is safe to overwrite. - samplesKustomization := sampleKustomizationFragment - for _, gvk := range p.config.Resources { - samplesKustomization += fmt.Sprintf("- %s\n", makeCRFileName(gvk)) - } - kpath := filepath.Join("config", "samples") - if err := kustomize.Write(kpath, samplesKustomization); err != nil { - return err - } - - return nil -} - -// makeCRFileName returns a Custom Resource example file name in the same format -// as kubebuilder's CreateAPI plugin for a gvk. -func makeCRFileName(gvk config.GVK) string { - return fmt.Sprintf("%s_%s_%s.yaml", gvk.Group, gvk.Version, strings.ToLower(gvk.Kind)) + return utilplugins.WriteSamplesKustomization(p.config) } diff --git a/internal/plugins/golang/v2/init.go b/internal/plugins/golang/v2/init.go index 8dd7930e57..1e00261d55 100644 --- a/internal/plugins/golang/v2/init.go +++ b/internal/plugins/golang/v2/init.go @@ -16,11 +16,12 @@ package v2 import ( "fmt" - "io/ioutil" "github.com/spf13/pflag" "sigs.k8s.io/kubebuilder/pkg/model/config" "sigs.k8s.io/kubebuilder/pkg/plugin" + + utilplugins "github.com/operator-framework/operator-sdk/internal/util/plugins" ) type initPlugin struct { @@ -45,9 +46,8 @@ func (p *initPlugin) Run() error { } // Update the scaffolded Makefile with operator-sdk recipes. - // TODO: rewrite this when plugins phase 2 is implemented. - if err := initUpdateMakefile("Makefile"); err != nil { - return fmt.Errorf("error updating Makefile: %v", err) + if err := p.run(); err != nil { + return err } // Update plugin config section with this plugin's configuration. @@ -59,49 +59,7 @@ func (p *initPlugin) Run() error { return nil } -// initUpdateMakefile updates a vanilla kubebuilder Makefile with operator-sdk recipes. -func initUpdateMakefile(filePath string) error { - makefileBytes, err := ioutil.ReadFile(filePath) - if err != nil { - return err - } - - // Prepend bundle variables. - makefileBytes = append([]byte(makefileBundleVarFragment), makefileBytes...) - // Append bundle recipes. - makefileBytes = append(makefileBytes, []byte(makefileBundleFragment)...) - makefileBytes = append(makefileBytes, []byte(makefileBundleBuildFragment)...) - - return ioutil.WriteFile(filePath, makefileBytes, 0644) +// SDK plugin-specific scaffolds. +func (p *initPlugin) run() error { + return utilplugins.UpdateMakefile(p.config) } - -// Makefile fragments to add to the base Makefile. -const ( - makefileBundleVarFragment = `# Current Operator version -VERSION ?= 0.0.1 -# Default bundle image tag -BUNDLE_IMG ?= controller-bundle:$(VERSION) -# Options for 'bundle-build' -ifneq ($(origin CHANNELS), undefined) -BUNDLE_CHANNELS := --channels=$(CHANNELS) -endif -ifneq ($(origin DEFAULT_CHANNEL), undefined) -BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) -endif -BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) -` - - makefileBundleFragment = ` -# Generate bundle manifests and metadata, then validate generated files. -bundle: manifests - operator-sdk generate kustomize manifests -q - kustomize build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) - operator-sdk bundle validate ./bundle -` - - makefileBundleBuildFragment = ` -# Build the bundle image. -bundle-build: - docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . -` -) diff --git a/internal/util/plugins/makefile.go b/internal/util/plugins/makefile.go new file mode 100644 index 0000000000..8b8550358c --- /dev/null +++ b/internal/util/plugins/makefile.go @@ -0,0 +1,101 @@ +// Copyright 2020 The Operator-SDK 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. + +// TODO: rewrite this when plugins phase 2 is implemented. +package plugins + +import ( + "fmt" + "io/ioutil" + + "sigs.k8s.io/kubebuilder/pkg/model/config" + + "github.com/operator-framework/operator-sdk/internal/util/projutil" +) + +// UpdateMakefile modifies the project scaffolded by kubebuilder's Init plugin. +func UpdateMakefile(cfg *config.Config) error { + // Update the scaffolded Makefile with operator-sdk recipes. + if err := initUpdateMakefile("Makefile", cfg); err != nil { + return fmt.Errorf("error updating Makefile: %v", err) + } + return nil +} + +// initUpdateMakefile updates a vanilla kubebuilder Makefile with operator-sdk recipes. +func initUpdateMakefile(filePath string, cfg *config.Config) error { + makefileBytes, err := ioutil.ReadFile(filePath) + if err != nil { + return err + } + + // Prepend bundle variables. + makefileBytes = append([]byte(makefileBundleVarFragment), makefileBytes...) + + // Append bundle recipes. + operatorType := projutil.PluginKeyToOperatorType(cfg.Layout) + switch operatorType { + case projutil.OperatorTypeUnknown: + return fmt.Errorf("unsupported plugin key %q", cfg.Layout) + case projutil.OperatorTypeGo: + makefileBytes = append(makefileBytes, []byte(makefileBundleFragmentGo)...) + default: + makefileBytes = append(makefileBytes, []byte(makefileBundleFragmentNonGo)...) + } + + makefileBytes = append(makefileBytes, []byte(makefileBundleBuildFragment)...) + + return ioutil.WriteFile(filePath, makefileBytes, 0644) +} + +// Makefile fragments to add to the base Makefile. +const ( + makefileBundleVarFragment = `# Current Operator version +VERSION ?= 0.0.1 +# Default bundle image tag +BUNDLE_IMG ?= controller-bundle:$(VERSION) +# Options for 'bundle-build' +ifneq ($(origin CHANNELS), undefined) +BUNDLE_CHANNELS := --channels=$(CHANNELS) +endif +ifneq ($(origin DEFAULT_CHANNEL), undefined) +BUNDLE_DEFAULT_CHANNEL := --default-channel=$(DEFAULT_CHANNEL) +endif +BUNDLE_METADATA_OPTS ?= $(BUNDLE_CHANNELS) $(BUNDLE_DEFAULT_CHANNEL) + +.PHONY: bundle +` + + makefileBundleFragmentGo = ` +# Generate bundle manifests and metadata, then validate generated files. +bundle: manifests + operator-sdk generate kustomize manifests -q + $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) + operator-sdk bundle validate ./bundle +` + + makefileBundleFragmentNonGo = ` +# Generate bundle manifests and metadata, then validate generated files. +bundle: kustomize + operator-sdk generate kustomize manifests -q + $(KUSTOMIZE) build config/manifests | operator-sdk generate bundle -q --overwrite --version $(VERSION) $(BUNDLE_METADATA_OPTS) + operator-sdk bundle validate ./bundle +` + + makefileBundleBuildFragment = ` +# Build the bundle image. +bundle-build: + docker build -f bundle.Dockerfile -t $(BUNDLE_IMG) . +` +) diff --git a/internal/util/plugins/samples.go b/internal/util/plugins/samples.go new file mode 100644 index 0000000000..71c3e187ab --- /dev/null +++ b/internal/util/plugins/samples.go @@ -0,0 +1,57 @@ +// Copyright 2020 The Operator-SDK 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. + +// TODO: rewrite this when plugins phase 2 is implemented. +package plugins + +import ( + "fmt" + "path/filepath" + "strings" + + "sigs.k8s.io/kubebuilder/pkg/model/config" + + "github.com/operator-framework/operator-sdk/internal/scaffold/kustomize" +) + +// sampleKustomizationFragment is a template for samples/kustomization.yaml. +const sampleKustomizationFragment = `## This file is auto-generated, do not modify ## +resources: +` + +// WriteSamplesKustomization perform the SDK plugin-specific scaffolds. +func WriteSamplesKustomization(cfg *config.Config) error { + + // Write CR paths to the samples' kustomization file. This file has a + // "do not modify" comment so it is safe to overwrite. + samplesKustomization := sampleKustomizationFragment + for _, gvk := range cfg.Resources { + samplesKustomization += fmt.Sprintf("- %s\n", makeCRFileName(gvk)) + } + kpath := filepath.Join("config", "samples") + if err := kustomize.Write(kpath, samplesKustomization); err != nil { + return err + } + + return nil +} + +// todo(camilamacedo86): Now that we have the Kubebuilder scaffolding machinery included in our repo, we could make +// this an actual template that supports both file.Template and file.Inserter for init and create api, respectively. +// More info: https://github.com/operator-framework/operator-sdk/issues/3370 +// makeCRFileName returns a Custom Resource example file name in the same format +// as kubebuilder's CreateAPI plugin for a gvk. +func makeCRFileName(gvk config.GVK) string { + return fmt.Sprintf("%s_%s_%s.yaml", gvk.Group, gvk.Version, strings.ToLower(gvk.Kind)) +}