Skip to content

Commit 48a878a

Browse files
author
Jing Zhang
committed
Add support of trunk ports
Currenlty, getAttachedInterfacesByID() only returns neutron ports directly attached to VM. For vlan-aware VMs that have trunk ports, subports attached to the trunk ports are not returned. This pull request checks if VM has trunk ports, if so, adds their subports in the return. Signed-off-by: Jing Zhang <[email protected]>
1 parent 92d83ea commit 48a878a

File tree

3 files changed

+140
-19
lines changed

3 files changed

+140
-19
lines changed

pkg/openstack/instances.go

Lines changed: 127 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ import (
3030
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/attachinterfaces"
3131
"github.com/gophercloud/gophercloud/openstack/compute/v2/flavors"
3232
"github.com/gophercloud/gophercloud/openstack/compute/v2/servers"
33+
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/trunks"
34+
"github.com/gophercloud/gophercloud/openstack/networking/v2/networks"
35+
"github.com/gophercloud/gophercloud/openstack/networking/v2/ports"
3336
"github.com/gophercloud/gophercloud/pagination"
3437
"github.com/mitchellh/mapstructure"
3538
v1 "k8s.io/api/core/v1"
@@ -48,6 +51,7 @@ import (
4851
// Instances encapsulates an implementation of Instances for OpenStack.
4952
type Instances struct {
5053
compute *gophercloud.ServiceClient
54+
network *gophercloud.ServiceClient
5155
region string
5256
regionProviderID bool
5357
opts metadata.Opts
@@ -148,13 +152,20 @@ func (os *OpenStack) instances() (*Instances, bool) {
148152
return nil, false
149153
}
150154

155+
network, err := client.NewNetworkV2(os.provider, os.epOpts)
156+
if err != nil {
157+
klog.Errorf("Failed to create an OpenStack Network client: %v", err)
158+
return nil, false
159+
}
160+
151161
regionalProviderID := false
152162
if isRegionalProviderID := sysos.Getenv(RegionalProviderIDEnv); isRegionalProviderID == "true" {
153163
regionalProviderID = true
154164
}
155165

156166
return &Instances{
157167
compute: compute,
168+
network: network,
158169
region: os.epOpts.Region,
159170
regionProviderID: regionalProviderID,
160171
opts: os.metadataOpts,
@@ -193,7 +204,7 @@ func (i *Instances) AddSSHKeyToAllInstances(ctx context.Context, user string, ke
193204
func (i *Instances) NodeAddresses(ctx context.Context, name types.NodeName) ([]v1.NodeAddress, error) {
194205
klog.V(4).Infof("NodeAddresses(%v) called", name)
195206

196-
addrs, err := getAddressesByName(i.compute, name, i.networkingOpts)
207+
addrs, err := getAddressesByName(i.compute, name, i.networkingOpts, i.network)
197208
if err != nil {
198209
return nil, err
199210
}
@@ -226,7 +237,7 @@ func (i *Instances) NodeAddressesByProviderID(ctx context.Context, providerID st
226237
return []v1.NodeAddress{}, err
227238
}
228239

229-
interfaces, err := getAttachedInterfacesByID(i.compute, server.ID)
240+
interfaces, err := getAttachedInterfacesByID(i.compute, server.ID, i.network)
230241
if err != nil {
231242
return []v1.NodeAddress{}, err
232243
}
@@ -332,7 +343,7 @@ func (i *Instances) InstanceMetadata(ctx context.Context, node *v1.Node) (*cloud
332343
return nil, err
333344
}
334345

335-
interfaces, err := getAttachedInterfacesByID(i.compute, srv.ID)
346+
interfaces, err := getAttachedInterfacesByID(i.compute, srv.ID, i.network)
336347
if err != nil {
337348
return nil, err
338349
}
@@ -565,9 +576,15 @@ func getServerByName(client *gophercloud.ServiceClient, name types.NodeName) (*S
565576
// * metadata hostname
566577
// * server object Addresses (floating type)
567578
func nodeAddresses(srv *servers.Server, interfaces []attachinterfaces.Interface, networkingOpts NetworkingOpts) ([]v1.NodeAddress, error) {
579+
type Address struct {
580+
IPType string `mapstructure:"OS-EXT-IPS:type"`
581+
Addr string
582+
}
583+
568584
addrs := []v1.NodeAddress{}
569585

570586
// parse private IP addresses first in an ordered manner
587+
allPrivates := make(map[string][]Address)
571588
for _, iface := range interfaces {
572589
for _, fixedIP := range iface.FixedIPs {
573590
if iface.PortState == "ACTIVE" {
@@ -579,6 +596,10 @@ func nodeAddresses(srv *servers.Server, interfaces []attachinterfaces.Interface,
579596
Address: fixedIP.IPAddress,
580597
},
581598
)
599+
if len(iface.NetID) > 0 {
600+
addr := Address{IPType: "fixed", Addr: fixedIP.IPAddress}
601+
allPrivates[iface.NetID] = append(allPrivates[iface.NetID], addr)
602+
}
582603
}
583604
}
584605
}
@@ -613,17 +634,40 @@ func nodeAddresses(srv *servers.Server, interfaces []attachinterfaces.Interface,
613634
}
614635

615636
// process the rest
616-
type Address struct {
617-
IPType string `mapstructure:"OS-EXT-IPS:type"`
618-
Addr string
619-
}
620-
621637
var addresses map[string][]Address
622638
err := mapstructure.Decode(srv.Addresses, &addresses)
623639
if err != nil {
624640
return nil, err
625641
}
626642

643+
// add subports if exist to the server
644+
extraPrivates := make(map[string][]Address)
645+
for k, v := range allPrivates {
646+
ok := false
647+
for _, a := range v {
648+
for _, v1 := range addresses {
649+
for _, a1 := range v1 {
650+
if a.Addr == a1.Addr {
651+
ok = true
652+
break
653+
}
654+
}
655+
}
656+
}
657+
if !ok {
658+
extraPrivates[k] = v
659+
}
660+
}
661+
klog.V(5).Infof("Node '%s' extraPrivates '%s'", srv.Name, extraPrivates)
662+
for k, v := range extraPrivates {
663+
v1, ok := addresses[k]
664+
if !ok {
665+
addresses[k] = v
666+
} else {
667+
addresses[k] = append(v1, v...)
668+
}
669+
}
670+
627671
var networks []string
628672
for k := range addresses {
629673
networks = append(networks, k)
@@ -677,26 +721,91 @@ func nodeAddresses(srv *servers.Server, interfaces []attachinterfaces.Interface,
677721
return addrs, nil
678722
}
679723

680-
func getAddressesByName(client *gophercloud.ServiceClient, name types.NodeName, networkingOpts NetworkingOpts) ([]v1.NodeAddress, error) {
681-
srv, err := getServerByName(client, name)
724+
func getAddressesByName(compute *gophercloud.ServiceClient, name types.NodeName, networkingOpts NetworkingOpts, network *gophercloud.ServiceClient) ([]v1.NodeAddress, error) {
725+
srv, err := getServerByName(compute, name)
682726
if err != nil {
683727
return nil, err
684728
}
685729

686-
interfaces, err := getAttachedInterfacesByID(client, srv.ID)
730+
interfaces, err := getAttachedInterfacesByID(compute, srv.ID, network)
687731
if err != nil {
688732
return nil, err
689733
}
690734

691735
return nodeAddresses(&srv.Server, interfaces, networkingOpts)
692736
}
693737

738+
// getSubInterfaces
739+
func getSubInterfaces(network *gophercloud.ServiceClient) ([]attachinterfaces.Interface, error) {
740+
var interfaces []attachinterfaces.Interface
741+
742+
// Check if trunk ports are attached
743+
listOpts := trunks.ListOpts{}
744+
allPages, err := trunks.List(network, listOpts).AllPages()
745+
if err != nil {
746+
klog.Errorf("Failed to list trunks: %v", err)
747+
return interfaces, err
748+
}
749+
allTrunks, err := trunks.ExtractTrunks(allPages)
750+
if err != nil {
751+
klog.Errorf("Failed to extract trunks: %v", err)
752+
return interfaces, err
753+
}
754+
755+
// Get subports attached to the trunk
756+
var subports []trunks.Subport
757+
for _, trunk := range allTrunks {
758+
for _, iface := range interfaces {
759+
if iface.PortID == trunk.PortID {
760+
s, err := trunks.GetSubports(network, trunk.ID).Extract()
761+
if err != nil {
762+
klog.Errorf("Failed to get subports for trunk %s: %v", trunk.ID, err)
763+
return interfaces, err
764+
}
765+
subports = append(subports, s...)
766+
}
767+
}
768+
}
769+
klog.V(5).Infof("subports %v", subports)
770+
771+
// Arrange subports as for directly attached ports
772+
for _, sport := range subports {
773+
p, err := ports.Get(network, sport.PortID).Extract()
774+
if err != nil {
775+
klog.Errorf("Failed to get port info for subport %s: %v", sport.PortID, err)
776+
return interfaces, err
777+
}
778+
n, err := networks.Get(network, p.NetworkID).Extract()
779+
if err != nil {
780+
klog.Errorf("Failed to get network info for subport %s: %v", sport.PortID, err)
781+
return interfaces, err
782+
}
783+
var iface = attachinterfaces.Interface{
784+
PortState: "ACTIVE",
785+
FixedIPs: []attachinterfaces.FixedIP{},
786+
PortID: p.ID,
787+
NetID: n.Name,
788+
MACAddr: p.MACAddress,
789+
}
790+
for _, ip := range p.FixedIPs {
791+
var ip2 = attachinterfaces.FixedIP{
792+
SubnetID: ip.SubnetID,
793+
IPAddress: ip.IPAddress,
794+
}
795+
iface.FixedIPs = append(iface.FixedIPs, ip2)
796+
}
797+
interfaces = append(interfaces, iface)
798+
}
799+
klog.V(5).Infof("interfaces %v", interfaces)
800+
return interfaces, nil
801+
}
802+
694803
// getAttachedInterfacesByID returns the node interfaces of the specified instance.
695-
func getAttachedInterfacesByID(client *gophercloud.ServiceClient, serviceID string) ([]attachinterfaces.Interface, error) {
804+
func getAttachedInterfacesByID(compute *gophercloud.ServiceClient, serviceID string, network *gophercloud.ServiceClient) ([]attachinterfaces.Interface, error) {
696805
var interfaces []attachinterfaces.Interface
697806

698807
mc := metrics.NewMetricContext("server_os_interface", "list")
699-
pager := attachinterfaces.List(client, serviceID)
808+
pager := attachinterfaces.List(compute, serviceID)
700809
err := pager.EachPage(func(page pagination.Page) (bool, error) {
701810
s, err := attachinterfaces.ExtractInterfaces(page)
702811
if err != nil {
@@ -708,6 +817,10 @@ func getAttachedInterfacesByID(client *gophercloud.ServiceClient, serviceID stri
708817
if mc.ObserveRequest(err) != nil {
709818
return interfaces, err
710819
}
711-
820+
subInterfaces, err := getSubInterfaces(network)
821+
if err != nil {
822+
return interfaces, err
823+
}
824+
interfaces = append(interfaces, subInterfaces...)
712825
return interfaces, nil
713826
}

pkg/openstack/instancesv2.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
// InstancesV2 encapsulates an implementation of InstancesV2 for OpenStack.
3535
type InstancesV2 struct {
3636
compute *gophercloud.ServiceClient
37+
network *gophercloud.ServiceClient
3738
region string
3839
regionProviderID bool
3940
networkingOpts NetworkingOpts
@@ -56,13 +57,20 @@ func (os *OpenStack) instancesv2() (*InstancesV2, bool) {
5657
return nil, false
5758
}
5859

60+
network, err := client.NewNetworkV2(os.provider, os.epOpts)
61+
if err != nil {
62+
klog.Errorf("unable to access network V2 API : %v", err)
63+
return nil, false
64+
}
65+
5966
regionalProviderID := false
6067
if isRegionalProviderID := sysos.Getenv(RegionalProviderIDEnv); isRegionalProviderID == "true" {
6168
regionalProviderID = true
6269
}
6370

6471
return &InstancesV2{
6572
compute: compute,
73+
network: network,
6674
region: os.epOpts.Region,
6775
regionProviderID: regionalProviderID,
6876
networkingOpts: os.networkingOpts,
@@ -115,7 +123,7 @@ func (i *InstancesV2) InstanceMetadata(ctx context.Context, node *v1.Node) (*clo
115123
return nil, err
116124
}
117125

118-
interfaces, err := getAttachedInterfacesByID(i.compute, server.ID)
126+
interfaces, err := getAttachedInterfacesByID(i.compute, server.ID, i.network)
119127
if err != nil {
120128
return nil, err
121129
}

pkg/openstack/loadbalancer.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ func getBoolFromServiceAnnotation(service *corev1.Service, annotationKey string,
707707
}
708708

709709
// getSubnetIDForLB returns subnet-id for a specific node
710-
func getSubnetIDForLB(compute *gophercloud.ServiceClient, node corev1.Node, preferredIPFamily corev1.IPFamily) (string, error) {
710+
func getSubnetIDForLB(compute *gophercloud.ServiceClient, node corev1.Node, preferredIPFamily corev1.IPFamily, network *gophercloud.ServiceClient) (string, error) {
711711
ipAddress, err := nodeAddressForLB(&node, preferredIPFamily)
712712
if err != nil {
713713
return "", err
@@ -718,7 +718,7 @@ func getSubnetIDForLB(compute *gophercloud.ServiceClient, node corev1.Node, pref
718718
instanceID = instanceID[(ind + 1):]
719719
}
720720

721-
interfaces, err := getAttachedInterfacesByID(compute, instanceID)
721+
interfaces, err := getAttachedInterfacesByID(compute, instanceID, network)
722722
if err != nil {
723723
return "", err
724724
}
@@ -1503,7 +1503,7 @@ func (lbaas *LbaasV2) checkServiceUpdate(service *corev1.Service, nodes []*corev
15031503
} else {
15041504
svcConf.lbMemberSubnetID = getStringFromServiceAnnotation(service, ServiceAnnotationLoadBalancerSubnetID, lbaas.opts.SubnetID)
15051505
if len(svcConf.lbMemberSubnetID) == 0 && len(nodes) > 0 {
1506-
subnetID, err := getSubnetIDForLB(lbaas.compute, *nodes[0], svcConf.preferredIPFamily)
1506+
subnetID, err := getSubnetIDForLB(lbaas.compute, *nodes[0], svcConf.preferredIPFamily, lbaas.network)
15071507
if err != nil {
15081508
return fmt.Errorf("no subnet-id found for service %s: %v", serviceName, err)
15091509
}
@@ -1617,7 +1617,7 @@ func (lbaas *LbaasV2) checkService(service *corev1.Service, nodes []*corev1.Node
16171617
svcConf.lbMemberSubnetID = svcConf.lbSubnetID
16181618
}
16191619
if len(svcConf.lbNetworkID) == 0 && len(svcConf.lbSubnetID) == 0 {
1620-
subnetID, err := getSubnetIDForLB(lbaas.compute, *nodes[0], svcConf.preferredIPFamily)
1620+
subnetID, err := getSubnetIDForLB(lbaas.compute, *nodes[0], svcConf.preferredIPFamily, lbaas.network)
16211621
if err != nil {
16221622
return fmt.Errorf("failed to get subnet to create load balancer for service %s: %v", serviceName, err)
16231623
}

0 commit comments

Comments
 (0)