Skip to content

Commit

Permalink
add cluster data source
Browse files Browse the repository at this point in the history
  • Loading branch information
maciaszczykm committed Nov 15, 2023
1 parent 4711211 commit 521dba0
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 35 deletions.
4 changes: 4 additions & 0 deletions example/byok/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,7 @@ resource "plural_cluster" "byok_workload_cluster" {
"managed-by" = "terraform-provider-plural"
}
}

data "plural_cluster" "byok_workload_cluster" {
handle = "wctf"
}
111 changes: 103 additions & 8 deletions internal/datasource/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,127 @@ package datasource

import (
"context"
"fmt"

"terraform-provider-plural/internal/model"

"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
console "github.com/pluralsh/console-client-go"
)

func NewClusterDataSource() datasource.DataSource {
return &clusterDataSource{}
}

type clusterDataSource struct {
Id types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
Handle types.String `tfsdk:"handle"`
Cloud types.String `tfsdk:"cloud"`
Tags types.Map `tfsdk:"tags"`
client *console.Client
}

func (d *clusterDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_cluster"
}

func (d *clusterDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{}
resp.Schema = schema.Schema{
MarkdownDescription: "A representation of a cluster you can deploy to.",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Optional: true,
Computed: true,
MarkdownDescription: "Internal identifier of this cluster.",
},
"inserted_at": schema.StringAttribute{
MarkdownDescription: "Creation date of this cluster.",
Computed: true,
},
"name": schema.StringAttribute{
MarkdownDescription: "Human-readable name of this cluster, that also translates to cloud resource name.",
Computed: true,
},
"handle": schema.StringAttribute{
MarkdownDescription: "A short, unique human-readable name used to identify this cluster. Does not necessarily map to the cloud resource name.",
Optional: true,
Computed: true,
},
"cloud": schema.StringAttribute{
MarkdownDescription: "The cloud provider used to create this cluster.",
Computed: true,
},
"protect": schema.BoolAttribute{
MarkdownDescription: "If set to `true` then this cluster cannot be deleted.",
Computed: true,
},
"tags": schema.MapAttribute{
MarkdownDescription: "Key-value tags used to filter clusters.",
Computed: true,
ElementType: types.StringType,
},
},
}
}

func (d *clusterDataSource) Configure(_ context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
if req.ProviderData == nil {
return
}

client, ok := req.ProviderData.(*console.Client)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Cluster Resource Configure Type",
fmt.Sprintf("Expected *console.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData),
)
return
}

d.client = client
}

// TODO: Support read by handle and ID.
func (d *clusterDataSource) Read(_ context.Context, _ datasource.ReadRequest, _ *datasource.ReadResponse) {
func (d *clusterDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
var data model.Cluster
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

if data.Id.IsNull() && data.Handle.IsNull() {
resp.Diagnostics.AddError(
"Missing Cluster ID and Handle",
"The provider could not read cluster data. ID or handle needs to be specified.",
)
}

// First try to fetch cluster by ID if it was provided.
var cluster *console.ClusterFragment
if !data.Id.IsNull() {
if c, err := d.client.GetCluster(ctx, data.Id.ValueStringPointer()); err != nil {
resp.Diagnostics.AddWarning("Client Error", fmt.Sprintf("Unable to read cluster by ID, got error: %s", err))
} else {
cluster = c.Cluster
}
}

// If cluster was not fetched yet and handle was provided then try to use it to fetch cluster.
if cluster == nil && !data.Handle.IsNull() {
if c, err := d.client.GetClusterByHandle(ctx, data.Handle.ValueStringPointer()); err != nil {
resp.Diagnostics.AddWarning("Client Error", fmt.Sprintf("Unable to read cluster by handle, got error: %s", err))
} else {
cluster = c.Cluster
}
}

if cluster == nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to read cluster, see warnings for more information"))
return
}

data.Id = types.StringValue(cluster.ID)
data.InseredAt = types.StringPointerValue(cluster.InsertedAt)
data.Name = types.StringValue(cluster.Name)
data.Handle = types.StringPointerValue(cluster.Handle)
data.Protect = types.BoolPointerValue(cluster.Protect)

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}
14 changes: 14 additions & 0 deletions internal/model/model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package model

import "github.com/hashicorp/terraform-plugin-framework/types"

// Cluster describes the cluster resource and data source model.
type Cluster struct {
Id types.String `tfsdk:"id"`
InseredAt types.String `tfsdk:"inserted_at"`
Name types.String `tfsdk:"name"`
Handle types.String `tfsdk:"handle"`
Cloud types.String `tfsdk:"cloud"`
Protect types.Bool `tfsdk:"protect"`
Tags types.Map `tfsdk:"tags"`
}
45 changes: 18 additions & 27 deletions internal/resource/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"fmt"

"terraform-provider-plural/internal/model"

"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
Expand All @@ -16,34 +18,23 @@ import (
console "github.com/pluralsh/console-client-go"
)

var _ resource.Resource = &ClusterResource{}
var _ resource.ResourceWithImportState = &ClusterResource{}
var _ resource.Resource = &clusterResource{}
var _ resource.ResourceWithImportState = &clusterResource{}

func NewClusterResource() resource.Resource {
return &ClusterResource{}
return &clusterResource{}
}

// ClusterResource defines the cluster resource implementation.
type ClusterResource struct {
type clusterResource struct {
client *console.Client
}

// ClusterResourceModel describes the cluster resource data model.
type ClusterResourceModel struct {
Id types.String `tfsdk:"id"`
InseredAt types.String `tfsdk:"inserted_at"`
Name types.String `tfsdk:"name"`
Handle types.String `tfsdk:"handle"`
Cloud types.String `tfsdk:"cloud"`
Protect types.Bool `tfsdk:"protect"`
Tags types.Map `tfsdk:"tags"`
}

func (r *ClusterResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
func (r *clusterResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = req.ProviderTypeName + "_cluster"
}

func (r *ClusterResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "A representation of a cluster you can deploy to.",
Attributes: map[string]schema.Attribute{
Expand Down Expand Up @@ -85,7 +76,7 @@ func (r *ClusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
}
}

func (r *ClusterResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
func (r *clusterResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) {
if req.ProviderData == nil {
return
}
Expand All @@ -102,8 +93,8 @@ func (r *ClusterResource) Configure(_ context.Context, req resource.ConfigureReq
r.client = client
}

func (r *ClusterResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data ClusterResourceModel
func (r *clusterResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
var data model.Cluster
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
Expand Down Expand Up @@ -145,8 +136,8 @@ func (r *ClusterResource) Create(ctx context.Context, req resource.CreateRequest
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *ClusterResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data ClusterResourceModel
func (r *clusterResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
var data model.Cluster
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
Expand All @@ -167,8 +158,8 @@ func (r *ClusterResource) Read(ctx context.Context, req resource.ReadRequest, re
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *ClusterResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data ClusterResourceModel
func (r *clusterResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
var data model.Cluster
resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
Expand All @@ -190,8 +181,8 @@ func (r *ClusterResource) Update(ctx context.Context, req resource.UpdateRequest
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

func (r *ClusterResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data ClusterResourceModel
func (r *clusterResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
var data model.Cluster
resp.Diagnostics.Append(req.State.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
Expand All @@ -206,6 +197,6 @@ func (r *ClusterResource) Delete(ctx context.Context, req resource.DeleteRequest
tflog.Trace(ctx, "deleted the cluster")
}

func (r *ClusterResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
func (r *clusterResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}

0 comments on commit 521dba0

Please sign in to comment.