Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gen-csv: generate 'alm-examples' annotations from CR's #1116

Merged
merged 9 commits into from
Apr 3, 2019
28 changes: 26 additions & 2 deletions internal/pkg/scaffold/olm-catalog/csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ func replaceAllBytes(v interface{}, old, new []byte) error {
// user-defined manifests and updates csv.
func (s *CSV) updateCSVFromManifestFiles(cfg *CSVConfig, csv *olmapiv1alpha1.ClusterServiceVersion) error {
store := NewUpdaterStore()
otherSpecs := make(map[string][][]byte)
for _, f := range append(cfg.CRDCRPaths, cfg.OperatorPath, cfg.RolePath) {
yamlData, err := afero.ReadFile(s.getFS(), f)
if err != nil {
Expand All @@ -366,10 +367,33 @@ func (s *CSV) updateCSVFromManifestFiles(cfg *CSVConfig, csv *olmapiv1alpha1.Clu
scanner := yamlutil.NewYAMLScanner(yamlData)
for scanner.Scan() {
yamlSpec := scanner.Bytes()

if err = store.AddToUpdater(yamlSpec); err != nil {
kind, err := getKindfromYAML(yamlSpec)
if err != nil {
return err
}
found, err := store.AddToUpdater(yamlSpec, kind)
if err != nil {
return err
}
if !found {
if _, ok := otherSpecs[kind]; !ok {
otherSpecs[kind] = make([][]byte, 0)
}
otherSpecs[kind] = append(otherSpecs[kind], yamlSpec)
}
}
if err = scanner.Err(); err != nil {
return err
}
}

for k := range store.crds.crKinds {
if crSpecs, ok := otherSpecs[k]; ok {
for _, spec := range crSpecs {
if err := store.AddCR(spec); err != nil {
return err
}
}
}
}

Expand Down
91 changes: 66 additions & 25 deletions internal/pkg/scaffold/olm-catalog/csv_updaters.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package catalog
import (
"encoding/json"
"fmt"
"strings"

"github.com/ghodss/yaml"
olmapiv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
Expand All @@ -34,24 +35,28 @@ type CSVUpdater interface {
}

type updaterStore struct {
installStrategy *CSVInstallStrategyUpdate
crdUpdate *CSVCustomResourceDefinitionsUpdate
installStrategy *InstallStrategyUpdate
crds *CustomResourceDefinitionsUpdate
almExamples *ALMExamplesUpdate
}

func NewUpdaterStore() *updaterStore {
return &updaterStore{
installStrategy: &CSVInstallStrategyUpdate{
installStrategy: &InstallStrategyUpdate{
&olminstall.StrategyDetailsDeployment{},
},
crdUpdate: &CSVCustomResourceDefinitionsUpdate{
crds: &CustomResourceDefinitionsUpdate{
&olmapiv1alpha1.CustomResourceDefinitions{},
make(map[string]struct{}),
},
almExamples: &ALMExamplesUpdate{},
}
}

// Apply iteratively calls each stored CSVUpdater's Apply() method.
func (s *updaterStore) Apply(csv *olmapiv1alpha1.ClusterServiceVersion) error {
for _, updater := range []CSVUpdater{s.installStrategy, s.crdUpdate} {
updaters := []CSVUpdater{s.installStrategy, s.crds, s.almExamples}
for _, updater := range updaters {
if err := updater.Apply(csv); err != nil {
return err
}
Expand All @@ -60,7 +65,6 @@ func (s *updaterStore) Apply(csv *olmapiv1alpha1.ClusterServiceVersion) error {
}

func getKindfromYAML(yamlData []byte) (string, error) {
// Get Kind for inital categorization.
var temp struct {
Kind string
}
Expand All @@ -70,27 +74,25 @@ func getKindfromYAML(yamlData []byte) (string, error) {
return temp.Kind, nil
}

func (s *updaterStore) AddToUpdater(yamlSpec []byte) error {
kind, err := getKindfromYAML(yamlSpec)
if err != nil {
return err
}

func (s *updaterStore) AddToUpdater(yamlSpec []byte, kind string) (found bool, err error) {
found = true
switch kind {
case "Role":
return s.AddRole(yamlSpec)
err = s.AddRole(yamlSpec)
case "ClusterRole":
return s.AddClusterRole(yamlSpec)
err = s.AddClusterRole(yamlSpec)
case "Deployment":
return s.AddDeploymentSpec(yamlSpec)
err = s.AddDeploymentSpec(yamlSpec)
case "CustomResourceDefinition":
// All CRD's present will be 'owned'.
return s.AddOwnedCRD(yamlSpec)
err = s.AddOwnedCRD(yamlSpec)
default:
found = false
}
return nil
return found, err
}

type CSVInstallStrategyUpdate struct {
type InstallStrategyUpdate struct {
*olminstall.StrategyDetailsDeployment
}

Expand Down Expand Up @@ -136,7 +138,7 @@ func (store *updaterStore) AddDeploymentSpec(yamlDoc []byte) error {
return nil
}

func (u *CSVInstallStrategyUpdate) Apply(csv *olmapiv1alpha1.ClusterServiceVersion) (err error) {
func (u *InstallStrategyUpdate) Apply(csv *olmapiv1alpha1.ClusterServiceVersion) (err error) {
// Get install strategy from csv. Default to a deployment strategy if none found.
var strat olminstall.Strategy
if csv.Spec.InstallStrategy.StrategyName == "" {
Expand Down Expand Up @@ -170,44 +172,46 @@ func (u *CSVInstallStrategyUpdate) Apply(csv *olmapiv1alpha1.ClusterServiceVersi
return nil
}

func (u *CSVInstallStrategyUpdate) updatePermissions(strat *olminstall.StrategyDetailsDeployment) {
func (u *InstallStrategyUpdate) updatePermissions(strat *olminstall.StrategyDetailsDeployment) {
if len(u.Permissions) != 0 {
strat.Permissions = u.Permissions
}
}

func (u *CSVInstallStrategyUpdate) updateClusterPermissions(strat *olminstall.StrategyDetailsDeployment) {
func (u *InstallStrategyUpdate) updateClusterPermissions(strat *olminstall.StrategyDetailsDeployment) {
if len(u.ClusterPermissions) != 0 {
strat.ClusterPermissions = u.ClusterPermissions
}
}

func (u *CSVInstallStrategyUpdate) updateDeploymentSpecs(strat *olminstall.StrategyDetailsDeployment) {
func (u *InstallStrategyUpdate) updateDeploymentSpecs(strat *olminstall.StrategyDetailsDeployment) {
if len(u.DeploymentSpecs) != 0 {
strat.DeploymentSpecs = u.DeploymentSpecs
}
}

type CSVCustomResourceDefinitionsUpdate struct {
type CustomResourceDefinitionsUpdate struct {
*olmapiv1alpha1.CustomResourceDefinitions
crKinds map[string]struct{}
}

func (store *updaterStore) AddOwnedCRD(yamlDoc []byte) error {
crd := &apiextv1beta1.CustomResourceDefinition{}
if err := yaml.Unmarshal(yamlDoc, crd); err != nil {
return err
}
store.crdUpdate.Owned = append(store.crdUpdate.Owned, olmapiv1alpha1.CRDDescription{
store.crds.Owned = append(store.crds.Owned, olmapiv1alpha1.CRDDescription{
Name: crd.ObjectMeta.Name,
Version: crd.Spec.Version,
Kind: crd.Spec.Names.Kind,
})
store.crds.crKinds[crd.Spec.Names.Kind] = struct{}{}
return nil
}

// Apply updates csv's "owned" CRDDescriptions. "required" CRDDescriptions are
// left as-is, since they are user-defined values.
func (u *CSVCustomResourceDefinitionsUpdate) Apply(csv *olmapiv1alpha1.ClusterServiceVersion) error {
func (u *CustomResourceDefinitionsUpdate) Apply(csv *olmapiv1alpha1.ClusterServiceVersion) error {
set := make(map[string]olmapiv1alpha1.CRDDescription)
for _, csvDesc := range csv.Spec.CustomResourceDefinitions.Owned {
set[csvDesc.Name] = csvDesc
Expand All @@ -224,3 +228,40 @@ func (u *CSVCustomResourceDefinitionsUpdate) Apply(csv *olmapiv1alpha1.ClusterSe
csv.Spec.CustomResourceDefinitions.Owned = du.Owned
return nil
}

type ALMExamplesUpdate struct {
crs []string
}

func (store *updaterStore) AddCR(yamlDoc []byte) error {
if len(yamlDoc) == 0 {
return nil
}
crBytes, err := yaml.YAMLToJSON(yamlDoc)
if err != nil {
return err
}
store.almExamples.crs = append(store.almExamples.crs, string(crBytes))
return nil
}

func (u *ALMExamplesUpdate) Apply(csv *olmapiv1alpha1.ClusterServiceVersion) error {
if len(u.crs) == 0 {
return nil
}
if csv.GetAnnotations() == nil {
csv.SetAnnotations(make(map[string]string))
}
sb := &strings.Builder{}
sb.WriteString(`[`)
for i, example := range u.crs {
sb.WriteString(example)
if i < len(u.crs)-1 {
sb.WriteString(`,`)
}
}
sb.WriteString(`]`)

csv.GetAnnotations()["alm-examples"] = sb.String()
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ apiVersion: operators.coreos.com/v1alpha1
kind: ClusterServiceVersion
metadata:
annotations:
alm-examples: '[{"apiVersion":"app.example.com/v1alpha1","kind":"App","metadata":{"name":"example-app"},"spec":{"size":3}}]'
capabilities: Basic Install
name: app-operator.v0.1.0
namespace: placeholder
Expand Down