mirror of
https://github.com/kubernetes/client-go.git
synced 2025-07-17 00:31:27 +00:00
Support application/apply-patch+cbor in patch requests.
Kubernetes-commit: 37ed906a33211c7d578cab2d681941ebfd2f2f23
This commit is contained in:
parent
d7104c6737
commit
cff56219d9
@ -207,7 +207,7 @@ func TestGoldenRequest(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to load fixture: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(got, want); diff != "" {
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("unexpected difference from expected bytes:\n%s", diff)
|
||||
}
|
||||
}))
|
||||
|
@ -25,12 +25,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/client-go/features"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/apply"
|
||||
"k8s.io/client-go/util/consistencydetector"
|
||||
"k8s.io/client-go/util/watchlist"
|
||||
"k8s.io/klog/v2"
|
||||
@ -340,10 +340,6 @@ func (c *dynamicResourceClient) Apply(ctx context.Context, name string, obj *uns
|
||||
if err := validateNamespaceWithOptionalName(c.namespace, name); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outBytes, err := runtime.Encode(unstructured.UnstructuredJSONScheme, obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -355,21 +351,16 @@ func (c *dynamicResourceClient) Apply(ctx context.Context, name string, obj *uns
|
||||
}
|
||||
patchOpts := opts.ToPatchOptions()
|
||||
|
||||
result := c.client.client.
|
||||
Patch(types.ApplyPatchType).
|
||||
AbsPath(append(c.makeURLSegments(name), subresources...)...).
|
||||
Body(outBytes).
|
||||
SpecificallyVersionedParams(&patchOpts, dynamicParameterCodec, versionV1).
|
||||
Do(ctx)
|
||||
if err := result.Error(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
retBytes, err := result.Raw()
|
||||
request, err := apply.NewRequest(c.client.client, obj.Object)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var out unstructured.Unstructured
|
||||
if err := runtime.DecodeInto(unstructured.UnstructuredJSONScheme, retBytes, &out); err != nil {
|
||||
if err := request.
|
||||
AbsPath(append(c.makeURLSegments(name), subresources...)...).
|
||||
SpecificallyVersionedParams(&patchOpts, dynamicParameterCodec, versionV1).
|
||||
Do(ctx).Into(&out); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
|
4
dynamic/testdata/TestGoldenRequest/apply
vendored
4
dynamic/testdata/TestGoldenRequest/apply
vendored
@ -2,8 +2,8 @@ PATCH /apis/flops/v1alpha1/namespaces/mops/flips/mips/fin?force=true HTTP/1.1
|
||||
Host: example.com
|
||||
Accept: application/json
|
||||
Accept-Encoding: gzip
|
||||
Content-Length: 29
|
||||
Content-Length: 28
|
||||
Content-Type: application/apply-patch+yaml
|
||||
User-Agent: TestGoldenRequest
|
||||
|
||||
{"metadata":{"name":"mips"}}
|
||||
{"metadata":{"name":"mips"}}
|
@ -2,8 +2,8 @@ PATCH /apis/flops/v1alpha1/namespaces/mops/flips/mips/status?force=true HTTP/1.1
|
||||
Host: example.com
|
||||
Accept: application/json
|
||||
Accept-Encoding: gzip
|
||||
Content-Length: 29
|
||||
Content-Length: 28
|
||||
Content-Type: application/apply-patch+yaml
|
||||
User-Agent: TestGoldenRequest
|
||||
|
||||
{"metadata":{"name":"mips"}}
|
||||
{"metadata":{"name":"mips"}}
|
@ -18,7 +18,6 @@ package gentype
|
||||
|
||||
import (
|
||||
"context"
|
||||
json "encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
@ -27,6 +26,7 @@ import (
|
||||
types "k8s.io/apimachinery/pkg/types"
|
||||
watch "k8s.io/apimachinery/pkg/watch"
|
||||
rest "k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/apply"
|
||||
"k8s.io/client-go/util/consistencydetector"
|
||||
"k8s.io/client-go/util/watchlist"
|
||||
"k8s.io/klog/v2"
|
||||
@ -337,20 +337,21 @@ func (a *alsoApplier[T, C]) Apply(ctx context.Context, obj C, opts metav1.ApplyO
|
||||
return *new(T), fmt.Errorf("object provided to Apply must not be nil")
|
||||
}
|
||||
patchOpts := opts.ToPatchOptions()
|
||||
data, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return *new(T), err
|
||||
}
|
||||
if obj.GetName() == nil {
|
||||
return *new(T), fmt.Errorf("obj.Name must be provided to Apply")
|
||||
}
|
||||
err = a.client.client.Patch(types.ApplyPatchType).
|
||||
|
||||
request, err := apply.NewRequest(a.client.client, obj)
|
||||
if err != nil {
|
||||
return *new(T), err
|
||||
}
|
||||
|
||||
err = request.
|
||||
UseProtobufAsDefaultIfPreferred(a.client.prefersProtobuf).
|
||||
NamespaceIfScoped(a.client.namespace, a.client.namespace != "").
|
||||
Resource(a.client.resource).
|
||||
Name(*obj.GetName()).
|
||||
VersionedParams(&patchOpts, a.client.parameterCodec).
|
||||
Body(data).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return result, err
|
||||
@ -362,24 +363,24 @@ func (a *alsoApplier[T, C]) ApplyStatus(ctx context.Context, obj C, opts metav1.
|
||||
return *new(T), fmt.Errorf("object provided to Apply must not be nil")
|
||||
}
|
||||
patchOpts := opts.ToPatchOptions()
|
||||
data, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return *new(T), err
|
||||
}
|
||||
|
||||
if obj.GetName() == nil {
|
||||
return *new(T), fmt.Errorf("obj.Name must be provided to Apply")
|
||||
}
|
||||
|
||||
request, err := apply.NewRequest(a.client.client, obj)
|
||||
if err != nil {
|
||||
return *new(T), err
|
||||
}
|
||||
|
||||
result := a.client.newObject()
|
||||
err = a.client.client.Patch(types.ApplyPatchType).
|
||||
err = request.
|
||||
UseProtobufAsDefaultIfPreferred(a.client.prefersProtobuf).
|
||||
NamespaceIfScoped(a.client.namespace, a.client.namespace != "").
|
||||
Resource(a.client.resource).
|
||||
Name(*obj.GetName()).
|
||||
SubResource("status").
|
||||
VersionedParams(&patchOpts, a.client.parameterCodec).
|
||||
Body(data).
|
||||
Do(ctx).
|
||||
Into(result)
|
||||
return result, err
|
||||
|
49
util/apply/apply.go
Normal file
49
util/apply/apply.go
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
Copyright 2024 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package apply
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
cbor "k8s.io/apimachinery/pkg/runtime/serializer/cbor/direct"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/client-go/features"
|
||||
"k8s.io/client-go/rest"
|
||||
)
|
||||
|
||||
// NewRequest builds a new server-side apply request. The provided apply configuration object will
|
||||
// be marshalled to the request's body using the default encoding, and the Content-Type header will
|
||||
// be set to application/apply-patch with the appropriate structured syntax name suffix (today,
|
||||
// either +yaml or +cbor, see
|
||||
// https://www.iana.org/assignments/media-type-structured-suffix/media-type-structured-suffix.xhtml).
|
||||
func NewRequest(client rest.Interface, applyConfiguration interface{}) (*rest.Request, error) {
|
||||
pt := types.ApplyYAMLPatchType
|
||||
marshal := json.Marshal
|
||||
|
||||
if features.TestOnlyFeatureGates.Enabled(features.TestOnlyClientAllowsCBOR) && features.TestOnlyFeatureGates.Enabled(features.TestOnlyClientPrefersCBOR) {
|
||||
pt = types.ApplyCBORPatchType
|
||||
marshal = cbor.Marshal
|
||||
}
|
||||
|
||||
body, err := marshal(applyConfiguration)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal apply configuration: %w", err)
|
||||
}
|
||||
|
||||
return client.Patch(pt).Body(body), nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user