Skip to content

Commit a57250c

Browse files
authored
Merge pull request #26 from gig-tech/async
make all terraform calls sync
2 parents 6c2bd3f + 265c89f commit a57250c

File tree

2 files changed

+118
-7
lines changed

2 files changed

+118
-7
lines changed

ovc/client.go

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package ovc
22

33
import (
4+
"bytes"
5+
"encoding/json"
46
"errors"
57
"fmt"
68
"io/ioutil"
79
"net/http"
810
"net/url"
911
"strings"
12+
"time"
1013

1114
"github.com/sirupsen/logrus"
1215
)
@@ -116,8 +119,40 @@ func NewClient(c *Config) (*Client, error) {
116119
return client, nil
117120
}
118121

122+
// async adds "async=true" flag to all API calls
123+
func async(req *http.Request) (*http.Request, error) {
124+
// fetch request body to the string
125+
jsonMap := make(map[string]interface{})
126+
127+
if req.Body != nil {
128+
reqBody, err := ioutil.ReadAll(req.Body)
129+
if err != nil {
130+
return nil, err
131+
}
132+
err = json.Unmarshal(reqBody, &jsonMap)
133+
if err != nil {
134+
return nil, err
135+
}
136+
}
137+
138+
jsonMap["_async"] = true
139+
configJSON, err := json.Marshal(jsonMap)
140+
if err != nil {
141+
return nil, err
142+
}
143+
newReq, err := http.NewRequest(req.Method, req.URL.String(), bytes.NewBuffer(configJSON))
144+
if err != nil {
145+
return nil, err
146+
}
147+
return newReq, nil
148+
}
149+
119150
// Do sends and API Request and returns the body as an array of bytes
120151
func (c *Client) Do(req *http.Request) ([]byte, error) {
152+
req, err := async(req) // make request asynchronous
153+
if err != nil {
154+
return nil, err
155+
}
121156
client := &http.Client{}
122157
tokenString, err := c.JWT.Get()
123158
if err != nil {
@@ -137,19 +172,95 @@ func (c *Client) Do(req *http.Request) ([]byte, error) {
137172
if err != nil {
138173
return nil, err
139174
}
175+
taskID := string(body)
140176

141177
c.logger.Debug("OVC call: " + req.URL.Path)
142178
c.logger.Debug("OVC response status code: " + resp.Status)
143-
c.logger.Debug("OVC response body: " + string(body))
179+
c.logger.Debug("OVC response body: " + string(taskID))
144180

145181
switch {
146182
case resp.StatusCode == 401:
147183
return nil, ErrAuthentication
148184
case resp.StatusCode > 202:
149-
return body, errors.New(string(body))
185+
return body, errors.New(taskID)
150186
}
151187

152-
return body, nil
188+
// remove quotes from taskID if contains any
189+
taskID = strings.Replace(taskID, "\"", "", -1)
190+
191+
// create request to get result of an async API call by job id
192+
taskJSON, err := json.Marshal(
193+
struct {
194+
TaskID string `json:"taskguid"`
195+
}{
196+
TaskID: taskID,
197+
},
198+
)
199+
if err != nil {
200+
return nil, err
201+
}
202+
203+
var taskResp *http.Response
204+
result := make([]interface{}, 0)
205+
start, timeout := time.Now(), 10*time.Minute
206+
207+
// wait for result of the async task
208+
for {
209+
taskReq, err := http.NewRequest("POST", c.ServerURL+"/system/task/get", bytes.NewBuffer(taskJSON))
210+
if err != nil {
211+
return nil, err
212+
}
213+
taskReq.Header.Set("Authorization", fmt.Sprintf("bearer %s", tokenString))
214+
taskReq.Header.Set("Content-Type", "application/json")
215+
taskResp, err = client.Do(taskReq)
216+
if taskResp != nil {
217+
defer taskResp.Body.Close()
218+
}
219+
if err != nil {
220+
return nil, err
221+
}
222+
switch {
223+
case taskResp.StatusCode == 401:
224+
return nil, ErrAuthentication
225+
case taskResp.StatusCode == 404:
226+
// task may have not been registered yet
227+
continue
228+
case taskResp.StatusCode > 202:
229+
return nil, errors.New(taskID)
230+
}
231+
resultBody, err := ioutil.ReadAll(taskResp.Body)
232+
if err != nil {
233+
return nil, err
234+
}
235+
if len(resultBody) != 0 {
236+
// if body is not empty, parse result
237+
err = json.Unmarshal(resultBody, &result)
238+
if err != nil {
239+
return resultBody, err
240+
}
241+
if len(result) != 0 {
242+
// result is not empty if can be parsed to a []interface{}
243+
break
244+
}
245+
}
246+
if now := time.Now(); now.Sub(start) > timeout {
247+
return nil, fmt.Errorf("job timeout %s", taskID)
248+
}
249+
time.Sleep(2 * time.Second)
250+
}
251+
252+
success, ok := result[0].(bool)
253+
if !ok {
254+
return nil, fmt.Errorf("Task response is incorrect taskId %v \n expected response in form [True/False, taskResult], received: \n %v", string(taskID), result)
255+
}
256+
if !success {
257+
return nil, fmt.Errorf("Task was not successfull taskID: %v:\n %v", string(taskID), result[1])
258+
}
259+
finalBody, err := json.Marshal(result[1])
260+
if err != nil {
261+
return finalBody, err
262+
}
263+
return finalBody, nil
153264
}
154265

155266
// GetLocation parses the URL to return the location of the API

ovc/cloudspaces.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ type CloudSpaceConfig struct {
2121
MaxNetworkPeerTransfer int `json:"maxNetworkPeerTransfer,omitempty"`
2222
MaxNumPublicIP int `json:"maxNumPublicIP,omitempty"`
2323
AllowedVMSizes []int `json:"allowedVMSizes,omitempty"`
24-
PrivateNetwork string `json:"privatenetwork"`
25-
Mode string `json:"mode"`
26-
Type string `json:"type"`
27-
ExternalnetworkID string `json:"externalnetworkId"`
24+
PrivateNetwork string `json:"privatenetwork,omitempty"`
25+
Mode string `json:"mode,omitempty"`
26+
Type string `json:"type,omitempty"`
27+
ExternalnetworkID string `json:"externalnetworkId,omitempty"`
2828
}
2929

3030
// ResourceLimits contains all information related to resource limits

0 commit comments

Comments
 (0)