Skip to content

Commit 382cc0f

Browse files
authored
feat: support consumer labels from metadata labels (#410)
1 parent 45e38a1 commit 382cc0f

8 files changed

Lines changed: 260 additions & 7 deletions

File tree

internal/adc/translator/apisixconsumer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func (t *Translator) TranslateApisixConsumer(tctx *provider.TranslateContext, ac
110110
Username: username,
111111
}
112112
consumer.Plugins = plugins
113-
consumer.Labels = label.GenLabel(ac)
113+
consumer.Labels = label.GenLabelWithObjectLabels(ac)
114114
result.Consumers = append(result.Consumers, consumer)
115115
return result, nil
116116
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package translator
19+
20+
import (
21+
"context"
22+
"testing"
23+
24+
"github.com/go-logr/logr"
25+
"github.com/stretchr/testify/require"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
28+
apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
29+
"github.com/apache/apisix-ingress-controller/internal/controller/label"
30+
"github.com/apache/apisix-ingress-controller/internal/provider"
31+
)
32+
33+
func TestTranslateApisixConsumer_UsesMetadataLabelsWithoutOverwritingControllerLabels(t *testing.T) {
34+
translator := NewTranslator(logr.Discard())
35+
tctx := provider.NewDefaultTranslateContext(context.Background())
36+
37+
consumer := &apiv2.ApisixConsumer{
38+
TypeMeta: metav1.TypeMeta{
39+
Kind: "ApisixConsumer",
40+
APIVersion: apiv2.GroupVersion.String(),
41+
},
42+
ObjectMeta: metav1.ObjectMeta{
43+
Name: "demo",
44+
Namespace: "default",
45+
Labels: map[string]string{
46+
"team": "payments",
47+
label.LabelName: "user-value",
48+
label.LabelResourceKey: "user-resource-key",
49+
},
50+
},
51+
Spec: apiv2.ApisixConsumerSpec{
52+
AuthParameter: apiv2.ApisixConsumerAuthParameter{
53+
BasicAuth: &apiv2.ApisixConsumerBasicAuth{
54+
Value: &apiv2.ApisixConsumerBasicAuthValue{
55+
Username: "demo",
56+
Password: "secret",
57+
},
58+
},
59+
},
60+
},
61+
}
62+
63+
result, err := translator.TranslateApisixConsumer(tctx, consumer)
64+
require.NoError(t, err)
65+
require.Len(t, result.Consumers, 1)
66+
67+
translated := result.Consumers[0]
68+
require.Equal(t, "payments", translated.Labels["team"])
69+
require.Equal(t, consumer.Name, translated.Labels[label.LabelName])
70+
require.Equal(t, "ApisixConsumer/default/demo", translated.Labels[label.LabelResourceKey])
71+
}

internal/adc/translator/apisixroute.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ func (t *Translator) buildRoute(ar *apiv2.ApisixRoute, service *adc.Service, rul
186186
route.Name = adc.ComposeRouteName(ar.Namespace, ar.Name, rule.Name)
187187
route.ID = id.GenID(route.Name)
188188
route.Desc = "Created by apisix-ingress-controller, DO NOT modify it manually"
189-
route.Labels = label.GenLabel(ar)
189+
route.Labels = label.GenLabelWithObjectLabels(ar)
190190
route.EnableWebsocket = rule.Websocket
191191
if route.EnableWebsocket == nil && *enableWebsocket != nil {
192192
route.EnableWebsocket = *enableWebsocket
@@ -199,9 +199,6 @@ func (t *Translator) buildRoute(ar *apiv2.ApisixRoute, service *adc.Service, rul
199199
route.Timeout = timeout
200200
route.Uris = rule.Match.Paths
201201
route.Vars = vars
202-
for key, value := range ar.GetObjectMeta().GetLabels() {
203-
route.Labels[key] = value
204-
}
205202

206203
service.Routes = []*adc.Route{route}
207204
}

internal/adc/translator/apisixroute_test.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,40 @@ func TestBuildService_HostsSet(t *testing.T) {
8282
// service.Hosts SHOULD be set — this is the canonical location for hosts.
8383
assert.Equal(t, []string{"example.com", "foo.com"}, service.Hosts)
8484
}
85+
86+
func TestBuildRoute_MetadataLabelsDoNotOverwriteControllerLabels(t *testing.T) {
87+
translator := NewTranslator(logr.Discard())
88+
89+
ar := &apiv2.ApisixRoute{
90+
TypeMeta: metav1.TypeMeta{
91+
Kind: "ApisixRoute",
92+
APIVersion: apiv2.GroupVersion.String(),
93+
},
94+
ObjectMeta: metav1.ObjectMeta{
95+
Name: "test-route",
96+
Namespace: "default",
97+
Labels: map[string]string{
98+
"team": "payments",
99+
"k8s/name": "user-value",
100+
"k8s/resource-key": "user-resource-key",
101+
},
102+
},
103+
}
104+
105+
service := &adc.Service{}
106+
rule := apiv2.ApisixRouteHTTP{
107+
Name: "rule1",
108+
Match: apiv2.ApisixRouteHTTPMatch{
109+
Paths: []string{"/api/*"},
110+
},
111+
}
112+
113+
var enableWebsocket *bool
114+
translator.buildRoute(ar, service, rule, nil, nil, nil, &enableWebsocket)
115+
116+
assert.Len(t, service.Routes, 1)
117+
route := service.Routes[0]
118+
assert.Equal(t, "payments", route.Labels["team"])
119+
assert.Equal(t, ar.Name, route.Labels["k8s/name"])
120+
assert.Equal(t, "ApisixRoute/default/test-route", route.Labels["k8s/resource-key"])
121+
}

internal/adc/translator/consumer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ func (t *Translator) TranslateConsumerV1alpha1(tctx *provider.TranslateContext,
7171
credentials = append(credentials, credential)
7272
}
7373
consumer.Credentials = credentials
74-
consumer.Labels = label.GenLabel(consumerV)
74+
consumer.Labels = label.GenLabelWithObjectLabels(consumerV)
7575
plugins := adctypes.Plugins{}
7676
for _, plugin := range consumerV.Spec.Plugins {
7777
pluginName := plugin.Name
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package translator
19+
20+
import (
21+
"context"
22+
"testing"
23+
24+
"github.com/go-logr/logr"
25+
"github.com/stretchr/testify/require"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
28+
"github.com/apache/apisix-ingress-controller/api/v1alpha1"
29+
"github.com/apache/apisix-ingress-controller/internal/controller/label"
30+
"github.com/apache/apisix-ingress-controller/internal/provider"
31+
)
32+
33+
func TestTranslateConsumerV1alpha1_UsesMetadataLabelsWithoutOverwritingControllerLabels(t *testing.T) {
34+
translator := NewTranslator(logr.Discard())
35+
tctx := provider.NewDefaultTranslateContext(context.Background())
36+
37+
consumer := &v1alpha1.Consumer{
38+
TypeMeta: metav1.TypeMeta{
39+
Kind: "Consumer",
40+
APIVersion: v1alpha1.GroupVersion.String(),
41+
},
42+
ObjectMeta: metav1.ObjectMeta{
43+
Name: "demo",
44+
Namespace: "default",
45+
Labels: map[string]string{
46+
"team": "payments",
47+
label.LabelName: "user-value",
48+
label.LabelResourceKey: "user-resource-key",
49+
},
50+
},
51+
}
52+
53+
result, err := translator.TranslateConsumerV1alpha1(tctx, consumer)
54+
require.NoError(t, err)
55+
require.Len(t, result.Consumers, 1)
56+
57+
translated := result.Consumers[0]
58+
require.Equal(t, "payments", translated.Labels["team"])
59+
require.Equal(t, consumer.Name, translated.Labels[label.LabelName])
60+
require.Equal(t, "Consumer/default/demo", translated.Labels[label.LabelResourceKey])
61+
}

internal/controller/label/label.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,19 @@ func GenLabel(obj client.Object, args ...string) Label {
4444
label[LabelControllerName] = config.ControllerConfig.ControllerName
4545
label[LabelManagedBy] = "apisix-ingress-controller"
4646
label[LabelResourceKey] = fmt.Sprintf("%s/%s/%s", label[LabelKind], label[LabelNamespace], label[LabelName])
47-
for i := 0; i < len(args); i += 2 {
47+
for i := 0; i+1 < len(args); i += 2 {
4848
label[args[i]] = args[i+1]
4949
}
5050
return label
5151
}
52+
53+
func GenLabelWithObjectLabels(obj client.Object, args ...string) Label {
54+
label := make(Label)
55+
for key, value := range obj.GetLabels() {
56+
label[key] = value
57+
}
58+
for key, value := range GenLabel(obj, args...) {
59+
label[key] = value
60+
}
61+
return label
62+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package label
19+
20+
import (
21+
"testing"
22+
23+
"github.com/stretchr/testify/require"
24+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
25+
26+
apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
27+
"github.com/apache/apisix-ingress-controller/internal/controller/config"
28+
)
29+
30+
func TestGenLabelWithObjectLabels(t *testing.T) {
31+
consumer := &apiv2.ApisixConsumer{
32+
TypeMeta: metav1.TypeMeta{
33+
Kind: "ApisixConsumer",
34+
APIVersion: apiv2.GroupVersion.String(),
35+
},
36+
ObjectMeta: metav1.ObjectMeta{
37+
Name: "demo",
38+
Namespace: "default",
39+
Labels: map[string]string{
40+
"team": "payments",
41+
LabelName: "user-value",
42+
LabelResourceKey: "user-resource-key",
43+
LabelManagedBy: "user-manager",
44+
LabelNamespace: "user-namespace",
45+
LabelControllerName: "user-controller",
46+
},
47+
},
48+
}
49+
50+
labels := GenLabelWithObjectLabels(consumer)
51+
52+
require.Equal(t, "payments", labels["team"])
53+
require.Equal(t, consumer.Name, labels[LabelName])
54+
require.Equal(t, consumer.Namespace, labels[LabelNamespace])
55+
require.Equal(t, config.ControllerConfig.ControllerName, labels[LabelControllerName])
56+
require.Equal(t, "apisix-ingress-controller", labels[LabelManagedBy])
57+
require.Equal(t, "ApisixConsumer/default/demo", labels[LabelResourceKey])
58+
}
59+
60+
func TestGenLabel_IgnoresDanglingKeyArg(t *testing.T) {
61+
consumer := &apiv2.ApisixConsumer{
62+
TypeMeta: metav1.TypeMeta{
63+
Kind: "ApisixConsumer",
64+
APIVersion: apiv2.GroupVersion.String(),
65+
},
66+
ObjectMeta: metav1.ObjectMeta{
67+
Name: "demo",
68+
Namespace: "default",
69+
},
70+
}
71+
72+
labels := GenLabel(consumer, "team", "payments", "dangling")
73+
74+
require.Equal(t, "payments", labels["team"])
75+
require.NotContains(t, labels, "dangling")
76+
}

0 commit comments

Comments
 (0)