// MetaNamespaceIndexFunc is a default index function that indexes based on an object's namespace func MetaNamespaceIndexFunc(obj interface{}) (string, error) { meta, err := meta.Accessor(obj) if err != nil { return "", fmt.Errorf("object has no meta: %v", err) } return meta.Namespace(), nil }
// nameIndexFunc is an index function that indexes based on an object's name func nameIndexFunc(obj interface{}) ([]string, error) { meta, err := meta.Accessor(obj) if err != nil { return []string{""}, fmt.Errorf("object has no meta: %v", err) } return []string{meta.Name()}, nil }
func (r *Reflector) listAndWatch(stopCh <-chan struct{}) { var resourceVersion string resyncCh, cleanup := r.resyncChan() defer cleanup() list, err := r.listerWatcher.List() if err != nil { util.HandleError(fmt.Errorf("%s: Failed to list %v: %v", r.name, r.expectedType, err)) return } meta, err := meta.Accessor(list) if err != nil { util.HandleError(fmt.Errorf("%s: Unable to understand list result %#v", r.name, list)) return } resourceVersion = meta.ResourceVersion() items, err := runtime.ExtractList(list) if err != nil { util.HandleError(fmt.Errorf("%s: Unable to understand list result %#v (%v)", r.name, list, err)) return } if err := r.syncWith(items); err != nil { util.HandleError(fmt.Errorf("%s: Unable to sync list result: %v", r.name, err)) return } r.setLastSyncResourceVersion(resourceVersion) for { w, err := r.listerWatcher.Watch(resourceVersion) if err != nil { switch err { case io.EOF: // watch closed normally case io.ErrUnexpectedEOF: glog.V(1).Infof("%s: Watch for %v closed with unexpected EOF: %v", r.name, r.expectedType, err) default: util.HandleError(fmt.Errorf("%s: Failed to watch %v: %v", r.name, r.expectedType, err)) } // If this is "connection refused" error, it means that most likely apiserver is not responsive. // It doesn't make sense to re-list all objects because most likely we will be able to restart // watch where we ended. // If that's the case wait and resend watch request. if urlError, ok := err.(*url.Error); ok { if opError, ok := urlError.Err.(*net.OpError); ok { if errno, ok := opError.Err.(syscall.Errno); ok && errno == syscall.ECONNREFUSED { time.Sleep(time.Second) continue } } } return } if err := r.watchHandler(w, &resourceVersion, resyncCh, stopCh); err != nil { if err != errorResyncRequested && err != errorStopRequested { util.HandleError(fmt.Errorf("%s: watch of %v ended with: %v", r.name, r.expectedType, err)) } return } } }
// GetReference returns an ObjectReference which refers to the given // object, or an error if the object doesn't follow the conventions // that would allow this. func GetReference(obj runtime.Object) (*ObjectReference, error) { if obj == nil { return nil, ErrNilObject } if ref, ok := obj.(*ObjectReference); ok { // Don't make a reference to a reference. return ref, nil } meta, err := meta.Accessor(obj) if err != nil { return nil, err } _, kind, err := Scheme.ObjectVersionAndKind(obj) if err != nil { return nil, err } version := versionFromSelfLink.FindStringSubmatch(meta.SelfLink()) if len(version) < 2 { return nil, fmt.Errorf("unexpected self link format: '%v'; got version '%v'", meta.SelfLink(), version) } return &ObjectReference{ Kind: kind, APIVersion: version[1], Name: meta.Name(), Namespace: meta.Namespace(), UID: meta.UID(), ResourceVersion: meta.ResourceVersion(), }, nil }
// watchHandler watches w and keeps *resourceVersion up to date. func (r *Reflector) watchHandler(w watch.Interface, resourceVersion *string, resyncCh <-chan time.Time, stopCh <-chan struct{}) error { start := time.Now() eventCount := 0 // Stopping the watcher should be idempotent and if we return from this function there's no way // we're coming back in with the same watch interface. defer w.Stop() loop: for { select { case <-stopCh: return errorStopRequested case <-resyncCh: return errorResyncRequested case event, ok := <-w.ResultChan(): if !ok { break loop } if event.Type == watch.Error { return apierrs.FromObject(event.Object) } if e, a := r.expectedType, reflect.TypeOf(event.Object); e != a { util.HandleError(fmt.Errorf("%s: expected type %v, but watch event object had type %v", r.name, e, a)) continue } meta, err := meta.Accessor(event.Object) if err != nil { util.HandleError(fmt.Errorf("%s: unable to understand watch event %#v", r.name, event)) continue } switch event.Type { case watch.Added: r.store.Add(event.Object) case watch.Modified: r.store.Update(event.Object) case watch.Deleted: // TODO: Will any consumers need access to the "last known // state", which is passed in event.Object? If so, may need // to change this. r.store.Delete(event.Object) default: util.HandleError(fmt.Errorf("%s: unable to understand watch event %#v", r.name, event)) } *resourceVersion = meta.ResourceVersion() r.setLastSyncResourceVersion(*resourceVersion) eventCount++ } } watchDuration := time.Now().Sub(start) if watchDuration < 1*time.Second && eventCount == 0 { glog.V(4).Infof("%s: Unexpected watch close - watch lasted less than a second and no items received", r.name) return errors.New("very short watch") } glog.V(4).Infof("%s: Watch close - %v total %v items received", r.name, r.expectedType, eventCount) return nil }
// GetReference returns an ObjectReference which refers to the given // object, or an error if the object doesn't follow the conventions // that would allow this. // TODO: should take a meta.Interface see https://github.com/GoogleCloudPlatform/kubernetes/issues/7127 func GetReference(obj runtime.Object) (*ObjectReference, error) { if obj == nil { return nil, ErrNilObject } if ref, ok := obj.(*ObjectReference); ok { // Don't make a reference to a reference. return ref, nil } meta, err := meta.Accessor(obj) if err != nil { return nil, err } // if the object referenced is actually persisted, we can just get kind from meta // if we are building an object reference to something not yet persisted, we should fallback to scheme kind := meta.Kind() if kind == "" { _, kind, err = Scheme.ObjectVersionAndKind(obj) if err != nil { return nil, err } } // if the object referenced is actually persisted, we can also get version from meta version := meta.APIVersion() if version == "" { selfLink := meta.SelfLink() if selfLink == "" { if ForTesting_ReferencesAllowBlankSelfLinks { version = "testing" } else { return nil, ErrNoSelfLink } } else { selfLinkUrl, err := url.Parse(selfLink) if err != nil { return nil, err } // example paths: /<prefix>/<version>/* parts := strings.Split(selfLinkUrl.Path, "/") if len(parts) < 3 { return nil, fmt.Errorf("unexpected self link format: '%v'; got version '%v'", selfLink, version) } version = parts[2] } } return &ObjectReference{ Kind: kind, APIVersion: version, Name: meta.Name(), Namespace: meta.Namespace(), UID: meta.UID(), ResourceVersion: meta.ResourceVersion(), }, nil }
// MetaNamespaceKeyFunc is a convenient default KeyFunc which knows how to make // keys for API objects which implement meta.Interface. // The key uses the format: <namespace>/<name> func MetaNamespaceKeyFunc(obj interface{}) (string, error) { meta, err := meta.Accessor(obj) if err != nil { return "", fmt.Errorf("object has no meta: %v", err) } if len(meta.Namespace()) > 0 { return meta.Namespace() + "/" + meta.Name(), nil } return meta.Name(), nil }
func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, seed int64) runtime.Object { fuzzerFor(t, forVersion, rand.NewSource(seed)).Fuzz(item) j, err := meta.Accessor(item) if err != nil { t.Fatalf("Unexpected error %v for %#v", err, item) } j.SetKind("") j.SetAPIVersion("") return item }
// MetaNamespaceKeyFunc is a convenient default KeyFunc which knows how to make // keys for API objects which implement meta.Interface. // The key uses the format <namespace>/<name> unless <namespace> is empty, then // it's just <name>. // // TODO: replace key-as-string with a key-as-struct so that this // packing/unpacking won't be necessary. func MetaNamespaceKeyFunc(obj interface{}) (string, error) { if key, ok := obj.(ExplicitKey); ok { return string(key), nil } meta, err := meta.Accessor(obj) if err != nil { return "", fmt.Errorf("object has no meta: %v", err) } if len(meta.Namespace()) > 0 { return meta.Namespace() + "/" + meta.Name(), nil } return meta.Name(), nil }
// syncWith replaces the store's items with the given list. func (r *Reflector) syncWith(items []runtime.Object) error { found := map[string]interface{}{} for _, item := range items { meta, err := meta.Accessor(item) if err != nil { return fmt.Errorf("unexpected item in list: %v", err) } found[meta.Name()] = item } r.store.Replace(found) return nil }
// watchHandler watches w and keeps *resourceVersion up to date. func (r *Reflector) watchHandler(w watch.Interface, resourceVersion *string, exitWatch <-chan time.Time) error { start := time.Now() eventCount := 0 loop: for { select { case <-exitWatch: w.Stop() return errorResyncRequested case event, ok := <-w.ResultChan(): if !ok { break loop } if event.Type == watch.Error { return apierrs.FromObject(event.Object) } if e, a := r.expectedType, reflect.TypeOf(event.Object); e != a { glog.Errorf("expected type %v, but watch event object had type %v", e, a) continue } meta, err := meta.Accessor(event.Object) if err != nil { glog.Errorf("unable to understand watch event %#v", event) continue } switch event.Type { case watch.Added: r.store.Add(event.Object) case watch.Modified: r.store.Update(event.Object) case watch.Deleted: // TODO: Will any consumers need access to the "last known // state", which is passed in event.Object? If so, may need // to change this. r.store.Delete(event.Object) default: glog.Errorf("unable to understand watch event %#v", event) } *resourceVersion = meta.ResourceVersion() eventCount++ } } watchDuration := time.Now().Sub(start) if watchDuration < 1*time.Second && eventCount == 0 { glog.V(4).Infof("Unexpected watch close - watch lasted less than a second and no items received") return errors.New("very short watch") } glog.V(4).Infof("Watch close - %v total %v items received", r.expectedType, eventCount) return nil }
// ExtractFieldPathAsString extracts the field from the given object // and returns it as a string. The object must be a pointer to an // API type. // // Currently, this API is limited to supporting the fieldpaths: // // 1. metadata.name - The name of an API object // 2. metadata.namespace - The namespace of an API object func ExtractFieldPathAsString(obj interface{}, fieldPath string) (string, error) { accessor, err := meta.Accessor(obj) if err != nil { return "", nil } switch fieldPath { case "metadata.name": return accessor.Name(), nil case "metadata.namespace": return accessor.Namespace(), nil } return "", fmt.Errorf("Unsupported fieldPath: %v", fieldPath) }
func (r *Reflector) listAndWatch(stopCh <-chan struct{}) { var resourceVersion string resyncCh, cleanup := r.resyncChan() defer cleanup() list, err := r.listerWatcher.List() if err != nil { glog.Errorf("Failed to list %v: %v", r.expectedType, err) return } meta, err := meta.Accessor(list) if err != nil { glog.Errorf("Unable to understand list result %#v", list) return } resourceVersion = meta.ResourceVersion() items, err := runtime.ExtractList(list) if err != nil { glog.Errorf("Unable to understand list result %#v (%v)", list, err) return } if err := r.syncWith(items); err != nil { glog.Errorf("Unable to sync list result: %v", err) return } r.setLastSyncResourceVersion(resourceVersion) for { w, err := r.listerWatcher.Watch(resourceVersion) if err != nil { switch err { case io.EOF: // watch closed normally case io.ErrUnexpectedEOF: glog.V(1).Infof("Watch for %v closed with unexpected EOF: %v", r.expectedType, err) default: glog.Errorf("Failed to watch %v: %v", r.expectedType, err) } return } if err := r.watchHandler(w, &resourceVersion, resyncCh, stopCh); err != nil { if err != errorResyncRequested { glog.Errorf("watch of %v ended with: %v", r.expectedType, err) } return } } }
func (r *Reflector) listAndWatch() { var resourceVersion string list, err := r.listerWatcher.List() if err != nil { glog.Errorf("Failed to list %v: %v", r.expectedType, err) return } meta, err := meta.Accessor(list) if err != nil { glog.Errorf("Unable to understand list result %#v", list) return } resourceVersion = meta.ResourceVersion() items, err := runtime.ExtractList(list) if err != nil { glog.Errorf("Unable to understand list result %#v (%v)", list, err) return } err = r.syncWith(items) if err != nil { glog.Errorf("Unable to sync list result: %v", err) return } for { w, err := r.listerWatcher.Watch(resourceVersion) if err != nil { switch err { case io.EOF: // watch closed normally case io.ErrUnexpectedEOF: glog.V(1).Infof("Watch for %v closed with unexpected EOF: %v", r.expectedType, err) default: glog.Errorf("Failed to watch %v: %v", r.expectedType, err) } return } if err := r.watchHandler(w, &resourceVersion); err != nil { glog.Errorf("watch of %v ended with error: %v", r.expectedType, err) return } } }
func TestTypes(t *testing.T) { for kind := range api.Scheme.KnownTypes("") { // Try a few times, since runTest uses random values. for i := 0; i < *fuzzIters; i++ { item, err := api.Scheme.New("", kind) if err != nil { t.Errorf("Couldn't make a %v? %v", kind, err) continue } if _, err := meta.Accessor(item); err != nil { t.Logf("%s is not a TypeMeta and cannot be round tripped: %v", kind, err) continue } runTest(t, v1beta1.Codec, item) runTest(t, v1beta2.Codec, item) runTest(t, api.Codec, item) } } }
func stripNamespace(obj runtime.Object) { // Remove namespace from the item if itemMeta, err := meta.Accessor(obj); err == nil { itemMeta.SetNamespace("") return } // TODO: allow meta.Accessor to handle runtime.Unstructured if unstruct, ok := obj.(*runtime.Unstructured); ok && unstruct.Object != nil { if obj, ok := unstruct.Object["metadata"]; ok { if m, ok := obj.(map[string]interface{}); ok { if _, ok := m["namespace"]; ok { m["namespace"] = "" } } return } if _, ok := unstruct.Object["namespace"]; ok { unstruct.Object["namespace"] = "" return } } }
// GetReference returns an ObjectReference which refers to the given // object, or an error if the object doesn't follow the conventions // that would allow this. func GetReference(obj runtime.Object) (*ObjectReference, error) { if obj == nil { return nil, ErrNilObject } if ref, ok := obj.(*ObjectReference); ok { // Don't make a reference to a reference. return ref, nil } meta, err := meta.Accessor(obj) if err != nil { return nil, err } _, kind, err := Scheme.ObjectVersionAndKind(obj) if err != nil { return nil, err } version := "" parsedSelfLink := versionFromSelfLink.FindStringSubmatch(meta.SelfLink()) if len(parsedSelfLink) < 2 { if ForTesting_ReferencesAllowBlankSelfLinks { version = "testing" } else if meta.SelfLink() == "" { return nil, ErrNoSelfLink } else { return nil, fmt.Errorf("unexpected self link format: '%v'; got version '%v'", meta.SelfLink(), version) } } else { version = parsedSelfLink[1] } return &ObjectReference{ Kind: kind, APIVersion: version, Name: meta.Name(), Namespace: meta.Namespace(), UID: meta.UID(), ResourceVersion: meta.ResourceVersion(), }, nil }
func runTest(t *testing.T, codec runtime.Codec, source runtime.Object) { name := reflect.TypeOf(source).Elem().Name() apiObjectFuzzer.Fuzz(source) j, err := meta.Accessor(source) if err != nil { t.Fatalf("Unexpected error %v for %#v", err, source) } j.SetKind("") j.SetAPIVersion("") data, err := codec.Encode(source) if err != nil { t.Errorf("%v: %v (%#v)", name, err, source) return } obj2, err := codec.Decode(data) if err != nil { t.Errorf("%v: %v", name, err) return } else { if !reflect.DeepEqual(source, obj2) { t.Errorf("1: %v: diff: %v\nCodec: %v\nData: %s\nSource: %#v", name, util.ObjectDiff(source, obj2), codec, string(data), source) return } } obj3 := reflect.New(reflect.TypeOf(source).Elem()).Interface().(runtime.Object) err = codec.DecodeInto(data, obj3) if err != nil { t.Errorf("2: %v: %v", name, err) return } else { if !reflect.DeepEqual(source, obj3) { t.Errorf("3: %v: diff: %v\nCodec: %v", name, util.ObjectDiff(source, obj3), codec) return } } }
func (r *Reflector) listAndWatch() { var resourceVersion string list, err := r.listerWatcher.List() if err != nil { glog.Errorf("Failed to list %v: %v", r.expectedType, err) return } meta, err := meta.Accessor(list) if err != nil { glog.Errorf("Unable to understand list result %#v", list) return } resourceVersion = meta.ResourceVersion() items, err := runtime.ExtractList(list) if err != nil { glog.Errorf("Unable to understand list result %#v (%v)", list, err) return } err = r.syncWith(items) if err != nil { glog.Errorf("Unable to sync list result: %v", err) return } for { w, err := r.listerWatcher.Watch(resourceVersion) if err != nil { glog.Errorf("failed to watch %v: %v", r.expectedType, err) return } if err := r.watchHandler(w, &resourceVersion); err != nil { glog.Errorf("watch of %v ended with error: %v", r.expectedType, err) return } } }
func TestRoundTripTypes(t *testing.T) { // api.Scheme.Log(t) // defer api.Scheme.Log(nil) for kind := range api.Scheme.KnownTypes("") { if nonRoundTrippableTypes.Has(kind) { continue } // Try a few times, since runTest uses random values. for i := 0; i < *fuzzIters; i++ { item, err := api.Scheme.New("", kind) if err != nil { t.Fatalf("Couldn't make a %v? %v", kind, err) } if _, err := meta.Accessor(item); err != nil { t.Fatalf("%q is not a TypeMeta and cannot be tested - add it to nonRoundTrippableTypes: %v", kind, err) } roundTripSame(t, item) if !nonInternalRoundTrippableTypes.Has(kind) { roundTrip(t, api.Codec, fuzzInternalObject(t, "", item, rand.Int63())) } } } }
func TestAddConfigLabels(t *testing.T) { var nilLabels map[string]string testCases := []struct { obj runtime.Object addLabels map[string]string err bool expectedLabels map[string]string }{ { // [0] Test nil + nil => nil obj: &kapi.Pod{}, addLabels: nilLabels, err: false, expectedLabels: nilLabels, }, { // [1] Test nil + empty labels => empty labels obj: &kapi.Pod{}, addLabels: map[string]string{}, err: false, expectedLabels: map[string]string{}, }, { // [2] Test obj.Labels + nil => obj.Labels obj: &kapi.Pod{ ObjectMeta: kapi.ObjectMeta{Labels: map[string]string{"foo": "bar"}}, }, addLabels: nilLabels, err: false, expectedLabels: map[string]string{"foo": "bar"}, }, { // [3] Test obj.Labels + empty labels => obj.Labels obj: &kapi.Pod{ ObjectMeta: kapi.ObjectMeta{Labels: map[string]string{"foo": "bar"}}, }, addLabels: map[string]string{}, err: false, expectedLabels: map[string]string{"foo": "bar"}, }, { // [4] Test nil + addLabels => addLabels obj: &kapi.Pod{}, addLabels: map[string]string{"foo": "bar"}, err: false, expectedLabels: map[string]string{"foo": "bar"}, }, { // [5] Test obj.labels + addLabels => expectedLabels obj: &kapi.Service{ ObjectMeta: kapi.ObjectMeta{Labels: map[string]string{"baz": ""}}, }, addLabels: map[string]string{"foo": "bar"}, err: false, expectedLabels: map[string]string{"foo": "bar", "baz": ""}, }, { // [6] Test conflicting keys with the same value obj: &kapi.Service{ ObjectMeta: kapi.ObjectMeta{Labels: map[string]string{"foo": "same value"}}, }, addLabels: map[string]string{"foo": "same value"}, err: false, expectedLabels: map[string]string{"foo": "same value"}, }, { // [7] Test conflicting keys with a different value obj: &kapi.Service{ ObjectMeta: kapi.ObjectMeta{Labels: map[string]string{"foo": "first value"}}, }, addLabels: map[string]string{"foo": "second value"}, err: true, expectedLabels: map[string]string{"foo": "first value"}, }, { // [8] Test conflicting keys with the same value in ReplicationController nested labels obj: &kapi.ReplicationController{ ObjectMeta: kapi.ObjectMeta{ Labels: map[string]string{"foo": "same value"}, }, Spec: kapi.ReplicationControllerSpec{ Template: &kapi.PodTemplateSpec{ ObjectMeta: kapi.ObjectMeta{ Labels: map[string]string{}, }, }, }, }, addLabels: map[string]string{"foo": "same value"}, err: false, expectedLabels: map[string]string{"foo": "same value"}, }, { // [9] Test adding labels to a DeploymentConfig object obj: &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{ Labels: map[string]string{"foo": "first value"}, }, Template: deployapi.DeploymentTemplate{ ControllerTemplate: kapi.ReplicationControllerSpec{ Template: &kapi.PodTemplateSpec{ ObjectMeta: kapi.ObjectMeta{ Labels: map[string]string{}, }, }, }, }, }, addLabels: map[string]string{"bar": "second value"}, err: false, expectedLabels: map[string]string{"foo": "first value", "bar": "second value"}, }, { // [10] Test unknown Generic Object with Labels field obj: &FakeLabelsResource{ ObjectMeta: kapi.ObjectMeta{Labels: map[string]string{"baz": ""}}, }, addLabels: map[string]string{"foo": "bar"}, err: false, expectedLabels: map[string]string{"foo": "bar", "baz": ""}, }, } for i, test := range testCases { err := AddObjectLabels(test.obj, test.addLabels) if err != nil && !test.err { t.Errorf("Unexpected error while setting labels on testCase[%v]: %v.", i, err) } else if err == nil && test.err { t.Errorf("Unexpected non-error while setting labels on testCase[%v].", i) } accessor, err := kmeta.Accessor(test.obj) if err != nil { t.Error(err) } metaLabels := accessor.Labels() if e, a := test.expectedLabels, metaLabels; !reflect.DeepEqual(e, a) { t.Errorf("Unexpected labels on testCase[%v]. Expected: %#v, got: %#v.", i, e, a) } // must not add any new nested labels switch objType := test.obj.(type) { case *kapi.ReplicationController: if e, a := map[string]string{}, objType.Spec.Template.Labels; !reflect.DeepEqual(e, a) { t.Errorf("Unexpected labels on testCase[%v]. Expected: %#v, got: %#v.", i, e, a) } case *deployapi.DeploymentConfig: if e, a := map[string]string{}, objType.Template.ControllerTemplate.Template.Labels; !reflect.DeepEqual(e, a) { t.Errorf("Unexpected labels on testCase[%v]. Expected: %#v, got: %#v.", i, e, a) } } } }
// AddObjectLabels adds new label(s) to a single runtime.Object func AddObjectLabels(obj runtime.Object, labels labels.Set) error { if labels == nil { return nil } accessor, err := kmeta.Accessor(obj) if err != nil { if _, ok := obj.(*runtime.Unstructured); !ok { // error out if it's not possible to get an accessor and it's also not an unstructured object return err } } else { metaLabels := accessor.Labels() if metaLabels == nil { metaLabels = make(map[string]string) } if err := MergeInto(metaLabels, labels, ErrorOnDifferentDstKeyValue); err != nil { return fmt.Errorf("unable to add labels to Template.%s: %v", accessor.Kind(), err) } accessor.SetLabels(metaLabels) return nil } // handle unstructured object // TODO: allow meta.Accessor to handle runtime.Unstructured if unstruct, ok := obj.(*runtime.Unstructured); ok && unstruct.Object != nil { // the presence of "metadata" is sufficient for us to apply the rules for Kube-like // objects. // TODO: add swagger detection to allow this to happen more effectively if obj, ok := unstruct.Object["metadata"]; ok { if m, ok := obj.(map[string]interface{}); ok { existing := make(map[string]string) if l, ok := m["labels"]; ok { if found, ok := extractLabels(l); ok { existing = found } } if err := MergeInto(existing, labels, OverwriteExistingDstKey); err != nil { return err } m["labels"] = mapToGeneric(existing) } return nil } // only attempt to set root labels if a root object called labels exists // TODO: add swagger detection to allow this to happen more effectively if obj, ok := unstruct.Object["labels"]; ok { existing := make(map[string]string) if found, ok := extractLabels(obj); ok { existing = found } if err := MergeInto(existing, labels, OverwriteExistingDstKey); err != nil { return err } unstruct.Object["labels"] = mapToGeneric(existing) return nil } } return nil }
func executeAPIRequest(ctx api.Context, method string, c *client.Client) bool { storage, path, hasSuffix := storagePathFromArg(flag.Arg(1)) validStorage := checkStorage(storage) verb := "" setBody := false var version string printer := getPrinter() switch method { case "get": verb = "GET" if !validStorage || !hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>[/<id>]", method, prettyWireStorage()) } case "list": verb = "GET" if !validStorage || hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>", method, prettyWireStorage()) } case "delete": verb = "DELETE" if !validStorage || !hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>/<id>", method, prettyWireStorage()) } case "create": verb = "POST" setBody = true if !validStorage || hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>", method, prettyWireStorage()) } case "update": obj, err := c.Verb("GET").Namespace(api.Namespace(ctx)).Suffix(path).Do().Get() if err != nil { glog.Fatalf("error obtaining resource version for update: %v", err) } meta, err := meta.Accessor(obj) if err != nil { glog.Fatalf("error finding json base for update: %v", err) } version = meta.ResourceVersion() verb = "PUT" setBody = true if !validStorage || !hasSuffix { glog.Fatalf("usage: kubecfg [OPTIONS] %s <%s>/<id>", method, prettyWireStorage()) } case "print": data := readConfig(storage, c) obj, err := latest.Codec.Decode(data) if err != nil { glog.Fatalf("error setting resource version: %v", err) } printer.PrintObj(obj, os.Stdout) return true default: return false } r := c.Verb(verb).Namespace(api.Namespace(ctx)).Suffix(path) if len(*selector) > 0 { r.ParseSelectorParam("labels", *selector) } if len(*fieldSelector) > 0 { r.ParseSelectorParam("fields", *fieldSelector) } if setBody { if len(version) > 0 { data := readConfig(storage, c) obj, err := latest.Codec.Decode(data) if err != nil { glog.Fatalf("error setting resource version: %v", err) } jsonBase, err := meta.Accessor(obj) if err != nil { glog.Fatalf("error setting resource version: %v", err) } jsonBase.SetResourceVersion(version) data, err = c.RESTClient.Codec.Encode(obj) if err != nil { glog.Fatalf("error setting resource version: %v", err) } r.Body(data) } else { r.Body(readConfig(storage, c)) } } result := r.Do() obj, err := result.Get() if err != nil { glog.Fatalf("Got request error: %v\n", err) return false } if err = printer.PrintObj(obj, os.Stdout); err != nil { body, _ := result.Raw() glog.Fatalf("Failed to print: %v\nRaw received object:\n%#v\n\nBody received: %v", err, obj, string(body)) } fmt.Print("\n") return true }