github.com/kubewharf/katalyst-core@v0.5.3/pkg/client/control/cnr.go (about) 1 /* 2 Copyright 2022 The Katalyst 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 control 18 19 import ( 20 "context" 21 "encoding/json" 22 "fmt" 23 24 jsonpatch "github.com/evanphx/json-patch" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/apimachinery/pkg/types" 27 "k8s.io/klog/v2" 28 29 "github.com/kubewharf/katalyst-api/pkg/apis/node/v1alpha1" 30 clientset "github.com/kubewharf/katalyst-api/pkg/client/clientset/versioned" 31 ) 32 33 // CNRControl is used to update CNR 34 type CNRControl interface { 35 // CreateCNR creates CNR from APIServer 36 CreateCNR(ctx context.Context, cnr *v1alpha1.CustomNodeResource) (*v1alpha1.CustomNodeResource, error) 37 38 // DeleteCNR deletes CNR from APIServer 39 DeleteCNR(ctx context.Context, cnrName string) error 40 41 // PatchCNRSpecAndMetadata is used to update the changes for CNR Spec contents 42 PatchCNRSpecAndMetadata(ctx context.Context, cnrName string, oldCNR, newCNR *v1alpha1.CustomNodeResource) (*v1alpha1.CustomNodeResource, error) 43 44 // PatchCNRStatus is used to update the changes for CNR Status contents 45 PatchCNRStatus(ctx context.Context, cnrName string, oldCNR, newCNR *v1alpha1.CustomNodeResource) (*v1alpha1.CustomNodeResource, error) 46 } 47 48 type DummyCNRControl struct{} 49 50 func (d DummyCNRControl) CreateCNR(_ context.Context, _ *v1alpha1.CustomNodeResource) (*v1alpha1.CustomNodeResource, error) { 51 return nil, nil 52 } 53 54 func (d DummyCNRControl) DeleteCNR(_ context.Context, _ string) error { 55 return nil 56 } 57 58 func (d DummyCNRControl) PatchCNRSpecAndMetadata(_ context.Context, _ string, _, _ *v1alpha1.CustomNodeResource) (*v1alpha1.CustomNodeResource, error) { 59 return nil, nil 60 } 61 62 func (d DummyCNRControl) PatchCNRStatus(_ context.Context, _ string, _, _ *v1alpha1.CustomNodeResource) (*v1alpha1.CustomNodeResource, error) { 63 return nil, nil 64 } 65 66 var _ CNRControl = DummyCNRControl{} 67 68 type CNRControlImpl struct { 69 client clientset.Interface 70 } 71 72 func NewCNRControlImpl(client clientset.Interface) *CNRControlImpl { 73 return &CNRControlImpl{ 74 client: client, 75 } 76 } 77 78 func (c *CNRControlImpl) CreateCNR(ctx context.Context, cnr *v1alpha1.CustomNodeResource) (*v1alpha1.CustomNodeResource, error) { 79 if cnr == nil { 80 return nil, fmt.Errorf("can't create a nil cnr") 81 } 82 83 return c.client.NodeV1alpha1().CustomNodeResources().Create(ctx, cnr, metav1.CreateOptions{}) 84 } 85 86 func (c *CNRControlImpl) DeleteCNR(ctx context.Context, cnrName string) error { 87 return c.client.NodeV1alpha1().CustomNodeResources().Delete(ctx, cnrName, metav1.DeleteOptions{}) 88 } 89 90 func (c *CNRControlImpl) PatchCNRSpecAndMetadata(ctx context.Context, cnrName string, oldCNR, newCNR *v1alpha1.CustomNodeResource) (*v1alpha1.CustomNodeResource, error) { 91 patchBytes, err := preparePatchBytesForCNRSpecAndMetadata(cnrName, oldCNR, newCNR) 92 if err != nil { 93 klog.Errorf("prepare patch bytes for spec and metadata for cnr %q: %v", cnrName, err) 94 return nil, err 95 } 96 97 updatedCNR, err := c.client.NodeV1alpha1().CustomNodeResources().Patch(ctx, cnrName, types.MergePatchType, patchBytes, metav1.PatchOptions{}) 98 if err != nil { 99 klog.Errorf("failed to patch spec and metadata %q for cnr %q: %v", patchBytes, cnrName, err) 100 return nil, err 101 } 102 103 return updatedCNR, nil 104 } 105 106 func (c *CNRControlImpl) PatchCNRStatus(ctx context.Context, cnrName string, oldCNR, newCNR *v1alpha1.CustomNodeResource) (*v1alpha1.CustomNodeResource, error) { 107 patchBytes, err := preparePatchBytesForCNRStatus(cnrName, oldCNR, newCNR) 108 if err != nil { 109 klog.Errorf("prepare patch bytes for status for cnr %q: %v", cnrName, err) 110 return nil, err 111 } 112 113 updatedCNR, err := c.client.NodeV1alpha1().CustomNodeResources().Patch(ctx, cnrName, types.MergePatchType, patchBytes, metav1.PatchOptions{}, "status") 114 if err != nil { 115 klog.Errorf("failed to patch status %q for cnr %q: %v", patchBytes, cnrName, err) 116 return nil, err 117 } 118 119 return updatedCNR, nil 120 } 121 122 // preparePatchBytesForCNRStatus generate those json patch bytes for comparing new and old CNR Status 123 // while keep the Spec remains the same 124 func preparePatchBytesForCNRStatus(cnrName string, oldCNR, newCNR *v1alpha1.CustomNodeResource) ([]byte, error) { 125 if oldCNR == nil || newCNR == nil { 126 return nil, fmt.Errorf("neither old nor new object can be nil") 127 } 128 129 oldData, err := json.Marshal(oldCNR) 130 if err != nil { 131 return nil, fmt.Errorf("failed to Marshal oldData for cnr %q: %v", cnrName, err) 132 } 133 134 diffCNR := oldCNR.DeepCopy() 135 diffCNR.Status = newCNR.Status 136 newData, err := json.Marshal(diffCNR) 137 if err != nil { 138 return nil, fmt.Errorf("failed to Marshal newData for cnr %q: %v", cnrName, err) 139 } 140 141 patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) 142 if err != nil { 143 return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for cnr %q: %v", cnrName, err) 144 } 145 146 return patchBytes, nil 147 } 148 149 // preparePatchBytesForCNRStatus generate those json patch bytes for comparing new and old CNR Spec 150 // while keep the Status remains the same 151 func preparePatchBytesForCNRSpecAndMetadata(cnrName string, oldCNR, newCNR *v1alpha1.CustomNodeResource) ([]byte, error) { 152 if oldCNR == nil || newCNR == nil { 153 return nil, fmt.Errorf("neither old nor new object can be nil") 154 } 155 156 oldData, err := json.Marshal(oldCNR) 157 if err != nil { 158 return nil, fmt.Errorf("failed to Marshal oldData for cnr %q: %v", cnrName, err) 159 } 160 161 diffCNR := oldCNR.DeepCopy() 162 diffCNR.Spec = newCNR.Spec 163 diffCNR.ObjectMeta = newCNR.ObjectMeta 164 newData, err := json.Marshal(diffCNR) 165 if err != nil { 166 return nil, fmt.Errorf("failed to Marshal newData for cnr %q: %v", cnrName, err) 167 } 168 169 patchBytes, err := jsonpatch.CreateMergePatch(oldData, newData) 170 if err != nil { 171 return nil, fmt.Errorf("failed to CreateTwoWayMergePatch for cnr %q: %v", cnrName, err) 172 } 173 174 return patchBytes, nil 175 }