cloud/equinix/wrapngo: implement configurable parallelism

Setting this to a value higher than '1' is beneficial in case we want to
call some fast endpoints while we're executing a long-standing hardware
reservation list call. This can happen in the Equinix Shepherd.

Change-Id: I57cf416de1e5fe23cb28248ddf8bb1b2ad73b6a8
Reviewed-on: https://review.monogon.dev/c/monogon/+/1134
Tested-by: Jenkins CI
Reviewed-by: Mateusz Zalega <mateusz@monogon.tech>
diff --git a/cloud/shepherd/equinix/wrapngo/wrapn.go b/cloud/shepherd/equinix/wrapngo/wrapn.go
index 16478d5..f27ff54 100644
--- a/cloud/shepherd/equinix/wrapngo/wrapn.go
+++ b/cloud/shepherd/equinix/wrapngo/wrapn.go
@@ -67,11 +67,19 @@
 
 	// APIRate is the minimum time taken between subsequent API calls.
 	APIRate time.Duration
+
+	// Parallelism defines how many calls to the Equinix API will be issued in
+	// parallel. When this limit is reached, subsequent attmepts to call the API will
+	// block. The order of serving of pending calls is currently undefined.
+	//
+	// If not defined (ie. 0), defaults to 1.
+	Parallelism int
 }
 
 func (o *Opts) RegisterFlags() {
 	flag.StringVar(&o.User, "equinix_api_username", "", "Username for Equinix API")
 	flag.StringVar(&o.APIKey, "equinix_api_key", "", "Key/token/password for Equinix API")
+	flag.IntVar(&o.Parallelism, "equinix_parallelism", 1, "How many parallel connections to the Equinix API will be allowed")
 }
 
 // Client is a limited interface of methods that the Shepherd uses on Equinix. It
@@ -116,8 +124,8 @@
 	o        *Opts
 	rlt      *time.Ticker
 
-	// serializer is a 1-semaphore channel (effectively a mutex) which is used to
-	// limit the number of concurrent calls to the Equinix API.
+	// serializer is a N-semaphore channel (configured by opts.Parallelism) which is
+	// used to limit the number of concurrent calls to the Equinix API.
 	serializer chan (struct{})
 }
 
@@ -138,6 +146,9 @@
 			return backoff.NewExponentialBackOff()
 		}
 	}
+	if opts.Parallelism == 0 {
+		opts.Parallelism = 1
+	}
 
 	return &client{
 		username: opts.User,
@@ -145,7 +156,7 @@
 		o:        opts,
 		rlt:      time.NewTicker(opts.APIRate),
 
-		serializer: make(chan struct{}, 1),
+		serializer: make(chan struct{}, opts.Parallelism),
 	}
 }