1
2
3
4
19
20 package network
21
22 import (
23 "context"
24 "fmt"
25 "net/http"
26 "time"
27
28 compute "google.golang.org/api/compute/v1"
29
30 "github.com/GoogleCloudPlatform/k8s-cloud-provider/pkg/cloud"
31 v1 "k8s.io/api/core/v1"
32 "k8s.io/apimachinery/pkg/util/wait"
33 clientset "k8s.io/client-go/kubernetes"
34 cloudprovider "k8s.io/cloud-provider"
35 "k8s.io/kubernetes/test/e2e/framework"
36 "k8s.io/kubernetes/test/e2e/framework/providers/gce"
37 e2eservice "k8s.io/kubernetes/test/e2e/framework/service"
38 e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
39 "k8s.io/kubernetes/test/e2e/network/common"
40 gcecloud "k8s.io/legacy-cloud-providers/gce"
41 admissionapi "k8s.io/pod-security-admission/api"
42
43 "github.com/onsi/ginkgo/v2"
44 "github.com/onsi/gomega"
45 )
46
47 var _ = common.SIGDescribe("Services GCE", framework.WithSlow(), func() {
48 f := framework.NewDefaultFramework("services")
49 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
50
51 var cs clientset.Interface
52 serviceLBNames := []string{}
53
54 ginkgo.BeforeEach(func() {
55
56 e2eskipper.SkipUnlessProviderIs("gce")
57 cs = f.ClientSet
58 })
59
60 ginkgo.AfterEach(func(ctx context.Context) {
61 if ginkgo.CurrentSpecReport().Failed() {
62 DescribeSvc(f.Namespace.Name)
63 }
64 for _, lb := range serviceLBNames {
65 framework.Logf("cleaning gce resource for %s", lb)
66 framework.TestContext.CloudConfig.Provider.CleanupServiceResources(ctx, cs, lb, framework.TestContext.CloudConfig.Region, framework.TestContext.CloudConfig.Zone)
67 }
68
69 serviceLBNames = []string{}
70 })
71 f.It("should be able to create and tear down a standard-tier load balancer", f.WithSlow(), func(ctx context.Context) {
72 lagTimeout := e2eservice.LoadBalancerLagTimeoutDefault
73 createTimeout := e2eservice.GetServiceLoadBalancerCreationTimeout(ctx, cs)
74
75 svcName := "net-tiers-svc"
76 ns := f.Namespace.Name
77 jig := e2eservice.NewTestJig(cs, ns, svcName)
78
79 ginkgo.By("creating a pod to be part of the service " + svcName)
80 _, err := jig.Run(ctx, nil)
81 framework.ExpectNoError(err)
82
83
84 ginkgo.By("creating a Service of type LoadBalancer using the standard network tier")
85 svc, err := jig.CreateTCPService(ctx, func(svc *v1.Service) {
86 svc.Spec.Type = v1.ServiceTypeLoadBalancer
87 setNetworkTier(svc, string(gcecloud.NetworkTierAnnotationStandard))
88 })
89 framework.ExpectNoError(err)
90
91 svcTier, err := gcecloud.GetServiceNetworkTier(svc)
92 framework.ExpectNoError(err)
93 gomega.Expect(svcTier).To(gomega.Equal(cloud.NetworkTierStandard))
94
95 serviceLBNames = append(serviceLBNames, cloudprovider.DefaultLoadBalancerName(svc))
96
97
98 ingressIP := waitAndVerifyLBWithTier(ctx, jig, "", createTimeout, lagTimeout)
99
100
101 ginkgo.By("updating the Service to use the premium (default) tier")
102 svc, err = jig.UpdateService(ctx, func(svc *v1.Service) {
103 setNetworkTier(svc, string(gcecloud.NetworkTierAnnotationPremium))
104 })
105 framework.ExpectNoError(err)
106
107 svcTier, err = gcecloud.GetServiceNetworkTier(svc)
108 framework.ExpectNoError(err)
109 gomega.Expect(svcTier).To(gomega.Equal(cloud.NetworkTierDefault))
110
111
112
113 ingressIP = waitAndVerifyLBWithTier(ctx, jig, ingressIP, createTimeout, lagTimeout)
114
115
116 ginkgo.By("reserving a static IP for the load balancer")
117 requestedAddrName := fmt.Sprintf("e2e-ext-lb-net-tier-%s", framework.RunID)
118 gceCloud, err := gce.GetGCECloud()
119 framework.ExpectNoError(err)
120 requestedIP, err := reserveRegionalAddress(gceCloud, requestedAddrName, cloud.NetworkTierStandard)
121 framework.ExpectNoError(err, "failed to reserve a STANDARD tiered address")
122 defer func() {
123 if requestedAddrName != "" {
124
125 if err := gceCloud.DeleteRegionAddress(requestedAddrName, gceCloud.Region()); err != nil {
126 framework.Logf("failed to release static IP address %q: %v", requestedAddrName, err)
127 }
128 }
129 }()
130 framework.ExpectNoError(err)
131 framework.Logf("Allocated static IP to be used by the load balancer: %q", requestedIP)
132
133 ginkgo.By("updating the Service to use the standard tier with a requested IP")
134 svc, err = jig.UpdateService(ctx, func(svc *v1.Service) {
135 svc.Spec.LoadBalancerIP = requestedIP
136 setNetworkTier(svc, string(gcecloud.NetworkTierAnnotationStandard))
137 })
138 framework.ExpectNoError(err)
139
140 gomega.Expect(svc.Spec.LoadBalancerIP).To(gomega.Equal(requestedIP))
141 svcTier, err = gcecloud.GetServiceNetworkTier(svc)
142 framework.ExpectNoError(err)
143 gomega.Expect(svcTier).To(gomega.Equal(cloud.NetworkTierStandard))
144
145
146 waitAndVerifyLBWithTier(ctx, jig, ingressIP, createTimeout, lagTimeout)
147 })
148 })
149
150 func waitAndVerifyLBWithTier(ctx context.Context, jig *e2eservice.TestJig, existingIP string, waitTimeout, checkTimeout time.Duration) string {
151
152
153 svc, err := jig.WaitForNewIngressIP(ctx, existingIP, waitTimeout)
154 framework.ExpectNoError(err)
155
156 svcPort := int(svc.Spec.Ports[0].Port)
157 lbIngress := &svc.Status.LoadBalancer.Ingress[0]
158 ingressIP := e2eservice.GetIngressPoint(lbIngress)
159
160 ginkgo.By("running sanity and reachability checks")
161 if svc.Spec.LoadBalancerIP != "" {
162
163 gomega.Expect(ingressIP).To(gomega.Equal(svc.Spec.LoadBalancerIP))
164 }
165
166
167
168 e2eservice.TestReachableHTTPWithRetriableErrorCodes(ctx, ingressIP, svcPort, []int{http.StatusNotFound}, checkTimeout)
169
170
171 svcNetTier, err := gcecloud.GetServiceNetworkTier(svc)
172 framework.ExpectNoError(err)
173 netTier, err := getLBNetworkTierByIP(ingressIP)
174 framework.ExpectNoError(err, "failed to get the network tier of the load balancer")
175 gomega.Expect(netTier).To(gomega.Equal(svcNetTier))
176
177 return ingressIP
178 }
179
180 func getLBNetworkTierByIP(ip string) (cloud.NetworkTier, error) {
181 var rule *compute.ForwardingRule
182
183 err := wait.PollImmediate(5*time.Second, 15*time.Second, func() (bool, error) {
184 obj, err := getGCEForwardingRuleByIP(ip)
185 if err != nil {
186 return false, err
187 }
188 rule = obj
189 return true, nil
190 })
191 if err != nil {
192 return "", err
193 }
194 return cloud.NetworkTierGCEValueToType(rule.NetworkTier), nil
195 }
196
197 func getGCEForwardingRuleByIP(ip string) (*compute.ForwardingRule, error) {
198 cloud, err := gce.GetGCECloud()
199 if err != nil {
200 return nil, err
201 }
202 ruleList, err := cloud.ListRegionForwardingRules(cloud.Region())
203 if err != nil {
204 return nil, err
205 }
206 for _, rule := range ruleList {
207 if rule.IPAddress == ip {
208 return rule, nil
209 }
210 }
211 return nil, fmt.Errorf("forwarding rule with ip %q not found", ip)
212 }
213
214 func setNetworkTier(svc *v1.Service, tier string) {
215 key := gcecloud.NetworkTierAnnotationKey
216 if svc.ObjectMeta.Annotations == nil {
217 svc.ObjectMeta.Annotations = map[string]string{}
218 }
219 svc.ObjectMeta.Annotations[key] = tier
220 }
221
222
223 func reserveRegionalAddress(cloud *gcecloud.Cloud, name string, netTier cloud.NetworkTier) (string, error) {
224 Addr := &compute.Address{
225 Name: name,
226 NetworkTier: netTier.ToGCEValue(),
227 }
228
229 if err := cloud.ReserveRegionAddress(Addr, cloud.Region()); err != nil {
230 return "", err
231 }
232
233 addr, err := cloud.GetRegionAddress(name, cloud.Region())
234 if err != nil {
235 return "", err
236 }
237
238 return addr.Address, nil
239 }
240
View as plain text