blob: 60bf124e4c18f15abcefcee543b0d2da0a5b7a83 [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package provider
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
mapplanmodifiers "github.com/terraform-providers/terraform-provider-random/internal/planmodifiers/map"
"github.com/terraform-providers/terraform-provider-random/internal/random"
)
var _ resource.Resource = (*shuffleResource)(nil)
func NewShuffleResource() resource.Resource {
return &shuffleResource{}
}
type shuffleResource struct{}
func (r *shuffleResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_shuffle"
}
func (r *shuffleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Description: "The resource `random_shuffle` generates a random permutation of a list of strings " +
"given as an argument.",
Attributes: map[string]schema.Attribute{
"keepers": schema.MapAttribute{
Description: "Arbitrary map of values that, when changed, will trigger recreation of " +
"resource. See [the main provider documentation](../index.html) for more information.",
ElementType: types.StringType,
Optional: true,
PlanModifiers: []planmodifier.Map{
mapplanmodifiers.RequiresReplaceIfValuesNotNull(),
},
},
"seed": schema.StringAttribute{
Description: "Arbitrary string with which to seed the random number generator, in order to " +
"produce less-volatile permutations of the list.\n" +
"\n" +
"**Important:** Even with an identical seed, it is not guaranteed that the same permutation " +
"will be produced across different versions of Terraform. This argument causes the " +
"result to be *less volatile*, but not fixed for all time.",
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"input": schema.ListAttribute{
Description: "The list of strings to shuffle.",
ElementType: types.StringType,
Required: true,
PlanModifiers: []planmodifier.List{
listplanmodifier.RequiresReplace(),
},
},
"result_count": schema.Int64Attribute{
Description: "The number of results to return. Defaults to the number of items in the " +
"`input` list. If fewer items are requested, some elements will be excluded from the " +
"result. If more items are requested, items will be repeated in the result but not more " +
"frequently than the number of items in the input list.",
Optional: true,
PlanModifiers: []planmodifier.Int64{
int64planmodifier.RequiresReplace(),
},
},
"result": schema.ListAttribute{
Description: "Random permutation of the list of strings given in `input`.",
ElementType: types.StringType,
Computed: true,
PlanModifiers: []planmodifier.List{
listplanmodifier.UseStateForUnknown(),
},
},
"id": schema.StringAttribute{
Description: "A static value used internally by Terraform, this should not be referenced in configurations.",
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
},
}
}
func (r *shuffleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var plan shuffleModelV0
diags := req.Plan.Get(ctx, &plan)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
input := plan.Input
seed := plan.Seed.ValueString()
resultCount := plan.ResultCount.ValueInt64()
if resultCount == 0 {
resultCount = int64(len(input.Elements()))
}
result := make([]attr.Value, 0, resultCount)
if len(input.Elements()) > 0 {
rand := random.NewRand(seed)
// Keep producing permutations until we fill our result
Batches:
for {
perm := rand.Perm(len(input.Elements()))
for _, i := range perm {
result = append(result, input.Elements()[i])
if int64(len(result)) >= resultCount {
break Batches
}
}
}
}
res, diags := types.ListValue(types.StringType, result)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
s := shuffleModelV0{
ID: types.StringValue("-"),
Keepers: plan.Keepers,
Input: plan.Input,
Result: res,
}
if plan.Seed.IsNull() {
s.Seed = types.StringNull()
} else {
s.Seed = types.StringValue(seed)
}
if plan.ResultCount.IsNull() {
s.ResultCount = types.Int64Null()
} else {
s.ResultCount = types.Int64Value(resultCount)
}
diags = resp.State.Set(ctx, s)
resp.Diagnostics.Append(diags...)
if resp.Diagnostics.HasError() {
return
}
}
// Read does not need to perform any operations as the state in ReadResourceResponse is already populated.
func (r *shuffleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
}
// Update ensures the plan value is copied to the state to complete the update.
func (r *shuffleResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var model shuffleModelV0
resp.Diagnostics.Append(req.Plan.Get(ctx, &model)...)
if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &model)...)
}
// Delete does not need to explicitly call resp.State.RemoveResource() as this is automatically handled by the
// [framework](https://github.com/hashicorp/terraform-plugin-framework/pull/301).
func (r *shuffleResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
}
type shuffleModelV0 struct {
ID types.String `tfsdk:"id"`
Keepers types.Map `tfsdk:"keepers"`
Seed types.String `tfsdk:"seed"`
Input types.List `tfsdk:"input"`
ResultCount types.Int64 `tfsdk:"result_count"`
Result types.List `tfsdk:"result"`
}