// RunOnce verifies the state of allocations and returns an error if an unrecoverable problem occurs. func (c *Repair) RunOnce() error { // TODO: (per smarterclayton) if Get() or List() is a weak consistency read, // or if they are executed against different leaders, // the ordering guarantee required to ensure no item is allocated twice is violated. // List must return a ResourceVersion higher than the etcd index Get, // and the release code must not release items that have allocated but not yet been created // See #8295 latest, err := c.alloc.Get() if err != nil { return fmt.Errorf("unable to refresh the security allocation UID blocks: %v", err) } list, err := c.client.List(kapi.ListOptions{}) if err != nil { return fmt.Errorf("unable to refresh the security allocation UID blocks: %v", err) } uids := uidallocator.NewInMemory(c.uidRange) for _, ns := range list.Items { value, ok := ns.Annotations[security.UIDRangeAnnotation] if !ok { continue } block, err := uid.ParseBlock(value) if err != nil { continue } switch err := uids.Allocate(block); err { case nil: case uidallocator.ErrNotInRange, uidallocator.ErrAllocated: continue case uidallocator.ErrFull: // TODO: send event return fmt.Errorf("the UID range %s is full; you must widen the range in order to allocate more UIDs", c.uidRange) default: return fmt.Errorf("unable to allocate UID block %s for namespace %s due to an unknown error, exiting: %v", block, ns.Name, err) } } err = uids.Snapshot(latest) if err != nil { return fmt.Errorf("unable to persist the updated namespace UID allocations: %v", err) } if err := c.alloc.CreateOrUpdate(latest); err != nil { return fmt.Errorf("unable to persist the updated namespace UID allocations: %v", err) } return nil }
// parseSupplementalGroupAnnotation parses the group annotation into blocks. func parseSupplementalGroupAnnotation(groups string) ([]uid.Block, error) { blocks := []uid.Block{} segments := strings.Split(groups, ",") for _, segment := range segments { block, err := uid.ParseBlock(segment) if err != nil { return nil, err } blocks = append(blocks, block) } if len(blocks) == 0 { return nil, fmt.Errorf("no blocks parsed from annotation %s", groups) } return blocks, nil }
// getPreallocatedUIDRange retrieves the annotated value from the service account, splits it to make // the min/max and formats the data into the necessary types for the strategy options. func getPreallocatedUIDRange(ns *kapi.Namespace) (*int64, *int64, error) { annotationVal, ok := ns.Annotations[allocator.UIDRangeAnnotation] if !ok { return nil, nil, fmt.Errorf("unable to find annotation %s", allocator.UIDRangeAnnotation) } if len(annotationVal) == 0 { return nil, nil, fmt.Errorf("found annotation %s but it was empty", allocator.UIDRangeAnnotation) } uidBlock, err := uid.ParseBlock(annotationVal) if err != nil { return nil, nil, err } var min int64 = int64(uidBlock.Start) var max int64 = int64(uidBlock.End) glog.V(4).Infof("got preallocated values for min: %d, max: %d for uid range in namespace %s", min, max, ns.Name) return &min, &max, nil }