Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: wip deprecate test utils in favor of pod utils #6008

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions cluster-autoscaler/utils/test/common/test_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package common

import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
)

// GenerateOwnerReferences builds OwnerReferences with a single reference
func GenerateOwnerReferences(name, kind, api string, uid types.UID) []metav1.OwnerReference {
return []metav1.OwnerReference{
{
APIVersion: api,
Kind: kind,
Name: name,
BlockOwnerDeletion: boolptr(true),
Controller: boolptr(true),
UID: uid,
},
}
}

func boolptr(val bool) *bool {
b := val
return &b
}
196 changes: 196 additions & 0 deletions cluster-autoscaler/utils/test/pod/test_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/*
Copyright 2016 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package pod

import (
"fmt"

apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"

common "k8s.io/autoscaler/cluster-autoscaler/utils/test/common"
kube_types "k8s.io/kubernetes/pkg/kubelet/types"
)

const (
// cannot use constants from gpu module due to cyclic package import
resourceNvidiaGPU = "nvidia.com/gpu"
gpuLabel = "cloud.google.com/gke-accelerator"
defaultGPUType = "nvidia-tesla-k80"
)

func basePod(name string) *apiv1.Pod {
startTime := metav1.Unix(0, 0)
pod := &apiv1.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: types.UID(name),
Namespace: "default",
Name: name,
SelfLink: fmt.Sprintf("/api/v1/namespaces/default/pods/%s", name),
Annotations: map[string]string{},
},
Spec: apiv1.PodSpec{
Containers: []apiv1.Container{
{
Resources: apiv1.ResourceRequirements{
Requests: apiv1.ResourceList{},
},
},
},
},
Status: apiv1.PodStatus{
StartTime: &startTime,
},
}

return pod
}

// WithCPU adds requests.cpu (unit: number of CPUs) to all containers in the pod
func WithCPU(cpu int64) func(*apiv1.Pod) {
return func(pod *apiv1.Pod) {

for i := range pod.Spec.Containers {
pod.Spec.Containers[i].Resources.Requests[apiv1.ResourceCPU] = *resource.NewQuantity(cpu, resource.DecimalSI)
}
}
}

// WithMilliCPU adds requests.cpu (unit: number of milli CPUs) to all containers in the pod
func WithMilliCPU(cpu int64) func(*apiv1.Pod) {
return func(pod *apiv1.Pod) {

for i := range pod.Spec.Containers {
pod.Spec.Containers[i].Resources.Requests[apiv1.ResourceCPU] = *resource.NewMilliQuantity(cpu, resource.DecimalSI)
}
}
}

// WithMemory adds requests.memory to all the containers in the pod
func WithMemory(mem int64) func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {

for i := range pod.Spec.Containers {
pod.Spec.Containers[i].Resources.Requests[apiv1.ResourceMemory] = *resource.NewQuantity(mem, resource.DecimalSI)
}
}
}

// WithGPU adds requests.nvidia.com/gpu and limits.nvidia.com/gpu
// to all the containers in the pod
func WithGPU(gpusCount int64) func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {

for i := range pod.Spec.Containers {
pod.Spec.Containers[i].Resources.Requests[resourceNvidiaGPU] = *resource.NewQuantity(gpusCount, resource.DecimalSI)
pod.Spec.Containers[i].Resources.Limits[resourceNvidiaGPU] = *resource.NewQuantity(gpusCount, resource.DecimalSI)
}
}
}

// WithGPUToleration adds nvidia.com/gpu:Exists toleration to the pod
func WithGPUToleration() func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {
pod.Spec.Tolerations = append(pod.Spec.Tolerations, apiv1.Toleration{Key: resourceNvidiaGPU, Operator: apiv1.TolerationOpExists})
}
}

// WithAnnotations adds annotations to the pods
// note: if a key already exists, it will be overwritten
func WithAnnotations(anns map[string]string) func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {

for k, v := range anns {
pod.Annotations[k] = v
}
}
}

// WithOwnerRef adds owner ref to pod
func WithOwnerRef(ownerRefs []metav1.OwnerReference) func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {
pod.OwnerReferences = append(pod.OwnerReferences, ownerRefs...)
}
}

// WithEphemeralStorage adds requests.ephemeral-storage to all the containers in the pod
func WithEphemeralStorage(ephemeralStorage int64) func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {
for i := range pod.Spec.Containers {
pod.Spec.Containers[i].Resources.Requests[apiv1.ResourceEphemeralStorage] = *resource.NewQuantity(ephemeralStorage, resource.DecimalSI)
}
}
}

// ScheduledOnNode sets pod's spec.nodeName
func ScheduledOnNode(nodeName string) func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {
pod.Spec.NodeName = nodeName
}
}

// WithStaticPodAnnotation adds 'kubernetes.io/config.source: file' annotation to the pod
func WithStaticPodAnnotation() func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {
pod.Annotations[kube_types.ConfigSourceAnnotationKey] = kube_types.FileSource
}
}

// AsDaemonSetPod adds daemonset owner ref to the pod
func AsDaemonSetPod(uid string) func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {
pod.OwnerReferences = common.GenerateOwnerReferences("ds", "DaemonSet", "apps/v1", types.UID(uid))
}
}

// AsReplicaSetPod adds replicaset owner ref to the pod
func AsReplicaSetPod(uid string, rsName string) func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {
pod.OwnerReferences = common.GenerateOwnerReferences(rsName, "ReplicaSet", "extensions/v1beta1", types.UID(uid))
}
}

// WithMirrorPodAnnotation adds 'kubernetes.io/config.mirror: mirror' annotation to the pod
func WithMirrorPodAnnotation() func(*apiv1.Pod) {

return func(pod *apiv1.Pod) {
pod.ObjectMeta.Annotations[kube_types.ConfigMirrorAnnotationKey] = "mirror"
}
}

// NewTestPod creates pod with options passed as functions
func NewTestPod(name string, options ...func(*apiv1.Pod)) *apiv1.Pod {
pod := basePod(name)

for _, o := range options {
o(pod)
}

return pod
}
63 changes: 20 additions & 43 deletions cluster-autoscaler/utils/test/test_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,54 +29,26 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/autoscaler/cluster-autoscaler/cloudprovider"
kube_types "k8s.io/kubernetes/pkg/kubelet/types"
"k8s.io/autoscaler/cluster-autoscaler/utils/test/common"
po "k8s.io/autoscaler/cluster-autoscaler/utils/test/pod"
)

// BuildTestPod creates a pod with specified resources.
// [DEPRECATED]: use `NewTestPod` instead
func BuildTestPod(name string, cpu int64, mem int64) *apiv1.Pod {
startTime := metav1.Unix(0, 0)
pod := &apiv1.Pod{
ObjectMeta: metav1.ObjectMeta{
UID: types.UID(name),
Namespace: "default",
Name: name,
SelfLink: fmt.Sprintf("/api/v1/namespaces/default/pods/%s", name),
Annotations: map[string]string{},
},
Spec: apiv1.PodSpec{
Containers: []apiv1.Container{
{
Resources: apiv1.ResourceRequirements{
Requests: apiv1.ResourceList{},
},
},
},
},
Status: apiv1.PodStatus{
StartTime: &startTime,
},
}

if cpu >= 0 {
pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceCPU] = *resource.NewMilliQuantity(cpu, resource.DecimalSI)
}
if mem >= 0 {
pod.Spec.Containers[0].Resources.Requests[apiv1.ResourceMemory] = *resource.NewQuantity(mem, resource.DecimalSI)
}

return pod
return po.NewTestPod(name, po.WithMilliCPU(cpu), po.WithMemory(mem))
}

// BuildDSTestPod creates a DaemonSet pod with cpu and memory.
// [DEPRECATED]: use `NewTestPod` instead
func BuildDSTestPod(name string, cpu int64, mem int64) *apiv1.Pod {

pod := BuildTestPod(name, cpu, mem)
pod.OwnerReferences = GenerateOwnerReferences("ds", "DaemonSet", "apps/v1", "some-uid")

return pod
return po.NewTestPod(name, po.WithMilliCPU(cpu), po.WithMemory(mem),
po.WithOwnerRef(common.GenerateOwnerReferences("ds", "DaemonSet", "apps/v1", "some-uid")))
}

// BuildTestPodWithEphemeralStorage creates a pod with cpu, memory and ephemeral storage resources.
// [DEPRECATED]: use `NewTestPod` instead
func BuildTestPodWithEphemeralStorage(name string, cpu, mem, ephemeralStorage int64) *apiv1.Pod {
startTime := metav1.Unix(0, 0)
pod := &apiv1.Pod{
Expand Down Expand Up @@ -115,33 +87,36 @@ func BuildTestPodWithEphemeralStorage(name string, cpu, mem, ephemeralStorage in
}

// BuildScheduledTestPod builds a scheduled test pod with a given spec
// [DEPRECATED]: use `NewTestPod` instead
func BuildScheduledTestPod(name string, cpu, memory int64, nodeName string) *apiv1.Pod {
p := BuildTestPod(name, cpu, memory)
p.Spec.NodeName = nodeName
return p
return po.NewTestPod(name, po.WithMilliCPU(cpu), po.WithMemory(memory), po.ScheduledOnNode(nodeName))
}

// SetStaticPodSpec sets pod spec to make it a static pod
// [DEPRECATED]: use `NewTestPod` instead
func SetStaticPodSpec(pod *apiv1.Pod) *apiv1.Pod {
pod.Annotations[kube_types.ConfigSourceAnnotationKey] = kube_types.FileSource
po.WithStaticPodAnnotation()(pod)
return pod
}

// SetMirrorPodSpec sets pod spec to make it a mirror pod
// [DEPRECATED]: use `NewTestPod` instead
func SetMirrorPodSpec(pod *apiv1.Pod) *apiv1.Pod {
pod.ObjectMeta.Annotations[kube_types.ConfigMirrorAnnotationKey] = "mirror"
po.WithMirrorPodAnnotation()(pod)
return pod
}

// SetDSPodSpec sets pod spec to make it a DS pod
// [DEPRECATED]: use `NewTestPod` instead
func SetDSPodSpec(pod *apiv1.Pod) *apiv1.Pod {
pod.OwnerReferences = GenerateOwnerReferences("ds", "DaemonSet", "apps/v1", "api/v1/namespaces/default/daemonsets/ds")
po.WithOwnerRef(GenerateOwnerReferences("ds", "DaemonSet", "apps/v1", "api/v1/namespaces/default/daemonsets/ds"))(pod)
return pod
}

// SetRSPodSpec sets pod spec to make it a RS pod
// [DEPRECATED]: use `NewTestPod` instead
func SetRSPodSpec(pod *apiv1.Pod, rsName string) *apiv1.Pod {
pod.OwnerReferences = GenerateOwnerReferences(rsName, "ReplicaSet", "extensions/v1beta1", types.UID(rsName))
po.WithOwnerRef(GenerateOwnerReferences(rsName, "ReplicaSet", "extensions/v1beta1", types.UID(rsName)))(pod)
return pod
}

Expand All @@ -167,6 +142,7 @@ const (
)

// RequestGpuForPod modifies pod's resource requests by adding a number of GPUs to them.
// [DEPRECATED]: use `NewTestPod` instead
func RequestGpuForPod(pod *apiv1.Pod, gpusCount int64) {
if pod.Spec.Containers[0].Resources.Limits == nil {
pod.Spec.Containers[0].Resources.Limits = apiv1.ResourceList{}
Expand All @@ -180,6 +156,7 @@ func RequestGpuForPod(pod *apiv1.Pod, gpusCount int64) {
}

// TolerateGpuForPod adds toleration for nvidia.com/gpu to Pod
// [DEPRECATED]: use `NewTestPod` instead
func TolerateGpuForPod(pod *apiv1.Pod) {
pod.Spec.Tolerations = append(pod.Spec.Tolerations, apiv1.Toleration{Key: resourceNvidiaGPU, Operator: apiv1.TolerationOpExists})
}
Expand Down
Loading