Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/operator-framework/operator-lib v0.3.0
github.com/prometheus/client_golang v1.7.1
github.com/sirupsen/logrus v1.7.0
github.com/spf13/afero v1.2.2
github.com/spf13/cobra v1.1.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.6.1
Expand Down
127 changes: 127 additions & 0 deletions pkg/plugins/hybrid/v1alpha/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright 2021 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.

package v1alpha

import (
"fmt"

"github.com/operator-framework/helm-operator-plugins/pkg/plugins/hybrid/v1alpha/scaffolds"
"github.com/spf13/pflag"
"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/util"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang"
)

type initSubcommand struct {
config config.Config

// For help text
commandName string

// boilerplate options
license string
owner string

// go config options
repo string
}

var _ plugin.InitSubcommand = &initSubcommand{}

// UpdateMetadata defines plugin context
func (p *initSubcommand) UpdateMetadata(cliMeta plugin.CLIMetadata, subcmdMeta *plugin.SubcommandMetadata) {
subcmdMeta.Description = `Initialize a new project including the following files:
- a "go.mod" with project dependencies
- a "PROJECT" file that stores project configuration
- a "Makefile" with several useful make targets for the project
- several YAML files for project deployment under the "config" directory
- a "main.go" file that creates the manager that will run the project controllers
`
subcmdMeta.Examples = fmt.Sprintf(` # Initialize a new project with your domain and name in copyright
$ %[1]s init --plugins=%[2]s --domain=example.com --owner "Your Name"

# Initialize a new project defining a specific project version
%[1]s init --plugins=%[2]s --project-version 3
`, cliMeta.CommandName, pluginKey)

p.commandName = cliMeta.CommandName
}

func (p *initSubcommand) BindFlags(fs *pflag.FlagSet) {
fs.SortFlags = false

// project args
fs.StringVar(&p.repo, "repo", "", "name to use for go module (e.g., github.com/user/repo), "+
"defaults to the go package of the current working directory.")

// boilerplate args
fs.StringVar(&p.license, "license", "apache2",
"license to use to boilerplate, may be one of 'apache2', 'none'")
fs.StringVar(&p.owner, "owner", "", "owner to add to the copyright")

}

func (p *initSubcommand) InjectConfig(c config.Config) error {
p.config = c

// Try to guess repository if flag is not set
if p.repo == "" {
repoPath, err := golang.FindCurrentRepo()
if err != nil {
return fmt.Errorf("error finding current repository: %v", err)
}
p.repo = repoPath
}

if err := p.config.SetRepository(p.repo); err != nil {
return err
}
return nil
}

// TODO:
// 1. Pre-scaffold check to verify if the right Go version and directory is used.
// This needs to be added from Kubebuilder.
// 2. Verify if additional customizations are needed in config files as done in
// helm operator.
func (p *initSubcommand) Scaffold(fs machinery.Filesystem) error {

scaffolder := scaffolds.NewInitScaffolder(p.config, p.license, p.owner)
scaffolder.InjectFS(fs)
err := scaffolder.Scaffold()
if err != nil {
return err
}

// Ensure that we are pinning the controller-runtime version
// xref: https://github.com/kubernetes-sigs/kubebuilder/issues/997
err = util.RunCmd("Get controller runtime", "go", "get",
"sigs.k8s.io/controller-runtime@"+scaffolds.ControllerRuntimeVersion)
if err != nil {
return err
}
return nil
}

func (p *initSubcommand) PostScaffold() error {
err := util.RunCmd("Update dependencies", "go", "mod", "tidy")
if err != nil {
return err
}

return nil
}
44 changes: 44 additions & 0 deletions pkg/plugins/hybrid/v1alpha/plugin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 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.

package v1alpha

import (
"sigs.k8s.io/kubebuilder/v3/pkg/config"
cfgv3 "sigs.k8s.io/kubebuilder/v3/pkg/config/v3"
"sigs.k8s.io/kubebuilder/v3/pkg/model/stage"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
)

const pluginName = "hybrid.helm.sdk.operatorframework.io"

var (
pluginVersion = plugin.Version{Number: 1, Stage: stage.Alpha}
supportedProjectVersions = []config.Version{cfgv3.Version}
pluginKey = plugin.KeyFor(Plugin{})
)

var (
_ plugin.Plugin = Plugin{}
_ plugin.Init = Plugin{}
)

type Plugin struct {
initSubcommand
}

func (Plugin) Name() string { return pluginName }
func (Plugin) Version() plugin.Version { return pluginVersion }
func (Plugin) SupportedProjectVersions() []config.Version { return supportedProjectVersions }
func (p Plugin) GetInitSubcommand() plugin.InitSubcommand { return &p.initSubcommand }
139 changes: 139 additions & 0 deletions pkg/plugins/hybrid/v1alpha/scaffolds/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
Copyright 2019 The Kubernetes Authors.
Modifications 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.
*/

package scaffolds

import (
"fmt"

"github.com/operator-framework/helm-operator-plugins/pkg/plugins/hybrid/v1alpha/scaffolds/internal/templates"
"github.com/operator-framework/helm-operator-plugins/pkg/plugins/hybrid/v1alpha/scaffolds/internal/templates/hack"
"github.com/operator-framework/helm-operator-plugins/pkg/plugins/hybrid/v1alpha/scaffolds/internal/templates/rbac"
"github.com/spf13/afero"
"sigs.k8s.io/kubebuilder/v3/pkg/config"
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/util"
"sigs.k8s.io/kubebuilder/v3/pkg/plugins"
)

const (
// ControllerRuntimeVersion is the kubernetes-sigs/controller-runtime version to be used in the project
ControllerRuntimeVersion = "v0.8.3"
// ControllerToolsVersion is the kubernetes-sigs/controller-tools version to be used in the project
ControllerToolsVersion = "v0.5.0"
// KustomizeVersion is the kubernetes-sigs/kustomize version to be used in the project
KustomizeVersion = "v3.8.7"

imageName = "controller:latest"

// TODO: This is a placeholder for now. This would probably be the operator-sdk version
hybridOperatorVersion = "0.0.1"

// helmPluginVersion is the operator-framework/helm-operator-plugin version to be used in the project
helmPluginVersion = "dc6c589504b2884e68dff6dc0e5e87ce8c24702f"
)

var _ plugins.Scaffolder = &initScaffolder{}

type initScaffolder struct {
// fs is the filesystem that will be used by the scaffolder
fs machinery.Filesystem

config config.Config
boilerplatePath string
license string
owner string
}

// NewInitScaffolder returns a new plugins.Scaffolder for project initialization operations
func NewInitScaffolder(config config.Config, license, owner string) plugins.Scaffolder {
return &initScaffolder{
config: config,
boilerplatePath: hack.DefaultBoilerplatePath,
license: license,
owner: owner,
}
}

// InjectFS implements Scaffolder
func (s *initScaffolder) InjectFS(fs machinery.Filesystem) {
s.fs = fs
}

// Scaffold implements scaffolder
func (s *initScaffolder) Scaffold() error {
fmt.Println("Writing scaffolds for you to edit...")

// Initialize the machinery.Scaffold that will write the files to disk
scaffold := machinery.NewScaffold(s.fs,
machinery.WithDirectoryPermissions(0755),
machinery.WithFilePermissions(0644),
machinery.WithConfig(s.config),
)

// The boilerplate file needs to be scaffolded as a separate step as it is going to be used
// by rest of the files, even those scaffolded in this command call.
bpFile := &hack.Boilerplate{
License: s.license,
Owner: s.owner,
}

bpFile.Path = s.boilerplatePath
if err := scaffold.Execute(bpFile); err != nil {
return err
}

boilerplate, err := afero.ReadFile(s.fs.FS, s.boilerplatePath)
if err != nil {
return err
}

// Initialize the machinery.Scaffold that will write the files to disk
scaffold = machinery.NewScaffold(s.fs,
machinery.WithConfig(s.config),
machinery.WithBoilerplate(string(boilerplate)),
)

err = scaffold.Execute(
&templates.Main{},
&templates.GoMod{ControllerRuntimeVersion: ControllerRuntimeVersion},
&templates.GitIgnore{},
&templates.Watches{},
&rbac.ManagerRole{},
&templates.Makefile{
Image: imageName,
KustomizeVersion: KustomizeVersion,
HybridOperatorVersion: hybridOperatorVersion,
ControllerToolsVersion: ControllerToolsVersion,
ControllerRuntimeVersion: ControllerRuntimeVersion,
},
&templates.Dockerfile{},
&templates.DockerIgnore{},
)

if err != nil {
return err
}

err = util.RunCmd("Get helm-operator-plugins", "go", "get",
"github.com/operator-framework/helm-operator-plugins@"+helmPluginVersion)
if err != nil {
return err
}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright 2021 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.

package templates

import (
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
)

var _ machinery.Template = &Dockerfile{}

// Dockerfile scaffolds a file that defines the containerized build process
type Dockerfile struct {
machinery.TemplateMixin
}

// SetTemplateDefaults implements file.Template
func (f *Dockerfile) SetTemplateDefaults() error {
if f.Path == "" {
f.Path = "Dockerfile"
}

f.TemplateBody = dockerfileTemplate

return nil
}

// The current template scaffolds copying of go dependencies and building
// main.go. If there are any other depencies or folders to be copied like
// `api/` and `controller/` they would have to be added.

const dockerfileTemplate = `# Build the manager binary
FROM golang:1.16 as builder

WORKDIR /workspace
# Copy the Go Modules manifests
COPY go.mod go.mod
COPY go.sum go.sum
# cache deps before building and copying source so that we don't need to re-download as much
# and so that source changes don't invalidate our downloaded layer
RUN go mod download

# Copy the go source
COPY main.go main.go

# Build
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go

# Use distroless as minimal base image to package the manager binary
# Refer to https://github.com/GoogleContainerTools/distroless for more details
FROM gcr.io/distroless/static:nonroot
WORKDIR /

ENV HOME=/opt/helm

# Copy necessary files
COPY watches.yaml ${HOME}/watches.yaml
COPY helm-charts ${HOME}/helm-charts

# Copy manager binary
COPY --from=builder /workspace/manager .
Copy link
Member

Choose a reason for hiding this comment

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

I think we also need to copy the helm-charts directory

Copy link
Member

Choose a reason for hiding this comment

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

and generally probably need to be closer to the helm-operator base image though that can be a longer term thing

Copy link
Member Author

@varshaprasad96 varshaprasad96 Jul 2, 2021

Choose a reason for hiding this comment

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

added the helm chart repository. I have made the entry point to be the manager binary (for now), in a follow up Ill test it out and remove it (as entry point) if not needed.

USER 65532:65532

ENTRYPOINT ["/manager"]
`
Loading