1
16
17 package apimachinery
18
19 import (
20 "context"
21 "encoding/json"
22 "fmt"
23 "reflect"
24 "strings"
25 "time"
26
27 "github.com/google/go-cmp/cmp"
28 "github.com/onsi/ginkgo/v2"
29 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
30 apiextensionclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
31 "k8s.io/apiextensions-apiserver/test/integration/fixtures"
32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
33 "k8s.io/apimachinery/pkg/runtime/schema"
34 "k8s.io/apimachinery/pkg/util/wait"
35 "k8s.io/apiserver/pkg/storage/names"
36 "k8s.io/client-go/dynamic"
37 "k8s.io/client-go/openapi3"
38 aggregatorclient "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset"
39 "k8s.io/kube-openapi/pkg/spec3"
40 imageutils "k8s.io/kubernetes/test/utils/image"
41 admissionapi "k8s.io/pod-security-admission/api"
42 samplev1beta1 "k8s.io/sample-apiserver/pkg/apis/wardle/v1beta1"
43
44 "k8s.io/kubernetes/test/e2e/framework"
45
46
47 _ "github.com/stretchr/testify/assert"
48 )
49
50 var _ = SIGDescribe("OpenAPIV3", func() {
51 f := framework.NewDefaultFramework("openapiv3")
52 f.NamespacePodSecurityLevel = admissionapi.LevelBaseline
53
54
59 ginkgo.It("should round trip OpenAPI V3 for all built-in group versions", func(ctx context.Context) {
60 c := openapi3.NewRoot(f.ClientSet.Discovery().OpenAPIV3())
61 gvs, err := c.GroupVersions()
62 framework.ExpectNoError(err)
63
64 builtinGVs := map[string]bool{
65 "apps": true,
66 "autoscaling": true,
67 "batch": true,
68 "policy": true,
69 }
70
71 for _, gv := range gvs {
72
73
74 if !strings.HasSuffix(gv.Group, "k8s.io") && !builtinGVs[gv.Group] {
75 continue
76 }
77 spec1, err := c.GVSpec(gv)
78 framework.ExpectNoError(err)
79 specMarshalled, err := json.Marshal(spec1)
80 framework.ExpectNoError(err)
81 var spec2 spec3.OpenAPI
82 json.Unmarshal(specMarshalled, &spec2)
83
84 if !reflect.DeepEqual(*spec1, spec2) {
85 diff := cmp.Diff(*spec1, spec2)
86 framework.Failf("%s", diff)
87 }
88 }
89 })
90
91
96 ginkgo.It("should publish OpenAPI V3 for CustomResourceDefinition", func(ctx context.Context) {
97 config, err := framework.LoadConfig()
98 framework.ExpectNoError(err)
99 apiExtensionClient, err := apiextensionclientset.NewForConfig(config)
100 framework.ExpectNoError(err)
101 dynamicClient, err := dynamic.NewForConfig(config)
102 framework.ExpectNoError(err)
103 resourceName := "testcrd"
104
105 groupName := fmt.Sprintf("%s.example.com", names.SimpleNameGenerator.GenerateName("group"))
106 crd := &apiextensionsv1.CustomResourceDefinition{
107 ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("%ss.%s", resourceName, groupName)},
108 Spec: apiextensionsv1.CustomResourceDefinitionSpec{
109 Group: groupName,
110 Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
111 {
112 Name: "v1beta1",
113 Served: true,
114 Storage: true,
115 Schema: fixtures.AllowAllSchema(),
116 },
117 },
118 Names: apiextensionsv1.CustomResourceDefinitionNames{
119 Plural: resourceName + "s",
120 Singular: resourceName,
121 Kind: resourceName,
122 ListKind: resourceName + "List",
123 },
124 Scope: apiextensionsv1.NamespaceScoped,
125 },
126 }
127 gv := schema.GroupVersion{Group: crd.Spec.Group, Version: crd.Spec.Versions[0].Name}
128 _, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
129 defer func() {
130 _ = fixtures.DeleteV1CustomResourceDefinition(crd, apiExtensionClient)
131 }()
132
133 framework.ExpectNoError(err)
134 c := openapi3.NewRoot(f.ClientSet.Discovery().OpenAPIV3())
135 var openAPISpec *spec3.OpenAPI
136
137 err = wait.PollUntilContextTimeout(context.Background(), time.Second*1, wait.ForeverTestTimeout, false, func(context.Context) (bool, error) {
138 openAPISpec, err = c.GVSpec(gv)
139 if err == nil {
140 return true, nil
141 }
142 return false, nil
143 })
144 framework.ExpectNoError(err, "timed out getting new CustomResourceDefinition")
145
146 specMarshalled, err := json.Marshal(openAPISpec)
147 framework.ExpectNoError(err)
148 var spec2 spec3.OpenAPI
149 json.Unmarshal(specMarshalled, &spec2)
150
151 if !reflect.DeepEqual(*openAPISpec, spec2) {
152 diff := cmp.Diff(*openAPISpec, spec2)
153 framework.Failf("%s", diff)
154 }
155
156 err = fixtures.DeleteV1CustomResourceDefinition(crd, apiExtensionClient)
157 framework.ExpectNoError(err, "deleting CustomResourceDefinition")
158
159 err = wait.PollUntilContextTimeout(ctx, time.Second*1, wait.ForeverTestTimeout, true, func(_ context.Context) (bool, error) {
160 _, err = c.GVSpec(gv)
161 if err == nil {
162 return false, nil
163 }
164 _, isNotFound := err.(*openapi3.GroupVersionNotFoundError)
165 return isNotFound, nil
166 })
167 framework.ExpectNoError(err, "should not contain OpenAPI V3 for deleted CustomResourceDefinition")
168 })
169
170
175 ginkgo.It("should contain OpenAPI V3 for Aggregated APIServer", func(ctx context.Context) {
176 config, err := framework.LoadConfig()
177 framework.ExpectNoError(err)
178 aggrclient, err := aggregatorclient.NewForConfig(config)
179 framework.ExpectNoError(err)
180 names := generateSampleAPIServerObjectNames(f.Namespace.Name)
181 SetUpSampleAPIServer(ctx, f, aggrclient, imageutils.GetE2EImage(imageutils.APIServer), names, samplev1beta1.GroupName, "v1beta1")
182 defer cleanupSampleAPIServer(ctx, f.ClientSet, aggrclient, names, "v1beta1.wardle.example.com")
183
184 c := openapi3.NewRoot(f.ClientSet.Discovery().OpenAPIV3())
185 gv := schema.GroupVersion{Group: samplev1beta1.GroupName, Version: "v1beta1"}
186 var openAPISpec *spec3.OpenAPI
187
188 wait.Poll(time.Second*1, wait.ForeverTestTimeout, func() (bool, error) {
189 openAPISpec, err = c.GVSpec(gv)
190 if err == nil {
191 return true, nil
192 }
193 return false, nil
194 })
195
196 specMarshalled, err := json.Marshal(openAPISpec)
197 framework.ExpectNoError(err)
198 var spec2 spec3.OpenAPI
199 json.Unmarshal(specMarshalled, &spec2)
200
201 if !reflect.DeepEqual(*openAPISpec, spec2) {
202 diff := cmp.Diff(*openAPISpec, spec2)
203 framework.Failf("%s", diff)
204 }
205
206 cleanupSampleAPIServer(ctx, f.ClientSet, aggrclient, names, "v1beta1.wardle.example.com")
207
208 err = wait.PollUntilContextTimeout(ctx, time.Second*1, wait.ForeverTestTimeout, true, func(_ context.Context) (bool, error) {
209 _, err = c.GVSpec(gv)
210 if err == nil {
211 return false, nil
212 }
213 _, isNotFound := err.(*openapi3.GroupVersionNotFoundError)
214 return isNotFound, nil
215 })
216 framework.ExpectNoError(err, "should not contain OpenAPI V3 for deleted APIService")
217 })
218 })
219
View as plain text