func TestUnversionedTypes(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "testExternal"} otherGV := unversioned.GroupVersion{Group: "group", Version: "other"} scheme := runtime.NewScheme() scheme.AddUnversionedTypes(externalGV, &InternalSimple{}) scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &InternalSimple{}) scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &ExternalSimple{}) scheme.AddKnownTypeWithName(otherGV.WithKind("Simple"), &ExternalSimple{}) codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) if unv, ok := scheme.IsUnversioned(&InternalSimple{}); !unv || !ok { t.Fatalf("type not unversioned and in scheme: %t %t", unv, ok) } kinds, _, err := scheme.ObjectKinds(&InternalSimple{}) if err != nil { t.Fatal(err) } kind := kinds[0] if kind != externalGV.WithKind("InternalSimple") { t.Fatalf("unexpected: %#v", kind) } test := &InternalSimple{ TestString: "I'm the same", } obj := runtime.Object(test) data, err := runtime.Encode(codec, obj) if err != nil { t.Fatal(err) } obj2, gvk, err := codec.Decode(data, nil, nil) if err != nil { t.Fatal(err) } if _, ok := obj2.(*InternalSimple); !ok { t.Fatalf("Got wrong type") } if !reflect.DeepEqual(obj2, test) { t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2) } // object is serialized as an unversioned object (in the group and version it was defined in) if !reflect.DeepEqual(gvk, &unversioned.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "InternalSimple"}) { t.Errorf("unexpected gvk returned by decode: %#v", gvk) } // when serialized to a different group, the object is kept in its preferred name codec = serializer.NewCodecFactory(scheme).LegacyCodec(otherGV) data, err = runtime.Encode(codec, obj) if err != nil { t.Fatal(err) } if string(data) != `{"apiVersion":"test.group/testExternal","kind":"InternalSimple","testString":"I'm the same"}`+"\n" { t.Errorf("unexpected data: %s", data) } }
func TestEncode(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "testExternal"} scheme := runtime.NewScheme() scheme.AddKnownTypeWithName(internalGV.WithKind("Simple"), &InternalSimple{}) scheme.AddKnownTypeWithName(externalGV.WithKind("Simple"), &ExternalSimple{}) codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) test := &InternalSimple{ TestString: "I'm the same", } obj := runtime.Object(test) data, err := runtime.Encode(codec, obj) obj2, gvk, err2 := codec.Decode(data, nil, nil) if err != nil || err2 != nil { t.Fatalf("Failure: '%v' '%v'", err, err2) } if _, ok := obj2.(*InternalSimple); !ok { t.Fatalf("Got wrong type") } if !reflect.DeepEqual(obj2, test) { t.Errorf("Expected:\n %#v,\n Got:\n %#v", test, obj2) } if !reflect.DeepEqual(gvk, &unversioned.GroupVersionKind{Group: "test.group", Version: "testExternal", Kind: "Simple"}) { t.Errorf("unexpected gvk returned by decode: %#v", gvk) } }
func encodeOrDie(obj runtime.Object) []byte { data, err := runtime.Encode(internal.Codecs.LegacyCodec(api.SchemeGroupVersion), obj) if err != nil { panic(err.Error()) } return data }
func TestValidateOk(t *testing.T) { schema, err := loadSchemaForTest() if err != nil { t.Errorf("Failed to load: %v", err) } tests := []struct { obj runtime.Object typeName string }{ {obj: &api.Pod{}}, {obj: &api.Service{}}, {obj: &api.ReplicationController{}}, } seed := rand.Int63() apiObjectFuzzer := apitesting.FuzzerFor(nil, testapi.Default.InternalGroupVersion(), rand.NewSource(seed)) for i := 0; i < 5; i++ { for _, test := range tests { testObj := test.obj apiObjectFuzzer.Fuzz(testObj) data, err := runtime.Encode(testapi.Default.Codec(), testObj) if err != nil { t.Errorf("unexpected error: %v", err) } err = schema.ValidateBytes(data) if err != nil { t.Errorf("unexpected error: %v", err) } } } }
func HashObject(obj runtime.Object, codec runtime.Codec) (string, error) { data, err := runtime.Encode(codec, obj) if err != nil { return "", err } return fmt.Sprintf("%x", md5.Sum(data)), nil }
func (p *patcher) patchSimple(obj runtime.Object, modified []byte, source, namespace, name string) ([]byte, error) { // Serialize the current configuration of the object from the server. current, err := runtime.Encode(p.encoder, obj) if err != nil { return nil, cmdutil.AddSourceToErr(fmt.Sprintf("serializing current configuration from:\n%v\nfor:", obj), source, err) } // Retrieve the original configuration of the object from the annotation. original, err := kubectl.GetOriginalConfiguration(p.mapping, obj) if err != nil { return nil, cmdutil.AddSourceToErr(fmt.Sprintf("retrieving original configuration from:\n%v\nfor:", obj), source, err) } // Create the versioned struct from the original from the server for // strategic patch. // TODO: Move all structs in apply to use raw data. Can be done once // builder has a RawResult method which delivers raw data instead of // internal objects. versionedObject, _, err := p.decoder.Decode(current, nil, nil) if err != nil { return nil, cmdutil.AddSourceToErr(fmt.Sprintf("converting encoded server-side object back to versioned struct:\n%v\nfor:", obj), source, err) } // Compute a three way strategic merge patch to send to server. patch, err := strategicpatch.CreateThreeWayMergePatch(original, modified, current, versionedObject, true) if err != nil { format := "creating patch with:\noriginal:\n%s\nmodified:\n%s\ncurrent:\n%s\nfor:" return nil, cmdutil.AddSourceToErr(fmt.Sprintf(format, original, modified, current), source, err) } _, err = p.helper.Patch(namespace, name, api.StrategicMergePatchType, patch) return patch, err }
func TestExperimentalEncodeDecodeStatus(t *testing.T) { // TODO: caesarxuchao: use the testapi.Extensions.Codec() once the PR that // moves experimental from v1 to v1beta1 got merged. expCodec := api.Codecs.LegacyCodec(extensions.SchemeGroupVersion) encoded, err := runtime.Encode(expCodec, status) if err != nil { t.Errorf("unexpected error: %v", err) } typeMeta := unversioned.TypeMeta{} if err := json.Unmarshal(encoded, &typeMeta); err != nil { t.Errorf("unexpected error: %v", err) } if typeMeta.Kind != "Status" { t.Errorf("Kind is not set to \"Status\". Got %s", encoded) } if typeMeta.APIVersion != "v1" { t.Errorf("APIVersion is not set to \"\". Got %s", encoded) } decoded, err := runtime.Decode(expCodec, encoded) if err != nil { t.Errorf("unexpected error: %v", err) } if !reflect.DeepEqual(status, decoded) { t.Errorf("expected: %v, got: %v", status, decoded) } }
func TestUnversionedTypes(t *testing.T) { testcases := []runtime.Object{ &unversioned.Status{Status: "Failure", Message: "something went wrong"}, &unversioned.APIVersions{Versions: []string{"A", "B", "C"}}, &unversioned.APIGroupList{Groups: []unversioned.APIGroup{{Name: "mygroup"}}}, &unversioned.APIGroup{Name: "mygroup"}, &unversioned.APIResourceList{GroupVersion: "mygroup/myversion"}, } for _, obj := range testcases { // Make sure the unversioned codec can encode unversionedJSON, err := runtime.Encode(testapi.Default.Codec(), obj) if err != nil { t.Errorf("%v: unexpected error: %v", obj, err) continue } // Make sure the versioned codec under test can decode versionDecodedObject, err := runtime.Decode(testapi.Default.Codec(), unversionedJSON) if err != nil { t.Errorf("%v: unexpected error: %v", obj, err) continue } // Make sure it decodes correctly if !reflect.DeepEqual(obj, versionDecodedObject) { t.Errorf("%v: expected %#v, got %#v", obj, obj, versionDecodedObject) continue } } }
func TestEncode_Ptr(t *testing.T) { grace := int64(30) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Labels: map[string]string{"name": "foo"}, }, Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, TerminationGracePeriodSeconds: &grace, SecurityContext: &api.PodSecurityContext{}, }, } obj := runtime.Object(pod) data, err := runtime.Encode(testapi.Default.Codec(), obj) obj2, err2 := runtime.Decode(testapi.Default.Codec(), data) if err != nil || err2 != nil { t.Fatalf("Failure: '%v' '%v'", err, err2) } if _, ok := obj2.(*api.Pod); !ok { t.Fatalf("Got wrong type") } if !api.Semantic.DeepEqual(obj2, pod) { t.Errorf("\nExpected:\n\n %#v,\n\nGot:\n\n %#vDiff: %v\n\n", pod, obj2, diff.ObjectDiff(obj2, pod)) } }
// Create implements storage.Interface.Create. func (s *store) Create(ctx context.Context, key string, obj, out runtime.Object, ttl uint64) error { if version, err := s.versioner.ObjectResourceVersion(obj); err == nil && version != 0 { return errors.New("resourceVersion should not be set on objects to be created") } data, err := runtime.Encode(s.codec, obj) if err != nil { return err } key = keyWithPrefix(s.pathPrefix, key) opts, err := s.ttlOpts(ctx, int64(ttl)) if err != nil { return err } txnResp, err := s.client.KV.Txn(ctx).If( notFound(key), ).Then( clientv3.OpPut(key, string(data), opts...), ).Commit() if err != nil { return err } if !txnResp.Succeeded { return storage.NewKeyExistsError(key, 0) } if out != nil { putResp := txnResp.Responses[0].GetResponsePut() return decode(s.codec, s.versioner, data, out, putResp.Header.Revision) } return nil }
func TestV1EncodeDecodeStatus(t *testing.T) { v1Codec := testapi.Default.Codec() encoded, err := runtime.Encode(v1Codec, status) if err != nil { t.Errorf("unexpected error: %v", err) } typeMeta := unversioned.TypeMeta{} if err := json.Unmarshal(encoded, &typeMeta); err != nil { t.Errorf("unexpected error: %v", err) } if typeMeta.Kind != "Status" { t.Errorf("Kind is not set to \"Status\". Got %v", string(encoded)) } if typeMeta.APIVersion != "v1" { t.Errorf("APIVersion is not set to \"v1\". Got %v", string(encoded)) } decoded, err := runtime.Decode(v1Codec, encoded) if err != nil { t.Errorf("unexpected error: %v", err) } if !reflect.DeepEqual(status, decoded) { t.Errorf("expected: %v, got: %v", status, decoded) } }
// GuaranteedUpdate implements storage.Interface.GuaranteedUpdate. func (s *store) GuaranteedUpdate(ctx context.Context, key string, out runtime.Object, ignoreNotFound bool, precondtions *storage.Preconditions, tryUpdate storage.UpdateFunc) error { v, err := conversion.EnforcePtr(out) if err != nil { panic("unable to convert output object to pointer") } key = keyWithPrefix(s.pathPrefix, key) getResp, err := s.client.KV.Get(ctx, key) if err != nil { return err } for { origState, err := s.getState(getResp, key, v, ignoreNotFound) if err != nil { return err } if err := checkPreconditions(key, precondtions, origState.obj); err != nil { return err } ret, ttl, err := s.updateState(origState, tryUpdate) if err != nil { return err } data, err := runtime.Encode(s.codec, ret) if err != nil { return err } if bytes.Equal(data, origState.data) { return decode(s.codec, s.versioner, origState.data, out, origState.rev) } opts, err := s.ttlOpts(ctx, int64(ttl)) if err != nil { return err } txnResp, err := s.client.KV.Txn(ctx).If( clientv3.Compare(clientv3.ModRevision(key), "=", origState.rev), ).Then( clientv3.OpPut(key, string(data), opts...), ).Else( clientv3.OpGet(key), ).Commit() if err != nil { return err } if !txnResp.Succeeded { getResp = (*clientv3.GetResponse)(txnResp.Responses[0].GetResponseRange()) glog.V(4).Infof("GuaranteedUpdate of %s failed because of a conflict, going to retry", key) continue } putResp := txnResp.Responses[0].GetResponsePut() return decode(s.codec, s.versioner, data, out, putResp.Header.Revision) } }
// SavePodToFile will encode and save a pod to a given path & permissions func SavePodToFile(pod *api.Pod, filePath string, perm os.FileMode) error { if filePath == "" { return fmt.Errorf("file path not specified") } codec := api.Codecs.LegacyCodec(registered.GroupOrDie(api.GroupName).GroupVersion) data, err := runtime.Encode(codec, pod) if err != nil { return fmt.Errorf("failed encoding pod: %v", err) } return ioutil.WriteFile(filePath, data, perm) }
// Object converts a watch.Event into an appropriately serializable JSON object func Object(encoder runtime.Encoder, event *watch.Event) (interface{}, error) { obj, ok := event.Object.(runtime.Object) if !ok { return nil, fmt.Errorf("the event object cannot be safely converted to JSON: %v", reflect.TypeOf(event.Object).Name()) } data, err := runtime.Encode(encoder, obj) if err != nil { return nil, err } return &WatchEvent{event.Type, runtime.RawExtension{Raw: json.RawMessage(data)}}, nil }
// BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes // reflection (to clear APIVersion and Kind) func BenchmarkEncodeCodec(b *testing.B) { items := benchmarkItems() width := len(items) b.ResetTimer() for i := 0; i < b.N; i++ { if _, err := runtime.Encode(testapi.Default.Codec(), &items[i%width]); err != nil { b.Fatal(err) } } b.StopTimer() }
// roundTripOrDie round trips an object to get defaults set. func roundTripOrDie(codec runtime.Codec, object runtime.Object) runtime.Object { data, err := runtime.Encode(codec, object) if err != nil { panic(err) } obj, err := runtime.Decode(codec, data) if err != nil { panic(err) } return obj }
// BenchmarkEncodeCodec measures the cost of performing a codec encode, which includes // reflection (to clear APIVersion and Kind) func BenchmarkEncodeCodecProtobuf(b *testing.B) { items := benchmarkItems() width := len(items) s := protobuf.NewSerializer(nil, nil, "application/arbitrary.content.type") b.ResetTimer() for i := 0; i < b.N; i++ { if _, err := runtime.Encode(s, &items[i%width]); err != nil { b.Fatal(err) } } b.StopTimer() }
func Example_mergingSomeWithConflict() { commandLineFile, _ := ioutil.TempFile("", "") defer os.Remove(commandLineFile.Name()) envVarFile, _ := ioutil.TempFile("", "") defer os.Remove(envVarFile.Name()) WriteToFile(testConfigAlfa, commandLineFile.Name()) WriteToFile(testConfigConflictAlfa, envVarFile.Name()) loadingRules := ClientConfigLoadingRules{ Precedence: []string{commandLineFile.Name(), envVarFile.Name()}, } mergedConfig, err := loadingRules.Load() json, err := runtime.Encode(clientcmdlatest.Codec, mergedConfig) if err != nil { fmt.Printf("Unexpected error: %v", err) } output, err := yaml.JSONToYAML(json) if err != nil { fmt.Printf("Unexpected error: %v", err) } fmt.Printf("%v", string(output)) // Output: // apiVersion: v1 // clusters: // - cluster: // server: http://cow.org:8080 // name: cow-cluster // - cluster: // insecure-skip-tls-verify: true // server: http://donkey.org:8080 // name: donkey-cluster // contexts: // - context: // cluster: cow-cluster // namespace: hammer-ns // user: red-user // name: federal-context // current-context: federal-context // kind: Config // preferences: {} // users: // - name: red-user // user: // token: red-token // - name: yellow-user // user: // token: yellow-token }
func refJson(t *testing.T, o runtime.Object) string { ref, err := api.GetReference(o) if err != nil { t.Fatalf("unexpected error: %v", err) } _, _, codec := NewAPIFactory() json, err := runtime.Encode(codec, &api.SerializedReference{Reference: *ref}) if err != nil { t.Fatalf("unexpected error: %v", err) } return string(json) }
// errorJSONFatal renders an error to the response, and if codec fails will render plaintext. // Returns the HTTP status code of the error. func errorJSONFatal(err error, codec runtime.Encoder, w http.ResponseWriter) int { utilruntime.HandleError(fmt.Errorf("apiserver was unable to write a JSON response: %v", err)) status := errToAPIStatus(err) code := int(status.Code) output, err := runtime.Encode(codec, status) if err != nil { w.WriteHeader(code) fmt.Fprintf(w, "%s: %s", status.Reason, status.Message) return code } w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) w.Write(output) return code }
func TestCodec(t *testing.T) { daemonSet := extensions.DaemonSet{} // We do want to use package registered rather than testapi here, because we // want to test if the package install and package registered work as expected. data, err := runtime.Encode(api.Codecs.LegacyCodec(registered.GroupOrDie(extensions.GroupName).GroupVersion), &daemonSet) if err != nil { t.Fatalf("unexpected error: %v", err) } other := extensions.DaemonSet{} if err := json.Unmarshal(data, &other); err != nil { t.Fatalf("unexpected error: %v", err) } if other.APIVersion != registered.GroupOrDie(extensions.GroupName).GroupVersion.String() || other.Kind != "DaemonSet" { t.Errorf("unexpected unmarshalled object %#v", other) } }
// BenchmarkEncodeCodecFromInternal measures the cost of performing a codec encode, // including conversions. func BenchmarkEncodeCodecFromInternal(b *testing.B) { items := benchmarkItems() width := len(items) encodable := make([]api.Pod, width) for i := range items { if err := api.Scheme.Convert(&items[i], &encodable[i]); err != nil { b.Fatal(err) } } b.ResetTimer() for i := 0; i < b.N; i++ { if _, err := runtime.Encode(testapi.Default.Codec(), &encodable[i%width]); err != nil { b.Fatal(err) } } b.StopTimer() }
// BenchmarkEncodeCodecFromInternalProtobuf measures the cost of performing a codec encode, // including conversions and any type setting. This is a "full" encode. func BenchmarkEncodeCodecFromInternalProtobuf(b *testing.B) { items := benchmarkItems() width := len(items) encodable := make([]api.Pod, width) for i := range items { if err := api.Scheme.Convert(&items[i], &encodable[i]); err != nil { b.Fatal(err) } } s := protobuf.NewSerializer(nil, nil, "application/arbitrary.content.type") codec := api.Codecs.EncoderForVersion(s, v1.SchemeGroupVersion) b.ResetTimer() for i := 0; i < b.N; i++ { if _, err := runtime.Encode(codec, &encodable[i%width]); err != nil { b.Fatal(err) } } b.StopTimer() }
func roundTrip(t *testing.T, codec runtime.Codec, item runtime.Object) { printer := spew.ConfigState{DisableMethods: true} original := item copied, err := api.Scheme.DeepCopy(item) if err != nil { panic(fmt.Sprintf("unable to copy: %v", err)) } item = copied.(runtime.Object) name := reflect.TypeOf(item).Elem().Name() data, err := runtime.Encode(codec, item) if err != nil { t.Errorf("%v: %v (%s)", name, err, printer.Sprintf("%#v", item)) return } if !api.Semantic.DeepEqual(original, item) { t.Errorf("0: %v: encode altered the object, diff: %v", name, diff.ObjectReflectDiff(original, item)) return } obj2, err := runtime.Decode(codec, data) if err != nil { t.Errorf("0: %v: %v\nCodec: %#v\nData: %s\nSource: %#v", name, err, codec, dataAsString(data), printer.Sprintf("%#v", item)) panic("failed") } if !api.Semantic.DeepEqual(original, obj2) { t.Errorf("\n1: %v: diff: %v\nCodec: %#v\nSource:\n\n%#v\n\nEncoded:\n\n%s\n\nFinal:\n\n%#v", name, diff.ObjectReflectDiff(item, obj2), codec, printer.Sprintf("%#v", item), dataAsString(data), printer.Sprintf("%#v", obj2)) return } obj3 := reflect.New(reflect.TypeOf(item).Elem()).Interface().(runtime.Object) if err := runtime.DecodeInto(codec, data, obj3); err != nil { t.Errorf("2: %v: %v", name, err) return } if !api.Semantic.DeepEqual(item, obj3) { t.Errorf("3: %v: diff: %v\nCodec: %#v", name, diff.ObjectReflectDiff(item, obj3), codec) return } }
func BenchmarkDecodeCodec(b *testing.B) { codec := testapi.Default.Codec() items := benchmarkItems() width := len(items) encoded := make([][]byte, width) for i := range items { data, err := runtime.Encode(codec, &items[i]) if err != nil { b.Fatal(err) } encoded[i] = data } b.ResetTimer() for i := 0; i < b.N; i++ { if _, err := runtime.Decode(codec, encoded[i%width]); err != nil { b.Fatal(err) } } b.StopTimer() }
// BenchmarkDecodeJSON provides a baseline for regular JSON decode performance func BenchmarkDecodeIntoJSON(b *testing.B) { codec := testapi.Default.Codec() items := benchmarkItems() width := len(items) encoded := make([][]byte, width) for i := range items { data, err := runtime.Encode(codec, &items[i]) if err != nil { b.Fatal(err) } encoded[i] = data } b.ResetTimer() for i := 0; i < b.N; i++ { obj := v1.Pod{} if err := json.Unmarshal(encoded[i%width], &obj); err != nil { b.Fatal(err) } } b.StopTimer() }
// BenchmarkDecodeJSON provides a baseline for codecgen JSON decode performance func BenchmarkDecodeIntoJSONCodecGen(b *testing.B) { kcodec := testapi.Default.Codec() items := benchmarkItems() width := len(items) encoded := make([][]byte, width) for i := range items { data, err := runtime.Encode(kcodec, &items[i]) if err != nil { b.Fatal(err) } encoded[i] = data } handler := &codec.JsonHandle{} b.ResetTimer() for i := 0; i < b.N; i++ { obj := v1.Pod{} if err := codec.NewDecoderBytes(encoded[i%width], handler).Decode(&obj); err != nil { b.Fatal(err) } } b.StopTimer() }
func testEncodeDecodeStatus(t *testing.T, codec runtime.Codec) { encoded, err := runtime.Encode(codec, status) if err != nil { t.Errorf("unexpected error: %v", err) } typeMeta := unversioned.TypeMeta{} if err := json.Unmarshal(encoded, &typeMeta); err != nil { t.Errorf("unexpected error: %v", err) } if typeMeta.Kind != "Status" { t.Errorf("Kind is not set to \"Status\". Got %s", encoded) } if typeMeta.APIVersion != "v1" { t.Errorf("APIVersion is not set to \"\". Got %s", encoded) } decoded, err := runtime.Decode(codec, encoded) if err != nil { t.Errorf("unexpected error: %v", err) } if !reflect.DeepEqual(status, decoded) { t.Errorf("expected: %v, got: %v", status, decoded) } }
// BenchmarkDecodeCodecToInternalProtobuf measures the cost of performing a codec decode, // including conversions and any type setting. This is a "full" decode. func BenchmarkDecodeCodecToInternalProtobuf(b *testing.B) { items := benchmarkItems() width := len(items) s := protobuf.NewSerializer(api.Scheme, api.Scheme, "application/arbitrary.content.type") encoder := api.Codecs.EncoderForVersion(s, v1.SchemeGroupVersion) var encoded [][]byte for i := range items { data, err := runtime.Encode(encoder, &items[i]) if err != nil { b.Fatal(err) } encoded = append(encoded, data) } decoder := api.Codecs.DecoderToVersion(s, api.SchemeGroupVersion) b.ResetTimer() for i := 0; i < b.N; i++ { if _, err := runtime.Decode(decoder, encoded[i%width]); err != nil { b.Fatal(err) } } b.StopTimer() }
func getPodsAnnotationSet(template *api.PodTemplateSpec, object runtime.Object) (labels.Set, error) { desiredAnnotations := make(labels.Set) for k, v := range template.Annotations { desiredAnnotations[k] = v } createdByRef, err := api.GetReference(object) if err != nil { return desiredAnnotations, fmt.Errorf("unable to get controller reference: %v", err) } // TODO: this code was not safe previously - as soon as new code came along that switched to v2, old clients // would be broken upon reading it. This is explicitly hardcoded to v1 to guarantee predictable deployment. // We need to consistently handle this case of annotation versioning. codec := api.Codecs.LegacyCodec(unversioned.GroupVersion{Group: api.GroupName, Version: "v1"}) createdByRefJson, err := runtime.Encode(codec, &api.SerializedReference{ Reference: *createdByRef, }) if err != nil { return desiredAnnotations, fmt.Errorf("unable to serialize controller reference: %v", err) } desiredAnnotations[CreatedByAnnotation] = string(createdByRefJson) return desiredAnnotations, nil }