// // Traverse the PVs, fetching all the GIDs from those // in a given storage class, and mark them in the table. // func (p *glusterfsPlugin) collectGids(className string, gidTable *MinMaxAllocator) error { kubeClient := p.host.GetKubeClient() if kubeClient == nil { return fmt.Errorf("glusterfs: failed to get kube client when collecting gids") } pvList, err := kubeClient.Core().PersistentVolumes().List(v1.ListOptions{LabelSelector: labels.Everything().String()}) if err != nil { glog.Errorf("glusterfs: failed to get existing persistent volumes") return err } for _, pv := range pvList.Items { if storageutil.GetVolumeStorageClass(&pv) != className { continue } pvName := pv.ObjectMeta.Name gidStr, ok := pv.Annotations[volumehelper.VolumeGidAnnotationKey] if !ok { glog.Warningf("glusterfs: no gid found in pv '%v'", pvName) continue } gid, err := convertGid(gidStr) if err != nil { glog.Error(err) continue } _, err = gidTable.Allocate(gid) if err == ErrConflict { glog.Warningf("glusterfs: gid %v found in pv %v was already allocated", gid) } else if err != nil { glog.Errorf("glusterfs: failed to store gid %v found in pv '%v': %v", gid, pvName, err) return err } } return nil }
// find returns the nearest PV from the ordered list or nil if a match is not found func (pvIndex *persistentVolumeOrderedIndex) findByClaim(claim *v1.PersistentVolumeClaim, matchPredicate matchPredicate) (*v1.PersistentVolume, error) { // PVs are indexed by their access modes to allow easier searching. Each // index is the string representation of a set of access modes. There is a // finite number of possible sets and PVs will only be indexed in one of // them (whichever index matches the PV's modes). // // A request for resources will always specify its desired access modes. // Any matching PV must have at least that number of access modes, but it // can have more. For example, a user asks for ReadWriteOnce but a GCEPD // is available, which is ReadWriteOnce+ReadOnlyMany. // // Searches are performed against a set of access modes, so we can attempt // not only the exact matching modes but also potential matches (the GCEPD // example above). allPossibleModes := pvIndex.allPossibleMatchingAccessModes(claim.Spec.AccessModes) var smallestVolume *v1.PersistentVolume var smallestVolumeSize int64 requestedQty := claim.Spec.Resources.Requests[v1.ResourceName(v1.ResourceStorage)] requestedSize := requestedQty.Value() requestedClass := storageutil.GetClaimStorageClass(claim) var selector labels.Selector if claim.Spec.Selector != nil { internalSelector, err := metav1.LabelSelectorAsSelector(claim.Spec.Selector) if err != nil { // should be unreachable code due to validation return nil, fmt.Errorf("error creating internal label selector for claim: %v: %v", claimToClaimKey(claim), err) } selector = internalSelector } for _, modes := range allPossibleModes { volumes, err := pvIndex.listByAccessModes(modes) if err != nil { return nil, err } // Go through all available volumes with two goals: // - find a volume that is either pre-bound by user or dynamically // provisioned for this claim. Because of this we need to loop through // all volumes. // - find the smallest matching one if there is no volume pre-bound to // the claim. for _, volume := range volumes { if isVolumeBoundToClaim(volume, claim) { // this claim and volume are pre-bound; return // the volume if the size request is satisfied, // otherwise continue searching for a match volumeQty := volume.Spec.Capacity[v1.ResourceStorage] volumeSize := volumeQty.Value() if volumeSize < requestedSize { continue } return volume, nil } // In Alpha dynamic provisioning, we do now want not match claims // with existing PVs, findByClaim must find only PVs that are // pre-bound to the claim (by dynamic provisioning). TODO: remove in // 1.5 if metav1.HasAnnotation(claim.ObjectMeta, storageutil.AlphaStorageClassAnnotation) { continue } // filter out: // - volumes bound to another claim // - volumes whose labels don't match the claim's selector, if specified // - volumes in Class that is not requested if volume.Spec.ClaimRef != nil { continue } else if selector != nil && !selector.Matches(labels.Set(volume.Labels)) { continue } if storageutil.GetVolumeStorageClass(volume) != requestedClass { continue } volumeQty := volume.Spec.Capacity[v1.ResourceStorage] volumeSize := volumeQty.Value() if volumeSize >= requestedSize { if smallestVolume == nil || smallestVolumeSize > volumeSize { smallestVolume = volume smallestVolumeSize = volumeSize } } } if smallestVolume != nil { // Found a matching volume return smallestVolume, nil } } return nil, nil }