-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #830 from Juniper/829-implement-freeform-group-gen…
…erators implement freeform group generators with tests
- Loading branch information
Showing
12 changed files
with
900 additions
and
3 deletions.
There are no files selected for viewing
101 changes: 101 additions & 0 deletions
101
apstra/data_source_freeform_resource_group_generator.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package tfapstra | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/Juniper/apstra-go-sdk/apstra" | ||
"github.com/Juniper/terraform-provider-apstra/apstra/freeform" | ||
"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 = &dataSourceFreeformGroupGenerator{} | ||
_ datasourceWithSetFfBpClientFunc = &dataSourceFreeformGroupGenerator{} | ||
) | ||
|
||
type dataSourceFreeformGroupGenerator struct { | ||
getBpClientFunc func(context.Context, string) (*apstra.FreeformClient, error) | ||
} | ||
|
||
func (o *dataSourceFreeformGroupGenerator) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { | ||
resp.TypeName = req.ProviderTypeName + "_freeform_resource_group_generator" | ||
} | ||
|
||
func (o *dataSourceFreeformGroupGenerator) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { | ||
configureDataSource(ctx, o, req, resp) | ||
} | ||
|
||
func (o *dataSourceFreeformGroupGenerator) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) { | ||
resp.Schema = schema.Schema{ | ||
MarkdownDescription: docCategoryFreeform + "This data source provides details of a specific Freeform Group Generator.\n\n" + | ||
"At least one optional attribute is required.", | ||
Attributes: freeform.GroupGenerator{}.DataSourceAttributes(), | ||
} | ||
} | ||
|
||
func (o *dataSourceFreeformGroupGenerator) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { | ||
var config freeform.GroupGenerator | ||
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.FreeformGroupGenerator | ||
switch { | ||
case !config.Id.IsNull(): | ||
api, err = bp.GetGroupGenerator(ctx, apstra.ObjectId(config.Id.ValueString())) | ||
if utils.IsApstra404(err) { | ||
resp.Diagnostics.AddAttributeError( | ||
path.Root("id"), | ||
"Freeform Group Generator not found", | ||
fmt.Sprintf("Freeform Group Generator with ID %s not found", config.Id)) | ||
return | ||
} | ||
case !config.Name.IsNull(): | ||
api, err = bp.GetGroupGeneratorByName(ctx, config.Name.ValueString()) | ||
if utils.IsApstra404(err) { | ||
resp.Diagnostics.AddAttributeError( | ||
path.Root("name"), | ||
"Freeform Group Generator not found", | ||
fmt.Sprintf("Freeform Group Generator with Name %s not found", config.Name)) | ||
return | ||
} | ||
} | ||
if err != nil { | ||
resp.Diagnostics.AddError("failed reading Freeform Group Generator", err.Error()) | ||
return | ||
} | ||
if api.Data == nil { | ||
resp.Diagnostics.AddError("failed reading Freeform Group Generator", "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 *dataSourceFreeformGroupGenerator) setBpClientFunc(f func(context.Context, string) (*apstra.FreeformClient, error)) { | ||
o.getBpClientFunc = f | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
package freeform | ||
|
||
import ( | ||
"context" | ||
"regexp" | ||
|
||
"github.com/Juniper/apstra-go-sdk/apstra" | ||
"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" | ||
) | ||
|
||
type GroupGenerator struct { | ||
Id types.String `tfsdk:"id"` | ||
BlueprintId types.String `tfsdk:"blueprint_id"` | ||
GroupId types.String `tfsdk:"group_id"` | ||
Name types.String `tfsdk:"name"` | ||
Scope types.String `tfsdk:"scope"` | ||
} | ||
|
||
func (o GroupGenerator) DataSourceAttributes() map[string]dataSourceSchema.Attribute { | ||
return map[string]dataSourceSchema.Attribute{ | ||
"id": dataSourceSchema.StringAttribute{ | ||
MarkdownDescription: "Populate this field to look up the Freeform Group Generator 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"), | ||
}...), | ||
}, | ||
}, | ||
"blueprint_id": dataSourceSchema.StringAttribute{ | ||
MarkdownDescription: "Apstra Blueprint ID. Used to identify " + | ||
"the Blueprint where the Group lives.", | ||
Required: true, | ||
Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, | ||
}, | ||
"group_id": dataSourceSchema.StringAttribute{ | ||
MarkdownDescription: "Resource Group the Group Generator belongs to.", | ||
Computed: true, | ||
}, | ||
"name": dataSourceSchema.StringAttribute{ | ||
MarkdownDescription: "Populate this field to look up Group Generator by Name. Required when `id` is omitted.", | ||
Optional: true, | ||
Computed: true, | ||
Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, | ||
}, | ||
"scope": dataSourceSchema.StringAttribute{ | ||
MarkdownDescription: "Scope is a graph query which selects target nodes for which Groups should be generated.\n" + | ||
"Example: `node('system', name='target', label=aeq('*prod*'))`", | ||
Computed: true, | ||
}, | ||
} | ||
} | ||
|
||
func (o GroupGenerator) ResourceAttributes() map[string]resourceSchema.Attribute { | ||
return map[string]resourceSchema.Attribute{ | ||
"id": resourceSchema.StringAttribute{ | ||
MarkdownDescription: "ID of the Group Generator within the Freeform Blueprint.", | ||
Computed: true, | ||
PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, | ||
}, | ||
"blueprint_id": resourceSchema.StringAttribute{ | ||
MarkdownDescription: "Apstra Blueprint ID.", | ||
Required: true, | ||
Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, | ||
PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, | ||
}, | ||
"group_id": resourceSchema.StringAttribute{ | ||
MarkdownDescription: "Resource Group the Group Generator belongs to. Omit to create at the `root` level.", | ||
Optional: true, | ||
Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, | ||
}, | ||
"name": resourceSchema.StringAttribute{ | ||
MarkdownDescription: "Freeform Group Generator 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.-_", | ||
), | ||
}, | ||
}, | ||
"scope": resourceSchema.StringAttribute{ | ||
MarkdownDescription: "Scope is a graph query which selects target nodes for which Group Generators should " + | ||
"be generated.\nExample: `node('system', name='target', label=aeq('*prod*'))`", | ||
Required: true, | ||
Validators: []validator.String{stringvalidator.LengthAtLeast(1)}, | ||
}, | ||
} | ||
} | ||
|
||
func (o *GroupGenerator) Request(_ context.Context, _ *diag.Diagnostics) *apstra.FreeformGroupGeneratorData { | ||
return &apstra.FreeformGroupGeneratorData{ | ||
ParentId: (*apstra.ObjectId)(o.GroupId.ValueStringPointer()), | ||
Label: o.Name.ValueString(), | ||
Scope: o.Scope.ValueString(), | ||
} | ||
} | ||
|
||
func (o *GroupGenerator) LoadApiData(_ context.Context, in *apstra.FreeformGroupGeneratorData, _ *diag.Diagnostics) { | ||
o.GroupId = types.StringPointerValue((*string)(in.ParentId)) | ||
o.Name = types.StringValue(in.Label) | ||
o.Scope = types.StringValue(in.Scope) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.