Skip to content

Commit 087d2eb

Browse files
committed
pkg/manifest: Add 'overrides' handling
Centralize this aspect of manifest filtering, so it can be shared between the cluster-version operator (where it currently lives [1]) and 'oc' (where we want manifest extraction to understand this sort of condition [2]). [1]: https://github.com/openshift/cluster-version-operator/blob/cce97c25292b263a5a549b2bb8ce82ed7f2d4923/pkg/cvo/sync_worker.go#L959-L987 [2]: https://issues.redhat.com/browse/OTA-559
1 parent a704a57 commit 087d2eb

File tree

2 files changed

+88
-9
lines changed

2 files changed

+88
-9
lines changed

pkg/manifest/manifest.go

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,12 @@ func (m *Manifest) UnmarshalJSON(in []byte) error {
118118
if !ok {
119119
return fmt.Errorf("expected manifest to decode into *unstructured.Unstructured, got %T", ud)
120120
}
121-
m.GVK = ud.GroupVersionKind()
122121
m.Obj = ud
122+
return m.populateFromObj()
123+
}
124+
125+
func (m *Manifest) populateFromObj() error {
126+
m.GVK = m.Obj.GroupVersionKind()
123127
m.id = resourceId{
124128
Group: m.GVK.Group,
125129
Kind: m.GVK.Kind,
@@ -170,8 +174,8 @@ func checkFeatureSets(requiredFeatureSet string, annotations map[string]string)
170174
// processing by cluster version operator. Pointer arguments can be set nil to avoid excluding based on that
171175
// filter. For example, setting profile non-nil and capabilities nil will return an error if the manifest's
172176
// profile does not match, but will never return an error about capability issues.
173-
func (m *Manifest) Include(excludeIdentifier *string, requiredFeatureSet *string, profile *string, capabilities *configv1.ClusterVersionCapabilitiesStatus) error {
174-
return m.IncludeAllowUnknownCapabilities(excludeIdentifier, requiredFeatureSet, profile, capabilities, false)
177+
func (m *Manifest) Include(excludeIdentifier *string, requiredFeatureSet *string, profile *string, capabilities *configv1.ClusterVersionCapabilitiesStatus, overrides []configv1.ComponentOverride) error {
178+
return m.IncludeAllowUnknownCapabilities(excludeIdentifier, requiredFeatureSet, profile, capabilities, overrides, false)
175179
}
176180

177181
// IncludeAllowUnknownCapabilities returns an error if the manifest fails an inclusion filter and should be excluded from
@@ -181,7 +185,7 @@ func (m *Manifest) Include(excludeIdentifier *string, requiredFeatureSet *string
181185
// to capabilities filtering. When set to true a manifest will not be excluded simply because it contains an unknown
182186
// capability. This is necessary to allow updates to an OCP version containing newly defined capabilities.
183187
func (m *Manifest) IncludeAllowUnknownCapabilities(excludeIdentifier *string, requiredFeatureSet *string, profile *string,
184-
capabilities *configv1.ClusterVersionCapabilitiesStatus, allowUnknownCapabilities bool) error {
188+
capabilities *configv1.ClusterVersionCapabilitiesStatus, overrides []configv1.ComponentOverride, allowUnknownCapabilities bool) error {
185189

186190
annotations := m.Obj.GetAnnotations()
187191
if annotations == nil {
@@ -213,7 +217,34 @@ func (m *Manifest) IncludeAllowUnknownCapabilities(excludeIdentifier *string, re
213217

214218
// If there is no capabilities defined in a release then we do not need to check presence of capabilities in the manifest
215219
if capabilities != nil {
216-
return checkResourceEnablement(annotations, capabilities, allowUnknownCapabilities)
220+
err := checkResourceEnablement(annotations, capabilities, allowUnknownCapabilities)
221+
if err != nil {
222+
return err
223+
}
224+
}
225+
226+
if override := m.getOverrideForManifest(overrides); override != nil && override.Unmanaged {
227+
return fmt.Errorf("overridden")
228+
}
229+
230+
return nil
231+
}
232+
233+
// getOverrideForManifest returns the override when override exists and nil otherwise.
234+
func (m *Manifest) getOverrideForManifest(overrides []configv1.ComponentOverride) *configv1.ComponentOverride {
235+
for _, override := range overrides {
236+
namespace := override.Namespace
237+
if m.id.Namespace == "" {
238+
namespace = "" // cluster-scoped objects don't have namespace.
239+
}
240+
if m.id.equal(resourceId{
241+
Group: override.Group,
242+
Kind: override.Kind,
243+
Name: override.Name,
244+
Namespace: namespace,
245+
}) {
246+
return &override
247+
}
217248
}
218249
return nil
219250
}

pkg/manifest/manifest_test.go

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ func Test_include(t *testing.T) {
600600
profile *string
601601
annotations map[string]interface{}
602602
caps *configv1.ClusterVersionCapabilitiesStatus
603+
overrides []configv1.ComponentOverride
603604

604605
expected error
605606
}{
@@ -765,6 +766,44 @@ func Test_include(t *testing.T) {
765766
EnabledCapabilities: []configv1.ClusterVersionCapability{"cap1", "cap2", "cap3"},
766767
},
767768
},
769+
{
770+
name: "unrelated override",
771+
annotations: map[string]interface{}{},
772+
overrides: []configv1.ComponentOverride{
773+
{
774+
Kind: "Pod",
775+
Name: "my-pod",
776+
Namespace: "my-namespace",
777+
Unmanaged: true,
778+
},
779+
},
780+
},
781+
{
782+
name: "override, but managed",
783+
annotations: map[string]interface{}{},
784+
overrides: []configv1.ComponentOverride{
785+
{
786+
Group: "apps",
787+
Kind: "Deployment",
788+
Name: "my-deployment",
789+
Namespace: "my-namespace",
790+
},
791+
},
792+
},
793+
{
794+
name: "unmanaged override",
795+
annotations: map[string]interface{}{},
796+
overrides: []configv1.ComponentOverride{
797+
{
798+
Group: "apps",
799+
Kind: "Deployment",
800+
Name: "my-deployment",
801+
Namespace: "my-namespace",
802+
Unmanaged: true,
803+
},
804+
},
805+
expected: fmt.Errorf("overridden"),
806+
},
768807
{
769808
name: "all nil",
770809
profile: nil,
@@ -774,19 +813,27 @@ func Test_include(t *testing.T) {
774813
}
775814

776815
for _, tt := range tests {
777-
metadata := map[string]interface{}{}
816+
metadata := map[string]interface{}{
817+
"name": "my-deployment",
818+
"namespace": "my-namespace",
819+
}
778820
t.Run(tt.name, func(t *testing.T) {
779821
if tt.annotations != nil {
780822
metadata["annotations"] = tt.annotations
781823
}
782824
m := Manifest{
783825
Obj: &unstructured.Unstructured{
784826
Object: map[string]interface{}{
785-
"metadata": metadata,
827+
"apiVersion": "apps/v1",
828+
"kind": "Deployment",
829+
"metadata": metadata,
786830
},
787831
},
788832
}
789-
err := m.Include(tt.exclude, tt.requiredFeatureSet, tt.profile, tt.caps)
833+
err := m.populateFromObj()
834+
assert.Equal(t, nil, err)
835+
836+
err = m.Include(tt.exclude, tt.requiredFeatureSet, tt.profile, tt.caps, tt.overrides)
790837
assert.Equal(t, tt.expected, err)
791838
})
792839
}
@@ -801,6 +848,7 @@ func TestIncludeAllowUnknownCapabilities(t *testing.T) {
801848
profile *string
802849
annotations map[string]interface{}
803850
caps *configv1.ClusterVersionCapabilitiesStatus
851+
overrides []configv1.ComponentOverride
804852
allowUnknown bool
805853

806854
expected error
@@ -844,7 +892,7 @@ func TestIncludeAllowUnknownCapabilities(t *testing.T) {
844892
},
845893
},
846894
}
847-
err := m.IncludeAllowUnknownCapabilities(tt.exclude, tt.requiredFeatureSet, tt.profile, tt.caps, tt.allowUnknown)
895+
err := m.IncludeAllowUnknownCapabilities(tt.exclude, tt.requiredFeatureSet, tt.profile, tt.caps, tt.overrides, tt.allowUnknown)
848896
assert.Equal(t, tt.expected, err)
849897
})
850898
}

0 commit comments

Comments
 (0)