Skip to content

Commit 095cd15

Browse files
committed
Adds initial proxy.spec validation
1 parent 0830ac3 commit 095cd15

2 files changed

Lines changed: 430 additions & 4 deletions

File tree

pkg/controller/proxyconfig/proxyconfig_controller.go

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,24 @@ package proxyconfig
33
import (
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
5363
type 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\njson:\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

Comments
 (0)