From 3109ecf472d73ee94ea1b2829d2c9437fce1ca1e Mon Sep 17 00:00:00 2001 From: Timo Hirt Date: Tue, 14 Jul 2020 22:11:49 +0200 Subject: [PATCH] fix: Synchronize API requests Turned out that the Hetzner DNS API doesn't like multiple DNS records created at the same time. And if there is now implicit dependency between two resources, Terraform assumes it is safe to create more than one resource at a time. There is a bulk create endpoint, which might be the "right" way to implement the resource. However, it would be neccessary to add a DNS record group resource or something that groups a list of DNS records and this make the CRUD operations of this resource more complicated. I think having one resource per DNS record is good for now. Added a Mutex to synchronize all API requests. I hope this is an acceptable slow down. If there is demand for a DNS record set resources, let me know. It shouldn't be hard to and probably a good first issue for a contributer :-). fixes #5 --- hetznerdns/api/client.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hetznerdns/api/client.go b/hetznerdns/api/client.go index fe3cfee..7213b57 100644 --- a/hetznerdns/api/client.go +++ b/hetznerdns/api/client.go @@ -9,6 +9,7 @@ import ( "log" "net/http" "strings" + "sync" ) // UnauthorizedError represents the message of a HTTP 401 response @@ -32,6 +33,7 @@ func defaultCreateHTTPClient() *http.Client { // Client for the Hetzner DNS API. type Client struct { + requestLock sync.Mutex apiToken string createHTTPClient createHTTPClient } @@ -55,7 +57,16 @@ func (c *Client) doHTTPRequest(apiToken string, method string, url string, body req.Header.Set("Content-Type", "application/json; charset=utf-8") } + // This lock ensures that only one request is sent to Hetzber API + // at a time. See issue #5 for context. + // It seems that Terraform creates multiple resources simultanously + // and the API can't handle this right now. + c.requestLock.Lock() + resp, err := client.Do(req) + + c.requestLock.Unlock() + if err != nil { return nil, err } @@ -85,8 +96,6 @@ func parseUnprocessableEntityError(resp *http.Response) (*UnprocessableEntityErr if err != nil { return nil, fmt.Errorf("Error reading HTTP response body: %e", err) } - log.Printf("[DEBUG] 422 Unprocessable Entity error response body: %s", string(body)) - var unprocessableEntityError UnprocessableEntityError err = parseJSON(body, &unprocessableEntityError) if err != nil {