-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(LH-69453): CdFmc Resource (#84)
- Loading branch information
Showing
25 changed files
with
652 additions
and
69 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
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,7 @@ | ||
package application | ||
|
||
import "fmt" | ||
|
||
var ( | ||
NotFoundError = fmt.Errorf("unable to find application") | ||
) |
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,49 @@ | ||
package application | ||
|
||
import ( | ||
"context" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/http" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/url" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/application/applicationstatus" | ||
) | ||
|
||
type ReadInput struct { | ||
} | ||
|
||
type ReadOutput struct { | ||
Uid string `json:"uid"` | ||
Name string `json:"name"` | ||
Version int `json:"version"` | ||
ApplicationType string `json:"applicationType"` | ||
ApplicationStatus applicationstatus.Type `json:"applicationStatus"` | ||
ApplicationContent ApplicationContent `json:"applicationContent"` | ||
} | ||
|
||
type ApplicationContent struct { | ||
Type string `json:"@type"` | ||
FmceDeviceUid interface{} `json:"fmceDeviceUid"` | ||
DevicesCount int `json:"devicesCount"` | ||
SfcnDevicesCount int `json:"sfcnDevicesCount"` | ||
FmcApplianceUid interface{} `json:"fmcApplianceUid"` | ||
RequestedDevicesCount int `json:"requestedDevicesCount"` | ||
EstimatedDevicesCountRange string `json:"estimatedDevicesCountRange"` | ||
} | ||
|
||
func Read(ctx context.Context, client http.Client, readInp ReadInput) (*ReadOutput, error) { | ||
// create request | ||
readUrl := url.ReadApplication(client.BaseUrl()) | ||
readReq := client.NewGet(ctx, readUrl) | ||
|
||
// send request & map response | ||
var readApplicationOutput []ReadOutput | ||
err := readReq.Send(&readApplicationOutput) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
// check and return | ||
if len(readApplicationOutput) < 1 { | ||
return nil, NotFoundError | ||
} | ||
return &readApplicationOutput[0], 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 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,123 @@ | ||
package cloudfmc | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/device" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/device/application" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/goutil" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/http" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/retry" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/url" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/application/applicationstatus" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/devicetype" | ||
"time" | ||
) | ||
|
||
type CreateInput struct { | ||
} | ||
|
||
func NewCreateInput() CreateInput { | ||
return CreateInput{} | ||
} | ||
|
||
type createApplicationBody struct { | ||
ApplicationType string `json:"applicationType"` | ||
ApplicationStatus string `json:"applicationStatus"` | ||
ApplicationContent applicationContent `json:"applicationContent"` | ||
} | ||
|
||
type applicationContent struct { | ||
Type string `json:"@type"` | ||
} | ||
|
||
type CreateOutput = device.CreateOutput | ||
|
||
func Create(ctx context.Context, client http.Client, createInp CreateInput) (*CreateOutput, error) { | ||
|
||
client.Logger.Println("Creating application object for cdFMC") | ||
|
||
// 1. POST /aegis/rest/v1/services/targets/applications | ||
createApplicationUrl := url.CreateApplication(client.BaseUrl()) | ||
createApplicationReq := client.NewPost( | ||
ctx, | ||
createApplicationUrl, | ||
createApplicationBody{ | ||
ApplicationType: "FMCE", | ||
ApplicationStatus: "REQUESTED", | ||
ApplicationContent: applicationContent{ | ||
Type: "FmceApplicationContent", | ||
}, | ||
}, | ||
) | ||
var createApplicationOutp device.CreateOutput | ||
err := createApplicationReq.Send(&createApplicationOutp) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
client.Logger.Println("creating cloud FMC device") | ||
|
||
// 2. POST /aegis/rest/v1/services/targets/devices | ||
createOutp, err := device.Create(ctx, client, device.NewCreateInputBuilder(). | ||
Name("FMC"). | ||
DeviceType(devicetype.CloudFmc). | ||
Model(false). | ||
ConnectorType("CDG"). | ||
IgnoreCertificate(goutil.NewBoolPointer(true)). | ||
EnableOobDetection(goutil.NewBoolPointer(false)). | ||
Build(), | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
client.Logger.Println("waiting for fmce state machine to be done") | ||
|
||
err = retry.Do(untilApplicationActive(ctx, client), | ||
retry.NewOptionsBuilder(). | ||
Retries(-1). | ||
Timeout(30*time.Minute). // usually takes about 15-20 minutes | ||
Delay(3*time.Second). | ||
EarlyExitOnError(true). | ||
Logger(client.Logger). | ||
Build(), | ||
) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
client.Logger.Println("cloud FMC application successfully created") | ||
|
||
return createOutp, nil | ||
} | ||
|
||
func untilApplicationActive(ctx context.Context, client http.Client) retry.Func { | ||
var unreachable bool | ||
var initialUnreachableTime time.Time | ||
return func() (bool, error) { | ||
fmc, err := application.Read(ctx, client, application.ReadInput{}) | ||
if err != nil { | ||
if !errors.Is(err, application.NotFoundError) { | ||
// maybe the application is not created yet, and hopefully this is temporarily, ignoring | ||
return false, nil | ||
} | ||
return false, err | ||
} | ||
if fmc.ApplicationStatus == applicationstatus.Unreachable { | ||
// initial unreachable is possibly caused by https://jira-eng-rtp3.cisco.com/jira/browse/LH-71821 | ||
// wait for some time to confirm it is actually unreachable | ||
if unreachable { | ||
if initialUnreachableTime.Add(time.Minute * 5).After(time.Now()) { | ||
// if long enough time has passed, and we are still unreachable, treat it as actual error | ||
return false, err | ||
} | ||
} else { | ||
unreachable = true | ||
initialUnreachableTime = time.Now() | ||
return false, nil | ||
} | ||
} | ||
return fmc.ApplicationStatus == applicationstatus.Active, 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 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,72 @@ | ||
package device | ||
|
||
import ( | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/goutil" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/device/tags" | ||
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/model/devicetype" | ||
) | ||
|
||
// CreateInput builder pattern code | ||
type CreateInputBuilder struct { | ||
createInput *CreateInput | ||
} | ||
|
||
func NewCreateInputBuilder() *CreateInputBuilder { | ||
createInput := &CreateInput{} | ||
b := &CreateInputBuilder{createInput: createInput} | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) Name(name string) *CreateInputBuilder { | ||
b.createInput.Name = name | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) DeviceType(deviceType devicetype.Type) *CreateInputBuilder { | ||
b.createInput.DeviceType = deviceType | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) Model(model bool) *CreateInputBuilder { | ||
b.createInput.Model = model | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) ConnectorUid(connectorUid string) *CreateInputBuilder { | ||
b.createInput.ConnectorUid = connectorUid | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) ConnectorType(connectorType string) *CreateInputBuilder { | ||
b.createInput.ConnectorType = connectorType | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) SocketAddress(socketAddress string) *CreateInputBuilder { | ||
b.createInput.SocketAddress = socketAddress | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) IgnoreCertificate(ignoreCertificate *bool) *CreateInputBuilder { | ||
b.createInput.IgnoreCertificate = ignoreCertificate | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) Metadata(metadata interface{}) *CreateInputBuilder { | ||
b.createInput.Metadata = goutil.AsPointer(metadata) | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) Tags(tags tags.Type) *CreateInputBuilder { | ||
b.createInput.Tags = tags | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) EnableOobDetection(enableOobDetection *bool) *CreateInputBuilder { | ||
b.createInput.EnableOobDetection = enableOobDetection | ||
return b | ||
} | ||
|
||
func (b *CreateInputBuilder) Build() CreateInput { | ||
return *b.createInput | ||
} |
Oops, something went wrong.