From 1e599d9a39a50b4cf9ced1f3ea3d8e049b9de464 Mon Sep 17 00:00:00 2001
From: Igor Anic <ianic@inet.hr>
Date: Mon, 30 Nov 2020 12:09:41 +0100
Subject: [PATCH] Signal and fail deployment when no eligible nodes are found

I run into this problem by writing wrong datacenter name in the nomadfile.
There where no nodes in that misspelled datacenter but the deployment
run forever waiting for the node to appear without indication of the
problem.
Nomad UI is showing the warning that there are no nodes eligible for
evaluation. But there is no such warning in levant output. So I added
the same warning as in UI.
Instead of waiting for some node to appear we are now failing deployment.
---
 levant/deploy.go | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/levant/deploy.go b/levant/deploy.go
index 01b0c33e..2acf38bf 100644
--- a/levant/deploy.go
+++ b/levant/deploy.go
@@ -257,6 +257,19 @@ func (l *levantDeployment) evaluationInspector(evalID *string) error {
 							group, len(metrics.ConstraintFiltered), cf)
 					}
 				}
+
+				eligibleNodes := 0
+				for dc, cnt := range metrics.NodesAvailable {
+					if cnt == 0 {
+						log.Error().Msgf("levant/deploy: no nodes are available in datacenter %s", dc)
+					}
+					eligibleNodes += cnt
+				}
+				if eligibleNodes == 0 {
+					log.Error().Msgf("levant/deploy: no nodes were eligible for evaluation")
+					l.failDeployement(*evalID)
+					return fmt.Errorf("no nodes were eligible for evaluation")
+				}
 			}
 
 			// Do not return an error here; there could well be information from
@@ -271,13 +284,21 @@ func (l *levantDeployment) evaluationInspector(evalID *string) error {
 	}
 }
 
+func (l *levantDeployment) failDeployement(evalID string) {
+	if depID, err := l.getDeploymentID(evalID); err == nil {
+		if _, _, err := l.nomad.Deployments().Fail(depID, nil); err == nil {
+			log.Info().Msgf("levant/deploy: deployment %s failed", depID)
+		}
+	}
+}
+
 func (l *levantDeployment) deploymentWatcher(depID string) (success bool) {
 
 	var canaryChan chan interface{}
 	deploymentChan := make(chan interface{})
 
 	t := time.Now()
-	wt := 5 * time.Second
+	wt := 1 * time.Second
 
 	// Setup the canaryChan and launch the autoPromote go routine if autoPromote
 	// has been enabled.