Esempio n. 1
0
// 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 []string{""}, fmt.Errorf("object has no meta: %v", err)
	}
	return []string{meta.GetNamespace()}, nil
}
Esempio n. 2
0
func (t *tracker) Delete(gvk unversioned.GroupVersionKind, ns, name string) error {
	if err := checkNamespace(gvk, ns); err != nil {
		return err
	}

	t.lock.Lock()
	defer t.lock.Unlock()

	found := false

	for i, existingObj := range t.objects[gvk] {
		objMeta, err := meta.Accessor(existingObj)
		if err != nil {
			return err
		}
		if objMeta.GetNamespace() == ns && objMeta.GetName() == name {
			t.objects[gvk] = append(t.objects[gvk][:i], t.objects[gvk][i+1:]...)
			found = true
			break
		}
	}

	if found {
		return nil
	}

	return errors.NewNotFound(unversioned.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, name)
}
Esempio n. 3
0
// watchHandler watches w and keeps *resourceVersion up to date.
func (r *Reflector) watchHandler(w watch.Interface, resourceVersion *string, errc chan error, 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 err := <-errc:
			return err
		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 != nil && e != a {
				utilruntime.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 {
				utilruntime.HandleError(fmt.Errorf("%s: unable to understand watch event %#v", r.name, event))
				continue
			}
			newResourceVersion := meta.GetResourceVersion()
			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:
				utilruntime.HandleError(fmt.Errorf("%s: unable to understand watch event %#v", r.name, event))
			}
			*resourceVersion = newResourceVersion
			r.setLastSyncResourceVersion(newResourceVersion)
			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
}
Esempio n. 4
0
// 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.GetNamespace()) > 0 {
		return meta.GetNamespace() + "/" + meta.GetName(), nil
	}
	return meta.GetName(), nil
}
Esempio n. 5
0
// filterByNamespaceAndName returns all objects in the collection that
// match provided namespace and name. Empty namespace matches
// non-namespaced objects.
func filterByNamespaceAndName(objs []runtime.Object, ns, name string) ([]runtime.Object, error) {
	var res []runtime.Object

	for _, obj := range objs {
		acc, err := meta.Accessor(obj)
		if err != nil {
			return nil, err
		}
		if ns != "" && acc.GetNamespace() != ns {
			continue
		}
		if name != "" && acc.GetName() != name {
			continue
		}
		res = append(res, obj)
	}

	return res, nil
}
Esempio n. 6
0
// 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 http://issue.k8s.io/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
	}

	gvk := obj.GetObjectKind().GroupVersionKind()

	// 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 := gvk.Kind
	if len(kind) == 0 {
		// TODO: this is wrong
		gvks, _, err := Scheme.ObjectKinds(obj)
		if err != nil {
			return nil, err
		}
		kind = gvks[0].Kind
	}

	// An object that implements only List has enough metadata to build a reference
	var listMeta meta.List
	objectMeta, err := meta.Accessor(obj)
	if err != nil {
		listMeta, err = meta.ListAccessor(obj)
		if err != nil {
			return nil, err
		}
	} else {
		listMeta = objectMeta
	}

	// if the object referenced is actually persisted, we can also get version from meta
	version := gvk.GroupVersion().String()
	if len(version) == 0 {
		selfLink := listMeta.GetSelfLink()
		if len(selfLink) == 0 {
			return nil, ErrNoSelfLink
		}
		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]
	}

	// only has list metadata
	if objectMeta == nil {
		return &ObjectReference{
			Kind:            kind,
			APIVersion:      version,
			ResourceVersion: listMeta.GetResourceVersion(),
		}, nil
	}

	return &ObjectReference{
		Kind:            kind,
		APIVersion:      version,
		Name:            objectMeta.GetName(),
		Namespace:       objectMeta.GetNamespace(),
		UID:             objectMeta.GetUID(),
		ResourceVersion: objectMeta.GetResourceVersion(),
	}, nil
}
Esempio n. 7
0
// ObjectReaction returns a ReactionFunc that applies testing.Action to
// the given tracker.
func ObjectReaction(tracker ObjectTracker, mapper meta.RESTMapper) ReactionFunc {
	return func(action Action) (bool, runtime.Object, error) {
		ns := action.GetNamespace()
		gvr := action.GetResource()

		gvk, err := mapper.KindFor(gvr)
		if err != nil {
			return false, nil, fmt.Errorf("error getting kind for resource %q: %s", gvr, err)
		}

		// This is a temporary fix. Because there is no internal resource, so
		// the caller has no way to express that it expects to get an internal
		// kind back. A more proper fix will be directly specify the Kind when
		// build the action.
		gvk.Version = gvr.Version
		if len(gvk.Version) == 0 {
			gvk.Version = runtime.APIVersionInternal
		}

		// Here and below we need to switch on implementation types,
		// not on interfaces, as some interfaces are identical
		// (e.g. UpdateAction and CreateAction), so if we use them,
		// updates and creates end up matching the same case branch.
		switch action := action.(type) {

		case ListActionImpl:
			obj, err := tracker.List(gvk, ns)
			return true, obj, err

		case GetActionImpl:
			obj, err := tracker.Get(gvk, ns, action.GetName())
			return true, obj, err

		case CreateActionImpl:
			objMeta, err := meta.Accessor(action.GetObject())
			if err != nil {
				return true, nil, err
			}
			if action.GetSubresource() == "" {
				err = tracker.Add(action.GetObject())
			} else {
				// TODO: Currently we're handling subresource creation as an update
				// on the enclosing resource. This works for some subresources but
				// might not be generic enough.
				err = tracker.Update(action.GetObject())
			}
			if err != nil {
				return true, nil, err
			}
			obj, err := tracker.Get(gvk, ns, objMeta.GetName())
			return true, obj, err

		case UpdateActionImpl:
			objMeta, err := meta.Accessor(action.GetObject())
			if err != nil {
				return true, nil, err
			}
			err = tracker.Update(action.GetObject())
			if err != nil {
				return true, nil, err
			}
			obj, err := tracker.Get(gvk, ns, objMeta.GetName())
			return true, obj, err

		case DeleteActionImpl:
			err := tracker.Delete(gvk, ns, action.GetName())
			if err != nil {
				return true, nil, err
			}
			return true, nil, nil

		default:
			return false, nil, fmt.Errorf("no reaction implemented for %s", action)
		}
	}
}
Esempio n. 8
0
func (t *tracker) add(obj runtime.Object, replaceExisting bool) error {
	if meta.IsListType(obj) {
		return t.addList(obj, replaceExisting)
	}

	gvks, _, err := t.scheme.ObjectKinds(obj)
	if err != nil {
		return err
	}
	if len(gvks) == 0 {
		return fmt.Errorf("no registered kinds for %v", obj)
	}

	t.lock.Lock()
	defer t.lock.Unlock()

	for _, gvk := range gvks {
		gr := unversioned.GroupResource{Group: gvk.Group, Resource: gvk.Kind}

		// To avoid the object from being accidentally modified by caller
		// after it's been added to the tracker, we always store the deep
		// copy.
		obj, err = t.scheme.Copy(obj)
		if err != nil {
			return err
		}

		if status, ok := obj.(*unversioned.Status); ok && status.Details != nil {
			gvk.Kind = status.Details.Kind
		}

		newMeta, err := meta.Accessor(obj)
		if err != nil {
			return err
		}

		if err := checkNamespace(gvk, newMeta.GetNamespace()); err != nil {
			return err
		}

		for i, existingObj := range t.objects[gvk] {
			oldMeta, err := meta.Accessor(existingObj)
			if err != nil {
				return err
			}
			if oldMeta.GetNamespace() == newMeta.GetNamespace() && oldMeta.GetName() == newMeta.GetName() {
				if replaceExisting {
					t.objects[gvk][i] = obj
					return nil
				}
				return errors.NewAlreadyExists(gr, newMeta.GetName())
			}
		}

		if replaceExisting {
			// Tried to update but no matching object was found.
			return errors.NewNotFound(gr, newMeta.GetName())
		}

		t.objects[gvk] = append(t.objects[gvk], obj)
	}

	return nil
}