mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-20 10:20:51 +00:00
Merge pull request #114947 from saschagrunert/seccomp-ga-cleanup
Make seccomp annotations non-functional
This commit is contained in:
commit
6ce055d62d
@ -785,31 +785,6 @@ func schedulingGatesInUse(podSpec *api.PodSpec) bool {
|
||||
return len(podSpec.SchedulingGates) != 0
|
||||
}
|
||||
|
||||
// SeccompAnnotationForField takes a pod seccomp profile field and returns the
|
||||
// converted annotation value
|
||||
func SeccompAnnotationForField(field *api.SeccompProfile) string {
|
||||
// If only seccomp fields are specified, add the corresponding annotations.
|
||||
// This ensures that the fields are enforced even if the node version
|
||||
// trails the API version
|
||||
switch field.Type {
|
||||
case api.SeccompProfileTypeUnconfined:
|
||||
return v1.SeccompProfileNameUnconfined
|
||||
|
||||
case api.SeccompProfileTypeRuntimeDefault:
|
||||
return v1.SeccompProfileRuntimeDefault
|
||||
|
||||
case api.SeccompProfileTypeLocalhost:
|
||||
if field.LocalhostProfile != nil {
|
||||
return v1.SeccompLocalhostProfileNamePrefix + *field.LocalhostProfile
|
||||
}
|
||||
}
|
||||
|
||||
// we can only reach this code path if the LocalhostProfile is nil but the
|
||||
// provided field type is SeccompProfileTypeLocalhost or if an unrecognized
|
||||
// type is specified
|
||||
return ""
|
||||
}
|
||||
|
||||
func hasInvalidLabelValueInAffinitySelector(spec *api.PodSpec) bool {
|
||||
if spec.Affinity != nil {
|
||||
if spec.Affinity.PodAffinity != nil {
|
||||
|
@ -210,7 +210,7 @@ func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta
|
||||
// use of pod seccomp annotation without accompanying field
|
||||
if podSpec.SecurityContext == nil || podSpec.SecurityContext.SeccompProfile == nil {
|
||||
if _, exists := meta.Annotations[api.SeccompPodAnnotationKey]; exists {
|
||||
warnings = append(warnings, fmt.Sprintf(`%s: deprecated since v1.19, non-functional in a future release; use the "seccompProfile" field instead`, fieldPath.Child("metadata", "annotations").Key(api.SeccompPodAnnotationKey)))
|
||||
warnings = append(warnings, fmt.Sprintf(`%s: non-functional in v1.27+; use the "seccompProfile" field instead`, fieldPath.Child("metadata", "annotations").Key(api.SeccompPodAnnotationKey)))
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,7 +218,7 @@ func warningsForPodSpecAndMeta(fieldPath *field.Path, podSpec *api.PodSpec, meta
|
||||
// use of container seccomp annotation without accompanying field
|
||||
if c.SecurityContext == nil || c.SecurityContext.SeccompProfile == nil {
|
||||
if _, exists := meta.Annotations[api.SeccompContainerAnnotationKeyPrefix+c.Name]; exists {
|
||||
warnings = append(warnings, fmt.Sprintf(`%s: deprecated since v1.19, non-functional in a future release; use the "seccompProfile" field instead`, fieldPath.Child("metadata", "annotations").Key(api.SeccompContainerAnnotationKeyPrefix+c.Name)))
|
||||
warnings = append(warnings, fmt.Sprintf(`%s: non-functional in v1.27+; use the "seccompProfile" field instead`, fieldPath.Child("metadata", "annotations").Key(api.SeccompContainerAnnotationKeyPrefix+c.Name)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -432,8 +432,8 @@ func TestWarnings(t *testing.T) {
|
||||
},
|
||||
expected: []string{
|
||||
`metadata.annotations[scheduler.alpha.kubernetes.io/critical-pod]: non-functional in v1.16+; use the "priorityClassName" field instead`,
|
||||
`metadata.annotations[seccomp.security.alpha.kubernetes.io/pod]: deprecated since v1.19, non-functional in a future release; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[container.seccomp.security.alpha.kubernetes.io/foo]: deprecated since v1.19, non-functional in a future release; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[seccomp.security.alpha.kubernetes.io/pod]: non-functional in v1.27+; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[container.seccomp.security.alpha.kubernetes.io/foo]: non-functional in v1.27+; use the "seccompProfile" field instead`,
|
||||
`metadata.annotations[security.alpha.kubernetes.io/sysctls]: non-functional in v1.11+; use the "sysctls" field instead`,
|
||||
`metadata.annotations[security.alpha.kubernetes.io/unsafe-sysctls]: non-functional in v1.11+; use the "sysctls" field instead`,
|
||||
},
|
||||
|
@ -26,7 +26,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/fields"
|
||||
@ -89,7 +88,6 @@ func (podStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
|
||||
podutil.DropDisabledPodFields(pod, nil)
|
||||
|
||||
applySeccompVersionSkew(pod)
|
||||
applyWaitingForSchedulingGatesCondition(pod)
|
||||
}
|
||||
|
||||
@ -674,86 +672,3 @@ func applyWaitingForSchedulingGatesCondition(pod *api.Pod) {
|
||||
Message: "Scheduling is blocked due to non-empty scheduling gates",
|
||||
})
|
||||
}
|
||||
|
||||
// applySeccompVersionSkew implements the version skew behavior described in:
|
||||
// https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/135-seccomp#version-skew-strategy
|
||||
// Note that we dropped copying the field to annotation synchronization in
|
||||
// v1.25 with the functional removal of the annotations.
|
||||
func applySeccompVersionSkew(pod *api.Pod) {
|
||||
// get possible annotation and field
|
||||
annotation, hasAnnotation := pod.Annotations[v1.SeccompPodAnnotationKey]
|
||||
hasField := false
|
||||
|
||||
if pod.Spec.SecurityContext != nil && pod.Spec.SecurityContext.SeccompProfile != nil {
|
||||
hasField = true
|
||||
}
|
||||
|
||||
// sync field and annotation
|
||||
if hasAnnotation && !hasField {
|
||||
newField := seccompFieldForAnnotation(annotation)
|
||||
|
||||
if newField != nil {
|
||||
if pod.Spec.SecurityContext == nil {
|
||||
pod.Spec.SecurityContext = &api.PodSecurityContext{}
|
||||
}
|
||||
pod.Spec.SecurityContext.SeccompProfile = newField
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the containers of the pod
|
||||
podutil.VisitContainers(&pod.Spec, podutil.AllFeatureEnabledContainers(),
|
||||
func(ctr *api.Container, _ podutil.ContainerType) bool {
|
||||
// get possible annotation and field
|
||||
key := api.SeccompContainerAnnotationKeyPrefix + ctr.Name
|
||||
annotation, hasAnnotation := pod.Annotations[key]
|
||||
|
||||
hasField := false
|
||||
if ctr.SecurityContext != nil && ctr.SecurityContext.SeccompProfile != nil {
|
||||
hasField = true
|
||||
}
|
||||
|
||||
// sync field and annotation
|
||||
if hasAnnotation && !hasField {
|
||||
newField := seccompFieldForAnnotation(annotation)
|
||||
|
||||
if newField != nil {
|
||||
if ctr.SecurityContext == nil {
|
||||
ctr.SecurityContext = &api.SecurityContext{}
|
||||
}
|
||||
ctr.SecurityContext.SeccompProfile = newField
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
// seccompFieldForAnnotation takes a pod annotation and returns the converted
|
||||
// seccomp profile field.
|
||||
func seccompFieldForAnnotation(annotation string) *api.SeccompProfile {
|
||||
// If only seccomp annotations are specified, copy the values into the
|
||||
// corresponding fields. This ensures that existing applications continue
|
||||
// to enforce seccomp, and prevents the kubelet from needing to resolve
|
||||
// annotations & fields.
|
||||
if annotation == v1.SeccompProfileNameUnconfined {
|
||||
return &api.SeccompProfile{Type: api.SeccompProfileTypeUnconfined}
|
||||
}
|
||||
|
||||
if annotation == api.SeccompProfileRuntimeDefault || annotation == api.DeprecatedSeccompProfileDockerDefault {
|
||||
return &api.SeccompProfile{Type: api.SeccompProfileTypeRuntimeDefault}
|
||||
}
|
||||
|
||||
if strings.HasPrefix(annotation, v1.SeccompLocalhostProfileNamePrefix) {
|
||||
localhostProfile := strings.TrimPrefix(annotation, v1.SeccompLocalhostProfileNamePrefix)
|
||||
if localhostProfile != "" {
|
||||
return &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeLocalhost,
|
||||
LocalhostProfile: &localhostProfile,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we can only reach this code path if the localhostProfile name has a zero
|
||||
// length or if the annotation has an unrecognized value
|
||||
return nil
|
||||
}
|
||||
|
@ -26,8 +26,6 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/google/go-cmp/cmp/cmpopts"
|
||||
"github.com/stretchr/testify/require"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/resource"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -794,316 +792,6 @@ func TestPodIndexFunc(t *testing.T) {
|
||||
|
||||
}
|
||||
}
|
||||
func TestApplySeccompVersionSkew(t *testing.T) {
|
||||
const containerName = "container"
|
||||
testProfile := "test"
|
||||
|
||||
for _, test := range []struct {
|
||||
description string
|
||||
pod *api.Pod
|
||||
validation func(*testing.T, *api.Pod)
|
||||
}{
|
||||
{
|
||||
description: "Security context nil",
|
||||
pod: &api.Pod{},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.NotNil(t, pod)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Security context not nil",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{SecurityContext: &api.PodSecurityContext{}},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.NotNil(t, pod)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Field set and no annotation present",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
SecurityContext: &api.PodSecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 0)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Annotation 'unconfined' and no field present",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompPodAnnotationKey: v1.SeccompProfileNameUnconfined,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Equal(t, api.SeccompProfileTypeUnconfined, pod.Spec.SecurityContext.SeccompProfile.Type)
|
||||
require.Nil(t, pod.Spec.SecurityContext.SeccompProfile.LocalhostProfile)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Annotation 'runtime/default' and no field present",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompPodAnnotationKey: v1.SeccompProfileRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{SecurityContext: &api.PodSecurityContext{}},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Equal(t, api.SeccompProfileTypeRuntimeDefault, pod.Spec.SecurityContext.SeccompProfile.Type)
|
||||
require.Nil(t, pod.Spec.SecurityContext.SeccompProfile.LocalhostProfile)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Annotation 'docker/default' and no field present",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompPodAnnotationKey: v1.DeprecatedSeccompProfileDockerDefault,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{SecurityContext: &api.PodSecurityContext{}},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Equal(t, api.SeccompProfileTypeRuntimeDefault, pod.Spec.SecurityContext.SeccompProfile.Type)
|
||||
require.Nil(t, pod.Spec.SecurityContext.SeccompProfile.LocalhostProfile)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Annotation 'localhost/test' and no field present",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompPodAnnotationKey: v1.SeccompLocalhostProfileNamePrefix + testProfile,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{SecurityContext: &api.PodSecurityContext{}},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Equal(t, api.SeccompProfileTypeLocalhost, pod.Spec.SecurityContext.SeccompProfile.Type)
|
||||
require.Equal(t, testProfile, *pod.Spec.SecurityContext.SeccompProfile.LocalhostProfile)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Annotation 'localhost/' has zero length",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompPodAnnotationKey: v1.SeccompLocalhostProfileNamePrefix,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{SecurityContext: &api.PodSecurityContext{}},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Nil(t, pod.Spec.SecurityContext.SeccompProfile)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Security context nil (container)",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.NotNil(t, pod)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Security context not nil (container)",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
SecurityContext: &api.SecurityContext{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.NotNil(t, pod)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Field set and no annotation present (container)",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: containerName,
|
||||
SecurityContext: &api.SecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 0)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Multiple containers with fields (container)",
|
||||
pod: &api.Pod{
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{
|
||||
Name: containerName + "1",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeUnconfined,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: containerName + "2",
|
||||
},
|
||||
{
|
||||
Name: containerName + "3",
|
||||
SecurityContext: &api.SecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileTypeRuntimeDefault,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Len(t, pod.Annotations, 0)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Annotation 'unconfined' and no field present (container)",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompContainerAnnotationKeyPrefix + containerName: v1.SeccompProfileNameUnconfined,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
Name: containerName,
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Equal(t, api.SeccompProfileTypeUnconfined, pod.Spec.Containers[0].SecurityContext.SeccompProfile.Type)
|
||||
require.Nil(t, pod.Spec.Containers[0].SecurityContext.SeccompProfile.LocalhostProfile)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Annotation 'runtime/default' and no field present (container)",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompContainerAnnotationKeyPrefix + containerName: v1.SeccompProfileRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &api.SecurityContext{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Equal(t, api.SeccompProfileTypeRuntimeDefault, pod.Spec.Containers[0].SecurityContext.SeccompProfile.Type)
|
||||
require.Nil(t, pod.Spec.Containers[0].SecurityContext.SeccompProfile.LocalhostProfile)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Annotation 'docker/default' and no field present (container)",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompContainerAnnotationKeyPrefix + containerName: v1.DeprecatedSeccompProfileDockerDefault,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &api.SecurityContext{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Equal(t, api.SeccompProfileTypeRuntimeDefault, pod.Spec.Containers[0].SecurityContext.SeccompProfile.Type)
|
||||
require.Nil(t, pod.Spec.Containers[0].SecurityContext.SeccompProfile.LocalhostProfile)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Multiple containers by annotations (container)",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompContainerAnnotationKeyPrefix + containerName + "1": v1.SeccompLocalhostProfileNamePrefix + testProfile,
|
||||
v1.SeccompContainerAnnotationKeyPrefix + containerName + "3": v1.SeccompProfileRuntimeDefault,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{
|
||||
{Name: containerName + "1"},
|
||||
{Name: containerName + "2"},
|
||||
{Name: containerName + "3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Equal(t, api.SeccompProfileTypeLocalhost, pod.Spec.Containers[0].SecurityContext.SeccompProfile.Type)
|
||||
require.Equal(t, testProfile, *pod.Spec.Containers[0].SecurityContext.SeccompProfile.LocalhostProfile)
|
||||
require.Equal(t, api.SeccompProfileTypeRuntimeDefault, pod.Spec.Containers[2].SecurityContext.SeccompProfile.Type)
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Annotation 'localhost/test' and no field present (container)",
|
||||
pod: &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Annotations: map[string]string{
|
||||
v1.SeccompContainerAnnotationKeyPrefix + containerName: v1.SeccompLocalhostProfileNamePrefix + testProfile,
|
||||
},
|
||||
},
|
||||
Spec: api.PodSpec{
|
||||
Containers: []api.Container{{
|
||||
Name: containerName,
|
||||
SecurityContext: &api.SecurityContext{},
|
||||
}},
|
||||
},
|
||||
},
|
||||
validation: func(t *testing.T, pod *api.Pod) {
|
||||
require.Equal(t, api.SeccompProfileTypeLocalhost, pod.Spec.Containers[0].SecurityContext.SeccompProfile.Type)
|
||||
require.Equal(t, testProfile, *pod.Spec.Containers[0].SecurityContext.SeccompProfile.LocalhostProfile)
|
||||
},
|
||||
},
|
||||
} {
|
||||
output := &api.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}},
|
||||
}
|
||||
for i, ctr := range test.pod.Spec.Containers {
|
||||
output.Spec.Containers = append(output.Spec.Containers, api.Container{})
|
||||
if ctr.SecurityContext != nil && ctr.SecurityContext.SeccompProfile != nil {
|
||||
output.Spec.Containers[i].SecurityContext = &api.SecurityContext{
|
||||
SeccompProfile: &api.SeccompProfile{
|
||||
Type: api.SeccompProfileType(ctr.SecurityContext.SeccompProfile.Type),
|
||||
LocalhostProfile: ctr.SecurityContext.SeccompProfile.LocalhostProfile,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
applySeccompVersionSkew(test.pod)
|
||||
test.validation(t, test.pod)
|
||||
}
|
||||
}
|
||||
|
||||
func newPodWithHugePageValue(resourceName api.ResourceName, value resource.Quantity) *api.Pod {
|
||||
return &api.Pod{
|
||||
|
Loading…
Reference in New Issue
Block a user