• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

kubeovn / kube-ovn / 26349097361

24 May 2026 01:58AM UTC coverage: 23.992% (+0.002%) from 23.99%
26349097361

push

github

oilbeater
fix(controller): avoid panic in external VPC sync when no logical switch is found (#6777)

Three issues addressed in syncExternalVpc / getNonKubeovnRouterStatus:

- Fix index out of range panic at external_vpc.go when ListLogicalSwitch
  returns an empty slice without error: the previous guard only rejected
  err != nil or len > 1, so len == 0 fell through to switches[0] (#6774).
- Move the vpc.Status.Subnets reset to before the append loop so the
  subnets collected from the logical router are actually persisted on
  the freshly created external VPC instead of being overwritten with [].
- Split combined error/length guards in the peerPorts block, fix %s
  formatting of a util.Port struct, and inline the temporary
  aLogicalSwitch variable.

Closes #6774

Signed-off-by: Mengxin Liu <liumengxinfly@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit 9aa6246b9)
Signed-off-by: Mengxin Liu <liumengxinfly@gmail.com>

0 of 12 new or added lines in 1 file covered. (0.0%)

2 existing lines in 1 file now uncovered.

13151 of 54815 relevant lines covered (23.99%)

0.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/pkg/controller/external_vpc.go
1
package controller
2

3
import (
4
        "context"
5
        "slices"
6

7
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8
        "k8s.io/apimachinery/pkg/labels"
9
        "k8s.io/klog/v2"
10

11
        v1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
12
        "github.com/kubeovn/kube-ovn/pkg/ovsdb/ovnnb"
13
        "github.com/kubeovn/kube-ovn/pkg/util"
14
)
15

16
// syncExternalVpc syncs the non kubeovn created ovn vpc, such as neutron ovn vpc
17
func (c *Controller) syncExternalVpc() {
×
18
        logicalRouters, err := c.getNonKubeovnRouterStatus()
×
19
        if err != nil {
×
20
                klog.Error("failed to list ovn logical routers", err)
×
21
                return
×
22
        }
×
23
        klog.V(3).Infof("sync external vpcs with ovn non kube-ovn created vpc")
×
24
        vpcs, err := c.vpcsLister.List(labels.SelectorFromSet(labels.Set{util.VpcExternalLabel: "true"}))
×
25
        if err != nil {
×
26
                klog.Errorf("failed to list vpc, %v", err)
×
27
                return
×
28
        }
×
29
        for _, cachedVpc := range vpcs {
×
30
                vpc := cachedVpc.DeepCopy()
×
31
                if _, ok := logicalRouters[vpc.Name]; ok {
×
32
                        // update vpc status subnet list
×
33
                        vpc.Status.Subnets = []string{}
×
34
                        for _, ls := range logicalRouters[vpc.Name].LogicalSwitches {
×
35
                                vpc.Status.Subnets = append(vpc.Status.Subnets, ls.Name)
×
36
                        }
×
37
                        _, err = c.config.KubeOvnClient.KubeovnV1().Vpcs().UpdateStatus(context.Background(), vpc, metav1.UpdateOptions{})
×
38
                        if err != nil {
×
39
                                klog.Errorf("failed to update vpc %s status: %v", vpc.Name, err)
×
40
                                continue
×
41
                        }
42
                        delete(logicalRouters, vpc.Name)
×
43
                } else {
×
44
                        klog.Infof("external vpc %s has no ovn logical router, delete it", vpc.Name)
×
45
                        err = c.config.KubeOvnClient.KubeovnV1().Vpcs().Delete(context.Background(), vpc.Name, metav1.DeleteOptions{})
×
46
                        if err != nil {
×
47
                                klog.Errorf("failed to delete vpc %s: %v", vpc.Name, err)
×
48
                                continue
×
49
                        }
50
                }
51
        }
52
        if len(logicalRouters) != 0 {
×
53
                // routerName, logicalRouter
×
54
                for routerName, logicalRouter := range logicalRouters {
×
55
                        vpc := &v1.Vpc{}
×
56
                        vpc.Name = routerName
×
57
                        vpc.Labels = map[string]string{util.VpcExternalLabel: "true"}
×
58
                        vpc, err = c.config.KubeOvnClient.KubeovnV1().Vpcs().Create(context.Background(), vpc, metav1.CreateOptions{})
×
59
                        if err != nil {
×
60
                                klog.Errorf("failed init external vpc %s, %v", routerName, err)
×
61
                                return
×
62
                        }
×
63

NEW
64
                        vpc.Status.Subnets = []string{}
×
65
                        for _, logicalSwitch := range logicalRouter.LogicalSwitches {
×
66
                                vpc.Status.Subnets = append(vpc.Status.Subnets, logicalSwitch.Name)
×
67
                        }
×
68
                        vpc.Status.DefaultLogicalSwitch = ""
×
69
                        vpc.Status.Router = routerName
×
70
                        vpc.Status.Standby = true
×
71
                        vpc.Status.Default = false
×
72

×
73
                        _, err = c.config.KubeOvnClient.KubeovnV1().Vpcs().UpdateStatus(context.Background(), vpc, metav1.UpdateOptions{})
×
74
                        if err != nil {
×
75
                                klog.Errorf("failed to update vpc %s status, %v", routerName, err)
×
76
                                return
×
77
                        }
×
78
                        klog.V(4).Infof("added external vpc %s", routerName)
×
79
                }
80
        }
81
}
82

83
func (c *Controller) getNonKubeovnRouterStatus() (logicalRouters map[string]util.LogicalRouter, err error) {
×
84
        logicalRouters = make(map[string]util.LogicalRouter)
×
85
        nonKubeovnRouters, err := c.OVNNbClient.ListLogicalRouter(false, func(lr *ovnnb.LogicalRouter) bool {
×
86
                return len(lr.ExternalIDs) == 0 || lr.ExternalIDs["vendor"] != util.CniTypeName
×
87
        })
×
88
        if err != nil {
×
89
                klog.Errorf("failed to list non kubeovn logical router, %v", err)
×
90
                return logicalRouters, err
×
91
        }
×
92
        if len(nonKubeovnRouters) == 0 {
×
93
                klog.V(4).Info("no non kubeovn logical router")
×
94
                return logicalRouters, nil
×
95
        }
×
96

97
        for _, router := range nonKubeovnRouters {
×
98
                lr := util.LogicalRouter{
×
99
                        Name:  router.Name,
×
100
                        Ports: make([]util.Port, 0, len(router.Ports)),
×
101
                }
×
102
                for _, uuid := range router.Ports {
×
103
                        lrp, err := c.OVNNbClient.GetLogicalRouterPortByUUID(uuid)
×
104
                        if err != nil {
×
105
                                klog.Warningf("failed to get LRP by UUID %s: %v", uuid, err)
×
106
                                continue
×
107
                        }
108
                        lr.Ports = append(lr.Ports, util.Port{Name: lrp.Name})
×
109
                }
110
                logicalRouters[lr.Name] = lr
×
111
        }
112
        for routerName, logicalRouter := range logicalRouters {
×
113
                tmpRouter := logicalRouter
×
114
                for _, port := range logicalRouter.Ports {
×
115
                        peerPorts, err := c.OVNNbClient.ListLogicalSwitchPorts(false, nil, func(lsp *ovnnb.LogicalSwitchPort) bool {
×
116
                                return len(lsp.Options) != 0 && lsp.Options["router-port"] == port.Name
×
117
                        })
×
NEW
118
                        if err != nil {
×
NEW
119
                                klog.Errorf("failed to list peer port of %s: %v", port.Name, err)
×
UNCOV
120
                                continue
×
121
                        }
122
                        if len(peerPorts) == 0 {
×
123
                                continue
×
124
                        }
NEW
125
                        if len(peerPorts) > 1 {
×
NEW
126
                                klog.Errorf("expected at most one peer port for %s, got %d", port.Name, len(peerPorts))
×
NEW
127
                                continue
×
128
                        }
129
                        lsp := peerPorts[0]
×
130
                        switches, err := c.OVNNbClient.ListLogicalSwitch(false, func(ls *ovnnb.LogicalSwitch) bool {
×
131
                                return slices.Contains(ls.Ports, lsp.UUID)
×
132
                        })
×
NEW
133
                        if err != nil {
×
NEW
134
                                klog.Errorf("failed to list logical switch of LSP %s: %v", lsp.Name, err)
×
NEW
135
                                continue
×
136
                        }
NEW
137
                        if len(switches) != 1 {
×
NEW
138
                                klog.Warningf("expected exactly one logical switch for LSP %s, got %d", lsp.Name, len(switches))
×
UNCOV
139
                                continue
×
140
                        }
NEW
141
                        tmpRouter.LogicalSwitches = append(tmpRouter.LogicalSwitches, util.LogicalSwitch{Name: switches[0].Name})
×
142
                }
143
                logicalRouters[routerName] = tmpRouter
×
144
        }
145
        return logicalRouters, nil
×
146
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc