Skip to content

Commit

Permalink
Add basic global service resource
Browse files Browse the repository at this point in the history
We definitely need to automate creating these as well.
  • Loading branch information
michaeljguarino committed Dec 25, 2023
1 parent 5e1c4ee commit 145e9c5
Show file tree
Hide file tree
Showing 4 changed files with 227 additions and 3 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/hashicorp/terraform-plugin-framework-validators v0.12.0
github.com/hashicorp/terraform-plugin-log v0.9.0
github.com/mitchellh/go-homedir v1.1.0
github.com/pluralsh/console-client-go v0.0.63
github.com/pluralsh/console-client-go v0.0.66
github.com/pluralsh/plural-cli v0.8.3-0.20231204142546-98d50a1936d3
github.com/pluralsh/polly v0.1.4
github.com/samber/lo v1.38.1
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -856,8 +856,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
github.com/pluralsh/console-client-go v0.0.63 h1:gZn6qsdNE9BbEZfi3fT/CCt2voGNiJrfBTQ7Dp0qZNE=
github.com/pluralsh/console-client-go v0.0.63/go.mod h1:u/RjzXE3wtl3L6wiWxwhQHSpxFX46+EYvpkss2mALN4=
github.com/pluralsh/console-client-go v0.0.66 h1:IbspdlRyHieQSr3bLOEumO09LIL8vMuEV3m2fM7vcnI=
github.com/pluralsh/console-client-go v0.0.66/go.mod h1:u/RjzXE3wtl3L6wiWxwhQHSpxFX46+EYvpkss2mALN4=
github.com/pluralsh/gqlclient v1.11.0 h1:FfXW7FiEJLHOfTAa7NxDb8jb3aMZNIpCAcG+bg8uHYA=
github.com/pluralsh/gqlclient v1.11.0/go.mod h1:qSXKUlio1F2DRPy8el4oFYsmpKbkUYspgPB87T4it5I=
github.com/pluralsh/plural-cli v0.8.3-0.20231204142546-98d50a1936d3 h1:zGbRWvgu4eQ1gygIbLiWfAQl+MR6Z11MJTIxN8H0hRo=
Expand Down
165 changes: 165 additions & 0 deletions internal/resource/global_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package resource

import (
"context"
"fmt"

"terraform-provider-plural/internal/common"

"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/mapplanmodifier"
"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"

"terraform-provider-plural/internal/client"
)

var _ resource.Resource = &GlobalServiceResource{}
var _ resource.ResourceWithImportState = &GlobalServiceResource{}

func NewGlobalServiceResource() resource.Resource {
return &GlobalServiceResource{}
}

// GlobalServiceResource defines the GlobalService resource implementation.
type GlobalServiceResource struct {
client *client.Client
}

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

func (r *GlobalServiceResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
MarkdownDescription: "GlobalService resource",
Attributes: map[string]schema.Attribute{
"id": schema.StringAttribute{
Computed: true,
Description: "Internal identifier of this GlobalService.",
MarkdownDescription: "Internal identifier of this GlobalService.",
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"name": schema.StringAttribute{
Required: true,
Description: "Name of this GlobalService.",
MarkdownDescription: "Name of this GlobalService.",
},
"distro": schema.StringAttribute{
Optional: true,
Description: "Kubernetes distribution for this global servie, eg EKS, AKS, GKE, K3S.",
},
"provider_id": schema.StringAttribute{
Optional: true,
Description: "Id of a CAPI provider that this global service targets",
MarkdownDescription: "Id of a CAPI provider that this global service targets.",
},
"service_id": schema.StringAttribute{
Optional: true,
Required: true,
Description: "The id of the service that will be replicated by this global service.",
MarkdownDescription: "The id of the service that will be replicated by this global service.",
},
"tags": schema.MapAttribute{
Description: "Key-value tags used to target clusters for this global service.",
MarkdownDescription: "Key-value tags used to target clusters for this global service.",
Optional: true,
ElementType: types.StringType,
PlanModifiers: []planmodifier.Map{mapplanmodifier.RequiresReplace()},
},
},
}
}

func (r *GlobalServiceResource) Configure(
_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse,
) {
if req.ProviderData == nil {
return
}

data, ok := req.ProviderData.(*common.ProviderData)
if !ok {
resp.Diagnostics.AddError(
"Unexpected Git Repository Resource Configure Type",
fmt.Sprintf(
"Expected *common.ProviderData, got: %T. Please report this issue to the provider developers.",
req.ProviderData,
),
)

return
}

r.client = data.Client
}

func (r *GlobalServiceResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
data := new(globalService)
resp.Diagnostics.Append(req.Plan.Get(ctx, data)...)
if resp.Diagnostics.HasError() {
return
}

response, err := r.client.CreateGlobalService(ctx, data.Attributes(ctx, resp.Diagnostics))
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to create GlobalService, got error: %s", err))
return
}

data.From(response.CreateGlobalService, resp.Diagnostics)
resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
}

func (r *GlobalServiceResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
data := new(globalService)
resp.Diagnostics.Append(req.State.Get(ctx, data)...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
}

func (r *GlobalServiceResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
data := new(globalService)
resp.Diagnostics.Append(req.Plan.Get(ctx, data)...)
if resp.Diagnostics.HasError() {
return
}

_, err := r.client.UpdateGlobalService(ctx, data.Id.ValueString(), data.Attributes(ctx, resp.Diagnostics))
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to update GlobalService, got error: %s", err))
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, data)...)
}

func (r *GlobalServiceResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
data := new(globalService)
resp.Diagnostics.Append(req.State.Get(ctx, data)...)
if resp.Diagnostics.HasError() {
return
}

_, err := r.client.DeleteGlobalService(ctx, data.Id.ValueString())
if err != nil {
resp.Diagnostics.AddError("Client Error", fmt.Sprintf("Unable to delete GlobalService, got error: %s", err))
return
}
}

func (r *GlobalServiceResource) ImportState(
ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse,
) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp)
}
59 changes: 59 additions & 0 deletions internal/resource/global_service_model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package resource

import (
"context"
"strings"
"terraform-provider-plural/internal/common"

"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
gqlclient "github.com/pluralsh/console-client-go"
"github.com/samber/lo"
)

type globalService struct {
Id types.String `tfsdk:"id"`
Name types.String `tfsdk:"name"`
ServiceId types.String `tfsdk:"service_id"`
Distro types.String `tfsdk:"distro"`
ProviderId types.String `tfsdk:"provider_id"`
Tags types.Map `tfsdk:"tags"`
}

func (g *globalService) From(response *gqlclient.GlobalServiceFragment, d diag.Diagnostics) {
g.Id = types.StringValue(response.ID)
g.Name = types.StringValue(response.Name)
g.ServiceId = types.StringValue(response.Service.ID)
if response.Distro != nil {
g.Distro = types.StringValue(string(*response.Distro))
}
if response.Provider != nil {
g.ProviderId = types.StringValue(response.Provider.ID)
}
g.Tags = common.ClusterTagsFrom(response.Tags, d)
}

func (g *globalService) Attributes(ctx context.Context, d diag.Diagnostics) gqlclient.GlobalServiceAttributes {
var distro *gqlclient.ClusterDistro
if !g.Distro.IsNull() {
distro = lo.ToPtr(gqlclient.ClusterDistro(strings.ToUpper(g.Distro.ValueString())))
}
return gqlclient.GlobalServiceAttributes{
Name: g.Name.ValueString(),
Distro: distro,
ProviderID: g.ProviderId.ValueStringPointer(),
Tags: g.TagsAttribute(ctx, d),
}
}

func (g *globalService) TagsAttribute(ctx context.Context, d diag.Diagnostics) []*gqlclient.TagAttributes {
result := make([]*gqlclient.TagAttributes, 0)
elements := make(map[string]types.String, len(g.Tags.Elements()))
d.Append(g.Tags.ElementsAs(ctx, &elements, false)...)

for k, v := range elements {
result = append(result, &gqlclient.TagAttributes{Name: k, Value: v.ValueString()})
}

return result
}

0 comments on commit 145e9c5

Please sign in to comment.