Skip to content

Commit

Permalink
feat: set metadata.name automatically for tag_definition
Browse files Browse the repository at this point in the history
  • Loading branch information
henryde committed Nov 14, 2024
1 parent a5db81f commit 5c7398e
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 79 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,26 @@ For general information about Terraform, visit the [official website](https://ww
Please submit support questions via email to [email protected]. Support questions submitted under the Issues section of this repo will be handled on a "best effort" basis.

Feature requests can be submitted at [canny.io](https://meshcloud.canny.io).

## Local Development

To use the provider locally during development place the following in `~/.terraformrc`:

```
provider_installation {
dev_overrides {
"meshcloud/meshstack" = "<GOBIN>",
"registry.terraform.io/meshcloud/meshstack" = "<GOBIN>"
}
# For all other providers, install them directly from their origin provider
# registries as normal. If you omit this, Terraform will _only_ use
# the dev_overrides block, and so no other providers will be available.
direct {}
}
```

Replace `<GOBIN>` with the output of `go env GOBIN` or `go env GOPATH` + `/bin`.
Run `go install` to update your local provider installation.
If everything is working correctly Terraform will show a warning that dev overrides are being used.
1 change: 1 addition & 0 deletions client/tag_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/url"
)

const API_VERSION_TAG_DEFINITION = "v1"
const CONTENT_TYPE_TAG_DEFINITION = "application/vnd.meshcloud.api.meshtagdefinition.v1.hal+json"

type MeshTagDefinition struct {
Expand Down
24 changes: 11 additions & 13 deletions docs/resources/tag_definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ Manage tag definitions

```terraform
resource "meshstack_tag_definition" "example" {
metadata = {
name = "meshProject.example-key"
}
spec = {
target_kind = "meshProject"
key = "example-key"
Expand All @@ -44,21 +40,13 @@ resource "meshstack_tag_definition" "example" {

### Required

- `metadata` (Attributes) Tag definition metadata. Name of the target tag definition must be set here. (see [below for nested schema](#nestedatt--metadata))
- `spec` (Attributes) Tag definition specification. (see [below for nested schema](#nestedatt--spec))

### Read-Only

- `api_version` (String) Tag definition datatype version
- `kind` (String) meshObject type, always `meshTagDefinition`.

<a id="nestedatt--metadata"></a>
### Nested Schema for `metadata`

Required:

- `name` (String)

- `metadata` (Attributes) Tag definition metadata. Name of the target tag definition must be `target_kind.key` and will be set automatically. (see [below for nested schema](#nestedatt--metadata))

<a id="nestedatt--spec"></a>
### Nested Schema for `spec`
Expand Down Expand Up @@ -141,6 +129,16 @@ Optional:
- `default_value` (String)
- `validation_regex` (String)




<a id="nestedatt--metadata"></a>
### Nested Schema for `metadata`

Read-Only:

- `name` (String)

## Import

Import is supported using the following syntax:
Expand Down
4 changes: 0 additions & 4 deletions examples/resources/meshstack_tag_definition/resource.tf
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
resource "meshstack_tag_definition" "example" {
metadata = {
name = "meshProject.example-key"
}

spec = {
target_kind = "meshProject"
key = "example-key"
Expand Down
102 changes: 40 additions & 62 deletions internal/provider/tag_definition_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package provider
import (
"context"
"fmt"
"regexp"

"github.com/meshcloud/terraform-provider-meshstack/client"
"github.com/meshcloud/terraform-provider-meshstack/internal/modifiers/tagdefinitionmodifier"

"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault"
Expand Down Expand Up @@ -74,26 +74,17 @@ func (r *tagDefinitionResource) Configure(_ context.Context, req resource.Config
}

func (r *tagDefinitionResource) ValidateConfig(ctx context.Context, req resource.ValidateConfigRequest, resp *resource.ValidateConfigResponse) {
var config tagDefinitionCreate
var spec tagDefinitionSpec

diags := req.Config.Get(ctx, &config)
diags := req.Config.GetAttribute(ctx, path.Root("spec"), &spec)

resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

expectedName := fmt.Sprintf("%s.%s", config.Spec.TargetKind.ValueString(), config.Spec.Key.ValueString())
if config.Metadata.Name.ValueString() != expectedName {
resp.Diagnostics.AddError(
"Invalid Name",
fmt.Sprintf("<metadata.name> must be equal to <spec.target_kind>.<spec.key>. Expected: %s, Got: %s", expectedName, config.Metadata.Name.ValueString()),
)
return
}

// Validate that value_type only contains one of the value types
valueType := config.Spec.ValueType
valueType := spec.ValueType
count := 0
if valueType.String != nil {
count++
Expand Down Expand Up @@ -145,18 +136,12 @@ func (r *tagDefinitionResource) Schema(_ context.Context, _ resource.SchemaReque
},

"metadata": schema.SingleNestedAttribute{
MarkdownDescription: "Tag definition metadata. Name of the target tag definition must be set here.",
Required: true,
MarkdownDescription: "Tag definition metadata. Name of the target tag definition must be `target_kind.key` and will be set automatically.",
Computed: true,
Attributes: map[string]schema.Attribute{
"name": schema.StringAttribute{
Required: true,
Computed: true,
PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()},
Validators: []validator.String{
stringvalidator.RegexMatches(
regexp.MustCompile(`^[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+$`),
"Name must be in the format 'target_kind.key'",
),
},
},
},
},
Expand Down Expand Up @@ -266,17 +251,6 @@ func (r *tagDefinitionResource) Schema(_ context.Context, _ resource.SchemaReque
}

// These structs use Terraform types so that we can read the plan and check for unknown/null values.
type tagDefinitionCreate struct {
ApiVersion types.String `json:"apiVersion" tfsdk:"api_version"`
Kind types.String `json:"kind" tfsdk:"kind"`
Metadata tagDefinitionMetadata `json:"metadata" tfsdk:"metadata"`
Spec tagDefinitionSpec `json:"spec" tfsdk:"spec"`
}

type tagDefinitionMetadata struct {
Name types.String `json:"name" tfsdk:"name"`
}

type tagDefinitionSpec struct {
TargetKind types.String `json:"targetKind" tfsdk:"target_kind"`
Key types.String `json:"key" tfsdk:"key"`
Expand Down Expand Up @@ -328,32 +302,34 @@ type tagValueMultiSelect struct {

// Create creates the resource and sets the initial Terraform state.
func (r *tagDefinitionResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan tagDefinitionCreate
var spec tagDefinitionSpec

diags := req.Plan.Get(ctx, &plan)
diags := req.Plan.GetAttribute(ctx, path.Root("spec"), &spec)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

valueType := buildValueType(plan.Spec.ValueType)
valueType := buildValueType(spec.ValueType)

name := spec.TargetKind.ValueString() + "." + spec.Key.ValueString()

create := client.MeshTagDefinition{
ApiVersion: plan.ApiVersion.ValueString(),
ApiVersion: client.API_VERSION_TAG_DEFINITION,
Kind: "meshTagDefinition",
Metadata: client.MeshTagDefinitionMetadata{
Name: plan.Metadata.Name.ValueString(),
Name: name,
},
Spec: client.MeshTagDefinitionSpec{
TargetKind: plan.Spec.TargetKind.ValueString(),
Key: plan.Spec.Key.ValueString(),
TargetKind: spec.TargetKind.ValueString(),
Key: spec.Key.ValueString(),
ValueType: valueType,
Description: plan.Spec.Description.ValueString(),
DisplayName: plan.Spec.DisplayName.ValueString(),
SortOrder: plan.Spec.SortOrder.ValueInt64(),
Mandatory: plan.Spec.Mandatory.ValueBool(),
Immutable: plan.Spec.Immutable.ValueBool(),
Restricted: plan.Spec.Restricted.ValueBool(),
Description: spec.Description.ValueString(),
DisplayName: spec.DisplayName.ValueString(),
SortOrder: spec.SortOrder.ValueInt64(),
Mandatory: spec.Mandatory.ValueBool(),
Immutable: spec.Immutable.ValueBool(),
Restricted: spec.Restricted.ValueBool(),
},
}

Expand Down Expand Up @@ -426,15 +402,16 @@ func buildValueType(valueType tagDefinitionValueType) client.MeshTagDefinitionVa

// Read refreshes the Terraform state with the latest data.
func (r *tagDefinitionResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var state client.MeshTagDefinition
var spec tagDefinitionSpec

diags := req.State.Get(ctx, &state)
diags := req.State.GetAttribute(ctx, path.Root("spec"), &spec)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

tagDefinition, err := r.client.ReadTagDefinition(state.Metadata.Name)
name := spec.TargetKind.ValueString() + "." + spec.Key.ValueString()
tagDefinition, err := r.client.ReadTagDefinition(name)
if err != nil {
resp.Diagnostics.AddError("Unable to read tag definition", err.Error())
}
Expand All @@ -449,32 +426,33 @@ func (r *tagDefinitionResource) Read(ctx context.Context, req resource.ReadReque

// Update updates the resource and sets the updated Terraform state on success.
func (r *tagDefinitionResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var plan tagDefinitionCreate
var spec tagDefinitionSpec

diags := req.Plan.Get(ctx, &plan)
diags := req.Plan.GetAttribute(ctx, path.Root("spec"), &spec)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}

valueType := buildValueType(plan.Spec.ValueType)
valueType := buildValueType(spec.ValueType)
name := spec.TargetKind.ValueString() + "." + spec.Key.ValueString()

update := client.MeshTagDefinition{
ApiVersion: plan.ApiVersion.ValueString(),
ApiVersion: client.API_VERSION_TAG_DEFINITION,
Kind: "meshTagDefinition",
Metadata: client.MeshTagDefinitionMetadata{
Name: plan.Metadata.Name.ValueString(),
Name: name,
},
Spec: client.MeshTagDefinitionSpec{
TargetKind: plan.Spec.TargetKind.ValueString(),
Key: plan.Spec.Key.ValueString(),
TargetKind: spec.TargetKind.ValueString(),
Key: spec.Key.ValueString(),
ValueType: valueType,
Description: plan.Spec.Description.ValueString(),
DisplayName: plan.Spec.DisplayName.ValueString(),
SortOrder: plan.Spec.SortOrder.ValueInt64(),
Mandatory: plan.Spec.Mandatory.ValueBool(),
Immutable: plan.Spec.Immutable.ValueBool(),
Restricted: plan.Spec.Restricted.ValueBool(),
Description: spec.Description.ValueString(),
DisplayName: spec.DisplayName.ValueString(),
SortOrder: spec.SortOrder.ValueInt64(),
Mandatory: spec.Mandatory.ValueBool(),
Immutable: spec.Immutable.ValueBool(),
Restricted: spec.Restricted.ValueBool(),
},
}

Expand Down

0 comments on commit 5c7398e

Please sign in to comment.