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

internal/scaffold/olm-catalog: populate CSV customresourcedefinitions from Go type annotations #1162

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
65236bd
pkg/scaffold/olm-catalog/*: generate CSV manifest {spec,status}Descri…
estroz Mar 1, 2019
869e49a
add comments and reorg code a bit
estroz Mar 1, 2019
1aea2a2
Merge branch 'master' into csv-customresourcedefinitions
estroz Mar 22, 2019
2560266
make CSV CRD updates if fields are not set
estroz Mar 22, 2019
84f85c9
pkg/scaffold/olm-catalog/*: suggest path and x-descriptors if not pre…
estroz Mar 25, 2019
4ca3ce1
Merge branch 'master' into csv-customresourcedefinitions
estroz Apr 8, 2019
267c6de
internal/pkg/scaffold/olm-catalog: use +operator-sdk:gen-csv parse an…
estroz Apr 13, 2019
2d3dc95
sort descriptors by display name; make parser more robust
estroz Apr 13, 2019
e1e5351
add TODO's
estroz Apr 13, 2019
db75858
internal/annotations: implement annotations splitting and joining
estroz Apr 15, 2019
e07364d
rework annotations and parser
estroz Apr 15, 2019
808a6b3
ignore non-existent API dirs
estroz Apr 16, 2019
ea9f7c0
fix vet issue
estroz Apr 16, 2019
7884094
revendor
estroz Apr 16, 2019
c3b3580
add tag parsing for resources and displayName
estroz Apr 17, 2019
2be5216
parse path directly from tags, no annotation override
estroz Apr 17, 2019
c4625d8
remove print statements, refactor initial type parsing, fix test CSV
estroz Apr 18, 2019
6326cc5
append x-descriptors found by path elements to annotation-specified x…
estroz Apr 18, 2019
5f50937
remove actionDescriptor parsing
estroz Apr 18, 2019
141a384
persist actionDescriptors and required CRD's in CSV's
estroz Apr 18, 2019
4119f15
cleanup and renaming
estroz Apr 18, 2019
c5e16db
get full hierarchal path instead of immediate parent+child
estroz Apr 19, 2019
c93b958
Merge branch 'master' into csv-customresourcedefinitions
estroz Apr 23, 2019
291855c
Merge branch 'master' into csv-customresourcedefinitions
estroz May 24, 2019
8cee281
bump maxLevel to 10; use 'spec'/'status' path segments if already see…
estroz May 24, 2019
e1bf6fe
add comments; refactor getSpecStatusPkgTypesForAPI to only do search …
estroz May 24, 2019
753829d
Merge branch 'master' into csv-customresourcedefinitions
estroz Jul 10, 2019
4de0e64
fix errors after merge
estroz Jul 10, 2019
9b8addd
add required CRD's back to CSV testdata; some CRD Apply() updates
estroz Jul 10, 2019
65c97b9
Merge branch 'master' into csv-customresourcedefinitions
estroz Jul 10, 2019
e854b16
Merge branch 'master' into csv-customresourcedefinitions
estroz Jul 16, 2019
f5a1809
some refactoring
estroz Jul 16, 2019
d9c7775
internal/pkg/scaffold/olm-catalog: error message updates and defer wr…
estroz Jul 17, 2019
a5bba17
some refactoring
estroz Jul 17, 2019
8750e06
move descriptor.go to internal/pkg/descriptor, split functions into t…
estroz Jul 17, 2019
1f37cfe
fix link
estroz Jul 17, 2019
55a64c0
Merge branch 'master' into csv-customresourcedefinitions
estroz Jul 17, 2019
4ae9847
Merge branch 'master' into csv-customresourcedefinitions
estroz Aug 9, 2019
93560be
move search functions into search.go
estroz Aug 9, 2019
3fc54a6
internal/pkg/scaffold/olm-catalog: sort both owned and required CRDDe…
estroz Aug 9, 2019
86fccfa
refactor functions
estroz Aug 21, 2019
70acfae
add parse and descriptor unit tests
estroz Sep 10, 2019
bfa2912
Merge branch 'master' into csv-customresourcedefinitions
estroz Sep 18, 2019
d4f0021
refactor descriptor retrieval from types
estroz Sep 18, 2019
8725662
doc/user/olm-catalog/csv-annotations.md: document csv-gen annotations
estroz Sep 19, 2019
0141a5f
add more unit tests and test data, fix errors caught by tests
estroz Sep 20, 2019
23f48fc
use embedded SpecDescriptor in descriptor
estroz Sep 20, 2019
9d806f3
Merge branch 'master' into csv-customresourcedefinitions
estroz Oct 23, 2019
20f4390
fix unit test
estroz Oct 28, 2019
d222743
change resource name for dummy types
estroz Oct 30, 2019
3cf1a3b
prevent generators from running on dummy types
estroz Oct 31, 2019
22fb0cc
Merge branch 'master' into csv-customresourcedefinitions
estroz Nov 11, 2019
c5578ab
Apply suggestions from code review
Nov 12, 2019
1fb896d
updates based on PR comments
estroz Nov 12, 2019
5214d50
respect inlined and omitted tags
estroz Nov 13, 2019
8f07a49
Merge branch 'master' into csv-customresourcedefinitions
estroz Nov 13, 2019
fb93d43
check if prefix is local dir; chdir in tests
estroz Nov 18, 2019
6e911ce
remove print statement
estroz Nov 20, 2019
db24904
Merge branch 'master' into csv-customresourcedefinitions
estroz Nov 20, 2019
8735c3f
Merge remote-tracking branch 'origin/csv-customresourcedefinitions' i…
estroz Nov 20, 2019
c2a1843
use structtag.Parse to correctly parse tags; unit tests
estroz Nov 21, 2019
a67dc94
Merge branch 'master' into csv-customresourcedefinitions
estroz Nov 21, 2019
e0977a6
update test/test-framework go.sum
estroz Nov 21, 2019
5b2693e
consider embedded structs and add test cases
estroz Dec 2, 2019
f11b35f
Merge branch 'master' into csv-customresourcedefinitions
estroz Dec 2, 2019
4fe5f95
fix tests and return jsonTag.Name if name is -
estroz Dec 3, 2019
7e3e9a6
Merge branch 'master' into csv-customresourcedefinitions
estroz Dec 4, 2019
241f71a
fix linter error
estroz Dec 4, 2019
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
17 changes: 15 additions & 2 deletions pkg/scaffold/olm-catalog/csv_updaters.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (
appsv1 "k8s.io/api/apps/v1"
rbacv1 "k8s.io/api/rbac/v1"
apiextv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apimachinery/pkg/runtime/schema"
)

// CSVUpdater is an interface for any data that can be in a CSV, which will be
Expand Down Expand Up @@ -197,11 +198,17 @@ func (store *updaterStore) AddOwnedCRD(yamlDoc []byte) error {
if err := yaml.Unmarshal(yamlDoc, crd); err != nil {
return err
}
store.crdUpdate.Owned = append(store.crdUpdate.Owned, olmapiv1alpha1.CRDDescription{
crdDesc := olmapiv1alpha1.CRDDescription{
Name: crd.ObjectMeta.Name,
Version: crd.Spec.Version,
Kind: crd.Spec.Names.Kind,
})
}
// Parse {spec,status}Descriptor's from source code comments.
gv := schema.GroupVersion{Group: crd.Spec.Group, Version: crd.Spec.Version}
if err := setCRDDescriptorsForGV(&crdDesc, gv); err != nil {
return err
}
store.crdUpdate.Owned = append(store.crdUpdate.Owned, crdDesc)
return nil
}

Expand All @@ -218,6 +225,12 @@ func (u *CSVCustomResourceDefinitionsUpdate) Apply(csv *olmapiv1alpha1.ClusterSe
csvDesc.Name = uDesc.Name
csvDesc.Version = uDesc.Version
csvDesc.Kind = uDesc.Kind
csvDesc.Description = uDesc.Description
if csvDesc.DisplayName == "" {
csvDesc.DisplayName = getDisplayName(uDesc.Kind)
}
csvDesc.SpecDescriptors = uDesc.SpecDescriptors
csvDesc.StatusDescriptors = uDesc.StatusDescriptors
du.Owned[i] = csvDesc
}
}
Expand Down
215 changes: 215 additions & 0 deletions pkg/scaffold/olm-catalog/descriptor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
// 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 catalog

import (
"bufio"
"bytes"
"fmt"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"go/types"
"os"
"path/filepath"
"regexp"
"strings"

olmapiv1alpha1 "github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
"github.com/operator-framework/operator-sdk/pkg/scaffold"
log "github.com/sirupsen/logrus"
"k8s.io/apimachinery/pkg/runtime/schema"
)

type fieldVals struct {
name, typ, tag, comments string
}

// setCRDDescriptorsForGV parses document and type declaration comments on
// CRD types to populate a csv's 'crds.owned[].{spec,status}Descriptors' for
// a given group and version.
func setCRDDescriptorsForGV(crdDesc *olmapiv1alpha1.CRDDescription, gv schema.GroupVersion) error {
fset := token.NewFileSet()
ff := func(info os.FileInfo) bool {
return strings.HasSuffix(info.Name(), "_types.go")
}
dir := filepath.Join(scaffold.ApisDir, strings.Split(gv.Group, ".")[0], gv.Version)
pkgs, err := parser.ParseDir(fset, dir, ff, parser.ParseComments)
if err != nil {
// Don't return in error as other CSV components can still be generated.
if os.IsNotExist(err) {
return nil
}
log.Fatal(err)
}

allTypes := make(map[string][]fieldVals)
for _, pkg := range pkgs {
ast.Inspect(pkg, func(n ast.Node) bool {
switch x := n.(type) {
case *ast.GenDecl:
for _, spec := range x.Specs {
if spec, ok := spec.(*ast.TypeSpec); ok {
specName := spec.Name.Name
if specName == crdDesc.Kind {
crdDesc.Description = processComments(x.Doc.Text())
}
vals, ok := allTypes[specName]
if !ok {
vals = make([]fieldVals, 0)
}
switch st := spec.Type.(type) {
case *ast.StructType:
for _, field := range st.Fields.List {
typ := processType(fset, field.Type)
comments := processComments(field.Doc.Text())
names := field.Names
if len(names) == 0 {
names = []*ast.Ident{{Name: typ}}
}
for _, name := range names {
// Is exported, primitive, or imported.
if name.IsExported() || strings.Contains(name.Name, ".") {
vals = append(vals, fieldVals{
name: getDisplayName(name.Name),
typ: typ,
tag: field.Tag.Value,
comments: comments,
})
}
}
}
}
allTypes[specName] = vals
}
}
}
return true
})
}
kindTypes, ok := allTypes[crdDesc.Kind]
if !ok {
return fmt.Errorf("no type found for kind %s", crdDesc.Kind)
}
for _, kt := range kindTypes {
for _, fields := range allTypes[kt.typ] {
if strings.HasSuffix(kt.name, "Spec") {
path, xd := guessPathAndXDescriptorFromTag(fields.tag, true)
crdDesc.SpecDescriptors = append(crdDesc.SpecDescriptors, olmapiv1alpha1.SpecDescriptor{
Description: fields.comments,
DisplayName: fields.name,
Path: path,
XDescriptors: xd,
})
} else if strings.HasSuffix(kt.name, "Status") {
path, xd := guessPathAndXDescriptorFromTag(fields.tag, false)
crdDesc.StatusDescriptors = append(crdDesc.StatusDescriptors, olmapiv1alpha1.StatusDescriptor{
Description: fields.comments,
DisplayName: fields.name,
Path: path,
XDescriptors: xd,
})
}
}
}
return nil
}

// processComments joins comment strings into one line, removing any tool
// directives.
func processComments(comments string) string {
lines := make([]string, 0)
scanner := bufio.NewScanner(strings.NewReader(comments))
for scanner.Scan() {
l := strings.TrimSpace(scanner.Text())
if l == "" || strings.Contains(l, "+k8s:") || strings.Contains(l, "+kubebuilder:") {
continue
}
lines = append(lines, l)
}
if err := scanner.Err(); err != nil {
log.Error(err)
}
return strings.Join(lines, " ")
}

var mapRe = regexp.MustCompile(`map\[.+\]`)

// processType cleans and returns the string of a type expression within fset.
func processType(fset *token.FileSet, e ast.Expr) (t string) {
tbuf := &bytes.Buffer{}
if err := printer.Fprint(tbuf, fset, e); err != nil {
log.Fatal(err)
}
t = tbuf.String()
// Clean slice, map, and pointer syntax.
tt := strings.Replace(t, "[]", "", -1)
tt = strings.Replace(tt, "*", "", -1)
tt = mapRe.ReplaceAllString(tt, "")
// Only return non-primitive types without extra syntax.
if types.Universe.Lookup(tt) == nil {
t = tt
}
return t
}

// From https://github.com/openshift/console/blob/master/frontend/public/components/operator-lifecycle-manager/descriptors/types.ts#L5-L14
var specXDescriptors = map[string][]string{
"size": {"size", "urn:alm:descriptor:com.tectonic.ui:podCount"},
"endpoints": {"endpointList", "urn:alm:descriptor:com.tectonic.ui:endpointList"},
"label": {"label", "urn:alm:descriptor:com.tectonic.ui:label"},
"resourceRequirements": {"resourceRequirements", "urn:alm:descriptor:com.tectonic.ui:resourceRequirements"},
"selector": {"selector", "urn:alm:descriptor:com.tectonic.ui:selector:"},
"namespaceSelector": {"namespaceSelector", "urn:alm:descriptor:com.tectonic.ui:namespaceSelector"},
"booleanSwitch": {"booleanSwitch", "urn:alm:descriptor:com.tectonic.ui:booleanSwitch"},
}

// From https://github.com/openshift/console/blob/master/frontend/public/components/operator-lifecycle-manager/descriptors/types.ts#L16-L27
var statusXDescriptors = map[string][]string{
"size": {"size", "urn:alm:descriptor:com.tectonic.ui:podCount"},
"podStatuses": {"podStatuses", "urn:alm:descriptor:com.tectonic.ui:podStatuses"},
"links": {"w3Link", "urn:alm:descriptor:org.w3:link"},
"conditions": {"conditions", "urn:alm:descriptor:io.kubernetes.conditions"},
"text": {"text", "urn:alm:descriptor:text"},
"prometheusEndpoint": {"prometheusEndpoint", "urn:alm:descriptor:prometheusEndpoint"},
"status": {"phase", "urn:alm:descriptor:io.kubernetes.phase"},
"reason": {"reason", "urn:alm:descriptor:io.kubernetes.phase:reason"},
}

var jsonTagRe = regexp.MustCompile("`json:\"([^,]+),?.*\"`")

// guessPathAndXDescriptorFromTag uses json field tags to guess which path
// and x-descriptor a CRD should have. This choice is a guess based on tag
// identifier.
func guessPathAndXDescriptorFromTag(tag string, isSpec bool) (path string, xd []string) {
tagMatches := jsonTagRe.FindStringSubmatch(tag)
if len(tagMatches) == 2 {
path = tagMatches[1]
}
var (
pathAndXD []string
ok bool
)
if isSpec {
pathAndXD, ok = specXDescriptors[path]
} else {
pathAndXD, ok = statusXDescriptors[path]
}
if ok {
return pathAndXD[0], []string{pathAndXD[1]}
}
return path, xd
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ spec:
kind: App
name: apps1.example.com
version: v1alpha1
- description: some description
- displayName: App
kind: App
name: apps2.example.com
version: v1alpha2
Expand Down