Skip to content

Commit

Permalink
#27 Add 422 retry on vm create
Browse files Browse the repository at this point in the history
  • Loading branch information
ja6a authored Jan 4, 2019
2 parents ca05522 + 8ba98f1 commit bcdf62b
Show file tree
Hide file tree
Showing 2 changed files with 99 additions and 3 deletions.
20 changes: 17 additions & 3 deletions skytap/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"log"
"net/http"
"sort"
"time"
)
Expand Down Expand Up @@ -278,10 +279,23 @@ func (s *VMsServiceClient) Create(ctx context.Context, environmentID string, opt
return nil, err
}

// Retry to work around 422 errors on creating a vm.
var createdEnvironment Environment
_, err = s.client.do(ctx, req, &createdEnvironment)
if err != nil {
return nil, err
var makeRequest = true
for i := 0; i < s.client.retryCount+1 && makeRequest; i++ {
_, err = s.client.do(ctx, req, &createdEnvironment)
if err == nil {
log.Printf("[INFO] VM created\n")
makeRequest = false
} else {
errorResponse := err.(*ErrorResponse)
if http.StatusUnprocessableEntity == errorResponse.Response.StatusCode {
log.Printf("[INFO] 422 error received: waiting for %d second(s)\n", s.client.retryAfter)
time.Sleep(time.Duration(s.client.retryAfter) * time.Second)
} else {
return nil, err
}
}
}

// The create method returns an environment. The ID of the VM is not specified.
Expand Down
82 changes: 82 additions & 0 deletions skytap/vm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,88 @@ func TestCreateVM(t *testing.T) {
assert.Equal(t, environment.VMs[1], *createdVM, "Bad VM")
}

func TestCreateVM422(t *testing.T) {
request := fmt.Sprintf(`{
"template_id": "%d",
"vm_ids": [
"%d"
]
}`, 42, 43)
response := fmt.Sprintf(string(readTestFile(t, "createVMResponse.json")), 123, 123, 456)
requestCounter := 0

skytap, hs, handler := createClient(t)
defer hs.Close()

*handler = func(rw http.ResponseWriter, req *http.Request) {
assert.Equal(t, "/configurations/123", req.URL.Path, "Bad path")
assert.Equal(t, "PUT", req.Method, "Bad method")

body, err := ioutil.ReadAll(req.Body)
assert.Nil(t, err, "Bad request body")
assert.JSONEq(t, request, string(body), "Bad request body")

if requestCounter == 0 {
rw.WriteHeader(http.StatusUnprocessableEntity)
} else {
_, err = io.WriteString(rw, response)
assert.NoError(t, err)
}
requestCounter++
}
opts := &CreateVMRequest{
TemplateID: "42",
VMID: "43",
}

createdVM, err := skytap.VMs.Create(context.Background(), "123", opts)
assert.Nil(t, err, "Bad API method")

var environment Environment
err = json.Unmarshal([]byte(response), &environment)
assert.NoError(t, err)
assert.Equal(t, environment.VMs[1], *createdVM, "Bad VM")

assert.Equal(t, 2, requestCounter)
}

func TestCreateVMError(t *testing.T) {
request := fmt.Sprintf(`{
"template_id": "%d",
"vm_ids": [
"%d"
]
}`, 42, 43)
requestCounter := 0

skytap, hs, handler := createClient(t)
defer hs.Close()

*handler = func(rw http.ResponseWriter, req *http.Request) {
assert.Equal(t, "/configurations/123", req.URL.Path, "Bad path")
assert.Equal(t, "PUT", req.Method, "Bad method")

body, err := ioutil.ReadAll(req.Body)
assert.Nil(t, err, "Bad request body")
assert.JSONEq(t, request, string(body), "Bad request body")

rw.WriteHeader(401)
requestCounter++
}
opts := &CreateVMRequest{
TemplateID: "42",
VMID: "43",
}

createdVM, err := skytap.VMs.Create(context.Background(), "123", opts)
assert.Nil(t, createdVM, "Bad API method")
errorResponse := err.(*ErrorResponse)

assert.Nil(t, errorResponse.RetryAfter)
assert.Equal(t, 1, requestCounter)
assert.Equal(t, http.StatusUnauthorized, errorResponse.Response.StatusCode)
}

func TestReadVM(t *testing.T) {
response := fmt.Sprintf(string(readTestFile(t, "VMResponse.json")), 456)

Expand Down

0 comments on commit bcdf62b

Please sign in to comment.