func (w *userProjectWatcher) GroupMembershipChanged(namespaceName string, users, groups sets.String) { if !w.visibleNamespaces.Has("*") && !w.visibleNamespaces.Has(namespaceName) { // this user is scoped to a level that shouldn't see this update return } hasAccess := users.Has(w.user.GetName()) || groups.HasAny(w.user.GetGroups()...) _, known := w.knownProjects[namespaceName] switch { // this means that we were removed from the project case !hasAccess && known: delete(w.knownProjects, namespaceName) select { case w.cacheIncoming <- watch.Event{ Type: watch.Deleted, Object: projectutil.ConvertNamespace(&kapi.Namespace{ObjectMeta: kapi.ObjectMeta{Name: namespaceName}}), }: default: // remove the watcher so that we wont' be notified again and block w.authCache.RemoveWatcher(w) w.cacheError <- errors.New("delete notification timeout") } case hasAccess: namespace, err := w.projectCache.GetNamespace(namespaceName) if err != nil { utilruntime.HandleError(err) return } event := watch.Event{ Type: watch.Added, Object: projectutil.ConvertNamespace(namespace), } // if we already have this in our list, then we're getting notified because the object changed if lastResourceVersion, known := w.knownProjects[namespaceName]; known { event.Type = watch.Modified // if we've already notified for this particular resourceVersion, there's no work to do if lastResourceVersion == namespace.ResourceVersion { return } } w.knownProjects[namespaceName] = namespace.ResourceVersion select { case w.cacheIncoming <- event: default: // remove the watcher so that we won't be notified again and block w.authCache.RemoveWatcher(w) w.cacheError <- errors.New("add notification timeout") } } }
func (w *userProjectWatcher) GroupMembershipChanged(namespaceName string, latestUsers, lastestGroups, removedUsers, removedGroups, addedUsers, addedGroups sets.String) { hasAccess := latestUsers.Has(w.username) || lastestGroups.HasAny(w.groups...) removed := !hasAccess && (removedUsers.Has(w.username) || removedGroups.HasAny(w.groups...)) switch { case removed: if _, known := w.knownProjects[namespaceName]; !known { return } delete(w.knownProjects, namespaceName) select { case w.cacheIncoming <- watch.Event{ Type: watch.Deleted, Object: projectutil.ConvertNamespace(&kapi.Namespace{ObjectMeta: kapi.ObjectMeta{Name: namespaceName}}), }: default: // remove the watcher so that we wont' be notified again and block w.authCache.RemoveWatcher(w) w.cacheError <- errors.New("delete notification timeout") } case hasAccess: namespace, err := w.projectCache.GetNamespace(namespaceName) if err != nil { utilruntime.HandleError(err) return } event := watch.Event{ Type: watch.Added, Object: projectutil.ConvertNamespace(namespace), } // if we already have this in our list, then we're getting notified because the object changed if lastResourceVersion, known := w.knownProjects[namespaceName]; known { event.Type = watch.Modified // if we've already notified for this particular resourceVersion, there's no work to do if lastResourceVersion == namespace.ResourceVersion { return } } w.knownProjects[namespaceName] = namespace.ResourceVersion select { case w.cacheIncoming <- event: default: // remove the watcher so that we won't be notified again and block w.authCache.RemoveWatcher(w) w.cacheError <- errors.New("add notification timeout") } } }
func (s *REST) Update(ctx kapi.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { oldObj, err := s.Get(ctx, name) if err != nil { return nil, false, err } obj, err := objInfo.UpdatedObject(ctx, oldObj) if err != nil { return nil, false, err } project, ok := obj.(*api.Project) if !ok { return nil, false, fmt.Errorf("not a project: %#v", obj) } s.updateStrategy.PrepareForUpdate(obj, oldObj) if errs := s.updateStrategy.ValidateUpdate(ctx, obj, oldObj); len(errs) > 0 { return nil, false, kerrors.NewInvalid(projectapi.Kind("Project"), project.Name, errs) } namespace, err := s.client.Update(projectutil.ConvertProject(project)) if err != nil { return nil, false, err } return projectutil.ConvertNamespace(namespace), false, nil }
// Get retrieves a Project by name func (s *REST) Get(ctx kapi.Context, name string) (runtime.Object, error) { namespace, err := s.client.Get(name) if err != nil { return nil, err } return projectutil.ConvertNamespace(namespace), nil }
// Create registers the given Project. func (s *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) { project, ok := obj.(*api.Project) if !ok { return nil, fmt.Errorf("not a project: %#v", obj) } kapi.FillObjectMetaSystemFields(ctx, &project.ObjectMeta) s.createStrategy.PrepareForCreate(obj) if errs := s.createStrategy.Validate(ctx, obj); len(errs) > 0 { return nil, kerrors.NewInvalid(projectapi.Kind("Project"), project.Name, errs) } namespace, err := s.client.Create(projectutil.ConvertProject(project)) if err != nil { return nil, err } return projectutil.ConvertNamespace(namespace), nil }
// Watch pulls stuff from etcd, converts, and pushes out the outgoing channel. Meant to be // called as a goroutine. func (w *userProjectWatcher) Watch() { defer close(w.outgoing) defer func() { // when the watch ends, always remove the watcher from the cache to avoid leaking. w.authCache.RemoveWatcher(w) }() defer utilruntime.HandleCrash() // start by emitting all the `initialProjects` for i := range w.initialProjects { // keep this check here to sure we don't keep this open in the case of failures select { case err := <-w.cacheError: w.emit(makeErrorEvent(err)) return default: } w.emit(watch.Event{ Type: watch.Added, Object: projectutil.ConvertNamespace(&w.initialProjects[i]), }) } for { select { case err := <-w.cacheError: w.emit(makeErrorEvent(err)) return case <-w.userStop: return case event := <-w.cacheIncoming: if curLen := int64(len(w.cacheIncoming)); watchChannelHWM.Update(curLen) { // Monitor if this gets backed up, and how much. glog.V(2).Infof("watch: %v objects queued in project cache watching channel.", curLen) } w.emit(event) } } }