Merge pull request #99101 from deads2k/crd-beta-prune

stop using CRD v1beta1 in tests
This commit is contained in:
Kubernetes Prow Robot 2021-03-03 08:39:21 -08:00 committed by GitHub
commit 2f263b24a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 1127 additions and 949 deletions

View File

@ -21,7 +21,7 @@ import (
"testing"
"time"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"
@ -34,43 +34,50 @@ func TestAPIApproval(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
if noxuAPIApproved := findCRDCondition(noxuDefinition, apiextensionsv1beta1.KubernetesAPIApprovalPolicyConformant); noxuAPIApproved != nil {
if noxuAPIApproved := findCRDCondition(noxuDefinition, apiextensionsv1.KubernetesAPIApprovalPolicyConformant); noxuAPIApproved != nil {
t.Fatal(noxuAPIApproved)
}
newSigKubeAPIFn := func(resource, approvalAnnotation string) *apiextensionsv1beta1.CustomResourceDefinition {
return &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: resource + ".sigs.k8s.io", Annotations: map[string]string{apiextensionsv1beta1.KubeAPIApprovedAnnotation: approvalAnnotation}},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "sigs.k8s.io",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
newSigKubeAPIFn := func(resource, approvalAnnotation string) *apiextensionsv1.CustomResourceDefinition {
return &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: resource + ".sigs.k8s.io", Annotations: map[string]string{apiextensionsv1.KubeAPIApprovedAnnotation: approvalAnnotation}},
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "sigs.k8s.io",
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
Schema: fixtures.AllowAllSchema(),
},
},
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: resource,
Singular: resource + "singular",
Kind: resource + "Kind",
ListKind: resource + "List",
},
Scope: apiextensionsv1beta1.NamespaceScoped,
Scope: apiextensionsv1.NamespaceScoped,
},
}
}
// the unit tests cover all variations. We just need to be sure that we see the code being called
approvedKubeAPI := newSigKubeAPIFn("approved", "https://github.com/kubernetes/kubernetes/pull/79724")
approvedKubeAPI, err = fixtures.CreateNewCustomResourceDefinition(approvedKubeAPI, apiExtensionClient, dynamicClient)
approvedKubeAPI, err = fixtures.CreateNewV1CustomResourceDefinition(approvedKubeAPI, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
err = wait.PollImmediate(100*time.Millisecond, 30*time.Second, func() (bool, error) {
approvedKubeAPI, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), approvedKubeAPI.Name, metav1.GetOptions{})
approvedKubeAPI, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), approvedKubeAPI.Name, metav1.GetOptions{})
if err != nil {
return false, err
}
if approvedKubeAPIApproved := findCRDCondition(approvedKubeAPI, apiextensionsv1beta1.KubernetesAPIApprovalPolicyConformant); approvedKubeAPIApproved == nil || approvedKubeAPIApproved.Status != apiextensionsv1beta1.ConditionTrue {
if approvedKubeAPIApproved := findCRDCondition(approvedKubeAPI, apiextensionsv1.KubernetesAPIApprovalPolicyConformant); approvedKubeAPIApproved == nil || approvedKubeAPIApproved.Status != apiextensionsv1.ConditionTrue {
t.Log(approvedKubeAPIApproved)
return false, nil
}

View File

@ -21,7 +21,7 @@ import (
"fmt"
"testing"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
"k8s.io/apimachinery/pkg/api/errors"
@ -50,14 +50,14 @@ func TestApplyBasic(t *testing.T) {
t.Fatal(err)
}
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
kind := noxuDefinition.Spec.Names.Kind
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Version
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
rest := apiExtensionClient.Discovery().RESTClient()
yamlBody := []byte(fmt.Sprintf(`
@ -70,7 +70,7 @@ values:
boolVal: true
stringVal: "1"`, apiVersion, kind))
result, err := rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name("mytest").
Param("fieldManager", "apply_test").
Body(yamlBody).
@ -80,7 +80,7 @@ values:
}
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name("mytest").
Body([]byte(`{"values":{"numVal": 5}}`)).
DoRaw(context.TODO())
@ -90,7 +90,7 @@ values:
// Re-apply the same object, we should get conflicts now.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name("mytest").
Param("fieldManager", "apply_test").
Body(yamlBody).
@ -108,7 +108,7 @@ values:
// Re-apply with force, should work fine.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name("mytest").
Param("force", "true").
Param("fieldManager", "apply_test").

View File

@ -25,7 +25,7 @@ import (
"testing"
"time"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
@ -56,8 +56,8 @@ func TestNamespaceScopedCRUD(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -75,8 +75,8 @@ func TestClusterScopedCRUD(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -86,7 +86,7 @@ func TestClusterScopedCRUD(t *testing.T) {
testFieldSelector(t, ns, noxuDefinition, dynamicClient)
}
func testSimpleCRUD(t *testing.T, ns string, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition, dynamicClient dynamic.Interface) {
func testSimpleCRUD(t *testing.T, ns string, noxuDefinition *apiextensionsv1.CustomResourceDefinition, dynamicClient dynamic.Interface) {
noxuResourceClients := map[string]dynamic.ResourceInterface{}
noxuWatchs := map[string]watch.Interface{}
disabledVersions := map[string]bool{}
@ -321,8 +321,8 @@ func TestInvalidCRUD(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -373,7 +373,7 @@ func TestInvalidCRUD(t *testing.T) {
}
}
func testFieldSelector(t *testing.T, ns string, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition, dynamicClient dynamic.Interface) {
func testFieldSelector(t *testing.T, ns string, noxuDefinition *apiextensionsv1.CustomResourceDefinition, dynamicClient dynamic.Interface) {
noxuResourceClient := newNamespacedCustomResourceClient(ns, dynamicClient, noxuDefinition)
initialList, err := noxuResourceClient.List(context.TODO(), metav1.ListOptions{})
if err != nil {
@ -527,9 +527,9 @@ func TestDiscovery(t *testing.T) {
}
defer tearDown()
scope := apiextensionsv1beta1.NamespaceScoped
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(scope)
if _, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient); err != nil {
scope := apiextensionsv1.NamespaceScoped
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(scope)
if _, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient); err != nil {
t.Fatal(err)
}
@ -574,8 +574,8 @@ func TestNoNamespaceReject(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -593,7 +593,7 @@ func TestNoNamespaceReject(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if e, a := noxuDefinition.Spec.Group+"/"+noxuDefinition.Spec.Version, initialListTypeMeta.GetAPIVersion(); e != a {
if e, a := noxuDefinition.Spec.Group+"/"+noxuDefinition.Spec.Versions[0].Name, initialListTypeMeta.GetAPIVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := noxuDefinition.Spec.Names.ListKind, initialListTypeMeta.GetKind(); e != a {
@ -613,8 +613,8 @@ func TestSameNameDiffNamespace(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -636,8 +636,8 @@ func TestSelfLink(t *testing.T) {
defer tearDown()
// namespace scoped
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -656,8 +656,8 @@ func TestSelfLink(t *testing.T) {
}
// cluster scoped
curletDefinition := fixtures.NewCurletCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
curletDefinition, err = fixtures.CreateNewCustomResourceDefinition(curletDefinition, apiExtensionClient, dynamicClient)
curletDefinition := fixtures.NewCurletV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
curletDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(curletDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -682,8 +682,8 @@ func TestPreserveInt(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -724,8 +724,8 @@ func TestPatch(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -802,8 +802,8 @@ func TestCrossNamespaceListWatch(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -881,7 +881,7 @@ func TestCrossNamespaceListWatch(t *testing.T) {
if err != nil {
t.Fatal(err)
}
if e, a := noxuDefinition.Spec.Group+"/"+noxuDefinition.Spec.Version, createdTypeMeta.GetAPIVersion(); e != a {
if e, a := noxuDefinition.Spec.Group+"/"+noxuDefinition.Spec.Versions[0].Name, createdTypeMeta.GetAPIVersion(); e != a {
t.Errorf("expected %v, got %v", e, a)
}
if e, a := noxuDefinition.Spec.Names.Kind, createdTypeMeta.GetKind(); e != a {
@ -901,7 +901,7 @@ func TestCrossNamespaceListWatch(t *testing.T) {
checkNamespacesWatchHelper(t, ns2, noxuNamespacesWatch2)
}
func createInstanceWithNamespaceHelper(t *testing.T, ns string, name string, noxuNamespacedResourceClient dynamic.ResourceInterface, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition) *unstructured.Unstructured {
func createInstanceWithNamespaceHelper(t *testing.T, ns string, name string, noxuNamespacedResourceClient dynamic.ResourceInterface, noxuDefinition *apiextensionsv1.CustomResourceDefinition) *unstructured.Unstructured {
createdInstance, err := instantiateCustomResource(t, fixtures.NewNoxuInstance(ns, name), noxuNamespacedResourceClient, noxuDefinition)
if err != nil {
t.Fatalf("unable to create noxu Instance:%v", err)
@ -944,27 +944,27 @@ func TestNameConflict(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
noxu2Definition := fixtures.NewNoxu2CustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(context.TODO(), noxu2Definition, metav1.CreateOptions{})
noxu2Definition := fixtures.NewNoxu2CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
_, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Create(context.TODO(), noxu2Definition, metav1.CreateOptions{})
if err != nil {
t.Fatal(err)
}
// A NameConflict occurs
err = wait.Poll(500*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
crd, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), noxu2Definition.Name, metav1.GetOptions{})
crd, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxu2Definition.Name, metav1.GetOptions{})
if err != nil {
return false, err
}
for _, condition := range crd.Status.Conditions {
if condition.Type == apiextensionsv1beta1.NamesAccepted && condition.Status == apiextensionsv1beta1.ConditionFalse {
if condition.Type == apiextensionsv1.NamesAccepted && condition.Status == apiextensionsv1.ConditionFalse {
return true, nil
}
}
@ -974,20 +974,20 @@ func TestNameConflict(t *testing.T) {
t.Fatal(err)
}
err = fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient)
err = fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient)
if err != nil {
t.Fatal(err)
}
// Names are now accepted
err = wait.Poll(500*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
crd, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), noxu2Definition.Name, metav1.GetOptions{})
crd, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxu2Definition.Name, metav1.GetOptions{})
if err != nil {
return false, err
}
for _, condition := range crd.Status.Conditions {
if condition.Type == apiextensionsv1beta1.NamesAccepted && condition.Status == apiextensionsv1beta1.ConditionTrue {
if condition.Type == apiextensionsv1.NamesAccepted && condition.Status == apiextensionsv1.ConditionTrue {
return true, nil
}
}
@ -1005,15 +1005,15 @@ func TestStatusGetAndPatch(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
// make sure we don't get 405 Method Not Allowed from Getting CRD/status subresource
result := &apiextensionsv1beta1.CustomResourceDefinition{}
err = apiExtensionClient.ApiextensionsV1beta1().RESTClient().Get().
result := &apiextensionsv1.CustomResourceDefinition{}
err = apiExtensionClient.ApiextensionsV1().RESTClient().Get().
Resource("customresourcedefinitions").
Name(noxuDefinition.Name).
SubResource("status").
@ -1024,7 +1024,7 @@ func TestStatusGetAndPatch(t *testing.T) {
}
// make sure we don't get 405 Method Not Allowed from Patching CRD/status subresource
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().
_, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().
Patch(context.TODO(), noxuDefinition.Name, types.StrategicMergePatchType,
[]byte(fmt.Sprintf(`{"labels":{"test-label":"dummy"}}`)), metav1.PatchOptions{},
"status")

View File

@ -23,7 +23,7 @@ import (
"testing"
"time"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -50,8 +50,8 @@ func TestChangeCRD(t *testing.T) {
t.Fatal(err)
}
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionsClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionsClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -76,7 +76,7 @@ func TestChangeCRD(t *testing.T) {
time.Sleep(10 * time.Millisecond)
noxuDefinitionToUpdate, err := apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
noxuDefinitionToUpdate, err := apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
if err != nil {
t.Error(err)
continue
@ -90,7 +90,7 @@ func TestChangeCRD(t *testing.T) {
} else {
noxuDefinitionToUpdate.Spec.Versions = noxuDefinitionToUpdate.Spec.Versions[0:1]
}
if _, err := apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), noxuDefinitionToUpdate, metav1.UpdateOptions{}); err != nil && !apierrors.IsConflict(err) {
if _, err := apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), noxuDefinitionToUpdate, metav1.UpdateOptions{}); err != nil && !apierrors.IsConflict(err) {
t.Error(err)
continue
}

View File

@ -335,10 +335,8 @@ func validateNonTrivialConverted(t *testing.T, ctc *conversionTestContext) {
client := ctc.versionedClient(ns, createVersion.Name)
fixture := newConversionMultiVersionFixture(ns, name, createVersion.Name)
if !*ctc.crd.Spec.PreserveUnknownFields {
if err := unstructured.SetNestedField(fixture.Object, "foo", "garbage"); err != nil {
t.Fatal(err)
}
if err := unstructured.SetNestedField(fixture.Object, "foo", "garbage"); err != nil {
t.Fatal(err)
}
if _, err := client.Create(context.TODO(), fixture, metav1.CreateOptions{}); err != nil {
t.Fatal(err)
@ -393,10 +391,8 @@ func validateNonTrivialConvertedList(t *testing.T, ctc *conversionTestContext) {
name := "converted-" + createVersion.Name
client := ctc.versionedClient(ns, createVersion.Name)
fixture := newConversionMultiVersionFixture(ns, name, createVersion.Name)
if !*ctc.crd.Spec.PreserveUnknownFields {
if err := unstructured.SetNestedField(fixture.Object, "foo", "garbage"); err != nil {
t.Fatal(err)
}
if err := unstructured.SetNestedField(fixture.Object, "foo", "garbage"); err != nil {
t.Fatal(err)
}
_, err := client.Create(context.TODO(), fixture, metav1.CreateOptions{})
if err != nil {
@ -428,10 +424,6 @@ func validateNonTrivialConvertedList(t *testing.T, ctc *conversionTestContext) {
}
func validateStoragePruning(t *testing.T, ctc *conversionTestContext) {
if *ctc.crd.Spec.PreserveUnknownFields {
return
}
ns := ctc.namespace
for _, createVersion := range ctc.crd.Spec.Versions {
@ -905,13 +897,13 @@ func newConversionTestContext(t *testing.T, apiExtensionsClient clientset.Interf
if err != nil {
t.Fatal(err)
}
crd, err := apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), v1CRD.Name, metav1.GetOptions{})
crd, err := apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), v1CRD.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
tearDown := func() {
if err := fixtures.DeleteCustomResourceDefinition(crd, apiExtensionsClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(crd, apiExtensionsClient); err != nil {
t.Fatal(err)
}
}
@ -923,13 +915,13 @@ type conversionTestContext struct {
namespace string
apiExtensionsClient clientset.Interface
dynamicClient dynamic.Interface
crd *apiextensionsv1beta1.CustomResourceDefinition
crd *apiextensionsv1.CustomResourceDefinition
etcdObjectReader *storage.EtcdObjectReader
}
func (c *conversionTestContext) versionedClient(ns string, version string) dynamic.ResourceInterface {
gvr := schema.GroupVersionResource{Group: c.crd.Spec.Group, Version: version, Resource: c.crd.Spec.Names.Plural}
if c.crd.Spec.Scope != apiextensionsv1beta1.ClusterScoped {
if c.crd.Spec.Scope != apiextensionsv1.ClusterScoped {
return c.dynamicClient.Resource(gvr).Namespace(ns)
}
return c.dynamicClient.Resource(gvr)
@ -943,17 +935,19 @@ func (c *conversionTestContext) versionedClients(ns string) map[string]dynamic.R
return ret
}
func (c *conversionTestContext) setConversionWebhook(t *testing.T, webhookClientConfig *apiextensionsv1beta1.WebhookClientConfig, reviewVersions []string) {
crd, err := c.apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), c.crd.Name, metav1.GetOptions{})
func (c *conversionTestContext) setConversionWebhook(t *testing.T, webhookClientConfig *apiextensionsv1.WebhookClientConfig, reviewVersions []string) {
crd, err := c.apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), c.crd.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
crd.Spec.Conversion = &apiextensionsv1beta1.CustomResourceConversion{
Strategy: apiextensionsv1beta1.WebhookConverter,
WebhookClientConfig: webhookClientConfig,
ConversionReviewVersions: reviewVersions,
crd.Spec.Conversion = &apiextensionsv1.CustomResourceConversion{
Strategy: apiextensionsv1.WebhookConverter,
Webhook: &apiextensionsv1.WebhookConversion{
ClientConfig: webhookClientConfig,
ConversionReviewVersions: reviewVersions,
},
}
crd, err = c.apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
crd, err = c.apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
if err != nil {
t.Fatal(err)
}
@ -962,15 +956,15 @@ func (c *conversionTestContext) setConversionWebhook(t *testing.T, webhookClient
}
func (c *conversionTestContext) removeConversionWebhook(t *testing.T) {
crd, err := c.apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), c.crd.Name, metav1.GetOptions{})
crd, err := c.apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), c.crd.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
crd.Spec.Conversion = &apiextensionsv1beta1.CustomResourceConversion{
Strategy: apiextensionsv1beta1.NoneConverter,
crd.Spec.Conversion = &apiextensionsv1.CustomResourceConversion{
Strategy: apiextensionsv1.NoneConverter,
}
crd, err = c.apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
crd, err = c.apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
if err != nil {
t.Fatal(err)
}
@ -998,14 +992,14 @@ func (c *conversionTestContext) setAndWaitStorageVersion(t *testing.T, version s
}
func (c *conversionTestContext) setStorageVersion(t *testing.T, version string) {
crd, err := c.apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), c.crd.Name, metav1.GetOptions{})
crd, err := c.apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), c.crd.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
for i, v := range crd.Spec.Versions {
crd.Spec.Versions[i].Storage = v.Name == version
}
crd, err = c.apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
crd, err = c.apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
if err != nil {
t.Fatal(err)
}
@ -1027,7 +1021,7 @@ func (c *conversionTestContext) waitForStorageVersion(t *testing.T, version stri
}
func (c *conversionTestContext) setServed(t *testing.T, version string, served bool) {
crd, err := c.apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), c.crd.Name, metav1.GetOptions{})
crd, err := c.apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), c.crd.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
@ -1036,7 +1030,7 @@ func (c *conversionTestContext) setServed(t *testing.T, version string, served b
crd.Spec.Versions[i].Served = served
}
}
crd, err = c.apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
crd, err = c.apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
if err != nil {
t.Fatal(err)
}

View File

@ -38,7 +38,7 @@ import (
// StartConversionWebhookServer starts an http server with the provided handler and returns the WebhookClientConfig
// needed to configure a CRD to use this conversion webhook as its converter.
func StartConversionWebhookServer(handler http.Handler) (func(), *apiextensionsv1beta1.WebhookClientConfig, error) {
func StartConversionWebhookServer(handler http.Handler) (func(), *apiextensionsv1.WebhookClientConfig, error) {
roots := x509.NewCertPool()
if !roots.AppendCertsFromPEM(localhostCert) {
return nil, nil, fmt.Errorf("failed to append Cert from PEM")
@ -57,7 +57,7 @@ func StartConversionWebhookServer(handler http.Handler) (func(), *apiextensionsv
}
webhookServer.StartTLS()
endpoint := webhookServer.URL + "/convert"
webhookConfig := &apiextensionsv1beta1.WebhookClientConfig{
webhookConfig := &apiextensionsv1.WebhookClientConfig{
CABundle: localhostCert,
URL: &endpoint,
}

View File

@ -23,8 +23,7 @@ import (
"github.com/stretchr/testify/require"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -36,8 +35,8 @@ func TestFinalization(t *testing.T) {
require.NoError(t, err)
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
require.NoError(t, err)
ns := "not-the-default"
@ -100,8 +99,8 @@ func TestFinalizationAndDeletion(t *testing.T) {
defer tearDown()
// Create a CRD.
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
require.NoError(t, err)
// Create a CR with a finalizer.
@ -129,7 +128,7 @@ func TestFinalizationAndDeletion(t *testing.T) {
require.NotNil(t, gottenNoxuInstance.GetDeletionTimestamp())
// Delete the CRD.
fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient)
fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient)
// Check is CR still there after the CRD deletion.
gottenNoxuInstance, err = noxuResourceClient.Get(context.TODO(), name, metav1.GetOptions{})
@ -157,7 +156,7 @@ func TestFinalizationAndDeletion(t *testing.T) {
}
err = wait.Poll(500*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
_, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
return errors.IsNotFound(err), err
})
if !errors.IsNotFound(err) {

View File

@ -44,6 +44,16 @@ const (
noxuInstanceNum int64 = 9223372036854775807
)
// AllowAllSchema doesn't enforce any schema restrictions
func AllowAllSchema() *apiextensionsv1.CustomResourceValidation {
return &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
XPreserveUnknownFields: pointer.BoolPtr(true),
Type: "object",
},
}
}
// NewRandomNameV1CustomResourceDefinition generates a CRD with random name to avoid name conflict in e2e tests
func NewRandomNameV1CustomResourceDefinition(scope apiextensionsv1.ResourceScope) *apiextensionsv1.CustomResourceDefinition {
// ensure the singular doesn't end in an s for now
@ -57,12 +67,7 @@ func NewRandomNameV1CustomResourceDefinition(scope apiextensionsv1.ResourceScope
Name: "v1beta1",
Served: true,
Storage: true,
Schema: &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
XPreserveUnknownFields: pointer.BoolPtr(true),
Type: "object",
},
},
Schema: AllowAllSchema(),
},
},
Names: apiextensionsv1.CustomResourceDefinitionNames{
@ -76,46 +81,6 @@ func NewRandomNameV1CustomResourceDefinition(scope apiextensionsv1.ResourceScope
}
}
// NewRandomNameCustomResourceDefinition generates a CRD with random name to avoid name conflict in e2e tests
func NewRandomNameCustomResourceDefinition(scope apiextensionsv1beta1.ResourceScope) *apiextensionsv1beta1.CustomResourceDefinition {
// ensure the singular doesn't end in an s for now
gName := names.SimpleNameGenerator.GenerateName("foo") + "a"
return &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: gName + "s.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: gName + "s",
Singular: gName,
Kind: gName,
ListKind: gName + "List",
},
Scope: scope,
},
}
}
// NewNoxuCustomResourceDefinition returns a WishIHadChosenNoxu CRD.
func NewNoxuCustomResourceDefinition(scope apiextensionsv1beta1.ResourceScope) *apiextensionsv1beta1.CustomResourceDefinition {
return &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: "noxus",
Singular: "nonenglishnoxu",
Kind: "WishIHadChosenNoxu",
ShortNames: []string{"foo", "bar", "abc", "def"},
ListKind: "NoxuItemList",
Categories: []string{"all"},
},
Scope: scope,
},
}
}
// NewNoxuV1CustomResourceDefinition returns a WishIHadChosenNoxu CRD.
func NewNoxuV1CustomResourceDefinition(scope apiextensionsv1.ResourceScope) *apiextensionsv1.CustomResourceDefinition {
return &apiextensionsv1.CustomResourceDefinition{
@ -126,12 +91,7 @@ func NewNoxuV1CustomResourceDefinition(scope apiextensionsv1.ResourceScope) *api
Name: "v1beta1",
Served: true,
Storage: true,
Schema: &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
XPreserveUnknownFields: pointer.BoolPtr(true),
Type: "object",
},
},
Schema: AllowAllSchema(),
}},
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "noxus",
@ -173,13 +133,12 @@ func NewNoxuInstance(namespace, name string) *unstructured.Unstructured {
}
// NewMultipleVersionNoxuCRD returns a WishIHadChosenNoxu with multiple versions.
func NewMultipleVersionNoxuCRD(scope apiextensionsv1beta1.ResourceScope) *apiextensionsv1beta1.CustomResourceDefinition {
return &apiextensionsv1beta1.CustomResourceDefinition{
func NewMultipleVersionNoxuCRD(scope apiextensionsv1.ResourceScope) *apiextensionsv1.CustomResourceDefinition {
return &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "noxus",
Singular: "nonenglishnoxu",
Kind: "WishIHadChosenNoxu",
@ -188,38 +147,52 @@ func NewMultipleVersionNoxuCRD(scope apiextensionsv1beta1.ResourceScope) *apiext
Categories: []string{"all"},
},
Scope: scope,
Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: false,
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
},
Schema: AllowAllSchema(),
},
{
Name: "v1beta2",
Served: true,
Storage: true,
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
},
Schema: AllowAllSchema(),
},
{
Name: "v0",
Served: false,
Storage: false,
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
},
Schema: AllowAllSchema(),
},
},
Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
},
},
}
}
// NewNoxu2CustomResourceDefinition returns a WishIHadChosenNoxu2 CRD.
func NewNoxu2CustomResourceDefinition(scope apiextensionsv1beta1.ResourceScope) *apiextensionsv1beta1.CustomResourceDefinition {
return &apiextensionsv1beta1.CustomResourceDefinition{
func NewNoxu2CustomResourceDefinition(scope apiextensionsv1.ResourceScope) *apiextensionsv1.CustomResourceDefinition {
return &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "noxus2.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1alpha1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{{
Name: "v1alpha1",
Served: true,
Storage: true,
Schema: AllowAllSchema(),
}},
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "noxus2",
Singular: "nonenglishnoxu2",
Kind: "WishIHadChosenNoxu2",
@ -231,14 +204,21 @@ func NewNoxu2CustomResourceDefinition(scope apiextensionsv1beta1.ResourceScope)
}
}
// NewCurletCustomResourceDefinition returns a Curlet CRD.
func NewCurletCustomResourceDefinition(scope apiextensionsv1beta1.ResourceScope) *apiextensionsv1beta1.CustomResourceDefinition {
return &apiextensionsv1beta1.CustomResourceDefinition{
// NewCurletV1CustomResourceDefinition returns a Curlet CRD.
func NewCurletV1CustomResourceDefinition(scope apiextensionsv1.ResourceScope) *apiextensionsv1.CustomResourceDefinition {
return &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "curlets.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
Schema: AllowAllSchema(),
},
},
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "curlets",
Singular: "curlet",
Kind: "Curlet",
@ -506,23 +486,6 @@ func isWatchCachePrimed(crd *apiextensionsv1.CustomResourceDefinition, dynamicCl
return true, nil
}
// DeleteCustomResourceDefinition deletes a CRD and waits until it disappears from discovery.
func DeleteCustomResourceDefinition(crd *apiextensionsv1beta1.CustomResourceDefinition, apiExtensionsClient clientset.Interface) error {
if err := apiExtensionsClient.ApiextensionsV1beta1().CustomResourceDefinitions().Delete(context.TODO(), crd.Name, metav1.DeleteOptions{}); err != nil {
return err
}
for _, version := range servedVersions(crd) {
err := wait.PollImmediate(500*time.Millisecond, 30*time.Second, func() (bool, error) {
exists, err := existsInDiscovery(crd, apiExtensionsClient, version)
return !exists, err
})
if err != nil {
return err
}
}
return nil
}
// DeleteV1CustomResourceDefinition deletes a CRD and waits until it disappears from discovery.
func DeleteV1CustomResourceDefinition(crd *apiextensionsv1.CustomResourceDefinition, apiExtensionsClient clientset.Interface) error {
if err := apiExtensionsClient.ApiextensionsV1().CustomResourceDefinitions().Delete(context.TODO(), crd.Name, metav1.DeleteOptions{}); err != nil {
@ -564,7 +527,7 @@ func DeleteV1CustomResourceDefinitions(deleteListOpts metav1.ListOptions, apiExt
}
// CreateNewVersionedScaleClient returns a scale client.
func CreateNewVersionedScaleClient(crd *apiextensionsv1beta1.CustomResourceDefinition, config *rest.Config, version string) (scale.ScalesGetter, error) {
func CreateNewVersionedScaleClient(crd *apiextensionsv1.CustomResourceDefinition, config *rest.Config, version string) (scale.ScalesGetter, error) {
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
return nil, err

View File

@ -20,9 +20,15 @@ import (
"io/ioutil"
"os"
"strings"
"time"
"github.com/google/uuid"
"go.etcd.io/etcd/clientv3"
"go.etcd.io/etcd/pkg/transport"
"google.golang.org/grpc"
"k8s.io/apiextensions-apiserver/pkg/cmd/server/options"
serveroptions "k8s.io/apiextensions-apiserver/pkg/cmd/server/options"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
servertesting "k8s.io/apiextensions-apiserver/pkg/cmd/server/testing"
@ -103,6 +109,55 @@ func StartDefaultServerWithClients(t servertesting.Logger, extraFlags ...string)
return tearDown, apiExtensionsClient, dynamicClient, nil
}
// StartDefaultServerWithClientsAndEtcd starts a test server and returns clients for it.
func StartDefaultServerWithClientsAndEtcd(t servertesting.Logger, extraFlags ...string) (func(), clientset.Interface, dynamic.Interface, *clientv3.Client, string, error) {
tearDown, config, options, err := StartDefaultServer(t, extraFlags...)
if err != nil {
return nil, nil, nil, nil, "", err
}
apiExtensionsClient, err := clientset.NewForConfig(config)
if err != nil {
tearDown()
return nil, nil, nil, nil, "", err
}
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
tearDown()
return nil, nil, nil, nil, "", err
}
RESTOptionsGetter := serveroptions.NewCRDRESTOptionsGetter(*options.RecommendedOptions.Etcd)
restOptions, err := RESTOptionsGetter.GetRESTOptions(schema.GroupResource{Group: "hopefully-ignored-group", Resource: "hopefully-ignored-resources"})
if err != nil {
return nil, nil, nil, nil, "", err
}
tlsInfo := transport.TLSInfo{
CertFile: restOptions.StorageConfig.Transport.CertFile,
KeyFile: restOptions.StorageConfig.Transport.KeyFile,
TrustedCAFile: restOptions.StorageConfig.Transport.TrustedCAFile,
}
tlsConfig, err := tlsInfo.ClientConfig()
if err != nil {
return nil, nil, nil, nil, "", err
}
etcdConfig := clientv3.Config{
Endpoints: restOptions.StorageConfig.Transport.ServerList,
DialTimeout: 20 * time.Second,
DialOptions: []grpc.DialOption{
grpc.WithBlock(), // block until the underlying connection is up
},
TLS: tlsConfig,
}
etcdclient, err := clientv3.New(etcdConfig)
if err != nil {
return nil, nil, nil, nil, "", err
}
return tearDown, apiExtensionsClient, dynamicClient, etcdclient, restOptions.StorageConfig.Prefix, nil
}
// IntegrationEtcdServers returns etcd server URLs.
func IntegrationEtcdServers() []string {
if etcdURL, ok := os.LookupEnv("KUBE_INTEGRATION_ETCD_URL"); ok {

View File

@ -22,7 +22,6 @@ import (
"testing"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
@ -34,11 +33,11 @@ import (
var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()
func instantiateCustomResource(t *testing.T, instanceToCreate *unstructured.Unstructured, client dynamic.ResourceInterface, definition *apiextensionsv1beta1.CustomResourceDefinition) (*unstructured.Unstructured, error) {
func instantiateCustomResource(t *testing.T, instanceToCreate *unstructured.Unstructured, client dynamic.ResourceInterface, definition *apiextensionsv1.CustomResourceDefinition) (*unstructured.Unstructured, error) {
return instantiateVersionedCustomResource(t, instanceToCreate, client, definition, definition.Spec.Versions[0].Name)
}
func instantiateVersionedCustomResource(t *testing.T, instanceToCreate *unstructured.Unstructured, client dynamic.ResourceInterface, definition *apiextensionsv1beta1.CustomResourceDefinition, version string) (*unstructured.Unstructured, error) {
func instantiateVersionedCustomResource(t *testing.T, instanceToCreate *unstructured.Unstructured, client dynamic.ResourceInterface, definition *apiextensionsv1.CustomResourceDefinition, version string) (*unstructured.Unstructured, error) {
createdInstance, err := client.Create(context.TODO(), instanceToCreate, metav1.CreateOptions{})
if err != nil {
t.Logf("%#v", createdInstance)
@ -65,28 +64,28 @@ func instantiateVersionedCustomResource(t *testing.T, instanceToCreate *unstruct
return createdInstance, nil
}
func newNamespacedCustomResourceVersionedClient(ns string, client dynamic.Interface, crd *apiextensionsv1beta1.CustomResourceDefinition, version string) dynamic.ResourceInterface {
func newNamespacedCustomResourceVersionedClient(ns string, client dynamic.Interface, crd *apiextensionsv1.CustomResourceDefinition, version string) dynamic.ResourceInterface {
gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: version, Resource: crd.Spec.Names.Plural}
if crd.Spec.Scope != apiextensionsv1beta1.ClusterScoped {
if crd.Spec.Scope != apiextensionsv1.ClusterScoped {
return client.Resource(gvr).Namespace(ns)
}
return client.Resource(gvr)
}
func newNamespacedCustomResourceClient(ns string, client dynamic.Interface, crd *apiextensionsv1beta1.CustomResourceDefinition) dynamic.ResourceInterface {
func newNamespacedCustomResourceClient(ns string, client dynamic.Interface, crd *apiextensionsv1.CustomResourceDefinition) dynamic.ResourceInterface {
return newNamespacedCustomResourceVersionedClient(ns, client, crd, crd.Spec.Versions[0].Name)
}
// UpdateCustomResourceDefinitionWithRetry updates a CRD, retrying up to 5 times on version conflict errors.
func UpdateCustomResourceDefinitionWithRetry(client clientset.Interface, name string, update func(*apiextensionsv1beta1.CustomResourceDefinition)) (*apiextensionsv1beta1.CustomResourceDefinition, error) {
func UpdateCustomResourceDefinitionWithRetry(client clientset.Interface, name string, update func(*apiextensionsv1.CustomResourceDefinition)) (*apiextensionsv1.CustomResourceDefinition, error) {
for i := 0; i < 5; i++ {
crd, err := client.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
crd, err := client.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return nil, fmt.Errorf("failed to get CustomResourceDefinition %q: %v", name, err)
}
update(crd)
crd, err = client.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
crd, err = client.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
if err == nil {
return crd, nil
}
@ -117,13 +116,7 @@ func UpdateV1CustomResourceDefinitionWithRetry(client clientset.Interface, name
}
// getSchemaForVersion returns the validation schema for given version in given CRD.
func getSchemaForVersion(crd *apiextensionsv1beta1.CustomResourceDefinition, version string) (*apiextensionsv1beta1.CustomResourceValidation, error) {
if !hasPerVersionSchema(crd.Spec.Versions) {
return crd.Spec.Validation, nil
}
if crd.Spec.Validation != nil {
return nil, fmt.Errorf("malformed CustomResourceDefinition %s version %s: top-level and per-version schemas must be mutual exclusive", crd.Name, version)
}
func getSchemaForVersion(crd *apiextensionsv1.CustomResourceDefinition, version string) (*apiextensionsv1.CustomResourceValidation, error) {
for _, v := range crd.Spec.Versions {
if version == v.Name {
return v.Schema, nil
@ -133,13 +126,7 @@ func getSchemaForVersion(crd *apiextensionsv1beta1.CustomResourceDefinition, ver
}
// getSubresourcesForVersion returns the subresources for given version in given CRD.
func getSubresourcesForVersion(crd *apiextensionsv1beta1.CustomResourceDefinition, version string) (*apiextensionsv1beta1.CustomResourceSubresources, error) {
if !hasPerVersionSubresources(crd.Spec.Versions) {
return crd.Spec.Subresources, nil
}
if crd.Spec.Subresources != nil {
return nil, fmt.Errorf("malformed CustomResourceDefinition %s version %s: top-level and per-version subresources must be mutual exclusive", crd.Name, version)
}
func getSubresourcesForVersion(crd *apiextensionsv1.CustomResourceDefinition, version string) (*apiextensionsv1.CustomResourceSubresources, error) {
for _, v := range crd.Spec.Versions {
if version == v.Name {
return v.Subresources, nil
@ -152,13 +139,7 @@ func getSubresourcesForVersion(crd *apiextensionsv1beta1.CustomResourceDefinitio
// NOTE: the newly logically-defaulted columns is not pointing to the original CRD object.
// One cannot mutate the original CRD columns using the logically-defaulted columns. Please iterate through
// the original CRD object instead.
func getColumnsForVersion(crd *apiextensionsv1beta1.CustomResourceDefinition, version string) ([]apiextensionsv1beta1.CustomResourceColumnDefinition, error) {
if !hasPerVersionColumns(crd.Spec.Versions) {
return serveDefaultColumnsIfEmpty(crd.Spec.AdditionalPrinterColumns), nil
}
if len(crd.Spec.AdditionalPrinterColumns) > 0 {
return nil, fmt.Errorf("malformed CustomResourceDefinition %s version %s: top-level and per-version additionalPrinterColumns must be mutual exclusive", crd.Name, version)
}
func getColumnsForVersion(crd *apiextensionsv1.CustomResourceDefinition, version string) ([]apiextensionsv1.CustomResourceColumnDefinition, error) {
for _, v := range crd.Spec.Versions {
if version == v.Name {
return serveDefaultColumnsIfEmpty(v.AdditionalPrinterColumns), nil
@ -171,41 +152,11 @@ func getColumnsForVersion(crd *apiextensionsv1beta1.CustomResourceDefinition, ve
// NOTE: in this way, the newly logically-defaulted columns is not pointing to the original CRD object.
// One cannot mutate the original CRD columns using the logically-defaulted columns. Please iterate through
// the original CRD object instead.
func serveDefaultColumnsIfEmpty(columns []apiextensionsv1beta1.CustomResourceColumnDefinition) []apiextensionsv1beta1.CustomResourceColumnDefinition {
func serveDefaultColumnsIfEmpty(columns []apiextensionsv1.CustomResourceColumnDefinition) []apiextensionsv1.CustomResourceColumnDefinition {
if len(columns) > 0 {
return columns
}
return []apiextensionsv1beta1.CustomResourceColumnDefinition{
return []apiextensionsv1.CustomResourceColumnDefinition{
{Name: "Age", Type: "date", Description: swaggerMetadataDescriptions["creationTimestamp"], JSONPath: ".metadata.creationTimestamp"},
}
}
// hasPerVersionSchema returns true if a CRD uses per-version schema.
func hasPerVersionSchema(versions []apiextensionsv1beta1.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if v.Schema != nil {
return true
}
}
return false
}
// hasPerVersionSubresources returns true if a CRD uses per-version subresources.
func hasPerVersionSubresources(versions []apiextensionsv1beta1.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if v.Subresources != nil {
return true
}
}
return false
}
// hasPerVersionColumns returns true if a CRD uses per-version columns.
func hasPerVersionColumns(versions []apiextensionsv1beta1.CustomResourceDefinitionVersion) bool {
for _, v := range versions {
if len(v.AdditionalPrinterColumns) > 0 {
return true
}
}
return false
}

View File

@ -22,13 +22,12 @@ import (
"strings"
"testing"
"k8s.io/client-go/dynamic"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
)
func TestLimits(t *testing.T) {
@ -47,14 +46,14 @@ func TestLimits(t *testing.T) {
t.Fatal(err)
}
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
kind := noxuDefinition.Spec.Names.Kind
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Version
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
rest := apiExtensionClient.Discovery().RESTClient()
@ -70,7 +69,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
_, err := rest.Post().
SetHeader("Accept", "application/yaml").
SetHeader("Content-Type", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Body(yamlBody).
DoRaw(context.TODO())
if !apierrors.IsRequestEntityTooLargeError(err) {
@ -93,7 +92,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
_, err := rest.Post().
SetHeader("Accept", "application/yaml").
SetHeader("Content-Type", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Body(yamlBody).
DoRaw(context.TODO())
if !apierrors.IsBadRequest(err) {
@ -116,7 +115,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
_, err := rest.Post().
SetHeader("Accept", "application/yaml").
SetHeader("Content-Type", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Body(yamlBody).
DoRaw(context.TODO())
if !apierrors.IsBadRequest(err) {
@ -137,7 +136,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
_, err := rest.Post().
SetHeader("Accept", "application/json").
SetHeader("Content-Type", "application/json").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Body(jsonBody).
DoRaw(context.TODO())
if !apierrors.IsRequestEntityTooLargeError(err) {
@ -161,7 +160,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
_, err := rest.Post().
SetHeader("Accept", "application/json").
SetHeader("Content-Type", "application/json").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Body(jsonBody).
DoRaw(context.TODO())
if !apierrors.IsBadRequest(err) {
@ -185,7 +184,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
_, err := rest.Post().
SetHeader("Accept", "application/json").
SetHeader("Content-Type", "application/json").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Body(jsonBody).
DoRaw(context.TODO())
if !apierrors.IsBadRequest(err) {
@ -196,7 +195,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
// Create instance to allow patching
{
jsonBody := []byte(fmt.Sprintf(`{"apiVersion": %q, "kind": %q, "metadata": {"name": "test"}}`, apiVersion, kind))
_, err := rest.Post().AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).Body(jsonBody).DoRaw(context.TODO())
_, err := rest.Post().AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).Body(jsonBody).DoRaw(context.TODO())
if err != nil {
t.Fatalf("error creating object: %v", err)
}
@ -207,7 +206,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
t.Skip("skipping expensive test")
}
patchBody := []byte(`[{"op":"add","path":"/foo","value":` + strings.Repeat("[", 3*1024*1024/2-100) + strings.Repeat("]", 3*1024*1024/2-100) + `}]`)
err = rest.Patch(types.JSONPatchType).AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "test").
err = rest.Patch(types.JSONPatchType).AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "test").
Body(patchBody).Do(context.TODO()).Error()
if !apierrors.IsBadRequest(err) {
t.Errorf("expected success or bad request err, got %v", err)
@ -218,7 +217,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
t.Skip("skipping expensive test")
}
patchBody := []byte(`{"value":` + strings.Repeat("[", 3*1024*1024/2-100) + strings.Repeat("]", 3*1024*1024/2-100) + `}`)
err = rest.Patch(types.MergePatchType).AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "test").
err = rest.Patch(types.MergePatchType).AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "test").
Body(patchBody).Do(context.TODO()).Error()
if !apierrors.IsBadRequest(err) {
t.Errorf("expected success or bad request err, got %v", err)
@ -229,7 +228,7 @@ values: `+strings.Repeat("[", 3*1024*1024), apiVersion, kind))
t.Skip("skipping expensive test")
}
patchBody := []byte(`{"value":` + strings.Repeat("[", 3*1024*1024/2-100) + strings.Repeat("]", 3*1024*1024/2-100) + `}`)
err = rest.Patch(types.ApplyPatchType).Param("fieldManager", "test").AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "test").
err = rest.Patch(types.ApplyPatchType).Param("fieldManager", "test").AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "test").
Body(patchBody).Do(context.TODO()).Error()
if !apierrors.IsBadRequest(err) {
t.Errorf("expected bad request err, got %#v", err)

View File

@ -22,37 +22,36 @@ import (
"testing"
"time"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/yaml"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/yaml"
)
var listTypeResourceFixture = &apiextensionsv1beta1.CustomResourceDefinition{
var listTypeResourceFixture = &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "foos.tests.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "tests.example.com",
Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Storage: true,
Served: true,
Schema: fixtures.AllowAllSchema(),
},
},
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "foos",
Singular: "foo",
Kind: "Foo",
ListKind: "FooList",
},
Scope: apiextensionsv1beta1.ClusterScoped,
Validation: &apiextensionsv1beta1.CustomResourceValidation{},
Scope: apiextensionsv1.ClusterScoped,
},
}
@ -128,11 +127,11 @@ func TestListTypes(t *testing.T) {
defer tearDownFn()
crd := listTypeResourceFixture.DeepCopy()
if err := yaml.Unmarshal([]byte(listTypeResourceSchema), &crd.Spec.Validation.OpenAPIV3Schema); err != nil {
if err := yaml.Unmarshal([]byte(listTypeResourceSchema), &crd.Spec.Versions[0].Schema.OpenAPIV3Schema); err != nil {
t.Fatal(err)
}
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -195,14 +194,14 @@ func TestListTypes(t *testing.T) {
t.Logf("Remove \"b\" from the keys in the schema which renders the valid instance invalid")
err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
crd, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
crd, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
if err != nil {
return err
}
s := crd.Spec.Validation.OpenAPIV3Schema.Properties["correct-map"]
s := crd.Spec.Versions[0].Schema.OpenAPIV3Schema.Properties["correct-map"]
s.XListMapKeys = []string{"a"}
crd.Spec.Validation.OpenAPIV3Schema.Properties["correct-map"] = s
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
crd.Spec.Versions[0].Schema.OpenAPIV3Schema.Properties["correct-map"] = s
_, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
return err
})
if err != nil {

View File

@ -30,7 +30,6 @@ import (
"sigs.k8s.io/yaml"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
serveroptions "k8s.io/apiextensions-apiserver/pkg/cmd/server/options"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
@ -52,8 +51,8 @@ func TestPostInvalidObjectMeta(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -114,11 +113,11 @@ func TestInvalidObjectMetaInStorage(t *testing.T) {
t.Fatal(err)
}
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1beta1.JSONSchemaProps{
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition.Spec.Versions[0].Schema = &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"embedded": {
Type: "object",
XEmbeddedResource: true,
@ -127,7 +126,7 @@ func TestInvalidObjectMetaInStorage(t *testing.T) {
},
},
}
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}

View File

@ -24,6 +24,8 @@ import (
"testing"
"time"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"go.etcd.io/etcd/clientv3"
"go.etcd.io/etcd/pkg/transport"
"google.golang.org/grpc"
@ -39,29 +41,37 @@ import (
"k8s.io/apimachinery/pkg/util/json"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/client-go/dynamic"
"k8s.io/utils/pointer"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
)
var pruningFixture = &apiextensionsv1beta1.CustomResourceDefinition{
var pruningFixture = &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "foos.tests.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "tests.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "tests.example.com",
Scope: apiextensionsv1.ClusterScoped,
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
},
Schema: &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
Type: "object",
},
},
},
},
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "foos",
Singular: "foo",
Kind: "Foo",
ListKind: "FooList",
},
Scope: apiextensionsv1beta1.ClusterScoped,
PreserveUnknownFields: pointer.BoolPtr(false),
Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
},
},
}
@ -189,18 +199,18 @@ func TestPruningCreate(t *testing.T) {
defer tearDownFn()
crd := pruningFixture.DeepCopy()
crd.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchema), &crd.Spec.Validation.OpenAPIV3Schema); err != nil {
crd.Spec.Versions[0].Schema = &apiextensionsv1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchema), &crd.Spec.Versions[0].Schema.OpenAPIV3Schema); err != nil {
t.Fatal(err)
}
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
t.Logf("Creating CR and expect 'unspecified' fields to be pruned")
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Plural})
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Versions[0].Name, crd.Spec.Names.Plural})
foo := &unstructured.Unstructured{}
if err := yaml.Unmarshal([]byte(pruningFooInstance), &foo.Object); err != nil {
t.Fatal(err)
@ -241,18 +251,18 @@ func TestPruningStatus(t *testing.T) {
defer tearDownFn()
crd := pruningFixture.DeepCopy()
crd.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooStatusSchema), &crd.Spec.Validation.OpenAPIV3Schema); err != nil {
crd.Spec.Versions[0].Schema = &apiextensionsv1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooStatusSchema), &crd.Spec.Versions[0].Schema.OpenAPIV3Schema); err != nil {
t.Fatal(err)
}
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
t.Logf("Creating CR and expect 'unspecified' fields to be pruned")
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Plural})
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Versions[0].Name, crd.Spec.Names.Plural})
foo := &unstructured.Unstructured{}
if err := yaml.Unmarshal([]byte(pruningFooInstance), &foo.Object); err != nil {
t.Fatal(err)
@ -310,12 +320,12 @@ func TestPruningFromStorage(t *testing.T) {
}
crd := pruningFixture.DeepCopy()
crd.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchema), &crd.Spec.Validation.OpenAPIV3Schema); err != nil {
crd.Spec.Versions[0].Schema = &apiextensionsv1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchema), &crd.Spec.Versions[0].Schema.OpenAPIV3Schema); err != nil {
t.Fatal(err)
}
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -368,7 +378,7 @@ func TestPruningFromStorage(t *testing.T) {
}
t.Logf("Checking that CustomResource is pruned from unknown fields")
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Plural})
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Versions[0].Name, crd.Spec.Names.Plural})
foo, err := fooClient.Get(context.TODO(), "foo", metav1.GetOptions{})
if err != nil {
t.Fatalf("unexpected error: %v", err)
@ -400,16 +410,16 @@ func TestPruningPatch(t *testing.T) {
defer tearDownFn()
crd := pruningFixture.DeepCopy()
crd.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchema), &crd.Spec.Validation.OpenAPIV3Schema); err != nil {
crd.Spec.Versions[0].Schema = &apiextensionsv1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchema), &crd.Spec.Versions[0].Schema.OpenAPIV3Schema); err != nil {
t.Fatal(err)
}
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Plural})
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Versions[0].Name, crd.Spec.Names.Plural})
foo := &unstructured.Unstructured{}
if err := yaml.Unmarshal([]byte(pruningFooInstance), &foo.Object); err != nil {
t.Fatal(err)
@ -451,18 +461,18 @@ func TestPruningCreatePreservingUnknownFields(t *testing.T) {
defer tearDownFn()
crd := pruningFixture.DeepCopy()
crd.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchemaPreservingUnknownFields), &crd.Spec.Validation.OpenAPIV3Schema); err != nil {
crd.Spec.Versions[0].Schema = &apiextensionsv1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchemaPreservingUnknownFields), &crd.Spec.Versions[0].Schema.OpenAPIV3Schema); err != nil {
t.Fatal(err)
}
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
t.Logf("Creating CR and expect 'unspecified' field to be pruned")
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Plural})
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Versions[0].Name, crd.Spec.Names.Plural})
foo := &unstructured.Unstructured{}
if err := yaml.Unmarshal([]byte(pruningFooInstance), &foo.Object); err != nil {
t.Fatal(err)
@ -536,18 +546,18 @@ func TestPruningEmbeddedResources(t *testing.T) {
defer tearDownFn()
crd := pruningFixture.DeepCopy()
crd.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchemaEmbeddedResource), &crd.Spec.Validation.OpenAPIV3Schema); err != nil {
crd.Spec.Versions[0].Schema = &apiextensionsv1.CustomResourceValidation{}
if err := yaml.Unmarshal([]byte(fooSchemaEmbeddedResource), &crd.Spec.Versions[0].Schema.OpenAPIV3Schema); err != nil {
t.Fatal(err)
}
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
t.Logf("Creating CR and expect 'unspecified' field to be pruned")
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Version, crd.Spec.Names.Plural})
fooClient := dynamicClient.Resource(schema.GroupVersionResource{crd.Spec.Group, crd.Spec.Versions[0].Name, crd.Spec.Names.Plural})
foo := &unstructured.Unstructured{}
if err := yaml.Unmarshal([]byte(fooSchemaEmbeddedResourceInstance), &foo.Object); err != nil {
t.Fatal(err)

View File

@ -28,7 +28,7 @@ import (
"go.etcd.io/etcd/clientv3"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
"k8s.io/apimachinery/pkg/api/errors"
@ -47,8 +47,8 @@ func TestMultipleResourceInstances(t *testing.T) {
defer tearDown()
ns := "not-the-default"
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -172,8 +172,8 @@ func TestMultipleRegistration(t *testing.T) {
ns := "not-the-default"
sameInstanceName := "foo"
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -191,8 +191,8 @@ func TestMultipleRegistration(t *testing.T) {
t.Errorf("expected %v, got %v", e, a)
}
curletDefinition := fixtures.NewCurletCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
curletDefinition, err = fixtures.CreateNewCustomResourceDefinition(curletDefinition, apiExtensionClient, dynamicClient)
curletDefinition := fixtures.NewCurletV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
curletDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(curletDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -225,11 +225,11 @@ func TestDeRegistrationAndReRegistration(t *testing.T) {
t.Fatal(err)
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
ns := "not-the-default"
sameInstanceName := "foo"
func() {
noxuDefinition, err := fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err := fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -237,10 +237,10 @@ func TestDeRegistrationAndReRegistration(t *testing.T) {
if _, err := instantiateCustomResource(t, fixtures.NewNoxuInstance(ns, sameInstanceName), noxuNamespacedResourceClient, noxuDefinition); err != nil {
t.Fatal(err)
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
if _, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{}); err == nil || !errors.IsNotFound(err) {
if _, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{}); err == nil || !errors.IsNotFound(err) {
t.Fatalf("expected a NotFound error, got:%v", err)
}
if _, err = noxuNamespacedResourceClient.List(context.TODO(), metav1.ListOptions{}); err == nil || !errors.IsNotFound(err) {
@ -252,10 +252,10 @@ func TestDeRegistrationAndReRegistration(t *testing.T) {
}()
func() {
if _, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{}); err == nil || !errors.IsNotFound(err) {
if _, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{}); err == nil || !errors.IsNotFound(err) {
t.Fatalf("expected a NotFound error, got:%v", err)
}
noxuDefinition, err := fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err := fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -327,8 +327,8 @@ func TestEtcdStorage(t *testing.T) {
etcdPrefix := s.RecommendedOptions.Etcd.StorageConfig.Prefix
ns1 := "another-default-is-possible"
curletDefinition := fixtures.NewCurletCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
curletDefinition, err = fixtures.CreateNewCustomResourceDefinition(curletDefinition, apiExtensionClient, dynamicClient)
curletDefinition := fixtures.NewCurletV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
curletDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(curletDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -338,8 +338,8 @@ func TestEtcdStorage(t *testing.T) {
}
ns2 := "the-cruel-default"
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}

View File

@ -23,15 +23,14 @@ import (
"github.com/stretchr/testify/assert"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
)
func TestHandlerScope(t *testing.T) {
@ -41,15 +40,32 @@ func TestHandlerScope(t *testing.T) {
}
defer tearDown()
for _, scope := range []apiextensionsv1beta1.ResourceScope{apiextensionsv1beta1.ClusterScoped, apiextensionsv1beta1.NamespaceScoped} {
for _, scope := range []apiextensionsv1.ResourceScope{apiextensionsv1.ClusterScoped, apiextensionsv1.NamespaceScoped} {
t.Run(string(scope), func(t *testing.T) {
crd := &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: strings.ToLower(string(scope)) + "s.test.apiextensions-apiserver.k8s.io"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "test.apiextensions-apiserver.k8s.io",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
crd := &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: strings.ToLower(string(scope)) + "s.test.apiextensions-apiserver.k8s.io",
Annotations: map[string]string{"api-approved.kubernetes.io": "unapproved, test-only"},
},
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "test.apiextensions-apiserver.k8s.io",
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1.CustomResourceSubresourceScale{
SpecReplicasPath: ".spec.replicas",
StatusReplicasPath: ".status.replicas",
},
},
Schema: fixtures.AllowAllSchema(),
},
},
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: strings.ToLower(string(scope)) + "s",
Singular: strings.ToLower(string(scope)),
Kind: string(scope),
@ -58,14 +74,7 @@ func TestHandlerScope(t *testing.T) {
Scope: scope,
},
}
crd.Spec.Subresources = &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1beta1.CustomResourceSubresourceScale{
SpecReplicasPath: ".spec.replicas",
StatusReplicasPath: ".status.replicas",
},
}
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -75,7 +84,7 @@ func TestHandlerScope(t *testing.T) {
ns := "test"
var client dynamic.ResourceInterface = dynamicClient.Resource(gvr)
var otherScopeClient dynamic.ResourceInterface = dynamicClient.Resource(gvr).Namespace(ns)
if crd.Spec.Scope == apiextensionsv1beta1.NamespaceScoped {
if crd.Spec.Scope == apiextensionsv1.NamespaceScoped {
client, otherScopeClient = otherScopeClient, client
}
@ -141,7 +150,7 @@ func TestHandlerScope(t *testing.T) {
err = otherScopeClient.DeleteCollection(context.TODO(), metav1.DeleteOptions{}, metav1.ListOptions{})
assert.True(t, apierrors.IsNotFound(err))
if scope == apiextensionsv1beta1.ClusterScoped {
if scope == apiextensionsv1.ClusterScoped {
_, err = otherScopeClient.List(context.TODO(), metav1.ListOptions{})
assert.True(t, apierrors.IsNotFound(err))

View File

@ -35,7 +35,7 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/dynamic"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
)
@ -43,51 +43,14 @@ import (
var labelSelectorPath = ".status.labelSelector"
var anotherLabelSelectorPath = ".status.anotherLabelSelector"
func NewNoxuSubresourcesCRDs(scope apiextensionsv1beta1.ResourceScope) []*apiextensionsv1beta1.CustomResourceDefinition {
return []*apiextensionsv1beta1.CustomResourceDefinition{
// CRD that uses top-level subresources
{
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: "noxus",
Singular: "nonenglishnoxu",
Kind: "WishIHadChosenNoxu",
ShortNames: []string{"foo", "bar", "abc", "def"},
ListKind: "NoxuItemList",
},
Scope: scope,
Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
},
{
Name: "v1",
Served: true,
Storage: false,
},
},
Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1beta1.CustomResourceSubresourceScale{
SpecReplicasPath: ".spec.replicas",
StatusReplicasPath: ".status.replicas",
LabelSelectorPath: &labelSelectorPath,
},
},
},
},
func NewNoxuSubresourcesCRDs(scope apiextensionsv1.ResourceScope) []*apiextensionsv1.CustomResourceDefinition {
return []*apiextensionsv1.CustomResourceDefinition{
// CRD that uses per-version subresources
{
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "noxus",
Singular: "nonenglishnoxu",
Kind: "WishIHadChosenNoxu",
@ -95,32 +58,34 @@ func NewNoxuSubresourcesCRDs(scope apiextensionsv1beta1.ResourceScope) []*apiext
ListKind: "NoxuItemList",
},
Scope: scope,
Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1beta1.CustomResourceSubresourceScale{
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1.CustomResourceSubresourceScale{
SpecReplicasPath: ".spec.replicas",
StatusReplicasPath: ".status.replicas",
LabelSelectorPath: &labelSelectorPath,
},
},
Schema: fixtures.AllowAllSchema(),
},
{
Name: "v1",
Served: true,
Storage: false,
Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1beta1.CustomResourceSubresourceScale{
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
Scale: &apiextensionsv1.CustomResourceSubresourceScale{
SpecReplicasPath: ".spec.replicas",
StatusReplicasPath: ".status.replicas",
LabelSelectorPath: &anotherLabelSelectorPath,
},
},
Schema: fixtures.AllowAllSchema(),
},
},
},
@ -155,9 +120,9 @@ func TestStatusSubresource(t *testing.T) {
}
defer tearDown()
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1.NamespaceScoped)
for _, noxuDefinition := range noxuDefinitions {
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -254,7 +219,7 @@ func TestStatusSubresource(t *testing.T) {
}
noxuResourceClient.Delete(context.TODO(), "foo", metav1.DeleteOptions{})
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -281,7 +246,7 @@ func TestScaleSubresource(t *testing.T) {
t.Fatal(err)
}
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1.NamespaceScoped)
for _, noxuDefinition := range noxuDefinitions {
for _, v := range noxuDefinition.Spec.Versions {
// Start with a new CRD, so that the object doesn't have resourceVersion
@ -293,13 +258,13 @@ func TestScaleSubresource(t *testing.T) {
}
// set invalid json path for specReplicasPath
subresources.Scale.SpecReplicasPath = "foo,bar"
_, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
_, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err == nil {
t.Fatalf("unexpected non-error: specReplicasPath should be a valid json path under .spec")
}
subresources.Scale.SpecReplicasPath = ".spec.replicas"
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -400,7 +365,7 @@ func TestScaleSubresource(t *testing.T) {
t.Fatalf("unexpected non-error: .spec.replicas should be less than 2147483647")
}
noxuResourceClient.Delete(context.TODO(), "foo", metav1.DeleteOptions{})
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -423,22 +388,16 @@ func TestValidationSchemaWithStatus(t *testing.T) {
t.Fatal(err)
}
// fields other than properties in root schema are not allowed
noxuDefinition := newNoxuValidationCRDs(apiextensionsv1beta1.NamespaceScoped)[0]
noxuDefinition.Spec.Subresources = &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
}
_, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err == nil {
t.Fatalf(`unexpected non-error, expected: must not have "additionalProperties" at the root of the schema if the status subresource is enabled`)
}
noxuDefinition := newNoxuValidationCRDs()[0]
// make sure we are not restricting fields to properties even in subschemas
noxuDefinition.Spec.Validation.OpenAPIV3Schema = &apiextensionsv1beta1.JSONSchemaProps{
Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
noxuDefinition.Spec.Versions[0].Schema.OpenAPIV3Schema = &apiextensionsv1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"spec": {
Type: "object",
Description: "Validation for spec",
Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"replicas": {
Type: "integer",
},
@ -448,7 +407,9 @@ func TestValidationSchemaWithStatus(t *testing.T) {
Required: []string{"spec"},
Description: "This is a description at the root of the schema",
}
_, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition.Spec.Versions[1].Schema.OpenAPIV3Schema = noxuDefinition.Spec.Versions[0].Schema.OpenAPIV3Schema
_, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatalf("unable to created crd %v: %v", noxuDefinition.Name, err)
}
@ -468,10 +429,12 @@ func TestValidateOnlyStatus(t *testing.T) {
// 4. update the spec of the cr with .spec.num = 15 (spec is invalid), expect error
// max value of spec.num = 10 and status.num = 10
schema := &apiextensionsv1beta1.JSONSchemaProps{
Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
schema := &apiextensionsv1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"spec": {
Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"num": {
Type: "integer",
Maximum: float64Ptr(10),
@ -479,7 +442,8 @@ func TestValidateOnlyStatus(t *testing.T) {
},
},
"status": {
Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"num": {
Type: "integer",
Maximum: float64Ptr(10),
@ -489,24 +453,16 @@ func TestValidateOnlyStatus(t *testing.T) {
},
}
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1beta1.NamespaceScoped)
for i, noxuDefinition := range noxuDefinitions {
if i == 0 {
noxuDefinition.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{
OpenAPIV3Schema: schema,
}
} else {
noxuDefinition.Spec.Versions[0].Schema = &apiextensionsv1beta1.CustomResourceValidation{
OpenAPIV3Schema: schema,
}
schemaWithDescription := schema.DeepCopy()
schemaWithDescription.Description = "test"
noxuDefinition.Spec.Versions[1].Schema = &apiextensionsv1beta1.CustomResourceValidation{
OpenAPIV3Schema: schemaWithDescription,
}
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1.NamespaceScoped)
for _, noxuDefinition := range noxuDefinitions {
noxuDefinition.Spec.Versions[0].Schema = &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: schema.DeepCopy(),
}
noxuDefinition.Spec.Versions[1].Schema = &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: schema.DeepCopy(),
}
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -554,7 +510,7 @@ func TestValidateOnlyStatus(t *testing.T) {
}
noxuResourceClient.Delete(context.TODO(), "foo", metav1.DeleteOptions{})
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -576,9 +532,9 @@ func TestSubresourcesDiscovery(t *testing.T) {
t.Fatal(err)
}
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1.NamespaceScoped)
for _, noxuDefinition := range noxuDefinitions {
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -645,7 +601,7 @@ func TestSubresourcesDiscovery(t *testing.T) {
t.Fatalf("incorrect scale via discovery: expected: %v, got: %v", expectedVerbs, scale.Verbs)
}
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -658,9 +614,9 @@ func TestGeneration(t *testing.T) {
}
defer tearDown()
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1.NamespaceScoped)
for _, noxuDefinition := range noxuDefinitions {
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -718,7 +674,7 @@ func TestGeneration(t *testing.T) {
}
noxuResourceClient.Delete(context.TODO(), "foo", metav1.DeleteOptions{})
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -745,9 +701,9 @@ func TestSubresourcePatch(t *testing.T) {
t.Fatal(err)
}
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := NewNoxuSubresourcesCRDs(apiextensionsv1.NamespaceScoped)
for _, noxuDefinition := range noxuDefinitions {
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -882,7 +838,7 @@ func TestSubresourcePatch(t *testing.T) {
}
noxuResourceClient.Delete(context.TODO(), "foo", metav1.DeleteOptions{})
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}

View File

@ -32,42 +32,42 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/rest"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
)
func newTableCRD() *apiextensionsv1beta1.CustomResourceDefinition {
return &apiextensionsv1beta1.CustomResourceDefinition{
func newTableCRD() *apiextensionsv1.CustomResourceDefinition {
return &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "tables.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "tables",
Singular: "table",
Kind: "Table",
ListKind: "TablemList",
},
Scope: apiextensionsv1beta1.ClusterScoped,
Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{
Scope: apiextensionsv1.ClusterScoped,
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: false,
AdditionalPrinterColumns: []apiextensionsv1beta1.CustomResourceColumnDefinition{
AdditionalPrinterColumns: []apiextensionsv1.CustomResourceColumnDefinition{
{Name: "Age", Type: "date", JSONPath: ".metadata.creationTimestamp"},
{Name: "Alpha", Type: "string", JSONPath: ".spec.alpha"},
{Name: "Beta", Type: "integer", Description: "the beta field", Format: "int64", Priority: 42, JSONPath: ".spec.beta"},
{Name: "Gamma", Type: "integer", Description: "a column with wrongly typed values", JSONPath: ".spec.gamma"},
{Name: "Epsilon", Type: "string", Description: "an array of integers as string", JSONPath: ".spec.epsilon"},
},
Schema: fixtures.AllowAllSchema(),
},
{
Name: "v1",
Served: true,
Storage: true,
AdditionalPrinterColumns: []apiextensionsv1beta1.CustomResourceColumnDefinition{
AdditionalPrinterColumns: []apiextensionsv1.CustomResourceColumnDefinition{
{Name: "Age", Type: "date", JSONPath: ".metadata.creationTimestamp"},
{Name: "Alpha", Type: "string", JSONPath: ".spec.alpha"},
{Name: "Beta", Type: "integer", Description: "the beta field", Format: "int64", Priority: 42, JSONPath: ".spec.beta"},
@ -75,6 +75,7 @@ func newTableCRD() *apiextensionsv1beta1.CustomResourceDefinition {
{Name: "Epsilon", Type: "string", Description: "an array of integers as string", JSONPath: ".spec.epsilon"},
{Name: "Zeta", Type: "integer", Description: "the zeta field", Format: "int64", Priority: 42, JSONPath: ".spec.zeta"},
},
Schema: fixtures.AllowAllSchema(),
},
},
},
@ -119,12 +120,12 @@ func TestTableGet(t *testing.T) {
}
crd := newTableCRD()
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
crd, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
crd, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
@ -377,8 +378,8 @@ func TestColumnsPatch(t *testing.T) {
}
// CRD with no top-level and per-version columns should be created successfully
crd := NewNoxuSubresourcesCRDs(apiextensionsv1beta1.NamespaceScoped)[0]
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd := NewNoxuSubresourcesCRDs(apiextensionsv1.NamespaceScoped)[0]
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -386,14 +387,50 @@ func TestColumnsPatch(t *testing.T) {
// One should be able to patch the CRD to use per-version columns. The top-level columns
// should not be defaulted during creation, and apiserver should not return validation
// error about top-level and per-version columns being mutual exclusive.
patch := []byte(`{"spec":{"versions":[{"name":"v1beta1","served":true,"storage":true,"additionalPrinterColumns":[{"name":"Age","type":"date","JSONPath":".metadata.creationTimestamp"}]},{"name":"v1","served":true,"storage":false,"additionalPrinterColumns":[{"name":"Age2","type":"date","JSONPath":".metadata.creationTimestamp"}]}]}}`)
patch := []byte(`{
"spec": {
"versions": [
{
"name": "v1beta1",
"served": true,
"storage": true,
"additionalPrinterColumns": [
{
"name": "Age",
"type": "date",
"jsonPath": ".metadata.creationTimestamp"
}
],
"schema": {
"openAPIV3Schema": {"x-kubernetes-preserve-unknown-fields": true, "type": "object"}
}
},
{
"name": "v1",
"served": true,
"storage": false,
"additionalPrinterColumns": [
{
"name": "Age2",
"type": "date",
"jsonPath": ".metadata.creationTimestamp"
}
],
"schema": {
"openAPIV3Schema": {"x-kubernetes-preserve-unknown-fields": true, "type": "object"}
}
}
]
}
}
`)
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Patch(context.TODO(), crd.Name, types.MergePatchType, patch, metav1.PatchOptions{})
_, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Patch(context.TODO(), crd.Name, types.MergePatchType, patch, metav1.PatchOptions{})
if err != nil {
t.Fatal(err)
}
crd, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
crd, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
@ -420,11 +457,11 @@ func TestPatchCleanTopLevelColumns(t *testing.T) {
t.Fatal(err)
}
crd := NewNoxuSubresourcesCRDs(apiextensionsv1beta1.NamespaceScoped)[0]
crd.Spec.AdditionalPrinterColumns = []apiextensionsv1beta1.CustomResourceColumnDefinition{
crd := NewNoxuSubresourcesCRDs(apiextensionsv1.NamespaceScoped)[0]
crd.Spec.Versions[0].AdditionalPrinterColumns = []apiextensionsv1.CustomResourceColumnDefinition{
{Name: "Age", Type: "date", Description: swaggerMetadataDescriptions["creationTimestamp"], JSONPath: ".metadata.creationTimestamp"},
}
crd, err = fixtures.CreateNewCustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
crd, err = fixtures.CreateNewV1CustomResourceDefinition(crd, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -432,14 +469,51 @@ func TestPatchCleanTopLevelColumns(t *testing.T) {
// One should be able to patch the CRD to use per-version columns by cleaning
// the top-level columns.
patch := []byte(`{"spec":{"additionalPrinterColumns":null,"versions":[{"name":"v1beta1","served":true,"storage":true,"additionalPrinterColumns":[{"name":"Age","type":"date","JSONPath":".metadata.creationTimestamp"}]},{"name":"v1","served":true,"storage":false,"additionalPrinterColumns":[{"name":"Age2","type":"date","JSONPath":".metadata.creationTimestamp"}]}]}}`)
patch := []byte(`{
"spec": {
"additionalPrinterColumns": null,
"versions": [
{
"name": "v1beta1",
"served": true,
"storage": true,
"additionalPrinterColumns": [
{
"name": "Age",
"type": "date",
"jsonPath": ".metadata.creationTimestamp"
}
],
"schema": {
"openAPIV3Schema": {"x-kubernetes-preserve-unknown-fields": true, "type": "object"}
}
},
{
"name": "v1",
"served": true,
"storage": false,
"additionalPrinterColumns": [
{
"name": "Age2",
"type": "date",
"jsonPath": ".metadata.creationTimestamp"
}
],
"schema": {
"openAPIV3Schema": {"x-kubernetes-preserve-unknown-fields": true, "type": "object"}
}
}
]
}
}
`)
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Patch(context.TODO(), crd.Name, types.MergePatchType, patch, metav1.PatchOptions{})
_, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Patch(context.TODO(), crd.Name, types.MergePatchType, patch, metav1.PatchOptions{})
if err != nil {
t.Fatal(err)
}
crd, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
crd, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}

View File

@ -19,6 +19,7 @@ package integration
import (
"context"
"fmt"
"path"
"strings"
"testing"
"time"
@ -27,9 +28,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/json"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/util/yaml"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
@ -44,8 +46,8 @@ func TestForProperValidationErrors(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -91,13 +93,11 @@ func TestForProperValidationErrors(t *testing.T) {
}
}
func newNoxuValidationCRDs(scope apiextensionsv1beta1.ResourceScope) []*apiextensionsv1beta1.CustomResourceDefinition {
validationSchema := &apiextensionsv1beta1.JSONSchemaProps{
func newNoxuValidationCRDs() []*apiextensionsv1.CustomResourceDefinition {
validationSchema := &apiextensionsv1.JSONSchemaProps{
Type: "object",
Required: []string{"alpha", "beta"},
AdditionalProperties: &apiextensionsv1beta1.JSONSchemaPropsOrBool{
Allows: true,
},
Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"alpha": {
Description: "Alpha is an alphanumeric string with underscores",
Type: "string",
@ -111,7 +111,7 @@ func newNoxuValidationCRDs(scope apiextensionsv1beta1.ResourceScope) []*apiexten
"gamma": {
Description: "Gamma is restricted to foo, bar and baz",
Type: "string",
Enum: []apiextensionsv1beta1.JSON{
Enum: []apiextensionsv1.JSON{
{
Raw: []byte(`"foo"`),
},
@ -123,73 +123,29 @@ func newNoxuValidationCRDs(scope apiextensionsv1beta1.ResourceScope) []*apiexten
},
},
},
"delta": {
Description: "Delta is a string with a maximum length of 5 or a number with a minimum value of 0",
AnyOf: []apiextensionsv1beta1.JSONSchemaProps{
{
Type: "string",
MaxLength: int64Ptr(5),
},
{
Type: "number",
Minimum: float64Ptr(0),
},
},
},
},
}
validationSchemaWithDescription := validationSchema.DeepCopy()
validationSchemaWithDescription.Description = "test"
return []*apiextensionsv1beta1.CustomResourceDefinition{
return []*apiextensionsv1.CustomResourceDefinition{
{
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "noxus",
Singular: "nonenglishnoxu",
Kind: "WishIHadChosenNoxu",
ShortNames: []string{"foo", "bar", "abc", "def"},
ListKind: "NoxuItemList",
},
Scope: apiextensionsv1beta1.NamespaceScoped,
Validation: &apiextensionsv1beta1.CustomResourceValidation{
OpenAPIV3Schema: validationSchema,
},
Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{
Scope: apiextensionsv1.NamespaceScoped,
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
},
{
Name: "v1",
Served: true,
Storage: false,
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: "noxus",
Singular: "nonenglishnoxu",
Kind: "WishIHadChosenNoxu",
ShortNames: []string{"foo", "bar", "abc", "def"},
ListKind: "NoxuItemList",
},
Scope: apiextensionsv1beta1.NamespaceScoped,
Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
Schema: &apiextensionsv1beta1.CustomResourceValidation{
Schema: &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: validationSchema,
},
},
@ -197,7 +153,39 @@ func newNoxuValidationCRDs(scope apiextensionsv1beta1.ResourceScope) []*apiexten
Name: "v1",
Served: true,
Storage: false,
Schema: &apiextensionsv1beta1.CustomResourceValidation{
Schema: &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: validationSchema,
},
},
},
},
},
{
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "noxus",
Singular: "nonenglishnoxu",
Kind: "WishIHadChosenNoxu",
ShortNames: []string{"foo", "bar", "abc", "def"},
ListKind: "NoxuItemList",
},
Scope: apiextensionsv1.NamespaceScoped,
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
Schema: &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: validationSchema,
},
},
{
Name: "v1",
Served: true,
Storage: false,
Schema: &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: validationSchemaWithDescription,
},
},
@ -231,9 +219,9 @@ func TestCustomResourceValidation(t *testing.T) {
}
defer tearDown()
noxuDefinitions := newNoxuValidationCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := newNoxuValidationCRDs()
for _, noxuDefinition := range noxuDefinitions {
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -249,7 +237,7 @@ func TestCustomResourceValidation(t *testing.T) {
}
noxuResourceClient.Delete(context.TODO(), "foo", metav1.DeleteOptions{})
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -436,9 +424,9 @@ func TestCustomResourceUpdateValidation(t *testing.T) {
}
defer tearDown()
noxuDefinitions := newNoxuValidationCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := newNoxuValidationCRDs()
for _, noxuDefinition := range noxuDefinitions {
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -476,7 +464,7 @@ func TestCustomResourceUpdateValidation(t *testing.T) {
}
noxuResourceClient.Delete(context.TODO(), "foo", metav1.DeleteOptions{})
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -489,9 +477,9 @@ func TestCustomResourceValidationErrors(t *testing.T) {
}
defer tearDown()
noxuDefinitions := newNoxuValidationCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := newNoxuValidationCRDs()
for _, noxuDefinition := range noxuDefinitions {
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -530,18 +518,6 @@ func TestCustomResourceValidationErrors(t *testing.T) {
},
expectedErrors: []string{`gamma: Unsupported value: "qux": supported values: "foo", "bar", "baz"`},
},
{
name: "bad delta",
instanceFn: func() *unstructured.Unstructured {
instance := newNoxuValidationInstance(ns, "foo")
instance.Object["delta"] = "foobarbaz"
return instance
},
expectedErrors: []string{
"must validate at least one schema (anyOf)",
"delta in body should be at most 5 chars long",
},
},
{
name: "absent alpha and beta",
instanceFn: func() *unstructured.Unstructured {
@ -580,7 +556,7 @@ func TestCustomResourceValidationErrors(t *testing.T) {
}
}
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -593,26 +569,27 @@ func TestCRValidationOnCRDUpdate(t *testing.T) {
}
defer tearDown()
noxuDefinitions := newNoxuValidationCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := newNoxuValidationCRDs()
for i, noxuDefinition := range noxuDefinitions {
for _, v := range noxuDefinition.Spec.Versions {
// Re-define the CRD to make sure we start with a clean CRD
noxuDefinition := newNoxuValidationCRDs(apiextensionsv1beta1.NamespaceScoped)[i]
noxuDefinition := newNoxuValidationCRDs()[i]
validationSchema, err := getSchemaForVersion(noxuDefinition, v.Name)
if err != nil {
t.Fatal(err)
}
// set stricter schema
validationSchema.OpenAPIV3Schema.Required = []string{"alpha", "beta", "epsilon"}
validationSchema.OpenAPIV3Schema.Required = []string{"alpha", "beta", "gamma"}
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
ns := "not-the-default"
noxuResourceClient := newNamespacedCustomResourceVersionedClient(ns, dynamicClient, noxuDefinition, v.Name)
instanceToCreate := newNoxuValidationInstance(ns, "foo")
unstructured.RemoveNestedField(instanceToCreate.Object, "gamma")
instanceToCreate.Object["apiVersion"] = fmt.Sprintf("%s/%s", noxuDefinition.Spec.Group, v.Name)
// CR is rejected
@ -622,7 +599,7 @@ func TestCRValidationOnCRDUpdate(t *testing.T) {
}
// update the CRD to a less stricter schema
_, err = UpdateCustomResourceDefinitionWithRetry(apiExtensionClient, "noxus.mygroup.example.com", func(crd *apiextensionsv1beta1.CustomResourceDefinition) {
_, err = UpdateCustomResourceDefinitionWithRetry(apiExtensionClient, "noxus.mygroup.example.com", func(crd *apiextensionsv1.CustomResourceDefinition) {
validationSchema, err := getSchemaForVersion(crd, v.Name)
if err != nil {
t.Fatal(err)
@ -650,7 +627,7 @@ func TestCRValidationOnCRDUpdate(t *testing.T) {
t.Fatal(err)
}
noxuResourceClient.Delete(context.TODO(), "foo", metav1.DeleteOptions{})
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -664,51 +641,59 @@ func TestForbiddenFieldsInSchema(t *testing.T) {
}
defer tearDown()
noxuDefinitions := newNoxuValidationCRDs(apiextensionsv1beta1.NamespaceScoped)
noxuDefinitions := newNoxuValidationCRDs()
for i, noxuDefinition := range noxuDefinitions {
for _, v := range noxuDefinition.Spec.Versions {
// Re-define the CRD to make sure we start with a clean CRD
noxuDefinition := newNoxuValidationCRDs(apiextensionsv1beta1.NamespaceScoped)[i]
noxuDefinition := newNoxuValidationCRDs()[i]
validationSchema, err := getSchemaForVersion(noxuDefinition, v.Name)
if err != nil {
t.Fatal(err)
}
validationSchema.OpenAPIV3Schema.AdditionalProperties.Allows = false
_, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
existingProperties := validationSchema.OpenAPIV3Schema.Properties
validationSchema.OpenAPIV3Schema.Properties = nil
validationSchema.OpenAPIV3Schema.AdditionalProperties = &apiextensionsv1.JSONSchemaPropsOrBool{Allows: false}
_, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err == nil {
t.Fatalf("unexpected non-error: additionalProperties cannot be set to false")
}
// reset
validationSchema.OpenAPIV3Schema.Properties = existingProperties
validationSchema.OpenAPIV3Schema.AdditionalProperties = nil
validationSchema.OpenAPIV3Schema.Properties["zeta"] = apiextensionsv1beta1.JSONSchemaProps{
validationSchema.OpenAPIV3Schema.Properties["zeta"] = apiextensionsv1.JSONSchemaProps{
Type: "array",
UniqueItems: true,
AdditionalProperties: &apiextensionsv1.JSONSchemaPropsOrBool{
Allows: true,
},
}
validationSchema.OpenAPIV3Schema.AdditionalProperties.Allows = true
_, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
_, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err == nil {
t.Fatalf("unexpected non-error: uniqueItems cannot be set to true")
}
validationSchema.OpenAPIV3Schema.Ref = strPtr("#/definition/zeta")
validationSchema.OpenAPIV3Schema.Properties["zeta"] = apiextensionsv1beta1.JSONSchemaProps{
validationSchema.OpenAPIV3Schema.Properties["zeta"] = apiextensionsv1.JSONSchemaProps{
Type: "array",
UniqueItems: false,
Items: &apiextensionsv1.JSONSchemaPropsOrArray{
Schema: &apiextensionsv1.JSONSchemaProps{Type: "object"},
},
}
_, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
_, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err == nil {
t.Fatal("unexpected non-error: $ref cannot be non-empty string")
}
validationSchema.OpenAPIV3Schema.Ref = nil
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
if err := fixtures.DeleteCustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
if err := fixtures.DeleteV1CustomResourceDefinition(noxuDefinition, apiExtensionClient); err != nil {
t.Fatal(err)
}
}
@ -716,7 +701,7 @@ func TestForbiddenFieldsInSchema(t *testing.T) {
}
func TestNonStructuralSchemaConditionUpdate(t *testing.T) {
tearDown, apiExtensionClient, _, err := fixtures.StartDefaultServerWithClients(t)
tearDown, apiExtensionClient, _, etcdclient, etcdStoragePrefix, err := fixtures.StartDefaultServerWithClientsAndEtcd(t)
if err != nil {
t.Fatal(err)
}
@ -752,27 +737,37 @@ spec:
if err != nil {
t.Fatalf("failed decoding of: %v\n\n%s", err, manifest)
}
crd := obj.(*apiextensionsv1beta1.CustomResourceDefinition)
name := crd.Name
betaCRD := obj.(*apiextensionsv1beta1.CustomResourceDefinition)
name := betaCRD.Name
// save schema for later
origSchema := crd.Spec.Validation.OpenAPIV3Schema
origSchema := &apiextensionsv1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"a": {
Type: "object",
},
},
}
// create CRDs
t.Logf("Creating CRD %s", crd.Name)
if _, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Create(context.TODO(), crd, metav1.CreateOptions{}); err != nil {
t.Fatalf("unexpected create error: %v", err)
// create CRDs. We cannot create these in v1, but they can exist in upgraded clusters
t.Logf("Creating CRD %s", betaCRD.Name)
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
key := path.Join("/", etcdStoragePrefix, "apiextensions.k8s.io", "customresourcedefinitions/foos.tests.example.com")
val, _ := json.Marshal(betaCRD)
if _, err := etcdclient.Put(ctx, key, string(val)); err != nil {
t.Fatalf("unexpected error: %v", err)
}
// wait for condition with violations
t.Log("Waiting for NonStructuralSchema condition")
var cond *apiextensionsv1beta1.CustomResourceDefinitionCondition
var cond *apiextensionsv1.CustomResourceDefinitionCondition
err = wait.PollImmediate(100*time.Millisecond, 5*time.Second, func() (bool, error) {
obj, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
obj, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return false, err
}
cond = findCRDCondition(obj, apiextensionsv1beta1.NonStructuralSchema)
cond = findCRDCondition(obj, apiextensionsv1.NonStructuralSchema)
return cond != nil, nil
})
if err != nil {
@ -785,34 +780,32 @@ spec:
t.Fatalf("expected violation %q, but got: %v", v, cond.Message)
}
// remove schema
t.Log("Remove schema")
t.Log("fix schema")
for retry := 0; retry < 5; retry++ {
// This patch fixes two fields to resolve
// 1. property type validation error
// 2. preserveUnknownFields validation error
patch := []byte("[{\"op\":\"add\",\"path\":\"/spec/validation/openAPIV3Schema/properties/a/type\",\"value\":\"int\"}," +
"{\"op\":\"replace\",\"path\":\"/spec/preserveUnknownFields\",\"value\":false}]")
if _, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Patch(context.TODO(), name, types.JSONPatchType, patch, metav1.PatchOptions{}); apierrors.IsConflict(err) {
crd, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
crd.Spec.Versions[0].Schema = fixtures.AllowAllSchema()
crd.Spec.PreserveUnknownFields = false
_, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
if apierrors.IsConflict(err) {
continue
}
if err != nil {
t.Fatalf("unexpected update error: %v", err)
t.Fatal(err)
}
break
}
if err != nil {
t.Fatalf("unexpected update error: %v", err)
}
// wait for condition to go away
t.Log("Wait for condition to disappear")
err = wait.PollImmediate(100*time.Millisecond, 5*time.Second, func() (bool, error) {
obj, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
obj, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return false, err
}
cond = findCRDCondition(obj, apiextensionsv1beta1.NonStructuralSchema)
cond = findCRDCondition(obj, apiextensionsv1.NonStructuralSchema)
return cond == nil, nil
})
if err != nil {
@ -822,43 +815,23 @@ spec:
// re-add schema
t.Log("Re-add schema")
for retry := 0; retry < 5; retry++ {
crd, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
crd, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
t.Fatalf("unexpected get error: %v", err)
}
crd.Spec.PreserveUnknownFields = nil
crd.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{OpenAPIV3Schema: origSchema}
if _, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{}); apierrors.IsConflict(err) {
crd.Spec.PreserveUnknownFields = true
crd.Spec.Versions[0].Schema = &apiextensionsv1.CustomResourceValidation{OpenAPIV3Schema: origSchema}
if _, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{}); apierrors.IsConflict(err) {
continue
}
if err != nil {
t.Fatalf("unexpected update error: %v", err)
if err == nil {
t.Fatalf("missing error")
}
if !strings.Contains(err.Error(), "spec.preserveUnknownFields") {
t.Fatal(err)
}
break
}
if err != nil {
t.Fatalf("unexpected update error: %v", err)
}
// wait for condition with violations
t.Log("Wait for condition to reappear")
err = wait.PollImmediate(100*time.Millisecond, 5*time.Second, func() (bool, error) {
obj, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return false, err
}
cond = findCRDCondition(obj, apiextensionsv1beta1.NonStructuralSchema)
return cond != nil, nil
})
if err != nil {
t.Fatalf("unexpected error waiting for NonStructuralSchema condition: %v", cond)
}
if v := "spec.versions[0].schema.openAPIV3Schema.properties[a].type: Required value: must not be empty for specified object fields"; !strings.Contains(cond.Message, v) {
t.Fatalf("expected violation %q, but got: %v", v, cond.Message)
}
if v := "spec.preserveUnknownFields: Invalid value: true: must be false"; !strings.Contains(cond.Message, v) {
t.Fatalf("expected violation %q, but got: %v", v, cond.Message)
}
}
func TestNonStructuralSchemaCondition(t *testing.T) {
@ -1657,13 +1630,13 @@ properties:
if len(tst.expectedViolations) == 0 {
// wait for condition to not appear
var cond *apiextensionsv1beta1.CustomResourceDefinitionCondition
var cond *apiextensionsv1.CustomResourceDefinitionCondition
err := wait.PollImmediate(100*time.Millisecond, 5*time.Second, func() (bool, error) {
obj, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
obj, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
if err != nil {
return false, err
}
cond = findCRDCondition(obj, apiextensionsv1beta1.NonStructuralSchema)
cond = findCRDCondition(obj, apiextensionsv1.NonStructuralSchema)
if cond == nil {
return false, nil
}
@ -1676,13 +1649,13 @@ properties:
}
// wait for condition to appear with the given violations
var cond *apiextensionsv1beta1.CustomResourceDefinitionCondition
var cond *apiextensionsv1.CustomResourceDefinitionCondition
err = wait.PollImmediate(100*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
obj, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
obj, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), crd.Name, metav1.GetOptions{})
if err != nil {
return false, err
}
cond = findCRDCondition(obj, apiextensionsv1beta1.NonStructuralSchema)
cond = findCRDCondition(obj, apiextensionsv1.NonStructuralSchema)
if cond != nil {
return true, nil
}
@ -1696,7 +1669,7 @@ properties:
if cond.Reason != "Violations" {
t.Errorf("expected reason Violations, got: %v", cond.Reason)
}
if cond.Status != apiextensionsv1beta1.ConditionTrue {
if cond.Status != apiextensionsv1.ConditionTrue {
t.Errorf("expected reason True, got: %v", cond.Status)
}
@ -1717,7 +1690,7 @@ properties:
}
// findCRDCondition returns the condition you're looking for or nil.
func findCRDCondition(crd *apiextensionsv1beta1.CustomResourceDefinition, conditionType apiextensionsv1beta1.CustomResourceDefinitionConditionType) *apiextensionsv1beta1.CustomResourceDefinitionCondition {
func findCRDCondition(crd *apiextensionsv1.CustomResourceDefinition, conditionType apiextensionsv1.CustomResourceDefinitionConditionType) *apiextensionsv1.CustomResourceDefinitionCondition {
for i := range crd.Status.Conditions {
if crd.Status.Conditions[i].Type == conditionType {
return &crd.Status.Conditions[i]
@ -1742,10 +1715,6 @@ func float64Ptr(f float64) *float64 {
return &f
}
func int64Ptr(f int64) *int64 {
return &f
}
func strPtr(str string) *string {
return &str
}

View File

@ -25,7 +25,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -40,13 +40,13 @@ func TestInternalVersionIsHandlerVersion(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.NamespaceScoped)
assert.Equal(t, "v1beta1", noxuDefinition.Spec.Versions[0].Name)
assert.Equal(t, "v1beta2", noxuDefinition.Spec.Versions[1].Name)
assert.True(t, noxuDefinition.Spec.Versions[1].Storage)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -64,16 +64,20 @@ func TestInternalVersionIsHandlerVersion(t *testing.T) {
// update validation via update because the cache priming in CreateNewCustomResourceDefinition will fail otherwise
t.Logf("Updating CRD to validate apiVersion")
noxuDefinition, err = UpdateCustomResourceDefinitionWithRetry(apiExtensionClient, noxuDefinition.Name, func(crd *apiextensionsv1beta1.CustomResourceDefinition) {
crd.Spec.Validation = &apiextensionsv1beta1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1beta1.JSONSchemaProps{
Properties: map[string]apiextensionsv1beta1.JSONSchemaProps{
"apiVersion": {
Pattern: "^mygroup.example.com/v1beta1$", // this means we can only patch via the v1beta1 handler version
noxuDefinition, err = UpdateCustomResourceDefinitionWithRetry(apiExtensionClient, noxuDefinition.Name, func(crd *apiextensionsv1.CustomResourceDefinition) {
for i := range crd.Spec.Versions {
crd.Spec.Versions[i].Schema = &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
Type: "object",
Properties: map[string]apiextensionsv1.JSONSchemaProps{
"apiVersion": {
Pattern: "^mygroup.example.com/v1beta1$", // this means we can only patch via the v1beta1 handler version
Type: "string",
},
},
Required: []string{"apiVersion"},
},
Required: []string{"apiVersion"},
},
}
}
})
assert.NoError(t, err)
@ -134,8 +138,8 @@ func TestVersionedNamespacedScopedCRD(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.NamespaceScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -151,8 +155,8 @@ func TestVersionedClusterScopedCRD(t *testing.T) {
}
defer tearDown()
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
@ -162,40 +166,44 @@ func TestVersionedClusterScopedCRD(t *testing.T) {
}
func TestStoragedVersionInNamespacedCRDStatus(t *testing.T) {
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1beta1.NamespaceScoped)
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.NamespaceScoped)
ns := "not-the-default"
testStoragedVersionInCRDStatus(t, ns, noxuDefinition)
}
func TestStoragedVersionInClusterScopedCRDStatus(t *testing.T) {
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1beta1.ClusterScoped)
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.ClusterScoped)
ns := ""
testStoragedVersionInCRDStatus(t, ns, noxuDefinition)
}
func testStoragedVersionInCRDStatus(t *testing.T, ns string, noxuDefinition *apiextensionsv1beta1.CustomResourceDefinition) {
versionsV1Beta1Storage := []apiextensionsv1beta1.CustomResourceDefinitionVersion{
func testStoragedVersionInCRDStatus(t *testing.T, ns string, noxuDefinition *apiextensionsv1.CustomResourceDefinition) {
versionsV1Beta1Storage := []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: true,
Schema: fixtures.AllowAllSchema(),
},
{
Name: "v1beta2",
Served: true,
Storage: false,
Schema: fixtures.AllowAllSchema(),
},
}
versionsV1Beta2Storage := []apiextensionsv1beta1.CustomResourceDefinitionVersion{
versionsV1Beta2Storage := []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: false,
Schema: fixtures.AllowAllSchema(),
},
{
Name: "v1beta2",
Served: true,
Storage: true,
Schema: fixtures.AllowAllSchema(),
},
}
tearDown, apiExtensionClient, dynamicClient, err := fixtures.StartDefaultServerWithClients(t)
@ -205,13 +213,13 @@ func testStoragedVersionInCRDStatus(t *testing.T, ns string, noxuDefinition *api
defer tearDown()
noxuDefinition.Spec.Versions = versionsV1Beta1Storage
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
// The storage version list should be initilized to storage version
crd, err := apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
crd, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
@ -221,11 +229,11 @@ func testStoragedVersionInCRDStatus(t *testing.T, ns string, noxuDefinition *api
// Changing CRD storage version should be reflected immediately
crd.Spec.Versions = versionsV1Beta2Storage
_, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
_, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
if err != nil {
t.Fatal(err)
}
crd, err = apiExtensionClient.ApiextensionsV1beta1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
crd, err = apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuDefinition.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
@ -233,7 +241,7 @@ func testStoragedVersionInCRDStatus(t *testing.T, ns string, noxuDefinition *api
t.Errorf("expected %v, got %v", e, a)
}
err = fixtures.DeleteCustomResourceDefinition(crd, apiExtensionClient)
err = fixtures.DeleteV1CustomResourceDefinition(crd, apiExtensionClient)
if err != nil {
t.Fatal(err)
}

View File

@ -30,7 +30,7 @@ import (
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/dynamic"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
)
@ -51,15 +51,15 @@ func TestYAML(t *testing.T) {
t.Fatal(err)
}
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := fixtures.NewNoxuV1CustomResourceDefinition(apiextensionsv1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
kind := noxuDefinition.Spec.Names.Kind
listKind := noxuDefinition.Spec.Names.ListKind
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Version
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
rest := apiExtensionClient.Discovery().RESTClient()
@ -67,7 +67,7 @@ func TestYAML(t *testing.T) {
{
result, err := rest.Get().
SetHeader("Accept", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name).
DoRaw(context.TODO())
if err != nil {
t.Fatal(err, string(result))
@ -88,7 +88,7 @@ func TestYAML(t *testing.T) {
{
result, err := rest.Get().
SetHeader("Accept", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "missingname").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "missingname").
DoRaw(context.TODO())
if !errors.IsNotFound(err) {
t.Fatalf("expected not found, got %v", err)
@ -123,7 +123,7 @@ values:
result, err := rest.Post().
SetHeader("Accept", "application/yaml").
SetHeader("Content-Type", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Body(yamlBody).
DoRaw(context.TODO())
if err != nil {
@ -159,7 +159,7 @@ values:
{
result, err := rest.Get().
SetHeader("Accept", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "mytest").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "mytest").
DoRaw(context.TODO())
if err != nil {
t.Fatal(err)
@ -192,7 +192,7 @@ values:
{
result, err := rest.Get().
SetHeader("Accept", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
DoRaw(context.TODO())
if err != nil {
t.Fatal(err, string(result))
@ -236,7 +236,7 @@ values:
{
result, err := rest.Get().
SetHeader("Accept", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Param("watch", "true").
DoRaw(context.TODO())
if !errors.IsNotAcceptable(err) {
@ -273,7 +273,7 @@ values:
result, err := rest.Put().
SetHeader("Accept", "application/yaml").
SetHeader("Content-Type", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "mytest").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "mytest").
Body(yamlBody).
DoRaw(context.TODO())
if err != nil {
@ -314,7 +314,7 @@ values:
result, err := rest.Patch(types.MergePatchType).
SetHeader("Accept", "application/yaml").
SetHeader("Content-Type", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "mytest").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "mytest").
Body(yamlBody).
DoRaw(context.TODO())
if !errors.IsUnsupportedMediaType(err) {
@ -336,7 +336,7 @@ values:
{
result, err := rest.Delete().
SetHeader("Accept", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "mytest").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "mytest").
DoRaw(context.TODO())
if err != nil {
t.Fatal(err, string(result))
@ -370,14 +370,14 @@ func TestYAMLSubresource(t *testing.T) {
t.Fatal(err)
}
noxuDefinition := NewNoxuSubresourcesCRDs(apiextensionsv1beta1.ClusterScoped)[0]
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition := NewNoxuSubresourcesCRDs(apiextensionsv1.ClusterScoped)[0]
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
kind := noxuDefinition.Spec.Names.Kind
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Version
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
rest := apiExtensionClient.Discovery().RESTClient()
@ -397,7 +397,7 @@ spec:
result, err := rest.Post().
SetHeader("Accept", "application/yaml").
SetHeader("Content-Type", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Body(yamlBody).
DoRaw(context.TODO())
if err != nil {
@ -427,7 +427,7 @@ spec:
{
result, err := rest.Get().
SetHeader("Accept", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "mytest", "status").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "mytest", "status").
DoRaw(context.TODO())
if err != nil {
t.Fatal(err)
@ -466,7 +466,7 @@ status:
result, err := rest.Put().
SetHeader("Accept", "application/yaml").
SetHeader("Content-Type", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "mytest", "status").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "mytest", "status").
Body(yamlBody).
DoRaw(context.TODO())
if err != nil {
@ -500,7 +500,7 @@ status:
{
result, err := rest.Get().
SetHeader("Accept", "application/yaml").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural, "mytest", "scale").
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural, "mytest", "scale").
DoRaw(context.TODO())
if err != nil {
t.Fatal(err)

View File

@ -34,7 +34,7 @@ import (
apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsclient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -798,28 +798,35 @@ func TestMetadataClient(t *testing.T) {
t.Fatal(err)
}
fooCRD := &apiextensionsv1beta1.CustomResourceDefinition{
fooCRD := &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "foos.cr.bar.com",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "cr.bar.com",
Version: "v1",
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "cr.bar.com",
Scope: apiextensionsv1.NamespaceScoped,
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "foos",
Kind: "Foo",
},
Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
Schema: fixtures.AllowAllSchema(),
Subresources: &apiextensionsv1.CustomResourceSubresources{
Status: &apiextensionsv1.CustomResourceSubresourceStatus{},
},
},
},
},
}
fooCRD, err = fixtures.CreateNewCustomResourceDefinition(fooCRD, apiExtensionClient, dynamicClient)
fooCRD, err = fixtures.CreateNewV1CustomResourceDefinition(fooCRD, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
crdGVR := schema.GroupVersionResource{Group: fooCRD.Spec.Group, Version: fooCRD.Spec.Version, Resource: "foos"}
crdGVR := schema.GroupVersionResource{Group: fooCRD.Spec.Group, Version: fooCRD.Spec.Versions[0].Name, Resource: "foos"}
testcases := []struct {
name string
@ -1119,26 +1126,33 @@ func TestAPICRDProtobuf(t *testing.T) {
t.Fatal(err)
}
fooCRD := &apiextensionsv1beta1.CustomResourceDefinition{
fooCRD := &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "foos.cr.bar.com",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "cr.bar.com",
Version: "v1",
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "cr.bar.com",
Scope: apiextensionsv1.NamespaceScoped,
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "foos",
Kind: "Foo",
},
Subresources: &apiextensionsv1beta1.CustomResourceSubresources{Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{}},
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
Schema: fixtures.AllowAllSchema(),
Subresources: &apiextensionsv1.CustomResourceSubresources{Status: &apiextensionsv1.CustomResourceSubresourceStatus{}},
},
},
},
}
fooCRD, err = fixtures.CreateNewCustomResourceDefinition(fooCRD, apiExtensionClient, dynamicClient)
fooCRD, err = fixtures.CreateNewV1CustomResourceDefinition(fooCRD, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
crdGVR := schema.GroupVersionResource{Group: fooCRD.Spec.Group, Version: fooCRD.Spec.Version, Resource: "foos"}
crdGVR := schema.GroupVersionResource{Group: fooCRD.Spec.Group, Version: fooCRD.Spec.Versions[0].Name, Resource: "foos"}
crclient := dynamicClient.Resource(crdGVR).Namespace(testNamespace)
testcases := []struct {
@ -1331,25 +1345,32 @@ func TestTransform(t *testing.T) {
t.Fatal(err)
}
fooCRD := &apiextensionsv1beta1.CustomResourceDefinition{
fooCRD := &apiextensionsv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "foos.cr.bar.com",
},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "cr.bar.com",
Version: "v1",
Scope: apiextensionsv1beta1.NamespaceScoped,
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Spec: apiextensionsv1.CustomResourceDefinitionSpec{
Group: "cr.bar.com",
Scope: apiextensionsv1.NamespaceScoped,
Names: apiextensionsv1.CustomResourceDefinitionNames{
Plural: "foos",
Kind: "Foo",
},
Versions: []apiextensionsv1.CustomResourceDefinitionVersion{
{
Name: "v1",
Served: true,
Storage: true,
Schema: fixtures.AllowAllSchema(),
},
},
},
}
fooCRD, err = fixtures.CreateNewCustomResourceDefinition(fooCRD, apiExtensionClient, dynamicClient)
fooCRD, err = fixtures.CreateNewV1CustomResourceDefinition(fooCRD, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
crdGVR := schema.GroupVersionResource{Group: fooCRD.Spec.Group, Version: fooCRD.Spec.Version, Resource: "foos"}
crdGVR := schema.GroupVersionResource{Group: fooCRD.Spec.Group, Version: fooCRD.Spec.Versions[0].Name, Resource: "foos"}
crclient := dynamicClient.Resource(crdGVR).Namespace(testNamespace)
testcases := []struct {

View File

@ -0,0 +1,234 @@
/*
Copyright 2021 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 apiserver
import (
"context"
"fmt"
"reflect"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
"k8s.io/apiextensions-apiserver/test/integration/fixtures"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
genericfeatures "k8s.io/apiserver/pkg/features"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/dynamic"
featuregatetesting "k8s.io/component-base/featuregate/testing"
apiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
"k8s.io/kubernetes/test/integration/framework"
)
// TestApplyCRDNoSchema tests that CRDs and CRs can both be applied to with a PATCH request with the apply content type
// when there is no validation field provided.
func TestApplyCRDNoSchema(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, true)()
server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), nil, framework.SharedEtcd())
if err != nil {
t.Fatal(err)
}
defer server.TearDownFn()
config := server.ClientConfig
apiExtensionClient, err := clientset.NewForConfig(config)
if err != nil {
t.Fatal(err)
}
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
t.Fatal(err)
}
noxuDefinition := nearlyRemovedBetaMultipleVersionNoxuCRD(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
kind := noxuDefinition.Spec.Names.Kind
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Version
name := "mytest"
rest := apiExtensionClient.Discovery().RESTClient()
yamlBody := []byte(fmt.Sprintf(`
apiVersion: %s
kind: %s
metadata:
name: %s
spec:
replicas: 1`, apiVersion, kind, name))
result, err := rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test").
Body(yamlBody).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("failed to create custom resource with apply: %v:\n%v", err, string(result))
}
verifyReplicas(t, result, 1)
// Patch object to change the number of replicas
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Body([]byte(`{"spec":{"replicas": 5}}`)).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("failed to update number of replicas with merge patch: %v:\n%v", err, string(result))
}
verifyReplicas(t, result, 5)
// Re-apply, we should get conflicts now, since the number of replicas was changed.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test").
Body(yamlBody).
DoRaw(context.TODO())
if err == nil {
t.Fatalf("Expecting to get conflicts when applying object after updating replicas, got no error: %s", result)
}
status, ok := err.(*apierrors.StatusError)
if !ok {
t.Fatalf("Expecting to get conflicts as API error")
}
if len(status.Status().Details.Causes) != 1 {
t.Fatalf("Expecting to get one conflict when applying object after updating replicas, got: %v", status.Status().Details.Causes)
}
// Re-apply with force, should work fine.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("force", "true").
Param("fieldManager", "apply_test").
Body(yamlBody).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("failed to apply object with force after updating replicas: %v:\n%v", err, string(result))
}
verifyReplicas(t, result, 1)
// Try to set managed fields using a subresource and verify that it has no effect
existingManagedFields, err := getManagedFields(result)
if err != nil {
t.Fatalf("failed to get managedFields from response: %v", err)
}
updateBytes := []byte(`{
"metadata": {
"managedFields": [{
"manager":"testing",
"operation":"Update",
"apiVersion":"v1",
"fieldsType":"FieldsV1",
"fieldsV1":{
"f:spec":{
"f:containers":{
"k:{\"name\":\"testing\"}":{
".":{},
"f:image":{},
"f:name":{}
}
}
}
}
}]
}
}`)
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
SubResource("status").
Name(name).
Param("fieldManager", "subresource_test").
Body(updateBytes).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("Error updating subresource: %v ", err)
}
newManagedFields, err := getManagedFields(result)
if err != nil {
t.Fatalf("failed to get managedFields from response: %v", err)
}
if !reflect.DeepEqual(existingManagedFields, newManagedFields) {
t.Fatalf("Expected managed fields to not have changed when trying manually settting them via subresoures.\n\nExpected: %#v\n\nGot: %#v", existingManagedFields, newManagedFields)
}
// However, it is possible to modify managed fields using the main resource
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "subresource_test").
Body([]byte(`{"metadata":{"managedFields":[{}]}}`)).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("Error updating managed fields of the main resource: %v ", err)
}
newManagedFields, err = getManagedFields(result)
if err != nil {
t.Fatalf("failed to get managedFields from response: %v", err)
}
if len(newManagedFields) != 0 {
t.Fatalf("Expected managed fields to have been reset, but got: %v", newManagedFields)
}
}
func nearlyRemovedBetaMultipleVersionNoxuCRD(scope apiextensionsv1beta1.ResourceScope) *apiextensionsv1beta1.CustomResourceDefinition {
return &apiextensionsv1beta1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Version: "v1beta1",
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: "noxus",
Singular: "nonenglishnoxu",
Kind: "WishIHadChosenNoxu",
ShortNames: []string{"foo", "bar", "abc", "def"},
ListKind: "NoxuItemList",
Categories: []string{"all"},
},
Scope: scope,
Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{
{
Name: "v1beta1",
Served: true,
Storage: false,
},
{
Name: "v1beta2",
Served: true,
Storage: true,
},
{
Name: "v0",
Served: false,
Storage: false,
},
},
Subresources: &apiextensionsv1beta1.CustomResourceSubresources{
Status: &apiextensionsv1beta1.CustomResourceSubresourceStatus{},
},
},
}
}

View File

@ -20,8 +20,18 @@ import (
"context"
"encoding/json"
"fmt"
"path"
"reflect"
"testing"
"time"
"k8s.io/apimachinery/pkg/util/wait"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"go.etcd.io/etcd/clientv3"
"go.etcd.io/etcd/pkg/transport"
"google.golang.org/grpc"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
@ -39,163 +49,6 @@ import (
"k8s.io/kubernetes/test/integration/framework"
)
// TestApplyCRDNoSchema tests that CRDs and CRs can both be applied to with a PATCH request with the apply content type
// when there is no validation field provided.
func TestApplyCRDNoSchema(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, true)()
server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), nil, framework.SharedEtcd())
if err != nil {
t.Fatal(err)
}
defer server.TearDownFn()
config := server.ClientConfig
apiExtensionClient, err := clientset.NewForConfig(config)
if err != nil {
t.Fatal(err)
}
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
t.Fatal(err)
}
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1beta1.ClusterScoped)
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
kind := noxuDefinition.Spec.Names.Kind
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Version
name := "mytest"
rest := apiExtensionClient.Discovery().RESTClient()
yamlBody := []byte(fmt.Sprintf(`
apiVersion: %s
kind: %s
metadata:
name: %s
spec:
replicas: 1`, apiVersion, kind, name))
result, err := rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test").
Body(yamlBody).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("failed to create custom resource with apply: %v:\n%v", err, string(result))
}
verifyReplicas(t, result, 1)
// Patch object to change the number of replicas
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Body([]byte(`{"spec":{"replicas": 5}}`)).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("failed to update number of replicas with merge patch: %v:\n%v", err, string(result))
}
verifyReplicas(t, result, 5)
// Re-apply, we should get conflicts now, since the number of replicas was changed.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test").
Body(yamlBody).
DoRaw(context.TODO())
if err == nil {
t.Fatalf("Expecting to get conflicts when applying object after updating replicas, got no error: %s", result)
}
status, ok := err.(*apierrors.StatusError)
if !ok {
t.Fatalf("Expecting to get conflicts as API error")
}
if len(status.Status().Details.Causes) != 1 {
t.Fatalf("Expecting to get one conflict when applying object after updating replicas, got: %v", status.Status().Details.Causes)
}
// Re-apply with force, should work fine.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("force", "true").
Param("fieldManager", "apply_test").
Body(yamlBody).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("failed to apply object with force after updating replicas: %v:\n%v", err, string(result))
}
verifyReplicas(t, result, 1)
// Try to set managed fields using a subresource and verify that it has no effect
existingManagedFields, err := getManagedFields(result)
if err != nil {
t.Fatalf("failed to get managedFields from response: %v", err)
}
updateBytes := []byte(`{
"metadata": {
"managedFields": [{
"manager":"testing",
"operation":"Update",
"apiVersion":"v1",
"fieldsType":"FieldsV1",
"fieldsV1":{
"f:spec":{
"f:containers":{
"k:{\"name\":\"testing\"}":{
".":{},
"f:image":{},
"f:name":{}
}
}
}
}
}]
}
}`)
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
SubResource("status").
Name(name).
Param("fieldManager", "subresource_test").
Body(updateBytes).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("Error updating subresource: %v ", err)
}
newManagedFields, err := getManagedFields(result)
if err != nil {
t.Fatalf("failed to get managedFields from response: %v", err)
}
if !reflect.DeepEqual(existingManagedFields, newManagedFields) {
t.Fatalf("Expected managed fields to not have changed when trying manually settting them via subresoures.\n\nExpected: %#v\n\nGot: %#v", existingManagedFields, newManagedFields)
}
// However, it is possible to modify managed fields using the main resource
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "subresource_test").
Body([]byte(`{"metadata":{"managedFields":[{}]}}`)).
DoRaw(context.TODO())
if err != nil {
t.Fatalf("Error updating managed fields of the main resource: %v ", err)
}
newManagedFields, err = getManagedFields(result)
if err != nil {
t.Fatalf("failed to get managedFields from response: %v", err)
}
if len(newManagedFields) != 0 {
t.Fatalf("Expected managed fields to have been reset, but got: %v", newManagedFields)
}
}
// TestApplyCRDStructuralSchema tests that when a CRD has a structural schema in its validation field,
// it will be used to construct the CR schema used by apply.
func TestApplyCRDStructuralSchema(t *testing.T) {
@ -217,9 +70,9 @@ func TestApplyCRDStructuralSchema(t *testing.T) {
t.Fatal(err)
}
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1beta1.ClusterScoped)
noxuDefinition := fixtures.NewMultipleVersionNoxuCRD(apiextensionsv1.ClusterScoped)
var c apiextensionsv1beta1.CustomResourceValidation
var c apiextensionsv1.CustomResourceValidation
err = json.Unmarshal([]byte(`{
"openAPIV3Schema": {
"type": "object",
@ -274,17 +127,17 @@ func TestApplyCRDStructuralSchema(t *testing.T) {
if err != nil {
t.Fatal(err)
}
noxuDefinition.Spec.Validation = &c
falseBool := false
noxuDefinition.Spec.PreserveUnknownFields = &falseBool
for i := range noxuDefinition.Spec.Versions {
noxuDefinition.Spec.Versions[i].Schema = &c
}
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
noxuDefinition, err = fixtures.CreateNewV1CustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatal(err)
}
kind := noxuDefinition.Spec.Names.Kind
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Version
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
name := "mytest"
rest := apiExtensionClient.Discovery().RESTClient()
@ -303,7 +156,7 @@ spec:
containerPort: 80
protocol: TCP`, apiVersion, kind, name))
result, err := rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test").
Body(yamlBody).
@ -318,7 +171,7 @@ spec:
// Patch object to add another finalizer to the finalizers list
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Body([]byte(`{"metadata":{"finalizers":["test-finalizer","another-one"]}}`)).
DoRaw(context.TODO())
@ -331,7 +184,7 @@ spec:
// Re-apply the same config, should work fine, since finalizers should have the list-type extension 'set'.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test").
SetHeader("Accept", "application/json").
@ -346,7 +199,7 @@ spec:
// Patch object to change the number of replicas
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Body([]byte(`{"spec":{"replicas": 5}}`)).
DoRaw(context.TODO())
@ -357,7 +210,7 @@ spec:
// Re-apply, we should get conflicts now, since the number of replicas was changed.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test").
Body(yamlBody).
@ -375,7 +228,7 @@ spec:
// Re-apply with force, should work fine.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("force", "true").
Param("fieldManager", "apply_test").
@ -388,7 +241,7 @@ spec:
// New applier tries to edit an existing list item, we should get conflicts.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test_2").
Body([]byte(fmt.Sprintf(`
@ -415,7 +268,7 @@ spec:
// New applier tries to add a new list item, should work fine.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test_2").
Body([]byte(fmt.Sprintf(`
@ -459,7 +312,7 @@ spec:
"protocol": "TCP"
}`, apiVersion, kind, "should-not-exist"))
_, err = rest.Put().
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name("should-not-exist").
Param("fieldManager", "apply_test").
Body(notExistingYAMLBody).
@ -552,12 +405,45 @@ func verifyNumPorts(t *testing.T, b []byte, n int) {
}
}
func findCRDCondition(crd *apiextensionsv1.CustomResourceDefinition, conditionType apiextensionsv1.CustomResourceDefinitionConditionType) *apiextensionsv1.CustomResourceDefinitionCondition {
for i := range crd.Status.Conditions {
if crd.Status.Conditions[i].Type == conditionType {
return &crd.Status.Conditions[i]
}
}
return nil
}
// TestApplyCRDUnhandledSchema tests that when a CRD has a schema that kube-openapi ToProtoModels cannot handle correctly,
// apply falls back to non-schema behavior
func TestApplyCRDUnhandledSchema(t *testing.T) {
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, genericfeatures.ServerSideApply, true)()
server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), nil, framework.SharedEtcd())
storageConfig := framework.SharedEtcd()
tlsInfo := transport.TLSInfo{
CertFile: storageConfig.Transport.CertFile,
KeyFile: storageConfig.Transport.KeyFile,
TrustedCAFile: storageConfig.Transport.TrustedCAFile,
}
tlsConfig, err := tlsInfo.ClientConfig()
if err != nil {
t.Fatal(err)
}
etcdConfig := clientv3.Config{
Endpoints: storageConfig.Transport.ServerList,
DialTimeout: 20 * time.Second,
DialOptions: []grpc.DialOption{
grpc.WithBlock(), // block until the underlying connection is up
},
TLS: tlsConfig,
}
etcdclient, err := clientv3.New(etcdConfig)
if err != nil {
t.Fatal(err)
}
server, err := apiservertesting.StartTestServer(t, apiservertesting.NewDefaultTestServerOptions(), nil, storageConfig)
if err != nil {
t.Fatal(err)
}
@ -568,12 +454,33 @@ func TestApplyCRDUnhandledSchema(t *testing.T) {
if err != nil {
t.Fatal(err)
}
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
t.Fatal(err)
}
noxuDefinition := fixtures.NewNoxuCustomResourceDefinition(apiextensionsv1beta1.ClusterScoped)
// this has to be v1beta1, so we can have an item with validation that does not match. v1 validation prevents this.
noxuBetaDefinition := &apiextensionsv1beta1.CustomResourceDefinition{
TypeMeta: metav1.TypeMeta{
Kind: "CustomResourceDefinition",
APIVersion: "apiextensions.k8s.io/v1beta1",
},
ObjectMeta: metav1.ObjectMeta{Name: "noxus.mygroup.example.com"},
Spec: apiextensionsv1beta1.CustomResourceDefinitionSpec{
Group: "mygroup.example.com",
Versions: []apiextensionsv1beta1.CustomResourceDefinitionVersion{{
Name: "v1beta1",
Served: true,
Storage: true,
}},
Names: apiextensionsv1beta1.CustomResourceDefinitionNames{
Plural: "noxus",
Singular: "nonenglishnoxu",
Kind: "WishIHadChosenNoxu",
ShortNames: []string{"foo", "bar", "abc", "def"},
ListKind: "NoxuItemList",
Categories: []string{"all"},
},
Scope: apiextensionsv1beta1.ClusterScoped,
},
}
// This is a schema that kube-openapi ToProtoModels does not handle correctly.
// https://github.com/kubernetes/kubernetes/blob/38752f7f99869ed65fb44378360a517649dc2f83/vendor/k8s.io/kube-openapi/pkg/util/proto/document.go#L184
@ -590,15 +497,44 @@ func TestApplyCRDUnhandledSchema(t *testing.T) {
if err != nil {
t.Fatal(err)
}
noxuDefinition.Spec.Validation = &c
noxuBetaDefinition.Spec.Validation = &c
noxuDefinition, err = fixtures.CreateNewCustomResourceDefinition(noxuDefinition, apiExtensionClient, dynamicClient)
betaBytes, err := json.Marshal(noxuBetaDefinition)
if err != nil {
t.Fatal(err)
}
t.Log(string(betaBytes))
ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), metav1.NamespaceNone)
key := path.Join("/", storageConfig.Prefix, "apiextensions.k8s.io", "customresourcedefinitions", noxuBetaDefinition.Name)
if _, err := etcdclient.Put(ctx, key, string(betaBytes)); err != nil {
t.Fatalf("unexpected error: %v", err)
}
noxuDefinition, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuBetaDefinition.Name, metav1.GetOptions{})
if err != nil {
t.Fatal(err)
}
// wait until the CRD is established
err = wait.Poll(100*time.Millisecond, 10*time.Second, func() (bool, error) {
localCrd, err := apiExtensionClient.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), noxuBetaDefinition.Name, metav1.GetOptions{})
if err != nil {
return false, err
}
condition := findCRDCondition(localCrd, apiextensionsv1.Established)
if condition == nil {
return false, nil
}
if condition.Status == apiextensionsv1.ConditionTrue {
return true, nil
}
return false, nil
})
if err != nil {
t.Fatal(err)
}
kind := noxuDefinition.Spec.Names.Kind
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Version
apiVersion := noxuDefinition.Spec.Group + "/" + noxuDefinition.Spec.Versions[0].Name
name := "mytest"
rest := apiExtensionClient.Discovery().RESTClient()
@ -610,7 +546,7 @@ metadata:
spec:
replicas: 1`, apiVersion, kind, name))
result, err := rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test").
Body(yamlBody).
@ -622,7 +558,7 @@ spec:
// Patch object to change the number of replicas
result, err = rest.Patch(types.MergePatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Body([]byte(`{"spec":{"replicas": 5}}`)).
DoRaw(context.TODO())
@ -633,7 +569,7 @@ spec:
// Re-apply, we should get conflicts now, since the number of replicas was changed.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("fieldManager", "apply_test").
Body(yamlBody).
@ -651,7 +587,7 @@ spec:
// Re-apply with force, should work fine.
result, err = rest.Patch(types.ApplyPatchType).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Version, noxuDefinition.Spec.Names.Plural).
AbsPath("/apis", noxuDefinition.Spec.Group, noxuDefinition.Spec.Versions[0].Name, noxuDefinition.Spec.Names.Plural).
Name(name).
Param("force", "true").
Param("fieldManager", "apply_test").

View File

@ -26,7 +26,7 @@ import (
"time"
v1 "k8s.io/api/core/v1"
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
apiextensionstestserver "k8s.io/apiextensions-apiserver/test/integration/fixtures"
apierrors "k8s.io/apimachinery/pkg/api/errors"
@ -136,11 +136,11 @@ func newOwnerRC(name, namespace string) *v1.ReplicationController {
}
}
func newCRDInstance(definition *apiextensionsv1beta1.CustomResourceDefinition, namespace, name string) *unstructured.Unstructured {
func newCRDInstance(definition *apiextensionsv1.CustomResourceDefinition, namespace, name string) *unstructured.Unstructured {
return &unstructured.Unstructured{
Object: map[string]interface{}{
"kind": definition.Spec.Names.Kind,
"apiVersion": definition.Spec.Group + "/" + definition.Spec.Version,
"apiVersion": definition.Spec.Group + "/" + definition.Spec.Versions[0].Name,
"metadata": map[string]interface{}{
"name": name,
"namespace": namespace,
@ -180,18 +180,18 @@ func createRandomCustomResourceDefinition(
t *testing.T, apiExtensionClient apiextensionsclientset.Interface,
dynamicClient dynamic.Interface,
namespace string,
) (*apiextensionsv1beta1.CustomResourceDefinition, dynamic.ResourceInterface) {
) (*apiextensionsv1.CustomResourceDefinition, dynamic.ResourceInterface) {
// Create a random custom resource definition and ensure it's available for
// use.
definition := apiextensionstestserver.NewRandomNameCustomResourceDefinition(apiextensionsv1beta1.NamespaceScoped)
definition := apiextensionstestserver.NewRandomNameV1CustomResourceDefinition(apiextensionsv1.NamespaceScoped)
definition, err := apiextensionstestserver.CreateNewCustomResourceDefinition(definition, apiExtensionClient, dynamicClient)
definition, err := apiextensionstestserver.CreateNewV1CustomResourceDefinition(definition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatalf("failed to create CustomResourceDefinition: %v", err)
}
// Get a client for the custom resource.
gvr := schema.GroupVersionResource{Group: definition.Spec.Group, Version: definition.Spec.Version, Resource: definition.Spec.Names.Plural}
gvr := schema.GroupVersionResource{Group: definition.Spec.Group, Version: definition.Spec.Versions[0].Name, Resource: definition.Spec.Names.Plural}
resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
@ -1230,14 +1230,14 @@ func TestCRDDeletionCascading(t *testing.T) {
t.Logf("Second pass CRD cascading deletion")
accessor := meta.NewAccessor()
accessor.SetResourceVersion(definition, "")
_, err := apiextensionstestserver.CreateNewCustomResourceDefinition(definition, apiExtensionClient, dynamicClient)
_, err := apiextensionstestserver.CreateNewV1CustomResourceDefinition(definition, apiExtensionClient, dynamicClient)
if err != nil {
t.Fatalf("failed to create CustomResourceDefinition: %v", err)
}
testCRDDeletion(t, ctx, ns, definition, resourceClient)
}
func testCRDDeletion(t *testing.T, ctx *testContext, ns *v1.Namespace, definition *apiextensionsv1beta1.CustomResourceDefinition, resourceClient dynamic.ResourceInterface) {
func testCRDDeletion(t *testing.T, ctx *testContext, ns *v1.Namespace, definition *apiextensionsv1.CustomResourceDefinition, resourceClient dynamic.ResourceInterface) {
clientSet, apiExtensionClient := ctx.clientSet, ctx.apiExtensionClient
configMapClient := clientSet.CoreV1().ConfigMaps(ns.Name)
@ -1261,7 +1261,7 @@ func testCRDDeletion(t *testing.T, ctx *testContext, ns *v1.Namespace, definitio
time.Sleep(ctx.syncPeriod + 5*time.Second)
// Delete the definition, which should cascade to the owner and ultimately its dependents.
if err := apiextensionstestserver.DeleteCustomResourceDefinition(definition, apiExtensionClient); err != nil {
if err := apiextensionstestserver.DeleteV1CustomResourceDefinition(definition, apiExtensionClient); err != nil {
t.Fatalf("failed to delete %q: %v", definition.Name, err)
}

View File

@ -89,12 +89,7 @@ func CreateMultiVersionTestCRD(f *framework.Framework, group string, opts ...Opt
Served: true,
Storage: true,
Name: "v1",
Schema: &apiextensionsv1.CustomResourceValidation{
OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
XPreserveUnknownFields: pointer.BoolPtr(true),
Type: "object",
},
},
Schema: fixtures.AllowAllSchema(),
}}
}