Skip to content

Commit

Permalink
feat: minimal building black data resource
Browse files Browse the repository at this point in the history
  • Loading branch information
henryde committed Apr 29, 2024
1 parent 8b60d80 commit 2846dcc
Show file tree
Hide file tree
Showing 9 changed files with 118 additions and 306 deletions.
21 changes: 0 additions & 21 deletions .copywrite.hcl

This file was deleted.

23 changes: 23 additions & 0 deletions examples/provider-install-verification/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
terraform {
required_providers {
meshstack = {
source = "meshcloud/meshstack"
}
}
}

provider "meshstack" {
endpoint = "https://federation.dev.meshcloud.io"
apikey = "c0da6389-217a-4581-bed0-2728a1fed78b"
apisecret = "tnPKGcVoFKeaCXRyknRfx0V2xXL7bKbo"
}

data "meshstack_buildingblock" "test" {
metadata = {
uuid = "a797d382-b316-4827-95a1-5af8e6a1217f"
}
}

output "bb_provider_uuid" {
value = data.meshstack_buildingblock.test.metadata.definition_uuid
}
63 changes: 53 additions & 10 deletions internal/provider/buildingblock_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,58 @@ import (

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
)

// Ensure provider defined types fully satisfy framework interfaces.
var _ datasource.DataSource = &BuildingBlockDataSource{}
var (
_ datasource.DataSource = &buildingBlockDataSource{}
_ datasource.DataSourceWithConfigure = &buildingBlockDataSource{}
)

func NewBuildingBlockSource() datasource.DataSource {
return &BuildingBlockDataSource{}
func NewBuildingBlockDataSource() datasource.DataSource {
return &buildingBlockDataSource{}
}

type BuildingBlockDataSource struct {
type buildingBlockDataSource struct {
client *MeshStackProviderClient
}

type BuildingBlockDataSourceModel struct {
type buildingBlockDataSourceModel struct {
Metadata buildingBlockMetadataModel `tfsdk:"metadata"`
}

type buildingBlockMetadataModel struct {
Uuid types.String `tfsdk:"uuid"`
DefinitionUuid types.String `tfsdk:"definition_uuid"`
}

func (d *BuildingBlockDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
func (d *buildingBlockDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_buildingblock"
}

func (d *BuildingBlockDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
func (d *buildingBlockDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "BuildingBlock data source",

Attributes: map[string]schema.Attribute{},
Attributes: map[string]schema.Attribute{
"metadata": schema.SingleNestedAttribute{
Description: "Metadata",
Required: true,
Attributes: map[string]schema.Attribute{
"uuid": schema.StringAttribute{
Required: true,
},
"definition_uuid": schema.StringAttribute{
Computed: true,
},
},
},
},
}
}

func (d *BuildingBlockDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
func (d *buildingBlockDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
Expand All @@ -53,5 +76,25 @@ func (d *BuildingBlockDataSource) Configure(ctx context.Context, req datasource.
d.client = client
}

func (d *BuildingBlockDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
func (d *buildingBlockDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var state buildingBlockDataSourceModel

resp.Diagnostics.Append(req.Config.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

uuid := state.Metadata.Uuid.ValueString()
bb, err := d.client.ReadBuildingBlock(uuid)
if err != nil {
resp.Diagnostics.AddError("Unable to read buildingblock", err.Error())
}

state.Metadata.DefinitionUuid = types.StringValue(bb.Metadata.DefinitionUuid)

diags := resp.State.Set(ctx, &state)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
53 changes: 30 additions & 23 deletions internal/provider/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package provider
import (
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"net/url"
"strings"
"time"
)

Expand All @@ -15,8 +18,8 @@ const (

ERROR_GENERIC_CLIENT_ERROR = "client error"
ERROR_GENERIC_API_ERROR = "api error"
ERROR_AUTHENTICATION_FAILURE = "not authorized. check api key and secret."
ERROR_ENDPOINT_LOOKUP = "could not fetch endpoints for meshStack."
ERROR_AUTHENTICATION_FAILURE = "Not authorized. Check api key and secret."
ERROR_ENDPOINT_LOOKUP = "Could not fetch endpoints for meshStack."
)

// TODO this will be an abstraction that does the login call, get a token and then use this token in the Auth header.
Expand Down Expand Up @@ -50,66 +53,66 @@ func NewClient(url *url.URL, apiKey string, apiSecret string) (*MeshStackProvide
token: "",
}

if err := client.lookUpEndpoints(); err != nil {
return nil, errors.New(ERROR_ENDPOINT_LOOKUP)
}
// if err := client.lookUpEndpoints(); err != nil {
// return nil, errors.New(ERROR_ENDPOINT_LOOKUP)
// }
client.endpoints = endpoints{BuildingBlocks: "api/meshobjects/meshbuildingblocks"}

return client, nil
}

func (c *MeshStackProviderClient) login() error {
log.Println("login")
loginPath, err := url.JoinPath(c.url.String(), loginEndpoint)
if err != nil {
return err
}
loginUrl, _ := url.Parse(loginPath)

res, _ := c.httpClient.Do(
&http.Request{
URL: loginUrl,
Method: "POST",
Header: http.Header{
"client_id": {c.apiKey},
"client_secret": {c.apiSecret},
"grant_type": {"client_credentials"},
},
},
)
formData := url.Values{}
formData.Set("client_id", c.apiKey)
formData.Set("client_secret", c.apiSecret)
formData.Set("grant_type", "client_credentials")

if err != nil {
return errors.New(ERROR_GENERIC_CLIENT_ERROR)
}
req, _ := http.NewRequest(http.MethodPost, loginPath, strings.NewReader(formData.Encode()))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")

defer res.Body.Close()
res, err := c.httpClient.Do(req)

if err != nil || res.StatusCode != 200 {
return errors.New(ERROR_AUTHENTICATION_FAILURE)
}

log.Println(res)

defer res.Body.Close()

data, err := io.ReadAll(res.Body)
if err != nil {
return err
}

var loginResult loginResponse
json.Unmarshal(data, &loginResult)
c.token = loginResult.Token
c.token = fmt.Sprintf("Bearer %s", loginResult.Token)
c.tokenExpiry = time.Now().Add(time.Second * time.Duration(loginResult.ExpireSec))

return nil
}

func (c *MeshStackProviderClient) ensureValidToken() error {
log.Printf("current token: %s", c.token)
if c.token == "" || time.Now().Add(time.Second*30).After(c.tokenExpiry) {
return c.login()
}
return nil
}

func (c *MeshStackProviderClient) lookUpEndpoints() error {
log.Println("lookUpEndpoints")
if c.ensureValidToken() != nil {
return errors.New(ERROR_AUTHENTICATION_FAILURE)
}
log.Printf("new token: %s", c.token)

meshObjectsPath, err := url.JoinPath(c.url.String(), apiMeshObjectsRoot)
if err != nil {
Expand Down Expand Up @@ -149,15 +152,18 @@ func (c *MeshStackProviderClient) lookUpEndpoints() error {
}

func (c *MeshStackProviderClient) ReadBuildingBlock(uuid string) (*MeshBuildingBlock, error) {
log.Println("ReadBuildingBlock")
if c.ensureValidToken() != nil {
return nil, errors.New(ERROR_AUTHENTICATION_FAILURE)
}
log.Printf("new token: %s", c.token)

targetPath, err := url.JoinPath(c.url.String(), c.endpoints.BuildingBlocks, uuid)
if err != nil {
return nil, err
}

log.Println(targetPath)
targetUrl, _ := url.Parse(targetPath)
res, err := c.httpClient.Do(
&http.Request{
Expand All @@ -183,7 +189,8 @@ func (c *MeshStackProviderClient) ReadBuildingBlock(uuid string) (*MeshBuildingB
if err != nil {
return nil, err
}

log.Printf("response data: %s", data)

var bb MeshBuildingBlock
json.Unmarshal(data, &bb)
return &bb, nil
Expand Down
Loading

0 comments on commit 2846dcc

Please sign in to comment.