-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Tidy up polling now that datastore bug is fixed
A server side datastore bug [1] has been fixed. This allows us to refactor polling the relevant async operation in a way that is less specific to the resource type. [1] FF-28659
- Loading branch information
1 parent
7c105f9
commit e16ca15
Showing
8 changed files
with
228 additions
and
215 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package async | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"time" | ||
|
||
"github.com/HewlettPackard/hpegl-pcbe-terraform-resources/internal/client" | ||
"github.com/HewlettPackard/hpegl-pcbe-terraform-resources/internal/sdk/async/dataservices" | ||
) | ||
|
||
type Operation struct { | ||
ctx context.Context | ||
client client.PCBeClient | ||
operationID string | ||
associatedResourceType string | ||
opResp dataservices.V1beta1AsyncOperationsItemAsyncOperationsGetResponseable | ||
} | ||
|
||
// New returns a new Operation struct that can be used to poll | ||
// asynchronous operations for any resource type. | ||
func New( | ||
ctx context.Context, | ||
client client.PCBeClient, | ||
OperationID string, | ||
associatedResourceType string, | ||
) Operation { | ||
a := Operation{} | ||
a.ctx = ctx | ||
a.client = client | ||
a.operationID = OperationID | ||
a.associatedResourceType = associatedResourceType | ||
|
||
return a | ||
} | ||
|
||
func (a Operation) GetSourceResourceURI() (string, error) { | ||
if a.opResp == nil { | ||
msg := "GetSourceResourceURI requies a non-nil opResp" | ||
|
||
return "", errors.New(msg) | ||
} | ||
|
||
if a.opResp.GetSourceResourceUri() == nil { | ||
msg := "GetSourceResourceURI requies a non-nil GetSourceResourceUri" | ||
|
||
return "", errors.New(msg) | ||
} | ||
|
||
return *a.opResp.GetSourceResourceUri(), nil | ||
} | ||
|
||
func (a Operation) GetAssociatedResourceURI() (string, error) { | ||
if a.opResp == nil { | ||
msg := "GetAssociatedResourceURI requies a non-nil opResp" | ||
|
||
return "", errors.New(msg) | ||
} | ||
|
||
if len(a.opResp.GetAssociatedResources()) != 1 { | ||
msg := "GetAssociatedResourceURI requires exactly one associatedResource" | ||
|
||
return "", errors.New(msg) | ||
|
||
} | ||
|
||
if a.opResp.GetAssociatedResources()[0].GetTypeEscaped() == nil { | ||
msg := "GetAssociatedResourceURI requires a non-nil associatedResource type" | ||
|
||
return "", errors.New(msg) | ||
} | ||
|
||
typeEscaped := *(a.opResp.GetAssociatedResources()[0].GetTypeEscaped()) | ||
if typeEscaped != a.associatedResourceType { | ||
msg := "GetAssociatedResourceURI type mismatch (" + typeEscaped + | ||
" != " + a.associatedResourceType + ")" | ||
|
||
return "", errors.New(msg) | ||
} | ||
|
||
if a.opResp.GetAssociatedResources()[0].GetResourceUri() == nil { | ||
msg := "GetAssociatedResourceURI requires a non-nil associatedResource uri" | ||
|
||
return "", errors.New(msg) | ||
} | ||
|
||
return *(a.opResp.GetAssociatedResources()[0].GetResourceUri()), nil | ||
} | ||
|
||
// Poll waits for an asynchronous operation to complete | ||
// It is not thread safe (but does not currently need to be) | ||
// Typically the operation flow will be: | ||
// | ||
// a := New(...) | ||
// a.Poll() | ||
// uri ... = a.GetAssociatedResourceURI() | ||
func (a *Operation) Poll() error { | ||
maxPolls := int(a.client.Config.MaxPolls) | ||
pollWaitTime := time.Duration(a.client.Config.PollInterval) * time.Second | ||
|
||
asyncClient, err := a.client.NewAsyncClient(a.ctx) | ||
if err != nil { | ||
msg := "error polling async operation " + a.operationID + ": " + | ||
err.Error() | ||
|
||
return errors.New(msg) | ||
} | ||
|
||
var opResp dataservices.V1beta1AsyncOperationsItemAsyncOperationsGetResponseable | ||
arc := dataservices. | ||
V1beta1AsyncOperationsAsyncOperationsItemRequestBuilderGetRequestConfiguration{} | ||
|
||
for count := 1; ; count++ { | ||
opResp, err = asyncClient.DataServices(). | ||
V1beta1(). | ||
AsyncOperations(). | ||
ById(a.operationID). | ||
Get(a.ctx, &arc) | ||
|
||
if err != nil { | ||
msg := "error polling async operation " + a.operationID + ": " + err.Error() | ||
|
||
return errors.New(msg) | ||
} | ||
|
||
if opResp == nil { | ||
msg := "error polling async operation " + a.operationID + ": " + | ||
"nil op response" | ||
|
||
return errors.New(msg) | ||
} | ||
|
||
opRespState := opResp.GetState() | ||
if opRespState == nil { | ||
msg := "error polling async operation " + a.operationID + ": " + | ||
"operation has nil state" | ||
|
||
return errors.New(msg) | ||
} | ||
|
||
// TODO: (API) Use enum not string for state when FF-28181 is fixed | ||
if *opRespState == "FAILED" { | ||
msg := "error polling async operation " + a.operationID + "operation state FAILED" | ||
|
||
return errors.New(msg) | ||
} | ||
|
||
// TODO: (API) Use enum not string for state when FF-28181 is fixed | ||
if *opRespState == "SUCCEEDED" { | ||
a.opResp = opResp | ||
|
||
break | ||
} | ||
|
||
if count == maxPolls { | ||
msg := "error polling async operation " + a.operationID + ": " + | ||
"max polls exceeded" | ||
|
||
return errors.New(msg) | ||
} | ||
|
||
time.Sleep(pollWaitTime) | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.