mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 03:41:45 +00:00
apiextensions: add conversion pruning tests
This commit is contained in:
parent
26366255fc
commit
33e95bc185
@ -28,6 +28,7 @@ go_test(
|
|||||||
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
|
"//staging/src/k8s.io/client-go/dynamic:go_default_library",
|
||||||
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
||||||
"//vendor/github.com/google/go-cmp/cmp:go_default_library",
|
"//vendor/github.com/google/go-cmp/cmp:go_default_library",
|
||||||
|
"//vendor/k8s.io/utils/pointer:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ func testWebhookConverter(t *testing.T, pruning bool) {
|
|||||||
{
|
{
|
||||||
group: "nontrivial-converter",
|
group: "nontrivial-converter",
|
||||||
handler: NewObjectConverterWebhookHandler(t, nontrivialConverter),
|
handler: NewObjectConverterWebhookHandler(t, nontrivialConverter),
|
||||||
checks: checks(validateStorageVersion, validateServed, validateMixedStorageVersions("v1alpha1", "v1beta1", "v1beta2"), validateNonTrivialConverted, validateNonTrivialConvertedList),
|
checks: checks(validateStorageVersion, validateServed, validateMixedStorageVersions("v1alpha1", "v1beta1", "v1beta2"), validateNonTrivialConverted, validateNonTrivialConvertedList, validateStoragePruning),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
group: "empty-response",
|
group: "empty-response",
|
||||||
@ -275,10 +275,24 @@ func validateNonTrivialConverted(t *testing.T, ctc *conversionTestContext) {
|
|||||||
t.Run(fmt.Sprintf("getting objects created as %s", createVersion.Name), func(t *testing.T) {
|
t.Run(fmt.Sprintf("getting objects created as %s", createVersion.Name), func(t *testing.T) {
|
||||||
name := "converted-" + createVersion.Name
|
name := "converted-" + createVersion.Name
|
||||||
client := ctc.versionedClient(ns, createVersion.Name)
|
client := ctc.versionedClient(ns, createVersion.Name)
|
||||||
if _, err := client.Create(newConversionMultiVersionFixture(ns, name, createVersion.Name), metav1.CreateOptions{}); err != nil {
|
|
||||||
|
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 := client.Create(fixture, metav1.CreateOptions{}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// verify that the right, pruned version is in storage
|
||||||
|
obj, err := ctc.etcdObjectReader.GetStoredCustomResource(ns, name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
verifyMultiVersionObject(t, "v1beta1", obj)
|
||||||
|
|
||||||
for _, getVersion := range ctc.crd.Spec.Versions {
|
for _, getVersion := range ctc.crd.Spec.Versions {
|
||||||
client := ctc.versionedClient(ns, getVersion.Name)
|
client := ctc.versionedClient(ns, getVersion.Name)
|
||||||
obj, err := client.Get(name, metav1.GetOptions{})
|
obj, err := client.Get(name, metav1.GetOptions{})
|
||||||
@ -298,7 +312,14 @@ func validateNonTrivialConvertedList(t *testing.T, ctc *conversionTestContext) {
|
|||||||
for _, createVersion := range ctc.crd.Spec.Versions {
|
for _, createVersion := range ctc.crd.Spec.Versions {
|
||||||
name := "converted-" + createVersion.Name
|
name := "converted-" + createVersion.Name
|
||||||
client := ctc.versionedClient(ns, createVersion.Name)
|
client := ctc.versionedClient(ns, createVersion.Name)
|
||||||
if _, err := client.Create(newConversionMultiVersionFixture(ns, name, createVersion.Name), metav1.CreateOptions{}); err != nil {
|
fixture := newConversionMultiVersionFixture(ns, name, createVersion.Name)
|
||||||
|
if !*ctc.crd.Spec.PreserveUnknownFields {
|
||||||
|
if err := unstructured.SetNestedField(fixture.Object, "foo", "garbage"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_, err := client.Create(fixture, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
names.Insert(name)
|
names.Insert(name)
|
||||||
@ -326,6 +347,67 @@ 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 {
|
||||||
|
t.Run(fmt.Sprintf("getting objects created as %s", createVersion.Name), func(t *testing.T) {
|
||||||
|
name := "storagepruning-" + createVersion.Name
|
||||||
|
client := ctc.versionedClient(ns, createVersion.Name)
|
||||||
|
|
||||||
|
fixture := newConversionMultiVersionFixture(ns, name, createVersion.Name)
|
||||||
|
if err := unstructured.SetNestedField(fixture.Object, "foo", "garbage"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
_, err := client.Create(fixture, metav1.CreateOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// verify that the right, pruned version is in storage
|
||||||
|
obj, err := ctc.etcdObjectReader.GetStoredCustomResource(ns, name)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
verifyMultiVersionObject(t, "v1beta1", obj)
|
||||||
|
|
||||||
|
// add garbage and set a label
|
||||||
|
if err := unstructured.SetNestedField(obj.Object, "foo", "garbage"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
labels := obj.GetLabels()
|
||||||
|
if labels == nil {
|
||||||
|
labels = map[string]string{}
|
||||||
|
}
|
||||||
|
labels["mutated"] = "true"
|
||||||
|
obj.SetLabels(labels)
|
||||||
|
if err := ctc.etcdObjectReader.SetStoredCustomResource(ns, name, obj); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, getVersion := range ctc.crd.Spec.Versions {
|
||||||
|
client := ctc.versionedClient(ns, getVersion.Name)
|
||||||
|
obj, err := client.Get(name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// check that the direct mutation in etcd worked
|
||||||
|
labels := obj.GetLabels()
|
||||||
|
if labels["mutated"] != "true" {
|
||||||
|
t.Errorf("expected object %s in version %s to have label 'mutated=true'", name, getVersion.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyMultiVersionObject(t, getVersion.Name, obj)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func expectConversionFailureMessage(id, message string) func(t *testing.T, ctc *conversionTestContext) {
|
func expectConversionFailureMessage(id, message string) func(t *testing.T, ctc *conversionTestContext) {
|
||||||
return func(t *testing.T, ctc *conversionTestContext) {
|
return func(t *testing.T, ctc *conversionTestContext) {
|
||||||
ns := ctc.namespace
|
ns := ctc.namespace
|
||||||
@ -763,11 +845,11 @@ func verifyMultiVersionObject(t *testing.T, v string, obj *unstructured.Unstruct
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete(j, "metadata")
|
delete(j, "metadata")
|
||||||
delete(j, "apiVersion")
|
|
||||||
delete(j, "kind")
|
|
||||||
|
|
||||||
var expected = map[string]map[string]interface{}{
|
var expected = map[string]map[string]interface{}{
|
||||||
"v1alpha1": {
|
"v1alpha1": {
|
||||||
|
"apiVersion": "stable.example.com/v1alpha1",
|
||||||
|
"kind": "MultiVersion",
|
||||||
"content": map[string]interface{}{
|
"content": map[string]interface{}{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
@ -777,6 +859,8 @@ func verifyMultiVersionObject(t *testing.T, v string, obj *unstructured.Unstruct
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"v1beta1": {
|
"v1beta1": {
|
||||||
|
"apiVersion": "stable.example.com/v1beta1",
|
||||||
|
"kind": "MultiVersion",
|
||||||
"content": map[string]interface{}{
|
"content": map[string]interface{}{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
@ -786,6 +870,8 @@ func verifyMultiVersionObject(t *testing.T, v string, obj *unstructured.Unstruct
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"v1beta2": {
|
"v1beta2": {
|
||||||
|
"apiVersion": "stable.example.com/v1beta2",
|
||||||
|
"kind": "MultiVersion",
|
||||||
"contentv2": map[string]interface{}{
|
"contentv2": map[string]interface{}{
|
||||||
"key": "value",
|
"key": "value",
|
||||||
},
|
},
|
||||||
|
@ -84,6 +84,20 @@ func (s *EtcdObjectReader) GetStoredCustomResource(ns, name string) (*unstructur
|
|||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetStoredCustomResource writes the storage representation of a custom resource to etcd.
|
||||||
|
func (s *EtcdObjectReader) SetStoredCustomResource(ns, name string, obj *unstructured.Unstructured) error {
|
||||||
|
bs, err := obj.MarshalJSON()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
key := path.Join("/", s.storagePrefix, s.crd.Spec.Group, s.crd.Spec.Names.Plural, ns, name)
|
||||||
|
if _, err := s.etcdClient.KV.Put(context.Background(), key, string(bs)); err != nil {
|
||||||
|
return fmt.Errorf("error setting storage object %s, %s from etcd at key %s: %v", ns, name, key, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetEtcdClients returns an initialized clientv3.Client and clientv3.KV.
|
// GetEtcdClients returns an initialized clientv3.Client and clientv3.KV.
|
||||||
func GetEtcdClients(config storagebackend.TransportConfig) (*clientv3.Client, clientv3.KV, error) {
|
func GetEtcdClients(config storagebackend.TransportConfig) (*clientv3.Client, clientv3.KV, error) {
|
||||||
tlsInfo := transport.TLSInfo{
|
tlsInfo := transport.TLSInfo{
|
||||||
|
Loading…
Reference in New Issue
Block a user