func isChangingOwnerReference(newObj, oldObj runtime.Object) bool { newMeta, err := meta.Accessor(newObj) if err != nil { // if we don't have objectmeta, we don't have the object reference return false } if oldObj == nil { return len(newMeta.GetOwnerReferences()) > 0 } oldMeta, err := meta.Accessor(oldObj) if err != nil { // if we don't have objectmeta, we don't have the object reference return false } // compare the old and new. If they aren't the same, then we're trying to change an ownerRef oldOwners := oldMeta.GetOwnerReferences() newOwners := newMeta.GetOwnerReferences() if len(oldOwners) != len(newOwners) { return true } for i := range oldOwners { if !api.Semantic.DeepEqual(oldOwners[i], newOwners[i]) { return true } } return false }
func annotateRuntimeObject(t *testing.T, originalObj, currentObj runtime.Object, kind string) (string, []byte) { originalAccessor, err := meta.Accessor(originalObj) if err != nil { t.Fatal(err) } originalLabels := originalAccessor.GetLabels() originalLabels["DELETE_ME"] = "DELETE_ME" originalAccessor.SetLabels(originalLabels) original, err := json.Marshal(originalObj) if err != nil { t.Fatal(err) } currentAccessor, err := meta.Accessor(currentObj) if err != nil { t.Fatal(err) } currentAnnotations := currentAccessor.GetAnnotations() if currentAnnotations == nil { currentAnnotations = make(map[string]string) } currentAnnotations[annotations.LastAppliedConfigAnnotation] = string(original) currentAccessor.SetAnnotations(currentAnnotations) current, err := json.Marshal(currentObj) if err != nil { t.Fatal(err) } return currentAccessor.GetName(), current }
func setFinalizersRuntimeObject(t *testing.T, originalObj, currentObj runtime.Object) (string, []byte) { originalAccessor, err := meta.Accessor(originalObj) if err != nil { t.Fatal(err) } originalFinalizers := []string{"a/a"} originalAccessor.SetFinalizers(originalFinalizers) original, err := runtime.Encode(testapi.Default.Codec(), originalObj) if err != nil { t.Fatal(err) } currentAccessor, err := meta.Accessor(currentObj) if err != nil { t.Fatal(err) } currentFinalizers := []string{"b/b"} currentAccessor.SetFinalizers(currentFinalizers) currentAnnotations := currentAccessor.GetAnnotations() if currentAnnotations == nil { currentAnnotations = make(map[string]string) } currentAnnotations[annotations.LastAppliedConfigAnnotation] = string(original) currentAccessor.SetAnnotations(currentAnnotations) current, err := runtime.Encode(testapi.Default.Codec(), currentObj) if err != nil { t.Fatal(err) } return currentAccessor.GetName(), current }
func TestControllerRoleLabel(t *testing.T) { roles := ControllerRoles() for i := range roles { role := roles[i] accessor, err := meta.Accessor(&role) if err != nil { t.Fatalf("unexpected error: %v", err) } if got, want := accessor.GetLabels(), map[string]string{"kubernetes.io/bootstrapping": "rbac-defaults"}; !reflect.DeepEqual(got, want) { t.Errorf("ClusterRole: %s GetLabels() = %s, want %s", accessor.GetName(), got, want) } } rolebindings := ControllerRoleBindings() for i := range rolebindings { rolebinding := rolebindings[i] accessor, err := meta.Accessor(&rolebinding) if err != nil { t.Fatalf("unexpected error: %v", err) } if got, want := accessor.GetLabels(), map[string]string{"kubernetes.io/bootstrapping": "rbac-defaults"}; !reflect.DeepEqual(got, want) { t.Errorf("ClusterRoleBinding: %s GetLabels() = %s, want %s", accessor.GetName(), got, want) } } }
func TestNoOpUpdates(t *testing.T) { server, registry := NewTestGenericStoreRegistry(t) defer server.Terminate(t) newPod := func() *api.Pod { return &api.Pod{ ObjectMeta: api.ObjectMeta{ Namespace: api.NamespaceDefault, Name: "foo", Labels: map[string]string{"prepare_create": "true"}, }, Spec: api.PodSpec{NodeName: "machine"}, } } var err error var createResult runtime.Object if createResult, err = registry.Create(api.NewDefaultContext(), newPod()); err != nil { t.Fatalf("Unexpected error: %v", err) } createdPod, err := registry.Get(api.NewDefaultContext(), "foo") if err != nil { t.Fatalf("Unexpected error: %v", err) } var updateResult runtime.Object p := newPod() if updateResult, _, err = registry.Update(api.NewDefaultContext(), p.Name, rest.DefaultUpdatedObjectInfo(p, api.Scheme)); err != nil { t.Fatalf("Unexpected error: %v", err) } // Check whether we do not return empty result on no-op update. if !reflect.DeepEqual(createResult, updateResult) { t.Errorf("no-op update should return a correct value, got: %#v", updateResult) } updatedPod, err := registry.Get(api.NewDefaultContext(), "foo") if err != nil { t.Fatalf("Unexpected error: %v", err) } createdMeta, err := meta.Accessor(createdPod) if err != nil { t.Fatalf("Unexpected error: %v", err) } updatedMeta, err := meta.Accessor(updatedPod) if err != nil { t.Fatalf("Unexpected error: %v", err) } if createdMeta.GetResourceVersion() != updatedMeta.GetResourceVersion() { t.Errorf("no-op update should be ignored and not written to etcd") } }
// ObjectReaction returns a ReactionFunc that takes a generic action string of the form // <verb>-<resource> or <verb>-<subresource>-<resource> and attempts to return a runtime // Object or error that matches the requested action. For instance, list-replicationControllers // should attempt to return a list of replication controllers. This method delegates to the // ObjectRetriever interface to satisfy retrieval of lists or retrieval of single items. // TODO: add support for sub resources func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc { return func(action Action) (bool, runtime.Object, error) { resource := action.GetResource() kind, err := mapper.KindFor(resource) // 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. kind.Version = resource.Version if err != nil { return false, nil, fmt.Errorf("unrecognized action %s: %v", action.GetResource(), err) } // TODO: have mapper return a Kind for a subresource? switch castAction := action.(type) { case ListAction: kind.Kind += "List" resource, err := o.Kind(kind, "") return true, resource, err case GetAction: resource, err := o.Kind(kind, castAction.GetName()) return true, resource, err case DeleteAction: resource, err := o.Kind(kind, castAction.GetName()) return true, resource, err case CreateAction: accessor, err := meta.Accessor(castAction.GetObject()) if err != nil { return true, nil, err } resource, err := o.Kind(kind, accessor.GetName()) return true, resource, err case UpdateAction: accessor, err := meta.Accessor(castAction.GetObject()) if err != nil { return true, nil, err } resource, err := o.Kind(kind, accessor.GetName()) return true, resource, err default: return false, nil, fmt.Errorf("no reaction implemented for %s", action) } } }
// storeObjectUpdate updates given cache with a new object version from Informer // callback (i.e. with events from etcd) or with an object modified by the // controller itself. Returns "true", if the cache was updated, false if the // object is an old version and should be ignored. func storeObjectUpdate(store cache.Store, obj interface{}, className string) (bool, error) { objAccessor, err := meta.Accessor(obj) if err != nil { return false, fmt.Errorf("Error reading cache of %s: %v", className, err) } objName := objAccessor.GetNamespace() + "/" + objAccessor.GetName() oldObj, found, err := store.Get(obj) if err != nil { return false, fmt.Errorf("Error finding %s %q in controller cache: %v", className, objName, err) } if !found { // This is a new object glog.V(4).Infof("storeObjectUpdate: adding %s %q, version %s", className, objName, objAccessor.GetResourceVersion()) if err = store.Add(obj); err != nil { return false, fmt.Errorf("Error adding %s %q to controller cache: %v", className, objName, err) } return true, nil } oldObjAccessor, err := meta.Accessor(oldObj) if err != nil { return false, err } objResourceVersion, err := strconv.ParseInt(objAccessor.GetResourceVersion(), 10, 64) if err != nil { return false, fmt.Errorf("Error parsing ResourceVersion %q of %s %q: %s", objAccessor.GetResourceVersion(), className, objName, err) } oldObjResourceVersion, err := strconv.ParseInt(oldObjAccessor.GetResourceVersion(), 10, 64) if err != nil { return false, fmt.Errorf("Error parsing old ResourceVersion %q of %s %q: %s", oldObjAccessor.GetResourceVersion(), className, objName, err) } // Throw away only older version, let the same version pass - we do want to // get periodic sync events. if oldObjResourceVersion > objResourceVersion { glog.V(4).Infof("storeObjectUpdate: ignoring %s %q version %s", className, objName, objAccessor.GetResourceVersion()) return false, nil } glog.V(4).Infof("storeObjectUpdate updating %s %q with version %s", className, objName, objAccessor.GetResourceVersion()) if err = store.Update(obj); err != nil { return false, fmt.Errorf("Error updating %s %q in controller cache: %v", className, objName, err) } return true, nil }
// getChangeCause returns the change-cause annotation of the input object func getChangeCause(obj runtime.Object) string { accessor, err := meta.Accessor(obj) if err != nil { return "" } return accessor.GetAnnotations()[ChangeCauseAnnotation] }
func GetPodFromTemplate(template *v1.PodTemplateSpec, parentObject runtime.Object, controllerRef *metav1.OwnerReference) (*v1.Pod, error) { desiredLabels := getPodsLabelSet(template) desiredFinalizers := getPodsFinalizers(template) desiredAnnotations, err := getPodsAnnotationSet(template, parentObject) if err != nil { return nil, err } accessor, err := meta.Accessor(parentObject) if err != nil { return nil, fmt.Errorf("parentObject does not have ObjectMeta, %v", err) } prefix := getPodsPrefix(accessor.GetName()) pod := &v1.Pod{ ObjectMeta: v1.ObjectMeta{ Labels: desiredLabels, Annotations: desiredAnnotations, GenerateName: prefix, Finalizers: desiredFinalizers, }, } if controllerRef != nil { pod.OwnerReferences = append(pod.OwnerReferences, *controllerRef) } clone, err := api.Scheme.DeepCopy(&template.Spec) if err != nil { return nil, err } pod.Spec = *clone.(*v1.PodSpec) return pod, nil }
func (t *tracker) Delete(gvk schema.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(schema.GroupResource{Group: gvk.Group, Resource: gvk.Kind}, name) }
// 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 }
// getEvent returns next item in the event queue which satisfies item version greater than given start version // checkCondition is an optimization that ignores version check when it is not needed func getEvent(eventQueue *oscache.EventQueue, startVersion uint64, checkCondition *bool) (watch.EventType, interface{}, error) { if *checkCondition { // Ignore all events with version <= given start version for { eventType, obj, err := eventQueue.Pop() if err != nil { return watch.Error, nil, err } accessor, err := meta.Accessor(obj) if err != nil { return watch.Error, nil, err } currentVersion, err := strconv.ParseUint(accessor.GetResourceVersion(), 10, 64) if err != nil { return watch.Error, nil, err } if currentVersion <= startVersion { log.V(5).Infof("Ignoring %s with version %d, start version: %d", accessor.GetName(), currentVersion, startVersion) continue } *checkCondition = false return eventType, obj, nil } } else { return eventQueue.Pop() } }
func setNamespace(typer runtime.ObjectTyper, obj runtime.Object, namespace string) error { itemMeta, err := meta.Accessor(obj) if err != nil { return err } gvks, _, err := typer.ObjectKinds(obj) if err != nil { return err } group, err := registered.Group(gvks[0].Group) if err != nil { return err } mapping, err := group.RESTMapper.RESTMapping(gvks[0].GroupKind(), gvks[0].Version) if err != nil { return err } switch mapping.Scope.Name() { case meta.RESTScopeNameNamespace: if len(itemMeta.GetNamespace()) == 0 { itemMeta.SetNamespace(namespace) } } return nil }
func NamespaceKeyFunc(prefix string, obj runtime.Object) (string, error) { meta, err := meta.Accessor(obj) if err != nil { return "", err } return prefix + "/" + meta.Namespace() + "/" + 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 { glog.Warningf("%s: watch of %v ended with: %v", r.name, r.expectedType, err) } return } } }
func TestFiltering(t *testing.T) { server, etcdStorage := newEtcdTestStorage(t, testapi.Default.Codec(), etcdtest.PathPrefix()) defer server.Terminate(t) cacher := newTestCacher(etcdStorage) defer cacher.Stop() // Ensure that the cacher is initialized, before creating any pods, // so that we are sure that all events will be present in cacher. syncWatcher, err := cacher.Watch(context.TODO(), "pods/ns/foo", "0", storage.Everything) if err != nil { t.Fatalf("Unexpected error: %v", err) } syncWatcher.Stop() podFoo := makeTestPod("foo") podFoo.Labels = map[string]string{"filter": "foo"} podFooFiltered := makeTestPod("foo") podFooPrime := makeTestPod("foo") podFooPrime.Labels = map[string]string{"filter": "foo"} podFooPrime.Spec.NodeName = "fakeNode" podFooNS2 := makeTestPod("foo") podFooNS2.Namespace += "2" podFooNS2.Labels = map[string]string{"filter": "foo"} // Create in another namespace first to make sure events from other namespaces don't get delivered updatePod(t, etcdStorage, podFooNS2, nil) fooCreated := updatePod(t, etcdStorage, podFoo, nil) fooFiltered := updatePod(t, etcdStorage, podFooFiltered, fooCreated) fooUnfiltered := updatePod(t, etcdStorage, podFoo, fooFiltered) _ = updatePod(t, etcdStorage, podFooPrime, fooUnfiltered) deleted := api.Pod{} if err := etcdStorage.Delete(context.TODO(), etcdtest.AddPrefix("pods/ns/foo"), &deleted, nil); err != nil { t.Errorf("Unexpected error: %v", err) } // Set up Watch for object "podFoo" with label filter set. selector := labels.SelectorFromSet(labels.Set{"filter": "foo"}) filterFunc := func(obj runtime.Object) bool { metadata, err := meta.Accessor(obj) if err != nil { t.Errorf("Unexpected error: %v", err) return false } return selector.Matches(labels.Set(metadata.GetLabels())) } filter := storage.NewSimpleFilter(filterFunc, storage.NoTriggerFunc) watcher, err := cacher.Watch(context.TODO(), "pods/ns/foo", fooCreated.ResourceVersion, filter) if err != nil { t.Fatalf("Unexpected error: %v", err) } defer watcher.Stop() verifyWatchEvent(t, watcher, watch.Deleted, podFooFiltered) verifyWatchEvent(t, watcher, watch.Added, podFoo) verifyWatchEvent(t, watcher, watch.Modified, podFooPrime) verifyWatchEvent(t, watcher, watch.Deleted, podFooPrime) }
// BenchmarkAccessorSetReflection provides a baseline for accessor performance func BenchmarkAccessorSetReflection(b *testing.B) { obj := &InternalObject{ InternalTypeMeta{ Namespace: "bar", Name: "foo", GenerateName: "prefix", UID: "uid", APIVersion: "a", Kind: "b", ResourceVersion: "1", SelfLink: "some/place/only/we/know", Labels: map[string]string{"foo": "bar"}, Annotations: map[string]string{"x": "y"}, }, } b.ResetTimer() for i := 0; i < b.N; i++ { acc, err := meta.Accessor(obj) if err != nil { b.Fatal(err) } acc.SetNamespace("something") } b.StopTimer() }
func (r RealPodControl) createPods(nodeName, namespace string, template *api.PodTemplateSpec, object runtime.Object) error { pod, err := GetPodFromTemplate(template, object) if err != nil { return err } if len(nodeName) != 0 { pod.Spec.NodeName = nodeName } if labels.Set(pod.Labels).AsSelector().Empty() { return fmt.Errorf("unable to create pods, no labels") } if newPod, err := r.KubeClient.Core().Pods(namespace).Create(pod); err != nil { r.Recorder.Eventf(object, api.EventTypeWarning, "FailedCreate", "Error creating: %v", err) return fmt.Errorf("unable to create pods: %v", err) } else { accessor, err := meta.Accessor(object) if err != nil { glog.Errorf("parentObject does not have ObjectMeta, %v", err) return nil } glog.V(4).Infof("Controller %v created pod %v", accessor.GetName(), newPod.Name) r.Recorder.Eventf(object, api.EventTypeNormal, "SuccessfulCreate", "Created pod: %v", newPod.Name) } return nil }
func GetPodFromTemplate(template *api.PodTemplateSpec, parentObject runtime.Object, controllerRef *api.OwnerReference) (*api.Pod, error) { desiredLabels := getPodsLabelSet(template) desiredAnnotations, err := getPodsAnnotationSet(template, parentObject) if err != nil { return nil, err } accessor, err := meta.Accessor(parentObject) if err != nil { return nil, fmt.Errorf("parentObject does not have ObjectMeta, %v", err) } prefix := getPodsPrefix(accessor.GetName()) pod := &api.Pod{ ObjectMeta: api.ObjectMeta{ Labels: desiredLabels, Annotations: desiredAnnotations, GenerateName: prefix, }, } if controllerRef != nil { pod.OwnerReferences = append(pod.OwnerReferences, *controllerRef) } if err := api.Scheme.Convert(&template.Spec, &pod.Spec); err != nil { return nil, fmt.Errorf("unable to convert pod template: %v", err) } return pod, nil }
// updateTaints updates taints of obj func (o TaintOptions) updateTaints(obj runtime.Object) error { accessor, err := meta.Accessor(obj) if err != nil { return err } if !o.overwrite { if err := validateNoTaintOverwrites(accessor, o.taintsToAdd); err != nil { return err } } annotations := accessor.GetAnnotations() if annotations == nil { annotations = make(map[string]string) } newTaints, err := reorganizeTaints(accessor, o.overwrite, o.taintsToAdd, o.taintsToRemove) if err != nil { return err } taintsData, err := json.Marshal(newTaints) if err != nil { return err } annotations[api.TaintsAnnotationKey] = string(taintsData) accessor.SetAnnotations(annotations) return nil }
// updateAnnotations updates annotations of obj func (o AnnotateOptions) updateAnnotations(obj runtime.Object) error { accessor, err := meta.Accessor(obj) if err != nil { return err } if !o.overwrite { if err := validateNoAnnotationOverwrites(accessor, o.newAnnotations); err != nil { return err } } annotations := accessor.GetAnnotations() if annotations == nil { annotations = make(map[string]string) } for key, value := range o.newAnnotations { annotations[key] = value } for _, annotation := range o.removeAnnotations { delete(annotations, annotation) } accessor.SetAnnotations(annotations) if len(o.resourceVersion) != 0 { accessor.SetResourceVersion(o.resourceVersion) } return nil }
func labelFunc(obj runtime.Object, overwrite bool, resourceVersion string, labels map[string]string, remove []string) error { accessor, err := meta.Accessor(obj) if err != nil { return err } if !overwrite { if err := validateNoOverwrites(accessor, labels); err != nil { return err } } objLabels := accessor.GetLabels() if objLabels == nil { objLabels = make(map[string]string) } for key, value := range labels { objLabels[key] = value } for _, label := range remove { delete(objLabels, label) } accessor.SetLabels(objLabels) if len(resourceVersion) != 0 { accessor.SetResourceVersion(resourceVersion) } return nil }
// watchForResourceVersion watches for an Add/Modify event matching the given resourceVersion. // If an error, timeout, or unexpected event is received, an error is returned. // If an add/modify event is observed with the correct resource version, nil is returned. func watchForResourceVersion(versioner storage.Versioner, watcher rest.Watcher, resourceVersion string, timeout time.Duration) error { // Watch from the previous resource version, so the first watch event is the desired version previousVersion, err := previousResourceVersion(versioner, resourceVersion) if err != nil { return err } w, err := watcher.Watch(context.TODO(), &kapi.ListOptions{ResourceVersion: previousVersion}) if err != nil { return fmt.Errorf("error verifying resourceVersion %s: %v", resourceVersion, err) } defer w.Stop() select { case event := <-w.ResultChan(): if event.Type != watch.Added && event.Type != watch.Modified { return fmt.Errorf("unexpected watch event verifying resourceVersion %s: %q", resourceVersion, event.Type) } if event.Object == nil { return fmt.Errorf("unexpected watch event verifying resourceVersion %s: object was nil", resourceVersion) } accessor, err := meta.Accessor(event.Object) if err != nil { return err } actualResourceVersion := accessor.GetResourceVersion() if actualResourceVersion != resourceVersion { return fmt.Errorf("unexpected watch event verifying resourceVersion %s: resource version was %s)", resourceVersion, actualResourceVersion) } return nil case <-time.After(timeout): return fmt.Errorf("timeout verifying resourceVersion %s", resourceVersion) } }
func TestParseFederationReplicaSetReference(t *testing.T) { successPrefs := []string{ `{"rebalance": true, "clusters": { "k8s-1": {"minReplicas": 10, "maxReplicas": 20, "weight": 2}, "*": {"weight": 1} }}`, } failedPrefes := []string{ `{`, // bad json } rs := newReplicaSetWithReplicas("rs-1", 100) accessor, _ := meta.Accessor(rs) anno := accessor.GetAnnotations() if anno == nil { anno = make(map[string]string) accessor.SetAnnotations(anno) } for _, prefString := range successPrefs { anno[FedReplicaSetPreferencesAnnotation] = prefString pref, err := parseFederationReplicaSetReference(rs) assert.NotNil(t, pref) assert.Nil(t, err) } for _, prefString := range failedPrefes { anno[FedReplicaSetPreferencesAnnotation] = prefString pref, err := parseFederationReplicaSetReference(rs) assert.Nil(t, pref) assert.NotNil(t, err) } }
// getControllerRef returns a subresource reference to the owning controller of the given object. // It will use both the CreatedByAnnotation from Kubernetes, as well as the DeploymentConfigAnnotation // from Origin to look this up. If neither are found, it will return nil. func getControllerRef(obj runtime.Object, decoder runtime.Decoder) (*kapi.ObjectReference, error) { objMeta, err := meta.Accessor(obj) if err != nil { return nil, err } annotations := objMeta.GetAnnotations() creatorRefRaw, creatorListed := annotations[kapi.CreatedByAnnotation] if !creatorListed { // if we don't have a creator listed, try the openshift-specific Deployment annotation dcName, dcNameListed := annotations[deployapi.DeploymentConfigAnnotation] if !dcNameListed { return nil, nil } return &kapi.ObjectReference{ Name: dcName, Namespace: objMeta.GetNamespace(), Kind: "DeploymentConfig", }, nil } serializedRef := &kapi.SerializedReference{} if err := runtime.DecodeInto(decoder, []byte(creatorRefRaw), serializedRef); err != nil { return nil, fmt.Errorf("could not decoded pod's creator reference: %v", err) } return &serializedRef.Reference, nil }
// UsageStats calculates latest observed usage stats for all objects func (g *GenericEvaluator) UsageStats(options quota.UsageStatsOptions) (quota.UsageStats, error) { // default each tracked resource to zero result := quota.UsageStats{Used: api.ResourceList{}} for _, resourceName := range g.MatchedResourceNames { result.Used[resourceName] = resource.MustParse("0") } list, err := g.ListFuncByNamespace(options.Namespace, api.ListOptions{}) if err != nil { return result, fmt.Errorf("%s: Failed to list %v: %v", g.Name, g.GroupKind(), err) } _, err = meta.Accessor(list) if err != nil { return result, fmt.Errorf("%s: Unable to understand list result %#v", g.Name, list) } items, err := meta.ExtractList(list) if err != nil { return result, fmt.Errorf("%s: Unable to understand list result %#v (%v)", g.Name, list, err) } for _, item := range items { // need to verify that the item matches the set of scopes matchesScopes := true for _, scope := range options.Scopes { if !g.MatchesScope(scope, item) { matchesScopes = false } } // only count usage if there was a match if matchesScopes { result.Used = quota.Add(result.Used, g.Usage(item)) } } return result, nil }
func shouldOrphanDependents(e event, accessor meta.Object) bool { // The delta_fifo may combine the creation and update of the object into one // event, so we need to check AddEvent as well. if e.oldObj == nil { if accessor.GetDeletionTimestamp() == nil { return false } } else { oldAccessor, err := meta.Accessor(e.oldObj) if err != nil { utilruntime.HandleError(fmt.Errorf("cannot access oldObj: %v", err)) return false } // ignore the event if it's not updating DeletionTimestamp from non-nil to nil. if accessor.GetDeletionTimestamp() == nil || oldAccessor.GetDeletionTimestamp() != nil { return false } } finalizers := accessor.GetFinalizers() for _, finalizer := range finalizers { if finalizer == api.FinalizerOrphan { return true } } return false }
// 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 != 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 }
// ObjectReaction returns a ReactionFunc that takes a generic action string of the form // <verb>-<resource> or <verb>-<subresource>-<resource> and attempts to return a runtime // Object or error that matches the requested action. For instance, list-replicationControllers // should attempt to return a list of replication controllers. This method delegates to the // ObjectRetriever interface to satisfy retrieval of lists or retrieval of single items. // TODO: add support for sub resources func ObjectReaction(o ObjectRetriever, mapper meta.RESTMapper) ReactionFunc { return func(action Action) (bool, runtime.Object, error) { kind, err := mapper.KindFor(unversioned.GroupVersionResource{Resource: action.GetResource()}) if err != nil { return false, nil, fmt.Errorf("unrecognized action %s: %v", action.GetResource(), err) } // TODO: have mapper return a Kind for a subresource? switch castAction := action.(type) { case ListAction: kind.Kind += "List" resource, err := o.Kind(kind, "") return true, resource, err case GetAction: resource, err := o.Kind(kind, castAction.GetName()) return true, resource, err case DeleteAction: resource, err := o.Kind(kind, castAction.GetName()) return true, resource, err case CreateAction: accessor, err := meta.Accessor(castAction.GetObject()) if err != nil { return true, nil, err } resource, err := o.Kind(kind, accessor.GetName()) return true, resource, err case UpdateAction: accessor, err := meta.Accessor(castAction.GetObject()) if err != nil { return true, nil, err } resource, err := o.Kind(kind, accessor.GetName()) return true, resource, err default: return false, nil, fmt.Errorf("no reaction implemented for %s", action) } return true, nil, nil } }