Skip to content

Commit 8fc0191

Browse files
authored
Merge pull request #5983 from XiShanYongYe-Chang/automated-cherry-pick-of-#5972-upstream-release-1.10
Automated cherry pick of #5972: fix the issue of missing workqueue metrics in the Karmada controller
2 parents 9413770 + b9435eb commit 8fc0191

File tree

49 files changed

+263
-7570
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+263
-7570
lines changed

Diff for: pkg/resourceinterpreter/customized/webhook/customized.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ import (
3131
webhookutil "k8s.io/apiserver/pkg/util/webhook"
3232
corev1 "k8s.io/client-go/listers/core/v1"
3333
"k8s.io/klog/v2"
34-
"k8s.io/kube-aggregator/pkg/apiserver"
3534
utiltrace "k8s.io/utils/trace"
3635

3736
configv1alpha1 "github.com/karmada-io/karmada/pkg/apis/config/v1alpha1"
@@ -65,7 +64,7 @@ func NewCustomizedInterpreter(informer genericmanager.SingleClusterInformerManag
6564
}
6665

6766
cm.SetAuthenticationInfoResolver(authInfoResolver)
68-
cm.SetServiceResolver(apiserver.NewClusterIPServiceResolver(serviceLister))
67+
cm.SetServiceResolver(NewServiceResolver(serviceLister))
6968

7069
return &CustomizedInterpreter{
7170
hookManager: configmanager.NewExploreConfigManager(informer),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
Copyright 2024 The Karmada Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package webhook
18+
19+
import (
20+
"fmt"
21+
"net"
22+
"net/url"
23+
24+
corev1 "k8s.io/api/core/v1"
25+
apierrors "k8s.io/apimachinery/pkg/api/errors"
26+
webhookutil "k8s.io/apiserver/pkg/util/webhook"
27+
corev1lister "k8s.io/client-go/listers/core/v1"
28+
)
29+
30+
// ServiceResolver knows how to convert a service reference into an actual location.
31+
type ServiceResolver interface {
32+
ResolveEndpoint(namespace, name string, port int32) (*url.URL, error)
33+
}
34+
35+
// NewServiceResolver returns a ServiceResolver that parses service first,
36+
// if service not exist, constructs a service URL from a given namespace and name.
37+
func NewServiceResolver(services corev1lister.ServiceLister) ServiceResolver {
38+
return &serviceResolver{
39+
services: services,
40+
defaultResolver: webhookutil.NewDefaultServiceResolver(),
41+
}
42+
}
43+
44+
type serviceResolver struct {
45+
services corev1lister.ServiceLister
46+
defaultResolver ServiceResolver
47+
}
48+
49+
func (r *serviceResolver) ResolveEndpoint(namespace, name string, port int32) (*url.URL, error) {
50+
svc, err := r.services.Services(namespace).Get(name)
51+
if err != nil {
52+
if apierrors.IsNotFound(err) {
53+
return r.defaultResolver.ResolveEndpoint(namespace, name, port)
54+
}
55+
return nil, err
56+
}
57+
return resolveCluster(svc, port)
58+
}
59+
60+
// resolveCluster parses Service resource to url.
61+
func resolveCluster(svc *corev1.Service, port int32) (*url.URL, error) {
62+
switch {
63+
case svc.Spec.Type == corev1.ServiceTypeClusterIP && svc.Spec.ClusterIP == corev1.ClusterIPNone:
64+
return nil, fmt.Errorf(`cannot route to service with ClusterIP "None"`)
65+
// use IP from a clusterIP for these service types
66+
case svc.Spec.Type == corev1.ServiceTypeClusterIP, svc.Spec.Type == corev1.ServiceTypeLoadBalancer, svc.Spec.Type == corev1.ServiceTypeNodePort:
67+
svcPort, err := findServicePort(svc, port)
68+
if err != nil {
69+
return nil, err
70+
}
71+
return &url.URL{
72+
Scheme: "https",
73+
Host: net.JoinHostPort(svc.Spec.ClusterIP, fmt.Sprintf("%d", svcPort.Port)),
74+
}, nil
75+
case svc.Spec.Type == corev1.ServiceTypeExternalName:
76+
return &url.URL{
77+
Scheme: "https",
78+
Host: net.JoinHostPort(svc.Spec.ExternalName, fmt.Sprintf("%d", port)),
79+
}, nil
80+
default:
81+
return nil, fmt.Errorf("unsupported service type %q", svc.Spec.Type)
82+
}
83+
}
84+
85+
// findServicePort finds the service port by name or numerically.
86+
func findServicePort(svc *corev1.Service, port int32) (*corev1.ServicePort, error) {
87+
for _, svcPort := range svc.Spec.Ports {
88+
if svcPort.Port == port {
89+
return &svcPort, nil
90+
}
91+
}
92+
return nil, apierrors.NewServiceUnavailable(fmt.Sprintf("no service port %d found for service %q", port, svc.Name))
93+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
Copyright 2024 The Karmada Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package webhook
18+
19+
import (
20+
"fmt"
21+
"net"
22+
"net/url"
23+
"testing"
24+
25+
"github.com/stretchr/testify/assert"
26+
corev1 "k8s.io/api/core/v1"
27+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28+
"k8s.io/apimachinery/pkg/util/intstr"
29+
)
30+
31+
func Test_resolveCluster(t *testing.T) {
32+
type args struct {
33+
svc *corev1.Service
34+
port int32
35+
}
36+
tests := []struct {
37+
name string
38+
args args
39+
want *url.URL
40+
wantErr assert.ErrorAssertionFunc
41+
}{
42+
{
43+
name: "ClusterIP service without expect port, can not be resolved",
44+
args: args{
45+
svc: &corev1.Service{
46+
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
47+
Spec: corev1.ServiceSpec{
48+
Type: corev1.ServiceTypeClusterIP,
49+
ClusterIP: "10.10.10.10",
50+
Ports: []corev1.ServicePort{
51+
{Port: 1234, TargetPort: intstr.FromInt32(1234)},
52+
}}},
53+
port: 443,
54+
},
55+
wantErr: assert.Error,
56+
},
57+
{
58+
name: "ClusterIP service, can be resolved",
59+
args: args{
60+
svc: &corev1.Service{
61+
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
62+
Spec: corev1.ServiceSpec{
63+
Type: corev1.ServiceTypeClusterIP,
64+
ClusterIP: "10.10.10.10",
65+
Ports: []corev1.ServicePort{
66+
{Name: "https", Port: 443, TargetPort: intstr.FromInt32(1443)},
67+
{Port: 1234, TargetPort: intstr.FromInt32(1234)},
68+
}}},
69+
port: 443,
70+
},
71+
want: &url.URL{
72+
Scheme: "https",
73+
Host: net.JoinHostPort("10.10.10.10", "443"),
74+
},
75+
wantErr: assert.NoError,
76+
},
77+
{
78+
name: "headless service, can not be resolved",
79+
args: args{
80+
svc: &corev1.Service{
81+
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
82+
Spec: corev1.ServiceSpec{
83+
Type: corev1.ServiceTypeClusterIP,
84+
ClusterIP: corev1.ClusterIPNone,
85+
}},
86+
port: 443,
87+
},
88+
wantErr: assert.Error,
89+
},
90+
{
91+
name: "LoadBalancer service, can be resolved",
92+
args: args{
93+
svc: &corev1.Service{
94+
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
95+
Spec: corev1.ServiceSpec{
96+
Type: corev1.ServiceTypeLoadBalancer,
97+
ClusterIP: "10.10.10.10",
98+
Ports: []corev1.ServicePort{
99+
{Name: "https", Port: 443, TargetPort: intstr.FromInt32(1443)},
100+
{Port: 1234, TargetPort: intstr.FromInt32(1234)},
101+
}}},
102+
port: 443,
103+
},
104+
want: &url.URL{
105+
Scheme: "https",
106+
Host: net.JoinHostPort("10.10.10.10", "443"),
107+
},
108+
wantErr: assert.NoError,
109+
},
110+
{
111+
name: "NodePort service, can be resolved",
112+
args: args{
113+
svc: &corev1.Service{
114+
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
115+
Spec: corev1.ServiceSpec{
116+
Type: corev1.ServiceTypeLoadBalancer,
117+
ClusterIP: "10.10.10.10",
118+
Ports: []corev1.ServicePort{
119+
{Name: "https", Port: 443, TargetPort: intstr.FromInt32(1443)},
120+
{Port: 1234, TargetPort: intstr.FromInt32(1234)},
121+
}}},
122+
port: 443,
123+
},
124+
want: &url.URL{
125+
Scheme: "https",
126+
Host: net.JoinHostPort("10.10.10.10", "443"),
127+
},
128+
wantErr: assert.NoError,
129+
},
130+
{
131+
name: "ExternalName service, can be resolved",
132+
args: args{
133+
svc: &corev1.Service{
134+
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
135+
Spec: corev1.ServiceSpec{
136+
Type: corev1.ServiceTypeExternalName,
137+
ExternalName: "foo.bar.com",
138+
}},
139+
port: 443,
140+
},
141+
want: &url.URL{
142+
Scheme: "https",
143+
Host: net.JoinHostPort("foo.bar.com", "443"),
144+
},
145+
wantErr: assert.NoError,
146+
},
147+
{
148+
name: "unsupported type service, can not be resolved",
149+
args: args{
150+
svc: &corev1.Service{
151+
ObjectMeta: metav1.ObjectMeta{Namespace: "one", Name: "alfa"},
152+
Spec: corev1.ServiceSpec{
153+
Type: "unsupported service",
154+
}},
155+
port: 443,
156+
},
157+
wantErr: assert.Error,
158+
},
159+
}
160+
for _, tt := range tests {
161+
t.Run(tt.name, func(t *testing.T) {
162+
got, err := resolveCluster(tt.args.svc, tt.args.port)
163+
if !tt.wantErr(t, err, fmt.Sprintf("resolveCluster(%v, %v)", tt.args.svc, tt.args.port)) {
164+
return
165+
}
166+
assert.Equalf(t, tt.want, got, "resolveCluster(%v, %v)", tt.args.svc, tt.args.port)
167+
})
168+
}
169+
}

Diff for: vendor/k8s.io/apimachinery/pkg/api/meta/table/table.go

-70
This file was deleted.

0 commit comments

Comments
 (0)