diff --git a/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go b/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go index 90b3195789..6499296565 100644 --- a/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go +++ b/pkg/operator/configobserver/cloudprovider/observe_cloudprovider.go @@ -77,6 +77,7 @@ func (c *cloudProviderObserver) ObserveCloudProviderNames(genericListers configo return observedConfig, errs } if err != nil { + errs = append(errs, err) return previouslyObservedConfig, errs } diff --git a/pkg/operator/configobserver/proxy/observe_proxy.go b/pkg/operator/configobserver/proxy/observe_proxy.go new file mode 100644 index 0000000000..53988d6b8d --- /dev/null +++ b/pkg/operator/configobserver/proxy/observe_proxy.go @@ -0,0 +1,88 @@ +package proxy + +import ( + "reflect" + + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + + configv1 "github.com/openshift/api/config/v1" + configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" + "github.com/openshift/library-go/pkg/operator/configobserver" + "github.com/openshift/library-go/pkg/operator/events" +) + +type ProxyLister interface { + ProxyLister() configlistersv1.ProxyLister +} + +func NewProxyObserveFunc(configPath []string) configobserver.ObserveConfigFunc { + return (&observeProxyFlags{ + configPath: configPath, + }).ObserveProxyConfig +} + +type observeProxyFlags struct { + configPath []string +} + +// ObserveProxyConfig observes the proxy.config.openshift.io/cluster object and writes +// its content to an unstructured object in a string map at the path from the constructor +func (f *observeProxyFlags) ObserveProxyConfig(genericListers configobserver.Listers, recorder events.Recorder, existingConfig map[string]interface{}) (map[string]interface{}, []error) { + proxyLister := genericListers.(ProxyLister) + + errs := []error{} + prevObservedProxyConfig := map[string]interface{}{} + + // grab the current Proxy config to later check whether it was updated + currentProxyMap, _, err := unstructured.NestedStringMap(existingConfig, f.configPath...) + if err != nil { + return prevObservedProxyConfig, append(errs, err) + } + + if len(currentProxyMap) > 0 { + unstructured.SetNestedStringMap(prevObservedProxyConfig, currentProxyMap, f.configPath...) + } + + observedConfig := map[string]interface{}{} + proxyConfig, err := proxyLister.ProxyLister().Get("cluster") + if errors.IsNotFound(err) { + recorder.Warningf("ObserveProxyConfig", "proxy.%s/cluster not found", configv1.GroupName) + return observedConfig, errs + } + if err != nil { + errs = append(errs, err) + return existingConfig, errs + } + + newProxyMap := proxyToMap(proxyConfig) + if len(newProxyMap) > 0 { + if err := unstructured.SetNestedStringMap(observedConfig, newProxyMap, f.configPath...); err != nil { + errs = append(errs, err) + } + } + + if !reflect.DeepEqual(currentProxyMap, newProxyMap) { + recorder.Eventf("ObserveProxyConfig", "proxy changed to %q", newProxyMap) + } + + return observedConfig, errs +} + +func proxyToMap(proxy *configv1.Proxy) map[string]string { + proxyMap := map[string]string{} + + if noProxy := proxy.Spec.NoProxy; len(noProxy) > 0 { + proxyMap["NO_PROXY"] = noProxy + } + + if httpProxy := proxy.Spec.HTTPProxy; len(httpProxy) > 0 { + proxyMap["HTTP_PROXY"] = httpProxy + } + + if httpsProxy := proxy.Spec.HTTPSProxy; len(httpsProxy) > 0 { + proxyMap["HTTPS_PROXY"] = httpsProxy + } + + return proxyMap +} diff --git a/pkg/operator/configobserver/proxy/observe_proxy_test.go b/pkg/operator/configobserver/proxy/observe_proxy_test.go new file mode 100644 index 0000000000..4909ea8fc2 --- /dev/null +++ b/pkg/operator/configobserver/proxy/observe_proxy_test.go @@ -0,0 +1,91 @@ +package proxy + +import ( + "reflect" + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/tools/cache" + + configv1 "github.com/openshift/api/config/v1" + configlistersv1 "github.com/openshift/client-go/config/listers/config/v1" + "github.com/openshift/library-go/pkg/operator/events" + "github.com/openshift/library-go/pkg/operator/resourcesynccontroller" +) + +type testLister struct { + lister configlistersv1.ProxyLister +} + +func (l testLister) ProxyLister() configlistersv1.ProxyLister { + return l.lister +} + +func (l testLister) ResourceSyncer() resourcesynccontroller.ResourceSyncer { + return nil +} + +func (l testLister) PreRunHasSynced() []cache.InformerSynced { + return nil +} + +func TestObserveProxyConfig(t *testing.T) { + configPath := []string{"openshift", "proxy"} + + tests := []struct { + name string + proxySpec configv1.ProxySpec + expected map[string]interface{} + expectedError []error + }{ + { + name: "all unset", + proxySpec: configv1.ProxySpec{}, + expected: map[string]interface{}{}, + expectedError: []error{}, + }, + { + name: "all set", + proxySpec: configv1.ProxySpec{ + HTTPProxy: "http://someplace.it", + HTTPSProxy: "https://someplace.it", + NoProxy: "127.0.0.1", + }, + expected: map[string]interface{}{ + "openshift": map[string]interface{}{ + "proxy": map[string]interface{}{ + "HTTP_PROXY": "http://someplace.it", + "HTTPS_PROXY": "https://someplace.it", + "NO_PROXY": "127.0.0.1", + }, + }, + }, + expectedError: []error{}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{}) + indexer.Add(&configv1.Proxy{ + ObjectMeta: metav1.ObjectMeta{Name: "cluster"}, + Spec: tt.proxySpec, + }) + listers := testLister{ + lister: configlistersv1.NewProxyLister(indexer), + } + eventRecorder := events.NewInMemoryRecorder("") + + initialExistingConfig := map[string]interface{}{} + + observeFn := NewProxyObserveFunc(configPath) + + got, errorsGot := observeFn(listers, eventRecorder, initialExistingConfig) + if !reflect.DeepEqual(got, tt.expected) { + t.Errorf("observeProxyFlags.ObserveProxyConfig() got = %v, want %v", got, tt.expected) + } + if !reflect.DeepEqual(errorsGot, tt.expectedError) { + t.Errorf("observeProxyFlags.ObserveProxyConfig() errorsGot = %v, want %v", errorsGot, tt.expectedError) + } + }) + } +}