Repository: gardener/machine-controller-manager (go)

Issue:
Backoff when secret is missing referred by MachineClass.
**What happened**: If MachineClass is created but referred Secret is not yet available, MCM just ignores the MachineDeployment in the reconciliation by returning `nil`. Even if the Secret is created immediately after, MCM would process the MachineDeployment only in the next reconciliation[~10min or update call].

**What you expected to happen**:  I would expect MachineDeployment to back off when the secret referred by MachineClass is not found. Hence MachineDeplloyment should then be immediately reconciled when the referred secret is available later.

**How to reproduce it (as minimally and precisely as possible)**: Create Machinedeployment, MachineClass first. Then create a secret, observe MCM not reconciling the MachineDeployment till next reconciliation. 

**Possible solution**:  ~~This [codepath](https://github.com/gardener/machine-controller-manager/blob/master/pkg/controller/machine.go#L863-L867) should return an error, and back off eventually.~~

Pull request description:
Retry when secret is referred by machineClass is missing
**What this PR does / why we need it**:
The PR returns an `error` when the Secret referred by the MachineClass is absent/not created yet. Waits until the secret is created while prompting it on the logs. MachineDeployment immediately reconciles when the referred secret is available later.

**Which issue(s) this PR fixes**:
Fixes #430 

**Special notes for your reviewer**:
This is my first PR to this repo. I have tried my best to adhere to the guidelines. Let me know if there is anything to be rectified.

**Release note**:
<!--  Write your release note:
1. Enter your release note in the below block.
2. If no release note is required, just write "NONE" within the block.

Format of block header: <category> <target_group>
Possible values:
- category:       improvement|noteworthy
- target_group:   user|operator|developer
-->
```improvement user
Retry when secret is referred by machineClass is missing
```
 @hardikdr @prashanth26 

Patch:
diff --git a/pkg/controller/machine.go b/pkg/controller/machine.go
index f6e54fd3b..70887a703 100644
--- a/pkg/controller/machine.go
+++ b/pkg/controller/machine.go
@@ -949,7 +949,7 @@ func (c *controller) getSecret(ref *v1.SecretReference, machineClassName string)
 	secretRef, err := c.secretLister.Secrets(ref.Namespace).Get(ref.Name)
 	if apierrors.IsNotFound(err) {
 		klog.V(3).Infof("No secret %q: found for MachineClass %q", ref, machineClassName)
-		return nil, nil
+		return nil, err
 	}
 	if err != nil {
 		klog.Errorf("Unable get secret %q for MachineClass %q: %v", machineClassName, ref, err)


Test patch:
diff --git a/pkg/controller/controller_suite_test.go b/pkg/controller/controller_suite_test.go
index 9b23aa749..28bddd77a 100644
--- a/pkg/controller/controller_suite_test.go
+++ b/pkg/controller/controller_suite_test.go
@@ -463,6 +463,16 @@ func createController(
 	pvcs := coreTargetSharedInformers.PersistentVolumeClaims()
 	pvs := coreTargetSharedInformers.PersistentVolumes()
 
+	coreControlInformerFactory := coreinformers.NewFilteredSharedInformerFactory(
+		fakeControlCoreClient,
+		100*time.Millisecond,
+		namespace,
+		nil,
+	)
+	defer coreControlInformerFactory.Start(stop)
+	coreControlSharedInformers := coreControlInformerFactory.Core().V1()
+	secret := coreControlSharedInformers.Secrets()
+
 	controlMachineInformerFactory := machineinformers.NewFilteredSharedInformerFactory(
 		fakeControlMachineClient,
 		100*time.Millisecond,
@@ -511,6 +521,7 @@ func createController(
 		nodeLister:                     nodes.Lister(),
 		pvcLister:                      pvcs.Lister(),
 		pvLister:                       pvs.Lister(),
+		secretLister:                   secret.Lister(),
 		machineLister:                  machines.Lister(),
 		machineSetLister:               machineSets.Lister(),
 		machineDeploymentLister:        machineDeployments.Lister(),
@@ -518,6 +529,7 @@ func createController(
 		machineSetSynced:               machineSets.Informer().HasSynced,
 		machineDeploymentSynced:        machineDeployments.Informer().HasSynced,
 		nodeSynced:                     nodes.Informer().HasSynced,
+		secretSynced:                   secret.Informer().HasSynced,
 		secretQueue:                    workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "secret"),
 		nodeQueue:                      workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "node"),
 		openStackMachineClassQueue:     workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "openstackmachineclass"),
diff --git a/pkg/controller/machine_test.go b/pkg/controller/machine_test.go
index 2c55922ee..1dcb1b3ae 100644
--- a/pkg/controller/machine_test.go
+++ b/pkg/controller/machine_test.go
@@ -50,6 +50,61 @@ var _ = Describe("machine", func() {
 		c                 *controller
 	)
 
+	Describe("getSecret", func() {
+
+		var (
+			secretRef *v1.SecretReference
+		)
+
+		BeforeEach(func() {
+
+			secretRef = &v1.SecretReference{
+				Name:      "test-secret",
+				Namespace: testNamespace,
+			}
+		})
+
+		It("should return success", func() {
+			stop := make(chan struct{})
+			defer close(stop)
+
+			testSecret := &v1.Secret{
+				ObjectMeta: metav1.ObjectMeta{
+					Name:      "test-secret",
+					Namespace: testNamespace,
+				},
+			}
+			objects := []runtime.Object{}
+			objects = append(objects, testSecret)
+
+			c, trackers := createController(stop, testNamespace, nil, objects, nil)
+			defer trackers.Stop()
+
+			waitForCacheSync(stop, c)
+			secretRet, errRet := c.getSecret(secretRef, "test-aws")
+			Expect(errRet).Should(BeNil())
+			Expect(secretRet).Should(Not(BeNil()))
+			Expect(secretRet).Should(Equal(testSecret))
+
+		})
+
+		It("should return error", func() {
+			err := errors.New("secret \"test-secret\" not found")
+			stop := make(chan struct{})
+			defer close(stop)
+
+			c, trackers := createController(stop, testNamespace, nil, nil, nil)
+			defer trackers.Stop()
+
+			waitForCacheSync(stop, c)
+			secretRet, errRet := c.getSecret(secretRef, "test-aws")
+			Expect(errRet).Should(Not(BeNil()))
+			Expect(errRet.Error()).Should(Equal(err.Error()))
+			Expect(secretRet).Should(BeNil())
+		})
+
+	})
+
 	Describe("#updateMachineStatus", func() {
 		var (
 			machine       *machinev1.Machine