From 085f077eee9d0354860d3481fdc7f9ab79f9022f Mon Sep 17 00:00:00 2001 From: PranoSA Date: Tue, 23 Jan 2024 18:23:33 -0800 Subject: [PATCH] Added Resource Definition --- .gitignore | 2 + .../provider-install-verification/main.tf | 14 +- .../variables.tf | 6 + internal/provider/app_resource.go | 125 +++++++++-- internal/provider/provider.go | 2 +- internal/provider/string_resource.go | 2 +- internal/provider/unicode_data_source.go | 3 +- internal/unicode/provider.go | 202 ++++++++++++++++++ 8 files changed, 328 insertions(+), 28 deletions(-) create mode 100644 examples/provider-install-verification/variables.tf diff --git a/.gitignore b/.gitignore index fd3ad8e..c8658e2 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ website/vendor # Keep windows files with windows line endings *.winfile eol=crlf + +terraform-provider-unicode diff --git a/examples/provider-install-verification/main.tf b/examples/provider-install-verification/main.tf index 6f4d2f9..536f1af 100644 --- a/examples/provider-install-verification/main.tf +++ b/examples/provider-install-verification/main.tf @@ -10,7 +10,8 @@ terraform { } provider "unicode" { - user = "tray" + //user = "tray" + user = var.user } data "unicode_unicode_chars" "example" { @@ -27,7 +28,7 @@ output "unicode_char" { */ resource "unicode_app" "example_app" { - id = "examplrrrre" + id = "example 14" name = "example app234" description = "example" updated_at = "2021-07-01T00:00:00Z" @@ -38,13 +39,18 @@ output "name" { value = resource.unicode_app.example_app } -resource "unicode_unicode_string" "my_string" { +/*resource "unicode_unicode_string" "my_string" { app_id = unicode_app.example_app.id name = "Hello, World!" index = 0 id = "example" } -output "my_gamer" { +*/ + +/*output "my_gamer" { value = resource.unicode_unicode_string.my_string } +*/ + +// Get Resources and Print Them diff --git a/examples/provider-install-verification/variables.tf b/examples/provider-install-verification/variables.tf new file mode 100644 index 0000000..f174591 --- /dev/null +++ b/examples/provider-install-verification/variables.tf @@ -0,0 +1,6 @@ + +// User To Use For Provider + default of terry +variable "user" { + type = string + default = "terry" +} diff --git a/internal/provider/app_resource.go b/internal/provider/app_resource.go index 9d6d54a..23c04e4 100644 --- a/internal/provider/app_resource.go +++ b/internal/provider/app_resource.go @@ -3,12 +3,15 @@ package provider import ( "context" + unicode_client "terraform-provider-unicode/internal/unicode" + "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" ) var ( - _ resource.Resource = &UnicodeAppResource{} + _ resource.Resource = &UnicodeAppResource{} + _ resource.ResourceWithConfigure = &UnicodeAppResource{} ) func NewUnicodeAppResource() resource.Resource { @@ -16,6 +19,7 @@ func NewUnicodeAppResource() resource.Resource { } type UnicodeAppResource struct { + unicodeClient *unicode_client.UnicodeProviderClient } func (r *UnicodeAppResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { @@ -23,13 +27,6 @@ func (r *UnicodeAppResource) Metadata(_ context.Context, req resource.MetadataRe } // What Types and Annotations Will I need if I want to create a resource that will create a unicode character -type UnicodeAppModel struct { - Id string `json:"id" tfsdk:"id"` - Name string `json:"name" tfsdk:"name"` - Description string `json:"description" tfsdk:"description"` - Created_at string `json:"created_at" tfsdk:"created_at"` - Updated_at string `json:"updated_at" tfsdk:"updated_at"` -} func (r *UnicodeAppResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { //resp.Schema = schema.Schema{} @@ -58,24 +55,26 @@ func (r *UnicodeAppResource) Schema(_ context.Context, _ resource.SchemaRequest, // Create a New Resource func (r *UnicodeAppResource) Create(_ context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - //resp.State = req.Plan - var plan UnicodeAppModel - diags := req.Config.Get(context.Background(), &plan) - resp.Diagnostics.Append(diags...) + var plan unicode_client.UnicodeAppModel + //resp.State = req.NewState + req.Config.Get(context.Background(), &plan) - if resp.Diagnostics.HasError() { - return - } + resp.Diagnostics.AddWarning("Client Resource", plan.Id) - rt := &UnicodeAppModel{ + //Get the Resource Client + res, err := r.unicodeClient.CreateApplication(unicode_client.UnicodeAppModel{ Id: plan.Id, Name: plan.Name, Description: plan.Description, Created_at: plan.Created_at, Updated_at: plan.Updated_at, + }) + if err != nil { + resp.Diagnostics.AddError("Unable to get Unicode Applications", err.Error()) + return } - diags = resp.State.Set(context.Background(), rt) + diags := resp.State.Set(context.Background(), res) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { return @@ -84,14 +83,100 @@ func (r *UnicodeAppResource) Create(_ context.Context, req resource.CreateReques } func (r *UnicodeAppResource) Read(_ context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - resp.State = req.State + var response *unicode_client.UnicodeAppModel + + // + // + response, err := r.unicodeClient.GetApplications() + if err != nil { + resp.Diagnostics.AddError("Unable to get Unicode Applications", err.Error()) + resp.Diagnostics.AddWarning("OLD ID ", response.Id) + return + } + + var old_state unicode_client.UnicodeAppModel + + req.State.Get(context.Background(), &old_state) + + diags := resp.State.Set(context.Background(), old_state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } func (r *UnicodeAppResource) Update(_ context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan unicode_client.UnicodeAppModel //resp.State = req.NewState - resp.State = req.State + req.Config.Get(context.Background(), &plan) + //req.State.Get(context.Background(), &plan) + + var old_plan unicode_client.UnicodeAppModel + + req.State.Get(context.Background(), &old_plan) + + resp.Diagnostics.AddWarning("Client Resource", old_plan.Id) + + //Delete Old Resource + err := r.unicodeClient.DeleteApplication(old_plan.Id) //Assuming It keeps Same ID -> Stop Being a Silly Goose ... + if err != nil { + resp.Diagnostics.AddError("Unable to get Unicode Applications", err.Error()) + return + } + + //Get the Resource Client + res, err := r.unicodeClient.CreateApplication(unicode_client.UnicodeAppModel{ + Id: plan.Id, + Name: plan.Name, + Description: plan.Description, + Created_at: plan.Created_at, + Updated_at: plan.Updated_at, + }) + if err != nil { + resp.Diagnostics.AddError("Unable to get Unicode Applications", err.Error()) + return + } + + diags := resp.State.Set(context.Background(), res) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + } func (r *UnicodeAppResource) Delete(_ context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { - resp.State = req.State + //Delete Application + + var plan unicode_client.UnicodeAppModel + + req.State.Get(context.Background(), &plan) + + err := r.unicodeClient.DeleteApplication(plan.Id) + + if err != nil { + resp.Diagnostics.AddError("Unable to get Unicode Applications", err.Error()) + return + } + + // Return + resp.State.Set(context.Background(), nil) + +} + +func (r *UnicodeAppResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + + unicodeClient, ok := req.ProviderData.(*unicode_client.UnicodeProviderClient) + + if !ok { + //resp.Diagnostics.AddError("Unable to create client in resource", "Client is NULL After NewUnicodeProviderClient") + //return + resp.Diagnostics.AddWarning("Unable to create client in resource", "Client is NULL After NewUnicodeProviderClient") + unicodeClient = unicode_client.NewUnicodeProviderClient("bob") + } + + r.unicodeClient = unicodeClient + + return } diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 2a1ef14..ceb7a5b 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -129,7 +129,7 @@ func (up *unicodeProvider) Configure(ctx context.Context, req provider.Configure client := unicode_client.NewUnicodeProviderClient(username) if client == nil { - resp.Diagnostics.AddError("Unable to create client", "Client is NULL After NewUnicodeProviderClient") + resp.Diagnostics.AddError("Unable to create client provider", "Client is NULL After NewUnicodeProviderClient") return } diff --git a/internal/provider/string_resource.go b/internal/provider/string_resource.go index 2983bbf..4a58179 100644 --- a/internal/provider/string_resource.go +++ b/internal/provider/string_resource.go @@ -103,7 +103,7 @@ func (r *unicodeStringResource) Read(_ context.Context, req resource.ReadRequest } func (r *unicodeStringResource) Update(_ context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - // + // Didn't Change } func (r *unicodeStringResource) Delete(_ context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { diff --git a/internal/provider/unicode_data_source.go b/internal/provider/unicode_data_source.go index d36e4aa..b69e4de 100644 --- a/internal/provider/unicode_data_source.go +++ b/internal/provider/unicode_data_source.go @@ -48,12 +48,11 @@ func (d *UnicodeDataSource) Metadata(ctx context.Context, req datasource.Metadat func (d *UnicodeDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { - resp.Diagnostics.AddWarning("configure not implemented", "") - unicodeClient, ok := req.ProviderData.(*unicode_client.UnicodeProviderClient) if unicodeClient == nil { resp.Diagnostics.AddWarning("invalid provider configuration", "IS NULL") + unicodeClient = unicode_client.NewUnicodeProviderClient("bob") } if !ok { diff --git a/internal/unicode/provider.go b/internal/unicode/provider.go index a66f143..652818d 100644 --- a/internal/unicode/provider.go +++ b/internal/unicode/provider.go @@ -1,9 +1,43 @@ package unicode_client +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "net/http/cookiejar" + "net/url" +) + +var endpoint_url string = "unicode.compressibleflowcalculator.com/Prod/api/v1" +var host_url string = "unicode.compressibleflowcalculator.com" + type UnicodeProviderClient struct { Username string } +type UnicodeAppModel struct { + Id string `json:"appid" tfsdk:"id"` + Name string `json:"name" tfsdk:"name"` + Description string `json:"description" tfsdk:"description"` + Created_at string `json:"created_at" tfsdk:"created_at"` + Updated_at string `json:"updated_at" tfsdk:"updated_at"` +} + +type UnicodeAppModelReq struct { + Id string `json:"appid" tfsdk:"id"` + Name string `json:"name" tfsdk:"name"` + Description string `json:"description" tfsdk:"description"` + Created_at string `json:"created_at" tfsdk:"created_at"` + Updated_at string `json:"updated_at" tfsdk:"updated_at"` + Conversions []Conversion `json:"conversions"` +} + +type Conversion struct { + Value string `json:"value"` +} + func NewUnicodeProviderClient(username string) *UnicodeProviderClient { return &UnicodeProviderClient{Username: username} } @@ -23,3 +57,171 @@ func (u *UnicodeProviderClient) GetUnicodeCharData(unicodeChar string) (*Unicode Name: "LATIN SMALL LETTER A", }, nil } + +func (u *UnicodeProviderClient) GetApplications() (*UnicodeAppModel, error) { + + client := &http.Client{} + + return &UnicodeAppModel{ + + Id: "1", + Name: "App 1", + Description: "App 1 Description", + Created_at: "2021-01-01", + Updated_at: "2021-01-01", + }, nil + // Now Assign Cookie Header of user=Username + client.Jar.SetCookies(&url.URL{Scheme: "https", Host: host_url}, []*http.Cookie{ + { + Name: "user", + Value: u.Username, + }, + }) + + resp, err := client.Do(&http.Request{ + Method: "GET", + URL: &url.URL{Scheme: "https", Host: endpoint_url + "/saved"}, + }) + + if err != nil { + return nil, err + } + + var apps []UnicodeAppModel + + // Decode JSON + err = json.NewDecoder(resp.Body).Decode(&apps) + + if err != nil { + return nil, err + } + + //return &apps, nil + return &(apps[0]), nil +} + +func (u *UnicodeProviderClient) CreateApplication(model UnicodeAppModel) (*UnicodeAppModel, error) { + + jar, err := cookiejar.New(nil) + if err != nil { + return nil, err + } + + client := &http.Client{ + Jar: jar, + } + + //sET cOOKIE + client.Jar.SetCookies(&url.URL{Scheme: "https", Host: host_url}, []*http.Cookie{ + { + Name: "user", + Value: u.Username, + }, + }) + + // turn model into model request + model_req := UnicodeAppModelReq{ + Id: model.Id, + Name: model.Name, + Description: model.Description, + Created_at: model.Created_at, + Updated_at: model.Updated_at, + Conversions: []Conversion{}, + } + + body_bytes, err := json.Marshal(model_req) + if err != nil { + return nil, err + } + + req := &http.Request{ + Method: "POST", + URL: &url.URL{Scheme: "https", Host: host_url, Path: "/Prod/api/v1/application"}, + Body: io.NopCloser(bytes.NewReader(body_bytes)), + Header: make(http.Header), + } + + res, err := client.Do(req) + + if res.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code %d", res.StatusCode) + } + + if err != nil { + return nil, err + } + + return &model, nil +} + +func (u *UnicodeProviderClient) DeleteApplication(id string) error { + + jar, err := cookiejar.New(nil) + if err != nil { + return err + } + + client := &http.Client{ + Jar: jar, + } + + //sET cOOKIE + client.Jar.SetCookies(&url.URL{Scheme: "https", Host: host_url}, []*http.Cookie{ + { + Name: "user", + Value: u.Username, + }, + }) + + req := &http.Request{ + Method: "DELETE", + URL: &url.URL{Scheme: "https", Host: host_url, Path: "/Prod/api/v1/application/" + id}, + Body: nil, + Header: make(http.Header), + } + + res, err := client.Do(req) + + if err != nil { + return err + } + if res.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status code %d", res.StatusCode) + } + + return nil +} + +func (u *UnicodeProviderClient) UpdateApplication(model UnicodeAppModel) (*UnicodeAppModel, error) { + + jar, err := cookiejar.New(nil) + if err != nil { + return nil, err + } + + client := &http.Client{ + Jar: jar, + } + + //sET cOOKIE + + body_bytes, err := json.Marshal(model) + if err != nil { + return nil, err + } + + req := &http.Request{ + Method: "PUT", + URL: &url.URL{Scheme: "https", Host: host_url, Path: "/Prod/api/v1/application/" + model.Id}, + Body: io.NopCloser(bytes.NewReader(body_bytes)), + Header: make(http.Header), + } + + _, err = client.Do(req) + + if err != nil { + return nil, err + } + + return &model, nil +}