Skip to content

Commit

Permalink
Merge pull request #41 from nullplatform/features/metadata-specification
Browse files Browse the repository at this point in the history
feat: metadata specification
  • Loading branch information
sebasnallar authored Dec 5, 2024
2 parents 0a9cb93 + 998e821 commit a758da9
Show file tree
Hide file tree
Showing 6 changed files with 307 additions and 14 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ testacc:
TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 120m

update-docs:
tfplugindocs generate -provider-name nullplatform --rendered-provider-name "Null Platform"
tfplugindocs generate -provider-name nullplatform --rendered-provider-name "Null Platform"
118 changes: 118 additions & 0 deletions nullplatform/metadata_specification.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package nullplatform

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)

const (
METADATA_SPECIFICATION_PATH = "/metadata/metadata_specification"
)

type MetadataSpecification struct {
Id string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Description string `json:"description,omitempty"`
Nrn string `json:"nrn,omitempty"`
Entity string `json:"entity,omitempty"`
Metadata string `json:"metadata,omitempty"`
Schema map[string]interface{} `json:"schema,omitempty"`
}

func (c *NullClient) CreateMetadataSpecification(m *MetadataSpecification) (*MetadataSpecification, error) {
var buf bytes.Buffer
err := json.NewEncoder(&buf).Encode(*m)
if err != nil {
return nil, fmt.Errorf("failed to encode metadata specification: %v", err)
}

res, err := c.MakeRequest("POST", METADATA_SPECIFICATION_PATH, &buf)
if err != nil {
return nil, fmt.Errorf("failed to make API request: %v", err)
}
defer res.Body.Close()

if res.StatusCode != http.StatusOK {
bodyBytes, _ := io.ReadAll(res.Body)
return nil, fmt.Errorf("failed to create metadata specification: status code %d, response: %s", res.StatusCode, string(bodyBytes))
}

mRes := &MetadataSpecification{}
if err := json.NewDecoder(res.Body).Decode(mRes); err != nil {
return nil, fmt.Errorf("failed to decode API response: %v", err)
}

return mRes, nil
}

func (c *NullClient) UpdateMetadataSpecification(id string, m *MetadataSpecification) (*MetadataSpecification, error) {
path := fmt.Sprintf("%s/%s", METADATA_SPECIFICATION_PATH, id)

var buf bytes.Buffer
err := json.NewEncoder(&buf).Encode(*m)
if err != nil {
return nil, fmt.Errorf("failed to encode metadata specification: %v", err)
}

res, err := c.MakeRequest("PATCH", path, &buf)
if err != nil {
return nil, fmt.Errorf("failed to make API request: %v", err)
}
defer res.Body.Close()

if res.StatusCode != http.StatusOK {
bodyBytes, _ := io.ReadAll(res.Body)
return nil, fmt.Errorf("failed to update metadata specification: status code %d, response: %s", res.StatusCode, string(bodyBytes))
}

mRes := &MetadataSpecification{}
if err := json.NewDecoder(res.Body).Decode(mRes); err != nil {
return nil, fmt.Errorf("failed to decode API response: %v", err)
}

return mRes, nil
}

func (c *NullClient) GetMetadataSpecification(id string) (*MetadataSpecification, error) {
path := fmt.Sprintf("%s/%s", METADATA_SPECIFICATION_PATH, id)

res, err := c.MakeRequest("GET", path, nil)
if err != nil {
return nil, fmt.Errorf("failed to make API request: %v", err)
}
defer res.Body.Close()

if res.StatusCode != http.StatusOK {
bodyBytes, _ := io.ReadAll(res.Body)
return nil, fmt.Errorf("failed to get metadata specification: status code %d, response: %s", res.StatusCode, string(bodyBytes))
}

m := &MetadataSpecification{}
if err := json.NewDecoder(res.Body).Decode(m); err != nil {
return nil, fmt.Errorf("failed to decode API response: %v", err)
}

return m, nil
}

func (c *NullClient) DeleteMetadataSpecification(id string) error {
path := fmt.Sprintf("%s/%s", METADATA_SPECIFICATION_PATH, id)

emptyBody := bytes.NewBuffer([]byte("{}"))

res, err := c.MakeRequest("DELETE", path, emptyBody)
if err != nil {
return fmt.Errorf("failed to make API request: %v", err)
}
defer res.Body.Close()

if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusNoContent {
bodyBytes, _ := io.ReadAll(res.Body)
return fmt.Errorf("failed to delete metadata specification: status code %d, response: %s", res.StatusCode, string(bodyBytes))
}

return nil
}
5 changes: 5 additions & 0 deletions nullplatform/null_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,11 @@ type NullOps interface {
GetAccount(accountId string) (*Account, error)
PatchAccount(accountId string, account *Account) error
DeleteAccount(accountId string) error

CreateMetadataSpecification(spec *MetadataSpecification) (*MetadataSpecification, error)
GetMetadataSpecification(specId string) (*MetadataSpecification, error)
UpdateMetadataSpecification(specId string, spec *MetadataSpecification) (*MetadataSpecification, error)
DeleteMetadataSpecification(specId string) error
}

func (c *NullClient) MakeRequest(method, path string, body *bytes.Buffer) (*http.Response, error) {
Expand Down
27 changes: 14 additions & 13 deletions nullplatform/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,20 @@ func Provider() *schema.Provider {
},
},
ResourcesMap: map[string]*schema.Resource{
"nullplatform_account": resourceAccount(),
"nullplatform_scope": resourceScope(),
"nullplatform_service": resourceService(),
"nullplatform_link": resourceLink(),
"nullplatform_parameter": resourceParameter(),
"nullplatform_parameter_value": resourceParameterValue(),
"nullplatform_approval_action": resourceApprovalAction(),
"nullplatform_approval_policy": resourceApprovalPolicy(),
"nullplatform_notification_channel": resourceNotificationChannel(),
"nullplatform_runtime_configuration": resourceRuntimeConfiguration(),
"nullplatform_provider_config": resourceProviderConfig(),
"nullplatform_dimension": resourceDimension(),
"nullplatform_dimension_value": resourceDimensionValue(),
"nullplatform_account": resourceAccount(),
"nullplatform_scope": resourceScope(),
"nullplatform_service": resourceService(),
"nullplatform_link": resourceLink(),
"nullplatform_parameter": resourceParameter(),
"nullplatform_parameter_value": resourceParameterValue(),
"nullplatform_approval_action": resourceApprovalAction(),
"nullplatform_approval_policy": resourceApprovalPolicy(),
"nullplatform_notification_channel": resourceNotificationChannel(),
"nullplatform_runtime_configuration": resourceRuntimeConfiguration(),
"nullplatform_provider_config": resourceProviderConfig(),
"nullplatform_metadata_specification": resourceMetadataSpecification(),
"nullplatform_dimension": resourceDimension(),
"nullplatform_dimension_value": resourceDimensionValue(),
},
DataSourcesMap: map[string]*schema.Resource{
"nullplatform_scope": dataSourceScope(),
Expand Down
1 change: 1 addition & 0 deletions nullplatform/provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ func TestProvider_HasChildResources(t *testing.T) {
"nullplatform_notification_channel",
"nullplatform_runtime_configuration",
"nullplatform_provider_config",
"nullplatform_metadata_specification",
"nullplatform_dimension",
"nullplatform_dimension_value",
}
Expand Down
168 changes: 168 additions & 0 deletions nullplatform/resource_metadata_specification.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package nullplatform

import (
"context"
"encoding/json"
"fmt"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceMetadataSpecification() *schema.Resource {
return &schema.Resource{
Description: "The metadata_specification resource allows you to manage entity metadata specifications",

Create: MetadataSpecificationCreate,
Read: MetadataSpecificationRead,
Update: MetadataSpecificationUpdate,
Delete: MetadataSpecificationDelete,

Importer: &schema.ResourceImporter{
StateContext: func(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
d.Set("id", d.Id())
return []*schema.ResourceData{d}, nil
},
},

Schema: AddNRNSchema(map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Required: true,
Description: "Metadata specification name",
},
"description": {
Type: schema.TypeString,
Optional: true,
Description: "Metadata specification description",
},
"entity": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Parent entity that holds metadata information",
},
"metadata": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Description: "Entity metadata key",
},
"schema": {
Type: schema.TypeString,
Required: true,
Description: "JSON schema definition for the metadata specification",
DiffSuppressFunc: suppressEquivalentJSON,
},
}),
}
}

func MetadataSpecificationCreate(d *schema.ResourceData, m interface{}) error {
nullOps := m.(NullOps)

var nrn string
var err error
if v, ok := d.GetOk("nrn"); ok {
nrn = v.(string)
} else {
nrn, err = ConstructNRNFromComponents(d, nullOps)
if err != nil {
return fmt.Errorf("error constructing NRN: %v %s", err, nrn)
}
}

schemaJSON := d.Get("schema").(string)
var schemaMap map[string]interface{}
if err := json.Unmarshal([]byte(schemaJSON), &schemaMap); err != nil {
return fmt.Errorf("error parsing schema JSON: %v", err)
}

spec := &MetadataSpecification{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Nrn: nrn,
Entity: d.Get("entity").(string),
Metadata: d.Get("metadata").(string),
Schema: schemaMap,
}

created, err := nullOps.CreateMetadataSpecification(spec)
if err != nil {
return err
}

d.SetId(created.Id)
return MetadataSpecificationRead(d, m)
}

func MetadataSpecificationRead(d *schema.ResourceData, m interface{}) error {
nullOps := m.(NullOps)

spec, err := nullOps.GetMetadataSpecification(d.Id())
if err != nil {
return err
}

if err := d.Set("name", spec.Name); err != nil {
return err
}
if err := d.Set("description", spec.Description); err != nil {
return err
}
if err := d.Set("nrn", spec.Nrn); err != nil {
return err
}
if err := d.Set("entity", spec.Entity); err != nil {
return err
}
if err := d.Set("metadata", spec.Metadata); err != nil {
return err
}

schemaJSON, err := json.Marshal(spec.Schema)
if err != nil {
return fmt.Errorf("error serializing schema to JSON: %v", err)
}
if err := d.Set("schema", string(schemaJSON)); err != nil {
return err
}

return nil
}

func MetadataSpecificationUpdate(d *schema.ResourceData, m interface{}) error {
nullOps := m.(NullOps)

spec := &MetadataSpecification{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
}

if d.HasChange("schema") {
schemaJSON := d.Get("schema").(string)
var schemaMap map[string]interface{}
if err := json.Unmarshal([]byte(schemaJSON), &schemaMap); err != nil {
return fmt.Errorf("error parsing schema JSON: %v", err)
}
spec.Schema = schemaMap
}

_, err := nullOps.UpdateMetadataSpecification(d.Id(), spec)
if err != nil {
return err
}

return MetadataSpecificationRead(d, m)
}

func MetadataSpecificationDelete(d *schema.ResourceData, m interface{}) error {
nullOps := m.(NullOps)

err := nullOps.DeleteMetadataSpecification(d.Id())
if err != nil {
return err
}

d.SetId("")
return nil
}

0 comments on commit a758da9

Please sign in to comment.