Skip to content

Commit 6ceeb4a

Browse files
authored
Merge pull request #196 from hasbro17/haseeb/generate-alm-manifests
*: add generate alm-catalog command
2 parents 2187405 + 3bf83e0 commit 6ceeb4a

File tree

6 files changed

+408
-26
lines changed

6 files changed

+408
-26
lines changed

commands/operator-sdk/cmd/build.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const (
5555

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

6161
bcmd := exec.Command(build)

commands/operator-sdk/cmd/generate.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@ func NewGenerateCmd() *cobra.Command {
2828
`,
2929
}
3030
cmd.AddCommand(generate.NewGenerateK8SCmd())
31+
cmd.AddCommand(generate.NewGenerateAlmCatalogCmd())
3132
return cmd
3233
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2018 The Operator-SDK Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package generate
16+
17+
import (
18+
"errors"
19+
"fmt"
20+
"io/ioutil"
21+
"os"
22+
23+
cmdError "github.com/coreos/operator-sdk/commands/operator-sdk/error"
24+
"github.com/coreos/operator-sdk/pkg/generator"
25+
yaml "gopkg.in/yaml.v2"
26+
27+
"github.com/spf13/cobra"
28+
)
29+
30+
const (
31+
configYaml = "./config/config.yaml"
32+
)
33+
34+
var (
35+
image string
36+
version string
37+
)
38+
39+
func NewGenerateAlmCatalogCmd() *cobra.Command {
40+
almCatalogCmd := &cobra.Command{
41+
Use: "alm-catalog",
42+
Short: "Generates ALM Catalog manifests",
43+
Long: `alm-catalog generator generates the following ALM Catalog manifests needed to create a catalog entry in ALM:
44+
- Cluster Service Version: deploy/alm-catalog/csv.yaml
45+
- Package: deploy/alm-catalog/package.yaml
46+
- Custom Resource Definition: deploy/alm-catalog/crd.yaml
47+
48+
The following flags are required:
49+
--image: The container image name to set in the CSV to deploy the operator
50+
--version: The version of the current CSV
51+
52+
For example:
53+
$ operator-sdk generate alm-catalog --image=quay.io/example/operator:v0.0.1 --version=0.0.1
54+
`,
55+
Run: almCatalogFunc,
56+
}
57+
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")
58+
almCatalogCmd.MarkFlagRequired("image")
59+
almCatalogCmd.Flags().StringVar(&version, "version", "", "The version of the current CSV e.g: 0.0.1")
60+
almCatalogCmd.MarkFlagRequired("version")
61+
62+
return almCatalogCmd
63+
}
64+
65+
func almCatalogFunc(cmd *cobra.Command, args []string) {
66+
if len(args) != 0 {
67+
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("alm-catalog command doesn't accept any arguments."))
68+
}
69+
verifyFlags()
70+
71+
fmt.Fprintln(os.Stdout, "Generating ALM catalog manifests")
72+
73+
c := &generator.Config{}
74+
fp, err := ioutil.ReadFile(configYaml)
75+
if err != nil {
76+
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to read config file %v: (%v)", configYaml, err))
77+
}
78+
if err = yaml.Unmarshal(fp, c); err != nil {
79+
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to unmarshal config file %v: (%v)", configYaml, err))
80+
}
81+
82+
// Generate ALM catalog manifests
83+
if err = generator.RenderAlmCatalog(c, image, version); err != nil {
84+
cmdError.ExitWithError(cmdError.ExitError, fmt.Errorf("failed to generate deploy/alm-catalog: (%v)", err))
85+
}
86+
}
87+
88+
func verifyFlags() {
89+
if len(image) == 0 {
90+
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("--image must not have empty value"))
91+
}
92+
if len(version) == 0 {
93+
cmdError.ExitWithError(cmdError.ExitBadArgs, errors.New("--version must not have empty value"))
94+
}
95+
}

pkg/generator/alm_catalog_tmpl.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2018 The Operator-SDK Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package generator
16+
17+
const catalogPackageTmpl = `packageName: {{.PackageName}}
18+
channels:
19+
- name: {{.ChannelName}}
20+
currentCSV: {{.CurrentCSV}}
21+
`
22+
23+
const crdTmpl = `apiVersion: apiextensions.k8s.io/v1beta1
24+
kind: CustomResourceDefinition
25+
metadata:
26+
name: {{.KindPlural}}.{{.GroupName}}
27+
spec:
28+
group: {{.GroupName}}
29+
names:
30+
kind: {{.Kind}}
31+
listKind: {{.Kind}}List
32+
plural: {{.KindPlural}}
33+
singular: {{.KindSingular}}
34+
scope: Namespaced
35+
version: {{.Version}}
36+
`
37+
38+
const catalogCSVTmpl = `apiVersion: app.coreos.com/v1alpha1
39+
kind: ClusterServiceVersion-v1
40+
metadata:
41+
name: {{.CSVName}}
42+
namespace: placeholder
43+
spec:
44+
install:
45+
strategy: deployment
46+
spec:
47+
permissions:
48+
- serviceAccountName: {{.ProjectName}}
49+
rules:
50+
- apiGroups:
51+
- {{.GroupName}}
52+
resources:
53+
- "*"
54+
verbs:
55+
- "*"
56+
- apiGroups:
57+
- ""
58+
resources:
59+
- pods
60+
- services
61+
- endpoints
62+
- persistentvolumeclaims
63+
- events
64+
- configmaps
65+
- secrets
66+
verbs:
67+
- "*"
68+
- apiGroups:
69+
- apps
70+
resources:
71+
- deployments
72+
- daemonsets
73+
- replicasets
74+
- statefulsets
75+
verbs:
76+
- "*"
77+
deployments:
78+
- name: {{.ProjectName}}
79+
spec:
80+
replicas: 1
81+
selector:
82+
matchLabels:
83+
app: {{.ProjectName}}
84+
template:
85+
metadata:
86+
labels:
87+
app: {{.ProjectName}}
88+
spec:
89+
containers:
90+
- name: {{.ProjectName}}-alm-owned
91+
image: {{.Image}}
92+
command:
93+
- {{.ProjectName}}
94+
imagePullPolicy: Always
95+
env:
96+
- name: MY_POD_NAMESPACE
97+
valueFrom:
98+
fieldRef:
99+
fieldPath: metadata.namespace
100+
- name: MY_POD_NAME
101+
valueFrom:
102+
fieldRef:
103+
fieldPath: metadata.name
104+
restartPolicy: Always
105+
terminationGracePeriodSeconds: 5
106+
serviceAccountName: {{.ProjectName}}
107+
serviceAccount: {{.ProjectName}}
108+
customresourcedefinitions:
109+
owned:
110+
- description: Represents an instance of a {{.Kind}} application
111+
displayName: {{.Kind}} Application
112+
kind: {{.Kind}}
113+
name: {{.KindPlural}}.{{.GroupName}}
114+
version: {{.CRDVersion}}
115+
version: {{.CatalogVersion}}
116+
displayName: {{.Kind}}
117+
labels:
118+
alm-owner-enterprise-app: {{.ProjectName}}
119+
alm-status-descriptors: {{.CSVName}}
120+
`

pkg/generator/gen_alm_catalog.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2018 The Operator-SDK Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package generator
16+
17+
import (
18+
"fmt"
19+
"io"
20+
"strings"
21+
"text/template"
22+
)
23+
24+
const (
25+
// Sample catalog resource values
26+
// TODO: Make this configurable
27+
packageChannel = "alpha"
28+
)
29+
30+
// CatalogPackageConfig contains the data needed to generate deploy/alm-catalog/package.yaml
31+
type CatalogPackageConfig struct {
32+
PackageName string
33+
ChannelName string
34+
CurrentCSV string
35+
}
36+
37+
// renderCatalogPackage generates deploy/alm-catalog/package.yaml
38+
func renderCatalogPackage(w io.Writer, config *Config, catalogVersion string) error {
39+
t := template.New(catalogPackageYaml)
40+
t, err := t.Parse(catalogPackageTmpl)
41+
if err != nil {
42+
return fmt.Errorf("failed to parse catalog package template: %v", err)
43+
}
44+
45+
name := strings.ToLower(config.Kind)
46+
cpConfig := CatalogPackageConfig{
47+
PackageName: name,
48+
ChannelName: packageChannel,
49+
CurrentCSV: getCSVName(name, catalogVersion),
50+
}
51+
return t.Execute(w, cpConfig)
52+
}
53+
54+
// CRDConfig contains the data needed to generate deploy/alm-catalog/crd.yaml
55+
type CRDConfig struct {
56+
Kind string
57+
KindSingular string
58+
KindPlural string
59+
GroupName string
60+
Version string
61+
}
62+
63+
// renderCRD generates deploy/alm-catalog/crd.yaml
64+
func renderCRD(w io.Writer, config *Config) error {
65+
t := template.New(catalogCRDYaml)
66+
t, err := t.Parse(crdTmpl)
67+
if err != nil {
68+
return fmt.Errorf("failed to parse catalog CRD template: %v", err)
69+
}
70+
71+
kindSingular := strings.ToLower(config.Kind)
72+
crdConfig := CRDConfig{
73+
Kind: config.Kind,
74+
KindSingular: kindSingular,
75+
KindPlural: kindSingular + "s",
76+
GroupName: groupName(config.APIVersion),
77+
Version: version(config.APIVersion),
78+
}
79+
return t.Execute(w, crdConfig)
80+
}
81+
82+
// CSVConfig contains the data needed to generate deploy/alm-catalog/csv.yaml
83+
type CSVConfig struct {
84+
Kind string
85+
KindSingular string
86+
KindPlural string
87+
GroupName string
88+
CRDVersion string
89+
ProjectName string
90+
CSVName string
91+
Image string
92+
CatalogVersion string
93+
}
94+
95+
// renderCatalogCSV generates deploy/alm-catalog/csv.yaml
96+
func renderCatalogCSV(w io.Writer, config *Config, image, catalogVersion string) error {
97+
t := template.New(catalogCSVYaml)
98+
t, err := t.Parse(catalogCSVTmpl)
99+
if err != nil {
100+
return fmt.Errorf("failed to parse catalog CSV template: %v", err)
101+
}
102+
103+
kindSingular := strings.ToLower(config.Kind)
104+
csvConfig := CSVConfig{
105+
Kind: config.Kind,
106+
KindSingular: kindSingular,
107+
KindPlural: kindSingular + "s",
108+
GroupName: groupName(config.APIVersion),
109+
CRDVersion: version(config.APIVersion),
110+
CSVName: getCSVName(kindSingular, catalogVersion),
111+
Image: image,
112+
CatalogVersion: catalogVersion,
113+
ProjectName: config.ProjectName,
114+
}
115+
return t.Execute(w, csvConfig)
116+
}
117+
118+
func getCSVName(name, version string) string {
119+
return name + ".v" + version
120+
}

0 commit comments

Comments
 (0)