Skip to content

Instantly share code, notes, and snippets.

@akutz
Last active September 30, 2019 21:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akutz/e393502b093ed8485861ede6b0799df7 to your computer and use it in GitHub Desktop.
Save akutz/e393502b093ed8485861ede6b0799df7 to your computer and use it in GitHub Desktop.
package controllers_test
import (
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
clusterv1 "sigs.k8s.io/cluster-api/api/v1alpha2"
"sigs.k8s.io/controller-runtime/pkg/client"
infrav1 "sigs.k8s.io/cluster-api-provider-vsphere/v1alpha2"
)
const (
namespace = "default"
)
type runtimeObject interface {
runtime.Object
GetName() string
GetNamespace() string
GetOwnerReferences() []metav1.OwnerReference
}
// The spec conformance tests assert that the infrastructure types
// can be submitted to the API server without any errors.
var _ = Describe("Spec conformance tests", func() {
var (
obj runtimeObject
key *client.ObjectKey
)
assertObjEventuallyExists := func() {
EventuallyWithOffset(1, func() bool {
if err := k8sClient.Get(ctx, *key, obj); err != nil {
return false
}
return true
}, time.Second*30).Should(BeTrue())
}
JustBeforeEach(func() {
Expect(k8sClient.Create(ctx, obj)).ToNot(HaveOccurred())
key = &client.ObjectKey{
Namespace: obj.GetNamespace(),
Name: obj.GetName(),
}
})
JustAfterEach(func() {
Expect(k8sClient.Delete(ctx, obj)).ShouldNot(HaveOccurred())
})
AfterEach(func() {
obj = nil
key = nil
})
Context("VSphereCluster", func() {
BeforeEach(func() {
obj = &infrav1.VSphereCluster{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-",
Namespace: namespace,
},
Spec: infrav1.VSphereClusterSpec{},
}
})
It("Will be created and wait on an OwnerRef", func() {
assertObjEventuallyExists()
})
})
Context("VSphereMachine", func() {
BeforeEach(func() {
obj = &infrav1.VSphereMachine{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-",
Namespace: namespace,
},
Spec: infrav1.VSphereMachineSpec{},
}
})
It("Will be created and wait on an OwnerRef", func() {
assertObjEventuallyExists()
})
})
})
type canDeleteAndWait interface {
runtime.Object
SetFinalizers(finalizers []string)
}
// Verifies that the infrastructure types have finalizers set when an OwnerRef
// is set that points to the corresponding CAPI resource.
var _ = Describe("Reconciler tests", func() {
Specify("Infrastructure resources should have finalizers after reconciliation", func() {
// Create the CAPI Cluster and wait for it to exist.
//
// A finalizer is added to prevent it from being deleted until its
// dependents are removed.
cluster := &clusterv1.Cluster{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-",
Namespace: namespace,
Finalizers: []string{"test"},
},
Spec: clusterv1.ClusterSpec{},
}
Expect(k8sClient.Create(ctx, cluster)).ShouldNot(HaveOccurred())
clusterKey := client.ObjectKey{Namespace: cluster.Namespace, Name: cluster.Name}
Eventually(func() error {
return k8sClient.Get(ctx, clusterKey, cluster)
}, time.Second*30).ShouldNot(HaveOccurred())
// Create the infrastructure cluster and wait for it to have a
// finalizer.
infraCluster := &infrav1.VSphereCluster{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-",
Namespace: namespace,
OwnerReferences: []metav1.OwnerReference{
metav1.OwnerReference{
APIVersion: cluster.APIVersion,
Kind: cluster.Kind,
Name: cluster.Name,
UID: cluster.UID,
},
},
},
Spec: infrav1.VSphereClusterSpec{},
}
Expect(k8sClient.Create(ctx, infraCluster)).ToNot(HaveOccurred())
// Assert that eventually the infrastructure cluster will have a
// finalizer.
infraClusterKey := client.ObjectKey{Namespace: infraCluster.Namespace, Name: infraCluster.Name}
Eventually(func() bool {
if err := k8sClient.Get(ctx, infraClusterKey, infraCluster); err != nil {
return false
}
return len(infraCluster.Finalizers) > 0
}, time.Second*30).Should(BeTrue())
// Update the corresponding CAPI Cluster's InfrastructureRef
cluster.Spec.InfrastructureRef = &corev1.ObjectReference{
APIVersion: infraCluster.APIVersion,
Kind: "VSphereCluster", //reflect.TypeOf(infraCluster).Elem().Name(),
Name: infraCluster.Name,
}
Expect(k8sClient.Update(ctx, cluster)).ShouldNot(HaveOccurred())
// Create the CAPI Machine and wait for it to exist.
//
// A finalizer is added to prevent it from being deleted until its
// dependents are removed.
machine := &clusterv1.Machine{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-",
Namespace: namespace,
Finalizers: []string{"test"},
Labels: map[string]string{
clusterv1.MachineClusterLabelName: cluster.Name,
},
OwnerReferences: []metav1.OwnerReference{
metav1.OwnerReference{
APIVersion: cluster.APIVersion,
Kind: cluster.Kind,
Name: cluster.Name,
UID: cluster.UID,
},
},
},
Spec: clusterv1.MachineSpec{},
}
Expect(k8sClient.Create(ctx, machine)).ShouldNot(HaveOccurred())
machineKey := client.ObjectKey{Namespace: machine.Namespace, Name: machine.Name}
Eventually(func() error {
return k8sClient.Get(ctx, machineKey, machine)
}, time.Second*30).ShouldNot(HaveOccurred())
// Create the infrastructure machine and wait for it to have a
// finalizer.
infraMachine := &infrav1.VSphereMachine{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-",
Namespace: namespace,
OwnerReferences: []metav1.OwnerReference{
metav1.OwnerReference{
APIVersion: machine.APIVersion,
Kind: machine.Kind,
Name: machine.Name,
UID: machine.UID,
},
},
},
Spec: infrav1.VSphereMachineSpec{},
}
Expect(k8sClient.Create(ctx, infraMachine)).ToNot(HaveOccurred())
infraMachineKey := client.ObjectKey{Namespace: infraMachine.Namespace, Name: infraMachine.Name}
Eventually(func() bool {
if err := k8sClient.Get(ctx, infraMachineKey, infraMachine); err != nil {
return false
}
return len(infraMachine.Finalizers) > 0
}, time.Second*30).Should(BeTrue())
deleteAndWait := func(key client.ObjectKey, obj canDeleteAndWait) {
// Delete the object.
Expect(k8sClient.Delete(ctx, obj)).ToNot(HaveOccurred())
// Issues updates until the patch to remove the finalizers is
// successful.
EventuallyWithOffset(1, func() error {
if err := k8sClient.Get(ctx, key, obj); err != nil {
return err
}
obj.SetFinalizers([]string{})
return k8sClient.Update(ctx, obj)
}, time.Second*30).ShouldNot(HaveOccurred())
// Wait for the object to no longer be available.
EventuallyWithOffset(1, func() error {
return k8sClient.Get(ctx, key, obj)
}, time.Second*30).Should(HaveOccurred())
}
// Delete the CAPI Cluster. To simulate the CAPI components we must:
//
// 1. Delete a resource.
// 2. Remove its finalizers.
// 3. Update the resource.
// 4. Wait for the resource to be deleted.
deleteAndWait(infraMachineKey, infraMachine)
deleteAndWait(machineKey, machine)
deleteAndWait(infraClusterKey, infraCluster)
deleteAndWait(clusterKey, cluster)
})
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment