controller-runtime patch
// Writer knows how to create, delete, and update Kubernetes objects.
type Writer interface {
// Create saves the object obj in the Kubernetes cluster.
Create(ctx context.Context, obj runtime.Object, opts ...CreateOption) error
// Delete deletes the given obj from Kubernetes cluster.
Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOption) error
// Update updates the given obj in the Kubernetes cluster. obj must be a
// struct pointer so that obj can be updated with the content returned by the Server.
Update(ctx context.Context, obj runtime.Object, opts ...UpdateOption) error
// Patch patches the given obj in the Kubernetes cluster. obj must be a
// struct pointer so that obj can be updated with the content returned by the Server.
Patch(ctx context.Context, obj runtime.Object, patch Patch, opts ...PatchOption) error
// DeleteAllOf deletes all objects of the given type matching the given options.
DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...DeleteAllOfOption) error
}
Patch接口
主要三个参数
1. obj
2. patch
// Patch is a patch that can be applied to a Kubernetes object.
type Patch interface {
// Type is the PatchType of the patch.
Type() types.PatchType
// Data is the raw data representing the patch.
Data(obj runtime.Object) ([]byte, error)
}
3. opts
假设我们调用时候
r.Patch(ctx, desired, client.MergeFrom(obj), ao...)
client.MergeFrom 是一个实现了 上面Patch接口结构体mergeFromPatch
结构体如下
这里的一个核心函数是 CreateMergePatch
// MergeFrom creates a Patch that patches using the merge-patch strategy with the given object as base.
func MergeFrom(obj runtime.Object) Patch {
return &mergeFromPatch{from: obj}
}
type mergeFromPatch struct {
from runtime.Object
opts MergeFromOptions
}
// Type implements patch.
func (s *mergeFromPatch) Type() types.PatchType {
return types.MergePatchType
}
// Data implements Patch.
func (s *mergeFromPatch) Data(obj runtime.Object) ([]byte, error) {
originalJSON, err := json.Marshal(s.from)
if err != nil {
return nil, err
}
modifiedJSON, err := json.Marshal(obj)
if err != nil {
return nil, err
}
data, err := jsonpatch.CreateMergePatch(originalJSON, modifiedJSON)
if err != nil {
return nil, err
}
if s.opts.OptimisticLock {
dataMap := map[string]interface{}{}
if err := json.Unmarshal(data, &dataMap); err != nil {
return nil, err
}
fromMeta, ok := s.from.(metav1.Object)
if !ok {
return nil, fmt.Errorf("cannot use OptimisticLock, from object %q is not a valid metav1.Object", s.from)
}
resourceVersion := fromMeta.GetResourceVersion()
if len(resourceVersion) == 0 {
return nil, fmt.Errorf("cannot use OptimisticLock, from object %q does not have any resource version we can use", s.from)
}
u := &unstructured.Unstructured{Object: dataMap}
u.SetResourceVersion(resourceVersion)
data, err = json.Marshal(u)
if err != nil {
return nil, err
}
}
return data, nil
}
然后我们再看一下 client.Patch函数的实现
// Patch implements client.Client
func (c *typedClient) Patch(ctx context.Context, obj Object, patch Patch, opts ...PatchOption) error {
o, err := c.cache.getObjMeta(obj)
if err != nil {
return err
}
data, err := patch.Data(obj)
if err != nil {
return err
}
patchOpts := &PatchOptions{}
return o.Patch(patch.Type()).
NamespaceIfScoped(o.GetNamespace(), o.isNamespaced()).
Resource(o.resource()).
Name(o.GetName()).
VersionedParams(patchOpts.ApplyOptions(opts).AsPatchOptions(), c.paramCodec).
Body(data).
Do(ctx).
Into(obj)
}
r.Patch(ctx, desired, client.MergeFrom(current), ao...)
回看我们的调用
在client.Patch的实现中
- client.MergeFrom(obj) 返回一个 mergeFromPatch 的结构体并给其
from
赋值 - 然后在client.Patch中调用了这个结构体的
Data()
方法, 并将desired传入 - 关键的地方来了 这里核心是使用 jsonpatch.CreateMergePatch
- 把
current
作为originalJSON
- 把
desired
作为modifiedJSON
合并做merge
- 把
网友评论