130 lines
4.7 KiB
Go
130 lines
4.7 KiB
Go
package file_local_snapshot
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/hashicorp/terraform-plugin-framework/datasource"
|
|
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
|
|
"github.com/hashicorp/terraform-plugin-framework/types"
|
|
"github.com/hashicorp/terraform-plugin-log/tflog"
|
|
)
|
|
|
|
// The `var _` is a special Go construct that results in an unusable variable.
|
|
// The purpose of these lines is to make sure our LocalFileDataSource correctly implements the `datasource.DataSource“ interface.
|
|
// These will fail at compilation time if the implementation is not satisfied.
|
|
var _ datasource.DataSource = &LocalSnapshotDataSource{}
|
|
|
|
func NewLocalSnapshotDataSource() datasource.DataSource {
|
|
return &LocalSnapshotDataSource{}
|
|
}
|
|
|
|
type LocalSnapshotDataSource struct{}
|
|
|
|
type LocalSnapshotDataSourceModel struct {
|
|
Id types.String `tfsdk:"id"`
|
|
Contents types.String `tfsdk:"contents"`
|
|
Data types.String `tfsdk:"data"`
|
|
Decompress types.Bool `tfsdk:"decompress"`
|
|
}
|
|
|
|
func (r *LocalSnapshotDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
|
|
resp.TypeName = req.ProviderTypeName + "_local_snapshot" // _local_snapshot
|
|
}
|
|
|
|
func (r *LocalSnapshotDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
|
|
resp.Schema = schema.Schema{
|
|
MarkdownDescription: "File LocalSnapshot data source. \n" +
|
|
"This data source retrieves the contents of a file from the output of a file_local_snapshot datasource." +
|
|
"Warning! Using this resource places the plain text contents of the snapshot in your state file.",
|
|
|
|
Attributes: map[string]schema.Attribute{
|
|
"contents": schema.StringAttribute{
|
|
MarkdownDescription: "The contents of the snapshot to retrieve. " +
|
|
"This could be any gzip compressed base64 encoded data. " +
|
|
"If the data isn't compressed, set the decompress argument to false, or leave it blank. " +
|
|
"If the decompress argument is false, the data will be the base64 decoded contents.",
|
|
Required: true,
|
|
Sensitive: true,
|
|
},
|
|
"decompress": schema.BoolAttribute{
|
|
MarkdownDescription: "Whether or not to decompress the contents. " +
|
|
"If left empty, this will default to false.",
|
|
Optional: true,
|
|
Computed: true,
|
|
},
|
|
"id": schema.StringAttribute{
|
|
MarkdownDescription: "Unique identifier for the datasource. The SHA256 hash of the contents.",
|
|
Computed: true,
|
|
},
|
|
"data": schema.StringAttribute{
|
|
MarkdownDescription: "The resulting data output. This is the plain text representation of the contents attribute. " +
|
|
"This is computed by first decoding the data from base64, then decompressing the resulting gzip. " +
|
|
"If decompress is false, then this will be the base64 decoded version of the contents.",
|
|
Computed: true,
|
|
Sensitive: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (r *LocalSnapshotDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
|
|
// Prevent panic if the provider has not been configured.
|
|
// This only configures the provider, so anything here must be available in the provider package to configure.
|
|
// If you want to configure a client, do that in the Create/Read/Update/Delete functions.
|
|
if req.ProviderData == nil {
|
|
return
|
|
}
|
|
}
|
|
|
|
func (r *LocalSnapshotDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
|
|
tflog.Debug(ctx, fmt.Sprintf("Read Request Object: %+v", req))
|
|
|
|
var config LocalSnapshotDataSourceModel
|
|
resp.Diagnostics.Append(req.Config.Get(ctx, &config)...)
|
|
if resp.Diagnostics.HasError() {
|
|
return
|
|
}
|
|
contents := config.Contents.ValueString()
|
|
decompress := config.Decompress.ValueBool()
|
|
|
|
hasher := sha256.New()
|
|
hasher.Write([]byte(contents))
|
|
hashBytes := hasher.Sum(nil)
|
|
hashString := hex.EncodeToString(hashBytes)
|
|
|
|
config.Id = types.StringValue(hashString)
|
|
d, err := base64.StdEncoding.DecodeString(contents)
|
|
if err != nil {
|
|
resp.Diagnostics.AddError("Error decoding file: ", err.Error())
|
|
return
|
|
}
|
|
contents = string(d)
|
|
|
|
if decompress {
|
|
gzipReader, err := gzip.NewReader(bytes.NewReader([]byte(contents)))
|
|
if err != nil {
|
|
resp.Diagnostics.AddError("Error creating gzip reader: ", err.Error())
|
|
return
|
|
}
|
|
defer gzipReader.Close()
|
|
decompressedBytes, err := io.ReadAll(gzipReader)
|
|
if err != nil {
|
|
resp.Diagnostics.AddError("Error reading compressed bytes: ", err.Error())
|
|
return
|
|
}
|
|
contents = string(decompressedBytes)
|
|
}
|
|
|
|
config.Data = types.StringValue(contents)
|
|
|
|
resp.Diagnostics.Append(resp.State.Set(ctx, &config)...)
|
|
tflog.Debug(ctx, fmt.Sprintf("Read Response Object: %+v", *resp))
|
|
}
|