ResourceQuota support for hugepages

This commit is contained in:
lichuqiang 2017-11-13 09:37:06 +08:00
parent bfe581d9e5
commit e9ff036e8a
5 changed files with 78 additions and 3 deletions

View File

@ -37,6 +37,12 @@ func IsHugePageResourceName(name core.ResourceName) bool {
return strings.HasPrefix(string(name), core.ResourceHugePagesPrefix)
}
// IsQuotaHugePageResourceName returns true if the resource name has the quota
// related huge page resource prefix.
func IsQuotaHugePageResourceName(name core.ResourceName) bool {
return strings.HasPrefix(string(name), core.ResourceHugePagesPrefix) || strings.HasPrefix(string(name), core.ResourceRequestsHugePagesPrefix)
}
// HugePageResourceName returns a ResourceName with the canonical hugepage
// prefix prepended for the specified page size. The page size is converted
// to its canonical representation.
@ -217,7 +223,7 @@ var standardQuotaResources = sets.NewString(
// IsStandardQuotaResourceName returns true if the resource is known to
// the quota tracking system
func IsStandardQuotaResourceName(str string) bool {
return standardQuotaResources.Has(str)
return standardQuotaResources.Has(str) || IsQuotaHugePageResourceName(core.ResourceName(str))
}
var standardResources = sets.NewString(
@ -245,7 +251,7 @@ var standardResources = sets.NewString(
// IsStandardResourceName returns true if the resource is known to the system
func IsStandardResourceName(str string) bool {
return standardResources.Has(str) || IsHugePageResourceName(core.ResourceName(str))
return standardResources.Has(str) || IsQuotaHugePageResourceName(core.ResourceName(str))
}
var integerResources = sets.NewString(

View File

@ -3968,6 +3968,13 @@ const (
ResourceLimitsEphemeralStorage ResourceName = "limits.ephemeral-storage"
)
// The following identify resource prefix for Kubernetes object types
const (
// HugePages request, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// As burst is not supported for HugePages, we would only quota its request, and ignore the limit.
ResourceRequestsHugePagesPrefix = "requests.hugepages-"
)
// A ResourceQuotaScope defines a filter that must match each object tracked by a quota
type ResourceQuotaScope string

View File

@ -58,6 +58,30 @@ var podResources = []api.ResourceName{
api.ResourcePods,
}
// podResourcePrefixes are the set of prefixes for resources (Hugepages, and other
// potential extended reources with specific prefix) managed by quota associated with pods.
var podResourcePrefixes = []string{
api.ResourceHugePagesPrefix,
api.ResourceRequestsHugePagesPrefix,
}
// requestedResourcePrefixes are the set of prefixes for resources
// that might be declared in pod's Resources.Requests/Limits
var requestedResourcePrefixes = []string{
api.ResourceHugePagesPrefix,
}
const (
requestsPrefix = "requests."
limitsPrefix = "limits."
)
// maskResourceWithPrefix mask resource with certain prefix
// e.g. hugepages-XXX -> requests.hugepages-XXX
func maskResourceWithPrefix(resource api.ResourceName, prefix string) api.ResourceName {
return api.ResourceName(fmt.Sprintf("%s%s", prefix, string(resource)))
}
// NOTE: it was a mistake, but if a quota tracks cpu or memory related resources,
// the incoming pod is required to have those values set. we should not repeat
// this mistake for other future resources (gpus, ephemeral-storage,etc).
@ -157,7 +181,14 @@ func (p *podEvaluator) Matches(resourceQuota *api.ResourceQuota, item runtime.Ob
// MatchingResources takes the input specified list of resources and returns the set of resources it matches.
func (p *podEvaluator) MatchingResources(input []api.ResourceName) []api.ResourceName {
return quota.Intersection(input, podResources)
result := quota.Intersection(input, podResources)
for _, resource := range input {
if quota.ContainsPrefix(podResourcePrefixes, resource) {
result = append(result, resource)
}
}
return result
}
// Usage knows how to measure usage associated with pods
@ -212,6 +243,18 @@ func podComputeUsageHelper(requests api.ResourceList, limits api.ResourceList) a
if limit, found := limits[api.ResourceEphemeralStorage]; found {
result[api.ResourceLimitsEphemeralStorage] = limit
}
for resource, request := range requests {
if quota.ContainsPrefix(requestedResourcePrefixes, resource) {
result[resource] = request
result[maskResourceWithPrefix(resource, requestsPrefix)] = request
}
}
for resource, limit := range limits {
if quota.ContainsPrefix(requestedResourcePrefixes, resource) {
result[maskResourceWithPrefix(resource, limitsPrefix)] = limit
}
}
return result
}

View File

@ -17,6 +17,8 @@ limitations under the License.
package quota
import (
"strings"
"k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/util/sets"
@ -196,6 +198,16 @@ func Contains(items []api.ResourceName, item api.ResourceName) bool {
return ToSet(items).Has(string(item))
}
// ContainsPrefix returns true if the specified item has a prefix that contained in given prefix Set
func ContainsPrefix(prefixSet []string, item api.ResourceName) bool {
for _, prefix := range prefixSet {
if strings.HasPrefix(string(item), prefix) {
return true
}
}
return false
}
// Intersection returns the intersection of both list of resources
func Intersection(a []api.ResourceName, b []api.ResourceName) []api.ResourceName {
setA := ToSet(a)

View File

@ -4496,6 +4496,13 @@ const (
ResourceLimitsEphemeralStorage ResourceName = "limits.ephemeral-storage"
)
// The following identify resource prefix for Kubernetes object types
const (
// HugePages request, in bytes. (500Gi = 500GiB = 500 * 1024 * 1024 * 1024)
// As burst is not supported for HugePages, we would only quota its request, and ignore the limit.
ResourceRequestsHugePagesPrefix = "requests.hugepages-"
)
// A ResourceQuotaScope defines a filter that must match each object tracked by a quota
type ResourceQuotaScope string