...

Source file src/k8s.io/kubernetes/test/e2e/apimachinery/table_conversion.go

Documentation: k8s.io/kubernetes/test/e2e/apimachinery

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package apimachinery
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"fmt"
    23  	"text/tabwriter"
    24  
    25  	"github.com/onsi/ginkgo/v2"
    26  	"github.com/onsi/gomega"
    27  
    28  	authorizationv1 "k8s.io/api/authorization/v1"
    29  	v1 "k8s.io/api/core/v1"
    30  	apierrors "k8s.io/apimachinery/pkg/api/errors"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1"
    33  	"k8s.io/client-go/util/workqueue"
    34  	admissionapi "k8s.io/pod-security-admission/api"
    35  
    36  	utilversion "k8s.io/apimachinery/pkg/util/version"
    37  	"k8s.io/cli-runtime/pkg/printers"
    38  	"k8s.io/kubernetes/test/e2e/framework"
    39  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    40  	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
    41  )
    42  
    43  var serverPrintVersion = utilversion.MustParseSemantic("v1.10.0")
    44  
    45  var _ = SIGDescribe("Servers with support for Table transformation", func() {
    46  	f := framework.NewDefaultFramework("tables")
    47  	f.NamespacePodSecurityLevel = admissionapi.LevelBaseline
    48  
    49  	ginkgo.BeforeEach(func() {
    50  		e2eskipper.SkipUnlessServerVersionGTE(serverPrintVersion, f.ClientSet.Discovery())
    51  	})
    52  
    53  	ginkgo.It("should return pod details", func(ctx context.Context) {
    54  		ns := f.Namespace.Name
    55  		c := f.ClientSet
    56  
    57  		podName := "pod-1"
    58  		framework.Logf("Creating pod %s", podName)
    59  
    60  		_, err := c.CoreV1().Pods(ns).Create(ctx, newTablePod(ns, podName), metav1.CreateOptions{})
    61  		framework.ExpectNoError(err, "failed to create pod %s in namespace: %s", podName, ns)
    62  
    63  		table := &metav1beta1.Table{}
    64  		err = c.CoreV1().RESTClient().Get().Resource("pods").Namespace(ns).Name(podName).SetHeader("Accept", "application/json;as=Table;v=v1beta1;g=meta.k8s.io").Do(ctx).Into(table)
    65  		framework.ExpectNoError(err, "failed to get pod %s in Table form in namespace: %s", podName, ns)
    66  		framework.Logf("Table: %#v", table)
    67  
    68  		gomega.Expect(len(table.ColumnDefinitions)).To(gomega.BeNumerically(">", 2))
    69  		gomega.Expect(table.Rows).To(gomega.HaveLen(1))
    70  		gomega.Expect(table.Rows[0].Cells).To(gomega.HaveLen(len(table.ColumnDefinitions)))
    71  		gomega.Expect(table.ColumnDefinitions[0].Name).To(gomega.Equal("Name"))
    72  		gomega.Expect(table.Rows[0].Cells[0]).To(gomega.Equal(podName))
    73  
    74  		out := printTable(table)
    75  		gomega.Expect(out).To(gomega.MatchRegexp("^NAME\\s"))
    76  		gomega.Expect(out).To(gomega.MatchRegexp("\npod-1\\s"))
    77  		framework.Logf("Table:\n%s", out)
    78  	})
    79  
    80  	ginkgo.It("should return chunks of table results for list calls", func(ctx context.Context) {
    81  		ns := f.Namespace.Name
    82  		c := f.ClientSet
    83  		client := c.CoreV1().PodTemplates(ns)
    84  
    85  		ginkgo.By("creating a large number of resources")
    86  		workqueue.ParallelizeUntil(ctx, 5, 20, func(i int) {
    87  			for tries := 3; tries >= 0; tries-- {
    88  				_, err := client.Create(ctx, &v1.PodTemplate{
    89  					ObjectMeta: metav1.ObjectMeta{
    90  						Name: fmt.Sprintf("template-%04d", i),
    91  					},
    92  					Template: v1.PodTemplateSpec{
    93  						Spec: v1.PodSpec{
    94  							Containers: []v1.Container{
    95  								{Name: "test", Image: "test2"},
    96  							},
    97  						},
    98  					},
    99  				}, metav1.CreateOptions{})
   100  				if err == nil {
   101  					return
   102  				}
   103  				framework.Logf("Got an error creating template %d: %v", i, err)
   104  			}
   105  			framework.Failf("Unable to create template %d, exiting", i)
   106  		})
   107  
   108  		pagedTable := &metav1beta1.Table{}
   109  		err := c.CoreV1().RESTClient().Get().Namespace(ns).Resource("podtemplates").
   110  			VersionedParams(&metav1.ListOptions{Limit: 2}, metav1.ParameterCodec).
   111  			SetHeader("Accept", "application/json;as=Table;v=v1beta1;g=meta.k8s.io").
   112  			Do(ctx).Into(pagedTable)
   113  		framework.ExpectNoError(err, "failed to get pod templates in Table form in namespace: %s", ns)
   114  		gomega.Expect(pagedTable.Rows).To(gomega.HaveLen(2))
   115  		gomega.Expect(pagedTable.ResourceVersion).ToNot(gomega.BeEmpty())
   116  		gomega.Expect(pagedTable.Continue).ToNot(gomega.BeEmpty())
   117  		gomega.Expect(pagedTable.Rows[0].Cells[0]).To(gomega.Equal("template-0000"))
   118  		gomega.Expect(pagedTable.Rows[1].Cells[0]).To(gomega.Equal("template-0001"))
   119  
   120  		err = c.CoreV1().RESTClient().Get().Namespace(ns).Resource("podtemplates").
   121  			VersionedParams(&metav1.ListOptions{Continue: pagedTable.Continue}, metav1.ParameterCodec).
   122  			SetHeader("Accept", "application/json;as=Table;v=v1beta1;g=meta.k8s.io").
   123  			Do(ctx).Into(pagedTable)
   124  		framework.ExpectNoError(err, "failed to get pod templates in Table form in namespace: %s", ns)
   125  		gomega.Expect(pagedTable.Rows).ToNot(gomega.BeEmpty())
   126  		gomega.Expect(pagedTable.Rows[0].Cells[0]).To(gomega.Equal("template-0002"))
   127  	})
   128  
   129  	ginkgo.It("should return generic metadata details across all namespaces for nodes", func(ctx context.Context) {
   130  		c := f.ClientSet
   131  
   132  		table := &metav1beta1.Table{}
   133  		err := c.CoreV1().RESTClient().Get().Resource("nodes").SetHeader("Accept", "application/json;as=Table;v=v1beta1;g=meta.k8s.io").Do(ctx).Into(table)
   134  		framework.ExpectNoError(err, "failed to get nodes in Table form across all namespaces")
   135  		framework.Logf("Table: %#v", table)
   136  
   137  		gomega.Expect(len(table.ColumnDefinitions)).To(gomega.BeNumerically(">=", 2))
   138  		gomega.Expect(table.Rows).ToNot(gomega.BeEmpty())
   139  		gomega.Expect(table.Rows[0].Cells).To(gomega.HaveLen(len(table.ColumnDefinitions)))
   140  		gomega.Expect(table.ColumnDefinitions[0].Name).To(gomega.Equal("Name"))
   141  		gomega.Expect(table.ResourceVersion).ToNot(gomega.BeEmpty())
   142  
   143  		out := printTable(table)
   144  		gomega.Expect(out).To(gomega.MatchRegexp("^NAME\\s"))
   145  		framework.Logf("Table:\n%s", out)
   146  	})
   147  
   148  	/*
   149  			    Release: v1.16
   150  				Testname: API metadata HTTP return
   151  				Description: Issue a HTTP request to the API.
   152  		        HTTP request MUST return a HTTP status code of 406.
   153  	*/
   154  	framework.ConformanceIt("should return a 406 for a backend which does not implement metadata", func(ctx context.Context) {
   155  		c := f.ClientSet
   156  
   157  		table := &metav1beta1.Table{}
   158  		sar := &authorizationv1.SelfSubjectAccessReview{
   159  			Spec: authorizationv1.SelfSubjectAccessReviewSpec{
   160  				NonResourceAttributes: &authorizationv1.NonResourceAttributes{
   161  					Path: "/",
   162  					Verb: "get",
   163  				},
   164  			},
   165  		}
   166  		err := c.AuthorizationV1().RESTClient().Post().Resource("selfsubjectaccessreviews").SetHeader("Accept", "application/json;as=Table;v=v1;g=meta.k8s.io").Body(sar).Do(ctx).Into(table)
   167  		gomega.Expect(err).To(gomega.HaveOccurred(), "failed to return error when posting self subject access review: %+v, to a backend that does not implement metadata", sar)
   168  		gomega.Expect(err.(apierrors.APIStatus)).To(gomega.HaveField("Status().Code", gomega.Equal(int32(406))))
   169  	})
   170  })
   171  
   172  func printTable(table *metav1beta1.Table) string {
   173  	buf := &bytes.Buffer{}
   174  	tw := tabwriter.NewWriter(buf, 5, 8, 1, ' ', 0)
   175  	printer := printers.NewTablePrinter(printers.PrintOptions{})
   176  	err := printer.PrintObj(table, tw)
   177  	framework.ExpectNoError(err, "failed to print table: %+v", table)
   178  	tw.Flush()
   179  	return buf.String()
   180  }
   181  
   182  func newTablePod(ns, podName string) *v1.Pod {
   183  	port := 8080
   184  	pod := e2epod.NewAgnhostPod(ns, podName, nil, nil, []v1.ContainerPort{{ContainerPort: int32(port)}}, "porter")
   185  	pod.Spec.Containers[0].Env = []v1.EnvVar{{Name: fmt.Sprintf("SERVE_PORT_%d", port), Value: "foo"}}
   186  	pod.Spec.RestartPolicy = v1.RestartPolicyNever
   187  	return pod
   188  }
   189  

View as plain text