Skip to content

Commit 30ed9fb

Browse files
author
Sanskar Jaiswal
committed
verify canary spec before syncing
Signed-off-by: Sanskar Jaiswal <sanskar.jaiswal@weave.works>
1 parent 0382d9c commit 30ed9fb

File tree

6 files changed

+141
-18
lines changed

6 files changed

+141
-18
lines changed

docs/gitbook/faq.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ to finish, and disable it afterward (`skipAnalysis: false`).
7474

7575
#### How to disable cross namespace references?
7676

77-
Flagger by default can access resources across namespaces (`AlertProivder` and `MetricProvider`). If you're in a multi-tenant enviornemnt
78-
and wish to disable this, you can do so through the `no-cross-namespace-refs` flag.
77+
Flagger by default can access resources across namespaces (`AlertProivder`, `MetricProvider` and Gloo `Upsteream`).
78+
If you're in a multi-tenant environment and wish to disable this, you can do so through the `no-cross-namespace-refs` flag.
7979

8080
```
8181
flagger \

pkg/controller/controller.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,10 @@ func (c *Controller) syncHandler(key string) error {
253253
return nil
254254
}
255255

256+
if err := c.verifyCanary(cd); err != nil {
257+
return fmt.Errorf("invalid canary spec: %s", err)
258+
}
259+
256260
// Finalize if canary has been marked for deletion and revert is desired
257261
if cd.Spec.RevertOnDeletion && cd.ObjectMeta.DeletionTimestamp != nil {
258262
// If finalizers have been previously removed proceed
@@ -315,6 +319,34 @@ func (c *Controller) enqueue(obj interface{}) {
315319
c.workqueue.AddRateLimited(key)
316320
}
317321

322+
func (c *Controller) verifyCanary(canary *flaggerv1.Canary) error {
323+
if c.noCrossNamespaceRefs {
324+
if err := verifyNoCrossNamespaceRefs(canary); err != nil {
325+
return err
326+
}
327+
}
328+
return nil
329+
}
330+
331+
func verifyNoCrossNamespaceRefs(canary *flaggerv1.Canary) error {
332+
if canary.Spec.UpstreamRef != nil && canary.Spec.UpstreamRef.Namespace != canary.Namespace {
333+
return fmt.Errorf("can't access gloo upstream %s.%s, cross-namespace references are blocked", canary.Spec.UpstreamRef.Name, canary.Spec.UpstreamRef.Namespace)
334+
}
335+
if canary.Spec.Analysis != nil {
336+
for _, metric := range canary.Spec.Analysis.Metrics {
337+
if metric.TemplateRef != nil && metric.TemplateRef.Namespace != canary.Namespace {
338+
return fmt.Errorf("can't access metric template %s.%s, cross-namespace references are blocked", metric.TemplateRef.Name, metric.TemplateRef.Namespace)
339+
}
340+
}
341+
for _, alert := range canary.Spec.Analysis.Alerts {
342+
if alert.ProviderRef.Namespace != canary.Namespace {
343+
return fmt.Errorf("can't access alert provider %s.%s, cross-namespace references are blocked", alert.ProviderRef.Name, alert.ProviderRef.Namespace)
344+
}
345+
}
346+
}
347+
return nil
348+
}
349+
318350
func checkCustomResourceType(obj interface{}, logger *zap.SugaredLogger) (flaggerv1.Canary, bool) {
319351
var roll *flaggerv1.Canary
320352
var ok bool

pkg/controller/controller_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package controller
2+
3+
import (
4+
"testing"
5+
6+
flaggerv1 "github.com/fluxcd/flagger/pkg/apis/flagger/v1beta1"
7+
"github.com/stretchr/testify/require"
8+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9+
)
10+
11+
func TestController_verifyCanary(t *testing.T) {
12+
tests := []struct {
13+
name string
14+
canary flaggerv1.Canary
15+
wantErr bool
16+
}{
17+
{
18+
name: "Gloo upstream in a different namespace should return an error",
19+
canary: flaggerv1.Canary{
20+
ObjectMeta: metav1.ObjectMeta{
21+
Name: "cd-1",
22+
Namespace: "default",
23+
},
24+
Spec: flaggerv1.CanarySpec{
25+
UpstreamRef: &flaggerv1.CrossNamespaceObjectReference{
26+
Name: "upstream",
27+
Namespace: "test",
28+
},
29+
},
30+
},
31+
wantErr: true,
32+
},
33+
{
34+
name: "Gloo upstream in the same namespace is allowed",
35+
canary: flaggerv1.Canary{
36+
ObjectMeta: metav1.ObjectMeta{
37+
Name: "cd-1",
38+
Namespace: "default",
39+
},
40+
Spec: flaggerv1.CanarySpec{
41+
UpstreamRef: &flaggerv1.CrossNamespaceObjectReference{
42+
Name: "upstream",
43+
Namespace: "default",
44+
},
45+
},
46+
},
47+
wantErr: false,
48+
},
49+
{
50+
name: "MetricTemplate in a different namespace should return an error",
51+
canary: flaggerv1.Canary{
52+
ObjectMeta: metav1.ObjectMeta{
53+
Name: "cd-1",
54+
Namespace: "default",
55+
},
56+
Spec: flaggerv1.CanarySpec{
57+
Analysis: &flaggerv1.CanaryAnalysis{
58+
Metrics: []flaggerv1.CanaryMetric{
59+
{
60+
TemplateRef: &flaggerv1.CrossNamespaceObjectReference{
61+
Name: "mt-1",
62+
Namespace: "test",
63+
},
64+
},
65+
},
66+
},
67+
},
68+
},
69+
wantErr: true,
70+
},
71+
{
72+
name: "AlertProvider in a different namespace should return an error",
73+
canary: flaggerv1.Canary{
74+
ObjectMeta: metav1.ObjectMeta{
75+
Name: "cd-1",
76+
Namespace: "default",
77+
},
78+
Spec: flaggerv1.CanarySpec{
79+
Analysis: &flaggerv1.CanaryAnalysis{
80+
Alerts: []flaggerv1.CanaryAlert{
81+
{
82+
ProviderRef: flaggerv1.CrossNamespaceObjectReference{
83+
Name: "ap-1",
84+
Namespace: "test",
85+
},
86+
},
87+
},
88+
},
89+
},
90+
},
91+
wantErr: true,
92+
},
93+
}
94+
95+
ctrl := &Controller{
96+
noCrossNamespaceRefs: true,
97+
}
98+
99+
for _, test := range tests {
100+
t.Run(test.name, func(t *testing.T) {
101+
err := ctrl.verifyCanary(&test.canary)
102+
if test.wantErr {
103+
require.Error(t, err)
104+
}
105+
})
106+
}
107+
}

pkg/controller/events.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,11 +109,6 @@ func (c *Controller) alert(canary *flaggerv1.Canary, message string, metadata bo
109109
// determine alert provider namespace
110110
providerNamespace := canary.GetNamespace()
111111
if alert.ProviderRef.Namespace != canary.Namespace {
112-
if c.noCrossNamespaceRefs {
113-
c.logger.With("canary", fmt.Sprintf("%s.%s", canary.Name, canary.Namespace)).
114-
Errorf("can't access alert provider ref %s.%s, cross-namespace references are blocked", alert.ProviderRef.Name, alert.ProviderRef.Namespace)
115-
return
116-
}
117112
providerNamespace = alert.ProviderRef.Namespace
118113
}
119114

pkg/controller/scheduler_metrics.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ func (c *Controller) checkMetricProviderAvailability(canary *flaggerv1.Canary) e
5555
if metric.TemplateRef != nil {
5656
namespace := canary.Namespace
5757
if metric.TemplateRef.Namespace != canary.Namespace {
58-
if c.noCrossNamespaceRefs {
59-
return fmt.Errorf("can't access metric template ref %s.%s, cross-namespace references are blocked", metric.TemplateRef.Name, metric.TemplateRef.Namespace)
60-
}
6158
namespace = metric.TemplateRef.Namespace
6259
}
6360

@@ -242,10 +239,6 @@ func (c *Controller) runMetricChecks(canary *flaggerv1.Canary) bool {
242239
if metric.TemplateRef != nil {
243240
namespace := canary.Namespace
244241
if metric.TemplateRef.Namespace != canary.Namespace {
245-
if c.noCrossNamespaceRefs {
246-
c.recordEventErrorf(canary, "Metric template %s.%s error: cross-namespace references are blocked", metric.TemplateRef.Name, metric.TemplateRef.Namespace)
247-
return false
248-
}
249242
namespace = metric.TemplateRef.Namespace
250243
}
251244

pkg/controller/scheduler_metrics_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,5 @@ func TestController_checkMetricProviderAvailability(t *testing.T) {
6565
Namespace: "default",
6666
}
6767
require.NoError(t, ctrl.checkMetricProviderAvailability(canary))
68-
69-
ctrl.noCrossNamespaceRefs = true
70-
canary.Namespace = "test"
71-
require.Error(t, ctrl.checkMetricProviderAvailability(canary))
7268
})
7369
}

0 commit comments

Comments
 (0)