Skip to content

Commit 9f99f52

Browse files
authored
Merge pull request #241 from chengxiangdong/feat_nic
feat: Add support for querying the primary network
2 parents 4255617 + c9ec87e commit 9f99f52

File tree

11 files changed

+462
-10
lines changed

11 files changed

+462
-10
lines changed

docs/huawei-cloud-controller-manager-configuration.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,9 @@ The following arguments are supported:
233233
which may ultimately cause CCM to malfunction.
234234
For example, `business-name: order-pass`, kubernetes loadbalancer service namespace/name: `default/order-service`,
235235
then the name of the ELB instance is: `k8s_service_order-pass_default_order-service`.
236+
237+
> Note:
236238
> Changing this will create new ELB instances, the old ELB instances will not be deleted and no longer maintained.
239+
240+
* `primary-nic` Optional. If you want to use the node's primary network card as the back-end service of ELB,
241+
please configure `force`, otherwise use HostIP of pod.

pkg/cloudprovider/huaweicloud/dedicatedloadbalancer.go

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"google.golang.org/grpc/status"
2727
"k8s.io/api/core/v1"
2828
"k8s.io/apimachinery/pkg/util/errors"
29+
"k8s.io/apimachinery/pkg/util/intstr"
2930
cloudprovider "k8s.io/cloud-provider"
3031
"k8s.io/klog/v2"
3132
"k8s.io/utils/pointer"
@@ -538,7 +539,7 @@ func (d *DedicatedLoadBalancer) addOrRemoveMembers(loadbalancer *elbmodel.LoadBa
538539
pod.Namespace, pod.Spec.NodeName)
539540
}
540541

541-
address, portNum, err := getMemberIP(service, node, pod, svcPort)
542+
address, portNum, err := d.getMemberIP(service, node, pod, svcPort)
542543
if err != nil {
543544
if common.IsNotFound(err) {
544545
// Node failure, do not create member
@@ -581,7 +582,7 @@ func (d *DedicatedLoadBalancer) addOrRemoveMembers(loadbalancer *elbmodel.LoadBa
581582

582583
func (d *DedicatedLoadBalancer) addMember(service *v1.Service, loadbalancer *elbmodel.LoadBalancer, pool *elbmodel.Pool, pod v1.Pod, svcPort v1.ServicePort, node *v1.Node) error {
583584
klog.Infof("Add a member(%s) to pool %s", node.Name, pool.Id)
584-
address, port, err := getMemberIP(service, node, pod, svcPort)
585+
address, port, err := d.getMemberIP(service, node, pod, svcPort)
585586
if err != nil {
586587
return err
587588
}
@@ -613,6 +614,48 @@ func (d *DedicatedLoadBalancer) addMember(service *v1.Service, loadbalancer *elb
613614
return nil
614615
}
615616

617+
func (d *DedicatedLoadBalancer) getMemberIP(service *v1.Service, node *v1.Node, pod v1.Pod, svcPort v1.ServicePort) (string, int32, error) {
618+
if service.Spec.AllocateLoadBalancerNodePorts != nil && *service.Spec.AllocateLoadBalancerNodePorts {
619+
klog.Infof("add member using the Node's IP and port, service: %s/%s, port: %s ", service.Namespace, service.Name, svcPort.Name)
620+
621+
address := ""
622+
if pod.Status.HostIP != "" {
623+
address = pod.Status.HostIP
624+
} else {
625+
addr, err := getNodeAddress(node)
626+
if err != nil {
627+
return "", 0, err
628+
}
629+
address = addr
630+
}
631+
632+
address, err := d.getPrimaryIP(address)
633+
if err != nil {
634+
return "", 0, err
635+
}
636+
return address, svcPort.NodePort, nil
637+
}
638+
639+
if service.Spec.AllocateLoadBalancerNodePorts != nil && !*service.Spec.AllocateLoadBalancerNodePorts {
640+
klog.Infof("add member using the Pod's IP and port, service: %s/%s, port: %s ", service.Namespace, service.Name, svcPort.Name)
641+
// get IP and port from Pod
642+
if svcPort.TargetPort.Type == intstr.Int {
643+
klog.V(6).Infof("targetPort is a number, service: %s/%s, port: %s ", service.Namespace, service.Name, svcPort.Name)
644+
return pod.Status.PodIP, svcPort.TargetPort.IntVal, nil
645+
}
646+
647+
klog.V(6).Infof("targetPort is a name, service: %s/%s, port: %s ", service.Namespace, service.Name, svcPort.Name)
648+
for _, c := range pod.Spec.Containers {
649+
for _, p := range c.Ports {
650+
if p.Name == svcPort.TargetPort.StrVal && string(p.Protocol) == string(svcPort.Protocol) {
651+
return pod.Status.PodIP, p.ContainerPort, nil
652+
}
653+
}
654+
}
655+
}
656+
return "", 0, fmt.Errorf("not found member IP and port")
657+
}
658+
616659
func (d *DedicatedLoadBalancer) deleteMember(elbID string, poolID string, member elbmodel.Member) error {
617660
klog.V(4).Infof("Deleting exists member %s for pool %s address %s", member.Id, poolID, member.Address)
618661
err := d.dedicatedELBClient.DeleteMember(poolID, member.Id)

pkg/cloudprovider/huaweicloud/huaweicloud.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,26 @@ func (b Basic) isSupportedSvc(svs *v1.Service) bool {
350350
return true
351351
}
352352

353+
func (b Basic) getPrimaryIP(ip string) (string, error) {
354+
if b.loadbalancerOpts.PrimaryNic != "force" {
355+
return ip, nil
356+
}
357+
358+
instance, err := b.ecsClient.GetByNodeIPNew(ip)
359+
if err != nil {
360+
return "", err
361+
}
362+
for _, arr := range instance.Addresses {
363+
for _, v := range arr {
364+
if v.Primary {
365+
klog.Infof("obtain the ECS details through the private IP: %s, and find the primary network card IP: %s", ip, v.Addr)
366+
return v.Addr, nil
367+
}
368+
}
369+
}
370+
return "", status.Errorf(codes.NotFound, "not found ECS primary network by private ip: %s", ip)
371+
}
372+
353373
type CloudProvider struct {
354374
Basic
355375
providers map[LoadBalanceVersion]cloudprovider.LoadBalancer
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package model
2+
3+
import (
4+
"net/http"
5+
6+
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/def"
7+
)
8+
9+
func GenReqDefForListServersDetails() *def.HttpRequestDef {
10+
reqDefBuilder := def.NewHttpRequestDefBuilder().
11+
WithMethod(http.MethodGet).
12+
WithPath("/v1/{project_id}/cloudservers/detail").
13+
WithResponse(new(ListServersDetailsResponse)).
14+
WithContentType("application/json")
15+
16+
reqDefBuilder.WithRequestField(def.NewFieldDef().
17+
WithName("EnterpriseProjectId").
18+
WithJsonTag("enterprise_project_id").
19+
WithLocationType(def.Query))
20+
reqDefBuilder.WithRequestField(def.NewFieldDef().
21+
WithName("Flavor").
22+
WithJsonTag("flavor").
23+
WithLocationType(def.Query))
24+
reqDefBuilder.WithRequestField(def.NewFieldDef().
25+
WithName("Ip").
26+
WithJsonTag("ip").
27+
WithLocationType(def.Query))
28+
reqDefBuilder.WithRequestField(def.NewFieldDef().
29+
WithName("Limit").
30+
WithJsonTag("limit").
31+
WithLocationType(def.Query))
32+
reqDefBuilder.WithRequestField(def.NewFieldDef().
33+
WithName("Name").
34+
WithJsonTag("name").
35+
WithLocationType(def.Query))
36+
reqDefBuilder.WithRequestField(def.NewFieldDef().
37+
WithName("NotTags").
38+
WithJsonTag("not-tags").
39+
WithLocationType(def.Query))
40+
reqDefBuilder.WithRequestField(def.NewFieldDef().
41+
WithName("Offset").
42+
WithJsonTag("offset").
43+
WithLocationType(def.Query))
44+
reqDefBuilder.WithRequestField(def.NewFieldDef().
45+
WithName("ReservationId").
46+
WithJsonTag("reservation_id").
47+
WithLocationType(def.Query))
48+
reqDefBuilder.WithRequestField(def.NewFieldDef().
49+
WithName("Status").
50+
WithJsonTag("status").
51+
WithLocationType(def.Query))
52+
reqDefBuilder.WithRequestField(def.NewFieldDef().
53+
WithName("Tags").
54+
WithJsonTag("tags").
55+
WithLocationType(def.Query))
56+
reqDefBuilder.WithRequestField(def.NewFieldDef().
57+
WithName("IpEq").
58+
WithJsonTag("ip_eq").
59+
WithLocationType(def.Query))
60+
reqDefBuilder.WithRequestField(def.NewFieldDef().
61+
WithName("ServerId").
62+
WithJsonTag("server_id").
63+
WithLocationType(def.Query))
64+
65+
requestDef := reqDefBuilder.Build()
66+
return requestDef
67+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// nolint: golint
2+
package model
3+
4+
import (
5+
"strings"
6+
7+
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/utils"
8+
)
9+
10+
// Response Object
11+
type ListServersDetailsResponse struct {
12+
13+
// 弹性云服务器的列表总数。
14+
Count *int32 `json:"count,omitempty"`
15+
16+
// 弹性云服务器详情列表,具体参照-查询云服务器详情接口。查询级别不同,返回的详情不同。
17+
Servers *[]ServerDetail `json:"servers,omitempty"`
18+
HttpStatusCode int `json:"-"`
19+
}
20+
21+
func (o ListServersDetailsResponse) String() string {
22+
data, err := utils.Marshal(o)
23+
if err != nil {
24+
return "ListServersDetailsResponse struct{}"
25+
}
26+
27+
return strings.Join([]string{"ListServersDetailsResponse", string(data)}, " ")
28+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// nolint: golint
2+
package model
3+
4+
import (
5+
"errors"
6+
"strings"
7+
8+
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/utils"
9+
10+
"github.com/huaweicloud/huaweicloud-sdk-go-v3/core/converter"
11+
)
12+
13+
// 弹性云服务器的网络属性。
14+
type ServerAddress struct {
15+
16+
// IP地址版本。 - “4”:代表IPv4。 - “6”:代表IPv6。
17+
Version string `json:"version"`
18+
19+
// IP地址。
20+
Addr string `json:"addr"`
21+
22+
// 是否主网卡
23+
Primary bool `json:"primary"`
24+
25+
// IP地址类型。 - fixed:代表私有IP地址。 - floating:代表浮动IP地址。
26+
OSEXTIPStype *ServerAddressOSEXTIPStype `json:"OS-EXT-IPS:type,omitempty"`
27+
28+
// MAC地址。
29+
OSEXTIPSMACmacAddr *string `json:"OS-EXT-IPS-MAC:mac_addr,omitempty"`
30+
31+
// IP地址对应的端口ID。
32+
OSEXTIPSportId *string `json:"OS-EXT-IPS:port_id,omitempty"`
33+
}
34+
35+
func (o ServerAddress) String() string {
36+
data, err := utils.Marshal(o)
37+
if err != nil {
38+
return "ServerAddress struct{}"
39+
}
40+
41+
return strings.Join([]string{"ServerAddress", string(data)}, " ")
42+
}
43+
44+
type ServerAddressOSEXTIPStype struct {
45+
value string
46+
}
47+
48+
type ServerAddressOSEXTIPStypeEnum struct {
49+
FIXED ServerAddressOSEXTIPStype
50+
FLOATING ServerAddressOSEXTIPStype
51+
}
52+
53+
func GetServerAddressOSEXTIPStypeEnum() ServerAddressOSEXTIPStypeEnum {
54+
return ServerAddressOSEXTIPStypeEnum{
55+
FIXED: ServerAddressOSEXTIPStype{
56+
value: "fixed",
57+
},
58+
FLOATING: ServerAddressOSEXTIPStype{
59+
value: "floating",
60+
},
61+
}
62+
}
63+
64+
func (c ServerAddressOSEXTIPStype) Value() string {
65+
return c.value
66+
}
67+
68+
func (c ServerAddressOSEXTIPStype) MarshalJSON() ([]byte, error) {
69+
return utils.Marshal(c.value)
70+
}
71+
72+
func (c *ServerAddressOSEXTIPStype) UnmarshalJSON(b []byte) error {
73+
myConverter := converter.StringConverterFactory("string")
74+
if myConverter != nil {
75+
val, err := myConverter.CovertStringToInterface(strings.Trim(string(b[:]), "\""))
76+
if err == nil {
77+
c.value = val.(string)
78+
return nil
79+
}
80+
return err
81+
} else {
82+
return errors.New("convert enum data to string error")
83+
}
84+
}

0 commit comments

Comments
 (0)