Files
velero/pkg/restore/prioritize_group_version_test.go
codegold79 6bdd4ac192 Restore API group version by priority (#3133)
* Restore API group version by priority

Signed-off-by: F. Gold <fgold@vmware.com>

* Add changelog

Signed-off-by: F. Gold <fgold@vmware.com>

* Correct spelling

Signed-off-by: F. Gold <fgold@vmware.com>

* Refactor userResourceGroupVersionPriorities(...) to accept config map, adjust unit test

Signed-off-by: F. Gold <fgold@vmware.com>

* Move some unit tests into e2e

Signed-off-by: F. Gold <fgold@vmware.com>

* Add three e2e tests using Testify Suites

Summary of changes

Makefile - add testify e2e test target
go.sum - changed with go mod tidy
pkg/install/install.go - increased polling timeout
test/e2e/restore_priority_group_test.go - deleted
test/e2e/restore_test.go - deleted
test/e2e/velero_utils.go - made restic optional in velero install
test/e2e_testify/Makefile - makefile for testify e2e tests
test/e2e_testify/README.md - example command for running tests
test/e2e_testify/common_test.go - helper functions
test/e2e_testify/e2e_suite_test.go - prepare for tests and run
test/e2e_testify/restore_priority_apigv_test.go - test cases

Signed-off-by: F. Gold <fgold@vmware.com>

* Make changes per @nrb code review

Signed-off-by: F. Gold <fgold@vmware.com>

* Wait for pods in e2e tests

Signed-off-by: F. Gold <fgold@vmware.com>

* Remove testify suites e2e scaffolding moved to PR #3354

Signed-off-by: F. Gold <fgold@vmware.com>

* Make changes per @brito-rafa and Velero maintainers code reviews

- Made changes suggested by @brito-rafa in GitHub.
- We had a code review meeting with @carlisia, @dsu-igeek, @zubron, and @nrb
- and changes were made based on their suggetions:
  - pull in logic from 'meetsAPIGVResotreReqs()' to restore.go.
  - add TODO to remove APIGroupVersionFeatureFlag check
  - have feature flag and backup version format checks in separate `if` statements.
  - rename variables to be sourceGVs, targetGVs, and userGVs.

Signed-off-by: F. Gold <fgold@vmware.com>

* Convert Testify Suites e2e tests to existing Ginkgo framework

Signed-off-by: F. Gold <fgold@vmware.com>

* Made changes per @zubron PR review

Signed-off-by: F. Gold <fgold@vmware.com>

* Run go mod tidy after resolving go.sum merge conflict

Signed-off-by: F. Gold <fgold@vmware.com>

* Add feature documentation to velero.io site

Signed-off-by: F. Gold <fgold@vmware.com>

* Add config map e2e test; rename e2e test file and name

Signed-off-by: F. Gold <fgold@vmware.com>

* Update go.{mod,sum} files

Signed-off-by: F. Gold <fgold@vmware.com>

* Move CRDs and CRs to testdata folder

Signed-off-by: F. Gold <fgold@vmware.com>

* Fix typos in cert-manager to pass codespell CICD check

Signed-off-by: F. Gold <fgold@vmware.com>

* Make changes per @nrb code review round 2

- make checkAndReadDir function private
- add info level messages when priorties 1-3 API group versions can not be used

Signed-off-by: F. Gold <fgold@vmware.com>

* Make user config map rules less strict

Signed-off-by: F. Gold <fgold@vmware.com>

* Update e2e test image version in example

Signed-off-by: F. Gold <fgold@vmware.com>

* Update case A music-system controller code

Signed-off-by: F. Gold <fgold@vmware.com>

* Documentation updates

Signed-off-by: F. Gold <fgold@vmware.com>

* Update migration case documentation

Signed-off-by: F. Gold <fgold@vmware.com>
2021-02-16 12:36:17 -05:00

375 lines
9.3 KiB
Go

/*
Copyright The Velero Contributors.
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 restore
import (
"testing"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/vmware-tanzu/velero/pkg/builder"
"github.com/vmware-tanzu/velero/pkg/test"
)
func TestK8sPrioritySort(t *testing.T) {
tests := []struct {
name string
orig []metav1.GroupVersionForDiscovery
want []metav1.GroupVersionForDiscovery
}{
{
name: "sorts Kubernetes API group versions per k8s priority",
orig: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
{Version: "v11alpha2"},
{Version: "foo10"},
{Version: "v10"},
{Version: "v12alpha1"},
{Version: "v3beta1"},
{Version: "foo1"},
{Version: "v1"},
{Version: "v10beta3"},
{Version: "v11beta2"},
},
want: []metav1.GroupVersionForDiscovery{
{Version: "v10"},
{Version: "v2"},
{Version: "v1"},
{Version: "v11beta2"},
{Version: "v10beta3"},
{Version: "v3beta1"},
{Version: "v12alpha1"},
{Version: "v11alpha2"},
{Version: "foo1"},
{Version: "foo10"},
},
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
k8sPrioritySort(tc.orig)
assert.Equal(t, tc.want, tc.orig)
})
}
}
func TestUserResourceGroupVersionPriorities(t *testing.T) {
tests := []struct {
name string
cm *corev1.ConfigMap
want map[string]metav1.APIGroup
wantErrMsg string
}{
{
name: "retrieve version priority data from config map",
cm: builder.
ForConfigMap("velero", "enableapigroupversions").
Data(
"restoreResourcesVersionPriority",
`rockbands.music.example.io=v2beta1,v2beta2
orchestras.music.example.io=v2,v3alpha1
subscriptions.operators.coreos.com=v2,v1`,
).
Result(),
want: map[string]metav1.APIGroup{
"rockbands.music.example.io": {Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2beta1"},
{Version: "v2beta2"},
}},
"orchestras.music.example.io": {Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
{Version: "v3alpha1"},
}},
"subscriptions.operators.coreos.com": {Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
{Version: "v1"},
}},
},
},
{
name: "incorrect data format returns an error",
cm: builder.
ForConfigMap("velero", "enableapigroupversions").
Data(
"restoreResourcesVersionPriority",
`rockbands.music.example.io=v2beta1,v2beta2\n orchestras.music.example.io=v2,v3alpha1`,
).
Result(),
want: nil,
wantErrMsg: "parsing user priorities: validating user priority: line must have one and only one equal sign",
},
{
name: "spaces and empty lines are removed before storing user version priorities",
cm: builder.
ForConfigMap("velero", "enableapigroupversions").
Data(
"restoreResourcesVersionPriority",
` pods=v2,v1beta2
horizontalpodautoscalers.autoscaling = v2beta2
jobs.batch=v3
`,
).
Result(),
want: map[string]metav1.APIGroup{
"pods": {Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
{Version: "v1beta2"},
}},
"horizontalpodautoscalers.autoscaling": {Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2beta2"},
}},
"jobs.batch": {Versions: []metav1.GroupVersionForDiscovery{
{Version: "v3"},
}},
},
},
}
fakeCtx := &restoreContext{
log: test.NewLogger(),
}
for _, tc := range tests {
t.Log(tc.name)
priorities := userResourceGroupVersionPriorities(fakeCtx, tc.cm)
assert.Equal(t, tc.want, priorities)
}
}
func TestFindAPIGroup(t *testing.T) {
tests := []struct {
name string
targetGrps []metav1.APIGroup
grpName string
want metav1.APIGroup
}{
{
name: "return the API Group in target list matching group string",
targetGrps: []metav1.APIGroup{
{
Name: "rbac.authorization.k8s.io",
Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v2"},
},
{
Name: "",
Versions: []metav1.GroupVersionForDiscovery{
{Version: "v1"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
},
{
Name: "velero.io",
Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2beta1"},
{Version: "v2beta2"},
{Version: "v2"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v2"},
},
},
grpName: "velero.io",
want: metav1.APIGroup{
Name: "velero.io",
Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2beta1"},
{Version: "v2beta2"},
{Version: "v2"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v2"},
},
},
{
name: "return empty API Group if no match in target list",
targetGrps: []metav1.APIGroup{
{
Name: "rbac.authorization.k8s.io",
Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v2"},
},
{
Name: "",
Versions: []metav1.GroupVersionForDiscovery{
{Version: "v1"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v1"},
},
{
Name: "velero.io",
Versions: []metav1.GroupVersionForDiscovery{
{Version: "v2beta1"},
{Version: "v2beta2"},
{Version: "v2"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{Version: "v2"},
},
},
grpName: "autoscaling",
want: metav1.APIGroup{},
},
}
for _, tc := range tests {
grp := findAPIGroup(tc.targetGrps, tc.grpName)
assert.Equal(t, tc.want, grp)
}
}
func TestFindSupportedUserVersion(t *testing.T) {
tests := []struct {
name string
userGVs []metav1.GroupVersionForDiscovery
targetGVs []metav1.GroupVersionForDiscovery
sourceGVs []metav1.GroupVersionForDiscovery
want string
}{
{
name: "return the single user group version that has a match in both source and target clusters",
userGVs: []metav1.GroupVersionForDiscovery{
{Version: "foo"},
{Version: "v10alpha2"},
{Version: "v3"},
},
targetGVs: []metav1.GroupVersionForDiscovery{
{Version: "v9"},
{Version: "v10beta1"},
{Version: "v10alpha2"},
{Version: "v10alpha3"},
},
sourceGVs: []metav1.GroupVersionForDiscovery{
{Version: "v10alpha2"},
{Version: "v9beta1"},
},
want: "v10alpha2",
},
{
name: "return the first user group version that has a match in both source and target clusters",
userGVs: []metav1.GroupVersionForDiscovery{
{Version: "v2beta1"},
{Version: "v2beta2"},
},
targetGVs: []metav1.GroupVersionForDiscovery{
{Version: "v2beta2"},
{Version: "v2beta1"},
},
sourceGVs: []metav1.GroupVersionForDiscovery{
{Version: "v1"},
{Version: "v2beta2"},
{Version: "v2beta1"},
},
want: "v2beta1",
},
{
name: "return empty string if there's only matches in the source cluster, but not target",
userGVs: []metav1.GroupVersionForDiscovery{
{Version: "v1"},
},
targetGVs: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
},
sourceGVs: []metav1.GroupVersionForDiscovery{
{Version: "v1"},
},
want: "",
},
{
name: "return empty string if there's only matches in the target cluster, but not source",
userGVs: []metav1.GroupVersionForDiscovery{
{Version: "v3"},
{Version: "v1"},
},
targetGVs: []metav1.GroupVersionForDiscovery{
{Version: "v3"},
{Version: "v3beta2"},
},
sourceGVs: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
{Version: "v2beta1"},
},
want: "",
},
{
name: "return empty string if there is no match with either target and source clusters",
userGVs: []metav1.GroupVersionForDiscovery{
{Version: "v2beta2"},
{Version: "v2beta1"},
{Version: "v2beta3"},
},
targetGVs: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
{Version: "v1"},
{Version: "v2alpha1"},
},
sourceGVs: []metav1.GroupVersionForDiscovery{
{Version: "v1"},
{Version: "v2alpha1"},
},
want: "",
},
}
for _, tc := range tests {
uv := findSupportedUserVersion(tc.userGVs, tc.targetGVs, tc.sourceGVs)
assert.Equal(t, tc.want, uv)
}
}
func TestVersionsContain(t *testing.T) {
tests := []struct {
name string
GVs []metav1.GroupVersionForDiscovery
ver string
want bool
}{
{
name: "version is not in list",
GVs: []metav1.GroupVersionForDiscovery{
{Version: "v1"},
{Version: "v2alpha1"},
{Version: "v2beta1"},
},
ver: "v2",
want: false,
},
{
name: "version is in list",
GVs: []metav1.GroupVersionForDiscovery{
{Version: "v2"},
{Version: "v2alpha1"},
{Version: "v2beta1"},
},
ver: "v2",
want: true,
},
}
for _, tc := range tests {
assert.Equal(t, tc.want, versionsContain(tc.GVs, tc.ver))
}
}