github.com/openshift/installer@v1.4.17/pkg/quota/quota.go (about)

     1  package quota
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"strings"
     8  )
     9  
    10  // Quota stores the used and limit for a resouce's quota.
    11  type Quota struct {
    12  	Service string
    13  	Name    string
    14  	Region  string
    15  
    16  	InUse int64
    17  	Limit int64
    18  
    19  	Unlimited bool
    20  }
    21  
    22  // Constraint defines a check against availablity
    23  // for a resource quota.
    24  type Constraint struct {
    25  	Name string
    26  	// This should be global or specific region.
    27  	Region string
    28  	// Count is the number of the resource that is required
    29  	// to be free for use.
    30  	Count int64
    31  }
    32  
    33  // ConstraintReportResult provide one word result for the constraint
    34  type ConstraintReportResult string
    35  
    36  const (
    37  	// Available corresponds to a constraint that is available.
    38  	Available ConstraintReportResult = "Available"
    39  	// AvailableButLow corresponds to a constraint that is available but there is very low overhead after satisfying the constraint.
    40  	AvailableButLow ConstraintReportResult = "AvailableButLow"
    41  	// NotAvailable corresponds to a constraint that is not available.
    42  	NotAvailable ConstraintReportResult = "NotAvailable"
    43  	// Unknown corresponds to a constraint that could not be calculated.
    44  	Unknown ConstraintReportResult = "Unknown"
    45  )
    46  
    47  // ConstraintReport provides result for a given constraint.
    48  type ConstraintReport struct {
    49  	For     *Constraint
    50  	Result  ConstraintReportResult
    51  	Message string
    52  }
    53  
    54  // Check returns whether the checks constraints are possible gives the quotas.
    55  // It returns an erros when any one of the constraint's result was `NotAvailable` or `Unknown`
    56  func Check(quotas []Quota, checks []Constraint) ([]ConstraintReport, error) {
    57  	reports := make([]ConstraintReport, 0, len(checks))
    58  
    59  	match := func(check Constraint) (Quota, bool) {
    60  		for _, q := range quotas {
    61  			if !strings.EqualFold(check.Name, q.Name) {
    62  				continue
    63  			}
    64  			if !strings.EqualFold(q.Region, check.Region) {
    65  				continue
    66  			}
    67  			return q, true
    68  		}
    69  		return Quota{}, false
    70  	}
    71  
    72  	for idx, check := range checks {
    73  		report := ConstraintReport{
    74  			For: &checks[idx],
    75  		}
    76  		matched, ok := match(check)
    77  		if !ok {
    78  			report.Result = Unknown
    79  			report.Message = "No matching quota found for the constraint"
    80  			reports = append(reports, report)
    81  			continue
    82  		}
    83  
    84  		if matched.Unlimited {
    85  			report.Result = Available
    86  			report.Message = "Unlimited quota found for the constraint"
    87  			reports = append(reports, report)
    88  			continue
    89  		}
    90  
    91  		if check.Count > matched.Limit {
    92  			report.Result = NotAvailable
    93  			report.Message = fmt.Sprintf("the required number of resources (%d) is more than the limit of %d", check.Count, matched.Limit)
    94  			reports = append(reports, report)
    95  			continue
    96  		}
    97  
    98  		avail := matched.Limit - matched.InUse
    99  		availAfterUse := avail - check.Count
   100  		headroom := int64(math.Ceil(0.2 * float64(matched.Limit)))
   101  		if check.Count > avail {
   102  			report.Result = NotAvailable
   103  			report.Message = fmt.Sprintf("the required number of resources (%d) is more than remaining quota of %d", check.Count, avail)
   104  			reports = append(reports, report)
   105  			continue
   106  		}
   107  		if availAfterUse <= headroom {
   108  			report.Result = AvailableButLow
   109  			report.Message = fmt.Sprintf("the required number of resources is available but only %d will be leftover", availAfterUse)
   110  			reports = append(reports, report)
   111  			continue
   112  		}
   113  		report.Result = Available
   114  		report.Message = "the required number of resources is available"
   115  		reports = append(reports, report)
   116  	}
   117  
   118  	failed := 0
   119  	for _, r := range reports {
   120  		if r.Result == Unknown ||
   121  			r.Result == NotAvailable {
   122  			failed++
   123  		}
   124  	}
   125  	if failed > 0 {
   126  		return reports, errors.New("%d checks failed")
   127  	}
   128  
   129  	return reports, nil
   130  }