-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
346 additions
and
0 deletions.
There are no files selected for viewing
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,3 @@ | ||
provider "clevercloud" { | ||
organisation = "%s" | ||
} |
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,21 @@ | ||
package materiakv | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/resource" | ||
"go.clever-cloud.dev/client" | ||
) | ||
|
||
type ResourceMateriaKV struct { | ||
cc *client.Client | ||
org string | ||
} | ||
|
||
func NewResourceMateriaKV() resource.Resource { | ||
return &ResourceMateriaKV{} | ||
} | ||
|
||
func (r *ResourceMateriaKV) Metadata(ctx context.Context, req resource.MetadataRequest, res *resource.MetadataResponse) { | ||
res.TypeName = req.ProviderTypeName + "_materiakv" | ||
} |
Empty file.
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,175 @@ | ||
package materiakv | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/path" | ||
"github.com/hashicorp/terraform-plugin-framework/resource" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
"github.com/hashicorp/terraform-plugin-log/tflog" | ||
"go.clever-cloud.com/terraform-provider/pkg" | ||
"go.clever-cloud.com/terraform-provider/pkg/provider" | ||
"go.clever-cloud.com/terraform-provider/pkg/tmp" | ||
) | ||
|
||
// Weird behaviour, but TF can ask for a Resource without having configured a Provider (maybe for Meta and Schema) | ||
// So we need to handle the case there is no ProviderData | ||
func (r *ResourceMateriaKV) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { | ||
tflog.Info(ctx, "ResourceMateriaKV.Configure()") | ||
|
||
// Prevent panic if the provider has not been configured. | ||
if req.ProviderData == nil { | ||
return | ||
} | ||
|
||
provider, ok := req.ProviderData.(provider.Provider) | ||
if ok { | ||
r.cc = provider.Client() | ||
r.org = provider.Organization() | ||
} | ||
} | ||
|
||
// Create a new resource | ||
func (r *ResourceMateriaKV) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { | ||
kv := MateriaKV{} | ||
|
||
resp.Diagnostics.Append(req.Plan.Get(ctx, &kv)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
addonsProvidersRes := tmp.GetAddonsProviders(ctx, r.cc) | ||
if addonsProvidersRes.HasError() { | ||
resp.Diagnostics.AddError("failed to get addon providers", addonsProvidersRes.Error().Error()) | ||
return | ||
} | ||
|
||
addonsProviders := addonsProvidersRes.Payload() | ||
prov := pkg.LookupAddonProvider(*addonsProviders, "kv") | ||
plan := pkg.LookupProviderPlan(prov, "alpha") | ||
|
||
addonReq := tmp.AddonRequest{ | ||
Name: kv.Name.ValueString(), | ||
Plan: plan.ID, | ||
ProviderID: "kv", | ||
Region: "par", | ||
} | ||
|
||
res := tmp.CreateAddon(ctx, r.cc, r.org, addonReq) | ||
if res.HasError() { | ||
resp.Diagnostics.AddError("failed to create addon", res.Error().Error()) | ||
return | ||
} | ||
|
||
kv.ID = pkg.FromStr(res.Payload().RealID) | ||
kv.CreationDate = pkg.FromI(res.Payload().CreationDate) | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, kv)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
kvInfoRes := tmp.GetMateriaKV(ctx, r.cc, r.org, kv.ID.ValueString()) | ||
if kvInfoRes.HasError() { | ||
resp.Diagnostics.AddError("failed to get materiakv connection infos", kvInfoRes.Error().Error()) | ||
return | ||
} | ||
|
||
kvInfo := kvInfoRes.Payload() | ||
tflog.Info(ctx, "API response", map[string]interface{}{ | ||
"payload": fmt.Sprintf("%+v", kvInfo), | ||
}) | ||
kv.Host = pkg.FromStr(kvInfo.Host) | ||
kv.Port = pkg.FromI(int64(kvInfo.Port)) | ||
kv.Token = pkg.FromStr(kvInfo.Token) | ||
|
||
resp.Diagnostics.Append(resp.State.Set(ctx, kv)...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
} | ||
|
||
// Read resource information | ||
func (r *ResourceMateriaKV) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { | ||
tflog.Info(ctx, "MateriaKV READ", map[string]interface{}{"request": req}) | ||
|
||
var kv MateriaKV | ||
diags := req.State.Get(ctx, &kv) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
|
||
addonPGRes := tmp.GetMateriaKV(ctx, r.cc, r.org, kv.ID.ValueString()) | ||
if addonPGRes.IsNotFoundError() { | ||
diags = resp.State.SetAttribute(ctx, path.Root("id"), types.StringUnknown()) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
} | ||
if addonPGRes.IsNotFoundError() { | ||
resp.State.RemoveResource(ctx) | ||
return | ||
} | ||
if addonPGRes.HasError() { | ||
resp.Diagnostics.AddError("failed to get materiakv resource", addonPGRes.Error().Error()) | ||
} | ||
|
||
addonPG := addonPGRes.Payload() | ||
|
||
if addonPG.Status.Status == "TO_DELETE" { | ||
resp.State.RemoveResource(ctx) | ||
return | ||
} | ||
|
||
tflog.Info(ctx, "STATE", map[string]interface{}{"kv": kv}) | ||
tflog.Info(ctx, "API", map[string]interface{}{"kv": addonPG}) | ||
kv.Host = pkg.FromStr(addonPG.Host) | ||
kv.Port = pkg.FromI(int64(addonPG.Port)) | ||
kv.Token = pkg.FromStr(addonPG.Token) | ||
|
||
diags = resp.State.Set(ctx, kv) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
} | ||
|
||
// Update resource | ||
func (r *ResourceMateriaKV) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { | ||
// TODO | ||
} | ||
|
||
// Delete resource | ||
func (r *ResourceMateriaKV) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { | ||
kv := MateriaKV{} | ||
|
||
diags := req.State.Get(ctx, &kv) | ||
resp.Diagnostics.Append(diags...) | ||
if resp.Diagnostics.HasError() { | ||
return | ||
} | ||
tflog.Info(ctx, "MateriaKV DELETE", map[string]interface{}{"kv": kv}) | ||
|
||
res := tmp.DeleteAddon(ctx, r.cc, r.org, kv.ID.ValueString()) | ||
if res.IsNotFoundError() { | ||
resp.State.RemoveResource(ctx) | ||
return | ||
} | ||
if res.HasError() { | ||
resp.Diagnostics.AddError("failed to delete addon", res.Error().Error()) | ||
return | ||
} | ||
|
||
resp.State.RemoveResource(ctx) | ||
} | ||
|
||
// Import resource | ||
func (r *ResourceMateriaKV) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { | ||
// Save the import identifier in the id attribute | ||
// and call Read() to fill fields | ||
attr := path.Root("id") | ||
resource.ImportStatePassthroughID(ctx, attr, req, resp) | ||
} |
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,44 @@ | ||
package materiakv | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/resource" | ||
"github.com/hashicorp/terraform-plugin-framework/resource/schema" | ||
"github.com/hashicorp/terraform-plugin-framework/types" | ||
) | ||
|
||
type MateriaKV struct { | ||
ID types.String `tfsdk:"id"` | ||
Name types.String `tfsdk:"name"` | ||
CreationDate types.Int64 `tfsdk:"creation_date"` | ||
Host types.String `tfsdk:"host"` | ||
Port types.Int64 `tfsdk:"port"` | ||
Token types.String `tfsdk:"token"` | ||
} | ||
|
||
//go:embed resource_materiakv.md | ||
var resourceMateriaKVDoc string | ||
|
||
func (r ResourceMateriaKV) Schema(_ context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { | ||
resp.Schema = schema.Schema{ | ||
Version: 0, | ||
MarkdownDescription: resourceMateriaKVDoc, | ||
Attributes: map[string]schema.Attribute{ | ||
// customer provided | ||
"name": schema.StringAttribute{Required: true, MarkdownDescription: "Name of the service"}, | ||
// provider | ||
"id": schema.StringAttribute{Computed: true, MarkdownDescription: "Generated unique identifier"}, | ||
"creation_date": schema.Int64Attribute{Computed: true, MarkdownDescription: "Date of database creation"}, | ||
"host": schema.StringAttribute{Computed: true, MarkdownDescription: "Database host, used to connect to"}, | ||
"port": schema.Int64Attribute{Computed: true, MarkdownDescription: "Database port"}, | ||
"token": schema.StringAttribute{Computed: true, MarkdownDescription: "Token to authenticate"}, | ||
}, | ||
} | ||
} | ||
|
||
// https://developer.hashicorp.com/terraform/plugin/framework/resources/state-upgrade#implementing-state-upgrade-support | ||
func (r ResourceMateriaKV) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader { | ||
return map[int64]resource.StateUpgrader{} | ||
} |
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,73 @@ | ||
package materiakv_test | ||
|
||
import ( | ||
"context" | ||
_ "embed" | ||
"fmt" | ||
"os" | ||
"regexp" | ||
"testing" | ||
"time" | ||
|
||
"github.com/hashicorp/terraform-plugin-framework/providerserver" | ||
"github.com/hashicorp/terraform-plugin-go/tfprotov6" | ||
"github.com/hashicorp/terraform-plugin-testing/helper/resource" | ||
"github.com/hashicorp/terraform-plugin-testing/terraform" | ||
"go.clever-cloud.com/terraform-provider/pkg/provider/impl" | ||
"go.clever-cloud.com/terraform-provider/pkg/tmp" | ||
"go.clever-cloud.dev/client" | ||
) | ||
|
||
//go:embed resource_materiakv_test_block.tf | ||
var materiakvBlock string | ||
|
||
//go:embed provider_test_block.tf | ||
var providerBlock string | ||
|
||
var protoV6Provider = map[string]func() (tfprotov6.ProviderServer, error){ | ||
"clevercloud": providerserver.NewProtocol6WithError(impl.New("test")()), | ||
} | ||
|
||
func TestAccMateriaKV_basic(t *testing.T) { | ||
ctx := context.Background() | ||
rName := fmt.Sprintf("tf-test-kv-%d", time.Now().UnixMilli()) | ||
fullName := fmt.Sprintf("clevercloud_materiakv.%s", rName) | ||
cc := client.New(client.WithAutoOauthConfig()) | ||
org := os.Getenv("ORGANISATION") | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { | ||
if org == "" { | ||
t.Fatalf("missing ORGANISATION env var") | ||
} | ||
}, | ||
ProtoV6ProviderFactories: protoV6Provider, | ||
CheckDestroy: func(state *terraform.State) error { | ||
for _, resource := range state.RootModule().Resources { | ||
res := tmp.GetMateriaKV(ctx, cc, org, resource.Primary.ID) | ||
if res.IsNotFoundError() { | ||
continue | ||
} | ||
if res.HasError() { | ||
return fmt.Errorf("unexpectd error: %s", res.Error().Error()) | ||
} | ||
if res.Payload().Status.Status == "TO_DELETE" { | ||
continue | ||
} | ||
|
||
return fmt.Errorf("expect resource '%s' to be deleted", resource.Primary.ID) | ||
} | ||
return nil | ||
}, | ||
Steps: []resource.TestStep{{ | ||
ResourceName: rName, | ||
Config: fmt.Sprintf(providerBlock, org) + fmt.Sprintf(materiakvBlock, rName, rName), | ||
Check: resource.ComposeAggregateTestCheckFunc( | ||
resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^kv_.*`)), | ||
resource.TestMatchResourceAttr(fullName, "host", regexp.MustCompile(`^.*clever-cloud.com$`)), | ||
resource.TestCheckResourceAttrSet(fullName, "port"), | ||
resource.TestCheckResourceAttrSet(fullName, "token"), | ||
), | ||
}}, | ||
}) | ||
} |
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,3 @@ | ||
resource "clevercloud_materiakv" "%s" { | ||
name = "%s" | ||
} |
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