Skip to content

Commit

Permalink
feat(LH-72231): SEC Resource (#104)
Browse files Browse the repository at this point in the history
  • Loading branch information
weilueluo authored Nov 14, 2023
1 parent e2e6fde commit ec4f49c
Show file tree
Hide file tree
Showing 43 changed files with 1,069 additions and 78 deletions.
17 changes: 17 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package client
import (
"context"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/connector/connectoronboarding"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/connector/sec"
"net/http"

"github.com/CiscoDevnet/terraform-provider-cdo/go-client/connector"
Expand Down Expand Up @@ -223,3 +224,19 @@ func (c *Client) ReadConnectorOnboarding(ctx context.Context, inp connectoronboa
func (c *Client) DeleteConnectorOnboarding(ctx context.Context, inp connectoronboarding.DeleteInput) (*connectoronboarding.DeleteOutput, error) {
return connectoronboarding.Delete(ctx, c.client, inp)
}

func (c *Client) CreateSec(ctx context.Context, inp sec.CreateInput) (*sec.CreateOutput, error) {
return sec.Create(ctx, c.client, inp)
}

func (c *Client) UpdateSec(ctx context.Context, inp sec.UpdateInput) (*sec.UpdateOutput, error) {
return sec.Update(ctx, c.client, inp)
}

func (c *Client) DeleteSec(ctx context.Context, inp sec.DeleteInput) (*sec.DeleteOutput, error) {
return sec.Delete(ctx, c.client, inp)
}

func (c *Client) ReadSec(ctx context.Context, inp sec.ReadInput) (*sec.ReadOutput, error) {
return sec.Read(ctx, c.client, inp)
}
28 changes: 28 additions & 0 deletions client/connector/sec/bootstrapdata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package sec

import (
"context"
"encoding/base64"
"fmt"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/http"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/user"
)

func ComputeEventOnlyBootstrapData(secName, accessToken, tenantName, baseUrl, host string) string {
bootstrapUrl := fmt.Sprintf("%s/connector/bootstrap/%s/%s", baseUrl, tenantName, secName)

rawBootstrapData := fmt.Sprintf("CDO_TOKEN=%q\nCDO_DOMAIN=%q\nCDO_TENANT=%q\nCDO_BOOTSTRAP_URL=%q\nONLY_EVENTING=\"true\"\n", accessToken, host, tenantName, bootstrapUrl)

bootstrapData := base64.StdEncoding.EncodeToString([]byte(rawBootstrapData))

return bootstrapData
}

func generateBootstrapData(ctx context.Context, client http.Client, secName string) (string, error) {
userToken, err := user.GetToken(ctx, client, user.NewGetTokenInput())
if err != nil {
return "", err
}

return ComputeEventOnlyBootstrapData(secName, userToken.AccessToken, userToken.TenantName, client.BaseUrl(), client.Host()), nil
}
103 changes: 103 additions & 0 deletions client/connector/sec/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package sec

import (
"context"
"fmt"
"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/statemachine"
"github.com/CiscoDevnet/terraform-provider-cdo/go-client/internal/url"
"time"
)

type CreateInput struct{}

type CreateOutput struct {
Uid string
Name string
SecBootstrapData string
CdoBoostrapData string
}

type createSecBody struct {
QueueTriggerState string `json:"queueTriggerState"`
}

func Create(ctx context.Context, client http.Client, createInp CreateInput) (*CreateOutput, error) {

// 1. create new sec
createUrl := url.CreateSec(client.BaseUrl())
createBody := createSecBody{QueueTriggerState: "ONBOARD_EVENT_STREAMER"}
req := client.NewPost(ctx, createUrl, createBody)
var createReqOutput CreateOutput
if err := req.Send(&createReqOutput); err != nil {
return nil, err
}

// 2. wait for state machine finish
err := retry.Do(
ctx,
statemachine.UntilDone(ctx, client, createReqOutput.Uid, "eventingPushRequest"),
retry.NewOptionsBuilder().
Message("Waiting for SEC to be created...").
Logger(client.Logger).
EarlyExitOnError(true).
Timeout(5*time.Minute).
Retries(-1).
Delay(time.Second).
Build(),
)
if err != nil {
return nil, err
}
// 3. get sec bootstrap data
readOutput, err := Read(ctx, client, NewReadInputBuilder().Uid(createReqOutput.Uid).Build())
if err != nil {
return nil, err
}
if readOutput.BootStrapData == "" {
return nil, fmt.Errorf("SEC bootstrap data not found")
}
secBootstrapData := readOutput.BootStrapData

// 4. generate cdo bootstrap data
cdoBootstrapData, err := generateBootstrapData(ctx, client, readOutput.Name)
if err != nil {
return nil, err
}

// 5. re-read the sec until its name is updated, no idea why the name is empty some time...
var readOut ReadOutput
err = retry.Do(
ctx,
func() (bool, error) {
out, err := Read(ctx, client, NewReadInputBuilder().Uid(createReqOutput.Uid).Build())
if err != nil {
return false, err
}
readOut = *out
return out.Name != "", nil
},
retry.NewOptionsBuilder().
Message("Waiting for SEC to finalize...").
Logger(client.Logger).
EarlyExitOnError(true).
Timeout(1*time.Minute).
Retries(-1).
Delay(500*time.Millisecond).
Build(),
)
if err != nil {
return nil, err
}

// done, create output
createOutput := CreateOutput{
Uid: createReqOutput.Uid,
Name: readOut.Name,
SecBootstrapData: secBootstrapData,
CdoBoostrapData: cdoBootstrapData,
}

return &createOutput, nil
}
15 changes: 15 additions & 0 deletions client/connector/sec/create_inputbuilder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package sec

type CreateInputBuilder struct {
createInput *CreateInput
}

func NewCreateInputBuilder() *CreateInputBuilder {
createInput := &CreateInput{}
b := &CreateInputBuilder{createInput: createInput}
return b
}

func (b *CreateInputBuilder) Build() CreateInput {
return *b.createInput
}
35 changes: 35 additions & 0 deletions client/connector/sec/create_outputbuilder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package sec

type CreateOutputBuilder struct {
createOutput *CreateOutput
}

func NewCreateOutputBuilder() *CreateOutputBuilder {
createOutput := &CreateOutput{}
b := &CreateOutputBuilder{createOutput: createOutput}
return b
}

func (b *CreateOutputBuilder) Uid(uid string) *CreateOutputBuilder {
b.createOutput.Uid = uid
return b
}

func (b *CreateOutputBuilder) Name(name string) *CreateOutputBuilder {
b.createOutput.Name = name
return b
}

func (b *CreateOutputBuilder) SecBootstrapData(secBootstrapData string) *CreateOutputBuilder {
b.createOutput.SecBootstrapData = secBootstrapData
return b
}

func (b *CreateOutputBuilder) CdoBoostrapData(cdoBoostrapData string) *CreateOutputBuilder {
b.createOutput.CdoBoostrapData = cdoBoostrapData
return b
}

func (b *CreateOutputBuilder) Build() CreateOutput {
return *b.createOutput
}
Loading

0 comments on commit ec4f49c

Please sign in to comment.