Skip to content

Commit

Permalink
[release-4.7] Bug 1950926: Extend OLM data with CSV display name (ope…
Browse files Browse the repository at this point in the history
  • Loading branch information
tremes committed Apr 19, 2021
1 parent 23a2989 commit b958d37
Show file tree
Hide file tree
Showing 7 changed files with 229 additions and 80 deletions.
5 changes: 5 additions & 0 deletions docs/insights-archive-sample/config/olm_operators.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[
{
"name": "eap.openshift-operators",
"displayName": "JBoss EAP",
"version": "v2.1.1",
"csv_conditions": [
{
Expand Down Expand Up @@ -42,6 +43,7 @@
},
{
"name": "elasticsearch-operator.openshift-operators-redhat",
"displayName": "OpenShift Elasticsearch Operator",
"version": "4.6.0-202102200141.p0",
"csv_conditions": [
{
Expand Down Expand Up @@ -83,6 +85,7 @@
},
{
"name": "kiali-ossm.openshift-operators",
"displayName": "Kiali Operator",
"version": "v1.24.5",
"csv_conditions": [
{
Expand Down Expand Up @@ -124,6 +127,7 @@
},
{
"name": "postgresql-operator-dev4devs-com.psql-test",
"displayName": "PostgreSQL Operator by Dev4Ddevs.com",
"version": "v0.1.1",
"csv_conditions": [
{
Expand Down Expand Up @@ -165,6 +169,7 @@
},
{
"name": "radanalytics-spark.openshift-operators",
"displayName": "Apache Spark Operator",
"version": "v1.1.0",
"csv_conditions": [
{
Expand Down
117 changes: 78 additions & 39 deletions pkg/gather/clusterconfig/olm_operators.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ package clusterconfig

import (
"context"
"encoding/json"
"fmt"
"strings"

"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog/v2"

"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
Expand All @@ -17,13 +16,17 @@ import (

var (
operatorGVR = schema.GroupVersionResource{Group: "operators.coreos.com", Version: "v1", Resource: "operators"}
clusterServiceVersionGVR = schema.GroupVersionResource{Group: "operators.coreos.com", Version: "v1alpha1", Resource: "clusterserviceversions"}
clusterServiceVersionGVR = schema.GroupVersionResource{
Group: "operators.coreos.com",
Version: "v1alpha1",
Resource: "clusterserviceversions"}
)

type olmOperator struct {
Name string `json:"name"`
Version string `json:"version"`
Conditions []interface{} `json:"csv_conditions"`
Name string `json:"name"`
DisplayName string `json:"displayName"`
Version string `json:"version"`
Conditions []interface{} `json:"csv_conditions"`
}

// ClusterServiceVersion helper struct
Expand Down Expand Up @@ -63,39 +66,56 @@ func gatherOLMOperators(ctx context.Context, dynamicClient dynamic.Interface) ([
}
var refs []interface{}
olms := []olmOperator{}
errs := []error{}
for _, i := range olmOperators.Items {
newOlm := olmOperator{
Name: i.GetName(),
}
err := parseJSONQuery(i.Object, "status.components.refs", &refs)
if err != nil {
klog.Errorf("Cannot find \"status.components.refs\" in %s definition: %v", i.GetName(), err)
// if no references are found then add an error and OLM operator with only name and continue
errs = append(errs, fmt.Errorf("cannot find \"status.components.refs\" in %s definition: %v", i.GetName(), err))
olms = append(olms, newOlm)
continue
}
for _, r := range refs {
csvRef := getCSVRefFromRefs(r)
csvRef, err := findCSVRefInRefs(r)
if err != nil {
errs = append(errs, err)
olms = append(olms, newOlm)
continue
}
// CSV reference can still be nil
if csvRef == nil {
continue
}
conditions, err := getCSVConditions(ctx, dynamicClient, csvRef)
newOlm.Version = csvRef.Version

name, conditions, err := getCSVAndParse(ctx, dynamicClient, csvRef)
if err != nil {
klog.Errorf("failed to get %s conditions: %v", csvRef.Name, err)
// append the error and the OLM data we already have and continue
errs = append(errs, err)
olms = append(olms, newOlm)
continue
}
olmO := olmOperator{
Name: i.GetName(),
Version: csvRef.Version,
Conditions: conditions,
}
if isInArray(olmO, olms) {
newOlm.DisplayName = name
newOlm.Conditions = conditions

if isInArray(newOlm, olms) {
continue
}
olms = append(olms, olmO)
olms = append(olms, newOlm)
}
}
if len(olms) == 0 {
return nil, nil
}
r := record.Record{
Name: "config/olm_operators",
Item: OlmOperatorAnonymizer{operators: olms},
Item: record.JSONMarshaller{Object: olms},
}
if len(errs) != 0 {
return []record.Record{r}, errs
}
return []record.Record{r}, nil
}
Expand All @@ -109,48 +129,67 @@ func isInArray(o olmOperator, a []olmOperator) bool {
return false
}

func getCSVRefFromRefs(r interface{}) *csvRef {
//getCSVAndParse gets full CSV definition from csvRef and tries to parse the definition
func getCSVAndParse(ctx context.Context, dynamicClient dynamic.Interface, csvRef *csvRef) (name string, conditions []interface{}, err error) {
csv, err := getCsvFromRef(ctx, dynamicClient, csvRef)
if err != nil {
return "", nil, fmt.Errorf("failed to get %s ClusterServiceVersion: %v", csvRef.Name, err)
}
name, conditions, err = parseCsv(csv)

if err != nil {
return "", nil, fmt.Errorf("cannot read %s ClusterServiceVersion attributes: %v", csvRef.Name, err)
}

return name, conditions, nil
}

//findCSVRefInRefs tries to find ClusterServiceVersion reference in the references
//and parse the ClusterServiceVersion if successful.
//It can return nil with no error if the CSV was not found
func findCSVRefInRefs(r interface{}) (*csvRef, error) {
refMap, ok := r.(map[string]interface{})
if !ok {
klog.Errorf("Cannot convert %s to map[string]interface{}", r)
return nil
return nil, fmt.Errorf("cannot convert %s to map[string]interface{}", r)
}
// version is part of the name of ClusterServiceVersion
if refMap["kind"] == "ClusterServiceVersion" {
name := refMap["name"].(string)
if !strings.Contains(name, ".") {
return nil, fmt.Errorf("clusterserviceversion \"%s\" probably doesn't include version", name)
}
nameVer := strings.SplitN(name, ".", 2)
csvRef := &csvRef{
Name: name,
Namespace: refMap["namespace"].(string),
Version: nameVer[1],
}
return csvRef
return csvRef, nil
}
return nil
return nil, nil
}

func getCSVConditions(ctx context.Context, dynamicClient dynamic.Interface, csvRef *csvRef) ([]interface{}, error) {
func getCsvFromRef(ctx context.Context, dynamicClient dynamic.Interface, csvRef *csvRef) (map[string]interface{}, error) {
csv, err := dynamicClient.Resource(clusterServiceVersionGVR).Namespace(csvRef.Namespace).Get(ctx, csvRef.Name, metav1.GetOptions{})
if err != nil {
return nil, err
}
return csv.Object, nil
}

//parseCsv tries to parse "status.conditions" and "spec.displayName" from the input map.
// Returns an error if any of the values cannot be parsed.
func parseCsv(csv map[string]interface{}) (string, []interface{}, error) {
var conditions []interface{}
err = parseJSONQuery(csv.Object, "status.conditions", &conditions)
var name string
err := parseJSONQuery(csv, "status.conditions", &conditions)
if err != nil {
return nil, err
return "", nil, err
}
err = parseJSONQuery(csv, "spec.displayName", &name)
if err != nil {
return "", nil, err
}
return conditions, nil
}

// OlmOperatorAnonymizer implements HostSubnet serialization
type OlmOperatorAnonymizer struct{ operators []olmOperator }

// Marshal implements OlmOperator serialization
func (a OlmOperatorAnonymizer) Marshal(_ context.Context) ([]byte, error) {
return json.Marshal(a.operators)
}

// GetExtension returns extension for OlmOperator object
func (a OlmOperatorAnonymizer) GetExtension() string {
return "json"
return name, conditions, nil
}

0 comments on commit b958d37

Please sign in to comment.