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

kubeovn / kube-ovn / 15269660763

27 May 2025 07:51AM UTC coverage: 21.822%. First build
15269660763

Pull #5268

github

web-flow
Merge branch 'master' into vpc-any-external
Pull Request #5268: any vpc can use any external subnet

0 of 131 new or added lines in 2 files covered. (0.0%)

10363 of 47488 relevant lines covered (21.82%)

0.25 hits per line

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

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

3
import (
4
        "context"
5
        "errors"
6
        "fmt"
7
        "maps"
8
        "reflect"
9
        "slices"
10
        "strings"
11

12
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
13
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14
        "k8s.io/apimachinery/pkg/types"
15
        "k8s.io/klog/v2"
16

17
        kubeovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
18
        "github.com/kubeovn/kube-ovn/pkg/util"
19
)
20

21
var (
22
        exGwEnabled = "unknown"
23
        lastExGwCM  map[string]string
24
)
25

26
func (c *Controller) resyncExternalGateway() {
×
NEW
27
        // check if default vpc only use extra external subnet
×
NEW
28
        defaultVPC, err := c.vpcsLister.Get(c.config.ClusterRouter)
×
NEW
29
        if err != nil {
×
NEW
30
                klog.Errorf("failed to get vpc %s, %v", c.config.ClusterRouter, err)
×
NEW
31
                return
×
NEW
32
        }
×
33

NEW
34
        if defaultVPC.Spec.ExtraExternalSubnets != nil || defaultVPC.Status.ExtraExternalSubnets != nil {
×
NEW
35
                // vpc controller will handle
×
NEW
36
                klog.Infof("default vpc only use extra external subnets: %v", defaultVPC.Spec.ExtraExternalSubnets)
×
NEW
37
                return
×
NEW
38
        }
×
39

40
        cm, err := c.configMapsLister.ConfigMaps(c.config.ExternalGatewayConfigNS).Get(util.ExternalGatewayConfig)
×
41
        if err != nil && !k8serrors.IsNotFound(err) {
×
42
                klog.Errorf("failed to get ovn-external-gw-config, %v", err)
×
43
                return
×
44
        }
×
45

46
        if k8serrors.IsNotFound(err) || cm.Data["enable-external-gw"] == "false" {
×
47
                if exGwEnabled == "false" {
×
48
                        return
×
49
                }
×
50
                klog.Info("start to remove ovn external gw")
×
51
                if err := c.removeExternalGateway(); err != nil {
×
52
                        klog.Errorf("failed to remove ovn external gw, %v", err)
×
53
                        return
×
54
                }
×
55
                if err := c.updateDefaultVpcExternal(false); err != nil {
×
56
                        klog.Errorf("failed to update default vpc, %v", err)
×
57
                        return
×
58
                }
×
59
                exGwEnabled = "false"
×
60
                lastExGwCM = nil
×
61
                klog.Info("finish remove ovn external gw")
×
62
                return
×
63
        }
64

65
        if exGwEnabled == "true" && lastExGwCM != nil && maps.Equal(cm.Data, lastExGwCM) {
×
66
                return
×
67
        }
×
68
        klog.Infof("last external gw configmap: %v", lastExGwCM)
×
69
        if (lastExGwCM["type"] == kubeovnv1.GWDistributedType && cm.Data["type"] == kubeovnv1.GWCentralizedType) ||
×
70
                lastExGwCM != nil && !reflect.DeepEqual(lastExGwCM["external-gw-nodes"], cm.Data["external-gw-nodes"]) {
×
71
                klog.Info("external gw nodes list changed, start to remove ovn external gw")
×
72
                if err := c.removeExternalGateway(); err != nil {
×
73
                        klog.Errorf("failed to remove old ovn external gw, %v", err)
×
74
                        return
×
75
                }
×
76
        }
77
        klog.Info("start to establish ovn external gw")
×
78
        if err := c.establishExternalGateway(cm.Data); err != nil {
×
79
                klog.Errorf("failed to establish ovn-external-gw, %v", err)
×
80
                return
×
81
        }
×
82
        exGwEnabled = "true"
×
83
        lastExGwCM = cm.Data
×
84
        c.ExternalGatewayType = cm.Data["type"]
×
85
        if err := c.updateDefaultVpcExternal(true); err != nil {
×
86
                klog.Errorf("failed to update default vpc, %v", err)
×
87
                return
×
88
        }
×
89
        klog.Info("finish establishing ovn external gw")
×
90
}
91

92
func (c *Controller) removeExternalGateway() error {
×
93
        sel, _ := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{util.ExGatewayLabel: "true"}})
×
94
        nodes, err := c.nodesLister.List(sel)
×
95
        if err != nil {
×
96
                klog.Errorf("failed to list external gw nodes, %v", err)
×
97
                return err
×
98
        }
×
99
        for _, node := range nodes {
×
100
                patch := util.KVPatch{util.ExGatewayLabel: "false"}
×
101
                if err = util.PatchLabels(c.config.KubeClient.CoreV1().Nodes(), node.Name, patch); err != nil {
×
102
                        klog.Errorf("failed to patch external gw node %s: %v", node.Name, err)
×
103
                        return err
×
104
                }
×
105
        }
106

107
        keepExternalSubnet := false
×
108
        externalSubnet, err := c.subnetsLister.Get(c.config.ExternalGatewaySwitch)
×
109
        if err != nil {
×
110
                if !k8serrors.IsNotFound(err) {
×
111
                        klog.Errorf("failed to get subnet %s, %v", c.config.ExternalGatewaySwitch, err)
×
112
                        return err
×
113
                }
×
114
        } else {
×
115
                if externalSubnet.Spec.Vlan != "" {
×
116
                        keepExternalSubnet = true
×
117
                }
×
118
        }
119

120
        if !keepExternalSubnet {
×
121
                klog.Infof("delete external gateway switch %s", c.config.ExternalGatewaySwitch)
×
122
                if err := c.OVNNbClient.DeleteLogicalGatewaySwitch(util.ExternalGatewaySwitch, c.config.ClusterRouter); err != nil {
×
123
                        klog.Errorf("delete external gateway switch %s: %v", util.ExternalGatewaySwitch, err)
×
124
                        return err
×
125
                }
×
126
        } else {
×
127
                // provider network, underlay vlan control the external gateway switch
×
128
                klog.Infof("should keep provider network underlay vlan external gateway switch %s", c.config.ExternalGatewaySwitch)
×
129
                lrpName := fmt.Sprintf("%s-%s", c.config.ClusterRouter, c.config.ExternalGatewaySwitch)
×
130
                klog.Infof("delete logical router port %s", lrpName)
×
131
                if err := c.OVNNbClient.DeleteLogicalRouterPort(lrpName); err != nil {
×
132
                        klog.Errorf("failed to delete lrp %s, %v", lrpName, err)
×
133
                        return err
×
134
                }
×
135
        }
136
        return nil
×
137
}
138

139
func (c *Controller) establishExternalGateway(config map[string]string) error {
×
140
        chassises, err := c.getGatewayChassis(config)
×
141
        if err != nil {
×
142
                klog.Errorf("failed to get gateway chassis, %v", err)
×
143
                return err
×
144
        }
×
145
        var lrpIP, lrpMac string
×
146
        lrpName := fmt.Sprintf("%s-%s", c.config.ClusterRouter, c.config.ExternalGatewaySwitch)
×
147
        lrp, err := c.OVNNbClient.GetLogicalRouterPort(lrpName, true)
×
148
        if err != nil {
×
149
                klog.Errorf("failed to get lrp %s, %v", lrpName, err)
×
150
                return err
×
151
        }
×
152

153
        switch {
×
154
        case lrp != nil:
×
155
                klog.Infof("lrp %s already exist", lrpName)
×
156
                lrpMac = lrp.MAC
×
157
                lrpIP = lrp.Networks[0]
×
158
        case config["nic-ip"] == "":
×
159
                if lrpIP, lrpMac, err = c.createDefaultVpcLrpEip(); err != nil {
×
160
                        klog.Errorf("failed to create ovn eip for default vpc lrp: %v", err)
×
161
                        return err
×
162
                }
×
163
        default:
×
164
                lrpIP = config["nic-ip"]
×
165
                lrpMac = config["nic-mac"]
×
166
        }
167

168
        if err := c.OVNNbClient.CreateGatewayLogicalSwitch(c.config.ExternalGatewaySwitch, c.config.ClusterRouter, c.config.ExternalGatewayNet, lrpIP, lrpMac, c.config.ExternalGatewayVlanID, chassises...); err != nil {
×
169
                klog.Errorf("failed to create external gateway switch %s: %v", c.config.ExternalGatewaySwitch, err)
×
170
                return err
×
171
        }
×
172

173
        return nil
×
174
}
175

176
func (c *Controller) createDefaultVpcLrpEip() (string, string, error) {
×
177
        cachedSubnet, err := c.subnetsLister.Get(c.config.ExternalGatewaySwitch)
×
178
        if err != nil {
×
179
                klog.Errorf("failed to get subnet %s, %v", c.config.ExternalGatewaySwitch, err)
×
180
                return "", "", err
×
181
        }
×
182
        needCreateEip := false
×
183
        lrpEipName := fmt.Sprintf("%s-%s", c.config.ClusterRouter, c.config.ExternalGatewaySwitch)
×
184
        cachedEip, err := c.ovnEipsLister.Get(lrpEipName)
×
185
        if err != nil {
×
186
                if !k8serrors.IsNotFound(err) {
×
187
                        klog.Errorf("failed to get eip %s, %v", lrpEipName, err)
×
188
                        return "", "", err
×
189
                }
×
190
                needCreateEip = true
×
191
        }
192
        var v4ip, mac string
×
193
        if !needCreateEip {
×
194
                v4ip = cachedEip.Status.V4Ip
×
195
                mac = cachedEip.Status.MacAddress
×
196
                if v4ip == "" || mac == "" {
×
197
                        err = fmt.Errorf("lrp %q ip or mac should not be empty", lrpEipName)
×
198
                        klog.Error(err)
×
199
                        return "", "", err
×
200
                }
×
201
        } else {
×
202
                var v6ip string
×
203
                v4ip, v6ip, mac, err = c.acquireIPAddress(c.config.ExternalGatewaySwitch, lrpEipName, lrpEipName)
×
204
                if err != nil {
×
205
                        klog.Errorf("failed to acquire ip address for default vpc lrp %s, %v", lrpEipName, err)
×
206
                        return "", "", err
×
207
                }
×
208
                if err := c.createOrUpdateOvnEipCR(lrpEipName, c.config.ExternalGatewaySwitch, v4ip, v6ip, mac, util.OvnEipTypeLRP); err != nil {
×
209
                        klog.Errorf("failed to create ovn lrp eip %s, %v", lrpEipName, err)
×
210
                        return "", "", err
×
211
                }
×
212
        }
213
        v4ipCidr, err := util.GetIPAddrWithMask(v4ip, cachedSubnet.Spec.CIDRBlock)
×
214
        if err != nil {
×
215
                klog.Errorf("failed to get ip %s with mask %s, %v", v4ip, cachedSubnet.Spec.CIDRBlock, err)
×
216
                return "", "", err
×
217
        }
×
218
        return v4ipCidr, mac, nil
×
219
}
220

221
func (c *Controller) getGatewayChassis(config map[string]string) ([]string, error) {
×
222
        chassises := []string{}
×
223
        sel, _ := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{util.ExGatewayLabel: "true"}})
×
224
        nodes, err := c.nodesLister.List(sel)
×
225
        if err != nil {
×
226
                klog.Errorf("failed to list external gw nodes, %v", err)
×
227
                return nil, err
×
228
        }
×
229
        gwNodes := make([]string, 0, len(nodes))
×
230
        for _, node := range nodes {
×
231
                gwNodes = append(gwNodes, node.Name)
×
232
        }
×
233
        if config["type"] != kubeovnv1.GWDistributedType {
×
234
                nodeNames := strings.SplitSeq(config["external-gw-nodes"], ",")
×
235
                for name := range nodeNames {
×
236
                        name = strings.TrimSpace(name)
×
237
                        if name == "" {
×
238
                                continue
×
239
                        }
240
                        if !slices.Contains(gwNodes, name) {
×
241
                                gwNodes = append(gwNodes, name)
×
242
                        }
×
243
                }
244
        }
245
        for _, gw := range gwNodes {
×
246
                node, err := c.nodesLister.Get(gw)
×
247
                if err != nil {
×
248
                        klog.Errorf("failed to get gw node %s, %v", gw, err)
×
249
                        return nil, err
×
250
                }
×
251
                patch := util.KVPatch{util.ExGatewayLabel: "true"}
×
252
                if err = util.PatchLabels(c.config.KubeClient.CoreV1().Nodes(), node.Name, patch); err != nil {
×
253
                        klog.Errorf("failed to patch annotations of node %s: %v", node.Name, err)
×
254
                        return nil, err
×
255
                }
×
256

257
                annoChassisName := node.Annotations[util.ChassisAnnotation]
×
258
                if annoChassisName == "" {
×
259
                        err := fmt.Errorf("node %s has no chassis annotation, kube-ovn-cni not ready", gw)
×
260
                        klog.Error(err)
×
261
                        return nil, err
×
262
                }
×
263
                klog.Infof("get node %s chassis: %s", gw, annoChassisName)
×
264
                chassis, err := c.OVNSbClient.GetChassis(annoChassisName, false)
×
265
                if err != nil {
×
266
                        klog.Errorf("failed to get node %s chassis: %s, %v", node.Name, annoChassisName, err)
×
267
                        return nil, err
×
268
                }
×
269
                chassises = append(chassises, chassis.Name)
×
270
        }
271
        if len(chassises) == 0 {
×
272
                err := errors.New("no available external gw chassis")
×
273
                klog.Error(err)
×
274
                return nil, err
×
275
        }
×
276
        return chassises, nil
×
277
}
278

279
func (c *Controller) updateDefaultVpcExternal(enableExternal bool) error {
×
280
        cachedVpc, err := c.vpcsLister.Get(c.config.ClusterRouter)
×
281
        if err != nil {
×
282
                klog.Errorf("failed to get vpc %s, %v", c.config.ClusterRouter, err)
×
283
                return err
×
284
        }
×
285
        vpc := cachedVpc.DeepCopy()
×
286
        if vpc.Spec.EnableExternal != enableExternal {
×
287
                vpc.Spec.EnableExternal = enableExternal
×
288
                if _, err := c.config.KubeOvnClient.KubeovnV1().Vpcs().Update(context.Background(), vpc, metav1.UpdateOptions{}); err != nil {
×
289
                        err := fmt.Errorf("failed to update vpc enable external %s, %w", vpc.Name, err)
×
290
                        klog.Error(err)
×
291
                        return err
×
292
                }
×
293
        }
294
        if vpc.Status.EnableExternal != enableExternal {
×
295
                vpc.Status.EnableExternal = enableExternal
×
296
                bytes, err := vpc.Status.Bytes()
×
297
                if err != nil {
×
298
                        klog.Errorf("failed to get vpc bytes, %v", err)
×
299
                        return err
×
300
                }
×
301
                if _, err = c.config.KubeOvnClient.KubeovnV1().Vpcs().Patch(context.Background(),
×
302
                        vpc.Name, types.MergePatchType, bytes, metav1.PatchOptions{}, "status"); err != nil {
×
303
                        klog.Errorf("failed to patch vpc %s, %v", c.config.ClusterRouter, err)
×
304
                        return err
×
305
                }
×
306
        }
307
        return nil
×
308
}
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

© 2025 Coveralls, Inc