10 bpav1alpha1 "github.com/bpa-operator/pkg/apis/bpa/v1alpha1"
11 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12 batchv1 "k8s.io/api/batch/v1"
13 logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
14 "k8s.io/apimachinery/pkg/runtime"
15 "k8s.io/apimachinery/pkg/types"
16 "k8s.io/client-go/kubernetes/scheme"
17 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
18 "sigs.k8s.io/controller-runtime/pkg/client/fake"
19 "sigs.k8s.io/controller-runtime/pkg/reconcile"
20 fakedynamic "k8s.io/client-go/dynamic/fake"
23 func TestProvisioningController(t *testing.T) {
25 logf.SetLogger(logf.ZapLogger(true))
26 bpaName1 := "bpa-test-cr"
27 bpaName2 := "bpa-test-2"
28 bpaName3 := "bpa-test-3"
29 namespace := "default"
30 clusterName := "test-cluster"
31 clusterName2 := "test-cluster-2"
32 clusterName3 := "test-cluster-3"
33 macAddress1 := "08:00:27:00:ab:2c"
34 macAddress2 := "08:00:27:00:ab:3d"
35 macAddress3 := "08:00:27:00:ab:1c"
37 // Create Fake DHCP file
38 err := createFakeDHCP()
40 t.Fatalf("Cannot create Fake DHCP file for testing\n")
43 // Create Fake baremetalhost
44 bmhList := newBMList()
46 // Create Fake Provisioning CR
47 provisioning := newBPA(bpaName1, namespace, clusterName, macAddress1)
48 provisioning2 := newBPA(bpaName2, namespace, clusterName2, macAddress2)
49 provisioning3 := newBPA(bpaName3, namespace, clusterName3, macAddress3)
51 // Objects to track in the fake Client
52 objs := []runtime.Object{provisioning, provisioning2, provisioning3}
54 // Register operator types with the runtime scheme
57 sc.AddKnownTypes(bpav1alpha1.SchemeGroupVersion, provisioning, provisioning2, provisioning3)
59 // Create Fake Clients
60 fakeClient := fake.NewFakeClient(objs...)
61 fakeDyn := fakedynamic.NewSimpleDynamicClient(sc, bmhList,)
63 r := &ReconcileProvisioning{client: fakeClient, scheme: sc, bmhClient: fakeDyn}
65 // Mock request to simulate Reconcile() being called on an event for a watched resource
66 req := simulateRequest(provisioning)
67 _, err = r.Reconcile(req)
69 t.Fatalf("reconcile: (%v)", err)
72 // Test 1: Check the job was created with the expected name
74 err = r.client.Get(context.TODO(), types.NamespacedName{Name: "kud-test-cluster", Namespace: namespace}, job)
76 t.Fatalf("Error occured while getting job: (%v)", err)
79 // Test 2: Check that cluster name metadata in job is the expected cluster name
80 jobClusterName := job.Labels["cluster"]
81 if jobClusterName != clusterName {
82 t.Fatalf("Job cluster Name is wrong")
86 // Test 3: Check that the right error is produced when host with MAC address does not exist
87 req = simulateRequest(provisioning2)
88 _, err = r.Reconcile(req)
89 expectedErr := "Host with MAC Address " + macAddress2 + " not found\n"
90 if err.Error() != expectedErr {
91 t.Fatalf("Failed, Unexpected error occured %v\n", err)
94 // Test 4: Check that the right error is produced when MAC address is not found in the DHCP lease file
95 req = simulateRequest(provisioning3)
96 _, err = r.Reconcile(req)
97 expectedErr = "IP address not found for host with MAC address " + macAddress3 + " \n"
98 if err.Error() != expectedErr {
99 t.Fatalf("Failed, Unexpected error occured %v\n", err)
102 // Delete Fake DHCP file and cluster directories
103 err = os.Remove("/var/lib/dhcp/dhcpd.leases")
105 t.Logf("\nUnable to delete fake DHCP file\n")
107 err = os.RemoveAll("/multi-cluster/" + clusterName)
109 t.Logf("\nUnable to delete cluster directory %s\n", clusterName)
111 err = os.RemoveAll("/multi-cluster/" + clusterName2)
113 t.Logf("\nUnable to delete cluster directory %s\n", clusterName2)
115 err = os.RemoveAll("/multi-cluster/" + clusterName3)
117 t.Logf("\nUnable to delete cluster directory %s\n", clusterName3)
123 func simulateRequest(bpaCR *bpav1alpha1.Provisioning) reconcile.Request {
124 namespacedName := types.NamespacedName{
125 Name: bpaCR.ObjectMeta.Name,
126 Namespace: bpaCR.ObjectMeta.Namespace,
128 return reconcile.Request{NamespacedName: namespacedName}
133 func newBPA(name, namespace, clusterName, macAddress string) *bpav1alpha1.Provisioning {
135 provisioningCR := &bpav1alpha1.Provisioning{
136 ObjectMeta: metav1.ObjectMeta{
138 Namespace: namespace,
139 Labels: map[string]string{
140 "cluster": clusterName,
143 Spec: bpav1alpha1.ProvisioningSpec{
144 Masters: []map[string]bpav1alpha1.Master{
145 map[string]bpav1alpha1.Master{
146 "test-master" : bpav1alpha1.Master{
147 MACaddress: macAddress,
155 return provisioningCR
159 func newBMList() *unstructured.UnstructuredList{
161 bmMap := map[string]interface{}{
162 "apiVersion": "metal3.io/v1alpha1",
163 "kind": "BareMetalHostList",
164 "metaData": map[string]interface{}{
166 "resourceVersion": "11830058",
167 "selfLink": "/apis/metal3.io/v1alpha1/baremetalhosts",
175 metaData := map[string]interface{}{
176 "creationTimestamp": "2019-10-24T04:51:15Z",
178 "name": "fake-test-bmh",
179 "namespace": "default",
180 "resourceVersion": "11829263",
181 "selfLink": "/apis/metal3.io/v1alpha1/namespaces/default/baremetalhosts/bpa-test-bmh",
182 "uid": "e92cb312-f619-11e9-90bc-00219ba0c77a",
187 nicMap1 := map[string]interface{}{
189 "mac": "08:00:27:00:ab:2c",
190 "model": "0x8086 0x1572",
197 nicMap2 := map[string]interface{}{
199 "mac": "08:00:27:00:ab:1c",
200 "model": "0x8086 0x1572",
207 specMap := map[string]interface{}{
208 "status" : map[string]interface{}{
210 "hardware": map[string]interface{}{
211 "nics": map[string]interface{}{
221 itemMap := map[string]interface{}{
222 "apiVersion": "metal3.io/v1alpha1",
223 "kind": "BareMetalHost",
224 "metadata": metaData,
227 itemU := unstructured.Unstructured{
231 itemsList := []unstructured.Unstructured{itemU,}
233 bmhList := &unstructured.UnstructuredList{
243 // Create DHCP file for testing
244 func createFakeDHCP() error{
247 dhcpData := []byte(`lease 192.168.50.63 {
248 starts 4 2019/08/08 22:32:49;
249 ends 4 2019/08/08 23:52:49;
250 cltt 4 2019/08/08 22:32:49;
251 binding state active;
252 next binding state free;
253 rewind binding state free;
254 hardware ethernet 08:00:27:00:ab:2c;
255 client-hostname "fake-test-bmh"";
257 err := ioutil.WriteFile("/var/lib/dhcp/dhcpd.leases", dhcpData, 0777)