@@ -3,14 +3,24 @@ package proxyconfig
33import (
44 "context"
55 "fmt"
6+ "k8s.io/apimachinery/pkg/types"
67 "log"
8+ "net/url"
9+ "strconv"
10+ "strings"
11+
12+ "github.com/ghodss/yaml"
713
814 configv1 "github.com/openshift/api/config/v1"
915 "github.com/openshift/cluster-network-operator/pkg/controller/statusmanager"
1016 "github.com/openshift/cluster-network-operator/pkg/names"
17+ "github.com/openshift/cluster-network-operator/pkg/proxy"
18+
19+ corev1 "k8s.io/api/core/v1"
1120
1221 apierrors "k8s.io/apimachinery/pkg/api/errors"
1322 "k8s.io/apimachinery/pkg/runtime"
23+ "k8s.io/apimachinery/pkg/util/sets"
1424 "sigs.k8s.io/controller-runtime/pkg/client"
1525 "sigs.k8s.io/controller-runtime/pkg/controller"
1626 "sigs.k8s.io/controller-runtime/pkg/handler"
@@ -52,7 +62,7 @@ var _ reconcile.Reconciler = &ReconcileProxyConfig{}
5262// ReconcileProxyConfig reconciles a Proxy object
5363type ReconcileProxyConfig struct {
5464 // This client, initialized using mgr.Client() above, is a split client
55- // that reads objects from the cache and writes to the apiserver
65+ // that reads objects from the cache and writes to the apiserver.
5666 client client.Client
5767 scheme * runtime.Scheme
5868 status * statusmanager.StatusManager
@@ -83,9 +93,120 @@ func (r *ReconcileProxyConfig) Reconcile(request reconcile.Request) (reconcile.R
8393 return reconcile.Result {}, fmt .Errorf ("failed to get proxy %q: %v" , request , err )
8494 }
8595
86- // TODO: Validate the proxy spec and write status.
96+ // Only proceed if we can collect cluster config.
97+ infraConfig := & configv1.Infrastructure {}
98+ if err := r .client .Get (context .TODO (), types.NamespacedName {Name : "cluster" }, infraConfig ); err != nil {
99+ return reconcile.Result {}, fmt .Errorf ("failed to get infrastructure config 'cluster': %v" , err )
100+ }
101+ netConfig := & configv1.Network {}
102+ if err := r .client .Get (context .TODO (), types.NamespacedName {Name : "cluster" }, infraConfig ); err != nil {
103+ return reconcile.Result {}, fmt .Errorf ("failed to get network config 'cluster': %v" , err )
104+ }
105+ clusterConfig := & corev1.ConfigMap {}
106+ if err := r .client .Get (context .TODO (), types.NamespacedName {Name : "cluster-config-v1" }, clusterConfig ); err != nil {
107+ return reconcile.Result {}, fmt .Errorf ("failed to get network config 'cluster': %v" , err )
108+ }
109+
110+ if err := proxy .ValidateProxyConfig (r .client , proxyConfig .Spec ); err != nil {
111+ log .Printf ("Failed to validate Proxy.Spec: %v" , err )
112+ r .status .SetDegraded (statusmanager .ProxyConfig , "InvalidProxyConfig" ,
113+ fmt .Sprintf ("The proxy configuration is invalid (%v). Use 'oc edit proxy.config.openshift.io cluster' to fix." , err ))
114+ return reconcile.Result {}, err
115+ }
116+
117+ if err := r .syncProxyStatus (proxyConfig , infraConfig , netConfig , clusterConfig ); err != nil {
118+ log .Printf ("Failed to enforce NoProxy default values: %v" , err )
119+ r .status .SetDegraded (statusmanager .ProxyConfig , "DefaultNoProxyFailedEnforcement" ,
120+ fmt .Sprintf ("Failed to enforce system default NoProxy values: %v" , err ))
121+ return reconcile.Result {}, err
122+ }
123+
87124 // TODO: How should proxy reconciliation be reflected in clusteroperator/network status?
88125
89126 r .status .SetNotDegraded (statusmanager .ProxyConfig )
90127 return reconcile.Result {}, nil
91128}
129+
130+ // syncProxyStatus...
131+ func (r * ReconcileProxyConfig ) syncProxyStatus (proxy * configv1.Proxy , infra * configv1.Infrastructure , network * configv1.Network , cluster * corev1.ConfigMap ) error {
132+ updated := proxy .DeepCopy ()
133+
134+ apiServerURL , err := url .Parse (infra .Status .APIServerURL )
135+ if err != nil {
136+ return fmt .Errorf ("failed to parse API server URL" )
137+ }
138+ internalAPIServer , err := url .Parse (infra .Status .APIServerInternalURL )
139+ if err != nil {
140+ return fmt .Errorf ("failed to parse API server internal URL" )
141+ }
142+
143+ set := sets .NewString (
144+ "127.0.0.1" ,
145+ "localhost" ,
146+ network .Status .ServiceNetwork [0 ],
147+ apiServerURL .Hostname (),
148+ internalAPIServer .Hostname (),
149+ )
150+ platform := infra .Status .PlatformStatus .Type
151+
152+ // TODO: Does a better way exist to get machineCIDR and controlplane replicas?
153+ type installConfig struct {
154+ ControlPlane struct {
155+ Replicas string `json:"replicas"`
156+ } `json:"controlPlane"`
157+ Networking struct {
158+ MachineCIDR string `json:"machineCIDR"`
159+ } `json:"networking"`
160+ }
161+ var ic installConfig
162+ data , ok := cluster .Data ["install-config" ]
163+ if ! ok {
164+ return fmt .Errorf ("missing install-config in configmap" )
165+ }
166+ if err := yaml .Unmarshal ([]byte (data ), & ic ); err != nil {
167+ return fmt .Errorf ("invalid install-config: %v\n json:\n %s" , err , data )
168+ }
169+
170+ if platform != configv1 .VSpherePlatformType && platform != configv1 .NonePlatformType {
171+ set .Insert ("169.254.169.254" , ic .Networking .MachineCIDR )
172+ }
173+
174+ replicas , err := strconv .Atoi (ic .ControlPlane .Replicas )
175+ if err != nil {
176+ return fmt .Errorf ("failed to parse install config replicas: %v" , err )
177+ }
178+
179+ for i := int64 (0 ); i < int64 (replicas ); i ++ {
180+ etcdHost := fmt .Sprintf ("etcd-%d.%s" , i , infra .Status .EtcdDiscoveryDomain )
181+ set .Insert (etcdHost )
182+ }
183+
184+ for _ , clusterNetwork := range network .Status .ClusterNetwork {
185+ set .Insert (clusterNetwork .CIDR )
186+ }
187+
188+ for _ , userValue := range strings .Split (proxy .Spec .NoProxy , "," ) {
189+ set .Insert (userValue )
190+ }
191+
192+ updated .Status .NoProxy = strings .Join (set .List (), "," )
193+
194+ if ! proxyStatusesEqual (proxy .Status , updated .Status ) {
195+ if err := r .client .Status ().Update (context .TODO (), updated ); err != nil {
196+ return fmt .Errorf ("failed to update proxy status: %v" , err )
197+ }
198+ }
199+
200+ return nil
201+ }
202+
203+ // proxyStatusesEqual compares two ProxyStatus values. Returns true if the
204+ // provided values should be considered equal for the purpose of determining
205+ // whether an update is necessary, false otherwise.
206+ func proxyStatusesEqual (a , b configv1.ProxyStatus ) bool {
207+ if a .HTTPProxy != b .HTTPProxy || a .HTTPSProxy != b .HTTPSProxy || a .NoProxy != b .NoProxy {
208+ return false
209+ }
210+
211+ return true
212+ }
0 commit comments