Skip to content

Commit

Permalink
Sync bitbucket and GitHub
Browse files Browse the repository at this point in the history
  • Loading branch information
carchi8py committed Nov 5, 2020
1 parent 4b9ec4e commit 8a2ccdb
Show file tree
Hide file tree
Showing 4 changed files with 191 additions and 68 deletions.
24 changes: 16 additions & 8 deletions gcp/cvs/restapi/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,23 @@ type Request struct {
// BuildHTTPReq builds an HTTP request to carry out the REST request
func (r *Request) BuildHTTPReq(host string, serviceAccount string, credentials string, audience string, baseURL string) (*http.Request, error) {
var keyBytes []byte
bodyJSON, err := json.Marshal(r.Params)
if err != nil {
return nil, err
}

var err error
var req *http.Request
url := host + baseURL
req, err := http.NewRequest(r.Method, url, bytes.NewReader(bodyJSON))
if err != nil {
return nil, err
if r.Method != "GET" && r.Method != "DELETE" {
bodyJSON, err := json.Marshal(r.Params)
if err != nil {
return nil, err
}
req, err = http.NewRequest(r.Method, url, bytes.NewReader(bodyJSON))
if err != nil {
return nil, err
}
} else {
req, err = http.NewRequest(r.Method, url, nil)
if err != nil {
return nil, err
}
}
if credentials != "" {
keyBytes = []byte(credentials)
Expand Down
155 changes: 116 additions & 39 deletions gcp/resource_netapp_gcp_volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,6 @@ func resourceGCPVolumeCreate(d *schema.ResourceData, meta interface{}) error {
volType = "Volumes"
}

log.Print(volType)

if v, ok := d.GetOk("export_policy"); ok {
policy := v.(*schema.Set)
if policy.Len() > 0 {
Expand All @@ -368,41 +366,105 @@ func resourceGCPVolumeCreate(d *schema.ResourceData, meta interface{}) error {
return err
}

d.SetId(res.Name.JobID.VolID)
var volumeRes volumeResult
time.Sleep(5 * time.Second)
volumeRes, err = client.getVolumeByID(volumeRequest{Region: volume.Region, VolumeID: res.Name.JobID.VolID})
volume.Network = d.Get("network").(string)
volumeRes, err = validateVolumeExistsAfterCreate(client, volume, res.Name.JobID.VolID, volType)
if err != nil {
return err
}
d.SetId(volumeRes.VolumeID)
if volumeRes.LifeCycleState == "available" {
return resourceGCPVolumeRead(d, meta)
}
if volumeRes.LifeCycleState == "creating" {
// wait for 5 minutes for completing volume creation.
waitSeconds := 300
for waitSeconds > 0 && volumeRes.LifeCycleState == "creating" {
time.Sleep(10)
volumeRes, err = client.getVolumeByID(volumeRequest{Region: volume.Region, VolumeID: res.Name.JobID.VolID})
volumeRes, err = waitForVolumeCreationComplete(client, volumeRes)
if err != nil {
return err
}
// if volume's state is error, delete the volume and retry for twice. If the operation still fails, return error.
if volumeRes.LifeCycleState == "error" {
retries := 2
for retries > 0 && volumeRes.LifeCycleState == "error" {
deleteErr := resourceGCPVolumeDelete(d, meta)
if deleteErr != nil {
return fmt.Errorf("failed to delete volume in error state after creation. %s", deleteErr.Error())
}
volume.Network = d.Get("network").(string)
res, err = client.createVolume(&volume, volType)
if err != nil {
return err
}
time.Sleep(5 * time.Second)
volume.Network = d.Get("network").(string)
volumeRes, err = validateVolumeExistsAfterCreate(client, volume, res.Name.JobID.VolID, volType)
if err != nil {
return err
}
d.SetId(volumeRes.VolumeID)
volumeRes, err = waitForVolumeCreationComplete(client, volumeRes)
if err != nil {
return err
}
waitSeconds = waitSeconds - 10
if volumeRes.LifeCycleState == "available" {
return resourceGCPVolumeRead(d, meta)
}
timeSleep := time.Duration(nextRandomInt(5, 10)) * time.Second
time.Sleep(timeSleep)
retries--
}
} else if volumeRes.LifeCycleState == "error" {
if d.Get("delete_on_creation_error").(bool) {
deleteErr := resourceGCPVolumeDelete(d, meta)
if deleteErr != nil {
return fmt.Errorf("failed to delete volume in error state after creation. %s", deleteErr.Error())
}
return fmt.Errorf("%v. Volume in error state is deleted", err.Error())
return fmt.Errorf("%v. Volume in error state is deleted", volumeRes.LifeCycleStateDetails)
}
return fmt.Errorf("%v", err.Error())
return fmt.Errorf("%v", volumeRes.LifeCycleStateDetails)
}

return resourceGCPVolumeRead(d, meta)
}

// Wait 5 minutes for volume creation to complete.
func waitForVolumeCreationComplete(client *Client, volumeRes volumeResult) (volumeResult, error) {
waitSeconds := 300
var err error
for waitSeconds > 0 && volumeRes.LifeCycleState == "creating" {
timeSleep := time.Duration(nextRandomInt(20, 30)) * time.Second
time.Sleep(timeSleep)
volumeRes, err = client.getVolumeByID(volumeRequest{Region: volumeRes.Region, VolumeID: volumeRes.VolumeID})
if err != nil {
return volumeResult{}, err
}
waitSeconds = waitSeconds - int(timeSleep)
}
return volumeRes, nil
}

// A bug might be presented in the API. A volume creation request is acknowledged(volume ID is returned), but get volume by ID doesn't find any result.
// A temporary fix is to send the create request again.
func validateVolumeExistsAfterCreate(client *Client, volume volumeRequest, volumeID string, volType string) (volumeResult, error) {
volumeRes, err := client.getVolumeByID(volumeRequest{Region: volume.Region, VolumeID: volumeID})
var res createVolumeResult
network := volume.Network
retries := 3
if err != nil {
for err != nil && err.Error() == "code: 404, message: Error describing volume - Volume not found" && retries > 0 {
time.Sleep(20 * time.Second)
volume.Network = network
res, err = client.createVolume(&volume, volType)
if err != nil {
return volumeResult{}, err
}
volumeRes, err = client.getVolumeByID(volumeRequest{Region: volume.Region, VolumeID: res.Name.JobID.VolID})
retries--
}
if err != nil {
return volumeResult{}, err
}
}
return volumeRes, nil
}

func resourceGCPVolumeRead(d *schema.ResourceData, meta interface{}) error {
log.Printf("Reading volume: %#v", d)
client := meta.(*Client)
Expand All @@ -415,26 +477,34 @@ func resourceGCPVolumeRead(d *schema.ResourceData, meta interface{}) error {
volume.VolumeID = id

var res volumeResult
for {
var vol volumeResult
vol, err := client.getVolumeByID(volume)
res, err := client.getVolumeByID(volume)
if err != nil {
return err
}

waitSeconds := 300
for waitSeconds > 0 && (res.LifeCycleState == "creating" || res.LifeCycleState == "deleting" || res.LifeCycleState == "updating") {
time.Sleep(20)
res, err = client.getVolumeByID(volumeRequest{Region: volume.Region, VolumeID: id})
if err != nil {
return err
}
waitSeconds = waitSeconds - 10
}

if vol.VolumeID != id {
return fmt.Errorf("Expected Volume ID %v, Response contained Volume ID %v", id, res.VolumeID)
}
if res.VolumeID != id {
return fmt.Errorf("Expected Volume ID %v, Response contained Volume ID %v", id, res.VolumeID)
}

if vol.LifeCycleState == "error" {
return fmt.Errorf("Volume with name: %v and id: %v is in %v state. Please check the setup. LifeCycleStateDetails: %v",
vol.Name, vol.VolumeID, vol.LifeCycleState, vol.LifeCycleStateDetails)
} else if vol.LifeCycleState == "available" {
res = vol
break
} else {
time.Sleep(time.Duration(2) * time.Second)
}
if res.LifeCycleState == "error" {
return fmt.Errorf("Volume with name: %v and id: %v is in error state. Please manually delete the volume, make sure the config is correct and run terraform apply agian. LifeCycleStateDetails: %v",
res.Name, res.VolumeID, res.LifeCycleStateDetails)
} else if res.LifeCycleState == "disabled" {
return fmt.Errorf("Volume with name: %v and id: %v is in disabled state. Please manually enable the volume and runn terraform apply again. LifeCycleStateDetails: %v",
res.Name, res.VolumeID, res.LifeCycleStateDetails)
} else if res.LifeCycleState == "deleted" {
d.SetId("")
return nil
}

if err := d.Set("size", res.Size/GiBToBytes); err != nil {
Expand Down Expand Up @@ -549,17 +619,24 @@ func resourceGCPVolumeDelete(d *schema.ResourceData, meta interface{}) error {
if getVolume.LifeCycleState == "deleted" {
return nil
}
if getVolume.LifeCycleState == "error" {
break
}
}
// if volume is in error state when deleting, retry.
} else if getVolume.LifeCycleState == "error" {
time.Sleep(time.Duration(nextRandomInt(5, 20)) * time.Second)
deleteErr := client.deleteVolume(volume)
if deleteErr != nil {
return deleteErr
}
getVolume, err := client.getVolumeByID(volume)
if err != nil {
return err
}
if getVolume.LifeCycleState == "error" {
retries := 3
for getVolume.LifeCycleState == "error" && retries > 0 {
time.Sleep(time.Duration(nextRandomInt(5, 20)) * time.Second)
deleteErr := client.deleteVolume(volume)
if deleteErr != nil {
return deleteErr
}
getVolume, err = client.getVolumeByID(volume)
if err != nil {
return err
}
}
if getVolume.LifeCycleState == "error" {
return fmt.Errorf("error deleting volume with id: %s, name: %s; %s", getVolume.VolumeID, getVolume.Name, getVolume.LifeCycleStateDetails)
Expand Down
3 changes: 2 additions & 1 deletion gcp/snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package gcp
import (
"encoding/json"
"fmt"
"github.com/fatih/structs"
"log"

"github.com/fatih/structs"
)

// createSnapshotRequest the users input for creating a Snapshot
Expand Down
77 changes: 57 additions & 20 deletions gcp/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,61 +265,58 @@ func (c *Client) createVolume(request *volumeRequest, volType string) (createVol
if responseErrorContent.Code == 500 {
if responseErrorContent.Message == spawnJobCreationErrorMessage {
retries := 10
var responseErrorContent apiErrorResponse
for retries > 0 {
var spawnJobResponseErrorContent apiErrorResponse
time.Sleep(time.Duration(nextRandomInt(30, 50)) * time.Second)
statusCode, response, err = c.CallAPIMethod("POST", baseURL, params)
if err != nil {
return createVolumeResult{}, err
}
responseError = apiResponseChecker(statusCode, response, "createVolume")
responseContent = bytes.NewBuffer(response).String()
if err := json.Unmarshal(response, &responseErrorContent); err != nil {
if err := json.Unmarshal(response, &spawnJobResponseErrorContent); err != nil {
return createVolumeResult{}, fmt.Errorf(responseContent)
}
if responseErrorContent.Code == 0 {
if spawnJobResponseErrorContent.Code == 0 {
var result createVolumeResult
if err := json.Unmarshal(response, &result); err != nil {
log.Print("Failed to unmarshall response from createVolume")
return createVolumeResult{}, fmt.Errorf(bytes.NewBuffer(response).String())
}
return result, nil
}
if spawnJobResponseErrorContent.Code != 500 {
return createVolumeResult{}, responseError
}
retries--
}
if responseErrorContent.Code >= 300 || responseErrorContent.Code < 200 {
return createVolumeResult{}, responseError
}
} else if responseErrorContent.Message == contextDeadlineExceededErrorMessage {
retries := 5
var responseErrorContent apiErrorResponse
for retries > 0 {
var contextDeadlineResponseErrorContent apiErrorResponse
time.Sleep(time.Duration(nextRandomInt(5, 10)) * time.Second)
statusCode, response, err = c.CallAPIMethod("POST", baseURL, params)
if err != nil {
if err := json.Unmarshal(response, &responseErrorContent); err != nil {
return createVolumeResult{}, fmt.Errorf(responseContent)
}
return createVolumeResult{}, err
}
responseError = apiResponseChecker(statusCode, response, "createVolume")
responseContent = bytes.NewBuffer(response).String()
if err := json.Unmarshal(response, &responseErrorContent); err != nil {
if err := json.Unmarshal(response, &contextDeadlineResponseErrorContent); err != nil {
return createVolumeResult{}, fmt.Errorf(responseContent)
}
if responseErrorContent.Code == 0 {
if contextDeadlineResponseErrorContent.Code == 0 {
var result createVolumeResult
if err := json.Unmarshal(response, &result); err != nil {
log.Print("Failed to unmarshall response from createVolume")
return createVolumeResult{}, fmt.Errorf(bytes.NewBuffer(response).String())
}

return result, nil
}
if contextDeadlineResponseErrorContent.Code != 500 {
return createVolumeResult{}, responseError
}
retries--
}
if responseErrorContent.Code >= 300 || responseErrorContent.Code < 200 {
return createVolumeResult{}, responseError
}
} else {
return createVolumeResult{}, responseError
}
Expand Down Expand Up @@ -349,13 +346,53 @@ func (c *Client) deleteVolume(request volumeRequest) error {

responseError := apiResponseChecker(statusCode, response, "deleteVolume")
if responseError != nil {
return responseError
var responseErrorContent apiErrorResponse
responseContent := bytes.NewBuffer(response).String()
if err := json.Unmarshal(response, &responseErrorContent); err != nil {
return fmt.Errorf(responseContent)
}
if responseErrorContent.Code == 500 {
if responseErrorContent.Message == spawnJobDeletionErrorMessage {
retries := 10
for retries > 0 {
var deleteJobResponseErrorContent apiErrorResponse
time.Sleep(time.Duration(nextRandomInt(30, 50)) * time.Second)
statusCode, response, err = c.CallAPIMethod("DELETE", baseURL, nil)
if err != nil {
return err
}
responseError = apiResponseChecker(statusCode, response, "deleteVolume")
responseContent = bytes.NewBuffer(response).String()
if err := json.Unmarshal(response, &deleteJobResponseErrorContent); err != nil {
return fmt.Errorf(responseContent)
}
if deleteJobResponseErrorContent.Code == 0 {
var result createVolumeResult
if err := json.Unmarshal(response, &result); err != nil {
log.Print("Failed to unmarshall response from createVolume")
return fmt.Errorf(bytes.NewBuffer(response).String())
}
return nil
}
if deleteJobResponseErrorContent.Code != 500 {
return responseError
}
retries--
}

} else {
return responseError
}
}
if responseErrorContent.Code >= 300 || responseErrorContent.Code < 200 {
return responseError
}
}

var result apiResponseCodeMessage
var result apiErrorResponse
if err := json.Unmarshal(response, &result); err != nil {
log.Print("Failed to unmarshall response from deleteVolume")
return err
return fmt.Errorf(bytes.NewBuffer(response).String())
}

return nil
Expand All @@ -367,7 +404,7 @@ func (c *Client) createVolumeCreationToken(request volumeRequest) (volumeResult,
baseURL := fmt.Sprintf("%s/VolumeCreationToken", request.Region)
log.Printf("Parameters: %v", params)

statusCode, response, err := c.CallAPIMethod("", baseURL, params)
statusCode, response, err := c.CallAPIMethod("POST", baseURL, params)
if err != nil {
log.Print("CreationToken request failed")
return volumeResult{}, err
Expand Down

0 comments on commit 8a2ccdb

Please sign in to comment.