From 30c49a05edab1dc6247198da89177578f2d2522f Mon Sep 17 00:00:00 2001 From: bwJuniper <98770420+bwJuniper@users.noreply.github.com> Date: Mon, 22 Jul 2024 21:01:20 +0200 Subject: [PATCH 1/6] fixed ra_group items, examples, make docs --- apstra/blueprint/freeform_ra_group.go | 167 ++++++++++++++ apstra/datasource_freeform_ra_group.go | 101 +++++++++ apstra/export_test.go | 1 + apstra/provider.go | 2 + apstra/resource_freeform_ra_group.go | 211 ++++++++++++++++++ ...urce_freeform_ra_group_integration_test.go | 173 ++++++++++++++ docs/data-sources/freeform_ra_group.md | 74 ++++++ docs/resources/freeform_ra_group.md | 74 ++++++ .../apstra_freeform_ra_group/example.tf | 37 +++ .../apstra_freeform_ra_group/example.tf | 36 +++ go.mod | 2 +- go.sum | 4 +- 12 files changed, 879 insertions(+), 3 deletions(-) create mode 100644 apstra/blueprint/freeform_ra_group.go create mode 100644 apstra/datasource_freeform_ra_group.go create mode 100644 apstra/resource_freeform_ra_group.go create mode 100644 apstra/resource_freeform_ra_group_integration_test.go create mode 100644 docs/data-sources/freeform_ra_group.md create mode 100644 docs/resources/freeform_ra_group.md create mode 100644 examples/data-sources/apstra_freeform_ra_group/example.tf create mode 100644 examples/resources/apstra_freeform_ra_group/example.tf diff --git a/apstra/blueprint/freeform_ra_group.go b/apstra/blueprint/freeform_ra_group.go new file mode 100644 index 00000000..c5a0e958 --- /dev/null +++ b/apstra/blueprint/freeform_ra_group.go @@ -0,0 +1,167 @@ +package blueprint + +import ( + "context" + "encoding/json" + "fmt" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "regexp" + + "github.com/Juniper/apstra-go-sdk/apstra" + "github.com/Juniper/terraform-provider-apstra/apstra/utils" + "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + dataSourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + resourceSchema "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +//{ +// "parent_id": "string", +// "label": "string", +// "tags": [ +// "string" +// ], +// "data": {} +//} + +type FreeformRaGroup struct { + BlueprintId types.String `tfsdk:"blueprint_id"` + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + ParentId types.String `tfsdk:"parent_id"` + Tags types.Set `tfsdk:"tags"` + Data jsontypes.Normalized `tfsdk:"data"` + GeneratorId types.String `tfsdk:"generator_id"` +} + +func (o FreeformRaGroup) DataSourceAttributes() map[string]dataSourceSchema.Attribute { + return map[string]dataSourceSchema.Attribute{ + "blueprint_id": dataSourceSchema.StringAttribute{ + MarkdownDescription: "Apstra Blueprint ID. Used to identify " + + "the Blueprint where the Resource Allocation Group lives.", + Required: true, + Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, + }, + "id": dataSourceSchema.StringAttribute{ + MarkdownDescription: "Populate this field to look up the Freeform Allocation Group by ID. Required when `name` is omitted.", + Optional: true, + Computed: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + stringvalidator.ExactlyOneOf(path.Expressions{ + path.MatchRelative(), + path.MatchRoot("name"), + }...), + }, + }, + "name": dataSourceSchema.StringAttribute{ + MarkdownDescription: "Populate this field to look up the Allocation Group by Name. Required when `id` is omitted.", + Optional: true, + Computed: true, + Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, + }, + "parent_id": dataSourceSchema.StringAttribute{ + MarkdownDescription: "ID of the group node that is present as a parent of the current one in " + + "parent/children relationship." + + " If group is a top-level one, then 'parent_id' is equal to None/null.", + Computed: true, + }, + "tags": dataSourceSchema.SetAttribute{ + MarkdownDescription: "Set of Tag labels", + ElementType: types.StringType, + Computed: true, + }, + "data": dataSourceSchema.StringAttribute{ + MarkdownDescription: "Arbitrary key-value mapping that is useful in a context of this group. " + + "For example, you can store some VRF-related data there or add properties that are useful " + + "only in context of resource allocation, but not systems or interfaces.", + Computed: true, + CustomType: jsontypes.NormalizedType{}, + }, + "generator_id": dataSourceSchema.StringAttribute{ + MarkdownDescription: "ID of the group generator that created the group.", + Computed: true, + }, + } +} + +func (o FreeformRaGroup) ResourceAttributes() map[string]resourceSchema.Attribute { + return map[string]resourceSchema.Attribute{ + "blueprint_id": resourceSchema.StringAttribute{ + MarkdownDescription: "Apstra Blueprint ID.", + Required: true, + Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "id": resourceSchema.StringAttribute{ + MarkdownDescription: "ID of the Freeform Resource Allocation Group.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, + "name": resourceSchema.StringAttribute{ + MarkdownDescription: "Freeform Resource Allocation Group name as shown in the Web UI.", + Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexp.MustCompile("^[a-zA-Z0-9.-_]+$"), "name may consist only of the following characters : a-zA-Z0-9.-_")}, + }, + "parent_id": resourceSchema.StringAttribute{ + MarkdownDescription: fmt.Sprintf("Type of the System. Must be one of `%s` or `%s`", apstra.SystemTypeInternal, apstra.SystemTypeExternal), + Optional: true, + Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, + }, + "tags": resourceSchema.SetAttribute{ + MarkdownDescription: "Set of Tag labels", + ElementType: types.StringType, + Optional: true, + Validators: []validator.Set{setvalidator.SizeAtLeast(1)}, + }, + "data": resourceSchema.StringAttribute{ + MarkdownDescription: "Arbitrary key-value mapping that is useful in a context of this group. " + + "For example, you can store some VRF-related data there or add properties that are useful" + + " only in context of resource allocation, but not systems or interfaces. ", + Optional: true, + Computed: true, + Default: stringdefault.StaticString("{}"), + CustomType: jsontypes.NormalizedType{}, + }, + "generator_id": resourceSchema.StringAttribute{ + MarkdownDescription: "ID of the Generator that created Resource Allocation Group, " + + "always `null` because groups created with this resource were not generated.", + Computed: true, + }, + } +} + +func (o *FreeformRaGroup) Request(ctx context.Context, diags *diag.Diagnostics) *apstra.FreeformRaGroupData { + var tags []string + diags.Append(o.Tags.ElementsAs(ctx, &tags, false)...) + if diags.HasError() { + return nil + } + + return &apstra.FreeformRaGroupData{ + ParentId: (*apstra.ObjectId)(o.ParentId.ValueStringPointer()), + Label: o.Name.ValueString(), + Tags: tags, + Data: json.RawMessage(o.Data.ValueString()), + GeneratorId: (*apstra.ObjectId)(o.GeneratorId.ValueStringPointer()), + } +} + +func (o *FreeformRaGroup) LoadApiData(ctx context.Context, in *apstra.FreeformRaGroupData, diags *diag.Diagnostics) { + o.Name = types.StringValue(in.Label) + if in.ParentId != nil { + o.ParentId = types.StringValue(string(*in.ParentId)) + } + + o.Data = jsontypes.NewNormalizedValue(string(in.Data)) + o.Tags = utils.SetValueOrNull(ctx, types.StringType, in.Tags, diags) // safe to ignore diagnostic here + o.GeneratorId = types.StringPointerValue((*string)(in.GeneratorId)) +} diff --git a/apstra/datasource_freeform_ra_group.go b/apstra/datasource_freeform_ra_group.go new file mode 100644 index 00000000..5d01ffc7 --- /dev/null +++ b/apstra/datasource_freeform_ra_group.go @@ -0,0 +1,101 @@ +package tfapstra + +import ( + "context" + "fmt" + + "github.com/Juniper/apstra-go-sdk/apstra" + "github.com/Juniper/terraform-provider-apstra/apstra/blueprint" + "github.com/Juniper/terraform-provider-apstra/apstra/utils" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var ( + _ datasource.DataSourceWithConfigure = &dataSourceFreeformRaGroup{} + _ datasourceWithSetFfBpClientFunc = &dataSourceFreeformRaGroup{} +) + +type dataSourceFreeformRaGroup struct { + getBpClientFunc func(context.Context, string) (*apstra.FreeformClient, error) +} + +func (o *dataSourceFreeformRaGroup) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_freeform_ra_group" +} + +func (o *dataSourceFreeformRaGroup) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + configureDataSource(ctx, o, req, resp) +} + +func (o *dataSourceFreeformRaGroup) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: docCategoryFreeform + "This data source provides details of a specific Freeform Resource Allocation Group.\n\n" + + "At least one optional attribute is required.", + Attributes: blueprint.FreeformRaGroup{}.DataSourceAttributes(), + } +} + +func (o *dataSourceFreeformRaGroup) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config blueprint.FreeformRaGroup + resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) + if resp.Diagnostics.HasError() { + return + } + + // get a client for the Freeform reference design + bp, err := o.getBpClientFunc(ctx, config.BlueprintId.ValueString()) + if err != nil { + if utils.IsApstra404(err) { + resp.Diagnostics.AddError(fmt.Sprintf("blueprint %s not found", config.BlueprintId), err.Error()) + return + } + resp.Diagnostics.AddError("failed to create blueprint client", err.Error()) + return + } + + var api *apstra.FreeformRaGroup + switch { + case !config.Id.IsNull(): + api, err = bp.GetRaGroup(ctx, apstra.ObjectId(config.Id.ValueString())) + if utils.IsApstra404(err) { + resp.Diagnostics.AddAttributeError( + path.Root("id"), + "Freeform Resource Allocation Group not found", + fmt.Sprintf("Freeform Resource Allocation Group with ID %s not found", config.Id)) + return + } + case !config.Name.IsNull(): + api, err = bp.GetRaGroupByName(ctx, config.Name.ValueString()) + if utils.IsApstra404(err) { + resp.Diagnostics.AddAttributeError( + path.Root("name"), + "Freeform Resource Allocation Group not found", + fmt.Sprintf("Freeform resource allocation group with Name %s not found", config.Name)) + return + } + } + if err != nil { + resp.Diagnostics.AddError("failed reading Freeform Resource Allocation Group", err.Error()) + return + } + if api.Data == nil { + resp.Diagnostics.AddError("failed reading Freeform Resource Allocation Group", "api response has no payload") + return + } + + config.Id = types.StringValue(api.Id.String()) + config.LoadApiData(ctx, api.Data, &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + + // Set state + resp.Diagnostics.Append(resp.State.Set(ctx, &config)...) +} + +func (o *dataSourceFreeformRaGroup) setBpClientFunc(f func(context.Context, string) (*apstra.FreeformClient, error)) { + o.getBpClientFunc = f +} diff --git a/apstra/export_test.go b/apstra/export_test.go index 658d31c6..ddd61276 100644 --- a/apstra/export_test.go +++ b/apstra/export_test.go @@ -14,6 +14,7 @@ var ( ResourceFreeformLink = resourceFreeformLink{} ResourceFreeformSystem = resourceFreeformSystem{} ResourceFreeformPropertySet = resourceFreeformPropertySet{} + ResourceFreeformRaGroup = resourceFreeformRaGroup{} ResourceIpv4Pool = resourceIpv4Pool{} ResourceTemplatePodBased = resourceTemplatePodBased{} ResourceTemplateCollapsed = resourceTemplateCollapsed{} diff --git a/apstra/provider.go b/apstra/provider.go index 815157a6..2eb6c26d 100644 --- a/apstra/provider.go +++ b/apstra/provider.go @@ -551,6 +551,7 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource func() datasource.DataSource { return &dataSourceFreeformConfigTemplate{} }, func() datasource.DataSource { return &dataSourceFreeformLink{} }, func() datasource.DataSource { return &dataSourceFreeformPropertySet{} }, + func() datasource.DataSource { return &dataSourceFreeformRaGroup{} }, func() datasource.DataSource { return &dataSourceFreeformSystem{} }, func() datasource.DataSource { return &dataSourceIntegerPool{} }, func() datasource.DataSource { return &dataSourceInterfacesByLinkTag{} }, @@ -609,6 +610,7 @@ func (p *Provider) Resources(_ context.Context) []func() resource.Resource { func() resource.Resource { return &resourceFreeformConfigTemplate{} }, func() resource.Resource { return &resourceFreeformLink{} }, func() resource.Resource { return &resourceFreeformPropertySet{} }, + func() resource.Resource { return &resourceFreeformRaGroup{} }, func() resource.Resource { return &resourceFreeformSystem{} }, func() resource.Resource { return &resourceIntegerPool{} }, func() resource.Resource { return &resourceInterfaceMap{} }, diff --git a/apstra/resource_freeform_ra_group.go b/apstra/resource_freeform_ra_group.go new file mode 100644 index 00000000..8e1ef2a7 --- /dev/null +++ b/apstra/resource_freeform_ra_group.go @@ -0,0 +1,211 @@ +package tfapstra + +import ( + "context" + "fmt" + "github.com/Juniper/apstra-go-sdk/apstra" + "github.com/Juniper/terraform-provider-apstra/apstra/blueprint" + "github.com/Juniper/terraform-provider-apstra/apstra/utils" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var ( + _ resource.ResourceWithConfigure = &resourceFreeformRaGroup{} + _ resourceWithSetFfBpClientFunc = &resourceFreeformRaGroup{} + _ resourceWithSetBpLockFunc = &resourceFreeformRaGroup{} +) + +type resourceFreeformRaGroup struct { + getBpClientFunc func(context.Context, string) (*apstra.FreeformClient, error) + lockFunc func(context.Context, string) error +} + +func (o *resourceFreeformRaGroup) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_freeform_ra_group" +} + +func (o *resourceFreeformRaGroup) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + configureResource(ctx, o, req, resp) +} + +func (o *resourceFreeformRaGroup) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + MarkdownDescription: docCategoryFreeform + "This resource creates a Resource Allocation Group in a Freeform Blueprint.", + Attributes: blueprint.FreeformRaGroup{}.ResourceAttributes(), + } +} + +func (o *resourceFreeformRaGroup) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // Retrieve values from plan + var plan blueprint.FreeformRaGroup + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + // get a client for the Freeform reference design + bp, err := o.getBpClientFunc(ctx, plan.BlueprintId.ValueString()) + if err != nil { + if utils.IsApstra404(err) { + resp.Diagnostics.AddError(fmt.Sprintf("blueprint %s not found", plan.BlueprintId), err.Error()) + return + } + resp.Diagnostics.AddError("failed to create blueprint client", err.Error()) + return + } + + // Lock the blueprint mutex. + err = o.lockFunc(ctx, plan.BlueprintId.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("error locking blueprint %q mutex", plan.BlueprintId.ValueString()), + err.Error()) + return + } + + // Convert the plan into an API Request + request := plan.Request(ctx, &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + + id, err := bp.CreateRaGroup(ctx, request) + if err != nil { + resp.Diagnostics.AddError("error creating new Resource Allocation Group", err.Error()) + return + } + + plan.Id = types.StringValue(id.String()) + plan.GeneratorId = types.StringNull() + + // set state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (o *resourceFreeformRaGroup) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state blueprint.FreeformRaGroup + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + // get a client for the Freeform reference design + bp, err := o.getBpClientFunc(ctx, state.BlueprintId.ValueString()) + if err != nil { + if utils.IsApstra404(err) { + resp.Diagnostics.AddError(fmt.Sprintf("blueprint %s not found", state.BlueprintId), err.Error()) + return + } + resp.Diagnostics.AddError("failed to create blueprint client", err.Error()) + return + } + + api, err := bp.GetRaGroup(ctx, apstra.ObjectId(state.Id.ValueString())) + if err != nil { + if utils.IsApstra404(err) { + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError("Error retrieving Freeform Resource Allocation Group", err.Error()) + return + } + + state.LoadApiData(ctx, api.Data, &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + + // Set state + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (o *resourceFreeformRaGroup) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + // Get plan values + var plan blueprint.FreeformRaGroup + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + // get a client for the Freeform reference design + bp, err := o.getBpClientFunc(ctx, plan.BlueprintId.ValueString()) + if err != nil { + if utils.IsApstra404(err) { + resp.Diagnostics.AddError(fmt.Sprintf("blueprint %s not found", plan.BlueprintId), err.Error()) + return + } + resp.Diagnostics.AddError("failed to create blueprint client", err.Error()) + return + } + + // Lock the blueprint mutex. + err = o.lockFunc(ctx, plan.BlueprintId.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("error locking blueprint %q mutex", plan.BlueprintId.ValueString()), + err.Error()) + return + } + + request := plan.Request(ctx, &resp.Diagnostics) + if resp.Diagnostics.HasError() { + return + } + + // Update Config Template + err = bp.UpdateRaGroup(ctx, apstra.ObjectId(plan.Id.ValueString()), request) + if err != nil { + resp.Diagnostics.AddError("error updating Freeform Resource Allocation Group", err.Error()) + return + } + plan.GeneratorId = types.StringNull() + // set state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (o *resourceFreeformRaGroup) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state blueprint.FreeformRaGroup + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + // get a client for the Freeform reference design + bp, err := o.getBpClientFunc(ctx, state.BlueprintId.ValueString()) + if err != nil { + if utils.IsApstra404(err) { + return // 404 is okay + } + resp.Diagnostics.AddError("failed to create blueprint client", err.Error()) + return + } + + // Lock the blueprint mutex. + err = o.lockFunc(ctx, state.BlueprintId.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + fmt.Sprintf("error locking blueprint %q mutex", state.BlueprintId.ValueString()), + err.Error()) + return + } + + // Delete Config Template by calling API + err = bp.DeleteRaGroup(ctx, apstra.ObjectId(state.Id.ValueString())) + if err != nil { + if utils.IsApstra404(err) { + return // 404 is okay + } + resp.Diagnostics.AddError("error deleting Freeform Resource Allocation Group", err.Error()) + return + } +} + +func (o *resourceFreeformRaGroup) setBpClientFunc(f func(context.Context, string) (*apstra.FreeformClient, error)) { + o.getBpClientFunc = f +} + +func (o *resourceFreeformRaGroup) setBpLockFunc(f func(context.Context, string) error) { + o.lockFunc = f +} diff --git a/apstra/resource_freeform_ra_group_integration_test.go b/apstra/resource_freeform_ra_group_integration_test.go new file mode 100644 index 00000000..9c5e90ea --- /dev/null +++ b/apstra/resource_freeform_ra_group_integration_test.go @@ -0,0 +1,173 @@ +//go:build integration + +package tfapstra_test + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + "strconv" + "testing" + + tfapstra "github.com/Juniper/terraform-provider-apstra/apstra" + testutils "github.com/Juniper/terraform-provider-apstra/apstra/test_utils" + "github.com/hashicorp/go-version" + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +const ( + resourceFreeformRaGroupHcl = ` +resource %q %q { + blueprint_id = %q + name = %q + tags = %s + data = %s +} +` +) + +type resourceFreeformRaGroup struct { + blueprintId string + name string + tags []string + data json.RawMessage +} + +func (o resourceFreeformRaGroup) render(rType, rName string) string { + data := "null" + if o.data != nil { + data = fmt.Sprintf("%q", string(o.data)) + } + return fmt.Sprintf(resourceFreeformRaGroupHcl, + rType, rName, + o.blueprintId, + o.name, + stringSetOrNull(o.tags), + data, + ) +} + +func (o resourceFreeformRaGroup) testChecks(t testing.TB, rType, rName string) testChecks { + result := newTestChecks(rType + "." + rName) + + // required and computed attributes can always be checked + result.append(t, "TestCheckResourceAttrSet", "id") + result.append(t, "TestCheckResourceAttr", "blueprint_id", o.blueprintId) + result.append(t, "TestCheckResourceAttr", "name", o.name) + if len(o.tags) > 0 { + result.append(t, "TestCheckResourceAttr", "tags.#", strconv.Itoa(len(o.tags))) + for _, tag := range o.tags { + result.append(t, "TestCheckTypeSetElemAttr", "tags.*", tag) + } + } + if len(o.data) > 0 { + result.append(t, "TestCheckResourceAttr", "data", string(o.data)) + } + return result +} + +func TestResourceFreeformRaGroup(t *testing.T) { + ctx := context.Background() + client := testutils.GetTestClient(t, ctx) + apiVersion := version.Must(version.NewVersion(client.ApiVersion())) + + // create a blueprint + bp := testutils.FfBlueprintA(t, ctx) + + type testStep struct { + config resourceFreeformRaGroup + } + type testCase struct { + apiVersionConstraints version.Constraints + steps []testStep + } + + testCases := map[string]testCase{ + "start_with_no_tags": { + steps: []testStep{ + { + config: resourceFreeformRaGroup{ + blueprintId: bp.Id().String(), + name: acctest.RandString(6), + }, + }, + { + config: resourceFreeformRaGroup{ + blueprintId: bp.Id().String(), + name: acctest.RandString(6), + tags: randomStrings(rand.Intn(10)+2, 6), + }, + }, + { + config: resourceFreeformRaGroup{ + blueprintId: bp.Id().String(), + name: acctest.RandString(6), + data: randomJson(t, 6, 12, 4), + }, + }, + }, + }, + "start_with_tags": { + steps: []testStep{ + { + config: resourceFreeformRaGroup{ + blueprintId: bp.Id().String(), + name: acctest.RandString(6), + tags: randomStrings(rand.Intn(10)+2, 6), + data: randomJson(t, 6, 12, 4), + }, + }, + { + config: resourceFreeformRaGroup{ + blueprintId: bp.Id().String(), + name: acctest.RandString(6), + data: randomJson(t, 6, 12, 5), + }, + }, + { + config: resourceFreeformRaGroup{ + blueprintId: bp.Id().String(), + name: acctest.RandString(6), + tags: randomStrings(rand.Intn(10)+2, 6), + }, + }, + }, + }, + } + + resourceType := tfapstra.ResourceName(ctx, &tfapstra.ResourceFreeformRaGroup) + + for tName, tCase := range testCases { + tName, tCase := tName, tCase + t.Run(tName, func(t *testing.T) { + t.Parallel() + if !tCase.apiVersionConstraints.Check(apiVersion) { + t.Skipf("test case %s requires Apstra %s", tName, tCase.apiVersionConstraints.String()) + } + + steps := make([]resource.TestStep, len(tCase.steps)) + for i, step := range tCase.steps { + config := step.config.render(resourceType, tName) + checks := step.config.testChecks(t, resourceType, tName) + + chkLog := checks.string() + stepName := fmt.Sprintf("test case %q step %d", tName, i+1) + + t.Logf("\n// ------ begin config for %s ------\n%s// -------- end config for %s ------\n\n", stepName, config, stepName) + t.Logf("\n// ------ begin checks for %s ------\n%s// -------- end checks for %s ------\n\n", stepName, chkLog, stepName) + + steps[i] = resource.TestStep{ + Config: insecureProviderConfigHCL + config, + Check: resource.ComposeAggregateTestCheckFunc(checks.checks...), + } + } + + resource.Test(t, resource.TestCase{ + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: steps, + }) + }) + } +} diff --git a/docs/data-sources/freeform_ra_group.md b/docs/data-sources/freeform_ra_group.md new file mode 100644 index 00000000..e195d734 --- /dev/null +++ b/docs/data-sources/freeform_ra_group.md @@ -0,0 +1,74 @@ +--- +page_title: "apstra_freeform_ra_group Data Source - terraform-provider-apstra" +subcategory: "Reference Design: Freeform" +description: |- + This data source provides details of a specific Freeform Resource Allocation Group. + At least one optional attribute is required. +--- + +# apstra_freeform_ra_group (Data Source) + +This data source provides details of a specific Freeform Resource Allocation Group. + +At least one optional attribute is required. + + +## Example Usage + +```terraform +# This example defines a Freeform Resource Allocation Group in a blueprint + +resource "apstra_freeform_ra_group" "test" { + blueprint_id = "freeform_blueprint-d8c1fabf" + name = "test_ra_group_fizz" + tags = ["a", "b", "c"] + data = jsonencode({ + foo = "bar" + clown = 2 + }) +} + +# here we retrieve the freeform ra_group + +data "apstra_freeform_ra_group" "test" { + blueprint_id = "043c5787-66e8-41c7-8925-c7e52fbe6e32" + id = apstra_freeform_ra_group.test.id +} + +# here we build an output bock to display it + +output "test_ra_group_out" {value = data.apstra_freeform_ra_group.test} + +//test_ra_group_out = { +// "blueprint_id" = "043c5787-66e8-41c7-8925-c7e52fbe6e32" +// "data" = "{\"clown\": 2, \"foo\": \"bar\"}" +// "generator_id" = tostring(null) +// "id" = "98ubU5cuRj7WsT159L4" +// "name" = "test_ra_group_fizz" +// "parent_id" = tostring(null) +// "tags" = toset([ +// "a", +// "b", +// "c", +// ]) +//} +``` + + +## Schema + +### Required + +- `blueprint_id` (String) Apstra Blueprint ID. Used to identify the Blueprint where the Resource Allocation Group lives. + +### Optional + +- `id` (String) Populate this field to look up the Freeform Allocation Group by ID. Required when `name` is omitted. +- `name` (String) Populate this field to look up the Allocation Group by Name. Required when `id` is omitted. + +### Read-Only + +- `data` (String) Arbitrary key-value mapping that is useful in a context of this group. For example, you can store some VRF-related data there or add properties that are useful only in context of resource allocation, but not systems or interfaces. +- `generator_id` (String) ID of the group generator that created the group. +- `parent_id` (String) ID of the group node that is present as a parent of the current one in parent/children relationship. If group is a top-level one, then 'parent_id' is equal to None/null. +- `tags` (Set of String) Set of Tag labels diff --git a/docs/resources/freeform_ra_group.md b/docs/resources/freeform_ra_group.md new file mode 100644 index 00000000..d8ba9f00 --- /dev/null +++ b/docs/resources/freeform_ra_group.md @@ -0,0 +1,74 @@ +--- +page_title: "apstra_freeform_ra_group Resource - terraform-provider-apstra" +subcategory: "Reference Design: Freeform" +description: |- + This resource creates a Resource Allocation Group in a Freeform Blueprint. +--- + +# apstra_freeform_ra_group (Resource) + +This resource creates a Resource Allocation Group in a Freeform Blueprint. + + +## Example Usage + +```terraform +# This example defines a Freeform Resource Allocation Group in a blueprint + +resource "apstra_freeform_ra_group" "test" { + blueprint_id = "freeform_blueprint-d8c1fabf" + name = "test_ra_group_fizz" + tags = ["a", "b", "c"] + data = jsonencode({ + foo = "bar" + clown = 2 + }) +} + +# here we retrieve the freeform ra_group + +data "apstra_freeform_ra_group" "test" { + blueprint_id = "043c5787-66e8-41c7-8925-c7e52fbe6e32" + id = apstra_freeform_ra_group.test.id +} + +# here we build an output bock to display it + +output "test_ra_out" {value = data.apstra_freeform_ra_group.test} + +//test_ra_out = { +// "blueprint_id" = "043c5787-66e8-41c7-8925-c7e52fbe6e32" +// "data" = "{\"clown\": 2, \"foo\": \"bar\"}" +// "generator_id" = tostring(null) +// "id" = "98ubU5cuRj7WsT159L4" +// "name" = "test_ra_group_fizz" +// "parent_id" = tostring(null) +// "tags" = toset([ +// "a", +// "b", +// "c", +// ]) +//} +``` + + +## Schema + +### Required + +- `blueprint_id` (String) Apstra Blueprint ID. +- `name` (String) Freeform Resource Allocation Group name as shown in the Web UI. + +### Optional + +- `data` (String) Arbitrary key-value mapping that is useful in a context of this group. For example, you can store some VRF-related data there or add properties that are useful only in context of resource allocation, but not systems or interfaces. +- `parent_id` (String) Type of the System. Must be one of `internal` or `external` +- `tags` (Set of String) Set of Tag labels + +### Read-Only + +- `generator_id` (String) ID of the Generator that created Resource Allocation Group, always `null` because groups created with this resource were not generated. +- `id` (String) ID of the Freeform Resource Allocation Group. + + + diff --git a/examples/data-sources/apstra_freeform_ra_group/example.tf b/examples/data-sources/apstra_freeform_ra_group/example.tf new file mode 100644 index 00000000..218aa8f3 --- /dev/null +++ b/examples/data-sources/apstra_freeform_ra_group/example.tf @@ -0,0 +1,37 @@ +# This example defines a Freeform Resource Allocation Group in a blueprint + +resource "apstra_freeform_ra_group" "test" { + blueprint_id = "freeform_blueprint-d8c1fabf" + name = "test_ra_group_fizz" + tags = ["a", "b", "c"] + data = jsonencode({ + foo = "bar" + clown = 2 + }) +} + +# here we retrieve the freeform ra_group + +data "apstra_freeform_ra_group" "test" { + blueprint_id = "043c5787-66e8-41c7-8925-c7e52fbe6e32" + id = apstra_freeform_ra_group.test.id +} + +# here we build an output bock to display it + +output "test_ra_group_out" {value = data.apstra_freeform_ra_group.test} + +//test_ra_group_out = { +// "blueprint_id" = "043c5787-66e8-41c7-8925-c7e52fbe6e32" +// "data" = "{\"clown\": 2, \"foo\": \"bar\"}" +// "generator_id" = tostring(null) +// "id" = "98ubU5cuRj7WsT159L4" +// "name" = "test_ra_group_fizz" +// "parent_id" = tostring(null) +// "tags" = toset([ +// "a", +// "b", +// "c", +// ]) +//} + diff --git a/examples/resources/apstra_freeform_ra_group/example.tf b/examples/resources/apstra_freeform_ra_group/example.tf new file mode 100644 index 00000000..a40fef63 --- /dev/null +++ b/examples/resources/apstra_freeform_ra_group/example.tf @@ -0,0 +1,36 @@ +# This example defines a Freeform Resource Allocation Group in a blueprint + +resource "apstra_freeform_ra_group" "test" { + blueprint_id = "freeform_blueprint-d8c1fabf" + name = "test_ra_group_fizz" + tags = ["a", "b", "c"] + data = jsonencode({ + foo = "bar" + clown = 2 + }) +} + +# here we retrieve the freeform ra_group + +data "apstra_freeform_ra_group" "test" { + blueprint_id = "043c5787-66e8-41c7-8925-c7e52fbe6e32" + id = apstra_freeform_ra_group.test.id +} + +# here we build an output bock to display it + +output "test_ra_out" {value = data.apstra_freeform_ra_group.test} + +//test_ra_out = { +// "blueprint_id" = "043c5787-66e8-41c7-8925-c7e52fbe6e32" +// "data" = "{\"clown\": 2, \"foo\": \"bar\"}" +// "generator_id" = tostring(null) +// "id" = "98ubU5cuRj7WsT159L4" +// "name" = "test_ra_group_fizz" +// "parent_id" = tostring(null) +// "tags" = toset([ +// "a", +// "b", +// "c", +// ]) +//} diff --git a/go.mod b/go.mod index b76ba5c5..2bb97d17 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ go 1.22.5 require ( github.com/IBM/netaddr v1.5.0 - github.com/Juniper/apstra-go-sdk v0.0.0-20240716232834-1bab0a8d9e68 + github.com/Juniper/apstra-go-sdk v0.0.0-20240722155513-01f6e5e4e91a github.com/apparentlymart/go-cidr v1.1.0 github.com/chrismarget-j/go-licenses v0.0.0-20240224210557-f22f3e06d3d4 github.com/google/go-cmp v0.6.0 diff --git a/go.sum b/go.sum index 5d490fa9..1765f45d 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,8 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/IBM/netaddr v1.5.0 h1:IJlFZe1+nFs09TeMB/HOP4+xBnX2iM/xgiDOgZgTJq0= github.com/IBM/netaddr v1.5.0/go.mod h1:DDBPeYgbFzoXHjSz9Jwk7K8wmWV4+a/Kv0LqRnb8we4= -github.com/Juniper/apstra-go-sdk v0.0.0-20240716232834-1bab0a8d9e68 h1:7IIlWVoCJPPAazUdL522E2TJ40OKJ+dTKKV1If/M5Qg= -github.com/Juniper/apstra-go-sdk v0.0.0-20240716232834-1bab0a8d9e68/go.mod h1:Xwj3X8v/jRZWv28o6vQAqD4lz2JmzaSYLZ2ch1SS89w= +github.com/Juniper/apstra-go-sdk v0.0.0-20240722155513-01f6e5e4e91a h1:x4OFdv7+++KbErpr7QSdR0tnTQbzkXSwt+hlX0Ug/bY= +github.com/Juniper/apstra-go-sdk v0.0.0-20240722155513-01f6e5e4e91a/go.mod h1:Xwj3X8v/jRZWv28o6vQAqD4lz2JmzaSYLZ2ch1SS89w= github.com/Kunde21/markdownfmt/v3 v3.1.0 h1:KiZu9LKs+wFFBQKhrZJrFZwtLnCCWJahL+S+E/3VnM0= github.com/Kunde21/markdownfmt/v3 v3.1.0/go.mod h1:tPXN1RTyOzJwhfHoon9wUr4HGYmWgVxSQN6VBJDkrVc= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= From b5adbd83704d4d57e596898c99c5fb74610e624e Mon Sep 17 00:00:00 2001 From: Chris Marget Date: Mon, 22 Jul 2024 17:26:29 -0400 Subject: [PATCH 2/6] 735 review --- apstra/blueprint/freeform_ra_group.go | 95 +++++++++---------- apstra/resource_freeform_ra_group.go | 4 +- docs/data-sources/freeform_ra_group.md | 13 +-- docs/resources/freeform_ra_group.md | 13 +-- .../apstra_freeform_ra_group/example.tf | 6 -- .../apstra_freeform_ra_group/example.tf | 6 -- 6 files changed, 52 insertions(+), 85 deletions(-) diff --git a/apstra/blueprint/freeform_ra_group.go b/apstra/blueprint/freeform_ra_group.go index c5a0e958..b426118d 100644 --- a/apstra/blueprint/freeform_ra_group.go +++ b/apstra/blueprint/freeform_ra_group.go @@ -3,14 +3,12 @@ package blueprint import ( "context" "encoding/json" - "fmt" + "regexp" + "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" - "regexp" "github.com/Juniper/apstra-go-sdk/apstra" - "github.com/Juniper/terraform-provider-apstra/apstra/utils" - "github.com/hashicorp/terraform-plugin-framework-validators/setvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" dataSourceSchema "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/diag" @@ -22,21 +20,12 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -//{ -// "parent_id": "string", -// "label": "string", -// "tags": [ -// "string" -// ], -// "data": {} -//} - type FreeformRaGroup struct { - BlueprintId types.String `tfsdk:"blueprint_id"` - Id types.String `tfsdk:"id"` - Name types.String `tfsdk:"name"` - ParentId types.String `tfsdk:"parent_id"` - Tags types.Set `tfsdk:"tags"` + BlueprintId types.String `tfsdk:"blueprint_id"` + Id types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + ParentId types.String `tfsdk:"parent_id"` + // Tags types.Set `tfsdk:"tags"` Data jsontypes.Normalized `tfsdk:"data"` GeneratorId types.String `tfsdk:"generator_id"` } @@ -62,22 +51,21 @@ func (o FreeformRaGroup) DataSourceAttributes() map[string]dataSourceSchema.Attr }, }, "name": dataSourceSchema.StringAttribute{ - MarkdownDescription: "Populate this field to look up the Allocation Group by Name. Required when `id` is omitted.", + MarkdownDescription: "Populate this field to look up the Freeform Allocation Group by Name. Required when `id` is omitted.", Optional: true, Computed: true, Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, }, "parent_id": dataSourceSchema.StringAttribute{ - MarkdownDescription: "ID of the group node that is present as a parent of the current one in " + - "parent/children relationship." + - " If group is a top-level one, then 'parent_id' is equal to None/null.", + MarkdownDescription: "ID of the group node that is present as a parent of the current one in a " + + "parent/child relationship. If this is a top-level (root) node, then `parent_id` will be `null`.", Computed: true, }, - "tags": dataSourceSchema.SetAttribute{ - MarkdownDescription: "Set of Tag labels", - ElementType: types.StringType, - Computed: true, - }, + //"tags": dataSourceSchema.SetAttribute{ + // MarkdownDescription: "Set of Tag labels", + // ElementType: types.StringType, + // Computed: true, + //}, "data": dataSourceSchema.StringAttribute{ MarkdownDescription: "Arbitrary key-value mapping that is useful in a context of this group. " + "For example, you can store some VRF-related data there or add properties that are useful " + @@ -86,7 +74,7 @@ func (o FreeformRaGroup) DataSourceAttributes() map[string]dataSourceSchema.Attr CustomType: jsontypes.NormalizedType{}, }, "generator_id": dataSourceSchema.StringAttribute{ - MarkdownDescription: "ID of the group generator that created the group.", + MarkdownDescription: "ID of the group generator that created the group, if any.", Computed: true, }, } @@ -109,59 +97,62 @@ func (o FreeformRaGroup) ResourceAttributes() map[string]resourceSchema.Attribut MarkdownDescription: "Freeform Resource Allocation Group name as shown in the Web UI.", Required: true, Validators: []validator.String{ - stringvalidator.RegexMatches(regexp.MustCompile("^[a-zA-Z0-9.-_]+$"), "name may consist only of the following characters : a-zA-Z0-9.-_")}, + stringvalidator.RegexMatches( + regexp.MustCompile("^[a-zA-Z0-9.-_]+$"), + "name may consist only of the following characters : a-zA-Z0-9.-_"), + }, }, "parent_id": resourceSchema.StringAttribute{ - MarkdownDescription: fmt.Sprintf("Type of the System. Must be one of `%s` or `%s`", apstra.SystemTypeInternal, apstra.SystemTypeExternal), + MarkdownDescription: "ID of the parent Freeform Resource Allocation Group, if this group is to be nested.", Optional: true, Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, }, - "tags": resourceSchema.SetAttribute{ - MarkdownDescription: "Set of Tag labels", - ElementType: types.StringType, - Optional: true, - Validators: []validator.Set{setvalidator.SizeAtLeast(1)}, - }, + //"tags": resourceSchema.SetAttribute{ + // MarkdownDescription: "Set of Tag labels", + // ElementType: types.StringType, + // Optional: true, + // Validators: []validator.Set{setvalidator.SizeAtLeast(1)}, + //}, "data": resourceSchema.StringAttribute{ - MarkdownDescription: "Arbitrary key-value mapping that is useful in a context of this group. " + - "For example, you can store some VRF-related data there or add properties that are useful" + - " only in context of resource allocation, but not systems or interfaces. ", + MarkdownDescription: "Arbitrary JSON-encoded key-value mapping that is useful in a context of this " + + "group. For example, you can store some VRF-related data there or add properties that are useful " + + "only in context of resource allocation, but not systems or interfaces.", Optional: true, Computed: true, Default: stringdefault.StaticString("{}"), CustomType: jsontypes.NormalizedType{}, }, "generator_id": resourceSchema.StringAttribute{ - MarkdownDescription: "ID of the Generator that created Resource Allocation Group, " + - "always `null` because groups created with this resource were not generated.", + MarkdownDescription: "ID of the Generator that created Resource Allocation Group. " + + "Always `null` because groups created via resource declaration were not generated.", Computed: true, }, } } -func (o *FreeformRaGroup) Request(ctx context.Context, diags *diag.Diagnostics) *apstra.FreeformRaGroupData { - var tags []string - diags.Append(o.Tags.ElementsAs(ctx, &tags, false)...) - if diags.HasError() { - return nil - } +func (o *FreeformRaGroup) Request(_ context.Context, _ *diag.Diagnostics) *apstra.FreeformRaGroupData { + //var tags []string + //diags.Append(o.Tags.ElementsAs(ctx, &tags, false)...) + //if diags.HasError() { + // return nil + //} return &apstra.FreeformRaGroupData{ - ParentId: (*apstra.ObjectId)(o.ParentId.ValueStringPointer()), - Label: o.Name.ValueString(), - Tags: tags, + ParentId: (*apstra.ObjectId)(o.ParentId.ValueStringPointer()), + Label: o.Name.ValueString(), + // Tags: tags, Data: json.RawMessage(o.Data.ValueString()), GeneratorId: (*apstra.ObjectId)(o.GeneratorId.ValueStringPointer()), } } -func (o *FreeformRaGroup) LoadApiData(ctx context.Context, in *apstra.FreeformRaGroupData, diags *diag.Diagnostics) { +func (o *FreeformRaGroup) LoadApiData(_ context.Context, in *apstra.FreeformRaGroupData, _ *diag.Diagnostics) { o.Name = types.StringValue(in.Label) if in.ParentId != nil { o.ParentId = types.StringValue(string(*in.ParentId)) } o.Data = jsontypes.NewNormalizedValue(string(in.Data)) - o.Tags = utils.SetValueOrNull(ctx, types.StringType, in.Tags, diags) // safe to ignore diagnostic here + // o.Tags = utils.SetValueOrNull(ctx, types.StringType, in.Tags, diags) // safe to ignore diagnostic here o.GeneratorId = types.StringPointerValue((*string)(in.GeneratorId)) } diff --git a/apstra/resource_freeform_ra_group.go b/apstra/resource_freeform_ra_group.go index 8e1ef2a7..9e114f9d 100644 --- a/apstra/resource_freeform_ra_group.go +++ b/apstra/resource_freeform_ra_group.go @@ -73,7 +73,7 @@ func (o *resourceFreeformRaGroup) Create(ctx context.Context, req resource.Creat id, err := bp.CreateRaGroup(ctx, request) if err != nil { - resp.Diagnostics.AddError("error creating new Resource Allocation Group", err.Error()) + resp.Diagnostics.AddError("error creating new Freeform Resource Allocation Group", err.Error()) return } @@ -160,7 +160,9 @@ func (o *resourceFreeformRaGroup) Update(ctx context.Context, req resource.Updat resp.Diagnostics.AddError("error updating Freeform Resource Allocation Group", err.Error()) return } + plan.GeneratorId = types.StringNull() + // set state resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } diff --git a/docs/data-sources/freeform_ra_group.md b/docs/data-sources/freeform_ra_group.md index e195d734..c124f84f 100644 --- a/docs/data-sources/freeform_ra_group.md +++ b/docs/data-sources/freeform_ra_group.md @@ -21,7 +21,6 @@ At least one optional attribute is required. resource "apstra_freeform_ra_group" "test" { blueprint_id = "freeform_blueprint-d8c1fabf" name = "test_ra_group_fizz" - tags = ["a", "b", "c"] data = jsonencode({ foo = "bar" clown = 2 @@ -46,11 +45,6 @@ output "test_ra_group_out" {value = data.apstra_freeform_ra_group.test} // "id" = "98ubU5cuRj7WsT159L4" // "name" = "test_ra_group_fizz" // "parent_id" = tostring(null) -// "tags" = toset([ -// "a", -// "b", -// "c", -// ]) //} ``` @@ -64,11 +58,10 @@ output "test_ra_group_out" {value = data.apstra_freeform_ra_group.test} ### Optional - `id` (String) Populate this field to look up the Freeform Allocation Group by ID. Required when `name` is omitted. -- `name` (String) Populate this field to look up the Allocation Group by Name. Required when `id` is omitted. +- `name` (String) Populate this field to look up the Freeform Allocation Group by Name. Required when `id` is omitted. ### Read-Only - `data` (String) Arbitrary key-value mapping that is useful in a context of this group. For example, you can store some VRF-related data there or add properties that are useful only in context of resource allocation, but not systems or interfaces. -- `generator_id` (String) ID of the group generator that created the group. -- `parent_id` (String) ID of the group node that is present as a parent of the current one in parent/children relationship. If group is a top-level one, then 'parent_id' is equal to None/null. -- `tags` (Set of String) Set of Tag labels +- `generator_id` (String) ID of the group generator that created the group, if any. +- `parent_id` (String) ID of the group node that is present as a parent of the current one in a parent/child relationship. If this is a top-level (root) node, then `parent_id` will be `null`. diff --git a/docs/resources/freeform_ra_group.md b/docs/resources/freeform_ra_group.md index d8ba9f00..9212ea02 100644 --- a/docs/resources/freeform_ra_group.md +++ b/docs/resources/freeform_ra_group.md @@ -18,7 +18,6 @@ This resource creates a Resource Allocation Group in a Freeform Blueprint. resource "apstra_freeform_ra_group" "test" { blueprint_id = "freeform_blueprint-d8c1fabf" name = "test_ra_group_fizz" - tags = ["a", "b", "c"] data = jsonencode({ foo = "bar" clown = 2 @@ -43,11 +42,6 @@ output "test_ra_out" {value = data.apstra_freeform_ra_group.test} // "id" = "98ubU5cuRj7WsT159L4" // "name" = "test_ra_group_fizz" // "parent_id" = tostring(null) -// "tags" = toset([ -// "a", -// "b", -// "c", -// ]) //} ``` @@ -61,13 +55,12 @@ output "test_ra_out" {value = data.apstra_freeform_ra_group.test} ### Optional -- `data` (String) Arbitrary key-value mapping that is useful in a context of this group. For example, you can store some VRF-related data there or add properties that are useful only in context of resource allocation, but not systems or interfaces. -- `parent_id` (String) Type of the System. Must be one of `internal` or `external` -- `tags` (Set of String) Set of Tag labels +- `data` (String) Arbitrary JSON-encoded key-value mapping that is useful in a context of this group. For example, you can store some VRF-related data there or add properties that are useful only in context of resource allocation, but not systems or interfaces. +- `parent_id` (String) ID of the parent Freeform Resource Allocation Group, if this group is to be nested. ### Read-Only -- `generator_id` (String) ID of the Generator that created Resource Allocation Group, always `null` because groups created with this resource were not generated. +- `generator_id` (String) ID of the Generator that created Resource Allocation Group. Always `null` because groups created via resource declaration were not generated. - `id` (String) ID of the Freeform Resource Allocation Group. diff --git a/examples/data-sources/apstra_freeform_ra_group/example.tf b/examples/data-sources/apstra_freeform_ra_group/example.tf index 218aa8f3..63f12b8b 100644 --- a/examples/data-sources/apstra_freeform_ra_group/example.tf +++ b/examples/data-sources/apstra_freeform_ra_group/example.tf @@ -3,7 +3,6 @@ resource "apstra_freeform_ra_group" "test" { blueprint_id = "freeform_blueprint-d8c1fabf" name = "test_ra_group_fizz" - tags = ["a", "b", "c"] data = jsonencode({ foo = "bar" clown = 2 @@ -28,10 +27,5 @@ output "test_ra_group_out" {value = data.apstra_freeform_ra_group.test} // "id" = "98ubU5cuRj7WsT159L4" // "name" = "test_ra_group_fizz" // "parent_id" = tostring(null) -// "tags" = toset([ -// "a", -// "b", -// "c", -// ]) //} diff --git a/examples/resources/apstra_freeform_ra_group/example.tf b/examples/resources/apstra_freeform_ra_group/example.tf index a40fef63..245fd5ab 100644 --- a/examples/resources/apstra_freeform_ra_group/example.tf +++ b/examples/resources/apstra_freeform_ra_group/example.tf @@ -3,7 +3,6 @@ resource "apstra_freeform_ra_group" "test" { blueprint_id = "freeform_blueprint-d8c1fabf" name = "test_ra_group_fizz" - tags = ["a", "b", "c"] data = jsonencode({ foo = "bar" clown = 2 @@ -28,9 +27,4 @@ output "test_ra_out" {value = data.apstra_freeform_ra_group.test} // "id" = "98ubU5cuRj7WsT159L4" // "name" = "test_ra_group_fizz" // "parent_id" = tostring(null) -// "tags" = toset([ -// "a", -// "b", -// "c", -// ]) //} From ce75273bf7d80f80a4d237010425cd6610317c32 Mon Sep 17 00:00:00 2001 From: bwJuniper <98770420+bwJuniper@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:09:21 +0200 Subject: [PATCH 3/6] rename ra to resource --- ...ra_group.go => freeform_resource_group.go} | 10 ++--- ... => datasource_freeform_resource_group.go} | 20 +++++----- ...go => resource_freeform_resource_group.go} | 38 +++++++++---------- ...eeform_resource_group_integration_test.go} | 0 4 files changed, 34 insertions(+), 34 deletions(-) rename apstra/blueprint/{freeform_ra_group.go => freeform_resource_group.go} (93%) rename apstra/{datasource_freeform_ra_group.go => datasource_freeform_resource_group.go} (72%) rename apstra/{resource_freeform_ra_group.go => resource_freeform_resource_group.go} (74%) rename apstra/{resource_freeform_ra_group_integration_test.go => resource_freeform_resource_group_integration_test.go} (100%) diff --git a/apstra/blueprint/freeform_ra_group.go b/apstra/blueprint/freeform_resource_group.go similarity index 93% rename from apstra/blueprint/freeform_ra_group.go rename to apstra/blueprint/freeform_resource_group.go index b426118d..01c94a49 100644 --- a/apstra/blueprint/freeform_ra_group.go +++ b/apstra/blueprint/freeform_resource_group.go @@ -20,7 +20,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" ) -type FreeformRaGroup struct { +type FreeformResourceGroup struct { BlueprintId types.String `tfsdk:"blueprint_id"` Id types.String `tfsdk:"id"` Name types.String `tfsdk:"name"` @@ -30,7 +30,7 @@ type FreeformRaGroup struct { GeneratorId types.String `tfsdk:"generator_id"` } -func (o FreeformRaGroup) DataSourceAttributes() map[string]dataSourceSchema.Attribute { +func (o FreeformResourceGroup) DataSourceAttributes() map[string]dataSourceSchema.Attribute { return map[string]dataSourceSchema.Attribute{ "blueprint_id": dataSourceSchema.StringAttribute{ MarkdownDescription: "Apstra Blueprint ID. Used to identify " + @@ -80,7 +80,7 @@ func (o FreeformRaGroup) DataSourceAttributes() map[string]dataSourceSchema.Attr } } -func (o FreeformRaGroup) ResourceAttributes() map[string]resourceSchema.Attribute { +func (o FreeformResourceGroup) ResourceAttributes() map[string]resourceSchema.Attribute { return map[string]resourceSchema.Attribute{ "blueprint_id": resourceSchema.StringAttribute{ MarkdownDescription: "Apstra Blueprint ID.", @@ -130,7 +130,7 @@ func (o FreeformRaGroup) ResourceAttributes() map[string]resourceSchema.Attribut } } -func (o *FreeformRaGroup) Request(_ context.Context, _ *diag.Diagnostics) *apstra.FreeformRaGroupData { +func (o *FreeformResourceGroup) Request(_ context.Context, _ *diag.Diagnostics) *apstra.FreeformRaGroupData { //var tags []string //diags.Append(o.Tags.ElementsAs(ctx, &tags, false)...) //if diags.HasError() { @@ -146,7 +146,7 @@ func (o *FreeformRaGroup) Request(_ context.Context, _ *diag.Diagnostics) *apstr } } -func (o *FreeformRaGroup) LoadApiData(_ context.Context, in *apstra.FreeformRaGroupData, _ *diag.Diagnostics) { +func (o *FreeformResourceGroup) LoadApiData(_ context.Context, in *apstra.FreeformRaGroupData, _ *diag.Diagnostics) { o.Name = types.StringValue(in.Label) if in.ParentId != nil { o.ParentId = types.StringValue(string(*in.ParentId)) diff --git a/apstra/datasource_freeform_ra_group.go b/apstra/datasource_freeform_resource_group.go similarity index 72% rename from apstra/datasource_freeform_ra_group.go rename to apstra/datasource_freeform_resource_group.go index 5d01ffc7..e97551a3 100644 --- a/apstra/datasource_freeform_ra_group.go +++ b/apstra/datasource_freeform_resource_group.go @@ -14,32 +14,32 @@ import ( ) var ( - _ datasource.DataSourceWithConfigure = &dataSourceFreeformRaGroup{} - _ datasourceWithSetFfBpClientFunc = &dataSourceFreeformRaGroup{} + _ datasource.DataSourceWithConfigure = &dataSourceFreeformResourceGroup{} + _ datasourceWithSetFfBpClientFunc = &dataSourceFreeformResourceGroup{} ) -type dataSourceFreeformRaGroup struct { +type dataSourceFreeformResourceGroup struct { getBpClientFunc func(context.Context, string) (*apstra.FreeformClient, error) } -func (o *dataSourceFreeformRaGroup) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { +func (o *dataSourceFreeformResourceGroup) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { resp.TypeName = req.ProviderTypeName + "_freeform_ra_group" } -func (o *dataSourceFreeformRaGroup) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { +func (o *dataSourceFreeformResourceGroup) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { configureDataSource(ctx, o, req, resp) } -func (o *dataSourceFreeformRaGroup) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { +func (o *dataSourceFreeformResourceGroup) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { resp.Schema = schema.Schema{ MarkdownDescription: docCategoryFreeform + "This data source provides details of a specific Freeform Resource Allocation Group.\n\n" + "At least one optional attribute is required.", - Attributes: blueprint.FreeformRaGroup{}.DataSourceAttributes(), + Attributes: blueprint.FreeformResourceGroup{}.DataSourceAttributes(), } } -func (o *dataSourceFreeformRaGroup) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { - var config blueprint.FreeformRaGroup +func (o *dataSourceFreeformResourceGroup) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config blueprint.FreeformResourceGroup resp.Diagnostics.Append(req.Config.Get(ctx, &config)...) if resp.Diagnostics.HasError() { return @@ -96,6 +96,6 @@ func (o *dataSourceFreeformRaGroup) Read(ctx context.Context, req datasource.Rea resp.Diagnostics.Append(resp.State.Set(ctx, &config)...) } -func (o *dataSourceFreeformRaGroup) setBpClientFunc(f func(context.Context, string) (*apstra.FreeformClient, error)) { +func (o *dataSourceFreeformResourceGroup) setBpClientFunc(f func(context.Context, string) (*apstra.FreeformClient, error)) { o.getBpClientFunc = f } diff --git a/apstra/resource_freeform_ra_group.go b/apstra/resource_freeform_resource_group.go similarity index 74% rename from apstra/resource_freeform_ra_group.go rename to apstra/resource_freeform_resource_group.go index 9e114f9d..b09b38e5 100644 --- a/apstra/resource_freeform_ra_group.go +++ b/apstra/resource_freeform_resource_group.go @@ -12,34 +12,34 @@ import ( ) var ( - _ resource.ResourceWithConfigure = &resourceFreeformRaGroup{} - _ resourceWithSetFfBpClientFunc = &resourceFreeformRaGroup{} - _ resourceWithSetBpLockFunc = &resourceFreeformRaGroup{} + _ resource.ResourceWithConfigure = &resourceFreeformResourceGroup{} + _ resourceWithSetFfBpClientFunc = &resourceFreeformResourceGroup{} + _ resourceWithSetBpLockFunc = &resourceFreeformResourceGroup{} ) -type resourceFreeformRaGroup struct { +type resourceFreeformResourceGroup struct { getBpClientFunc func(context.Context, string) (*apstra.FreeformClient, error) lockFunc func(context.Context, string) error } -func (o *resourceFreeformRaGroup) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_freeform_ra_group" +func (o *resourceFreeformResourceGroup) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_freeform_resource_group" } -func (o *resourceFreeformRaGroup) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (o *resourceFreeformResourceGroup) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { configureResource(ctx, o, req, resp) } -func (o *resourceFreeformRaGroup) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (o *resourceFreeformResourceGroup) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ MarkdownDescription: docCategoryFreeform + "This resource creates a Resource Allocation Group in a Freeform Blueprint.", - Attributes: blueprint.FreeformRaGroup{}.ResourceAttributes(), + Attributes: blueprint.FreeformResourceGroup{}.ResourceAttributes(), } } -func (o *resourceFreeformRaGroup) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { +func (o *resourceFreeformResourceGroup) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // Retrieve values from plan - var plan blueprint.FreeformRaGroup + var plan blueprint.FreeformResourceGroup resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) if resp.Diagnostics.HasError() { return @@ -84,8 +84,8 @@ func (o *resourceFreeformRaGroup) Create(ctx context.Context, req resource.Creat resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } -func (o *resourceFreeformRaGroup) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var state blueprint.FreeformRaGroup +func (o *resourceFreeformResourceGroup) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state blueprint.FreeformResourceGroup resp.Diagnostics.Append(req.State.Get(ctx, &state)...) if resp.Diagnostics.HasError() { return @@ -121,9 +121,9 @@ func (o *resourceFreeformRaGroup) Read(ctx context.Context, req resource.ReadReq resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } -func (o *resourceFreeformRaGroup) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { +func (o *resourceFreeformResourceGroup) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { // Get plan values - var plan blueprint.FreeformRaGroup + var plan blueprint.FreeformResourceGroup resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) if resp.Diagnostics.HasError() { return @@ -167,8 +167,8 @@ func (o *resourceFreeformRaGroup) Update(ctx context.Context, req resource.Updat resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) } -func (o *resourceFreeformRaGroup) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - var state blueprint.FreeformRaGroup +func (o *resourceFreeformResourceGroup) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state blueprint.FreeformResourceGroup resp.Diagnostics.Append(req.State.Get(ctx, &state)...) if resp.Diagnostics.HasError() { return @@ -204,10 +204,10 @@ func (o *resourceFreeformRaGroup) Delete(ctx context.Context, req resource.Delet } } -func (o *resourceFreeformRaGroup) setBpClientFunc(f func(context.Context, string) (*apstra.FreeformClient, error)) { +func (o *resourceFreeformResourceGroup) setBpClientFunc(f func(context.Context, string) (*apstra.FreeformClient, error)) { o.getBpClientFunc = f } -func (o *resourceFreeformRaGroup) setBpLockFunc(f func(context.Context, string) error) { +func (o *resourceFreeformResourceGroup) setBpLockFunc(f func(context.Context, string) error) { o.lockFunc = f } diff --git a/apstra/resource_freeform_ra_group_integration_test.go b/apstra/resource_freeform_resource_group_integration_test.go similarity index 100% rename from apstra/resource_freeform_ra_group_integration_test.go rename to apstra/resource_freeform_resource_group_integration_test.go From becaa80c71d94c3889b71b776fba1d410229b2e1 Mon Sep 17 00:00:00 2001 From: bwJuniper <98770420+bwJuniper@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:16:21 +0200 Subject: [PATCH 4/6] fixup docs and provider --- apstra/datasource_freeform_resource_group.go | 2 +- apstra/provider.go | 4 ++-- ...ra_group.md => freeform_resource_group.md} | 20 +++++++++---------- ...ra_group.md => freeform_resource_group.md} | 20 +++++++++---------- .../example.tf | 16 +++++++-------- .../example.tf | 16 +++++++-------- 6 files changed, 39 insertions(+), 39 deletions(-) rename docs/data-sources/{freeform_ra_group.md => freeform_resource_group.md} (78%) rename docs/resources/{freeform_ra_group.md => freeform_resource_group.md} (74%) rename examples/data-sources/{apstra_freeform_ra_group => apstra_freeform_resource_group}/example.tf (57%) rename examples/resources/{apstra_freeform_ra_group => apstra_freeform_resource_group}/example.tf (55%) diff --git a/apstra/datasource_freeform_resource_group.go b/apstra/datasource_freeform_resource_group.go index e97551a3..91333d70 100644 --- a/apstra/datasource_freeform_resource_group.go +++ b/apstra/datasource_freeform_resource_group.go @@ -23,7 +23,7 @@ type dataSourceFreeformResourceGroup struct { } func (o *dataSourceFreeformResourceGroup) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_freeform_ra_group" + resp.TypeName = req.ProviderTypeName + "_freeform_resource_group" } func (o *dataSourceFreeformResourceGroup) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { diff --git a/apstra/provider.go b/apstra/provider.go index 2eb6c26d..4b8ae107 100644 --- a/apstra/provider.go +++ b/apstra/provider.go @@ -551,7 +551,7 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource func() datasource.DataSource { return &dataSourceFreeformConfigTemplate{} }, func() datasource.DataSource { return &dataSourceFreeformLink{} }, func() datasource.DataSource { return &dataSourceFreeformPropertySet{} }, - func() datasource.DataSource { return &dataSourceFreeformRaGroup{} }, + func() datasource.DataSource { return &dataSourceFreeformResourceGroup{} }, func() datasource.DataSource { return &dataSourceFreeformSystem{} }, func() datasource.DataSource { return &dataSourceIntegerPool{} }, func() datasource.DataSource { return &dataSourceInterfacesByLinkTag{} }, @@ -610,7 +610,7 @@ func (p *Provider) Resources(_ context.Context) []func() resource.Resource { func() resource.Resource { return &resourceFreeformConfigTemplate{} }, func() resource.Resource { return &resourceFreeformLink{} }, func() resource.Resource { return &resourceFreeformPropertySet{} }, - func() resource.Resource { return &resourceFreeformRaGroup{} }, + func() resource.Resource { return &resourceFreeformResourceGroup{} }, func() resource.Resource { return &resourceFreeformSystem{} }, func() resource.Resource { return &resourceIntegerPool{} }, func() resource.Resource { return &resourceInterfaceMap{} }, diff --git a/docs/data-sources/freeform_ra_group.md b/docs/data-sources/freeform_resource_group.md similarity index 78% rename from docs/data-sources/freeform_ra_group.md rename to docs/data-sources/freeform_resource_group.md index c124f84f..b5b9607c 100644 --- a/docs/data-sources/freeform_ra_group.md +++ b/docs/data-sources/freeform_resource_group.md @@ -1,12 +1,12 @@ --- -page_title: "apstra_freeform_ra_group Data Source - terraform-provider-apstra" +page_title: "apstra_freeform_resource_group Data Source - terraform-provider-apstra" subcategory: "Reference Design: Freeform" description: |- This data source provides details of a specific Freeform Resource Allocation Group. At least one optional attribute is required. --- -# apstra_freeform_ra_group (Data Source) +# apstra_freeform_resource_group (Data Source) This data source provides details of a specific Freeform Resource Allocation Group. @@ -18,32 +18,32 @@ At least one optional attribute is required. ```terraform # This example defines a Freeform Resource Allocation Group in a blueprint -resource "apstra_freeform_ra_group" "test" { +resource "apstra_freeform_resource_group" "test" { blueprint_id = "freeform_blueprint-d8c1fabf" - name = "test_ra_group_fizz" + name = "test_resource_group_fizz" data = jsonencode({ foo = "bar" clown = 2 }) } -# here we retrieve the freeform ra_group +# here we retrieve the freeform resource_group -data "apstra_freeform_ra_group" "test" { +data "apstra_freeform_resource_group" "test" { blueprint_id = "043c5787-66e8-41c7-8925-c7e52fbe6e32" - id = apstra_freeform_ra_group.test.id + id = apstra_freeform_resource_group.test.id } # here we build an output bock to display it -output "test_ra_group_out" {value = data.apstra_freeform_ra_group.test} +output "test_resource_group_out" {value = data.apstra_freeform_resource_group.test} -//test_ra_group_out = { +//test_resource_group_out = { // "blueprint_id" = "043c5787-66e8-41c7-8925-c7e52fbe6e32" // "data" = "{\"clown\": 2, \"foo\": \"bar\"}" // "generator_id" = tostring(null) // "id" = "98ubU5cuRj7WsT159L4" -// "name" = "test_ra_group_fizz" +// "name" = "test_resource_group_fizz" // "parent_id" = tostring(null) //} ``` diff --git a/docs/resources/freeform_ra_group.md b/docs/resources/freeform_resource_group.md similarity index 74% rename from docs/resources/freeform_ra_group.md rename to docs/resources/freeform_resource_group.md index 9212ea02..103ba124 100644 --- a/docs/resources/freeform_ra_group.md +++ b/docs/resources/freeform_resource_group.md @@ -1,11 +1,11 @@ --- -page_title: "apstra_freeform_ra_group Resource - terraform-provider-apstra" +page_title: "apstra_freeform_resource_group Resource - terraform-provider-apstra" subcategory: "Reference Design: Freeform" description: |- This resource creates a Resource Allocation Group in a Freeform Blueprint. --- -# apstra_freeform_ra_group (Resource) +# apstra_freeform_resource_group (Resource) This resource creates a Resource Allocation Group in a Freeform Blueprint. @@ -15,32 +15,32 @@ This resource creates a Resource Allocation Group in a Freeform Blueprint. ```terraform # This example defines a Freeform Resource Allocation Group in a blueprint -resource "apstra_freeform_ra_group" "test" { +resource "apstra_resource_freeform_resource_group" "test" { blueprint_id = "freeform_blueprint-d8c1fabf" - name = "test_ra_group_fizz" + name = "test_resource_group_fizz" data = jsonencode({ foo = "bar" clown = 2 }) } -# here we retrieve the freeform ra_group +# here we retrieve the freeform resource_group -data "apstra_freeform_ra_group" "test" { +data "apstra_resource_freeform_resource_group" "test" { blueprint_id = "043c5787-66e8-41c7-8925-c7e52fbe6e32" - id = apstra_freeform_ra_group.test.id + id = apstra_resource_freeform_resource_group.test.id } # here we build an output bock to display it -output "test_ra_out" {value = data.apstra_freeform_ra_group.test} +output "test_resource_out" {value = data.apstra_resource_freeform_resource_group.test} -//test_ra_out = { +//test_resource_out = { // "blueprint_id" = "043c5787-66e8-41c7-8925-c7e52fbe6e32" // "data" = "{\"clown\": 2, \"foo\": \"bar\"}" // "generator_id" = tostring(null) // "id" = "98ubU5cuRj7WsT159L4" -// "name" = "test_ra_group_fizz" +// "name" = "test_resource_group_fizz" // "parent_id" = tostring(null) //} ``` diff --git a/examples/data-sources/apstra_freeform_ra_group/example.tf b/examples/data-sources/apstra_freeform_resource_group/example.tf similarity index 57% rename from examples/data-sources/apstra_freeform_ra_group/example.tf rename to examples/data-sources/apstra_freeform_resource_group/example.tf index 63f12b8b..f5644b44 100644 --- a/examples/data-sources/apstra_freeform_ra_group/example.tf +++ b/examples/data-sources/apstra_freeform_resource_group/example.tf @@ -1,31 +1,31 @@ # This example defines a Freeform Resource Allocation Group in a blueprint -resource "apstra_freeform_ra_group" "test" { +resource "apstra_freeform_resource_group" "test" { blueprint_id = "freeform_blueprint-d8c1fabf" - name = "test_ra_group_fizz" + name = "test_resource_group_fizz" data = jsonencode({ foo = "bar" clown = 2 }) } -# here we retrieve the freeform ra_group +# here we retrieve the freeform resource_group -data "apstra_freeform_ra_group" "test" { +data "apstra_freeform_resource_group" "test" { blueprint_id = "043c5787-66e8-41c7-8925-c7e52fbe6e32" - id = apstra_freeform_ra_group.test.id + id = apstra_freeform_resource_group.test.id } # here we build an output bock to display it -output "test_ra_group_out" {value = data.apstra_freeform_ra_group.test} +output "test_resource_group_out" {value = data.apstra_freeform_resource_group.test} -//test_ra_group_out = { +//test_resource_group_out = { // "blueprint_id" = "043c5787-66e8-41c7-8925-c7e52fbe6e32" // "data" = "{\"clown\": 2, \"foo\": \"bar\"}" // "generator_id" = tostring(null) // "id" = "98ubU5cuRj7WsT159L4" -// "name" = "test_ra_group_fizz" +// "name" = "test_resource_group_fizz" // "parent_id" = tostring(null) //} diff --git a/examples/resources/apstra_freeform_ra_group/example.tf b/examples/resources/apstra_freeform_resource_group/example.tf similarity index 55% rename from examples/resources/apstra_freeform_ra_group/example.tf rename to examples/resources/apstra_freeform_resource_group/example.tf index 245fd5ab..2594dcd7 100644 --- a/examples/resources/apstra_freeform_ra_group/example.tf +++ b/examples/resources/apstra_freeform_resource_group/example.tf @@ -1,30 +1,30 @@ # This example defines a Freeform Resource Allocation Group in a blueprint -resource "apstra_freeform_ra_group" "test" { +resource "apstra_resource_freeform_resource_group" "test" { blueprint_id = "freeform_blueprint-d8c1fabf" - name = "test_ra_group_fizz" + name = "test_resource_group_fizz" data = jsonencode({ foo = "bar" clown = 2 }) } -# here we retrieve the freeform ra_group +# here we retrieve the freeform resource_group -data "apstra_freeform_ra_group" "test" { +data "apstra_resource_freeform_resource_group" "test" { blueprint_id = "043c5787-66e8-41c7-8925-c7e52fbe6e32" - id = apstra_freeform_ra_group.test.id + id = apstra_resource_freeform_resource_group.test.id } # here we build an output bock to display it -output "test_ra_out" {value = data.apstra_freeform_ra_group.test} +output "test_resource_out" {value = data.apstra_resource_freeform_resource_group.test} -//test_ra_out = { +//test_resource_out = { // "blueprint_id" = "043c5787-66e8-41c7-8925-c7e52fbe6e32" // "data" = "{\"clown\": 2, \"foo\": \"bar\"}" // "generator_id" = tostring(null) // "id" = "98ubU5cuRj7WsT159L4" -// "name" = "test_ra_group_fizz" +// "name" = "test_resource_group_fizz" // "parent_id" = tostring(null) //} From ccde5affe0a539c9068a265f82b785b748150e66 Mon Sep 17 00:00:00 2001 From: bwJuniper <98770420+bwJuniper@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:22:32 +0200 Subject: [PATCH 5/6] fix export_test.go --- apstra/export_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apstra/export_test.go b/apstra/export_test.go index ddd61276..697a024e 100644 --- a/apstra/export_test.go +++ b/apstra/export_test.go @@ -14,7 +14,7 @@ var ( ResourceFreeformLink = resourceFreeformLink{} ResourceFreeformSystem = resourceFreeformSystem{} ResourceFreeformPropertySet = resourceFreeformPropertySet{} - ResourceFreeformRaGroup = resourceFreeformRaGroup{} + ResourceFreeformRaGroup = resourceFreeformResourceGroup{} ResourceIpv4Pool = resourceIpv4Pool{} ResourceTemplatePodBased = resourceTemplatePodBased{} ResourceTemplateCollapsed = resourceTemplateCollapsed{} From 7bd7d39597eca44458bcaff2115a55a28998e4e0 Mon Sep 17 00:00:00 2001 From: Chris Marget Date: Tue, 23 Jul 2024 08:41:29 -0400 Subject: [PATCH 6/6] update tests: remove tags, add parent_id attribute --- ...reeform_resource_group_integration_test.go | 106 ++++++++++++------ 1 file changed, 72 insertions(+), 34 deletions(-) diff --git a/apstra/resource_freeform_resource_group_integration_test.go b/apstra/resource_freeform_resource_group_integration_test.go index 9c5e90ea..4b79a2a8 100644 --- a/apstra/resource_freeform_resource_group_integration_test.go +++ b/apstra/resource_freeform_resource_group_integration_test.go @@ -6,10 +6,11 @@ import ( "context" "encoding/json" "fmt" - "math/rand" - "strconv" "testing" + "github.com/Juniper/apstra-go-sdk/apstra" + "github.com/stretchr/testify/require" + tfapstra "github.com/Juniper/terraform-provider-apstra/apstra" testutils "github.com/Juniper/terraform-provider-apstra/apstra/test_utils" "github.com/hashicorp/go-version" @@ -18,57 +19,70 @@ import ( ) const ( - resourceFreeformRaGroupHcl = ` + resourceFreeformResourceGroupHcl = ` resource %q %q { - blueprint_id = %q - name = %q - tags = %s - data = %s + blueprint_id = %q + name = %q + parent_id = %s + data = %s } ` ) -type resourceFreeformRaGroup struct { +type resourceFreeformResourceGroup struct { blueprintId string name string - tags []string + parentId string data json.RawMessage + // tags []string } -func (o resourceFreeformRaGroup) render(rType, rName string) string { +func (o resourceFreeformResourceGroup) render(rType, rName string) string { data := "null" if o.data != nil { data = fmt.Sprintf("%q", string(o.data)) } - return fmt.Sprintf(resourceFreeformRaGroupHcl, + + return fmt.Sprintf(resourceFreeformResourceGroupHcl, rType, rName, o.blueprintId, o.name, - stringSetOrNull(o.tags), + stringOrNull(o.parentId), data, ) } -func (o resourceFreeformRaGroup) testChecks(t testing.TB, rType, rName string) testChecks { +func (o resourceFreeformResourceGroup) testChecks(t testing.TB, rType, rName string) testChecks { result := newTestChecks(rType + "." + rName) // required and computed attributes can always be checked result.append(t, "TestCheckResourceAttrSet", "id") result.append(t, "TestCheckResourceAttr", "blueprint_id", o.blueprintId) result.append(t, "TestCheckResourceAttr", "name", o.name) - if len(o.tags) > 0 { - result.append(t, "TestCheckResourceAttr", "tags.#", strconv.Itoa(len(o.tags))) - for _, tag := range o.tags { - result.append(t, "TestCheckTypeSetElemAttr", "tags.*", tag) - } - } + + //if len(o.tags) > 0 { + // result.append(t, "TestCheckResourceAttr", "tags.#", strconv.Itoa(len(o.tags))) + // for _, tag := range o.tags { + // result.append(t, "TestCheckTypeSetElemAttr", "tags.*", tag) + // } + //} + if len(o.data) > 0 { result.append(t, "TestCheckResourceAttr", "data", string(o.data)) + } else { + result.append(t, "TestCheckResourceAttr", "data", "{}") + } + + if len(o.parentId) > 0 { + result.append(t, "TestCheckResourceAttr", "parent_id", o.parentId) + } else { + result.append(t, "TestCheckNoResourceAttr", "parent_id") } + return result } -func TestResourceFreeformRaGroup(t *testing.T) { +func TestResourceFreeformResourceGroup(t *testing.T) { ctx := context.Background() client := testutils.GetTestClient(t, ctx) apiVersion := version.Must(version.NewVersion(client.ApiVersion())) @@ -76,8 +90,14 @@ func TestResourceFreeformRaGroup(t *testing.T) { // create a blueprint bp := testutils.FfBlueprintA(t, ctx) + makeParentResourceGroup := func(t testing.TB, ctx context.Context) apstra.ObjectId { + id, err := bp.CreateRaGroup(ctx, &apstra.FreeformRaGroupData{Label: acctest.RandString(6)}) + require.NoError(t, err) + return id + } + type testStep struct { - config resourceFreeformRaGroup + config resourceFreeformResourceGroup } type testCase struct { apiVersionConstraints version.Constraints @@ -85,52 +105,70 @@ func TestResourceFreeformRaGroup(t *testing.T) { } testCases := map[string]testCase{ - "start_with_no_tags": { + "start_minimal": { steps: []testStep{ { - config: resourceFreeformRaGroup{ + config: resourceFreeformResourceGroup{ blueprintId: bp.Id().String(), name: acctest.RandString(6), }, }, { - config: resourceFreeformRaGroup{ + config: resourceFreeformResourceGroup{ blueprintId: bp.Id().String(), name: acctest.RandString(6), - tags: randomStrings(rand.Intn(10)+2, 6), + parentId: makeParentResourceGroup(t, ctx).String(), + data: randomJson(t, 6, 12, 4), }, }, { - config: resourceFreeformRaGroup{ + config: resourceFreeformResourceGroup{ blueprintId: bp.Id().String(), name: acctest.RandString(6), - data: randomJson(t, 6, 12, 4), }, }, }, }, - "start_with_tags": { + "start_maximal": { steps: []testStep{ { - config: resourceFreeformRaGroup{ + config: resourceFreeformResourceGroup{ + blueprintId: bp.Id().String(), + name: acctest.RandString(6), + parentId: makeParentResourceGroup(t, ctx).String(), + data: randomJson(t, 6, 12, 4), + }, + }, + { + config: resourceFreeformResourceGroup{ blueprintId: bp.Id().String(), name: acctest.RandString(6), - tags: randomStrings(rand.Intn(10)+2, 6), + }, + }, + { + config: resourceFreeformResourceGroup{ + blueprintId: bp.Id().String(), + name: acctest.RandString(6), + parentId: makeParentResourceGroup(t, ctx).String(), data: randomJson(t, 6, 12, 4), }, }, + }, + }, + "swap_parents": { + steps: []testStep{ { - config: resourceFreeformRaGroup{ + config: resourceFreeformResourceGroup{ blueprintId: bp.Id().String(), name: acctest.RandString(6), - data: randomJson(t, 6, 12, 5), + parentId: makeParentResourceGroup(t, ctx).String(), }, }, { - config: resourceFreeformRaGroup{ + config: resourceFreeformResourceGroup{ blueprintId: bp.Id().String(), name: acctest.RandString(6), - tags: randomStrings(rand.Intn(10)+2, 6), + parentId: makeParentResourceGroup(t, ctx).String(), }, }, },