mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-08 03:33:56 +00:00
Merge pull request #47252 from sttts/sttts-crd-initializers
Automatic merge from submit-queue (batch tested with PRs 43443, 46193, 49071, 47252) custom-resources: add initializer test
This commit is contained in:
commit
06e3a00a14
@ -14,12 +14,15 @@ go_test(
|
|||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//vendor/k8s.io/api/admissionregistration/v1alpha1:go_default_library",
|
||||||
"//vendor/k8s.io/api/apps/v1beta1:go_default_library",
|
"//vendor/k8s.io/api/apps/v1beta1:go_default_library",
|
||||||
"//vendor/k8s.io/api/core/v1:go_default_library",
|
"//vendor/k8s.io/api/core/v1:go_default_library",
|
||||||
"//vendor/k8s.io/api/networking/v1:go_default_library",
|
"//vendor/k8s.io/api/networking/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
|
"//vendor/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
|
||||||
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
|
"//vendor/k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
"//vendor/k8s.io/client-go/dynamic:go_default_library",
|
||||||
|
@ -17,16 +17,20 @@ limitations under the License.
|
|||||||
package testing
|
package testing
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
admissionregistrationv1alpha1 "k8s.io/api/admissionregistration/v1alpha1"
|
||||||
appsv1beta1 "k8s.io/api/apps/v1beta1"
|
appsv1beta1 "k8s.io/api/apps/v1beta1"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
networkingv1 "k8s.io/api/networking/v1"
|
networkingv1 "k8s.io/api/networking/v1"
|
||||||
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||||
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
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/runtime/schema"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
"k8s.io/client-go/dynamic"
|
"k8s.io/client-go/dynamic"
|
||||||
@ -149,6 +153,11 @@ func TestCRD(t *testing.T) {
|
|||||||
config, tearDown := StartTestServerOrDie(t)
|
config, tearDown := StartTestServerOrDie(t)
|
||||||
defer tearDown()
|
defer tearDown()
|
||||||
|
|
||||||
|
kubeclient, err := kubernetes.NewForConfig(config)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
apiextensionsclient, err := apiextensionsclientset.NewForConfig(config)
|
apiextensionsclient, err := apiextensionsclientset.NewForConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Unexpected error: %v", err)
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
@ -193,6 +202,152 @@ func TestCRD(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Failed to list foos.cr.bar.com instances: %v", err)
|
t.Errorf("Failed to list foos.cr.bar.com instances: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t.Logf("Creating InitializerConfiguration")
|
||||||
|
_, err = kubeclient.AdmissionregistrationV1alpha1().InitializerConfigurations().Create(&admissionregistrationv1alpha1.InitializerConfiguration{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "foos.cr.bar.com",
|
||||||
|
},
|
||||||
|
Initializers: []admissionregistrationv1alpha1.Initializer{
|
||||||
|
{
|
||||||
|
Name: "cr.bar.com",
|
||||||
|
Rules: []admissionregistrationv1alpha1.Rule{
|
||||||
|
{
|
||||||
|
APIGroups: []string{"cr.bar.com"},
|
||||||
|
APIVersions: []string{"*"},
|
||||||
|
Resources: []string{"*"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed to create InitializerConfiguration: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO DO NOT MERGE THIS
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
|
t.Logf("Creating Foo instance")
|
||||||
|
foo := &Foo{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "cr.bar.com/v1",
|
||||||
|
Kind: "Foo",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
||||||
|
}
|
||||||
|
unstructuredFoo, err := unstructuredFoo(foo)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unable to create Foo: %v", err)
|
||||||
|
}
|
||||||
|
createErr := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
_, err = barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Create(unstructuredFoo)
|
||||||
|
t.Logf("Foo instance create returned: %v", err)
|
||||||
|
if err != nil {
|
||||||
|
createErr <- err
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = wait.PollImmediate(100*time.Millisecond, wait.ForeverTestTimeout, func() (bool, error) {
|
||||||
|
select {
|
||||||
|
case createErr := <-createErr:
|
||||||
|
return true, createErr
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Checking that Foo instance is visible with IncludeUninitialized=true")
|
||||||
|
_, err := barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Get(foo.ObjectMeta.Name, metav1.GetOptions{
|
||||||
|
IncludeUninitialized: true,
|
||||||
|
})
|
||||||
|
switch {
|
||||||
|
case err == nil:
|
||||||
|
return true, nil
|
||||||
|
case errors.IsNotFound(err):
|
||||||
|
return false, nil
|
||||||
|
default:
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Removing initializer from Foo instance")
|
||||||
|
success := false
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
// would love to replace the following with a patch, but removing strings from the intitializer array
|
||||||
|
// is not what JSON (Merge) patch authors had in mind.
|
||||||
|
fooUnstructured, err := barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Get(foo.ObjectMeta.Name, metav1.GetOptions{
|
||||||
|
IncludeUninitialized: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error getting Foo instance: %v", err)
|
||||||
|
}
|
||||||
|
bs, _ := fooUnstructured.MarshalJSON()
|
||||||
|
t.Logf("Got Foo instance: %v", string(bs))
|
||||||
|
foo := Foo{}
|
||||||
|
if err := json.Unmarshal(bs, &foo); err != nil {
|
||||||
|
t.Fatalf("Error parsing Foo instance: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove initialize
|
||||||
|
if foo.ObjectMeta.Initializers == nil {
|
||||||
|
t.Fatalf("Expected initializers to be set in Foo instance")
|
||||||
|
}
|
||||||
|
found := false
|
||||||
|
for i := range foo.ObjectMeta.Initializers.Pending {
|
||||||
|
if foo.ObjectMeta.Initializers.Pending[i].Name == "cr.bar.com" {
|
||||||
|
foo.ObjectMeta.Initializers.Pending = append(foo.ObjectMeta.Initializers.Pending[:i], foo.ObjectMeta.Initializers.Pending[i+1:]...)
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Fatalf("Expected cr.bar.com as initializer on Foo instance")
|
||||||
|
}
|
||||||
|
if len(foo.ObjectMeta.Initializers.Pending) == 0 && foo.ObjectMeta.Initializers.Result == nil {
|
||||||
|
foo.ObjectMeta.Initializers = nil
|
||||||
|
}
|
||||||
|
bs, err = json.Marshal(&foo)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
fooUnstructured.UnmarshalJSON(bs)
|
||||||
|
|
||||||
|
_, err = barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Update(fooUnstructured)
|
||||||
|
if err != nil && !errors.IsConflict(err) {
|
||||||
|
t.Fatalf("Failed to update Foo instance: %v", err)
|
||||||
|
} else if err == nil {
|
||||||
|
success = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !success {
|
||||||
|
t.Fatalf("Failed to remove initializer from Foo object")
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Logf("Checking that Foo instance is visible after removing the initializer")
|
||||||
|
if _, err := barComClient.Resource(&metav1.APIResource{Name: "foos", Namespaced: true}, "default").Get(foo.ObjectMeta.Name, metav1.GetOptions{}); err != nil {
|
||||||
|
t.Errorf("Unexpected error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Foo struct {
|
||||||
|
metav1.TypeMeta `json:",inline"`
|
||||||
|
metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func unstructuredFoo(foo *Foo) (*unstructured.Unstructured, error) {
|
||||||
|
bs, err := json.Marshal(foo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ret := &unstructured.Unstructured{}
|
||||||
|
if err = ret.UnmarshalJSON(bs); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForEstablishedCRD(client apiextensionsclientset.Interface, name string) error {
|
func waitForEstablishedCRD(client apiextensionsclientset.Interface, name string) error {
|
||||||
|
@ -79,6 +79,7 @@ func StartTestServer(t *testing.T) (result *restclient.Config, tearDownForCaller
|
|||||||
s.Etcd.StorageConfig = *storageConfig
|
s.Etcd.StorageConfig = *storageConfig
|
||||||
s.Etcd.DefaultStorageMediaType = "application/json"
|
s.Etcd.DefaultStorageMediaType = "application/json"
|
||||||
s.Admission.PluginNames = strings.Split("Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds", ",")
|
s.Admission.PluginNames = strings.Split("Initializers,NamespaceLifecycle,LimitRanger,ServiceAccount,PersistentVolumeLabel,DefaultStorageClass,ResourceQuota,DefaultTolerationSeconds", ",")
|
||||||
|
s.APIEnablement.RuntimeConfig.Set("api/all=true")
|
||||||
|
|
||||||
t.Logf("Starting kube-apiserver...")
|
t.Logf("Starting kube-apiserver...")
|
||||||
runErrCh := make(chan error, 1)
|
runErrCh := make(chan error, 1)
|
||||||
|
Loading…
Reference in New Issue
Block a user