// 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
}
// 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
}
Beispiel #3
0
// ResourceFromFile retrieves the name and namespace from a valid file. If the file does not
// resolve to a known type an error is returned. The returned mapping can be used to determine
// the correct REST endpoint to modify this resource with.
func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper) (mapping *meta.RESTMapping, namespace, name string, data []byte) {
	configData, err := ReadConfigData(filename)
	checkErr(err)
	data = configData

	version, kind, err := typer.DataVersionAndKind(data)
	checkErr(err)

	// TODO: allow unversioned objects?
	if len(version) == 0 {
		checkErr(fmt.Errorf("The resource in the provided file has no apiVersion defined"))
	}

	mapping, err = mapper.RESTMapping(version, kind)
	checkErr(err)

	obj, err := mapping.Codec.Decode(data)
	checkErr(err)

	meta := mapping.MetadataAccessor
	namespace, err = meta.Namespace(obj)
	checkErr(err)
	name, err = meta.Name(obj)
	checkErr(err)

	return
}
// 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 "", fmt.Errorf("object has no meta: %v", err)
	}
	return meta.Name(), nil
}
Beispiel #5
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.
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) error {
	start := time.Now()
	eventCount := 0
	for {
		event, ok := <-w.ResultChan()
		if !ok {
			break
		}
		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(meta.Name(), event.Object)
		case watch.Modified:
			r.store.Update(meta.Name(), 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(meta.Name())
		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
}
Beispiel #7
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 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
}
// 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
}
Beispiel #9
0
// ResourceFromFile retrieves the name and namespace from a valid file. If the file does not
// resolve to a known type an error is returned. The returned mapping can be used to determine
// the correct REST endpoint to modify this resource with.
// DEPRECATED: Use resource.Builder
func ResourceFromFile(filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper, schema validation.Schema, cmdVersion string) (mapping *meta.RESTMapping, namespace, name string, data []byte, err error) {
	data, err = ReadConfigData(filename)
	if err != nil {
		return
	}

	objVersion, kind, err := typer.DataVersionAndKind(data)
	if err != nil {
		return
	}

	// TODO: allow unversioned objects?
	if len(objVersion) == 0 {
		err = fmt.Errorf("the resource in the provided file has no apiVersion defined")
	}

	err = schema.ValidateBytes(data)
	if err != nil {
		return
	}

	// decode using the version stored with the object (allows codec to vary across versions)
	mapping, err = mapper.RESTMapping(kind, objVersion)
	if err != nil {
		return
	}

	obj, err := mapping.Codec.Decode(data)
	if err != nil {
		return
	}

	meta := mapping.MetadataAccessor
	namespace, err = meta.Namespace(obj)
	if err != nil {
		return
	}
	name, err = meta.Name(obj)
	if err != nil {
		return
	}

	// if the preferred API version differs, get a different mapper
	if cmdVersion != objVersion {
		mapping, err = mapper.RESTMapping(kind, cmdVersion)
	}
	return
}
Beispiel #10
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.
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
}
Beispiel #11
0
// ResourceFromFile retrieves the name and namespace from a valid file. If the file does not
// resolve to a known type an error is returned. The returned mapping can be used to determine
// the correct REST endpoint to modify this resource with.
func ResourceFromFile(cmd *cobra.Command, filename string, typer runtime.ObjectTyper, mapper meta.RESTMapper, schema validation.Schema) (mapping *meta.RESTMapping, namespace, name string, data []byte) {
	configData, err := ReadConfigData(filename)
	checkErr(err)
	data = configData

	objVersion, kind, err := typer.DataVersionAndKind(data)
	checkErr(err)

	// TODO: allow unversioned objects?
	if len(objVersion) == 0 {
		checkErr(fmt.Errorf("the resource in the provided file has no apiVersion defined"))
	}

	err = schema.ValidateBytes(data)
	checkErr(err)

	// decode using the version stored with the object (allows codec to vary across versions)
	mapping, err = mapper.RESTMapping(kind, objVersion)
	checkErr(err)

	obj, err := mapping.Codec.Decode(data)
	checkErr(err)

	meta := mapping.MetadataAccessor
	namespace, err = meta.Namespace(obj)
	checkErr(err)
	name, err = meta.Name(obj)
	checkErr(err)

	// if the preferred API version differs, get a different mapper
	version := GetFlagString(cmd, "api-version")
	if version != objVersion {
		mapping, err = mapper.RESTMapping(kind, version)
		checkErr(err)
	}

	return
}