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
2 changes: 1 addition & 1 deletion commands/operator-sdk/cmd/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ const (

func buildFunc(cmd *cobra.Command, args []string) {
if len(args) != 1 {
cmdError.ExitWithError(cmdError.ExitBadArgs, fmt.Errorf("new command needs 1 argument."))
cmdError.ExitWithError(cmdError.ExitBadArgs, fmt.Errorf("build command needs 1 argument."))
}

bcmd := exec.Command(build)
Expand Down
1 change: 1 addition & 0 deletions commands/operator-sdk/cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,6 @@ func NewGenerateCmd() *cobra.Command {
`,
}
cmd.AddCommand(generate.NewGenerateK8SCmd())
cmd.AddCommand(generate.NewGenerateAlmCatalogCmd())
return cmd
}
95 changes: 95 additions & 0 deletions commands/operator-sdk/cmd/generate/alm_catalog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2018 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 generate

import (
"errors"
"fmt"
"io/ioutil"
"os"

cmdError "github.com/coreos/operator-sdk/commands/operator-sdk/error"
"github.com/coreos/operator-sdk/pkg/generator"
yaml "gopkg.in/yaml.v2"

"github.com/spf13/cobra"
)

const (
configYaml = "./config/config.yaml"
)

var (
image string
version string
)

func NewGenerateAlmCatalogCmd() *cobra.Command {
almCatalogCmd := &cobra.Command{
Use: "alm-catalog",
Short: "Generates ALM Catalog manifests",
Long: `alm-catalog generator generates the following ALM Catalog manifests needed to create a catalog entry in ALM:
- Cluster Service Version: deploy/alm-catalog/csv.yaml
- Package: deploy/alm-catalog/package.yaml
- Custom Resource Definition: deploy/alm-catalog/crd.yaml

The following flags are required:
--image: The container image name to set in the CSV to deploy the operator
--version: The version of the current CSV

For example:
$ operator-sdk generate alm-catalog --image=quay.io/example/operator:v0.0.1 --version=0.0.1
`,
Run: almCatalogFunc,
}
almCatalogCmd.Flags().StringVar(&image, "image", "", "The container image name to set in the CSV to deploy the operator e.g: quay.io/example/operator:v0.0.1")
almCatalogCmd.MarkFlagRequired("image")
almCatalogCmd.Flags().StringVar(&version, "version", "", "The version of the current CSV e.g: 0.0.1")
almCatalogCmd.MarkFlagRequired("version")

return almCatalogCmd
}

func almCatalogFunc(cmd *cobra.Command, args []string) {
if len(args) != 0 {
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("alm-catalog command doesn't accept any arguments."))
}
verifyFlags()

fmt.Fprintln(os.Stdout, "Generating ALM catalog manifests")

c := &generator.Config{}
fp, err := ioutil.ReadFile(configYaml)
if err != nil {
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to read config file %v: (%v)", configYaml, err))
}
if err = yaml.Unmarshal(fp, c); err != nil {
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to unmarshal config file %v: (%v)", configYaml, err))
}

// Generate ALM catalog manifests
if err = generator.RenderAlmCatalog(c, image, version); err != nil {
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to generate deploy/alm-catalog: (%v)", err))
}
}

func verifyFlags() {
if len(image) == 0 {
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("--image must not have empty value"))
}
if len(version) == 0 {
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("--version must not have empty value"))
}
}
120 changes: 120 additions & 0 deletions pkg/generator/alm_catalog_tmpl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright 2018 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 generator

const catalogPackageTmpl = `packageName: {{.PackageName}}
channels:
- name: {{.ChannelName}}
currentCSV: {{.CurrentCSV}}
`

const crdTmpl = `apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: {{.KindPlural}}.{{.GroupName}}
spec:
group: {{.GroupName}}
names:
kind: {{.Kind}}
listKind: {{.Kind}}List
plural: {{.KindPlural}}
singular: {{.KindSingular}}
scope: Namespaced
version: {{.Version}}
`

const catalogCSVTmpl = `apiVersion: app.coreos.com/v1alpha1
kind: ClusterServiceVersion-v1
metadata:
name: {{.CSVName}}
namespace: placeholder
spec:
install:
strategy: deployment
spec:
permissions:
- serviceAccountName: {{.ProjectName}}
rules:
- apiGroups:
- {{.GroupName}}
resources:
- "*"
verbs:
- "*"
- apiGroups:
- ""
resources:
- pods
- services
- endpoints
- persistentvolumeclaims
- events
- configmaps
- secrets
verbs:
- "*"
- apiGroups:
- apps
resources:
- deployments
- daemonsets
- replicasets
- statefulsets
verbs:
- "*"
deployments:
- name: {{.ProjectName}}
spec:
replicas: 1
selector:
matchLabels:
app: {{.ProjectName}}
template:
metadata:
labels:
app: {{.ProjectName}}
spec:
containers:
- name: {{.ProjectName}}-alm-owned
image: {{.Image}}
command:
- {{.ProjectName}}
imagePullPolicy: Always
env:
- name: MY_POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: MY_POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
restartPolicy: Always
terminationGracePeriodSeconds: 5
serviceAccountName: {{.ProjectName}}
serviceAccount: {{.ProjectName}}
customresourcedefinitions:
owned:
- description: Represents an instance of a {{.Kind}} application
displayName: {{.Kind}} Application
kind: {{.Kind}}
name: {{.KindPlural}}.{{.GroupName}}
version: {{.CRDVersion}}
version: {{.CatalogVersion}}
displayName: {{.Kind}}
labels:
alm-owner-enterprise-app: {{.ProjectName}}
alm-status-descriptors: {{.CSVName}}
`
120 changes: 120 additions & 0 deletions pkg/generator/gen_alm_catalog.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright 2018 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 generator

import (
"fmt"
"io"
"strings"
"text/template"
)

const (
// Sample catalog resource values
// TODO: Make this configurable
packageChannel = "alpha"
)

// CatalogPackageConfig contains the data needed to generate deploy/alm-catalog/package.yaml
type CatalogPackageConfig struct {
PackageName string
ChannelName string
CurrentCSV string
}

// renderCatalogPackage generates deploy/alm-catalog/package.yaml
func renderCatalogPackage(w io.Writer, config *Config, catalogVersion string) error {
t := template.New(catalogPackageYaml)
t, err := t.Parse(catalogPackageTmpl)
if err != nil {
return fmt.Errorf("failed to parse catalog package template: %v", err)
}

name := strings.ToLower(config.Kind)
cpConfig := CatalogPackageConfig{
PackageName: name,
ChannelName: packageChannel,
CurrentCSV: getCSVName(name, catalogVersion),
}
return t.Execute(w, cpConfig)
}

// CRDConfig contains the data needed to generate deploy/alm-catalog/crd.yaml
type CRDConfig struct {
Kind string
KindSingular string
KindPlural string
GroupName string
Version string
}

// renderCRD generates deploy/alm-catalog/crd.yaml
func renderCRD(w io.Writer, config *Config) error {
t := template.New(catalogCRDYaml)
t, err := t.Parse(crdTmpl)
if err != nil {
return fmt.Errorf("failed to parse catalog CRD template: %v", err)
}

kindSingular := strings.ToLower(config.Kind)
crdConfig := CRDConfig{
Kind: config.Kind,
KindSingular: kindSingular,
KindPlural: kindSingular + "s",
GroupName: groupName(config.APIVersion),
Version: version(config.APIVersion),
}
return t.Execute(w, crdConfig)
}

// CSVConfig contains the data needed to generate deploy/alm-catalog/csv.yaml
type CSVConfig struct {
Kind string
KindSingular string
KindPlural string
GroupName string
CRDVersion string
ProjectName string
CSVName string
Image string
CatalogVersion string
}

// renderCatalogCSV generates deploy/alm-catalog/csv.yaml
func renderCatalogCSV(w io.Writer, config *Config, image, catalogVersion string) error {
t := template.New(catalogCSVYaml)
t, err := t.Parse(catalogCSVTmpl)
if err != nil {
return fmt.Errorf("failed to parse catalog CSV template: %v", err)
}

kindSingular := strings.ToLower(config.Kind)
csvConfig := CSVConfig{
Kind: config.Kind,
KindSingular: kindSingular,
KindPlural: kindSingular + "s",
GroupName: groupName(config.APIVersion),
CRDVersion: version(config.APIVersion),
CSVName: getCSVName(kindSingular, catalogVersion),
Image: image,
CatalogVersion: catalogVersion,
ProjectName: config.ProjectName,
}
return t.Execute(w, csvConfig)
}

func getCSVName(name, version string) string {
return name + ".v" + version
}
Loading