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
140 changes: 134 additions & 6 deletions pkg/operator/render/options/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package options

import (
"fmt"

apierrors "k8s.io/apimachinery/pkg/api/errors"

utilerrors "k8s.io/apimachinery/pkg/util/errors"

"k8s.io/apimachinery/pkg/api/meta"

"github.com/openshift/library-go/pkg/operator/resource/resourceread"
"k8s.io/apimachinery/pkg/api/equality"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/klog/v2"
Expand Down Expand Up @@ -57,29 +66,148 @@ type TemplateData struct {
FileConfig
}

func (c RenderedManifests) ListManifestOfType(gvk schema.GroupVersionKind) []RenderedManifest {
func (renderedManifests RenderedManifests) ListManifestOfType(gvk schema.GroupVersionKind) []RenderedManifest {
ret := []RenderedManifest{}
for i := range c {
obj, err := c[i].GetDecodedObj()
for i := range renderedManifests {
obj, err := renderedManifests[i].GetDecodedObj()
if err != nil {
klog.Warningf("failure to read %q: %v", c[i].OriginalFilename, err)
klog.Warningf("failure to read %q: %v", renderedManifests[i].OriginalFilename, err)
continue
}
if obj.GetObjectKind().GroupVersionKind() == gvk {
ret = append(ret, c[i])
ret = append(ret, renderedManifests[i])
}
}

return ret
}

func (renderedManifests RenderedManifests) GetManifest(gvk schema.GroupVersionKind, namespace, name string) (RenderedManifest, error) {
for i := range renderedManifests {
obj, err := renderedManifests[i].GetDecodedObj()
if err != nil {
klog.Warningf("failure to read %q: %v", renderedManifests[i].OriginalFilename, err)
continue
}
if obj.GetObjectKind().GroupVersionKind() != gvk {
continue
}
objMetadata, err := meta.Accessor(obj)
if err != nil {
klog.Warningf("failure to read metadata %q: %v", renderedManifests[i].OriginalFilename, err)
continue
}

// since validation requires that all of these are the same, it doesn't matterwhich one we return
if objMetadata.GetName() == name && objMetadata.GetNamespace() == namespace {
return renderedManifests[i], nil
}
}

return RenderedManifest{}, apierrors.NewNotFound(
schema.GroupResource{
Group: gvk.Group,
Resource: gvk.Kind,
},
name)
}

func (renderedManifests RenderedManifests) GetObject(gvk schema.GroupVersionKind, namespace, name string) (runtime.Object, error) {
manifest, err := renderedManifests.GetManifest(gvk, namespace, name)
if err != nil {
return nil, err
}
return manifest.decodedObj, nil
}

func (renderedManifests RenderedManifests) ValidateManifestPredictability() error {
errs := []error{}
decodeErrorsObserved := map[int]bool{}
metadataErrorsObserved := map[int]bool{}

type compareTuple struct {
i, j int
}
compareTuplesErrorsObserved := map[compareTuple]bool{}

for i := range renderedManifests {
lhs := renderedManifests[i]
lhsObj, err := lhs.GetDecodedObj()
if err != nil {
if !decodeErrorsObserved[i] {
errs = append(errs, err)
decodeErrorsObserved[i] = true
}
continue
}
lhsMetadata, err := meta.Accessor(lhsObj)
if err != nil {
if !metadataErrorsObserved[i] {
errs = append(errs, fmt.Errorf("unable to read metadata for %q: %w", lhs.OriginalFilename, err))
metadataErrorsObserved[i] = true
}
continue
}

for j := range renderedManifests {
if i == j {
continue
}
rhs := renderedManifests[j]
rhsObj, err := rhs.GetDecodedObj()
if err != nil {
if !decodeErrorsObserved[j] {
errs = append(errs, err)
decodeErrorsObserved[j] = true
}
continue
}
rhsMetadata, err := meta.Accessor(rhsObj)
if err != nil {
if !metadataErrorsObserved[j] {
errs = append(errs, fmt.Errorf("unable to read metadata for %q: %w", rhs.OriginalFilename, err))
metadataErrorsObserved[j] = true
}
continue
}
if lhsObj.GetObjectKind().GroupVersionKind().GroupKind() != rhsObj.GetObjectKind().GroupVersionKind().GroupKind() {
continue
}
if lhsMetadata.GetName() != rhsMetadata.GetName() {
continue
}
if lhsMetadata.GetNamespace() != rhsMetadata.GetNamespace() {
continue
}

if !equality.Semantic.DeepEqual(lhsObj, rhsObj) {
if !compareTuplesErrorsObserved[compareTuple{i, j}] {
errs = append(errs,
fmt.Errorf("%q and %q both set %v.%v/%v in ns/%v, but have different values",
lhs.OriginalFilename,
rhs.OriginalFilename,
lhsObj.GetObjectKind().GroupVersionKind().Kind,
lhsObj.GetObjectKind().GroupVersionKind().Group,
lhsMetadata.GetName(),
lhsMetadata.GetNamespace(),
))
compareTuplesErrorsObserved[compareTuple{i, j}] = true
compareTuplesErrorsObserved[compareTuple{j, i}] = true
}
}
}
}

return utilerrors.NewAggregate(errs)
}

func (c *RenderedManifest) GetDecodedObj() (runtime.Object, error) {
if c.decodedObj != nil {
return c.decodedObj, nil
}
obj, err := resourceread.ReadGenericWithUnstructured(c.Content)
if err != nil {
return nil, err
return nil, fmt.Errorf("unable to decode %q: %w", c.OriginalFilename, err)
}
c.decodedObj = obj

Expand Down
11 changes: 6 additions & 5 deletions pkg/operator/render/options/generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"io/ioutil"
"os"
"text/template"

"github.com/ghodss/yaml"
Expand Down Expand Up @@ -90,10 +89,11 @@ func (o *GenericOptions) Validate() error {
return errors.New("missing required flag: --config-output-file")
}

for _, filename := range o.RenderedManifestInputFilenames {
_, err := os.Stat(filename)
if err != nil {
return fmt.Errorf("--rendered-manifest-files, value %q could not be read: %v", filename, err)
if renderedManifests, err := o.ReadInputManifests(); err != nil {
return fmt.Errorf("--rendered-manifest-files, could not be read: %v", err)
} else {
if err := renderedManifests.ValidateManifestPredictability(); err != nil {
return fmt.Errorf("--rendered-manifest-files, are not consistent so results would be unpredictable depending on apply order: %v", err)
}
}

Expand All @@ -102,6 +102,7 @@ func (o *GenericOptions) Validate() error {
default:
return fmt.Errorf("invalid feature-set specified: %q", o.FeatureSet)
}

return nil
}

Expand Down