Skip to content

Commit 5d12697

Browse files
Merge pull request #1731 from atiratree/kubeversion
OCPBUGS-41257: introduce --operand-kubernetes-version flag and resolve API group versions accordingly
2 parents 37df1b1 + fa7f7d5 commit 5d12697

File tree

5 files changed

+183
-16
lines changed

5 files changed

+183
-16
lines changed

pkg/cmd/render/render.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"os"
1515
"path/filepath"
1616

17+
"github.com/blang/semver/v4"
1718
"github.com/ghodss/yaml"
1819
configv1 "github.com/openshift/api/config/v1"
1920
"github.com/openshift/api/features"
@@ -40,6 +41,8 @@ type renderOpts struct {
4041
manifest genericrenderoptions.ManifestOptions
4142
generic genericrenderoptions.GenericOptions
4243

44+
operandKubernetesVersion string
45+
4346
lockHostPath string
4447
etcdServerURLs []string
4548
etcdServingCA string
@@ -98,6 +101,7 @@ func (r *renderOpts) AddFlags(fs *pflag.FlagSet) {
98101
fs.StringVar(&r.clusterConfigFile, "cluster-config-file", r.clusterConfigFile, "Openshift Cluster API Config file.")
99102
fs.StringVar(&r.clusterAuthFile, "cluster-auth-file", r.clusterAuthFile, "Openshift Cluster Authentication API Config file.")
100103
fs.StringVar(&r.infraConfigFile, "infra-config-file", "", "File containing infrastructure.config.openshift.io manifest.")
104+
fs.StringVar(&r.operandKubernetesVersion, "operand-kubernetes-version", "", "Kubernetes version of the operand (hyperkube image).")
101105
}
102106

103107
// Validate verifies the inputs.
@@ -127,6 +131,14 @@ func (r *renderOpts) Validate() error {
127131
return err
128132
}
129133

134+
// TODO add after installer PR is merged
135+
//if len(r.operandKubernetesVersion) == 0 {
136+
// return errors.New("missing operand kubernetes version: --operand-kubernetes-version")
137+
//}
138+
//if _, err := semver.Parse(r.operandKubernetesVersion); err != nil {
139+
// return err
140+
//}
141+
130142
return nil
131143
}
132144

@@ -139,7 +151,15 @@ func (r *renderOpts) Complete() error {
139151
return err
140152
}
141153
if r.groupVersionsByFeatureGate == nil {
142-
r.groupVersionsByFeatureGate = apienablement.DefaultGroupVersionsByFeatureGate
154+
// TODO remove after installer PR is merged
155+
if len(r.operandKubernetesVersion) == 0 {
156+
r.operandKubernetesVersion = "1.30.0"
157+
}
158+
var err error
159+
r.groupVersionsByFeatureGate, err = apienablement.GetDefaultGroupVersionByFeatureGate(semver.MustParse(r.operandKubernetesVersion))
160+
if err != nil {
161+
return err
162+
}
143163
}
144164
return nil
145165
}

pkg/operator/configobservation/apienablement/observe_runtime_config.go

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ package apienablement
33
import (
44
"fmt"
55
"sort"
6+
"strings"
67

8+
"github.com/blang/semver/v4"
79
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
810
"k8s.io/apimachinery/pkg/runtime/schema"
911
"k8s.io/apimachinery/pkg/util/sets"
@@ -12,11 +14,47 @@ import (
1214
"github.com/openshift/library-go/pkg/operator/configobserver"
1315
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
1416
"github.com/openshift/library-go/pkg/operator/events"
17+
"github.com/openshift/library-go/pkg/operator/v1helpers"
1518
)
1619

17-
var DefaultGroupVersionsByFeatureGate = map[configv1.FeatureGateName][]schema.GroupVersion{
18-
"ValidatingAdmissionPolicy": {{Group: "admissionregistration.k8s.io", Version: "v1beta1"}},
19-
"DynamicResourceAllocation": {{Group: "resource.k8s.io", Version: "v1alpha2"}},
20+
var defaultGroupVersionsByFeatureGate = map[configv1.FeatureGateName][]groupVersionByOpenshiftVersion{
21+
"ValidatingAdmissionPolicy": {{GroupVersion: schema.GroupVersion{Group: "admissionregistration.k8s.io", Version: "v1beta1"}}},
22+
"DynamicResourceAllocation": {
23+
{KubeVersionRange: semver.MustParseRange("< 1.31.0"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha2"}},
24+
{KubeVersionRange: semver.MustParseRange(">= 1.31.0"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha3"}},
25+
},
26+
}
27+
28+
type groupVersionByOpenshiftVersion struct {
29+
schema.GroupVersion
30+
KubeVersionRange semver.Range
31+
}
32+
33+
func getGroupVersionByFeatureGate(groupVersionsByFeatureGate map[configv1.FeatureGateName][]groupVersionByOpenshiftVersion, kubeVersion semver.Version) (map[configv1.FeatureGateName][]schema.GroupVersion, error) {
34+
result := make(map[configv1.FeatureGateName][]schema.GroupVersion, len(groupVersionsByFeatureGate))
35+
groupByVersions := map[string][]string{}
36+
for featureGate, APIGroups := range groupVersionsByFeatureGate {
37+
for _, group := range APIGroups {
38+
if group.KubeVersionRange == nil || group.KubeVersionRange(kubeVersion) {
39+
groupByVersions[group.Group] = append(groupByVersions[group.Group], group.Version)
40+
result[featureGate] = append(result[featureGate], group.GroupVersion)
41+
}
42+
}
43+
}
44+
var errs []error
45+
for group, versions := range groupByVersions {
46+
if len(versions) > 1 {
47+
errs = append(errs, fmt.Errorf("found a duplicate group %v for FeatureGates, versions found: %v", group, strings.Join(versions, ",")))
48+
}
49+
}
50+
if len(errs) > 0 {
51+
return nil, v1helpers.NewMultiLineAggregate(errs)
52+
}
53+
return result, nil
54+
}
55+
56+
func GetDefaultGroupVersionByFeatureGate(kubeVersion semver.Version) (map[configv1.FeatureGateName][]schema.GroupVersion, error) {
57+
return getGroupVersionByFeatureGate(defaultGroupVersionsByFeatureGate, kubeVersion)
2058
}
2159

2260
var (

pkg/operator/configobservation/apienablement/observe_runtime_config_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"errors"
55
"testing"
66

7+
"github.com/blang/semver/v4"
78
"github.com/google/go-cmp/cmp"
89
configv1 "github.com/openshift/api/config/v1"
910
"github.com/openshift/library-go/pkg/operator/configobserver"
@@ -169,3 +170,105 @@ func TestFeatureGateObserverWithRuntimeConfig(t *testing.T) {
169170
})
170171
}
171172
}
173+
174+
func TestGroupVersionsByFeatureGate(t *testing.T) {
175+
for _, tc := range []struct {
176+
name string
177+
kubeVersion semver.Version
178+
groupVersionsByFeatureGate map[configv1.FeatureGateName][]groupVersionByOpenshiftVersion
179+
expectedGroupVersions map[configv1.FeatureGateName][]schema.GroupVersion
180+
expectErrors bool
181+
}{
182+
{
183+
name: "partial from/to",
184+
kubeVersion: semver.MustParse("1.30.0"),
185+
groupVersionsByFeatureGate: map[configv1.FeatureGateName][]groupVersionByOpenshiftVersion{
186+
"ValidatingAdmissionPolicy": {{GroupVersion: schema.GroupVersion{Group: "admissionregistration.k8s.io", Version: "v1beta1"}}},
187+
"DynamicResourceAllocation": {
188+
{KubeVersionRange: semver.MustParseRange("< 1.31.0"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha2"}},
189+
{KubeVersionRange: semver.MustParseRange(">= 1.31.0"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha3"}},
190+
},
191+
},
192+
expectedGroupVersions: map[configv1.FeatureGateName][]schema.GroupVersion{
193+
"ValidatingAdmissionPolicy": {{Group: "admissionregistration.k8s.io", Version: "v1beta1"}},
194+
"DynamicResourceAllocation": {{Group: "resource.k8s.io", Version: "v1alpha2"}},
195+
},
196+
},
197+
{
198+
name: "resolves newer API",
199+
kubeVersion: semver.MustParse("1.31.0"),
200+
groupVersionsByFeatureGate: map[configv1.FeatureGateName][]groupVersionByOpenshiftVersion{
201+
"DynamicResourceAllocation": {
202+
{KubeVersionRange: semver.MustParseRange("< 1.31.0"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha2"}},
203+
{KubeVersionRange: semver.MustParseRange(">= 1.31.0"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha3"}},
204+
},
205+
},
206+
expectedGroupVersions: map[configv1.FeatureGateName][]schema.GroupVersion{
207+
"DynamicResourceAllocation": {{Group: "resource.k8s.io", Version: "v1alpha3"}},
208+
},
209+
},
210+
{
211+
name: "resolves minor versions API",
212+
kubeVersion: semver.MustParse("1.31.15"),
213+
groupVersionsByFeatureGate: map[configv1.FeatureGateName][]groupVersionByOpenshiftVersion{
214+
"DynamicResourceAllocation": {
215+
{KubeVersionRange: semver.MustParseRange("< 1.31.15"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha2"}},
216+
{KubeVersionRange: semver.MustParseRange(">= 1.31.15"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha3"}},
217+
},
218+
},
219+
expectedGroupVersions: map[configv1.FeatureGateName][]schema.GroupVersion{
220+
"DynamicResourceAllocation": {{Group: "resource.k8s.io", Version: "v1alpha3"}},
221+
},
222+
},
223+
{
224+
name: "no intersection resolves to empty",
225+
kubeVersion: semver.MustParse("1.31.15"),
226+
groupVersionsByFeatureGate: map[configv1.FeatureGateName][]groupVersionByOpenshiftVersion{
227+
"DynamicResourceAllocation": {
228+
{KubeVersionRange: semver.MustParseRange("< 1.31.14"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha2"}},
229+
{KubeVersionRange: semver.MustParseRange(">= 1.31.16"), GroupVersion: schema.GroupVersion{Group: "resource.k8s.io", Version: "v1alpha3"}},
230+
},
231+
},
232+
expectedGroupVersions: map[configv1.FeatureGateName][]schema.GroupVersion{},
233+
},
234+
{
235+
name: "intersection of group versions should result in an error",
236+
kubeVersion: semver.MustParse("1.31.0"),
237+
groupVersionsByFeatureGate: map[configv1.FeatureGateName][]groupVersionByOpenshiftVersion{
238+
"DynamicResourceAllocation": {
239+
{KubeVersionRange: semver.MustParseRange("< 1.32.0"), GroupVersion: schema.GroupVersion{Group: "resource-a.k8s.io", Version: "v1alpha2"}},
240+
{KubeVersionRange: semver.MustParseRange(">= 1.30.0"), GroupVersion: schema.GroupVersion{Group: "resource-a.k8s.io", Version: "v1alpha3"}},
241+
{KubeVersionRange: semver.MustParseRange(">= 1.31.0"), GroupVersion: schema.GroupVersion{Group: "resource-b.k8s.io", Version: "v1alpha2"}},
242+
},
243+
},
244+
expectErrors: true,
245+
},
246+
{
247+
name: "intersection of group versions across feature gates should result in an error",
248+
kubeVersion: semver.MustParse("1.31.0"),
249+
groupVersionsByFeatureGate: map[configv1.FeatureGateName][]groupVersionByOpenshiftVersion{
250+
"DynamicResourceAllocation": {
251+
{KubeVersionRange: semver.MustParseRange("< 1.32.0"), GroupVersion: schema.GroupVersion{Group: "resource-a.k8s.io", Version: "v1alpha2"}},
252+
{KubeVersionRange: semver.MustParseRange(">= 1.31.0"), GroupVersion: schema.GroupVersion{Group: "resource-b.k8s.io", Version: "v1alpha2"}},
253+
},
254+
"DRA": {
255+
{GroupVersion: schema.GroupVersion{Group: "resource-b.k8s.io", Version: "v1alpha1"}},
256+
},
257+
},
258+
expectErrors: true,
259+
},
260+
} {
261+
t.Run(tc.name, func(t *testing.T) {
262+
actual, err := getGroupVersionByFeatureGate(tc.groupVersionsByFeatureGate, tc.kubeVersion)
263+
if diff := cmp.Diff(tc.expectedGroupVersions, actual); diff != "" {
264+
t.Errorf("unexpected group versions:\n%s", diff)
265+
}
266+
if tc.expectErrors && err == nil {
267+
t.Errorf("expected errors but got none")
268+
}
269+
if !tc.expectErrors && err != nil {
270+
t.Errorf("unexpecteded errors: %v", err)
271+
}
272+
})
273+
}
274+
}

pkg/operator/configobservation/configobservercontroller/observe_config_controller.go

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
package configobservercontroller
22

33
import (
4-
configv1 "github.com/openshift/api/config/v1"
5-
operatorv1informers "github.com/openshift/client-go/operator/informers/externalversions"
4+
"k8s.io/apimachinery/pkg/runtime/schema"
65
"k8s.io/apimachinery/pkg/util/sets"
76
"k8s.io/client-go/tools/cache"
87

8+
configv1 "github.com/openshift/api/config/v1"
99
configinformers "github.com/openshift/client-go/config/informers/externalversions"
10+
operatorv1informers "github.com/openshift/client-go/operator/informers/externalversions"
1011
"github.com/openshift/library-go/pkg/controller/factory"
1112
"github.com/openshift/library-go/pkg/operator/configobserver"
1213
libgoapiserver "github.com/openshift/library-go/pkg/operator/configobserver/apiserver"
@@ -37,15 +38,7 @@ type ConfigObserver struct {
3738
factory.Controller
3839
}
3940

40-
func NewConfigObserver(
41-
operatorClient v1helpers.StaticPodOperatorClient,
42-
kubeInformersForNamespaces v1helpers.KubeInformersForNamespaces,
43-
configInformer configinformers.SharedInformerFactory,
44-
operatorInformer operatorv1informers.SharedInformerFactory,
45-
resourceSyncer resourcesynccontroller.ResourceSyncer,
46-
featureGateAccessor featuregates.FeatureGateAccess,
47-
eventRecorder events.Recorder,
48-
) *ConfigObserver {
41+
func NewConfigObserver(operatorClient v1helpers.StaticPodOperatorClient, kubeInformersForNamespaces v1helpers.KubeInformersForNamespaces, configInformer configinformers.SharedInformerFactory, operatorInformer operatorv1informers.SharedInformerFactory, resourceSyncer resourcesynccontroller.ResourceSyncer, featureGateAccessor featuregates.FeatureGateAccess, eventRecorder events.Recorder, groupVersionsByFeatureGate map[configv1.FeatureGateName][]schema.GroupVersion) *ConfigObserver {
4942
interestingNamespaces := []string{
5043
operatorclient.GlobalUserSpecifiedConfigNamespace,
5144
operatorclient.GlobalMachineSpecifiedConfigNamespace,
@@ -147,7 +140,7 @@ func NewConfigObserver(
147140
nil,
148141
FeatureBlacklist,
149142
featureGateAccessor,
150-
apienablement.DefaultGroupVersionsByFeatureGate,
143+
groupVersionsByFeatureGate,
151144
),
152145
network.ObserveRestrictedCIDRs,
153146
network.ObserveServicesSubnet,

pkg/operator/starter.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"os"
99
"time"
1010

11+
"github.com/blang/semver/v4"
12+
1113
configv1 "github.com/openshift/api/config/v1"
1214
operatorv1 "github.com/openshift/api/operator/v1"
1315
configv1client "github.com/openshift/client-go/config/clientset/versioned"
@@ -22,6 +24,7 @@ import (
2224
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/certrotationcontroller"
2325
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/certrotationtimeupgradeablecontroller"
2426
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/configmetrics"
27+
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/configobservation/apienablement"
2528
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/configobservation/configobservercontroller"
2629
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/configobservation/node"
2730
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/connectivitycheckcontroller"
@@ -105,6 +108,15 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
105108
if err != nil {
106109
return err
107110
}
111+
operandKubernetesVersion, err := semver.Parse(status.VersionForOperandFromEnv())
112+
if err != nil {
113+
return err
114+
}
115+
groupVersionsByFeatureGate, err := apienablement.GetDefaultGroupVersionByFeatureGate(operandKubernetesVersion)
116+
if err != nil {
117+
return err
118+
}
119+
108120
kubeInformersForNamespaces := v1helpers.NewKubeInformersForNamespaces(
109121
kubeClient,
110122
"",
@@ -169,6 +181,7 @@ func RunOperator(ctx context.Context, controllerContext *controllercmd.Controlle
169181
resourceSyncController,
170182
featureGateAccessor,
171183
controllerContext.EventRecorder,
184+
groupVersionsByFeatureGate,
172185
)
173186

174187
serviceAccountIssuerController := serviceaccountissuercontroller.NewController(operatorV1Client.OperatorV1().KubeAPIServers(), operatorInformers, configInformers, controllerContext.EventRecorder)

0 commit comments

Comments
 (0)