k8s.io/kubernetes@v1.29.3/test/e2e/common/node/lease.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package node 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 "time" 24 25 coordinationv1 "k8s.io/api/coordination/v1" 26 apiequality "k8s.io/apimachinery/pkg/api/equality" 27 apierrors "k8s.io/apimachinery/pkg/api/errors" 28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 29 "k8s.io/apimachinery/pkg/labels" 30 "k8s.io/apimachinery/pkg/types" 31 "k8s.io/apimachinery/pkg/util/strategicpatch" 32 "k8s.io/kubernetes/test/e2e/framework" 33 admissionapi "k8s.io/pod-security-admission/api" 34 "k8s.io/utils/pointer" 35 36 "github.com/google/go-cmp/cmp" 37 "github.com/onsi/gomega" 38 ) 39 40 func getPatchBytes(oldLease, newLease *coordinationv1.Lease) ([]byte, error) { 41 oldData, err := json.Marshal(oldLease) 42 if err != nil { 43 return nil, fmt.Errorf("failed to Marshal oldData: %w", err) 44 } 45 newData, err := json.Marshal(newLease) 46 if err != nil { 47 return nil, fmt.Errorf("failed to Marshal newData: %w", err) 48 } 49 patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, coordinationv1.Lease{}) 50 if err != nil { 51 return nil, fmt.Errorf("failed to CreateTwoWayMergePatch: %w", err) 52 } 53 return patchBytes, nil 54 } 55 56 var _ = SIGDescribe("Lease", func() { 57 f := framework.NewDefaultFramework("lease-test") 58 f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged 59 60 /* 61 Release: v1.17 62 Testname: lease API should be available 63 Description: Create Lease object, and get it; create and get MUST be successful and Spec of the 64 read Lease MUST match Spec of original Lease. Update the Lease and get it; update and get MUST 65 be successful and Spec of the read Lease MUST match Spec of updated Lease. Patch the Lease and 66 get it; patch and get MUST be successful and Spec of the read Lease MUST match Spec of patched 67 Lease. Create a second Lease with labels and list Leases; create and list MUST be successful and 68 list MUST return both leases. Delete the labels lease via delete collection; the delete MUST be 69 successful and MUST delete only the labels lease. List leases; list MUST be successful and MUST 70 return just the remaining lease. Delete the lease; delete MUST be successful. Get the lease; get 71 MUST return not found error. 72 */ 73 framework.ConformanceIt("lease API should be available", func(ctx context.Context) { 74 leaseClient := f.ClientSet.CoordinationV1().Leases(f.Namespace.Name) 75 76 name := "lease" 77 lease := &coordinationv1.Lease{ 78 ObjectMeta: metav1.ObjectMeta{ 79 Name: name, 80 }, 81 Spec: coordinationv1.LeaseSpec{ 82 HolderIdentity: pointer.String("holder"), 83 LeaseDurationSeconds: pointer.Int32(30), 84 AcquireTime: &metav1.MicroTime{Time: time.Time{}.Add(2 * time.Second)}, 85 RenewTime: &metav1.MicroTime{Time: time.Time{}.Add(5 * time.Second)}, 86 LeaseTransitions: pointer.Int32(0), 87 }, 88 } 89 90 createdLease, err := leaseClient.Create(ctx, lease, metav1.CreateOptions{}) 91 framework.ExpectNoError(err, "creating Lease failed") 92 93 readLease, err := leaseClient.Get(ctx, name, metav1.GetOptions{}) 94 framework.ExpectNoError(err, "couldn't read Lease") 95 if !apiequality.Semantic.DeepEqual(lease.Spec, readLease.Spec) { 96 framework.Failf("Leases don't match. Diff (- for expected, + for actual):\n%s", cmp.Diff(lease.Spec, readLease.Spec)) 97 } 98 99 createdLease.Spec = coordinationv1.LeaseSpec{ 100 HolderIdentity: pointer.String("holder2"), 101 LeaseDurationSeconds: pointer.Int32(30), 102 AcquireTime: &metav1.MicroTime{Time: time.Time{}.Add(20 * time.Second)}, 103 RenewTime: &metav1.MicroTime{Time: time.Time{}.Add(50 * time.Second)}, 104 LeaseTransitions: pointer.Int32(1), 105 } 106 107 _, err = leaseClient.Update(ctx, createdLease, metav1.UpdateOptions{}) 108 framework.ExpectNoError(err, "updating Lease failed") 109 110 readLease, err = leaseClient.Get(ctx, name, metav1.GetOptions{}) 111 framework.ExpectNoError(err, "couldn't read Lease") 112 if !apiequality.Semantic.DeepEqual(createdLease.Spec, readLease.Spec) { 113 framework.Failf("Leases don't match. Diff (- for expected, + for actual):\n%s", cmp.Diff(createdLease.Spec, readLease.Spec)) 114 } 115 116 patchedLease := readLease.DeepCopy() 117 patchedLease.Spec = coordinationv1.LeaseSpec{ 118 HolderIdentity: pointer.String("holder3"), 119 LeaseDurationSeconds: pointer.Int32(60), 120 AcquireTime: &metav1.MicroTime{Time: time.Time{}.Add(50 * time.Second)}, 121 RenewTime: &metav1.MicroTime{Time: time.Time{}.Add(70 * time.Second)}, 122 LeaseTransitions: pointer.Int32(2), 123 } 124 patchBytes, err := getPatchBytes(readLease, patchedLease) 125 framework.ExpectNoError(err, "creating patch failed") 126 127 _, err = leaseClient.Patch(ctx, name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}) 128 framework.ExpectNoError(err, "patching Lease failed") 129 130 readLease, err = leaseClient.Get(ctx, name, metav1.GetOptions{}) 131 framework.ExpectNoError(err, "couldn't read Lease") 132 if !apiequality.Semantic.DeepEqual(patchedLease.Spec, readLease.Spec) { 133 framework.Failf("Leases don't match. Diff (- for expected, + for actual):\n%s", cmp.Diff(patchedLease.Spec, readLease.Spec)) 134 } 135 136 name2 := "lease2" 137 lease2 := &coordinationv1.Lease{ 138 ObjectMeta: metav1.ObjectMeta{ 139 Name: name2, 140 Labels: map[string]string{"deletecollection": "true"}, 141 }, 142 Spec: coordinationv1.LeaseSpec{ 143 HolderIdentity: pointer.String("holder"), 144 LeaseDurationSeconds: pointer.Int32(30), 145 AcquireTime: &metav1.MicroTime{Time: time.Time{}.Add(2 * time.Second)}, 146 RenewTime: &metav1.MicroTime{Time: time.Time{}.Add(5 * time.Second)}, 147 LeaseTransitions: pointer.Int32(0), 148 }, 149 } 150 _, err = leaseClient.Create(ctx, lease2, metav1.CreateOptions{}) 151 framework.ExpectNoError(err, "creating Lease failed") 152 153 leases, err := leaseClient.List(ctx, metav1.ListOptions{}) 154 framework.ExpectNoError(err, "couldn't list Leases") 155 gomega.Expect(leases.Items).To(gomega.HaveLen(2)) 156 157 selector := labels.Set(map[string]string{"deletecollection": "true"}).AsSelector() 158 err = leaseClient.DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{LabelSelector: selector.String()}) 159 framework.ExpectNoError(err, "couldn't delete collection") 160 161 leases, err = leaseClient.List(ctx, metav1.ListOptions{}) 162 framework.ExpectNoError(err, "couldn't list Leases") 163 gomega.Expect(leases.Items).To(gomega.HaveLen(1)) 164 165 err = leaseClient.Delete(ctx, name, metav1.DeleteOptions{}) 166 framework.ExpectNoError(err, "deleting Lease failed") 167 168 _, err = leaseClient.Get(ctx, name, metav1.GetOptions{}) 169 if !apierrors.IsNotFound(err) { 170 framework.Failf("expected IsNotFound error, got %#v", err) 171 } 172 173 leaseClient = f.ClientSet.CoordinationV1().Leases(metav1.NamespaceAll) 174 // Number of leases may be high in large clusters, as Lease object is 175 // created for every node by the corresponding Kubelet. 176 // That said, the objects themselves are small (~300B), so even with 5000 177 // of them, that gives ~1.5MB, which is acceptable. 178 _, err = leaseClient.List(ctx, metav1.ListOptions{}) 179 framework.ExpectNoError(err, "couldn't list Leases from all namespace") 180 }) 181 })