mirror of https://github.com/k3s-io/k3s
Merge pull request #61010 from anubhakushwaha/IntegrationTesting
Automatic merge from submit-queue (batch tested with PRs 61010, 61315, 62268). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. Added test to check object size to the api-server **What this PR does / why we need it**: **Which issue(s) this PR fixes** Helps #47668 **Special notes for your reviewer**: So incase of `labels` there is a validation of specific label values to be `<63 characters` [here](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go#L89) But no upper limit on the total size of all labels combined. So I noticed the following errors while changing the sizes : a) request size > 1MB `etcdserver: request is too large` b) request size > 2MB `rpc error: code = ResourceExhausted desc = grpc: trying to send message larger than max ` I have added tests to check for the same, let me know your thoughts. @sttts @lavalamp @nikhita **Edit 1 :** Incase of both `labels` and `finalizers` there is no limit on overall object. `finalizers` too have an upper limit of `253` for each value [here](https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/util/validation/validation.go#L136) but no validation on the whole string array sizepull/8/head
commit
8c241357f5
|
@ -60,6 +60,7 @@ go_test(
|
|||
"//test/integration/framework:go_default_library",
|
||||
"//vendor/github.com/ghodss/yaml:go_default_library",
|
||||
"//vendor/k8s.io/api/admissionregistration/v1alpha1:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/apps/v1beta1:go_default_library",
|
||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||
"//vendor/k8s.io/api/networking/v1:go_default_library",
|
||||
|
|
|
@ -24,6 +24,7 @@ import (
|
|||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
@ -31,7 +32,9 @@ import (
|
|||
|
||||
"github.com/ghodss/yaml"
|
||||
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
"k8s.io/api/core/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
|
@ -41,6 +44,7 @@ import (
|
|||
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
||||
"k8s.io/apiserver/plugin/pkg/authenticator/token/tokentest"
|
||||
clientsetv1 "k8s.io/client-go/kubernetes"
|
||||
clienttypedv1 "k8s.io/client-go/kubernetes/typed/core/v1"
|
||||
restclient "k8s.io/client-go/rest"
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
|
@ -225,6 +229,116 @@ func TestStatus(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func constructBody(val string, size int, field string, t *testing.T) *appsv1.Deployment {
|
||||
var replicas int32 = 1
|
||||
deploymentObject := &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Deployment",
|
||||
APIVersion: "apps/v1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Namespace: "default",
|
||||
Name: "test",
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: map[string]string{
|
||||
"foo": "bar",
|
||||
},
|
||||
},
|
||||
Strategy: appsv1.DeploymentStrategy{
|
||||
Type: appsv1.RollingUpdateDeploymentStrategyType,
|
||||
},
|
||||
Template: corev1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: map[string]string{"foo": "bar"},
|
||||
},
|
||||
Spec: corev1.PodSpec{
|
||||
Containers: []corev1.Container{
|
||||
{
|
||||
Name: "foo",
|
||||
Image: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
switch field {
|
||||
case "labels":
|
||||
labelsMap := map[string]string{}
|
||||
for i := 0; i < size; i++ {
|
||||
key := val + strconv.Itoa(i)
|
||||
labelsMap[key] = val
|
||||
}
|
||||
deploymentObject.ObjectMeta.Labels = labelsMap
|
||||
case "annotations":
|
||||
annotationsMap := map[string]string{}
|
||||
for i := 0; i < size; i++ {
|
||||
key := val + strconv.Itoa(i)
|
||||
annotationsMap[key] = val
|
||||
}
|
||||
deploymentObject.ObjectMeta.Annotations = annotationsMap
|
||||
case "finalizers":
|
||||
finalizerString := []string{}
|
||||
for i := 0; i < size; i++ {
|
||||
finalizerString = append(finalizerString, val)
|
||||
}
|
||||
deploymentObject.ObjectMeta.Finalizers = finalizerString
|
||||
default:
|
||||
t.Fatalf("Unexpected field: %s used for making large deployment object value", field)
|
||||
}
|
||||
|
||||
return deploymentObject
|
||||
}
|
||||
|
||||
func TestObjectSizeResponses(t *testing.T) {
|
||||
_, s, closeFn := framework.RunAMaster(nil)
|
||||
defer closeFn()
|
||||
|
||||
client := clientsetv1.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: testapi.Groups[api.GroupName].GroupVersion()}})
|
||||
|
||||
const DeploymentMegabyteSize = 100000
|
||||
const DeploymentTwoMegabyteSize = 1000000
|
||||
|
||||
expectedMsgFor1MB := `etcdserver: request is too large`
|
||||
expectedMsgFor2MB := `rpc error: code = ResourceExhausted desc = grpc: trying to send message larger than max`
|
||||
expectedMsgForLargeAnnotation := `metadata.annotations: Too long: must have at most 262144 characters`
|
||||
|
||||
deployment1 := constructBody("a", DeploymentMegabyteSize, "labels", t) // >1 MB file
|
||||
deployment2 := constructBody("a", DeploymentTwoMegabyteSize, "labels", t) // >2 MB file
|
||||
|
||||
deployment3 := constructBody("a", DeploymentMegabyteSize, "annotations", t)
|
||||
|
||||
deployment4 := constructBody("sample/sample", DeploymentMegabyteSize, "finalizers", t) // >1 MB file
|
||||
deployment5 := constructBody("sample/sample", DeploymentTwoMegabyteSize, "finalizers", t) // >2 MB file
|
||||
|
||||
requests := []struct {
|
||||
size string
|
||||
deploymentObject *appsv1.Deployment
|
||||
expectedMessage string
|
||||
}{
|
||||
{"1 MB", deployment1, expectedMsgFor1MB},
|
||||
{"2 MB", deployment2, expectedMsgFor2MB},
|
||||
{"1 MB", deployment3, expectedMsgForLargeAnnotation},
|
||||
{"1 MB", deployment4, expectedMsgFor1MB},
|
||||
{"2 MB", deployment5, expectedMsgFor2MB},
|
||||
}
|
||||
|
||||
for _, r := range requests {
|
||||
t.Run(r.size, func(t *testing.T) {
|
||||
_, err := client.AppsV1().Deployments(metav1.NamespaceDefault).Create(r.deploymentObject)
|
||||
if err != nil {
|
||||
if !strings.Contains(err.Error(), r.expectedMessage) {
|
||||
t.Errorf("got: %s;want: %s", err.Error(), r.expectedMessage)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWatchSucceedsWithoutArgs(t *testing.T) {
|
||||
_, s, closeFn := framework.RunAMaster(nil)
|
||||
defer closeFn()
|
||||
|
|
Loading…
Reference in New Issue