mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-10-31 02:08:13 +00:00 
			
		
		
		
	Move extract resources to its pkg
Move ExtractContainerResourceValue
This commit is contained in:
		| @@ -17,6 +17,9 @@ limitations under the License. | ||||
| package api | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| @@ -227,3 +230,41 @@ func PodRequestsAndLimits(pod *Pod) (reqs map[ResourceName]resource.Quantity, li | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // ExtractContainerResourceValue extracts the value of a resource | ||||
| // in an already known container | ||||
| func ExtractContainerResourceValue(fs *ResourceFieldSelector, container *Container) (string, error) { | ||||
| 	divisor := resource.Quantity{} | ||||
| 	if divisor.Cmp(fs.Divisor) == 0 { | ||||
| 		divisor = resource.MustParse("1") | ||||
| 	} else { | ||||
| 		divisor = fs.Divisor | ||||
| 	} | ||||
|  | ||||
| 	switch fs.Resource { | ||||
| 	case "limits.cpu": | ||||
| 		return ConvertResourceCPUToString(container.Resources.Limits.Cpu(), divisor) | ||||
| 	case "limits.memory": | ||||
| 		return ConvertResourceMemoryToString(container.Resources.Limits.Memory(), divisor) | ||||
| 	case "requests.cpu": | ||||
| 		return ConvertResourceCPUToString(container.Resources.Requests.Cpu(), divisor) | ||||
| 	case "requests.memory": | ||||
| 		return ConvertResourceMemoryToString(container.Resources.Requests.Memory(), divisor) | ||||
| 	} | ||||
|  | ||||
| 	return "", fmt.Errorf("unsupported container resource : %v", fs.Resource) | ||||
| } | ||||
|  | ||||
| // ConvertResourceCPUToString converts cpu value to the format of divisor and returns | ||||
| // ceiling of the value. | ||||
| func ConvertResourceCPUToString(cpu *resource.Quantity, divisor resource.Quantity) (string, error) { | ||||
| 	c := int64(math.Ceil(float64(cpu.MilliValue()) / float64(divisor.MilliValue()))) | ||||
| 	return strconv.FormatInt(c, 10), nil | ||||
| } | ||||
|  | ||||
| // ConvertResourceMemoryToString converts memory value to the format of divisor and returns | ||||
| // ceiling of the value. | ||||
| func ConvertResourceMemoryToString(memory *resource.Quantity, divisor resource.Quantity) (string, error) { | ||||
| 	m := int64(math.Ceil(float64(memory.Value()) / float64(divisor.Value()))) | ||||
| 	return strconv.FormatInt(m, 10), nil | ||||
| } | ||||
|   | ||||
| @@ -86,6 +86,7 @@ go_test( | ||||
|     library = ":go_default_library", | ||||
|     tags = ["automanaged"], | ||||
|     deps = [ | ||||
|         "//vendor:github.com/stretchr/testify/assert", | ||||
|         "//vendor:k8s.io/apimachinery/pkg/api/equality", | ||||
|         "//vendor:k8s.io/apimachinery/pkg/api/resource", | ||||
|         "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", | ||||
|   | ||||
| @@ -17,10 +17,12 @@ limitations under the License. | ||||
| package v1 | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
|  | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/kubernetes/pkg/api" | ||||
| ) | ||||
|  | ||||
| // Returns string version of ResourceName. | ||||
| @@ -255,3 +257,86 @@ func GetResourceRequest(pod *Pod, resource ResourceName) int64 { | ||||
| 	} | ||||
| 	return totalResources | ||||
| } | ||||
|  | ||||
| // ExtractResourceValueByContainerName extracts the value of a resource | ||||
| // by providing container name | ||||
| func ExtractResourceValueByContainerName(fs *ResourceFieldSelector, pod *Pod, containerName string) (string, error) { | ||||
| 	container, err := findContainerInPod(pod, containerName) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return ExtractContainerResourceValue(fs, container) | ||||
| } | ||||
|  | ||||
| // ExtractResourceValueByContainerNameAndNodeAllocatable extracts the value of a resource | ||||
| // by providing container name and node allocatable | ||||
| func ExtractResourceValueByContainerNameAndNodeAllocatable(fs *ResourceFieldSelector, pod *Pod, containerName string, nodeAllocatable ResourceList) (string, error) { | ||||
| 	realContainer, err := findContainerInPod(pod, containerName) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	containerCopy, err := api.Scheme.DeepCopy(realContainer) | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("failed to perform a deep copy of container object: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	container, ok := containerCopy.(*Container) | ||||
| 	if !ok { | ||||
| 		return "", fmt.Errorf("unexpected type returned from deep copy of container object") | ||||
| 	} | ||||
|  | ||||
| 	MergeContainerResourceLimits(container, nodeAllocatable) | ||||
|  | ||||
| 	return ExtractContainerResourceValue(fs, container) | ||||
| } | ||||
|  | ||||
| // ExtractContainerResourceValue extracts the value of a resource | ||||
| // in an already known container | ||||
| func ExtractContainerResourceValue(fs *ResourceFieldSelector, container *Container) (string, error) { | ||||
| 	divisor := resource.Quantity{} | ||||
| 	if divisor.Cmp(fs.Divisor) == 0 { | ||||
| 		divisor = resource.MustParse("1") | ||||
| 	} else { | ||||
| 		divisor = fs.Divisor | ||||
| 	} | ||||
|  | ||||
| 	switch fs.Resource { | ||||
| 	case "limits.cpu": | ||||
| 		return api.ConvertResourceCPUToString(container.Resources.Limits.Cpu(), divisor) | ||||
| 	case "limits.memory": | ||||
| 		return api.ConvertResourceMemoryToString(container.Resources.Limits.Memory(), divisor) | ||||
| 	case "requests.cpu": | ||||
| 		return api.ConvertResourceCPUToString(container.Resources.Requests.Cpu(), divisor) | ||||
| 	case "requests.memory": | ||||
| 		return api.ConvertResourceMemoryToString(container.Resources.Requests.Memory(), divisor) | ||||
| 	} | ||||
|  | ||||
| 	return "", fmt.Errorf("Unsupported container resource : %v", fs.Resource) | ||||
| } | ||||
|  | ||||
| // findContainerInPod finds a container by its name in the provided pod | ||||
| func findContainerInPod(pod *Pod, containerName string) (*Container, error) { | ||||
| 	for _, container := range pod.Spec.Containers { | ||||
| 		if container.Name == containerName { | ||||
| 			return &container, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("container %s not found", containerName) | ||||
| } | ||||
|  | ||||
| // MergeContainerResourceLimits checks if a limit is applied for | ||||
| // the container, and if not, it sets the limit to the passed resource list. | ||||
| func MergeContainerResourceLimits(container *Container, | ||||
| 	allocatable ResourceList) { | ||||
| 	if container.Resources.Limits == nil { | ||||
| 		container.Resources.Limits = make(ResourceList) | ||||
| 	} | ||||
| 	for _, resource := range []ResourceName{ResourceCPU, ResourceMemory} { | ||||
| 		if quantity, exists := container.Resources.Limits[resource]; !exists || quantity.IsZero() { | ||||
| 			if cap, exists := allocatable[resource]; exists { | ||||
| 				container.Resources.Limits[resource] = *cap.Copy() | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -20,6 +20,8 @@ import ( | ||||
| 	"testing" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
| @@ -118,3 +120,119 @@ func TestIsPodAvailable(t *testing.T) { | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestExtractResourceValue(t *testing.T) { | ||||
| 	cases := []struct { | ||||
| 		fs            *ResourceFieldSelector | ||||
| 		pod           *Pod | ||||
| 		cName         string | ||||
| 		expectedValue string | ||||
| 		expectedError error | ||||
| 	}{ | ||||
| 		{ | ||||
| 			fs: &ResourceFieldSelector{ | ||||
| 				Resource: "limits.cpu", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "9", "", ""), | ||||
| 			expectedValue: "9", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &ResourceFieldSelector{ | ||||
| 				Resource: "requests.cpu", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "", "", ""), | ||||
| 			expectedValue: "0", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &ResourceFieldSelector{ | ||||
| 				Resource: "requests.cpu", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "8", "", "", ""), | ||||
| 			expectedValue: "8", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &ResourceFieldSelector{ | ||||
| 				Resource: "requests.cpu", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "100m", "", "", ""), | ||||
| 			expectedValue: "1", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &ResourceFieldSelector{ | ||||
| 				Resource: "requests.cpu", | ||||
| 				Divisor:  resource.MustParse("100m"), | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "1200m", "", "", ""), | ||||
| 			expectedValue: "12", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &ResourceFieldSelector{ | ||||
| 				Resource: "requests.memory", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "", "100Mi", ""), | ||||
| 			expectedValue: "104857600", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &ResourceFieldSelector{ | ||||
| 				Resource: "requests.memory", | ||||
| 				Divisor:  resource.MustParse("1Mi"), | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "", "100Mi", "1Gi"), | ||||
| 			expectedValue: "100", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &ResourceFieldSelector{ | ||||
| 				Resource: "limits.memory", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "", "10Mi", "100Mi"), | ||||
| 			expectedValue: "104857600", | ||||
| 		}, | ||||
| 	} | ||||
| 	as := assert.New(t) | ||||
| 	for idx, tc := range cases { | ||||
| 		actual, err := ExtractResourceValueByContainerName(tc.fs, tc.pod, tc.cName) | ||||
| 		if tc.expectedError != nil { | ||||
| 			as.Equal(tc.expectedError, err, "expected test case [%d] to fail with error %v; got %v", idx, tc.expectedError, err) | ||||
| 		} else { | ||||
| 			as.Nil(err, "expected test case [%d] to not return an error; got %v", idx, err) | ||||
| 			as.Equal(tc.expectedValue, actual, "expected test case [%d] to return %q; got %q instead", idx, tc.expectedValue, actual) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getPod(cname, cpuRequest, cpuLimit, memoryRequest, memoryLimit string) *Pod { | ||||
| 	resources := ResourceRequirements{ | ||||
| 		Limits:   make(ResourceList), | ||||
| 		Requests: make(ResourceList), | ||||
| 	} | ||||
| 	if cpuLimit != "" { | ||||
| 		resources.Limits[ResourceCPU] = resource.MustParse(cpuLimit) | ||||
| 	} | ||||
| 	if memoryLimit != "" { | ||||
| 		resources.Limits[ResourceMemory] = resource.MustParse(memoryLimit) | ||||
| 	} | ||||
| 	if cpuRequest != "" { | ||||
| 		resources.Requests[ResourceCPU] = resource.MustParse(cpuRequest) | ||||
| 	} | ||||
| 	if memoryRequest != "" { | ||||
| 		resources.Requests[ResourceMemory] = resource.MustParse(memoryRequest) | ||||
| 	} | ||||
| 	return &Pod{ | ||||
| 		Spec: PodSpec{ | ||||
| 			Containers: []Container{ | ||||
| 				{ | ||||
| 					Name:      cname, | ||||
| 					Resources: resources, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -15,12 +15,7 @@ go_library( | ||||
|         "fieldpath.go", | ||||
|     ], | ||||
|     tags = ["automanaged"], | ||||
|     deps = [ | ||||
|         "//pkg/api:go_default_library", | ||||
|         "//pkg/api/v1:go_default_library", | ||||
|         "//vendor:k8s.io/apimachinery/pkg/api/meta", | ||||
|         "//vendor:k8s.io/apimachinery/pkg/api/resource", | ||||
|     ], | ||||
|     deps = ["//vendor:k8s.io/apimachinery/pkg/api/meta"], | ||||
| ) | ||||
|  | ||||
| go_test( | ||||
| @@ -30,8 +25,6 @@ go_test( | ||||
|     tags = ["automanaged"], | ||||
|     deps = [ | ||||
|         "//pkg/api/v1:go_default_library", | ||||
|         "//vendor:github.com/stretchr/testify/assert", | ||||
|         "//vendor:k8s.io/apimachinery/pkg/api/resource", | ||||
|         "//vendor:k8s.io/apimachinery/pkg/apis/meta/v1", | ||||
|     ], | ||||
| ) | ||||
|   | ||||
| @@ -18,14 +18,9 @@ package fieldpath | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/apimachinery/pkg/api/meta" | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| 	"k8s.io/kubernetes/pkg/api" | ||||
| 	"k8s.io/kubernetes/pkg/api/v1" | ||||
| ) | ||||
|  | ||||
| // FormatMap formats map[string]string to a string. | ||||
| @@ -65,126 +60,3 @@ func ExtractFieldPathAsString(obj interface{}, fieldPath string) (string, error) | ||||
|  | ||||
| 	return "", fmt.Errorf("unsupported fieldPath: %v", fieldPath) | ||||
| } | ||||
|  | ||||
| // TODO: move the functions below to pkg/api/util/resources | ||||
| // ExtractResourceValueByContainerName extracts the value of a resource | ||||
| // by providing container name | ||||
| func ExtractResourceValueByContainerName(fs *v1.ResourceFieldSelector, pod *v1.Pod, containerName string) (string, error) { | ||||
| 	container, err := findContainerInPod(pod, containerName) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	return ExtractContainerResourceValue(fs, container) | ||||
| } | ||||
|  | ||||
| // ExtractResourceValueByContainerNameAndNodeAllocatable extracts the value of a resource | ||||
| // by providing container name and node allocatable | ||||
| func ExtractResourceValueByContainerNameAndNodeAllocatable(fs *v1.ResourceFieldSelector, pod *v1.Pod, containerName string, nodeAllocatable v1.ResourceList) (string, error) { | ||||
| 	realContainer, err := findContainerInPod(pod, containerName) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	containerCopy, err := api.Scheme.DeepCopy(realContainer) | ||||
| 	if err != nil { | ||||
| 		return "", fmt.Errorf("failed to perform a deep copy of container object: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	container, ok := containerCopy.(*v1.Container) | ||||
| 	if !ok { | ||||
| 		return "", fmt.Errorf("unexpected type returned from deep copy of container object") | ||||
| 	} | ||||
|  | ||||
| 	MergeContainerResourceLimits(container, nodeAllocatable) | ||||
|  | ||||
| 	return ExtractContainerResourceValue(fs, container) | ||||
| } | ||||
|  | ||||
| // ExtractContainerResourceValue extracts the value of a resource | ||||
| // in an already known container | ||||
| func ExtractContainerResourceValue(fs *v1.ResourceFieldSelector, container *v1.Container) (string, error) { | ||||
| 	divisor := resource.Quantity{} | ||||
| 	if divisor.Cmp(fs.Divisor) == 0 { | ||||
| 		divisor = resource.MustParse("1") | ||||
| 	} else { | ||||
| 		divisor = fs.Divisor | ||||
| 	} | ||||
|  | ||||
| 	switch fs.Resource { | ||||
| 	case "limits.cpu": | ||||
| 		return convertResourceCPUToString(container.Resources.Limits.Cpu(), divisor) | ||||
| 	case "limits.memory": | ||||
| 		return convertResourceMemoryToString(container.Resources.Limits.Memory(), divisor) | ||||
| 	case "requests.cpu": | ||||
| 		return convertResourceCPUToString(container.Resources.Requests.Cpu(), divisor) | ||||
| 	case "requests.memory": | ||||
| 		return convertResourceMemoryToString(container.Resources.Requests.Memory(), divisor) | ||||
| 	} | ||||
|  | ||||
| 	return "", fmt.Errorf("Unsupported container resource : %v", fs.Resource) | ||||
| } | ||||
|  | ||||
| // TODO: remove this duplicate | ||||
| // InternalExtractContainerResourceValue extracts the value of a resource | ||||
| // in an already known container | ||||
| func InternalExtractContainerResourceValue(fs *api.ResourceFieldSelector, container *api.Container) (string, error) { | ||||
| 	divisor := resource.Quantity{} | ||||
| 	if divisor.Cmp(fs.Divisor) == 0 { | ||||
| 		divisor = resource.MustParse("1") | ||||
| 	} else { | ||||
| 		divisor = fs.Divisor | ||||
| 	} | ||||
|  | ||||
| 	switch fs.Resource { | ||||
| 	case "limits.cpu": | ||||
| 		return convertResourceCPUToString(container.Resources.Limits.Cpu(), divisor) | ||||
| 	case "limits.memory": | ||||
| 		return convertResourceMemoryToString(container.Resources.Limits.Memory(), divisor) | ||||
| 	case "requests.cpu": | ||||
| 		return convertResourceCPUToString(container.Resources.Requests.Cpu(), divisor) | ||||
| 	case "requests.memory": | ||||
| 		return convertResourceMemoryToString(container.Resources.Requests.Memory(), divisor) | ||||
| 	} | ||||
|  | ||||
| 	return "", fmt.Errorf("unsupported container resource : %v", fs.Resource) | ||||
| } | ||||
|  | ||||
| // findContainerInPod finds a container by its name in the provided pod | ||||
| func findContainerInPod(pod *v1.Pod, containerName string) (*v1.Container, error) { | ||||
| 	for _, container := range pod.Spec.Containers { | ||||
| 		if container.Name == containerName { | ||||
| 			return &container, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("container %s not found", containerName) | ||||
| } | ||||
|  | ||||
| // convertResourceCPUToString converts cpu value to the format of divisor and returns | ||||
| // ceiling of the value. | ||||
| func convertResourceCPUToString(cpu *resource.Quantity, divisor resource.Quantity) (string, error) { | ||||
| 	c := int64(math.Ceil(float64(cpu.MilliValue()) / float64(divisor.MilliValue()))) | ||||
| 	return strconv.FormatInt(c, 10), nil | ||||
| } | ||||
|  | ||||
| // convertResourceMemoryToString converts memory value to the format of divisor and returns | ||||
| // ceiling of the value. | ||||
| func convertResourceMemoryToString(memory *resource.Quantity, divisor resource.Quantity) (string, error) { | ||||
| 	m := int64(math.Ceil(float64(memory.Value()) / float64(divisor.Value()))) | ||||
| 	return strconv.FormatInt(m, 10), nil | ||||
| } | ||||
|  | ||||
| // MergeContainerResourceLimits checks if a limit is applied for | ||||
| // the container, and if not, it sets the limit to the passed resource list. | ||||
| func MergeContainerResourceLimits(container *v1.Container, | ||||
| 	allocatable v1.ResourceList) { | ||||
| 	if container.Resources.Limits == nil { | ||||
| 		container.Resources.Limits = make(v1.ResourceList) | ||||
| 	} | ||||
| 	for _, resource := range []v1.ResourceName{v1.ResourceCPU, v1.ResourceMemory} { | ||||
| 		if quantity, exists := container.Resources.Limits[resource]; !exists || quantity.IsZero() { | ||||
| 			if cap, exists := allocatable[resource]; exists { | ||||
| 				container.Resources.Limits[resource] = *cap.Copy() | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -20,9 +20,6 @@ import ( | ||||
| 	"strings" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/stretchr/testify/assert" | ||||
|  | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"k8s.io/kubernetes/pkg/api/v1" | ||||
| ) | ||||
| @@ -119,119 +116,3 @@ func TestExtractFieldPathAsString(t *testing.T) { | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getPod(cname, cpuRequest, cpuLimit, memoryRequest, memoryLimit string) *v1.Pod { | ||||
| 	resources := v1.ResourceRequirements{ | ||||
| 		Limits:   make(v1.ResourceList), | ||||
| 		Requests: make(v1.ResourceList), | ||||
| 	} | ||||
| 	if cpuLimit != "" { | ||||
| 		resources.Limits[v1.ResourceCPU] = resource.MustParse(cpuLimit) | ||||
| 	} | ||||
| 	if memoryLimit != "" { | ||||
| 		resources.Limits[v1.ResourceMemory] = resource.MustParse(memoryLimit) | ||||
| 	} | ||||
| 	if cpuRequest != "" { | ||||
| 		resources.Requests[v1.ResourceCPU] = resource.MustParse(cpuRequest) | ||||
| 	} | ||||
| 	if memoryRequest != "" { | ||||
| 		resources.Requests[v1.ResourceMemory] = resource.MustParse(memoryRequest) | ||||
| 	} | ||||
| 	return &v1.Pod{ | ||||
| 		Spec: v1.PodSpec{ | ||||
| 			Containers: []v1.Container{ | ||||
| 				{ | ||||
| 					Name:      cname, | ||||
| 					Resources: resources, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestExtractResourceValue(t *testing.T) { | ||||
| 	cases := []struct { | ||||
| 		fs            *v1.ResourceFieldSelector | ||||
| 		pod           *v1.Pod | ||||
| 		cName         string | ||||
| 		expectedValue string | ||||
| 		expectedError error | ||||
| 	}{ | ||||
| 		{ | ||||
| 			fs: &v1.ResourceFieldSelector{ | ||||
| 				Resource: "limits.cpu", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "9", "", ""), | ||||
| 			expectedValue: "9", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &v1.ResourceFieldSelector{ | ||||
| 				Resource: "requests.cpu", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "", "", ""), | ||||
| 			expectedValue: "0", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &v1.ResourceFieldSelector{ | ||||
| 				Resource: "requests.cpu", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "8", "", "", ""), | ||||
| 			expectedValue: "8", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &v1.ResourceFieldSelector{ | ||||
| 				Resource: "requests.cpu", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "100m", "", "", ""), | ||||
| 			expectedValue: "1", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &v1.ResourceFieldSelector{ | ||||
| 				Resource: "requests.cpu", | ||||
| 				Divisor:  resource.MustParse("100m"), | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "1200m", "", "", ""), | ||||
| 			expectedValue: "12", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &v1.ResourceFieldSelector{ | ||||
| 				Resource: "requests.memory", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "", "100Mi", ""), | ||||
| 			expectedValue: "104857600", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &v1.ResourceFieldSelector{ | ||||
| 				Resource: "requests.memory", | ||||
| 				Divisor:  resource.MustParse("1Mi"), | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "", "100Mi", "1Gi"), | ||||
| 			expectedValue: "100", | ||||
| 		}, | ||||
| 		{ | ||||
| 			fs: &v1.ResourceFieldSelector{ | ||||
| 				Resource: "limits.memory", | ||||
| 			}, | ||||
| 			cName:         "foo", | ||||
| 			pod:           getPod("foo", "", "", "10Mi", "100Mi"), | ||||
| 			expectedValue: "104857600", | ||||
| 		}, | ||||
| 	} | ||||
| 	as := assert.New(t) | ||||
| 	for idx, tc := range cases { | ||||
| 		actual, err := ExtractResourceValueByContainerName(tc.fs, tc.pod, tc.cName) | ||||
| 		if tc.expectedError != nil { | ||||
| 			as.Equal(tc.expectedError, err, "expected test case [%d] to fail with error %v; got %v", idx, tc.expectedError, err) | ||||
| 		} else { | ||||
| 			as.Nil(err, "expected test case [%d] to not return an error; got %v", idx, err) | ||||
| 			as.Equal(tc.expectedValue, actual, "expected test case [%d] to return %q; got %q instead", idx, tc.expectedValue, actual) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -648,9 +648,9 @@ func (kl *Kubelet) podFieldSelectorRuntimeValue(fs *v1.ObjectFieldSelector, pod | ||||
| func containerResourceRuntimeValue(fs *v1.ResourceFieldSelector, pod *v1.Pod, container *v1.Container) (string, error) { | ||||
| 	containerName := fs.ContainerName | ||||
| 	if len(containerName) == 0 { | ||||
| 		return fieldpath.ExtractContainerResourceValue(fs, container) | ||||
| 		return v1.ExtractContainerResourceValue(fs, container) | ||||
| 	} else { | ||||
| 		return fieldpath.ExtractResourceValueByContainerName(fs, pod, containerName) | ||||
| 		return v1.ExtractResourceValueByContainerName(fs, pod, containerName) | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -23,7 +23,6 @@ import ( | ||||
|  | ||||
| 	"k8s.io/kubernetes/pkg/api" | ||||
| 	"k8s.io/kubernetes/pkg/api/v1" | ||||
| 	"k8s.io/kubernetes/pkg/fieldpath" | ||||
| ) | ||||
|  | ||||
| // defaultPodLimitsForDownwardApi copies the input pod, and optional container, | ||||
| @@ -53,7 +52,7 @@ func (kl *Kubelet) defaultPodLimitsForDownwardApi(pod *v1.Pod, container *v1.Con | ||||
| 		return nil, nil, fmt.Errorf("unexpected type returned from deep copy of pod object") | ||||
| 	} | ||||
| 	for idx := range outputPod.Spec.Containers { | ||||
| 		fieldpath.MergeContainerResourceLimits(&outputPod.Spec.Containers[idx], allocatable) | ||||
| 		v1.MergeContainerResourceLimits(&outputPod.Spec.Containers[idx], allocatable) | ||||
| 	} | ||||
|  | ||||
| 	var outputContainer *v1.Container | ||||
| @@ -66,7 +65,7 @@ func (kl *Kubelet) defaultPodLimitsForDownwardApi(pod *v1.Pod, container *v1.Con | ||||
| 		if !ok { | ||||
| 			return nil, nil, fmt.Errorf("unexpected type returned from deep copy of container object") | ||||
| 		} | ||||
| 		fieldpath.MergeContainerResourceLimits(outputContainer, allocatable) | ||||
| 		v1.MergeContainerResourceLimits(outputContainer, allocatable) | ||||
| 	} | ||||
| 	return outputPod, outputContainer, nil | ||||
| } | ||||
|   | ||||
| @@ -1100,7 +1100,7 @@ func describeContainerEnvVars(container api.Container, resolverFn EnvVarResolver | ||||
| 			} | ||||
| 			w.Write(LEVEL_3, "%s:\t%s (%s:%s)\n", e.Name, valueFrom, e.ValueFrom.FieldRef.APIVersion, e.ValueFrom.FieldRef.FieldPath) | ||||
| 		case e.ValueFrom.ResourceFieldRef != nil: | ||||
| 			valueFrom, err := fieldpath.InternalExtractContainerResourceValue(e.ValueFrom.ResourceFieldRef, &container) | ||||
| 			valueFrom, err := api.ExtractContainerResourceValue(e.ValueFrom.ResourceFieldRef, &container) | ||||
| 			if err != nil { | ||||
| 				valueFrom = "" | ||||
| 			} | ||||
|   | ||||
| @@ -244,7 +244,7 @@ func CollectData(items []v1.DownwardAPIVolumeFile, pod *v1.Pod, host volume.Volu | ||||
| 			nodeAllocatable, err := host.GetNodeAllocatable() | ||||
| 			if err != nil { | ||||
| 				errlist = append(errlist, err) | ||||
| 			} else if values, err := fieldpath.ExtractResourceValueByContainerNameAndNodeAllocatable(fileInfo.ResourceFieldRef, pod, containerName, nodeAllocatable); err != nil { | ||||
| 			} else if values, err := v1.ExtractResourceValueByContainerNameAndNodeAllocatable(fileInfo.ResourceFieldRef, pod, containerName, nodeAllocatable); err != nil { | ||||
| 				glog.Errorf("Unable to extract field %s: %s", fileInfo.ResourceFieldRef.Resource, err.Error()) | ||||
| 				errlist = append(errlist, err) | ||||
| 			} else { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Harry Zhang
					Harry Zhang