mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-04 04:08:16 +00:00 
			
		
		
		
	Merge pull request #48922 from ConnorDoyle/integer-resources-as-default
Automatic merge from submit-queue (batch tested with PRs 46317, 48922, 50651, 50230, 47599) Resources outside the `*kubernetes.io` namespace are integers and cannot be over-committed. **What this PR does / why we need it**: Fixes #50473 Rationale: since the scheduler handles all resources except CPU as integers, that could just be the default behavior for namespaced resources. cc @RenaudWasTaken @vishh **Release note**: ```release-note Resources outside the `*kubernetes.io` namespace are integers and cannot be over-committed. ```
This commit is contained in:
		@@ -115,6 +115,21 @@ func IsStandardContainerResourceName(str string) bool {
 | 
				
			|||||||
	return standardContainerResources.Has(str)
 | 
						return standardContainerResources.Has(str)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsExtendedResourceName returns true if the resource name is not in the
 | 
				
			||||||
 | 
					// default namespace, or it has the opaque integer resource prefix.
 | 
				
			||||||
 | 
					func IsExtendedResourceName(name api.ResourceName) bool {
 | 
				
			||||||
 | 
						// TODO: Remove OIR part following deprecation.
 | 
				
			||||||
 | 
						return !IsDefaultNamespaceResource(name) || IsOpaqueIntResourceName(name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsDefaultNamespaceResource returns true if the resource name is in the
 | 
				
			||||||
 | 
					// *kubernetes.io/ namespace. Partially-qualified (unprefixed) names are
 | 
				
			||||||
 | 
					// implicitly in the kubernetes.io/ namespace.
 | 
				
			||||||
 | 
					func IsDefaultNamespaceResource(name api.ResourceName) bool {
 | 
				
			||||||
 | 
						return !strings.Contains(string(name), "/") ||
 | 
				
			||||||
 | 
							strings.Contains(string(name), api.ResourceDefaultNamespacePrefix)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsOpaqueIntResourceName returns true if the resource name has the opaque
 | 
					// IsOpaqueIntResourceName returns true if the resource name has the opaque
 | 
				
			||||||
// integer resource prefix.
 | 
					// integer resource prefix.
 | 
				
			||||||
func IsOpaqueIntResourceName(name api.ResourceName) bool {
 | 
					func IsOpaqueIntResourceName(name api.ResourceName) bool {
 | 
				
			||||||
@@ -131,6 +146,15 @@ func OpaqueIntResourceName(name string) api.ResourceName {
 | 
				
			|||||||
	return api.ResourceName(fmt.Sprintf("%s%s", api.ResourceOpaqueIntPrefix, name))
 | 
						return api.ResourceName(fmt.Sprintf("%s%s", api.ResourceOpaqueIntPrefix, name))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var overcommitBlacklist = sets.NewString(string(api.ResourceNvidiaGPU))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsOvercommitAllowed returns true if the resource is in the default
 | 
				
			||||||
 | 
					// namespace and not blacklisted.
 | 
				
			||||||
 | 
					func IsOvercommitAllowed(name api.ResourceName) bool {
 | 
				
			||||||
 | 
						return IsDefaultNamespaceResource(name) &&
 | 
				
			||||||
 | 
							!overcommitBlacklist.Has(string(name))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var standardLimitRangeTypes = sets.NewString(
 | 
					var standardLimitRangeTypes = sets.NewString(
 | 
				
			||||||
	string(api.LimitTypePod),
 | 
						string(api.LimitTypePod),
 | 
				
			||||||
	string(api.LimitTypeContainer),
 | 
						string(api.LimitTypeContainer),
 | 
				
			||||||
@@ -204,7 +228,7 @@ var integerResources = sets.NewString(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// IsIntegerResourceName returns true if the resource is measured in integer values
 | 
					// IsIntegerResourceName returns true if the resource is measured in integer values
 | 
				
			||||||
func IsIntegerResourceName(str string) bool {
 | 
					func IsIntegerResourceName(str string) bool {
 | 
				
			||||||
	return integerResources.Has(str) || IsOpaqueIntResourceName(api.ResourceName(str))
 | 
						return integerResources.Has(str) || IsExtendedResourceName(api.ResourceName(str))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// this function aims to check if the service's ClusterIP is set or not
 | 
					// this function aims to check if the service's ClusterIP is set or not
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3178,6 +3178,8 @@ const (
 | 
				
			|||||||
const (
 | 
					const (
 | 
				
			||||||
	// Namespace prefix for opaque counted resources (alpha).
 | 
						// Namespace prefix for opaque counted resources (alpha).
 | 
				
			||||||
	ResourceOpaqueIntPrefix = "pod.alpha.kubernetes.io/opaque-int-resource-"
 | 
						ResourceOpaqueIntPrefix = "pod.alpha.kubernetes.io/opaque-int-resource-"
 | 
				
			||||||
 | 
						// Default namespace prefix.
 | 
				
			||||||
 | 
						ResourceDefaultNamespacePrefix = "kubernetes.io/"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ResourceList is a set of (resource name, quantity) pairs.
 | 
					// ResourceList is a set of (resource name, quantity) pairs.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ go_library(
 | 
				
			|||||||
        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
					        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
 | 
					        "//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/apimachinery/pkg/selection:go_default_library",
 | 
					        "//vendor/k8s.io/apimachinery/pkg/selection:go_default_library",
 | 
				
			||||||
 | 
					        "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,9 +24,25 @@ import (
 | 
				
			|||||||
	"k8s.io/api/core/v1"
 | 
						"k8s.io/api/core/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/labels"
 | 
						"k8s.io/apimachinery/pkg/labels"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/selection"
 | 
						"k8s.io/apimachinery/pkg/selection"
 | 
				
			||||||
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/helper"
 | 
						"k8s.io/kubernetes/pkg/api/helper"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsExtendedResourceName returns true if the resource name is not in the
 | 
				
			||||||
 | 
					// default namespace, or it has the opaque integer resource prefix.
 | 
				
			||||||
 | 
					func IsExtendedResourceName(name v1.ResourceName) bool {
 | 
				
			||||||
 | 
						// TODO: Remove OIR part following deprecation.
 | 
				
			||||||
 | 
						return !IsDefaultNamespaceResource(name) || IsOpaqueIntResourceName(name)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsDefaultNamespaceResource returns true if the resource name is in the
 | 
				
			||||||
 | 
					// *kubernetes.io/ namespace. Partially-qualified (unprefixed) names are
 | 
				
			||||||
 | 
					// implicitly in the kubernetes.io/ namespace.
 | 
				
			||||||
 | 
					func IsDefaultNamespaceResource(name v1.ResourceName) bool {
 | 
				
			||||||
 | 
						return !strings.Contains(string(name), "/") ||
 | 
				
			||||||
 | 
							strings.Contains(string(name), v1.ResourceDefaultNamespacePrefix)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// IsOpaqueIntResourceName returns true if the resource name has the opaque
 | 
					// IsOpaqueIntResourceName returns true if the resource name has the opaque
 | 
				
			||||||
// integer resource prefix.
 | 
					// integer resource prefix.
 | 
				
			||||||
func IsOpaqueIntResourceName(name v1.ResourceName) bool {
 | 
					func IsOpaqueIntResourceName(name v1.ResourceName) bool {
 | 
				
			||||||
@@ -43,6 +59,15 @@ func OpaqueIntResourceName(name string) v1.ResourceName {
 | 
				
			|||||||
	return v1.ResourceName(fmt.Sprintf("%s%s", v1.ResourceOpaqueIntPrefix, name))
 | 
						return v1.ResourceName(fmt.Sprintf("%s%s", v1.ResourceOpaqueIntPrefix, name))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var overcommitBlacklist = sets.NewString(string(v1.ResourceNvidiaGPU))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsOvercommitAllowed returns true if the resource is in the default
 | 
				
			||||||
 | 
					// namespace and not blacklisted.
 | 
				
			||||||
 | 
					func IsOvercommitAllowed(name v1.ResourceName) bool {
 | 
				
			||||||
 | 
						return IsDefaultNamespaceResource(name) &&
 | 
				
			||||||
 | 
							!overcommitBlacklist.Has(string(name))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// this function aims to check if the service's ClusterIP is set or not
 | 
					// this function aims to check if the service's ClusterIP is set or not
 | 
				
			||||||
// the objective is not to perform validation here
 | 
					// the objective is not to perform validation here
 | 
				
			||||||
func IsServiceIPSet(service *v1.Service) bool {
 | 
					func IsServiceIPSet(service *v1.Service) bool {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,8 @@ go_library(
 | 
				
			|||||||
    srcs = ["validation.go"],
 | 
					    srcs = ["validation.go"],
 | 
				
			||||||
    deps = [
 | 
					    deps = [
 | 
				
			||||||
        "//pkg/api/helper:go_default_library",
 | 
					        "//pkg/api/helper:go_default_library",
 | 
				
			||||||
 | 
					        "//pkg/api/v1/helper:go_default_library",
 | 
				
			||||||
 | 
					        "//vendor/github.com/golang/glog:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
					        "//vendor/k8s.io/api/core/v1:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
 | 
					        "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
 | 
				
			||||||
        "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
 | 
					        "//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,12 +20,15 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/golang/glog"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"k8s.io/api/core/v1"
 | 
						"k8s.io/api/core/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/api/resource"
 | 
						"k8s.io/apimachinery/pkg/api/resource"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						"k8s.io/apimachinery/pkg/util/sets"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/validation"
 | 
						"k8s.io/apimachinery/pkg/util/validation"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
						"k8s.io/apimachinery/pkg/util/validation/field"
 | 
				
			||||||
	"k8s.io/kubernetes/pkg/api/helper"
 | 
						"k8s.io/kubernetes/pkg/api/helper"
 | 
				
			||||||
 | 
						v1helper "k8s.io/kubernetes/pkg/api/v1/helper"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const isNegativeErrorMsg string = `must be greater than or equal to 0`
 | 
					const isNegativeErrorMsg string = `must be greater than or equal to 0`
 | 
				
			||||||
@@ -46,9 +49,9 @@ func ValidateResourceRequirements(requirements *v1.ResourceRequirements, fldPath
 | 
				
			|||||||
		// Check that request <= limit.
 | 
							// Check that request <= limit.
 | 
				
			||||||
		requestQuantity, exists := requirements.Requests[resourceName]
 | 
							requestQuantity, exists := requirements.Requests[resourceName]
 | 
				
			||||||
		if exists {
 | 
							if exists {
 | 
				
			||||||
			// For GPUs, not only requests can't exceed limits, they also can't be lower, i.e. must be equal.
 | 
								// Ensure overcommit is allowed for the resource if request != limit
 | 
				
			||||||
			if resourceName == v1.ResourceNvidiaGPU && quantity.Cmp(requestQuantity) != 0 {
 | 
								if quantity.Cmp(requestQuantity) != 0 && !v1helper.IsOvercommitAllowed(resourceName) {
 | 
				
			||||||
				allErrs = append(allErrs, field.Invalid(reqPath, requestQuantity.String(), fmt.Sprintf("must be equal to %s limit", v1.ResourceNvidiaGPU)))
 | 
									allErrs = append(allErrs, field.Invalid(reqPath, requestQuantity.String(), fmt.Sprintf("must be equal to %s limit", resourceName)))
 | 
				
			||||||
			} else if quantity.Cmp(requestQuantity) < 0 {
 | 
								} else if quantity.Cmp(requestQuantity) < 0 {
 | 
				
			||||||
				allErrs = append(allErrs, field.Invalid(limPath, quantity.String(), fmt.Sprintf("must be greater than or equal to %s request", resourceName)))
 | 
									allErrs = append(allErrs, field.Invalid(limPath, quantity.String(), fmt.Sprintf("must be greater than or equal to %s request", resourceName)))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -99,6 +102,12 @@ func ValidateNonnegativeQuantity(value resource.Quantity, fldPath *field.Path) f
 | 
				
			|||||||
// Validate compute resource typename.
 | 
					// Validate compute resource typename.
 | 
				
			||||||
// Refer to docs/design/resources.md for more details.
 | 
					// Refer to docs/design/resources.md for more details.
 | 
				
			||||||
func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
 | 
					func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						// Opaque integer resources (OIR) deprecation began in v1.8
 | 
				
			||||||
 | 
						// TODO: Remove warning after OIR deprecation cycle.
 | 
				
			||||||
 | 
						if v1helper.IsOpaqueIntResourceName(v1.ResourceName(value)) {
 | 
				
			||||||
 | 
							glog.Errorf("DEPRECATION WARNING! Opaque integer resources are deprecated starting with v1.8: %s", value)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	allErrs := field.ErrorList{}
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
	for _, msg := range validation.IsQualifiedName(value) {
 | 
						for _, msg := range validation.IsQualifiedName(value) {
 | 
				
			||||||
		allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
 | 
							allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3358,6 +3358,12 @@ func ValidateNodeUpdate(node, oldNode *api.Node) field.ErrorList {
 | 
				
			|||||||
// Validate compute resource typename.
 | 
					// Validate compute resource typename.
 | 
				
			||||||
// Refer to docs/design/resources.md for more details.
 | 
					// Refer to docs/design/resources.md for more details.
 | 
				
			||||||
func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
 | 
					func validateResourceName(value string, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						// Opaque integer resources (OIR) deprecation began in v1.8
 | 
				
			||||||
 | 
						// TODO: Remove warning after OIR deprecation cycle.
 | 
				
			||||||
 | 
						if helper.IsOpaqueIntResourceName(api.ResourceName(value)) {
 | 
				
			||||||
 | 
							glog.Errorf("DEPRECATION WARNING! Opaque integer resources are deprecated starting with v1.8: %s", value)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	allErrs := field.ErrorList{}
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
	for _, msg := range validation.IsQualifiedName(value) {
 | 
						for _, msg := range validation.IsQualifiedName(value) {
 | 
				
			||||||
		allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
 | 
							allErrs = append(allErrs, field.Invalid(fldPath, value, msg))
 | 
				
			||||||
@@ -3715,9 +3721,9 @@ func ValidateResourceRequirements(requirements *api.ResourceRequirements, fldPat
 | 
				
			|||||||
		// Check that request <= limit.
 | 
							// Check that request <= limit.
 | 
				
			||||||
		requestQuantity, exists := requirements.Requests[resourceName]
 | 
							requestQuantity, exists := requirements.Requests[resourceName]
 | 
				
			||||||
		if exists {
 | 
							if exists {
 | 
				
			||||||
			// For GPUs, not only requests can't exceed limits, they also can't be lower, i.e. must be equal.
 | 
								// Ensure overcommit is allowed for the resource if request != limit
 | 
				
			||||||
			if resourceName == api.ResourceNvidiaGPU && quantity.Cmp(requestQuantity) != 0 {
 | 
								if quantity.Cmp(requestQuantity) != 0 && !helper.IsOvercommitAllowed(resourceName) {
 | 
				
			||||||
				allErrs = append(allErrs, field.Invalid(reqPath, requestQuantity.String(), fmt.Sprintf("must be equal to %s limit", api.ResourceNvidiaGPU)))
 | 
									allErrs = append(allErrs, field.Invalid(reqPath, requestQuantity.String(), fmt.Sprintf("must be equal to %s limit", resourceName)))
 | 
				
			||||||
			} else if quantity.Cmp(requestQuantity) < 0 {
 | 
								} else if quantity.Cmp(requestQuantity) < 0 {
 | 
				
			||||||
				allErrs = append(allErrs, field.Invalid(limPath, quantity.String(), fmt.Sprintf("must be greater than or equal to %s request", resourceName)))
 | 
									allErrs = append(allErrs, field.Invalid(limPath, quantity.String(), fmt.Sprintf("must be greater than or equal to %s request", resourceName)))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3287,7 +3287,7 @@ func TestValidateContainers(t *testing.T) {
 | 
				
			|||||||
				Limits: api.ResourceList{
 | 
									Limits: api.ResourceList{
 | 
				
			||||||
					api.ResourceName(api.ResourceCPU):    resource.MustParse("10"),
 | 
										api.ResourceName(api.ResourceCPU):    resource.MustParse("10"),
 | 
				
			||||||
					api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
 | 
										api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
 | 
				
			||||||
					api.ResourceName("my.org/resource"):  resource.MustParse("10m"),
 | 
										api.ResourceName("my.org/resource"):  resource.MustParse("10"),
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			ImagePullPolicy:          "IfNotPresent",
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
@@ -3349,12 +3349,12 @@ func TestValidateContainers(t *testing.T) {
 | 
				
			|||||||
				Requests: api.ResourceList{
 | 
									Requests: api.ResourceList{
 | 
				
			||||||
					api.ResourceName(api.ResourceCPU):    resource.MustParse("10"),
 | 
										api.ResourceName(api.ResourceCPU):    resource.MustParse("10"),
 | 
				
			||||||
					api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
 | 
										api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
 | 
				
			||||||
					api.ResourceName("my.org/resource"):  resource.MustParse("10m"),
 | 
										api.ResourceName("my.org/resource"):  resource.MustParse("10"),
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				Limits: api.ResourceList{
 | 
									Limits: api.ResourceList{
 | 
				
			||||||
					api.ResourceName(api.ResourceCPU):    resource.MustParse("10"),
 | 
										api.ResourceName(api.ResourceCPU):    resource.MustParse("10"),
 | 
				
			||||||
					api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
 | 
										api.ResourceName(api.ResourceMemory): resource.MustParse("10G"),
 | 
				
			||||||
					api.ResourceName("my.org/resource"):  resource.MustParse("10m"),
 | 
										api.ResourceName("my.org/resource"):  resource.MustParse("10"),
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			ImagePullPolicy:          "IfNotPresent",
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
@@ -3370,7 +3370,7 @@ func TestValidateContainers(t *testing.T) {
 | 
				
			|||||||
				},
 | 
									},
 | 
				
			||||||
				Limits: api.ResourceList{
 | 
									Limits: api.ResourceList{
 | 
				
			||||||
					api.ResourceName(api.ResourceCPU):   resource.MustParse("10"),
 | 
										api.ResourceName(api.ResourceCPU):   resource.MustParse("10"),
 | 
				
			||||||
					api.ResourceName("my.org/resource"): resource.MustParse("10m"),
 | 
										api.ResourceName("my.org/resource"): resource.MustParse("10"),
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			ImagePullPolicy:          "IfNotPresent",
 | 
								ImagePullPolicy:          "IfNotPresent",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -577,11 +577,11 @@ func (kl *Kubelet) setNodeStatusMachineInfo(node *v1.Node) {
 | 
				
			|||||||
	if node.Status.Allocatable == nil {
 | 
						if node.Status.Allocatable == nil {
 | 
				
			||||||
		node.Status.Allocatable = make(v1.ResourceList)
 | 
							node.Status.Allocatable = make(v1.ResourceList)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Remove opaque integer resources from allocatable that are no longer
 | 
						// Remove extended resources from allocatable that are no longer
 | 
				
			||||||
	// present in capacity.
 | 
						// present in capacity.
 | 
				
			||||||
	for k := range node.Status.Allocatable {
 | 
						for k := range node.Status.Allocatable {
 | 
				
			||||||
		_, found := node.Status.Capacity[k]
 | 
							_, found := node.Status.Capacity[k]
 | 
				
			||||||
		if !found && v1helper.IsOpaqueIntResourceName(k) {
 | 
							if !found && v1helper.IsExtendedResourceName(k) {
 | 
				
			||||||
			delete(node.Status.Allocatable, k)
 | 
								delete(node.Status.Allocatable, k)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -533,10 +533,10 @@ func GetResourceRequest(pod *v1.Pod) *schedulercache.Resource {
 | 
				
			|||||||
					result.StorageOverlay = overlay
 | 
										result.StorageOverlay = overlay
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			default:
 | 
								default:
 | 
				
			||||||
				if v1helper.IsOpaqueIntResourceName(rName) {
 | 
									if v1helper.IsExtendedResourceName(rName) {
 | 
				
			||||||
					value := rQuantity.Value()
 | 
										value := rQuantity.Value()
 | 
				
			||||||
					if value > result.OpaqueIntResources[rName] {
 | 
										if value > result.ExtendedResources[rName] {
 | 
				
			||||||
						result.SetOpaque(rName, value)
 | 
											result.SetExtended(rName, value)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -572,7 +572,7 @@ func PodFitsResources(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.No
 | 
				
			|||||||
		// We couldn't parse metadata - fallback to computing it.
 | 
							// We couldn't parse metadata - fallback to computing it.
 | 
				
			||||||
		podRequest = GetResourceRequest(pod)
 | 
							podRequest = GetResourceRequest(pod)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if podRequest.MilliCPU == 0 && podRequest.Memory == 0 && podRequest.NvidiaGPU == 0 && podRequest.StorageOverlay == 0 && podRequest.StorageScratch == 0 && len(podRequest.OpaqueIntResources) == 0 {
 | 
						if podRequest.MilliCPU == 0 && podRequest.Memory == 0 && podRequest.NvidiaGPU == 0 && podRequest.StorageOverlay == 0 && podRequest.StorageScratch == 0 && len(podRequest.ExtendedResources) == 0 {
 | 
				
			||||||
		return len(predicateFails) == 0, predicateFails, nil
 | 
							return len(predicateFails) == 0, predicateFails, nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -603,9 +603,9 @@ func PodFitsResources(pod *v1.Pod, meta interface{}, nodeInfo *schedulercache.No
 | 
				
			|||||||
		predicateFails = append(predicateFails, NewInsufficientResourceError(v1.ResourceStorageOverlay, podRequest.StorageOverlay, nodeInfo.RequestedResource().StorageOverlay, allocatable.StorageOverlay))
 | 
							predicateFails = append(predicateFails, NewInsufficientResourceError(v1.ResourceStorageOverlay, podRequest.StorageOverlay, nodeInfo.RequestedResource().StorageOverlay, allocatable.StorageOverlay))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for rName, rQuant := range podRequest.OpaqueIntResources {
 | 
						for rName, rQuant := range podRequest.ExtendedResources {
 | 
				
			||||||
		if allocatable.OpaqueIntResources[rName] < rQuant+nodeInfo.RequestedResource().OpaqueIntResources[rName] {
 | 
							if allocatable.ExtendedResources[rName] < rQuant+nodeInfo.RequestedResource().ExtendedResources[rName] {
 | 
				
			||||||
			predicateFails = append(predicateFails, NewInsufficientResourceError(rName, podRequest.OpaqueIntResources[rName], nodeInfo.RequestedResource().OpaqueIntResources[rName], allocatable.OpaqueIntResources[rName]))
 | 
								predicateFails = append(predicateFails, NewInsufficientResourceError(rName, podRequest.ExtendedResources[rName], nodeInfo.RequestedResource().ExtendedResources[rName], allocatable.ExtendedResources[rName]))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -254,85 +254,85 @@ func TestPodFitsResources(t *testing.T) {
 | 
				
			|||||||
			test: "equal edge case for init container",
 | 
								test: "equal edge case for init container",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod:      newResourcePod(schedulercache.Resource{OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 1}}),
 | 
								pod:      newResourcePod(schedulercache.Resource{ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 1}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(newResourcePod(schedulercache.Resource{})),
 | 
								nodeInfo: schedulercache.NewNodeInfo(newResourcePod(schedulercache.Resource{})),
 | 
				
			||||||
			fits:     true,
 | 
								fits:     true,
 | 
				
			||||||
			test:     "opaque resource fits",
 | 
								test:     "opaque resource fits",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod:      newResourceInitPod(newResourcePod(schedulercache.Resource{}), schedulercache.Resource{OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 1}}),
 | 
								pod:      newResourceInitPod(newResourcePod(schedulercache.Resource{}), schedulercache.Resource{ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 1}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(newResourcePod(schedulercache.Resource{})),
 | 
								nodeInfo: schedulercache.NewNodeInfo(newResourcePod(schedulercache.Resource{})),
 | 
				
			||||||
			fits:     true,
 | 
								fits:     true,
 | 
				
			||||||
			test:     "opaque resource fits for init container",
 | 
								test:     "opaque resource fits for init container",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod: newResourcePod(
 | 
								pod: newResourcePod(
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 10}}),
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 10}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(
 | 
								nodeInfo: schedulercache.NewNodeInfo(
 | 
				
			||||||
				newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 0}})),
 | 
									newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 0}})),
 | 
				
			||||||
			fits:    false,
 | 
								fits:    false,
 | 
				
			||||||
			test:    "opaque resource capacity enforced",
 | 
								test:    "opaque resource capacity enforced",
 | 
				
			||||||
			reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 10, 0, 5)},
 | 
								reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 10, 0, 5)},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
								pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 10}}),
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 10}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(
 | 
								nodeInfo: schedulercache.NewNodeInfo(
 | 
				
			||||||
				newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 0}})),
 | 
									newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 0}})),
 | 
				
			||||||
			fits:    false,
 | 
								fits:    false,
 | 
				
			||||||
			test:    "opaque resource capacity enforced for init container",
 | 
								test:    "opaque resource capacity enforced for init container",
 | 
				
			||||||
			reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 10, 0, 5)},
 | 
								reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 10, 0, 5)},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod: newResourcePod(
 | 
								pod: newResourcePod(
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 1}}),
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 1}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(
 | 
								nodeInfo: schedulercache.NewNodeInfo(
 | 
				
			||||||
				newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 5}})),
 | 
									newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 5}})),
 | 
				
			||||||
			fits:    false,
 | 
								fits:    false,
 | 
				
			||||||
			test:    "opaque resource allocatable enforced",
 | 
								test:    "opaque resource allocatable enforced",
 | 
				
			||||||
			reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 1, 5, 5)},
 | 
								reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 1, 5, 5)},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
								pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 1}}),
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 1}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(
 | 
								nodeInfo: schedulercache.NewNodeInfo(
 | 
				
			||||||
				newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 5}})),
 | 
									newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 5}})),
 | 
				
			||||||
			fits:    false,
 | 
								fits:    false,
 | 
				
			||||||
			test:    "opaque resource allocatable enforced for init container",
 | 
								test:    "opaque resource allocatable enforced for init container",
 | 
				
			||||||
			reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 1, 5, 5)},
 | 
								reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 1, 5, 5)},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod: newResourcePod(
 | 
								pod: newResourcePod(
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 3}},
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 3}},
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 3}}),
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 3}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(
 | 
								nodeInfo: schedulercache.NewNodeInfo(
 | 
				
			||||||
				newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 2}})),
 | 
									newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 2}})),
 | 
				
			||||||
			fits:    false,
 | 
								fits:    false,
 | 
				
			||||||
			test:    "opaque resource allocatable enforced for multiple containers",
 | 
								test:    "opaque resource allocatable enforced for multiple containers",
 | 
				
			||||||
			reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 6, 2, 5)},
 | 
								reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 6, 2, 5)},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
								pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 3}},
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 3}},
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 3}}),
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 3}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(
 | 
								nodeInfo: schedulercache.NewNodeInfo(
 | 
				
			||||||
				newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 2}})),
 | 
									newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 2}})),
 | 
				
			||||||
			fits: true,
 | 
								fits: true,
 | 
				
			||||||
			test: "opaque resource allocatable admits multiple init containers",
 | 
								test: "opaque resource allocatable admits multiple init containers",
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
								pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 6}},
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 6}},
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 3}}),
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 3}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(
 | 
								nodeInfo: schedulercache.NewNodeInfo(
 | 
				
			||||||
				newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceA: 2}})),
 | 
									newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceA: 2}})),
 | 
				
			||||||
			fits:    false,
 | 
								fits:    false,
 | 
				
			||||||
			test:    "opaque resource allocatable enforced for multiple init containers",
 | 
								test:    "opaque resource allocatable enforced for multiple init containers",
 | 
				
			||||||
			reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 6, 2, 5)},
 | 
								reasons: []algorithm.PredicateFailureReason{NewInsufficientResourceError(opaqueResourceA, 6, 2, 5)},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod: newResourcePod(
 | 
								pod: newResourcePod(
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceB: 1}}),
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceB: 1}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(
 | 
								nodeInfo: schedulercache.NewNodeInfo(
 | 
				
			||||||
				newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0})),
 | 
									newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0})),
 | 
				
			||||||
			fits:    false,
 | 
								fits:    false,
 | 
				
			||||||
@@ -341,7 +341,7 @@ func TestPodFitsResources(t *testing.T) {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
								pod: newResourceInitPod(newResourcePod(schedulercache.Resource{}),
 | 
				
			||||||
				schedulercache.Resource{MilliCPU: 1, Memory: 1, OpaqueIntResources: map[v1.ResourceName]int64{opaqueResourceB: 1}}),
 | 
									schedulercache.Resource{MilliCPU: 1, Memory: 1, ExtendedResources: map[v1.ResourceName]int64{opaqueResourceB: 1}}),
 | 
				
			||||||
			nodeInfo: schedulercache.NewNodeInfo(
 | 
								nodeInfo: schedulercache.NewNodeInfo(
 | 
				
			||||||
				newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0})),
 | 
									newResourcePod(schedulercache.Resource{MilliCPU: 0, Memory: 0})),
 | 
				
			||||||
			fits:    false,
 | 
								fits:    false,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -109,9 +109,9 @@ func TestAssumePodScheduled(t *testing.T) {
 | 
				
			|||||||
		pods: []*v1.Pod{testPods[4]},
 | 
							pods: []*v1.Pod{testPods[4]},
 | 
				
			||||||
		wNodeInfo: &NodeInfo{
 | 
							wNodeInfo: &NodeInfo{
 | 
				
			||||||
			requestedResource: &Resource{
 | 
								requestedResource: &Resource{
 | 
				
			||||||
				MilliCPU:           100,
 | 
									MilliCPU:          100,
 | 
				
			||||||
				Memory:             500,
 | 
									Memory:            500,
 | 
				
			||||||
				OpaqueIntResources: map[v1.ResourceName]int64{"pod.alpha.kubernetes.io/opaque-int-resource-oir-foo": 3},
 | 
									ExtendedResources: map[v1.ResourceName]int64{"pod.alpha.kubernetes.io/opaque-int-resource-oir-foo": 3},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			nonzeroRequest: &Resource{
 | 
								nonzeroRequest: &Resource{
 | 
				
			||||||
				MilliCPU: 100,
 | 
									MilliCPU: 100,
 | 
				
			||||||
@@ -125,9 +125,9 @@ func TestAssumePodScheduled(t *testing.T) {
 | 
				
			|||||||
		pods: []*v1.Pod{testPods[4], testPods[5]},
 | 
							pods: []*v1.Pod{testPods[4], testPods[5]},
 | 
				
			||||||
		wNodeInfo: &NodeInfo{
 | 
							wNodeInfo: &NodeInfo{
 | 
				
			||||||
			requestedResource: &Resource{
 | 
								requestedResource: &Resource{
 | 
				
			||||||
				MilliCPU:           300,
 | 
									MilliCPU:          300,
 | 
				
			||||||
				Memory:             1524,
 | 
									Memory:            1524,
 | 
				
			||||||
				OpaqueIntResources: map[v1.ResourceName]int64{"pod.alpha.kubernetes.io/opaque-int-resource-oir-foo": 8},
 | 
									ExtendedResources: map[v1.ResourceName]int64{"pod.alpha.kubernetes.io/opaque-int-resource-oir-foo": 8},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			nonzeroRequest: &Resource{
 | 
								nonzeroRequest: &Resource{
 | 
				
			||||||
				MilliCPU: 300,
 | 
									MilliCPU: 300,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -70,8 +70,8 @@ type Resource struct {
 | 
				
			|||||||
	StorageOverlay int64
 | 
						StorageOverlay int64
 | 
				
			||||||
	// We store allowedPodNumber (which is Node.Status.Allocatable.Pods().Value())
 | 
						// We store allowedPodNumber (which is Node.Status.Allocatable.Pods().Value())
 | 
				
			||||||
	// explicitly as int, to avoid conversions and improve performance.
 | 
						// explicitly as int, to avoid conversions and improve performance.
 | 
				
			||||||
	AllowedPodNumber   int
 | 
						AllowedPodNumber  int
 | 
				
			||||||
	OpaqueIntResources map[v1.ResourceName]int64
 | 
						ExtendedResources map[v1.ResourceName]int64
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// New creates a Resource from ResourceList
 | 
					// New creates a Resource from ResourceList
 | 
				
			||||||
@@ -102,8 +102,8 @@ func (r *Resource) Add(rl v1.ResourceList) {
 | 
				
			|||||||
		case v1.ResourceStorageOverlay:
 | 
							case v1.ResourceStorageOverlay:
 | 
				
			||||||
			r.StorageOverlay += rQuant.Value()
 | 
								r.StorageOverlay += rQuant.Value()
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			if v1helper.IsOpaqueIntResourceName(rName) {
 | 
								if v1helper.IsExtendedResourceName(rName) {
 | 
				
			||||||
				r.AddOpaque(rName, rQuant.Value())
 | 
									r.AddExtended(rName, rQuant.Value())
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -118,7 +118,7 @@ func (r *Resource) ResourceList() v1.ResourceList {
 | 
				
			|||||||
		v1.ResourceStorageOverlay: *resource.NewQuantity(r.StorageOverlay, resource.BinarySI),
 | 
							v1.ResourceStorageOverlay: *resource.NewQuantity(r.StorageOverlay, resource.BinarySI),
 | 
				
			||||||
		v1.ResourceStorageScratch: *resource.NewQuantity(r.StorageScratch, resource.BinarySI),
 | 
							v1.ResourceStorageScratch: *resource.NewQuantity(r.StorageScratch, resource.BinarySI),
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for rName, rQuant := range r.OpaqueIntResources {
 | 
						for rName, rQuant := range r.ExtendedResources {
 | 
				
			||||||
		result[rName] = *resource.NewQuantity(rQuant, resource.DecimalSI)
 | 
							result[rName] = *resource.NewQuantity(rQuant, resource.DecimalSI)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return result
 | 
						return result
 | 
				
			||||||
@@ -133,25 +133,25 @@ func (r *Resource) Clone() *Resource {
 | 
				
			|||||||
		StorageOverlay:   r.StorageOverlay,
 | 
							StorageOverlay:   r.StorageOverlay,
 | 
				
			||||||
		StorageScratch:   r.StorageScratch,
 | 
							StorageScratch:   r.StorageScratch,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if r.OpaqueIntResources != nil {
 | 
						if r.ExtendedResources != nil {
 | 
				
			||||||
		res.OpaqueIntResources = make(map[v1.ResourceName]int64)
 | 
							res.ExtendedResources = make(map[v1.ResourceName]int64)
 | 
				
			||||||
		for k, v := range r.OpaqueIntResources {
 | 
							for k, v := range r.ExtendedResources {
 | 
				
			||||||
			res.OpaqueIntResources[k] = v
 | 
								res.ExtendedResources[k] = v
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return res
 | 
						return res
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *Resource) AddOpaque(name v1.ResourceName, quantity int64) {
 | 
					func (r *Resource) AddExtended(name v1.ResourceName, quantity int64) {
 | 
				
			||||||
	r.SetOpaque(name, r.OpaqueIntResources[name]+quantity)
 | 
						r.SetExtended(name, r.ExtendedResources[name]+quantity)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (r *Resource) SetOpaque(name v1.ResourceName, quantity int64) {
 | 
					func (r *Resource) SetExtended(name v1.ResourceName, quantity int64) {
 | 
				
			||||||
	// Lazily allocate opaque integer resource map.
 | 
						// Lazily allocate opaque integer resource map.
 | 
				
			||||||
	if r.OpaqueIntResources == nil {
 | 
						if r.ExtendedResources == nil {
 | 
				
			||||||
		r.OpaqueIntResources = map[v1.ResourceName]int64{}
 | 
							r.ExtendedResources = map[v1.ResourceName]int64{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	r.OpaqueIntResources[name] = quantity
 | 
						r.ExtendedResources[name] = quantity
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewNodeInfo returns a ready to use empty NodeInfo object.
 | 
					// NewNodeInfo returns a ready to use empty NodeInfo object.
 | 
				
			||||||
@@ -306,11 +306,11 @@ func (n *NodeInfo) addPod(pod *v1.Pod) {
 | 
				
			|||||||
	n.requestedResource.NvidiaGPU += res.NvidiaGPU
 | 
						n.requestedResource.NvidiaGPU += res.NvidiaGPU
 | 
				
			||||||
	n.requestedResource.StorageOverlay += res.StorageOverlay
 | 
						n.requestedResource.StorageOverlay += res.StorageOverlay
 | 
				
			||||||
	n.requestedResource.StorageScratch += res.StorageScratch
 | 
						n.requestedResource.StorageScratch += res.StorageScratch
 | 
				
			||||||
	if n.requestedResource.OpaqueIntResources == nil && len(res.OpaqueIntResources) > 0 {
 | 
						if n.requestedResource.ExtendedResources == nil && len(res.ExtendedResources) > 0 {
 | 
				
			||||||
		n.requestedResource.OpaqueIntResources = map[v1.ResourceName]int64{}
 | 
							n.requestedResource.ExtendedResources = map[v1.ResourceName]int64{}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	for rName, rQuant := range res.OpaqueIntResources {
 | 
						for rName, rQuant := range res.ExtendedResources {
 | 
				
			||||||
		n.requestedResource.OpaqueIntResources[rName] += rQuant
 | 
							n.requestedResource.ExtendedResources[rName] += rQuant
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	n.nonzeroRequest.MilliCPU += non0_cpu
 | 
						n.nonzeroRequest.MilliCPU += non0_cpu
 | 
				
			||||||
	n.nonzeroRequest.Memory += non0_mem
 | 
						n.nonzeroRequest.Memory += non0_mem
 | 
				
			||||||
@@ -361,11 +361,11 @@ func (n *NodeInfo) removePod(pod *v1.Pod) error {
 | 
				
			|||||||
			n.requestedResource.MilliCPU -= res.MilliCPU
 | 
								n.requestedResource.MilliCPU -= res.MilliCPU
 | 
				
			||||||
			n.requestedResource.Memory -= res.Memory
 | 
								n.requestedResource.Memory -= res.Memory
 | 
				
			||||||
			n.requestedResource.NvidiaGPU -= res.NvidiaGPU
 | 
								n.requestedResource.NvidiaGPU -= res.NvidiaGPU
 | 
				
			||||||
			if len(res.OpaqueIntResources) > 0 && n.requestedResource.OpaqueIntResources == nil {
 | 
								if len(res.ExtendedResources) > 0 && n.requestedResource.ExtendedResources == nil {
 | 
				
			||||||
				n.requestedResource.OpaqueIntResources = map[v1.ResourceName]int64{}
 | 
									n.requestedResource.ExtendedResources = map[v1.ResourceName]int64{}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			for rName, rQuant := range res.OpaqueIntResources {
 | 
								for rName, rQuant := range res.ExtendedResources {
 | 
				
			||||||
				n.requestedResource.OpaqueIntResources[rName] -= rQuant
 | 
									n.requestedResource.ExtendedResources[rName] -= rQuant
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			n.nonzeroRequest.MilliCPU -= non0_cpu
 | 
								n.nonzeroRequest.MilliCPU -= non0_cpu
 | 
				
			||||||
			n.nonzeroRequest.Memory -= non0_mem
 | 
								n.nonzeroRequest.Memory -= non0_mem
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3611,6 +3611,8 @@ const (
 | 
				
			|||||||
const (
 | 
					const (
 | 
				
			||||||
	// Namespace prefix for opaque counted resources (alpha).
 | 
						// Namespace prefix for opaque counted resources (alpha).
 | 
				
			||||||
	ResourceOpaqueIntPrefix = "pod.alpha.kubernetes.io/opaque-int-resource-"
 | 
						ResourceOpaqueIntPrefix = "pod.alpha.kubernetes.io/opaque-int-resource-"
 | 
				
			||||||
 | 
						// Default namespace prefix.
 | 
				
			||||||
 | 
						ResourceDefaultNamespacePrefix = "kubernetes.io/"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ResourceList is a set of (resource name, quantity) pairs.
 | 
					// ResourceList is a set of (resource name, quantity) pairs.
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user