Skip to content

Commit d36ceeb

Browse files
committed
Allow for risks only desired update
This is to address the issue from [1]. We need to allow for n desired update with accept risks and without image, version and arch. [1]. #1318 (comment)
1 parent 54dc4ef commit d36ceeb

4 files changed

Lines changed: 96 additions & 4 deletions

File tree

lib/validation/validation.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
configv1 "github.com/openshift/api/config/v1"
1414
)
1515

16-
func ValidateClusterVersion(config *configv1.ClusterVersion) field.ErrorList {
16+
func ValidateClusterVersion(config *configv1.ClusterVersion, shouldReconcileAcceptRisks bool) field.ErrorList {
1717
errs := apivalidation.ValidateObjectMeta(&config.ObjectMeta, false, apivalidation.NameIsDNS1035Label, nil)
1818

1919
if len(config.Spec.Upstream) > 0 {
@@ -32,8 +32,12 @@ func ValidateClusterVersion(config *configv1.ClusterVersion) field.ErrorList {
3232
}
3333
if u := config.Spec.DesiredUpdate; u != nil {
3434
switch {
35-
case len(u.Architecture) == 0 && len(u.Version) == 0 && len(u.Image) == 0:
35+
case !shouldReconcileAcceptRisks && len(u.AcceptRisks) > 0:
36+
errs = append(errs, field.Forbidden(field.NewPath("spec", "desiredUpdate", "acceptRisks"), "acceptRisks must not be specified"))
37+
case len(u.Architecture) == 0 && len(u.Version) == 0 && len(u.Image) == 0 && !shouldReconcileAcceptRisks:
3638
errs = append(errs, field.Required(field.NewPath("spec", "desiredUpdate"), "must specify architecture, version, or image"))
39+
case len(u.Architecture) == 0 && len(u.Version) == 0 && len(u.Image) == 0 && len(u.AcceptRisks) == 0 && shouldReconcileAcceptRisks:
40+
errs = append(errs, field.Required(field.NewPath("spec", "desiredUpdate"), "must specify architecture, version, image, or acceptRisks"))
3741
case len(u.Version) > 0 && !validSemVer(u.Version):
3842
errs = append(errs, field.Invalid(field.NewPath("spec", "desiredUpdate", "version"), u.Version,
3943
"must be a semantic version (1.2.3[-...])"))

lib/validation/validation_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package validation
2+
3+
import (
4+
"testing"
5+
6+
"github.com/google/go-cmp/cmp"
7+
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
"k8s.io/apimachinery/pkg/util/validation/field"
10+
11+
configv1 "github.com/openshift/api/config/v1"
12+
)
13+
14+
func TestValidateClusterVersion(t *testing.T) {
15+
tests := []struct {
16+
name string
17+
config *configv1.ClusterVersion
18+
shouldReconcileAcceptRisks bool
19+
expect field.ErrorList
20+
}{
21+
{
22+
name: "allow accept risks if shouldReconcileAcceptRisks is true",
23+
shouldReconcileAcceptRisks: true,
24+
config: &configv1.ClusterVersion{
25+
ObjectMeta: metav1.ObjectMeta{
26+
Name: "version",
27+
},
28+
Spec: configv1.ClusterVersionSpec{
29+
DesiredUpdate: &configv1.Update{
30+
AcceptRisks: []configv1.AcceptRisk{{
31+
Name: "SomeInfrastructureThing",
32+
}, {
33+
Name: "SomeChannelThing",
34+
}},
35+
},
36+
},
37+
},
38+
},
39+
{
40+
name: "forbid accept risks if shouldReconcileAcceptRisks is false",
41+
config: &configv1.ClusterVersion{
42+
ObjectMeta: metav1.ObjectMeta{
43+
Name: "version",
44+
},
45+
Spec: configv1.ClusterVersionSpec{
46+
DesiredUpdate: &configv1.Update{
47+
AcceptRisks: []configv1.AcceptRisk{{
48+
Name: "SomeInfrastructureThing",
49+
}, {
50+
Name: "SomeChannelThing",
51+
}},
52+
},
53+
},
54+
},
55+
expect: append(make(field.ErrorList, 0), field.Forbidden(field.NewPath("spec", "desiredUpdate", "acceptRisks"), "acceptRisks must not be specified")),
56+
},
57+
{
58+
name: "empty desired update is not allowed if shouldReconcileAcceptRisks is true",
59+
shouldReconcileAcceptRisks: true,
60+
config: &configv1.ClusterVersion{
61+
ObjectMeta: metav1.ObjectMeta{
62+
Name: "version",
63+
},
64+
Spec: configv1.ClusterVersionSpec{DesiredUpdate: &configv1.Update{}},
65+
},
66+
expect: append(make(field.ErrorList, 0), field.Required(field.NewPath("spec", "desiredUpdate"), "must specify architecture, version, image, or acceptRisks")),
67+
},
68+
{
69+
name: "empty desired update is not allowed if shouldReconcileAcceptRisks is false",
70+
config: &configv1.ClusterVersion{
71+
ObjectMeta: metav1.ObjectMeta{
72+
Name: "version",
73+
},
74+
Spec: configv1.ClusterVersionSpec{DesiredUpdate: &configv1.Update{}},
75+
},
76+
expect: append(make(field.ErrorList, 0), field.Required(field.NewPath("spec", "desiredUpdate"), "must specify architecture, version, or image")),
77+
},
78+
}
79+
for _, test := range tests {
80+
t.Run(test.name, func(t *testing.T) {
81+
actual := ValidateClusterVersion(test.config, test.shouldReconcileAcceptRisks)
82+
if diff := cmp.Diff(test.expect, actual); diff != "" {
83+
t.Errorf("(-want, +got): %s", diff)
84+
}
85+
})
86+
}
87+
}

pkg/cvo/cvo.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,7 @@ func (optr *Operator) sync(ctx context.Context, key string) error {
748748
optr.uid = original.UID
749749

750750
// ensure that the object we do have is valid
751-
errs := validation.ValidateClusterVersion(original)
751+
errs := validation.ValidateClusterVersion(original, optr.shouldReconcileAcceptRisks())
752752
// for fields that have meaning that are incomplete, clear them
753753
// prevents us from loading clearly malformed payloads
754754
config := validation.ClearInvalidFields(original, errs)
@@ -839,7 +839,7 @@ func (optr *Operator) upgradeableSyncFunc(ignoreThrottlePeriod bool) func(_ cont
839839
if err != nil {
840840
return err
841841
}
842-
if errs := validation.ValidateClusterVersion(config); len(errs) > 0 {
842+
if errs := validation.ValidateClusterVersion(config, optr.shouldReconcileAcceptRisks()); len(errs) > 0 {
843843
return nil
844844
}
845845

pkg/cvo/cvo_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3845,6 +3845,7 @@ func TestOperator_upgradeableSync(t *testing.T) {
38453845

38463846
optr.upgradeableChecks = optr.defaultUpgradeableChecks()
38473847
optr.eventRecorder = record.NewFakeRecorder(100)
3848+
optr.enabledCVOFeatureGates = featuregates.DefaultCvoGates("version")
38483849

38493850
if tt.gateCm != nil {
38503851
if tt.gateCm.Name == "delete" {

0 commit comments

Comments
 (0)