Skip to content

Commit 614b98d

Browse files
Merge pull request #400 from mtulio/SPLAT-2341-fg-support
SPLAT-2341: Add feature gate support in the cloud-config sync controller
2 parents e355ad3 + c63ea02 commit 614b98d

15 files changed

Lines changed: 147 additions & 21 deletions

cmd/config-sync-controllers/main.go

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626

2727
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
2828
// to ensure that exec-entrypoint and run can make use of them.
29+
"k8s.io/client-go/kubernetes"
2930
_ "k8s.io/client-go/plugin/pkg/client/auth"
3031

3132
"k8s.io/apimachinery/pkg/runtime"
@@ -40,6 +41,11 @@ import (
4041
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
4142

4243
configv1 "github.com/openshift/api/config/v1"
44+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
45+
"github.com/openshift/library-go/pkg/operator/events"
46+
47+
configv1client "github.com/openshift/client-go/config/clientset/versioned"
48+
configinformers "github.com/openshift/client-go/config/informers/externalversions"
4349

4450
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/controllers"
4551
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/restmapper"
@@ -79,6 +85,12 @@ func main() {
7985
"The namespace for managed objects, target cloud-conf in particular.",
8086
)
8187

88+
recorderName := "cloud-controller-manager-operator-cloud-config-sync-controller"
89+
missingVersion := "0.0.1-snapshot"
90+
desiredVersion := controllers.GetReleaseVersion()
91+
sharedClock := clock.RealClock{}
92+
ctx := ctrl.SetupSignalHandler()
93+
8294
// Once all the flags are regitered, switch to pflag
8395
// to allow leader lection flags to be bound
8496
pflag.CommandLine.AddGoFlagSet(flag.CommandLine)
@@ -131,7 +143,36 @@ func main() {
131143
os.Exit(1)
132144
}
133145

134-
sharedClock := clock.RealClock{}
146+
// Feature gate accessor
147+
configClient, err := configv1client.NewForConfig(mgr.GetConfig())
148+
if err != nil {
149+
setupLog.Error(err, "unable to create config client")
150+
os.Exit(1)
151+
}
152+
kubeClient, err := kubernetes.NewForConfig(mgr.GetConfig())
153+
if err != nil {
154+
setupLog.Error(err, "unable to create kube client")
155+
os.Exit(1)
156+
}
157+
158+
configInformers := configinformers.NewSharedInformerFactory(configClient, 10*time.Minute)
159+
controllerRef, err := events.GetControllerReferenceForCurrentPod(ctx, kubeClient, *managedNamespace, nil)
160+
if err != nil {
161+
klog.Warningf("unable to get owner reference (falling back to namespace): %v", err)
162+
}
163+
164+
featureGateAccessor := featuregates.NewFeatureGateAccess(
165+
desiredVersion, missingVersion,
166+
configInformers.Config().V1().ClusterVersions(), configInformers.Config().V1().FeatureGates(),
167+
events.NewKubeRecorder(kubeClient.CoreV1().Events(*managedNamespace), recorderName, controllerRef, sharedClock),
168+
)
169+
featureGateAccessor.SetChangeHandler(func(featureChange featuregates.FeatureChange) {
170+
// Do nothing here. The controller watches feature gate changes and will react to them.
171+
klog.InfoS("FeatureGates changed", "enabled", featureChange.New.Enabled, "disabled", featureChange.New.Disabled)
172+
})
173+
go featureGateAccessor.Run(ctx)
174+
go configInformers.Start(ctx.Done())
175+
135176
if err = (&controllers.CloudConfigReconciler{
136177
ClusterOperatorStatusClient: controllers.ClusterOperatorStatusClient{
137178
Client: mgr.GetClient(),
@@ -140,7 +181,8 @@ func main() {
140181
ReleaseVersion: controllers.GetReleaseVersion(),
141182
ManagedNamespace: *managedNamespace,
142183
},
143-
Scheme: mgr.GetScheme(),
184+
Scheme: mgr.GetScheme(),
185+
FeatureGateAccess: featureGateAccessor,
144186
}).SetupWithManager(mgr); err != nil {
145187
setupLog.Error(err, "unable to create cloud-config sync controller", "controller", "ClusterOperator")
146188
os.Exit(1)
@@ -171,7 +213,7 @@ func main() {
171213
}
172214

173215
setupLog.Info("starting manager")
174-
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
216+
if err := mgr.Start(ctx); err != nil {
175217
setupLog.Error(err, "problem running manager")
176218
os.Exit(1)
177219
}

pkg/cloud/aws/aws_config_transformer.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import (
1111
"gopkg.in/ini.v1"
1212

1313
awsconfig "k8s.io/cloud-provider-aws/pkg/providers/v1/config"
14+
15+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
1416
)
1517

1618
// defaultConfig is a string holding the absolute bare minimum INI string that the AWS CCM needs to start.
@@ -20,7 +22,7 @@ const defaultConfig = `[Global]
2022

2123
// CloudConfigTransformer is used to inject OpenShift configuration defaults into the Cloud Provider config
2224
// for the AWS Cloud Provider. If an empty source string is provided, a minimal default configuration will be created.
23-
func CloudConfigTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network) (string, error) {
25+
func CloudConfigTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network, features featuregates.FeatureGate) (string, error) {
2426
cfg, err := readAWSConfig(source)
2527
if err != nil {
2628
return "", fmt.Errorf("failed to read the cloud.conf: %w", err)

pkg/cloud/aws/aws_config_transformer_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"testing"
55

66
. "github.com/onsi/gomega"
7+
8+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
79
)
810

911
func TestCloudConfigTransformer(t *testing.T) {
@@ -87,7 +89,7 @@ SigningRegion = signing_region
8789
t.Run(tc.name, func(t *testing.T) {
8890
g := NewWithT(t)
8991

90-
gotConfig, err := CloudConfigTransformer(tc.source, nil, nil) // No Infra or Network are required for the current functionality.
92+
gotConfig, err := CloudConfigTransformer(tc.source, nil, nil, featuregates.NewFeatureGate(nil, nil)) // No Infra or Network are required for the current functionality.
9193
g.Expect(err).ToNot(HaveOccurred())
9294

9395
g.Expect(gotConfig).To(Equal(tc.expected))

pkg/cloud/azure/azure.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020

2121
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/cloud/common"
2222
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/config"
23+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
2324
)
2425

2526
const providerName = "azure"
@@ -136,7 +137,7 @@ func IsAzure(infra *configv1.Infrastructure) bool {
136137
return false
137138
}
138139

139-
func CloudConfigTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network) (string, error) {
140+
func CloudConfigTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network, features featuregates.FeatureGate) (string, error) {
140141
if !IsAzure(infra) {
141142
return "", fmt.Errorf("invalid platform, expected CloudName to be %s", configv1.AzurePublicCloud)
142143
}

pkg/cloud/azure/azure_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/onsi/gomega/format"
1010
configv1 "github.com/openshift/api/config/v1"
1111
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/config"
12+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
1213
"github.com/stretchr/testify/assert"
1314

1415
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -259,7 +260,7 @@ func TestCloudConfigTransformer(t *testing.T) {
259260
src, err := json.Marshal(tc.source)
260261
g.Expect(err).NotTo(HaveOccurred(), "Marshal of source data should succeed")
261262

262-
actual, err := CloudConfigTransformer(string(src), tc.infra, nil)
263+
actual, err := CloudConfigTransformer(string(src), tc.infra, nil, featuregates.NewFeatureGate(nil, nil))
263264
if tc.errMsg != "" {
264265
g.Expect(err).Should(MatchError(tc.errMsg))
265266
g.Expect(actual).Should(Equal(""))

pkg/cloud/azurestack/azurestack.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/cloud/common"
1717
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/config"
18+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
1819
)
1920

2021
const providerName = "azurestack"
@@ -104,7 +105,7 @@ func IsAzureStackHub(platformStatus *configv1.PlatformStatus) bool {
104105
// modifies it to be compatible with the external cloud provider. It returns
105106
// an error if the platform is not OpenStackPlatformType or if any errors are
106107
// encountered while attempting to rework the configuration.
107-
func CloudConfigTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network) (string, error) {
108+
func CloudConfigTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network, features featuregates.FeatureGate) (string, error) {
108109
if !IsAzureStackHub(infra.Status.PlatformStatus) {
109110
return "", fmt.Errorf("invalid platform, expected CloudName to be %s", configv1.AzureStackCloud)
110111
}

pkg/cloud/azurestack/azurestack_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/stretchr/testify/assert"
1414

1515
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/config"
16+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
1617
)
1718

1819
const (
@@ -144,7 +145,7 @@ func TestCloudConfigTransformer(t *testing.T) {
144145
src, err := json.Marshal(tc.source)
145146
g.Expect(err).NotTo(HaveOccurred(), "Marshal of source data should succeed")
146147

147-
actual, err := CloudConfigTransformer(string(src), tc.infra, nil)
148+
actual, err := CloudConfigTransformer(string(src), tc.infra, nil, featuregates.NewFeatureGate(nil, nil))
148149
if tc.errMsg != "" {
149150
g.Expect(err).Should(MatchError(tc.errMsg))
150151
g.Expect(actual).Should(Equal(""))

pkg/cloud/cloud.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/cloud/common"
1010
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/config"
11+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
1112

1213
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/cloud/aws"
1314
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/cloud/azure"
@@ -23,7 +24,7 @@ import (
2324
// cloudConfigTransformer function transforms the source config map using the input infrastructure.config.openshift.io
2425
// and network.config.openshift.io objects. Only the data and binaryData field of the output ConfigMap will be respected by
2526
// consumer of the transformer.
26-
type cloudConfigTransformer func(source string, infra *configv1.Infrastructure, network *configv1.Network) (string, error)
27+
type cloudConfigTransformer func(source string, infra *configv1.Infrastructure, network *configv1.Network, features featuregates.FeatureGate) (string, error)
2728

2829
// GetCloudConfigTransformer returns the function that should be used to transform
2930
// the cloud configuration config map, and a boolean to indicate if the config should

pkg/cloud/common/config.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package common
22

33
import (
44
configv1 "github.com/openshift/api/config/v1"
5+
6+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
57
)
68

79
// NoOpTransformer implements the cloudConfigTransformer. It makes no changes
810
// to the source configuration and simply returns it as-is.
9-
func NoOpTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network) (string, error) {
11+
func NoOpTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network, features featuregates.FeatureGate) (string, error) {
1012
return source, nil
1113
}

pkg/cloud/openstack/openstack.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/cloud/common"
1616
"github.com/openshift/cluster-cloud-controller-manager-operator/pkg/config"
17+
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
1718
)
1819

1920
const providerName = "openstack"
@@ -142,7 +143,7 @@ func NewProviderAssets(config config.OperatorConfig) (common.CloudProviderAssets
142143
// modifies it to be compatible with the external cloud provider. It returns
143144
// an error if the platform is not OpenStackPlatformType or if any errors are
144145
// encountered while attempting to rework the configuration.
145-
func CloudConfigTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network) (string, error) {
146+
func CloudConfigTransformer(source string, infra *configv1.Infrastructure, network *configv1.Network, features featuregates.FeatureGate) (string, error) {
146147
if infra.Status.PlatformStatus == nil ||
147148
infra.Status.PlatformStatus.Type != configv1.OpenStackPlatformType {
148149
return "", fmt.Errorf("invalid platform, expected to be %s", configv1.OpenStackPlatformType)

0 commit comments

Comments
 (0)