From c9e0ca0dbf9ab83cf1d42f70a2003d7cd726ba26 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?I=C3=B1aki=20Malerba?= <inaki@malerba.space>
Date: Wed, 14 Jun 2023 20:13:39 +0200
Subject: [PATCH] Add timeout setting for waiting servers to be up
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Sometimes some machines are stuck on starting, and need to be manually
deleted.

Create new `--hetzner-wait-for-running-timeout` flag to define a time
limit until the servers are running.

Signed-off-by: IƱaki Malerba <inaki@malerba.space>
---
 README.md        |  1 +
 driver/driver.go | 18 ++++++++++++++----
 driver/setup.go  |  6 ++++++
 3 files changed, 21 insertions(+), 4 deletions(-)

diff --git a/README.md b/README.md
index 94cebce..9277e8d 100644
--- a/README.md
+++ b/README.md
@@ -116,6 +116,7 @@ $ docker-machine create \
 - `--hetzner-primary-ipv4/6`: Sets an existing primary IP (v4 or v6 respectively) for the server, as documented in [Networking](#networking)
 - `--hetzner-wait-on-error`: Amount of seconds to wait on server creation failure (0/no wait by default)
 - `--hetzner-wait-on-polling`: Amount of seconds to wait between requests when waiting for some state to change. (Default: 1 second)
+- `--hetzner-wait-for-running-timeout`: Max amount of seconds to wait until a machine is running. (Default: 0/no timeout)
 
 #### Image selection
 
diff --git a/driver/driver.go b/driver/driver.go
index 8ff0e97..14180fd 100644
--- a/driver/driver.go
+++ b/driver/driver.go
@@ -57,6 +57,7 @@ type Driver struct {
 
 	WaitOnError int
 	WaitOnPolling int
+	WaitForRunningTimeout int
 
 	// internal housekeeping
 	version string
@@ -98,10 +99,12 @@ const (
 	defaultSSHPort = 22
 	defaultSSHUser = "root"
 
-	flagWaitOnError      = "hetzner-wait-on-error"
-	defaultWaitOnError   = 0
-	flagWaitOnPolling    = "hetzner-wait-on-polling"
-	defaultWaitOnPolling = 1
+	flagWaitOnError                = "hetzner-wait-on-error"
+	defaultWaitOnError             = 0
+	flagWaitOnPolling              = "hetzner-wait-on-polling"
+	defaultWaitOnPolling           = 1
+	flagWaitForRunningTimeout      = "hetzner-wait-for-running-timeout"
+	defaultWaitForRunningTimeout   = 0
 
 	legacyFlagUserDataFromFile = "hetzner-user-data-from-file"
 	legacyFlagDisablePublic4   = "hetzner-disable-public-4"
@@ -307,6 +310,12 @@ func (d *Driver) GetCreateFlags() []mcnflag.Flag {
 			Usage:  "Period for waiting between requests when waiting for some state to change",
 			Value:  defaultWaitOnPolling,
 		},
+		mcnflag.IntFlag{
+			EnvVar: "HETZNER_WAIT_FOR_RUNNING_TIMEOUT",
+			Name:   flagWaitForRunningTimeout,
+			Usage:  "Period for waiting for a machine to be running before failing",
+			Value:  defaultWaitForRunningTimeout,
+		},
 	}
 }
 
@@ -349,6 +358,7 @@ func (d *Driver) setConfigFromFlagsImpl(opts drivers.DriverOptions) error {
 
 	d.WaitOnError = opts.Int(flagWaitOnError)
 	d.WaitOnPolling = opts.Int(flagWaitOnPolling)
+	d.WaitForRunningTimeout = opts.Int(flagWaitForRunningTimeout)
 
 	d.placementGroup = opts.String(flagPlacementGroup)
 	if opts.Bool(flagAutoSpread) {
diff --git a/driver/setup.go b/driver/setup.go
index 24362e4..cabfa00 100644
--- a/driver/setup.go
+++ b/driver/setup.go
@@ -10,6 +10,7 @@ import (
 )
 
 func (d *Driver) waitForRunningServer() error {
+	start_time := time.Now()
 	for {
 		srvstate, err := d.GetState()
 		if err != nil {
@@ -20,6 +21,11 @@ func (d *Driver) waitForRunningServer() error {
 			break
 		}
 
+		elapsed_time := time.Since(start_time).Seconds()
+		if d.WaitForRunningTimeout > 0 && int(elapsed_time) > d.WaitForRunningTimeout {
+			return errors.Errorf("server exceeded wait-for-running-timeout.")
+		}
+
 		time.Sleep(time.Duration(d.WaitOnPolling) * time.Second)
 	}
 	return nil
-- 
GitLab