mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 06:54:01 +00:00
Add PatchService method in service/helper.
addressed review comments
This commit is contained in:
parent
edbd51bc69
commit
f0e45689d3
@ -17,10 +17,14 @@ limitations under the License.
|
|||||||
package helpers
|
package helpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||||
|
corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||||
utilnet "k8s.io/utils/net"
|
utilnet "k8s.io/utils/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -121,6 +125,40 @@ func LoadBalancerStatusEqual(l, r *v1.LoadBalancerStatus) bool {
|
|||||||
return ingressSliceEqual(l.Ingress, r.Ingress)
|
return ingressSliceEqual(l.Ingress, r.Ingress)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PatchService patches the given service's Status or ObjectMeta based on the original and
|
||||||
|
// updated ones. Change to spec will be ignored.
|
||||||
|
func PatchService(c corev1.CoreV1Interface, oldSvc, newSvc *v1.Service) (*v1.Service, error) {
|
||||||
|
// Reset spec to make sure only patch for Status or ObjectMeta.
|
||||||
|
newSvc.Spec = oldSvc.Spec
|
||||||
|
|
||||||
|
patchBytes, err := getPatchBytes(oldSvc, newSvc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.Services(oldSvc.Namespace).Patch(oldSvc.Name, types.StrategicMergePatchType, patchBytes, "status")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func getPatchBytes(oldSvc, newSvc *v1.Service) ([]byte, error) {
|
||||||
|
oldData, err := json.Marshal(oldSvc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to Marshal oldData for svc %s/%s: %v", oldSvc.Namespace, oldSvc.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
newData, err := json.Marshal(newSvc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to Marshal newData for svc %s/%s: %v", newSvc.Namespace, newSvc.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, v1.Service{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for svc %s/%s: %v", oldSvc.Namespace, oldSvc.Name, err)
|
||||||
|
}
|
||||||
|
return patchBytes, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func ingressSliceEqual(lhs, rhs []v1.LoadBalancerIngress) bool {
|
func ingressSliceEqual(lhs, rhs []v1.LoadBalancerIngress) bool {
|
||||||
if len(lhs) != len(rhs) {
|
if len(lhs) != len(rhs) {
|
||||||
return false
|
return false
|
||||||
|
@ -17,11 +17,13 @@ limitations under the License.
|
|||||||
package helpers
|
package helpers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
utilnet "k8s.io/utils/net"
|
utilnet "k8s.io/utils/net"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -269,3 +271,78 @@ func TestHasLBFinalizer(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPatchService(t *testing.T) {
|
||||||
|
svcOrigin := &v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-patch",
|
||||||
|
Annotations: map[string]string{},
|
||||||
|
},
|
||||||
|
Spec: v1.ServiceSpec{
|
||||||
|
ClusterIP: "10.0.0.1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
fakeCs := fake.NewSimpleClientset(svcOrigin)
|
||||||
|
|
||||||
|
// Issue a separate update and verify patch doesn't fail after this.
|
||||||
|
svcToUpdate := svcOrigin.DeepCopy()
|
||||||
|
addAnnotations(svcToUpdate)
|
||||||
|
if _, err := fakeCs.CoreV1().Services(svcOrigin.Namespace).Update(svcToUpdate); err != nil {
|
||||||
|
t.Fatalf("Failed to update service: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attempt to patch based the original service.
|
||||||
|
svcToPatch := svcOrigin.DeepCopy()
|
||||||
|
svcToPatch.Finalizers = []string{"foo"}
|
||||||
|
svcToPatch.Spec.ClusterIP = "10.0.0.2"
|
||||||
|
svcToPatch.Status = v1.ServiceStatus{
|
||||||
|
LoadBalancer: v1.LoadBalancerStatus{
|
||||||
|
Ingress: []v1.LoadBalancerIngress{
|
||||||
|
{IP: "8.8.8.8"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
svcPatched, err := PatchService(fakeCs.CoreV1(), svcOrigin, svcToPatch)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to patch service: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Service returned by patch will contain latest content (e.g from
|
||||||
|
// the separate update).
|
||||||
|
addAnnotations(svcToPatch)
|
||||||
|
if !reflect.DeepEqual(svcPatched, svcToPatch) {
|
||||||
|
t.Errorf("PatchStatus() = %+v, want %+v", svcPatched, svcToPatch)
|
||||||
|
}
|
||||||
|
// Explicitly validate if spec is unchanged from origin.
|
||||||
|
if !reflect.DeepEqual(svcPatched.Spec, svcOrigin.Spec) {
|
||||||
|
t.Errorf("Got spec = %+v, want %+v", svcPatched.Spec, svcOrigin.Spec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_getPatchBytes(t *testing.T) {
|
||||||
|
origin := &v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-patch-bytes",
|
||||||
|
Finalizers: []string{"foo"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
updated := &v1.Service{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "test-patch-bytes",
|
||||||
|
Finalizers: []string{"foo", "bar"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := getPatchBytes(origin, updated)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
expected := `{"metadata":{"$setElementOrder/finalizers":["foo","bar"],"finalizers":["bar"]}}`
|
||||||
|
if string(b) != expected {
|
||||||
|
t.Errorf("getPatchBytes(%+v, %+v) = %s ; want %s", origin, updated, string(b), expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addAnnotations(svc *v1.Service) {
|
||||||
|
svc.Annotations["foo"] = "bar"
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user