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

kubeovn / kube-ovn / 12275027635

11 Dec 2024 11:03AM UTC coverage: 21.899% (+3.2%) from 18.675%
12275027635

Pull #4800

github

changluyi
add e2e test script

Signed-off-by: clyi <clyi@alauda.io>
Pull Request #4800: pod should use mac and ips provider by multus firstly

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

32 existing lines in 2 files now uncovered.

10185 of 46508 relevant lines covered (21.9%)

0.25 hits per line

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

0.0
/pkg/webhook/static_ip.go
1
package webhook
2

3
import (
4
        "context"
5
        "fmt"
6
        "net"
7
        "net/http"
8
        "strings"
9

10
        appsv1 "k8s.io/api/apps/v1"
11
        batchv1 "k8s.io/api/batch/v1"
12
        corev1 "k8s.io/api/core/v1"
13
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14
        "k8s.io/apimachinery/pkg/types"
15
        "k8s.io/klog/v2"
16
        ctrlwebhook "sigs.k8s.io/controller-runtime/pkg/webhook"
17
        "sigs.k8s.io/controller-runtime/pkg/webhook/admission"
18

19
        ovnv1 "github.com/kubeovn/kube-ovn/pkg/apis/kubeovn/v1"
20
        "github.com/kubeovn/kube-ovn/pkg/util"
21
)
22

23
var (
24
        deploymentGVK  = metav1.GroupVersionKind{Group: appsv1.SchemeGroupVersion.Group, Version: appsv1.SchemeGroupVersion.Version, Kind: "Deployment"}
25
        statefulSetGVK = metav1.GroupVersionKind{Group: appsv1.SchemeGroupVersion.Group, Version: appsv1.SchemeGroupVersion.Version, Kind: "StatefulSet"}
26
        daemonSetGVK   = metav1.GroupVersionKind{Group: appsv1.SchemeGroupVersion.Group, Version: appsv1.SchemeGroupVersion.Version, Kind: "DaemonSet"}
27
        jobSetGVK      = metav1.GroupVersionKind{Group: batchv1.SchemeGroupVersion.Group, Version: batchv1.SchemeGroupVersion.Version, Kind: "Job"}
28
        cornJobSetGVK  = metav1.GroupVersionKind{Group: batchv1.SchemeGroupVersion.Group, Version: batchv1.SchemeGroupVersion.Version, Kind: "CronJob"}
29
        podGVK         = metav1.GroupVersionKind{Group: corev1.SchemeGroupVersion.Group, Version: corev1.SchemeGroupVersion.Version, Kind: "Pod"}
30
        subnetGVK      = metav1.GroupVersionKind{Group: ovnv1.SchemeGroupVersion.Group, Version: ovnv1.SchemeGroupVersion.Version, Kind: "Subnet"}
31
        vpcGVK         = metav1.GroupVersionKind{Group: ovnv1.SchemeGroupVersion.Group, Version: ovnv1.SchemeGroupVersion.Version, Kind: "Vpc"}
32
)
33

34
func (v *ValidatingHook) DeploymentCreateHook(ctx context.Context, req admission.Request) admission.Response {
×
35
        o := appsv1.Deployment{}
×
36
        if err := v.decoder.Decode(req, &o); err != nil {
×
37
                return ctrlwebhook.Errored(http.StatusBadRequest, err)
×
38
        }
×
39
        // Get pod template static ips
40
        staticIPSAnno := o.Spec.Template.GetAnnotations()[util.IPPoolAnnotation]
×
41
        klog.V(3).Infof("%s %s@%s, ip_pool: %s", o.Kind, o.GetName(), o.GetNamespace(), staticIPSAnno)
×
42
        if staticIPSAnno == "" {
×
43
                return ctrlwebhook.Allowed("by pass")
×
44
        }
×
45
        return v.validateIP(ctx, o.Spec.Template.GetAnnotations(), o.Kind, o.GetName(), o.GetNamespace())
×
46
}
47

48
func (v *ValidatingHook) StatefulSetCreateHook(ctx context.Context, req admission.Request) admission.Response {
×
49
        o := appsv1.StatefulSet{}
×
50
        if err := v.decoder.Decode(req, &o); err != nil {
×
51
                return ctrlwebhook.Errored(http.StatusBadRequest, err)
×
52
        }
×
53
        // Get pod template static ips
54
        staticIPSAnno := o.Spec.Template.GetAnnotations()[util.IPPoolAnnotation]
×
55
        klog.V(3).Infof("%s %s@%s, ip_pool: %s", o.Kind, o.GetName(), o.GetNamespace(), staticIPSAnno)
×
56
        if staticIPSAnno == "" {
×
57
                return ctrlwebhook.Allowed("by pass")
×
58
        }
×
59
        return v.validateIP(ctx, o.Spec.Template.GetAnnotations(), o.Kind, o.GetName(), o.GetNamespace())
×
60
}
61

62
func (v *ValidatingHook) DaemonSetCreateHook(ctx context.Context, req admission.Request) admission.Response {
×
63
        o := appsv1.DaemonSet{}
×
64
        if err := v.decoder.Decode(req, &o); err != nil {
×
65
                return ctrlwebhook.Errored(http.StatusBadRequest, err)
×
66
        }
×
67
        // Get pod template static ips
68
        staticIPSAnno := o.Spec.Template.GetAnnotations()[util.IPPoolAnnotation]
×
69
        klog.V(3).Infof("%s %s@%s, ip_pool: %s", o.Kind, o.GetName(), o.GetNamespace(), staticIPSAnno)
×
70
        if staticIPSAnno == "" {
×
71
                return ctrlwebhook.Allowed("by pass")
×
72
        }
×
73
        return v.validateIP(ctx, o.Spec.Template.GetAnnotations(), o.Kind, o.GetName(), o.GetNamespace())
×
74
}
75

76
func (v *ValidatingHook) JobSetCreateHook(ctx context.Context, req admission.Request) admission.Response {
×
77
        o := batchv1.Job{}
×
78
        if err := v.decoder.Decode(req, &o); err != nil {
×
79
                return ctrlwebhook.Errored(http.StatusBadRequest, err)
×
80
        }
×
81
        // Get pod template static ips
82
        staticIPSAnno := o.Spec.Template.GetAnnotations()[util.IPPoolAnnotation]
×
83
        klog.V(3).Infof("%s %s@%s, ip_pool: %s", o.Kind, o.GetName(), o.GetNamespace(), staticIPSAnno)
×
84
        if staticIPSAnno == "" {
×
85
                return ctrlwebhook.Allowed("by pass")
×
86
        }
×
87
        return v.validateIP(ctx, o.Spec.Template.GetAnnotations(), o.Kind, o.GetName(), o.GetNamespace())
×
88
}
89

90
func (v *ValidatingHook) CornJobSetCreateHook(ctx context.Context, req admission.Request) admission.Response {
×
91
        o := batchv1.CronJob{}
×
92
        if err := v.decoder.Decode(req, &o); err != nil {
×
93
                return ctrlwebhook.Errored(http.StatusBadRequest, err)
×
94
        }
×
95
        // Get pod template static ips
96
        staticIPSAnno := o.Spec.JobTemplate.Spec.Template.GetAnnotations()[util.IPPoolAnnotation]
×
97
        klog.V(3).Infof("%s %s@%s, ip_pool: %s", o.Kind, o.GetName(), o.GetNamespace(), staticIPSAnno)
×
98
        if staticIPSAnno == "" {
×
99
                return ctrlwebhook.Allowed("by pass")
×
100
        }
×
101
        return v.validateIP(ctx, o.Spec.JobTemplate.Spec.Template.GetAnnotations(), o.Kind, o.GetName(), o.GetNamespace())
×
102
}
103

104
func (v *ValidatingHook) PodCreateHook(ctx context.Context, req admission.Request) admission.Response {
×
105
        o := corev1.Pod{}
×
106
        if err := v.decoder.Decode(req, &o); err != nil {
×
107
                return ctrlwebhook.Errored(http.StatusBadRequest, err)
×
108
        }
×
109
        poolAnno := o.GetAnnotations()[util.IPPoolAnnotation]
×
110
        klog.V(3).Infof("%s %s@%s, ip_pool: %s", o.Kind, o.GetName(), o.GetNamespace(), poolAnno)
×
111

×
112
        staticIP := o.GetAnnotations()[util.IPAddressAnnotation]
×
113
        klog.V(3).Infof("%s %s@%s, ip_address: %s", o.Kind, o.GetName(), o.GetNamespace(), staticIP)
×
114
        if staticIP == "" && poolAnno == "" {
×
115
                return ctrlwebhook.Allowed("by pass")
×
116
        }
×
117
        if v.allowLiveMigration(o.GetAnnotations()) {
×
118
                return ctrlwebhook.Allowed("by pass")
×
119
        }
×
120
        return v.validateIP(ctx, o.GetAnnotations(), o.Kind, o.GetName(), o.GetNamespace())
×
121
}
122

123
func (v *ValidatingHook) allowLiveMigration(annotations map[string]string) bool {
×
124
        if _, ok := annotations[util.MigrationJobAnnotation]; ok {
×
125
                return true
×
126
        }
×
127
        return false
×
128
}
129

130
func (v *ValidatingHook) validateIP(ctx context.Context, annotations map[string]string, kind, name, namespace string) admission.Response {
×
131
        if err := util.ValidatePodNetwork(annotations); err != nil {
×
132
                klog.Errorf("validate %s %s/%s failed: %v", kind, namespace, name, err)
×
133
                return ctrlwebhook.Errored(http.StatusBadRequest, err)
×
134
        }
×
135

136
        ipList := &ovnv1.IPList{}
×
137
        if err := v.cache.List(ctx, ipList); err != nil {
×
138
                return ctrlwebhook.Errored(http.StatusBadRequest, err)
×
139
        }
×
140
        if err := v.validateIPConflict(ctx, annotations, name, ipList.Items); err != nil {
×
141
                return ctrlwebhook.Denied(err.Error())
×
142
        }
×
143

144
        return ctrlwebhook.Allowed("by pass")
×
145
}
146

147
func (v *ValidatingHook) validateIPConflict(ctx context.Context, annotations map[string]string, name string, ipList []ovnv1.IP) error {
×
148
        annoSubnet := annotations[util.LogicalSwitchAnnotation]
×
149
        if annotations[util.LogicalSwitchAnnotation] == "" {
×
150
                annoSubnet = util.DefaultSubnet
×
151
        }
×
152

153
        if ipAddress := annotations[util.IPAddressAnnotation]; ipAddress != "" {
×
154
                if err := v.checkIPConflict(ipAddress, annoSubnet, name, ipList); err != nil {
×
155
                        return err
×
156
                }
×
157
        }
158

159
        ipPool := annotations[util.IPPoolAnnotation]
×
160
        if ipPool != "" {
×
161
                if !strings.ContainsRune(ipPool, ',') && net.ParseIP(ipPool) == nil {
×
162
                        pool := &ovnv1.IPPool{}
×
163
                        if err := v.cache.Get(ctx, types.NamespacedName{Name: ipPool}, pool); err != nil {
×
164
                                return fmt.Errorf("ippool %q not found", ipPool)
×
165
                        }
×
166
                } else if err := v.checkIPConflict(ipPool, annoSubnet, name, ipList); err != nil {
×
167
                        return err
×
168
                }
×
169
        }
170
        return nil
×
171
}
172

173
func (v *ValidatingHook) checkIPConflict(ipAddress, annoSubnet, name string, ipList []ovnv1.IP) error {
×
174
        var ipAddr net.IP
×
175
        for _, ip := range strings.Split(ipAddress, ",") {
×
176
                if strings.Contains(ip, "/") {
×
177
                        ipAddr, _, _ = net.ParseCIDR(ip)
×
178
                } else {
×
179
                        ipAddr = net.ParseIP(strings.TrimSpace(ip))
×
180
                }
×
181
                if ipAddr == nil {
×
182
                        return fmt.Errorf("invalid static ip/ippool annotation value: %s", ipAddress)
×
183
                }
×
184

185
                for _, ipCR := range ipList {
×
186
                        if annoSubnet != "" && ipCR.Spec.Subnet != annoSubnet {
×
187
                                continue
×
188
                        }
189

190
                        v4IP, v6IP := util.SplitStringIP(ipCR.Spec.IPAddress)
×
191
                        // v6 ip address can not use upper case
×
192
                        if util.ContainsUppercase(v6IP) {
×
193
                                err := fmt.Errorf("v6 ip address %s can not contain upper case", v6IP)
×
194
                                klog.Error(err)
×
195
                                return err
×
196
                        }
×
197
                        if ipAddr.String() == v4IP || ipAddr.String() == v6IP {
×
198
                                if name == ipCR.Spec.PodName {
×
199
                                        klog.Infof("get same ip crd for %s", name)
×
200
                                } else {
×
201
                                        err := fmt.Errorf("annotation static-ip %s is conflict with ip crd %s, ip %s", ipAddr.String(), ipCR.Name, ipCR.Spec.IPAddress)
×
202
                                        return err
×
203
                                }
×
UNCOV
204
                        }
×
UNCOV
205
                }
×
206
        }
207

208
        return nil
209
}
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