// Create processes a Template and creates a new list of objects func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { tpl, ok := obj.(*api.Template) if !ok { return nil, errors.NewBadRequest("not a template") } if errs := templatevalidation.ValidateProcessedTemplate(tpl); len(errs) > 0 { return nil, errors.NewInvalid(api.Kind("Template"), tpl.Name, errs) } generators := map[string]generator.Generator{ "expression": generator.NewExpressionValueGenerator(rand.New(rand.NewSource(time.Now().UnixNano()))), } processor := template.NewProcessor(generators) if errs := processor.Process(tpl); len(errs) > 0 { glog.V(1).Infof(errs.ToAggregate().Error()) return nil, errors.NewInvalid(api.Kind("Template"), tpl.Name, errs) } // we know that we get back runtime.Unstructured objects from the Process call. We need to encode those // objects using the unstructured codec BEFORE the REST layers gets its shot at encoding to avoid a layered // encode being done. for i := range tpl.Objects { tpl.Objects[i] = runtime.NewEncodable(runtime.UnstructuredJSONScheme, tpl.Objects[i]) } return tpl, nil }
// AddObjectsToTemplate adds the objects to the template using the target versions to choose the conversion destination func AddObjectsToTemplate(template *Template, objects []runtime.Object, targetVersions ...unversioned.GroupVersion) error { for i := range objects { obj := objects[i] if obj == nil { return errors.New("cannot add a nil object to a template") } kind, _, err := kapi.Scheme.ObjectKind(obj) if err != nil { return err } var targetVersion *unversioned.GroupVersion for j := range targetVersions { possibleVersion := targetVersions[j] if kind.Group == possibleVersion.Group { targetVersion = &possibleVersion break } } if targetVersion == nil { return fmt.Errorf("no target version found for object[%d], kind %v in %v", i, kind, targetVersions) } wrappedObject := runtime.NewEncodable(kapi.Codecs.LegacyCodec(*targetVersion), obj) template.Objects = append(template.Objects, wrappedObject) } return nil }
// Search attemps to read template files and transform it into template objects func (r *FileSearcher) Search(precise bool, terms ...string) (app.ComponentMatches, []error) { matches := app.ComponentMatches{} var errs []error for _, term := range terms { if term == "__dockercomposefile_fail" { errs = append(errs, fmt.Errorf("unable to find the specified template file: %s", term)) continue } if !IsPossibleDockerCompose(term) { continue } if _, err := os.Stat(term); err != nil { continue } template, err := Generate(term) if err != nil { errs = append(errs, fmt.Errorf("unable to convert docker-compose.yaml: %v", err)) continue } // TODO: template processing should handle objects that are not versioned for i := range template.Objects { template.Objects[i] = runtime.NewEncodable(kapi.Codecs.LegacyCodec(), template.Objects[i]) } glog.V(4).Infof("found docker-compose: %#v", template) matches = append(matches, &app.ComponentMatch{ Value: term, Argument: fmt.Sprintf("--file=%q", template.Name), Name: template.Name, Description: fmt.Sprintf("Docker compose file %s", term), Score: 0, Template: template, }) } return matches, errs }
func TestExtensionMapping(t *testing.T) { internalGV := schema.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := schema.GroupVersion{Group: "test.group", Version: "testExternal"} scheme := runtime.NewScheme() scheme.AddKnownTypeWithName(internalGV.WithKind("ExtensionType"), &InternalExtensionType{}) scheme.AddKnownTypeWithName(internalGV.WithKind("OptionalExtensionType"), &InternalOptionalExtensionType{}) scheme.AddKnownTypeWithName(externalGV.WithKind("ExtensionType"), &ExternalExtensionType{}) scheme.AddKnownTypeWithName(externalGV.WithKind("OptionalExtensionType"), &ExternalOptionalExtensionType{}) // register external first when the object is the same in both schemes, so ObjectVersionAndKind reports the // external version. scheme.AddKnownTypeWithName(externalGV.WithKind("A"), &ExtensionA{}) scheme.AddKnownTypeWithName(externalGV.WithKind("B"), &ExtensionB{}) scheme.AddKnownTypeWithName(internalGV.WithKind("A"), &ExtensionA{}) scheme.AddKnownTypeWithName(internalGV.WithKind("B"), &ExtensionB{}) codec := serializer.NewCodecFactory(scheme).LegacyCodec(externalGV) table := []struct { obj runtime.Object expected runtime.Object encoded string }{ { &InternalExtensionType{ Extension: runtime.NewEncodable(codec, &ExtensionA{TestString: "foo"}), }, &InternalExtensionType{ Extension: &runtime.Unknown{ Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}`), ContentType: runtime.ContentTypeJSON, }, }, // apiVersion is set in the serialized object for easier consumption by clients `{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"A","testString":"foo"}} `, }, { &InternalExtensionType{Extension: runtime.NewEncodable(codec, &ExtensionB{TestString: "bar"})}, &InternalExtensionType{ Extension: &runtime.Unknown{ Raw: []byte(`{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}`), ContentType: runtime.ContentTypeJSON, }, }, // apiVersion is set in the serialized object for easier consumption by clients `{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":{"apiVersion":"test.group/testExternal","kind":"B","testString":"bar"}} `, }, { &InternalExtensionType{Extension: nil}, &InternalExtensionType{ Extension: nil, }, `{"apiVersion":"` + externalGV.String() + `","kind":"ExtensionType","extension":null} `, }, } for i, item := range table { gotEncoded, err := runtime.Encode(codec, item.obj) if err != nil { t.Errorf("unexpected error '%v' (%#v)", err, item.obj) } else if e, a := item.encoded, string(gotEncoded); e != a { t.Errorf("expected\n%#v\ngot\n%#v\n", e, a) } gotDecoded, err := runtime.Decode(codec, []byte(item.encoded)) if err != nil { t.Errorf("unexpected error '%v' (%v)", err, item.encoded) } else if e, a := item.expected, gotDecoded; !reflect.DeepEqual(e, a) { t.Errorf("%d: unexpected objects:\n%s", i, diff.ObjectGoPrintSideBySide(e, a)) } } }
func TestNestedObject(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"} embeddedTestExternalGVK := externalGV.WithKind("EmbeddedTest") s := runtime.NewScheme() s.AddKnownTypes(internalGV, &EmbeddedTest{}) s.AddKnownTypeWithName(embeddedTestExternalGVK, &EmbeddedTestExternal{}) codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) inner := &EmbeddedTest{ ID: "inner", } outer := &EmbeddedTest{ ID: "outer", Object: runtime.NewEncodable(codec, inner), } wire, err := runtime.Encode(codec, outer) if err != nil { t.Fatalf("Unexpected encode error '%v'", err) } t.Logf("Wire format is:\n%v\n", string(wire)) decoded, err := runtime.Decode(codec, wire) if err != nil { t.Fatalf("Unexpected decode error %v", err) } // for later tests outer.Object = inner if e, a := outer, decoded; reflect.DeepEqual(e, a) { t.Errorf("Expected unequal %#v %#v", e, a) } obj, err := runtime.Decode(codec, decoded.(*EmbeddedTest).Object.(*runtime.Unknown).Raw) if err != nil { t.Fatal(err) } decoded.(*EmbeddedTest).Object = obj if e, a := outer, decoded; !reflect.DeepEqual(e, a) { t.Errorf("Expected equal %#v %#v", e, a) } // test JSON decoding of the external object, which should preserve // raw bytes var externalViaJSON EmbeddedTestExternal err = json.Unmarshal(wire, &externalViaJSON) if err != nil { t.Fatalf("Unexpected decode error %v", err) } if externalViaJSON.Kind == "" || externalViaJSON.APIVersion == "" || externalViaJSON.ID != "outer" { t.Errorf("Expected objects to have type info set, got %#v", externalViaJSON) } if !reflect.DeepEqual(externalViaJSON.EmptyObject.Raw, []byte("null")) || len(externalViaJSON.Object.Raw) == 0 { t.Errorf("Expected deserialization of nested objects into bytes, got %#v", externalViaJSON) } // test JSON decoding, too, since Decode uses yaml unmarshalling. // Generic Unmarshalling of JSON cannot load the nested objects because there is // no default schema set. Consumers wishing to get direct JSON decoding must use // the external representation var decodedViaJSON EmbeddedTest err = json.Unmarshal(wire, &decodedViaJSON) if err == nil || !strings.Contains(err.Error(), "unmarshal object into Go value of type runtime.Object") { t.Fatalf("Unexpected decode error %v", err) } if a := decodedViaJSON; a.Object != nil || a.EmptyObject != nil { t.Errorf("Expected embedded objects to be nil: %#v", a) } }