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

kubeovn / kube-ovn / 12365336204

17 Dec 2024 02:43AM UTC coverage: 22.074%. First build
12365336204

Pull #4838

github

zhangzujian
wip

Signed-off-by: zhangzujian <zhangzujian.7@gmail.com>
Pull Request #4838: use JSON merge patch to update labels/annotations

11 of 22 new or added lines in 6 files covered. (50.0%)

10262 of 46489 relevant lines covered (22.07%)

0.26 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
        "reflect"
8
        "slices"
9
        "strings"
10

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

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

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

25
func (c *Controller) resyncExternalGateway() {
×
26
        cm, err := c.configMapsLister.ConfigMaps(c.config.ExternalGatewayConfigNS).Get(util.ExternalGatewayConfig)
×
27
        if err != nil && !k8serrors.IsNotFound(err) {
×
28
                klog.Errorf("failed to get ovn-external-gw-config, %v", err)
×
29
                return
×
30
        }
×
31

32
        if k8serrors.IsNotFound(err) || cm.Data["enable-external-gw"] == "false" {
×
33
                if exGwEnabled == "false" {
×
34
                        return
×
35
                }
×
36
                klog.Info("start to remove ovn external gw")
×
37
                if err := c.removeExternalGateway(); err != nil {
×
38
                        klog.Errorf("failed to remove ovn external gw, %v", err)
×
39
                        return
×
40
                }
×
41
                if err := c.updateDefaultVpcExternal(false); err != nil {
×
42
                        klog.Errorf("failed to update default vpc, %v", err)
×
43
                        return
×
44
                }
×
45
                exGwEnabled = "false"
×
46
                lastExGwCM = nil
×
47
                klog.Info("finish remove ovn external gw")
×
48
                return
×
49
        }
50

51
        if exGwEnabled == "true" && lastExGwCM != nil && reflect.DeepEqual(cm.Data, lastExGwCM) {
×
52
                return
×
53
        }
×
54
        klog.Infof("last external gw configmap: %v", lastExGwCM)
×
55
        if (lastExGwCM["type"] == kubeovnv1.GWDistributedType && cm.Data["type"] == kubeovnv1.GWCentralizedType) ||
×
56
                lastExGwCM != nil && !reflect.DeepEqual(lastExGwCM["external-gw-nodes"], cm.Data["external-gw-nodes"]) {
×
57
                klog.Info("external gw nodes list changed, start to remove ovn external gw")
×
58
                if err := c.removeExternalGateway(); err != nil {
×
59
                        klog.Errorf("failed to remove old ovn external gw, %v", err)
×
60
                        return
×
61
                }
×
62
        }
63
        klog.Info("start to establish ovn external gw")
×
64
        if err := c.establishExternalGateway(cm.Data); err != nil {
×
65
                klog.Errorf("failed to establish ovn-external-gw, %v", err)
×
66
                return
×
67
        }
×
68
        exGwEnabled = "true"
×
69
        lastExGwCM = cm.Data
×
70
        c.ExternalGatewayType = cm.Data["type"]
×
71
        if err := c.updateDefaultVpcExternal(true); err != nil {
×
72
                klog.Errorf("failed to update default vpc, %v", err)
×
73
                return
×
74
        }
×
75
        klog.Info("finish establishing ovn external gw")
×
76
}
77

78
func (c *Controller) removeExternalGateway() error {
×
79
        sel, _ := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{util.ExGatewayLabel: "true"}})
×
80
        nodes, err := c.nodesLister.List(sel)
×
81
        if err != nil {
×
82
                klog.Errorf("failed to list external gw nodes, %v", err)
×
83
                return err
×
84
        }
×
85
        for _, node := range nodes {
×
86
                labels := map[string]any{util.ExGatewayLabel: "false"}
×
NEW
87
                if err = util.PatchLabels(c.config.KubeClient.CoreV1().Nodes(), node.Name, labels); err != nil {
×
88
                        klog.Errorf("failed to patch external gw node %s: %v", node.Name, err)
×
89
                        return err
×
90
                }
×
91
        }
92

93
        keepExternalSubnet := false
×
94
        externalSubnet, err := c.subnetsLister.Get(c.config.ExternalGatewaySwitch)
×
95
        if err != nil {
×
96
                if !k8serrors.IsNotFound(err) {
×
97
                        klog.Errorf("failed to get subnet %s, %v", c.config.ExternalGatewaySwitch, err)
×
98
                        return err
×
99
                }
×
100
        } else {
×
101
                if externalSubnet.Spec.Vlan != "" {
×
102
                        keepExternalSubnet = true
×
103
                }
×
104
        }
105

106
        if !keepExternalSubnet {
×
107
                klog.Infof("delete external gateway switch %s", c.config.ExternalGatewaySwitch)
×
108
                if err := c.OVNNbClient.DeleteLogicalGatewaySwitch(util.ExternalGatewaySwitch, c.config.ClusterRouter); err != nil {
×
109
                        klog.Errorf("delete external gateway switch %s: %v", util.ExternalGatewaySwitch, err)
×
110
                        return err
×
111
                }
×
112
        } else {
×
113
                // provider network, underlay vlan control the external gateway switch
×
114
                klog.Infof("should keep provider network underlay vlan external gateway switch %s", c.config.ExternalGatewaySwitch)
×
115
                lrpName := fmt.Sprintf("%s-%s", c.config.ClusterRouter, c.config.ExternalGatewaySwitch)
×
116
                klog.Infof("delete logical router port %s", lrpName)
×
117
                if err := c.OVNNbClient.DeleteLogicalRouterPort(lrpName); err != nil {
×
118
                        klog.Errorf("failed to delete lrp %s, %v", lrpName, err)
×
119
                        return err
×
120
                }
×
121
        }
122
        return nil
×
123
}
124

125
func (c *Controller) establishExternalGateway(config map[string]string) error {
×
126
        chassises, err := c.getGatewayChassis(config)
×
127
        if err != nil {
×
128
                klog.Errorf("failed to get gateway chassis, %v", err)
×
129
                return err
×
130
        }
×
131
        var lrpIP, lrpMac string
×
132
        lrpName := fmt.Sprintf("%s-%s", c.config.ClusterRouter, c.config.ExternalGatewaySwitch)
×
133
        lrp, err := c.OVNNbClient.GetLogicalRouterPort(lrpName, true)
×
134
        if err != nil {
×
135
                klog.Errorf("failed to get lrp %s, %v", lrpName, err)
×
136
                return err
×
137
        }
×
138

139
        switch {
×
140
        case lrp != nil:
×
141
                klog.Infof("lrp %s already exist", lrpName)
×
142
                lrpMac = lrp.MAC
×
143
                lrpIP = lrp.Networks[0]
×
144
        case config["nic-ip"] == "":
×
145
                if lrpIP, lrpMac, err = c.createDefaultVpcLrpEip(); err != nil {
×
146
                        klog.Errorf("failed to create ovn eip for default vpc lrp: %v", err)
×
147
                        return err
×
148
                }
×
149
        default:
×
150
                lrpIP = config["nic-ip"]
×
151
                lrpMac = config["nic-mac"]
×
152
        }
153

154
        if err := c.OVNNbClient.CreateGatewayLogicalSwitch(c.config.ExternalGatewaySwitch, c.config.ClusterRouter, c.config.ExternalGatewayNet, lrpIP, lrpMac, c.config.ExternalGatewayVlanID, chassises...); err != nil {
×
155
                klog.Errorf("failed to create external gateway switch %s: %v", c.config.ExternalGatewaySwitch, err)
×
156
                return err
×
157
        }
×
158

159
        return nil
×
160
}
161

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

207
func (c *Controller) getGatewayChassis(config map[string]string) ([]string, error) {
×
208
        chassises := []string{}
×
209
        sel, _ := metav1.LabelSelectorAsSelector(&metav1.LabelSelector{MatchLabels: map[string]string{util.ExGatewayLabel: "true"}})
×
210
        nodes, err := c.nodesLister.List(sel)
×
211
        if err != nil {
×
212
                klog.Errorf("failed to list external gw nodes, %v", err)
×
213
                return nil, err
×
214
        }
×
215
        gwNodes := make([]string, 0, len(nodes))
×
216
        for _, node := range nodes {
×
217
                gwNodes = append(gwNodes, node.Name)
×
218
        }
×
219
        if config["type"] != kubeovnv1.GWDistributedType {
×
220
                nodeNames := strings.Split(config["external-gw-nodes"], ",")
×
221
                for _, name := range nodeNames {
×
222
                        name = strings.TrimSpace(name)
×
223
                        if name == "" {
×
224
                                continue
×
225
                        }
226
                        if !slices.Contains(gwNodes, name) {
×
227
                                gwNodes = append(gwNodes, name)
×
228
                        }
×
229
                }
230
        }
231
        for _, gw := range gwNodes {
×
232
                node, err := c.nodesLister.Get(gw)
×
233
                if err != nil {
×
234
                        klog.Errorf("failed to get gw node %s, %v", gw, err)
×
235
                        return nil, err
×
236
                }
×
237
                labels := map[string]any{util.ExGatewayLabel: "true"}
×
NEW
238
                if err = util.PatchLabels(c.config.KubeClient.CoreV1().Nodes(), node.Name, labels); err != nil {
×
239
                        klog.Errorf("failed to update annotations of node %s: %v", node.Name, err)
×
240
                        return nil, err
×
241
                }
×
242

243
                annoChassisName := node.Annotations[util.ChassisAnnotation]
×
244
                if annoChassisName == "" {
×
245
                        err := fmt.Errorf("node %s has no chassis annotation, kube-ovn-cni not ready", gw)
×
246
                        klog.Error(err)
×
247
                        return nil, err
×
248
                }
×
249
                klog.Infof("get node %s chassis: %s", gw, annoChassisName)
×
250
                chassis, err := c.OVNSbClient.GetChassis(annoChassisName, false)
×
251
                if err != nil {
×
252
                        klog.Errorf("failed to get node %s chassis: %s, %v", node.Name, annoChassisName, err)
×
253
                        return nil, err
×
254
                }
×
255
                chassises = append(chassises, chassis.Name)
×
256
        }
257
        if len(chassises) == 0 {
×
258
                err := errors.New("no available external gw chassis")
×
259
                klog.Error(err)
×
260
                return nil, err
×
261
        }
×
262
        return chassises, nil
×
263
}
264

265
func (c *Controller) updateDefaultVpcExternal(enableExternal bool) error {
×
266
        cachedVpc, err := c.vpcsLister.Get(c.config.ClusterRouter)
×
267
        if err != nil {
×
268
                klog.Errorf("failed to get vpc %s, %v", c.config.ClusterRouter, err)
×
269
                return err
×
270
        }
×
271
        vpc := cachedVpc.DeepCopy()
×
272
        if vpc.Spec.EnableExternal != enableExternal {
×
273
                vpc.Spec.EnableExternal = enableExternal
×
274
                if _, err := c.config.KubeOvnClient.KubeovnV1().Vpcs().Update(context.Background(), vpc, metav1.UpdateOptions{}); err != nil {
×
275
                        err := fmt.Errorf("failed to update vpc enable external %s, %w", vpc.Name, err)
×
276
                        klog.Error(err)
×
277
                        return err
×
278
                }
×
279
        }
280
        if vpc.Status.EnableExternal != enableExternal {
×
281
                vpc.Status.EnableExternal = enableExternal
×
282
                bytes, err := vpc.Status.Bytes()
×
283
                if err != nil {
×
284
                        klog.Errorf("failed to get vpc bytes, %v", err)
×
285
                        return err
×
286
                }
×
287
                if _, err = c.config.KubeOvnClient.KubeovnV1().Vpcs().Patch(context.Background(),
×
288
                        vpc.Name, types.MergePatchType, bytes, metav1.PatchOptions{}, "status"); err != nil {
×
289
                        klog.Errorf("failed to patch vpc %s, %v", c.config.ClusterRouter, err)
×
290
                        return err
×
291
                }
×
292
        }
293
        return nil
×
294
}
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