mirror of
https://github.com/cozystack/cozystack.git
synced 2026-10-28 15:47:33 +09:00
Drop a local kubeconfig that was committed by accident alongside the console sources and ignore the filename so it cannot come back. Replace environment-specific values in the vSphere migration fixtures with synthetic ones: the tests only care about the shape of the inventory record, not where it was captured. Assisted-by: LLM Signed-off-by: Aleksei Sviridkin <f@lex.la>
112 lines
4.5 KiB
Go
112 lines
4.5 KiB
Go
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package migrationcontroller
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
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/types"
|
|
"k8s.io/client-go/tools/record"
|
|
clientfake "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
|
|
|
migrationv1alpha1 "github.com/cozystack/cozystack/api/migration/v1alpha1"
|
|
)
|
|
|
|
// hostOverride builds the Host and Secret pair the controller creates for one
|
|
// entry, as an earlier reconcile would have left them.
|
|
func hostOverride(src *migrationv1alpha1.VMImportSource, id string) (*unstructured.Unstructured, *corev1.Secret) {
|
|
name := hostOverrideName(src.Name, id)
|
|
owner := ownerRef(migrationv1alpha1.GroupVersion.WithKind("VMImportSource"), src.Name, src.UID)
|
|
|
|
host := newObject(hostGVK)
|
|
host.SetName(name)
|
|
host.SetNamespace(src.Namespace)
|
|
host.SetLabels(map[string]string{migrationv1alpha1.ManagedByLabel: migrationv1alpha1.ManagedByValue})
|
|
host.SetOwnerReferences([]metav1.OwnerReference{owner})
|
|
|
|
secret := &corev1.Secret{ObjectMeta: metav1.ObjectMeta{
|
|
Name: name,
|
|
Namespace: src.Namespace,
|
|
Labels: map[string]string{migrationv1alpha1.ManagedByLabel: migrationv1alpha1.ManagedByValue},
|
|
OwnerReferences: []metav1.OwnerReference{owner},
|
|
}}
|
|
return host, secret
|
|
}
|
|
|
|
// A Source is editable, so an override can be dropped after it was created. A
|
|
// Host left behind is not inert — Forklift keeps routing that ESXi host's
|
|
// transfers through the address it names — and its credentials would otherwise
|
|
// outlive the decision to stop using them.
|
|
func TestEditingASourceRemovesTheHostsItNoLongerLists(t *testing.T) {
|
|
s := testScheme(t)
|
|
src := vsphereSource("vcenter", "tenant-foo")
|
|
src.Spec.Hosts = []migrationv1alpha1.HostOverride{{
|
|
ID: "host-10",
|
|
Address: "192.0.2.29",
|
|
Credentials: migrationv1alpha1.ProviderCredentials{
|
|
Username: "root", Password: "x", InsecureSkipVerify: true,
|
|
},
|
|
}}
|
|
|
|
keptHost, keptSecret := hostOverride(src, "host-10")
|
|
goneHost, goneSecret := hostOverride(src, "host-99")
|
|
|
|
c := clientfake.NewClientBuilder().WithScheme(s).
|
|
WithObjects(src, keptHost, keptSecret, goneHost, goneSecret).Build()
|
|
r := &VMImportSourceReconciler{Client: c, Scheme: s, Recorder: record.NewFakeRecorder(10)}
|
|
|
|
if err := r.pruneHosts(context.Background(), src); err != nil {
|
|
t.Fatalf("pruneHosts: %v", err)
|
|
}
|
|
|
|
gone := types.NamespacedName{Namespace: "tenant-foo", Name: hostOverrideName("vcenter", "host-99")}
|
|
if err := c.Get(context.Background(), gone, newObject(hostGVK)); !apierrors.IsNotFound(err) {
|
|
t.Errorf("the dropped Host survived (err %v); it would keep redirecting transfers", err)
|
|
}
|
|
if err := c.Get(context.Background(), gone, &corev1.Secret{}); !apierrors.IsNotFound(err) {
|
|
t.Errorf("the dropped Host's credentials survived (err %v)", err)
|
|
}
|
|
|
|
kept := types.NamespacedName{Namespace: "tenant-foo", Name: hostOverrideName("vcenter", "host-10")}
|
|
if err := c.Get(context.Background(), kept, newObject(hostGVK)); err != nil {
|
|
t.Errorf("the still-listed Host was removed: %v", err)
|
|
}
|
|
if err := c.Get(context.Background(), kept, &corev1.Secret{}); err != nil {
|
|
t.Errorf("the still-listed Host's credentials were removed: %v", err)
|
|
}
|
|
}
|
|
|
|
// The label says this controller made the object, not that it made it for this
|
|
// Source. Two Sources in one namespace must not delete each other's Hosts.
|
|
func TestPruningLeavesAnotherSourcesHostsAlone(t *testing.T) {
|
|
s := testScheme(t)
|
|
mine := vsphereSource("vcenter", "tenant-foo")
|
|
theirs := vsphereSource("other", "tenant-foo")
|
|
theirs.UID = types.UID("other-uid")
|
|
|
|
theirHost, theirSecret := hostOverride(theirs, "host-10")
|
|
|
|
c := clientfake.NewClientBuilder().WithScheme(s).
|
|
WithObjects(mine, theirs, theirHost, theirSecret).Build()
|
|
r := &VMImportSourceReconciler{Client: c, Scheme: s, Recorder: record.NewFakeRecorder(10)}
|
|
|
|
// `mine` lists no hosts at all, so an ownership-blind prune would take the
|
|
// other Source's Host with it.
|
|
if err := r.pruneHosts(context.Background(), mine); err != nil {
|
|
t.Fatalf("pruneHosts: %v", err)
|
|
}
|
|
|
|
name := types.NamespacedName{Namespace: "tenant-foo", Name: hostOverrideName("other", "host-10")}
|
|
if err := c.Get(context.Background(), name, newObject(hostGVK)); err != nil {
|
|
t.Errorf("another Source's Host was deleted: %v", err)
|
|
}
|
|
if err := c.Get(context.Background(), name, &corev1.Secret{}); err != nil {
|
|
t.Errorf("another Source's credentials were deleted: %v", err)
|
|
}
|
|
}
|