func TestGetMultipleTypeObjectsAsList(t *testing.T) { pods, svc, _ := testData() f, tf, codec, _ := cmdtesting.NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &fake.RESTClient{ NegotiatedSerializer: unstructuredSerializer, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { case "/namespaces/test/pods": return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, pods)}, nil case "/namespaces/test/services": return &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, svc)}, nil default: t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) return nil, nil } }), } tf.Namespace = "test" tf.ClientConfig = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: ®istered.GroupOrDie(api.GroupName).GroupVersion}} buf := bytes.NewBuffer([]byte{}) errBuf := bytes.NewBuffer([]byte{}) cmd := NewCmdGet(f, buf, errBuf) cmd.SetOutput(buf) cmd.Flags().Set("output", "json") cmd.Run(cmd, []string{"pods,services"}) if tf.Printer.(*testPrinter).Objects != nil { t.Errorf("unexpected print to default printer") } out, err := runtime.Decode(codec, buf.Bytes()) if err != nil { t.Fatalf("unexpected error: %v", err) } list, err := meta.ExtractList(out) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list, codec); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } if err := meta.SetList(out, list); err != nil { t.Fatalf("unexpected error: %v", err) } expected := &api.List{ Items: []runtime.Object{ &pods.Items[0], &pods.Items[1], &svc.Items[0], }, } if !reflect.DeepEqual(expected, out) { t.Errorf("unexpected output: %#v", out) } }
func (o objects) Add(obj runtime.Object) error { gvk, err := o.scheme.ObjectKind(obj) if err != nil { return err } kind := gvk.Kind switch { case meta.IsListType(obj): if kind != "List" { o.types[kind] = append(o.types[kind], obj) } list, err := meta.ExtractList(obj) if err != nil { return err } if errs := runtime.DecodeList(list, o.decoder); len(errs) > 0 { return errs[0] } for _, obj := range list { if err := o.Add(obj); err != nil { return err } } default: if status, ok := obj.(*unversioned.Status); ok && status.Details != nil { kind = status.Details.Kind } o.types[kind] = append(o.types[kind], obj) } return nil }
// TransformTemplate processes a template with the provided parameters, returning an error if transformation fails. func TransformTemplate(tpl *templateapi.Template, client client.TemplateConfigsNamespacer, namespace string, parameters map[string]string) (*templateapi.Template, error) { // only set values that match what's expected by the template. for k, value := range parameters { v := template.GetParameterByName(tpl, k) if v == nil { return nil, fmt.Errorf("unexpected parameter name %q", k) } v.Value = value v.Generate = "" template.AddParameter(tpl, *v) } name := localOrRemoteName(tpl.ObjectMeta, namespace) // transform the template result, err := client.TemplateConfigs(namespace).Create(tpl) if err != nil { return nil, fmt.Errorf("error processing template %s: %v", name, err) } // ensure the template objects are decoded // TODO: in the future, this should be more automatic if errs := runtime.DecodeList(result.Objects, kapi.Codecs.UniversalDecoder()); len(errs) > 0 { err = errors.NewAggregate(errs) return nil, fmt.Errorf("error processing template %s: %v", name, err) } return result, nil }
func (v FlattenListVisitor) Visit(fn VisitorFunc) error { return v.Visitor.Visit(func(info *Info) error { if info.Object == nil { return fn(info) } items, err := runtime.ExtractList(info.Object) if err != nil { return fn(info) } if errs := runtime.DecodeList(items, struct { runtime.ObjectTyper runtime.Decoder }{v.Mapper, info.Mapping.Codec}); len(errs) > 0 { return errors.NewAggregate(errs) } for i := range items { item, err := v.InfoForObject(items[i]) if err != nil { return err } if len(info.ResourceVersion) != 0 { item.ResourceVersion = info.ResourceVersion } if err := fn(item); err != nil { return err } } return nil }) }
func TestDecodeUnstructured(t *testing.T) { groupVersionString := testapi.Default.GroupVersion().String() rawJson := fmt.Sprintf(`{"kind":"Pod","apiVersion":"%s","metadata":{"name":"test"}}`, groupVersionString) pl := &api.List{ Items: []runtime.Object{ &api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}}, &runtime.Unknown{ TypeMeta: runtime.TypeMeta{Kind: "Pod", APIVersion: groupVersionString}, Raw: []byte(rawJson), ContentType: runtime.ContentTypeJSON, }, &runtime.Unknown{ TypeMeta: runtime.TypeMeta{Kind: "", APIVersion: groupVersionString}, Raw: []byte(rawJson), ContentType: runtime.ContentTypeJSON, }, &runtime.Unstructured{ Object: map[string]interface{}{ "kind": "Foo", "apiVersion": "Bar", "test": "value", }, }, }, } if errs := runtime.DecodeList(pl.Items, runtime.UnstructuredJSONScheme); len(errs) == 1 { t.Fatalf("unexpected error %v", errs) } if pod, ok := pl.Items[1].(*runtime.Unstructured); !ok || pod.Object["kind"] != "Pod" || pod.Object["metadata"].(map[string]interface{})["name"] != "test" { t.Errorf("object not converted: %#v", pl.Items[1]) } if pod, ok := pl.Items[2].(*runtime.Unstructured); !ok || pod.Object["kind"] != "Pod" || pod.Object["metadata"].(map[string]interface{})["name"] != "test" { t.Errorf("object not converted: %#v", pl.Items[2]) } }
// buildTemplates converts a set of resolved, valid references into references to template objects. func (c *AppConfig) buildTemplates(components app.ComponentReferences, environment app.Environment) ([]runtime.Object, error) { objects := []runtime.Object{} for _, ref := range components { tpl := ref.Input().ResolvedMatch.Template glog.V(4).Infof("processing template %s/%s", c.originNamespace, tpl.Name) for _, env := range environment.List() { // only set environment values that match what's expected by the template. if v := template.GetParameterByName(tpl, env.Name); v != nil { v.Value = env.Value v.Generate = "" template.AddParameter(tpl, *v) } else { return nil, fmt.Errorf("unexpected parameter name %q", env.Name) } } result, err := c.osclient.TemplateConfigs(c.originNamespace).Create(tpl) if err != nil { return nil, fmt.Errorf("error processing template %s/%s: %v", c.originNamespace, tpl.Name, err) } errs := runtime.DecodeList(result.Objects, kapi.Scheme) if len(errs) > 0 { err = errors.NewAggregate(errs) return nil, fmt.Errorf("error processing template %s/%s: %v", c.originNamespace, tpl.Name, errs) } objects = append(objects, result.Objects...) } return objects, nil }
func TestDecodeList(t *testing.T) { pl := &api.List{ Items: []runtime.Object{ &api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}}, &runtime.Unknown{ TypeMeta: runtime.TypeMeta{Kind: "Pod", APIVersion: registered.GroupOrDie(api.GroupName).GroupVersion.String()}, Raw: []byte(`{"kind":"Pod","apiVersion":"` + registered.GroupOrDie(api.GroupName).GroupVersion.String() + `","metadata":{"name":"test"}}`), ContentType: runtime.ContentTypeJSON, }, &runtime.Unstructured{ Object: map[string]interface{}{ "kind": "Foo", "apiVersion": "Bar", "test": "value", }, }, }, } if errs := runtime.DecodeList(pl.Items, testapi.Default.Codec()); len(errs) != 0 { t.Fatalf("unexpected error %v", errs) } if pod, ok := pl.Items[1].(*api.Pod); !ok || pod.Name != "test" { t.Errorf("object not converted: %#v", pl.Items[1]) } }
// ReadObjectsFromPath reads objects from the specified file for testing. func ReadObjectsFromPath(path, namespace string, decoder runtime.Decoder, typer runtime.ObjectTyper) ([]runtime.Object, error) { data, err := ioutil.ReadFile(path) if err != nil { return nil, err } data, err = yaml.ToJSON(data) if err != nil { return nil, err } obj, err := runtime.Decode(decoder, data) if err != nil { return nil, err } if !meta.IsListType(obj) { if err := setNamespace(typer, obj, namespace); err != nil { return nil, err } return []runtime.Object{obj}, nil } list, err := meta.ExtractList(obj) if err != nil { return nil, err } errs := runtime.DecodeList(list, decoder) if len(errs) > 0 { return nil, errs[0] } for _, o := range list { if err := setNamespace(typer, o, namespace); err != nil { return nil, err } } return list, nil }
func TestGetMultipleTypeObjectsAsList(t *testing.T) { pods, svc, _ := testData() f, tf, codec := NewAPIFactory() tf.Printer = &testPrinter{} tf.Client = &client.FakeRESTClient{ Codec: codec, Client: client.HTTPClientFunc(func(req *http.Request) (*http.Response, error) { switch req.URL.Path { case "/namespaces/test/pods": return &http.Response{StatusCode: 200, Body: objBody(codec, pods)}, nil case "/namespaces/test/services": return &http.Response{StatusCode: 200, Body: objBody(codec, svc)}, nil default: t.Fatalf("unexpected request: %#v\n%#v", req.URL, req) return nil, nil } }), } tf.Namespace = "test" tf.ClientConfig = &client.Config{Version: testapi.Version()} buf := bytes.NewBuffer([]byte{}) cmd := NewCmdGet(f, buf) cmd.SetOutput(buf) cmd.Flags().Set("output", "json") cmd.Run(cmd, []string{"pods,services"}) if tf.Printer.(*testPrinter).Objects != nil { t.Errorf("unexpected print to default printer") } out, err := codec.Decode(buf.Bytes()) if err != nil { t.Fatalf("unexpected error: %v", err) } list, err := runtime.ExtractList(out) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list, api.Scheme); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } if err := runtime.SetList(out, list); err != nil { t.Fatalf("unexpected error: %v", err) } expected := &api.List{ Items: []runtime.Object{ &pods.Items[0], &pods.Items[1], &svc.Items[0], }, } if !reflect.DeepEqual(expected, out) { t.Errorf("unexpected output: %#v", out) } }
func NewCmdSecrets(f *cmdutil.Factory) *cobra.Command { cmd := &cobra.Command{ Use: "secrets", Short: "Set up Secrets on your Kubernetes or OpenShift environment", Long: `set up Secrets on your Kubernetes or OpenShift environment`, PreRun: func(cmd *cobra.Command, args []string) { showBanner() }, Run: func(cmd *cobra.Command, args []string) { c, cfg := client.NewClient(f) ns, _, _ := f.DefaultNamespace() util.Info("Setting up secrets on your ") util.Success(string(util.TypeOfMaster(c))) util.Info(" installation at ") util.Success(cfg.Host) util.Info(" in namespace ") util.Successf("%s\n\n", ns) if confirmAction(cmd.Flags()) { typeOfMaster := util.TypeOfMaster(c) if typeOfMaster == util.Kubernetes { util.Fatal("Support for Kubernetes not yet available...\n") } else { oc, _ := client.NewOpenShiftClient(cfg) t := getTemplates(oc, ns) count := 0 // get all the Templates and find the annotations on any Pods for _, i := range t.Items { // convert TemplateList.Objects to Kubernetes resources _ = runtime.DecodeList(i.Objects, api.Scheme, runtime.UnstructuredJSONScheme) for _, rc := range i.Objects { switch rc := rc.(type) { case *api.ReplicationController: for secretType, secretDataIdentifiers := range rc.Spec.Template.Annotations { count += createAndPrintSecrets(secretDataIdentifiers, secretType, c, f, cmd.Flags()) } } } } if count == 0 { util.Info("No secrets created as no fabric8 secrets annotations found in the templates\n") util.Info("For more details see: https://github.com/fabric8io/fabric8/blob/master/docs/secretAnnotations.md\n") } } } }, } cmd.PersistentFlags().BoolP("print-import-folder-structure", "", true, "Prints the folder structures that are being used by the template annotations to import secrets") cmd.PersistentFlags().BoolP("write-generated-keys", "", false, "Write generated secrets to the local filesystem") cmd.PersistentFlags().BoolP("generate-secrets-data", "g", true, "Generate secrets data if secrets cannot be found to import from the local filesystem") return cmd }
func validateObject(path string, obj runtime.Object, t *testing.T) { // if an object requires a namespace server side, be sure that it is filled in for validation if validation.HasObjectMeta(obj) { namespaceRequired, err := validation.GetRequiresNamespace(obj) if err != nil { t.Errorf("Expected no error, Got %v", err) return } if namespaceRequired { objectMeta, err := kapi.ObjectMetaFor(obj) if err != nil { t.Errorf("Expected no error, Got %v", err) return } objectMeta.Namespace = kapi.NamespaceDefault } } switch typedObj := obj.(type) { case *kapi.Pod: if errors := kvalidation.ValidatePod(typedObj); len(errors) > 0 { t.Errorf("%s did not validate correctly: %v", path, errors) } case *kapi.Service: if errors := kvalidation.ValidateService(typedObj); len(errors) > 0 { t.Errorf("%s did not validate correctly: %v", path, errors) } case *kapi.List, *imageapi.ImageStreamList: if list, err := runtime.ExtractList(typedObj); err == nil { runtime.DecodeList(list, kapi.Scheme) for i := range list { validateObject(path, list[i], t) } } else { t.Errorf("Expected no error, Got %v", err) } default: if errors := validation.Validator.Validate(obj); len(errors) > 0 { t.Errorf("%s with %v did not validate correctly: %v", path, reflect.TypeOf(obj), errors) } } }
func TestDecodeList(t *testing.T) { pl := &api.List{ Items: []runtime.Object{ &api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}}, &runtime.Unknown{TypeMeta: runtime.TypeMeta{Kind: "Pod", APIVersion: testapi.Default.Version()}, RawJSON: []byte(`{"kind":"Pod","apiVersion":"` + testapi.Default.Version() + `","metadata":{"name":"test"}}`)}, &runtime.Unstructured{TypeMeta: runtime.TypeMeta{Kind: "Foo", APIVersion: "Bar"}, Object: map[string]interface{}{"test": "value"}}, }, } if errs := runtime.DecodeList(pl.Items, api.Scheme); len(errs) != 0 { t.Fatalf("unexpected error %v", errs) } if pod, ok := pl.Items[1].(*api.Pod); !ok || pod.Name != "test" { t.Errorf("object not converted: %#v", pl.Items[1]) } }
func (t *tracker) addList(obj runtime.Object, replaceExisting bool) error { list, err := meta.ExtractList(obj) if err != nil { return err } errs := runtime.DecodeList(list, t.decoder) if len(errs) > 0 { return errs[0] } for _, obj := range list { err := t.add(obj, replaceExisting) if err != nil { return err } } return nil }
func (d *TemplateDescriber) DescribeTemplate(template *templateapi.Template) (string, error) { // TODO: write error? _ = runtime.DecodeList(template.Objects, kapi.Scheme, runtime.UnstructuredJSONScheme) return tabbedString(func(out *tabwriter.Writer) error { formatMeta(out, template.ObjectMeta) out.Write([]byte("\n")) out.Flush() d.DescribeParameters(template.Parameters, out) out.Write([]byte("\n")) formatString(out, "Object Labels", formatLabels(template.ObjectLabels)) out.Write([]byte("\n")) out.Flush() d.describeObjects(template.Objects, out) return nil }) }
func processSecretsForTemplate(c *k8sclient.Client, i tapi.Template, f *cmdutil.Factory, cmd *cobra.Command) int { count := 0 // convert TemplateList.Objects to Kubernetes resources errs := runtime.DecodeList(i.Objects, api.Codecs.UniversalDecoder()) if len(errs) > 0 { fmt.Println("Failed to decode templates %v", errs) os.Exit(2) } for _, rc := range i.Objects { switch rc := rc.(type) { case *api.ReplicationController: for secretType, secretDataIdentifiers := range rc.Spec.Template.Annotations { count += createAndPrintSecrets(secretDataIdentifiers, secretType, c, f, cmd.Flags()) } } } return count }
func TestDecodeUnstructured(t *testing.T) { version := testapi.Version() rawJson := fmt.Sprintf(`{"kind":"Pod","apiVersion":"%s","metadata":{"name":"test"}}`, version) pl := &api.List{ Items: []runtime.Object{ &api.Pod{ObjectMeta: api.ObjectMeta{Name: "1"}}, &runtime.Unknown{TypeMeta: runtime.TypeMeta{Kind: "Pod", APIVersion: version}, RawJSON: []byte(rawJson)}, &runtime.Unknown{TypeMeta: runtime.TypeMeta{Kind: "", APIVersion: version}, RawJSON: []byte(rawJson)}, &runtime.Unstructured{TypeMeta: runtime.TypeMeta{Kind: "Foo", APIVersion: "Bar"}, Object: map[string]interface{}{"test": "value"}}, }, } if errs := runtime.DecodeList(pl.Items, runtime.UnstructuredJSONScheme); len(errs) == 1 { t.Fatalf("unexpected error %v", errs) } if pod, ok := pl.Items[1].(*runtime.Unstructured); !ok || pod.Object["kind"] != "Pod" || pod.Object["metadata"].(map[string]interface{})["name"] != "test" { t.Errorf("object not converted: %#v", pl.Items[1]) } if _, ok := pl.Items[2].(*runtime.Unknown); !ok { t.Errorf("object should not have been converted: %#v", pl.Items[2]) } }
func downloadTemplateDockerImages(cmd *cobra.Command, ns string, c *oclient.Client, fac *cmdutil.Factory, name string) (Result, error) { rc, err := c.Templates(ns).Get(name) if err != nil { util.Fatalf("No Template %s found in namespace %s\n", name, ns) } // convert Template.Objects to Kubernetes resources _ = runtime.DecodeList(rc.Objects, api.Scheme, runtime.UnstructuredJSONScheme) for _, rc := range rc.Objects { switch rc := rc.(type) { case *api.ReplicationController: for _, container := range rc.Spec.Template.Spec.Containers { err = downloadDockerImage(container.Image) if err != nil { return Failure, err } } } } return Success, nil }
func (v FlattenListVisitor) Visit(fn VisitorFunc) error { return v.Visitor.Visit(func(info *Info, err error) error { if err != nil { return err } if info.Object == nil { return fn(info, nil) } items, err := meta.ExtractList(info.Object) if err != nil { return fn(info, nil) } if errs := runtime.DecodeList(items, struct { runtime.ObjectTyper runtime.Decoder }{v.Mapper, v.Mapper.Decoder}); len(errs) > 0 { return utilerrors.NewAggregate(errs) } // If we have a GroupVersionKind on the list, prioritize that when asking for info on the objects contained in the list var preferredGVKs []unversioned.GroupVersionKind if info.Mapping != nil && !info.Mapping.GroupVersionKind.Empty() { preferredGVKs = append(preferredGVKs, info.Mapping.GroupVersionKind) } for i := range items { item, err := v.InfoForObject(items[i], preferredGVKs) if err != nil { return err } if len(info.ResourceVersion) != 0 { item.ResourceVersion = info.ResourceVersion } if err := fn(item, nil); err != nil { return err } } return nil }) }
func changeObjectsVersion(items []kruntime.Object) { if errs := kruntime.DecodeList(items, api.Scheme); len(errs) > 0 { log.Fatalf("Unable to decode Template objects: %v", errs) } for i, obj := range items { _, kind, err := api.Scheme.ObjectVersionAndKind(obj) if err != nil { glog.Infof("Template.Objects[%d]: Unable to determine version and kind: %v", i, err) continue } mapping, err := latest.RESTMapper.RESTMapping(kind, *outputVersion) if err != nil { glog.Infof("Template.Objects[%d]: Unable to get REST mappings: %v", err) continue } info := resource.Info{Object: obj, Mapping: mapping} outputObj, err := resource.AsVersionedObject([]*resource.Info{&info}, false, *outputVersion) if err != nil { glog.Infof("Template.Objects[%d]: Unable to convert: %v", err) continue } items[i] = outputObj } }
// FilterResourceList receives a list of runtime objects. // If any objects are filtered, that number is returned along with a modified list. func FilterResourceList(obj runtime.Object, filterFuncs kubectl.Filters, filterOpts *kubectl.PrintOptions) (int, []runtime.Object, error) { items, err := meta.ExtractList(obj) if err != nil { return 0, []runtime.Object{obj}, utilerrors.NewAggregate([]error{err}) } if errs := runtime.DecodeList(items, api.Codecs.UniversalDecoder(), runtime.UnstructuredJSONScheme); len(errs) > 0 { return 0, []runtime.Object{obj}, utilerrors.NewAggregate(errs) } filterCount := 0 list := make([]runtime.Object, 0, len(items)) for _, obj := range items { if isFiltered, err := filterFuncs.Filter(obj, filterOpts); !isFiltered { if err != nil { glog.V(2).Infof("Unable to filter resource: %v", err) continue } list = append(list, obj) } else if isFiltered { filterCount++ } } return filterCount, list, nil }
func TestNewRESTTemplateLabels(t *testing.T) { testLabels := map[string]string{ "label1": "value1", "label2": "value2", } storage := NewREST() // because of encoding changes, we to round-trip ourselves templateToCreate := &template.Template{ ObjectMeta: kapi.ObjectMeta{ Name: "test", }, ObjectLabels: testLabels, } templateObjects := []runtime.Object{ &kapi.Service{ ObjectMeta: kapi.ObjectMeta{ Name: "test-service", }, Spec: kapi.ServiceSpec{ Ports: []kapi.ServicePort{ { Port: 80, Protocol: kapi.ProtocolTCP, }, }, SessionAffinity: kapi.ServiceAffinityNone, }, }, } template.AddObjectsToTemplate(templateToCreate, templateObjects, registered.GroupOrDie(kapi.GroupName).GroupVersions[0]) originalBytes, err := runtime.Encode(kapi.Codecs.LegacyCodec(registered.GroupOrDie(kapi.GroupName).GroupVersions[0]), templateToCreate) if err != nil { t.Fatalf("unexpected error: %v", err) } objToCreate, err := runtime.Decode(kapi.Codecs.UniversalDecoder(), originalBytes) if err != nil { t.Fatalf("unexpected error: %v", err) } templateToCreate = objToCreate.(*template.Template) obj, err := storage.Create(nil, templateToCreate) if err != nil { t.Fatalf("unexpected error: %v", err) } bytes, err := runtime.Encode(kapi.Codecs.LegacyCodec(registered.GroupOrDie(kapi.GroupName).GroupVersions[0]), obj) if err != nil { t.Fatalf("unexpected error: %v", err) } obj, err = runtime.Decode(kapi.Codecs.UniversalDecoder(), bytes) if err != nil { t.Fatalf("unexpected error: %v", err) } config := obj.(*template.Template) if err := utilerrors.NewAggregate(runtime.DecodeList(config.Objects, kapi.Codecs.UniversalDecoder())); err != nil { t.Fatalf("unexpected error: %v", err) } svc, ok := config.Objects[0].(*kapi.Service) if !ok { t.Fatalf("Unexpected object in config: %#v", config.Objects[0]) } for k, v := range testLabels { value, ok := svc.Labels[k] if !ok { t.Fatalf("Missing output label: %s", k) } if value != v { t.Fatalf("Unexpected label value: %s", value) } } }
func OverwriteBootstrapPolicy(optsGetter restoptions.Getter, policyFile, createBootstrapPolicyCommand string, change bool, out io.Writer) error { if !change { fmt.Fprintf(out, "Performing a dry run of policy overwrite:\n\n") } mapper := cmdclientcmd.ShortcutExpander{RESTMapper: kubectl.ShortcutExpander{RESTMapper: registered.RESTMapper()}} typer := kapi.Scheme clientMapper := resource.ClientMapperFunc(func(mapping *meta.RESTMapping) (resource.RESTClient, error) { return nil, nil }) r := resource.NewBuilder(mapper, typer, clientMapper, kapi.Codecs.UniversalDecoder()). FilenameParam(false, false, policyFile). Flatten(). Do() if r.Err() != nil { return r.Err() } policyStorage, err := policyetcd.NewStorage(optsGetter) if err != nil { return err } policyRegistry := policyregistry.NewRegistry(policyStorage) policyBindingStorage, err := policybindingetcd.NewStorage(optsGetter) if err != nil { return err } policyBindingRegistry := policybindingregistry.NewRegistry(policyBindingStorage) clusterPolicyStorage, err := clusterpolicyetcd.NewStorage(optsGetter) if err != nil { return err } clusterPolicyRegistry := clusterpolicyregistry.NewRegistry(clusterPolicyStorage) clusterPolicyBindingStorage, err := clusterpolicybindingetcd.NewStorage(optsGetter) if err != nil { return err } clusterPolicyBindingRegistry := clusterpolicybindingregistry.NewRegistry(clusterPolicyBindingStorage) ruleResolver := rulevalidation.NewDefaultRuleResolver( policyListerNamespacer{registry: policyRegistry}, policyBindingListerNamespacer{registry: policyBindingRegistry}, clusterpolicyregistry.ReadOnlyClusterPolicy{Registry: clusterPolicyRegistry}, clusterpolicybindingregistry.ReadOnlyClusterPolicyBinding{Registry: clusterPolicyBindingRegistry}, ) roleStorage := rolestorage.NewVirtualStorage(policyRegistry, ruleResolver, nil, authorizationapi.Resource("role")) roleBindingStorage := rolebindingstorage.NewVirtualStorage(policyBindingRegistry, ruleResolver, nil, authorizationapi.Resource("rolebinding")) clusterRoleStorage := clusterrolestorage.NewClusterRoleStorage(clusterPolicyRegistry, clusterPolicyBindingRegistry, nil) clusterRoleBindingStorage := clusterrolebindingstorage.NewClusterRoleBindingStorage(clusterPolicyRegistry, clusterPolicyBindingRegistry, nil) return r.Visit(func(info *resource.Info, err error) error { if err != nil { return err } template, ok := info.Object.(*templateapi.Template) if !ok { return errors.New("policy must be contained in a template. One can be created with '" + createBootstrapPolicyCommand + "'.") } runtime.DecodeList(template.Objects, kapi.Codecs.UniversalDecoder()) // For each object, we attempt the following to maximize our ability to persist the desired objects, while minimizing etcd write thrashing: // 1. Create the object (no-ops if the object already exists) // 2. If the object already exists, attempt to update the object (no-ops if an identical object is already persisted) // 3. If we encounter any error updating, delete and recreate errs := []error{} for _, item := range template.Objects { switch t := item.(type) { case *authorizationapi.Role: ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace) if change { // Attempt to create _, err := roleStorage.CreateRoleWithEscalation(ctx, t) // Unconditional replace if it already exists if kapierrors.IsAlreadyExists(err) { _, _, err = roleStorage.UpdateRoleWithEscalation(ctx, t) } // Delete and recreate as a last resort if err != nil { roleStorage.Delete(ctx, t.Name, nil) _, err = roleStorage.CreateRoleWithEscalation(ctx, t) } // Gather any error if err != nil { errs = append(errs, err) } } else { fmt.Fprintf(out, "Overwrite role %s/%s\n", t.Namespace, t.Name) if s, err := describe.DescribeRole(t); err == nil { fmt.Fprintf(out, "%s\n", s) } } case *authorizationapi.RoleBinding: ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace) if change { // Attempt to create _, err := roleBindingStorage.CreateRoleBindingWithEscalation(ctx, t) // Unconditional replace if it already exists if kapierrors.IsAlreadyExists(err) { _, _, err = roleBindingStorage.UpdateRoleBindingWithEscalation(ctx, t) } // Delete and recreate as a last resort if err != nil { roleBindingStorage.Delete(ctx, t.Name, nil) _, err = roleBindingStorage.CreateRoleBindingWithEscalation(ctx, t) } // Gather any error if err != nil { errs = append(errs, err) } } else { fmt.Fprintf(out, "Overwrite role binding %s/%s\n", t.Namespace, t.Name) if s, err := describe.DescribeRoleBinding(t, nil, nil); err == nil { fmt.Fprintf(out, "%s\n", s) } } case *authorizationapi.ClusterRole: ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace) if change { // Attempt to create _, err := clusterRoleStorage.CreateClusterRoleWithEscalation(ctx, t) // Unconditional replace if it already exists if kapierrors.IsAlreadyExists(err) { _, _, err = clusterRoleStorage.UpdateClusterRoleWithEscalation(ctx, t) } // Delete and recreate as a last resort if err != nil { clusterRoleStorage.Delete(ctx, t.Name, nil) _, err = clusterRoleStorage.CreateClusterRoleWithEscalation(ctx, t) } // Gather any error if err != nil { errs = append(errs, err) } } else { fmt.Fprintf(out, "Overwrite role %s/%s\n", t.Namespace, t.Name) if s, err := describe.DescribeRole(authorizationapi.ToRole(t)); err == nil { fmt.Fprintf(out, "%s\n", s) } } case *authorizationapi.ClusterRoleBinding: ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace) if change { // Attempt to create _, err := clusterRoleBindingStorage.CreateClusterRoleBindingWithEscalation(ctx, t) // Unconditional replace if it already exists if kapierrors.IsAlreadyExists(err) { _, _, err = clusterRoleBindingStorage.UpdateClusterRoleBindingWithEscalation(ctx, t) } // Delete and recreate as a last resort if err != nil { clusterRoleBindingStorage.Delete(ctx, t.Name, nil) _, err = clusterRoleBindingStorage.CreateClusterRoleBindingWithEscalation(ctx, t) } // Gather any error if err != nil { errs = append(errs, err) } } else { fmt.Fprintf(out, "Overwrite role binding %s/%s\n", t.Namespace, t.Name) if s, err := describe.DescribeRoleBinding(authorizationapi.ToRoleBinding(t), nil, nil); err == nil { fmt.Fprintf(out, "%s\n", s) } } default: errs = append(errs, fmt.Errorf("only roles and rolebindings may be created in this mode, not: %v", reflect.TypeOf(t))) } } if !change { fmt.Fprintf(out, "To make the changes described above, pass --force\n") } return kerrors.NewAggregate(errs) }) }
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { if err := rest.BeforeCreate(projectrequestregistry.Strategy, ctx, obj); err != nil { return nil, err } projectRequest := obj.(*projectapi.ProjectRequest) if _, err := r.openshiftClient.Projects().Get(projectRequest.Name); err == nil { return nil, kapierror.NewAlreadyExists("project", projectRequest.Name) } projectName := projectRequest.Name projectAdmin := "" if userInfo, exists := kapi.UserFrom(ctx); exists { projectAdmin = userInfo.GetName() } template, err := r.getTemplate() if err != nil { return nil, err } for i := range template.Parameters { switch template.Parameters[i].Name { case ProjectAdminUserParam: template.Parameters[i].Value = projectAdmin case ProjectDescriptionParam: template.Parameters[i].Value = projectRequest.Description case ProjectDisplayNameParam: template.Parameters[i].Value = projectRequest.DisplayName case ProjectNameParam: template.Parameters[i].Value = projectName } } list, err := r.openshiftClient.TemplateConfigs(kapi.NamespaceDefault).Create(template) if err != nil { return nil, err } if err := utilerrors.NewAggregate(runtime.DecodeList(list.Objects, kapi.Scheme)); err != nil { return nil, kapierror.NewInternalError(err) } // one of the items in this list should be the project. We are going to locate it, remove it from the list, create it separately var projectFromTemplate *projectapi.Project objectsToCreate := &kapi.List{} for i := range list.Objects { if templateProject, ok := list.Objects[i].(*projectapi.Project); ok { projectFromTemplate = templateProject if len(list.Objects) > (i + 1) { objectsToCreate.Items = append(objectsToCreate.Items, list.Objects[i+1:]...) } break } objectsToCreate.Items = append(objectsToCreate.Items, list.Objects[i]) } if projectFromTemplate == nil { return nil, kapierror.NewInternalError(fmt.Errorf("the project template (%s/%s) is not correctly configured: must contain a project resource", r.templateNamespace, r.templateName)) } // we split out project creation separately so that in a case of racers for the same project, only one will win and create the rest of their template objects if _, err := r.openshiftClient.Projects().Create(projectFromTemplate); err != nil { return nil, err } bulk := configcmd.Bulk{ Mapper: latest.RESTMapper, Typer: kapi.Scheme, RESTClientFactory: func(mapping *meta.RESTMapping) (resource.RESTClient, error) { if latest.OriginKind(mapping.Kind, mapping.APIVersion) { return r.openshiftClient, nil } return r.kubeClient, nil }, } if err := utilerrors.NewAggregate(bulk.Create(objectsToCreate, projectName)); err != nil { return nil, kapierror.NewInternalError(err) } return r.openshiftClient.Projects().Get(projectName) }
func TestArrayOfRuntimeObject(t *testing.T) { s := runtime.NewScheme() s.AddKnownTypes("", &EmbeddedTest{}) s.AddKnownTypeWithName("v1test", "EmbeddedTest", &EmbeddedTestExternal{}) s.AddKnownTypes("", &ObjectTest{}) s.AddKnownTypeWithName("v1test", "ObjectTest", &ObjectTestExternal{}) internal := &ObjectTest{ Items: []runtime.Object{ &EmbeddedTest{ID: "foo"}, &EmbeddedTest{ID: "bar"}, // TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization &runtime.Unknown{RawJSON: []byte(`{"apiVersion":"unknown","foo":"bar","kind":"OtherTest"}`)}, &ObjectTest{ Items: []runtime.Object{ &EmbeddedTest{ID: "baz"}, }, }, }, } wire, err := s.EncodeToVersion(internal, "v1test") if err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("Wire format is:\n%s\n", string(wire)) obj := &ObjectTestExternal{} if err := json.Unmarshal(wire, obj); err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("exact wire is: %s", string(obj.Items[0].RawJSON)) decoded, err := s.Decode(wire) if err != nil { t.Fatalf("unexpected error: %v", err) } list, err := runtime.ExtractList(decoded) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list, s); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } list2, err := runtime.ExtractList(list[3]) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list2, s); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } if err := runtime.SetList(list[3], list2); err != nil { t.Fatalf("unexpected error: %v", err) } internal.Items[2].(*runtime.Unknown).Kind = "OtherTest" internal.Items[2].(*runtime.Unknown).APIVersion = "unknown" if e, a := internal.Items, list; !reflect.DeepEqual(e, a) { t.Errorf("mismatched decoded: %s", util.ObjectDiff(e, a)) } }
func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { if err := rest.BeforeCreate(projectrequestregistry.Strategy, ctx, obj); err != nil { return nil, err } projectRequest := obj.(*projectapi.ProjectRequest) if _, err := r.openshiftClient.Projects().Get(projectRequest.Name); err == nil { return nil, kapierror.NewAlreadyExists(projectapi.Resource("project"), projectRequest.Name) } projectName := projectRequest.Name projectAdmin := "" projectRequester := "" if userInfo, exists := kapi.UserFrom(ctx); exists { projectAdmin = userInfo.GetName() projectRequester = userInfo.GetName() } template, err := r.getTemplate() if err != nil { return nil, err } for i := range template.Parameters { switch template.Parameters[i].Name { case ProjectAdminUserParam: template.Parameters[i].Value = projectAdmin case ProjectDescriptionParam: template.Parameters[i].Value = projectRequest.Description case ProjectDisplayNameParam: template.Parameters[i].Value = projectRequest.DisplayName case ProjectNameParam: template.Parameters[i].Value = projectName case ProjectRequesterParam: template.Parameters[i].Value = projectRequester } } list, err := r.openshiftClient.TemplateConfigs(kapi.NamespaceDefault).Create(template) if err != nil { return nil, err } if err := utilerrors.NewAggregate(runtime.DecodeList(list.Objects, kapi.Codecs.UniversalDecoder())); err != nil { return nil, kapierror.NewInternalError(err) } // one of the items in this list should be the project. We are going to locate it, remove it from the list, create it separately var projectFromTemplate *projectapi.Project var lastRoleBinding *authorizationapi.RoleBinding objectsToCreate := &kapi.List{} for i := range list.Objects { if templateProject, ok := list.Objects[i].(*projectapi.Project); ok { projectFromTemplate = templateProject // don't add this to the list to create. We'll create the project separately. continue } if roleBinding, ok := list.Objects[i].(*authorizationapi.RoleBinding); ok { // keep track of the rolebinding, but still add it to the list lastRoleBinding = roleBinding } objectsToCreate.Items = append(objectsToCreate.Items, list.Objects[i]) } if projectFromTemplate == nil { return nil, kapierror.NewInternalError(fmt.Errorf("the project template (%s/%s) is not correctly configured: must contain a project resource", r.templateNamespace, r.templateName)) } // we split out project creation separately so that in a case of racers for the same project, only one will win and create the rest of their template objects createdProject, err := r.openshiftClient.Projects().Create(projectFromTemplate) if err != nil { // log errors other than AlreadyExists and Forbidden if !kapierror.IsAlreadyExists(err) && !kapierror.IsForbidden(err) { utilruntime.HandleError(fmt.Errorf("error creating requested project %#v: %v", projectFromTemplate, err)) } return nil, err } // Stop on the first error, since we have to delete the whole project if any item in the template fails stopOnErr := configcmd.AfterFunc(func(_ *resource.Info, err error) bool { return err != nil }) bulk := configcmd.Bulk{ Mapper: &resource.Mapper{ RESTMapper: client.DefaultMultiRESTMapper(), ObjectTyper: kapi.Scheme, ClientMapper: resource.ClientMapperFunc(func(mapping *meta.RESTMapping) (resource.RESTClient, error) { if latest.OriginKind(mapping.GroupVersionKind) { return r.openshiftClient, nil } return r.kubeClient, nil }), }, After: stopOnErr, Op: configcmd.Create, } if err := utilerrors.NewAggregate(bulk.Run(objectsToCreate, projectName)); err != nil { utilruntime.HandleError(fmt.Errorf("error creating items in requested project %q: %v", createdProject.Name, err)) // We have to clean up the project if any part of the project request template fails if deleteErr := r.openshiftClient.Projects().Delete(createdProject.Name); deleteErr != nil { utilruntime.HandleError(fmt.Errorf("error cleaning up requested project %q: %v", createdProject.Name, deleteErr)) } return nil, kapierror.NewInternalError(err) } // wait for a rolebinding if we created one if lastRoleBinding != nil { r.waitForRoleBinding(projectName, lastRoleBinding.Name) } return r.openshiftClient.Projects().Get(projectName) }
func OverwriteBootstrapPolicy(optsGetter restoptions.Getter, policyFile, createBootstrapPolicyCommand string, change bool, out io.Writer) error { if !change { fmt.Fprintf(out, "Performing a dry run of policy overwrite:\n\n") } mapper := cmdclientcmd.ShortcutExpander{RESTMapper: kubectl.ShortcutExpander{RESTMapper: registered.RESTMapper()}} typer := kapi.Scheme clientMapper := resource.ClientMapperFunc(func(mapping *meta.RESTMapping) (resource.RESTClient, error) { return nil, nil }) r := resource.NewBuilder(mapper, typer, clientMapper, kapi.Codecs.UniversalDecoder()). FilenameParam(false, false, policyFile). Flatten(). Do() if r.Err() != nil { return r.Err() } policyStorage, err := policyetcd.NewStorage(optsGetter) if err != nil { return err } policyRegistry := policyregistry.NewRegistry(policyStorage) policyBindingStorage, err := policybindingetcd.NewStorage(optsGetter) if err != nil { return err } policyBindingRegistry := policybindingregistry.NewRegistry(policyBindingStorage) clusterPolicyStorage, err := clusterpolicyetcd.NewStorage(optsGetter) if err != nil { return err } clusterPolicyRegistry := clusterpolicyregistry.NewRegistry(clusterPolicyStorage) clusterPolicyBindingStorage, err := clusterpolicybindingetcd.NewStorage(optsGetter) if err != nil { return err } clusterPolicyBindingRegistry := clusterpolicybindingregistry.NewRegistry(clusterPolicyBindingStorage) ruleResolver := rulevalidation.NewDefaultRuleResolver( policyListerNamespacer{registry: policyRegistry}, policyBindingListerNamespacer{registry: policyBindingRegistry}, clusterpolicyregistry.ReadOnlyClusterPolicy{Registry: clusterPolicyRegistry}, clusterpolicybindingregistry.ReadOnlyClusterPolicyBinding{Registry: clusterPolicyBindingRegistry}, ) roleStorage := rolestorage.NewVirtualStorage(policyRegistry, ruleResolver) roleBindingStorage := rolebindingstorage.NewVirtualStorage(policyBindingRegistry, ruleResolver) clusterRoleStorage := clusterrolestorage.NewClusterRoleStorage(clusterPolicyRegistry, clusterPolicyBindingRegistry) clusterRoleBindingStorage := clusterrolebindingstorage.NewClusterRoleBindingStorage(clusterPolicyRegistry, clusterPolicyBindingRegistry) return r.Visit(func(info *resource.Info, err error) error { if err != nil { return err } template, ok := info.Object.(*templateapi.Template) if !ok { return errors.New("policy must be contained in a template. One can be created with '" + createBootstrapPolicyCommand + "'.") } runtime.DecodeList(template.Objects, kapi.Codecs.UniversalDecoder()) for _, item := range template.Objects { switch t := item.(type) { case *authorizationapi.Role: ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace) if change { roleStorage.Delete(ctx, t.Name, nil) if _, err := roleStorage.CreateRoleWithEscalation(ctx, t); err != nil { return err } } else { fmt.Fprintf(out, "Overwrite role %s/%s\n", t.Namespace, t.Name) if s, err := describe.DescribeRole(t); err == nil { fmt.Fprintf(out, "%s\n", s) } } case *authorizationapi.RoleBinding: ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace) if change { roleBindingStorage.Delete(ctx, t.Name, nil) if _, err := roleBindingStorage.CreateRoleBindingWithEscalation(ctx, t); err != nil { return err } } else { fmt.Fprintf(out, "Overwrite role binding %s/%s\n", t.Namespace, t.Name) if s, err := describe.DescribeRoleBinding(t, nil, nil); err == nil { fmt.Fprintf(out, "%s\n", s) } } case *authorizationapi.ClusterRole: ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace) if change { clusterRoleStorage.Delete(ctx, t.Name, nil) if _, err := clusterRoleStorage.CreateClusterRoleWithEscalation(ctx, t); err != nil { return err } } else { fmt.Fprintf(out, "Overwrite role %s/%s\n", t.Namespace, t.Name) if s, err := describe.DescribeRole(authorizationapi.ToRole(t)); err == nil { fmt.Fprintf(out, "%s\n", s) } } case *authorizationapi.ClusterRoleBinding: ctx := kapi.WithNamespace(kapi.NewContext(), t.Namespace) if change { clusterRoleBindingStorage.Delete(ctx, t.Name, nil) if _, err := clusterRoleBindingStorage.CreateClusterRoleBindingWithEscalation(ctx, t); err != nil { return err } } else { fmt.Fprintf(out, "Overwrite role binding %s/%s\n", t.Namespace, t.Name) if s, err := describe.DescribeRoleBinding(authorizationapi.ToRoleBinding(t), nil, nil); err == nil { fmt.Fprintf(out, "%s\n", s) } } default: return fmt.Errorf("only roles and rolebindings may be created in this mode, not: %v", reflect.TypeOf(t)) } } if !change { fmt.Fprintf(out, "To make the changes described above, pass --force\n") } return nil }) }
func TestTemplate(t *testing.T) { _, path, err := testutil.StartTestMaster() if err != nil { t.Fatalf("unexpected error: %v", err) } for _, version := range []string{"v1", "v1beta3"} { config, err := testutil.GetClusterAdminClientConfig(path) if err != nil { t.Fatalf("unexpected error: %v", err) } config.Version = version config.Prefix = "" c, err := client.New(config) if err != nil { t.Fatalf("unexpected error: %v", err) } template := &templateapi.Template{ Parameters: []templateapi.Parameter{ { Name: "NAME", Value: "test", }, }, Objects: []runtime.Object{ &v1beta3.Service{ ObjectMeta: v1beta3.ObjectMeta{ Name: "${NAME}-tester", Namespace: "somevalue", }, Spec: v1beta3.ServiceSpec{ PortalIP: "1.2.3.4", SessionAffinity: "some-bad-${VALUE}", }, }, }, } obj, err := c.TemplateConfigs("default").Create(template) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(obj.Objects) != 1 { t.Fatalf("unexpected object: %#v", obj) } if err := runtime.DecodeList(obj.Objects, runtime.UnstructuredJSONScheme); err != nil { t.Fatalf("unexpected error: %v", err) } svc := obj.Objects[0].(*runtime.Unstructured).Object spec := svc["spec"].(map[string]interface{}) meta := svc["metadata"].(map[string]interface{}) // keep existing values if spec["portalIP"] != "1.2.3.4" { t.Fatalf("unexpected object: %#v", svc) } // replace a value if meta["name"] != "test-tester" { t.Fatalf("unexpected object: %#v", svc) } // clear namespace if meta["namespace"] != "" { t.Fatalf("unexpected object: %#v", svc) } // preserve values exactly if spec["sessionAffinity"] != "some-bad-${VALUE}" { t.Fatalf("unexpected object: %#v", svc) } } }
func TestArrayOfRuntimeObject(t *testing.T) { internalGV := unversioned.GroupVersion{Group: "test.group", Version: runtime.APIVersionInternal} externalGV := unversioned.GroupVersion{Group: "test.group", Version: "v1test"} s := runtime.NewScheme() s.AddKnownTypes(internalGV, &EmbeddedTest{}) s.AddKnownTypeWithName(externalGV.WithKind("EmbeddedTest"), &EmbeddedTestExternal{}) s.AddKnownTypes(internalGV, &ObjectTest{}) s.AddKnownTypeWithName(externalGV.WithKind("ObjectTest"), &ObjectTestExternal{}) codec := serializer.NewCodecFactory(s).LegacyCodec(externalGV) innerItems := []runtime.Object{ &EmbeddedTest{ID: "baz"}, } items := []runtime.Object{ &EmbeddedTest{ID: "foo"}, &EmbeddedTest{ID: "bar"}, // TODO: until YAML is removed, this JSON must be in ascending key order to ensure consistent roundtrip serialization &runtime.Unknown{ Raw: []byte(`{"apiVersion":"unknown.group/unknown","foo":"bar","kind":"OtherTest"}`), ContentType: runtime.ContentTypeJSON, }, &ObjectTest{ Items: runtime.NewEncodableList(codec, innerItems), }, } internal := &ObjectTest{ Items: runtime.NewEncodableList(codec, items), } wire, err := runtime.Encode(codec, internal) if err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("Wire format is:\n%s\n", string(wire)) obj := &ObjectTestExternal{} if err := json.Unmarshal(wire, obj); err != nil { t.Fatalf("unexpected error: %v", err) } t.Logf("exact wire is: %s", string(obj.Items[0].Raw)) items[3] = &ObjectTest{Items: innerItems} internal.Items = items decoded, err := runtime.Decode(codec, wire) if err != nil { t.Fatalf("unexpected error: %v", err) } list, err := meta.ExtractList(decoded) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list, codec); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } list2, err := meta.ExtractList(list[3]) if err != nil { t.Fatalf("unexpected error: %v", err) } if errs := runtime.DecodeList(list2, codec); len(errs) > 0 { t.Fatalf("unexpected error: %v", errs) } if err := meta.SetList(list[3], list2); err != nil { t.Fatalf("unexpected error: %v", err) } // we want DecodeList to set type meta if possible, even on runtime.Unknown objects internal.Items[2].(*runtime.Unknown).TypeMeta = runtime.TypeMeta{Kind: "OtherTest", APIVersion: "unknown.group/unknown"} if e, a := internal.Items, list; !reflect.DeepEqual(e, a) { t.Errorf("mismatched decoded: %s", diff.ObjectGoPrintSideBySide(e, a)) } }
func TestTemplate(t *testing.T) { testutil.RequireEtcd(t) defer testutil.DumpEtcdOnFailure(t) _, path, err := testserver.StartTestMasterAPI() if err != nil { t.Fatalf("unexpected error: %v", err) } for _, version := range []unversioned.GroupVersion{v1.SchemeGroupVersion} { config, err := testutil.GetClusterAdminClientConfig(path) if err != nil { t.Fatalf("unexpected error: %v", err) } config.GroupVersion = &version c, err := client.New(config) if err != nil { t.Fatalf("unexpected error: %v", err) } template := &templateapi.Template{ Parameters: []templateapi.Parameter{ { Name: "NAME", Value: "test", }, }, } templateObjects := []runtime.Object{ &v1.Service{ ObjectMeta: v1.ObjectMeta{ Name: "${NAME}-tester", Namespace: "somevalue", }, Spec: v1.ServiceSpec{ ClusterIP: "1.2.3.4", SessionAffinity: "some-bad-${VALUE}", }, }, } templateapi.AddObjectsToTemplate(template, templateObjects, v1.SchemeGroupVersion) obj, err := c.TemplateConfigs("default").Create(template) if err != nil { t.Fatalf("unexpected error: %v", err) } if len(obj.Objects) != 1 { t.Fatalf("unexpected object: %#v", obj) } if err := runtime.DecodeList(obj.Objects, runtime.UnstructuredJSONScheme); err != nil { t.Fatalf("unexpected error: %v", err) } svc := obj.Objects[0].(*runtime.Unstructured).Object spec := svc["spec"].(map[string]interface{}) meta := svc["metadata"].(map[string]interface{}) // keep existing values if spec["clusterIP"] != "1.2.3.4" { t.Fatalf("unexpected object: %#v", svc) } // replace a value if meta["name"] != "test-tester" { t.Fatalf("unexpected object: %#v", svc) } // clear namespace if meta["namespace"] != "" { t.Fatalf("unexpected object: %#v", svc) } // preserve values exactly if spec["sessionAffinity"] != "some-bad-${VALUE}" { t.Fatalf("unexpected object: %#v", svc) } } }