From 71ec0743b8393a517589e57fe5bcc08be721946b Mon Sep 17 00:00:00 2001 From: miton18 Date: Thu, 26 Dec 2024 15:16:52 +0100 Subject: [PATCH] feat(PHP): implem update --- pkg/application/creation.go | 61 +++++++++++ pkg/attributes/addon.go | 7 +- pkg/attributes/runtime.go | 4 + pkg/helper/provider_block.go | 16 ++- pkg/helper/state.go | 20 ++++ pkg/resources/addon/addon_test.go | 6 +- pkg/resources/cellar/bucket/bucket_test.go | 6 +- pkg/resources/cellar/cellar_test.go | 6 +- pkg/resources/cellar/schema.go | 6 +- pkg/resources/docker/resource_docker_test.go | 6 +- pkg/resources/java/java_test.go | 6 +- pkg/resources/keycloak/keycloak_test.go | 10 +- pkg/resources/materiakv/materiakv_test.go | 6 +- pkg/resources/metabase/metabase_test.go | 10 +- pkg/resources/mongodb/mongodb_test.go | 12 +-- pkg/resources/nodejs/nodejs_test.go | 10 +- pkg/resources/php/crud.go | 102 +++++++++++++++++-- pkg/resources/php/php_test.go | 17 +++- pkg/resources/postgresql/postgresql_test.go | 12 +-- pkg/resources/scala/scala_test.go | 6 +- pkg/resources/static/static_test.go | 6 +- pkg/tmp/app.go | 24 +++-- 22 files changed, 286 insertions(+), 73 deletions(-) create mode 100644 pkg/helper/state.go diff --git a/pkg/application/creation.go b/pkg/application/creation.go index 705b446..a34f701 100644 --- a/pkg/application/creation.go +++ b/pkg/application/creation.go @@ -20,6 +20,17 @@ type CreateReq struct { Dependencies []string } +type UpdateReq struct { + ID string + Client *client.Client + Organization string + Application tmp.UpdateAppReq + Environment map[string]string + VHosts []string + Deployment *Deployment + Dependencies []string +} + type Deployment struct { Repository string Commit *string @@ -79,6 +90,56 @@ func CreateApp(ctx context.Context, req CreateReq) (*CreateRes, diag.Diagnostics return res, diags } +func UpdateApp(ctx context.Context, req UpdateReq) (*CreateRes, diag.Diagnostics) { + diags := diag.Diagnostics{} + + // Application + res := &CreateRes{} + + appRes := tmp.UpdateApp(ctx, req.Client, req.Organization, req.ID, req.Application) + if appRes.HasError() { + diags.AddError("failed to update application", appRes.Error().Error()) + tflog.Error(ctx, "failed to update app", map[string]interface{}{"error": appRes.Error().Error(), "payload": fmt.Sprintf("%+v", req.Application)}) + return nil, diags + } + + res.Application = *appRes.Payload() + + // Environment + envRes := tmp.UpdateAppEnv(ctx, req.Client, req.Organization, res.Application.ID, req.Environment) + if envRes.HasError() { + diags.AddError("failed to configure application environment", envRes.Error().Error()) + } + + // VHosts + for _, vhost := range req.VHosts { + addVhostRes := tmp.AddAppVHost(ctx, req.Client, req.Organization, res.Application.ID, vhost) + if addVhostRes.HasError() { + diags.AddError("failed to add additional vhost", addVhostRes.Error().Error()) + } + } + // TODO: old vhost need to be cleaned + + // Git Deployment + if req.Deployment != nil { + diags.Append(gitDeploy(ctx, *req.Deployment, req.Client, res.Application.DeployURL)...) + } + + // Dependencies + for _, dependency := range req.Dependencies { + // TODO: support another apps as dependency + + depRes := tmp.AddAppLinkedAddons(ctx, req.Client, req.Organization, res.Application.ID, dependency) + if depRes.HasError() { + tflog.Error(ctx, "ERROR: "+dependency, map[string]interface{}{"err": depRes.Error().Error()}) + diags.AddError("failed to add dependency", depRes.Error().Error()) + } + } + // TODO: unlink unneeded deps + + return res, diags +} + // on clever side, it's an enum func FromForceHTTPS(force bool) string { if force { diff --git a/pkg/attributes/addon.go b/pkg/attributes/addon.go index 0783e5e..c1dbb61 100644 --- a/pkg/attributes/addon.go +++ b/pkg/attributes/addon.go @@ -2,7 +2,10 @@ package attributes import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "go.clever-cloud.com/terraform-provider/pkg" ) @@ -16,7 +19,7 @@ type Addon struct { } var addonCommon = map[string]schema.Attribute{ - "id": schema.StringAttribute{Computed: true, MarkdownDescription: "Generated unique identifier"}, + "id": schema.StringAttribute{Computed: true, MarkdownDescription: "Generated unique identifier", PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}}, "name": schema.StringAttribute{Required: true, MarkdownDescription: "Name of the service"}, "plan": schema.StringAttribute{Required: true, MarkdownDescription: "Database size and spec"}, "region": schema.StringAttribute{ @@ -25,7 +28,7 @@ var addonCommon = map[string]schema.Attribute{ Default: stringdefault.StaticString("par"), MarkdownDescription: "Geographical region where the data will be stored", }, - "creation_date": schema.Int64Attribute{Computed: true, MarkdownDescription: "Date of database creation"}, + "creation_date": schema.Int64Attribute{Computed: true, MarkdownDescription: "Date of database creation", PlanModifiers: []planmodifier.Int64{int64planmodifier.UseStateForUnknown()}}, } func WithAddonCommons(runtimeSpecifics map[string]schema.Attribute) map[string]schema.Attribute { diff --git a/pkg/attributes/runtime.go b/pkg/attributes/runtime.go index 0da76ce..ef1ef74 100644 --- a/pkg/attributes/runtime.go +++ b/pkg/attributes/runtime.go @@ -7,7 +7,9 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" "go.clever-cloud.com/terraform-provider/pkg" ) @@ -98,10 +100,12 @@ var runtimeCommon = map[string]schema.Attribute{ "id": schema.StringAttribute{ Computed: true, MarkdownDescription: "Unique identifier generated during application creation", + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, "deploy_url": schema.StringAttribute{ Computed: true, MarkdownDescription: "Git URL used to push source code", + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, }, // cleverapps one "vhost": schema.StringAttribute{ diff --git a/pkg/helper/provider_block.go b/pkg/helper/provider_block.go index e89c0a0..eda8c75 100644 --- a/pkg/helper/provider_block.go +++ b/pkg/helper/provider_block.go @@ -1,9 +1,16 @@ package helper +import ( + "fmt" + + "go.clever-cloud.com/terraform-provider/pkg" +) + // Provider structur type Provider struct { provider string organisation string + blocks []fmt.Stringer } // New function type that accepts pointer to Provider @@ -37,6 +44,11 @@ func (p *Provider) SetOrganisation(orgName string) *Provider { return p } +func (p *Provider) Append(blocks ...fmt.Stringer) *Provider { + p.blocks = blocks + return p +} + // Provider block // - desc: chained function that stringify Provider into a terraform block // - args: none @@ -45,6 +57,8 @@ func (p *Provider) String() string { s := `provider "` + p.provider + `" { organisation = "` + p.organisation + `" } -` +` + pkg.Reduce[fmt.Stringer, string](p.blocks, "", func(acc string, block fmt.Stringer) string { + return acc + block.String() + "\n" + }) return s } diff --git a/pkg/helper/state.go b/pkg/helper/state.go new file mode 100644 index 0000000..71a3528 --- /dev/null +++ b/pkg/helper/state.go @@ -0,0 +1,20 @@ +package helper + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/tfsdk" +) + +func PlanFrom[T any](ctx context.Context, p tfsdk.Plan, diags diag.Diagnostics) T { + var t T + diags.Append(p.Get(ctx, &t)...) + return t +} + +func StateFrom[T any](ctx context.Context, s tfsdk.State, diags diag.Diagnostics) T { + var t T + diags.Append(s.Get(ctx, &t)...) + return t +} diff --git a/pkg/resources/addon/addon_test.go b/pkg/resources/addon/addon_test.go index 56f33ca..835d6a1 100644 --- a/pkg/resources/addon/addon_test.go +++ b/pkg/resources/addon/addon_test.go @@ -28,7 +28,7 @@ func TestAccAddon_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_addon.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) addonBlock := helper.NewRessource( "clevercloud_addon", rName, @@ -37,7 +37,7 @@ func TestAccAddon_basic(t *testing.T) { "region": "par", "plan": "clever_solo", "third_party_provider": "mailpace", - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -62,7 +62,7 @@ func TestAccAddon_basic(t *testing.T) { }, Steps: []resource.TestStep{{ ResourceName: rName, - Config: providerBlock + addonBlock, + Config: providerBlock.Append(addonBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^addon_.*`)), //resource.TestMatchResourceAttr(fullName, "password", regexp.MustCompile(`^[a-zA-Z0-9]+$`)), diff --git a/pkg/resources/cellar/bucket/bucket_test.go b/pkg/resources/cellar/bucket/bucket_test.go index 306d7d5..acf77dc 100644 --- a/pkg/resources/cellar/bucket/bucket_test.go +++ b/pkg/resources/cellar/bucket/bucket_test.go @@ -29,7 +29,7 @@ func TestAccCellarBucket_basic(t *testing.T) { rName := fmt.Sprintf("my-bucket-%d", time.Now().UnixMilli()) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) cellar := &tmp.AddonResponse{} if os.Getenv("TF_ACC") == "1" { @@ -59,7 +59,7 @@ func TestAccCellarBucket_basic(t *testing.T) { helper.SetKeyValues(map[string]any{ "id": rName, "cellar_id": cellar.RealID, - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -73,7 +73,7 @@ func TestAccCellarBucket_basic(t *testing.T) { ProtoV6ProviderFactories: TestProtoV6Provider, Steps: []resource.TestStep{{ ResourceName: "cellar_bucket_" + rName, - Config: providerBlock + cellarBucketBlock, + Config: providerBlock.Append(cellarBucketBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( func(*terraform.State) error { return nil diff --git a/pkg/resources/cellar/cellar_test.go b/pkg/resources/cellar/cellar_test.go index 09f4733..47760a9 100644 --- a/pkg/resources/cellar/cellar_test.go +++ b/pkg/resources/cellar/cellar_test.go @@ -29,14 +29,14 @@ func TestAccCellar_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_cellar.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) cellarBlock := helper.NewRessource( "clevercloud_cellar", rName, helper.SetKeyValues(map[string]any{ "name": rName, "region": "par", - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -47,7 +47,7 @@ func TestAccCellar_basic(t *testing.T) { ProtoV6ProviderFactories: TestProtoV6Provider, Steps: []resource.TestStep{{ ResourceName: "cellar_" + rName, - Config: providerBlock + cellarBlock, + Config: providerBlock.Append(cellarBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^cellar_.*`)), resource.TestMatchResourceAttr(fullName, "host", regexp.MustCompile(`^.*\.services.clever-cloud.com$`)), diff --git a/pkg/resources/cellar/schema.go b/pkg/resources/cellar/schema.go index 3306bde..4519cd7 100644 --- a/pkg/resources/cellar/schema.go +++ b/pkg/resources/cellar/schema.go @@ -6,7 +6,9 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/types" ) @@ -39,8 +41,8 @@ func (r ResourceCellar) Schema(_ context.Context, req resource.SchemaRequest, re }, // provider - "id": schema.StringAttribute{Computed: true, MarkdownDescription: "Generated unique identifier"}, - "host": schema.StringAttribute{Computed: true, MarkdownDescription: "S3 compatible Cellar endpoint"}, + "id": schema.StringAttribute{Computed: true, MarkdownDescription: "Generated unique identifier", PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}}, + "host": schema.StringAttribute{Computed: true, MarkdownDescription: "S3 compatible Cellar endpoint", PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}}, "key_id": schema.StringAttribute{Computed: true, MarkdownDescription: "Key ID used to authenticate"}, "key_secret": schema.StringAttribute{Computed: true, Sensitive: true, MarkdownDescription: "Key secret used to authenticate"}, }, diff --git a/pkg/resources/docker/resource_docker_test.go b/pkg/resources/docker/resource_docker_test.go index 71685c5..5048a91 100644 --- a/pkg/resources/docker/resource_docker_test.go +++ b/pkg/resources/docker/resource_docker_test.go @@ -29,7 +29,7 @@ func TestAccDocker_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_docker.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) dockerBlock := helper.NewRessource( "clevercloud_docker", rName, @@ -41,7 +41,7 @@ func TestAccDocker_basic(t *testing.T) { "smallest_flavor": "XS", "biggest_flavor": "M", "additional_vhosts": [1]string{"toto-tf5283457829345.com"}, - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -53,7 +53,7 @@ func TestAccDocker_basic(t *testing.T) { Steps: []resource.TestStep{{ Destroy: false, ResourceName: rName, - Config: providerBlock + dockerBlock, + Config: providerBlock.Append(dockerBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^app_.*$`)), resource.TestMatchResourceAttr(fullName, "deploy_url", regexp.MustCompile(`^git\+ssh.*\.git$`)), diff --git a/pkg/resources/java/java_test.go b/pkg/resources/java/java_test.go index c965726..4b4361f 100644 --- a/pkg/resources/java/java_test.go +++ b/pkg/resources/java/java_test.go @@ -29,7 +29,7 @@ func TestAccJava_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_java_war.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) javaBlock := helper.NewRessource( "clevercloud_java_war", rName, @@ -40,7 +40,7 @@ func TestAccJava_basic(t *testing.T) { "max_instance_count": 2, "smallest_flavor": "XS", "biggest_flavor": "M", - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -52,7 +52,7 @@ func TestAccJava_basic(t *testing.T) { Steps: []resource.TestStep{{ Destroy: false, ResourceName: rName, - Config: providerBlock + javaBlock, + Config: providerBlock.Append(javaBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^app_.*$`)), resource.TestMatchResourceAttr(fullName, "deploy_url", regexp.MustCompile(`^git\+ssh.*\.git$`)), diff --git a/pkg/resources/keycloak/keycloak_test.go b/pkg/resources/keycloak/keycloak_test.go index afc913d..61a7e1f 100644 --- a/pkg/resources/keycloak/keycloak_test.go +++ b/pkg/resources/keycloak/keycloak_test.go @@ -29,8 +29,12 @@ func TestAccKeycloak_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_keycloak.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() - materiakvBlock := helper.NewRessource("clevercloud_keycloak", rName, helper.SetKeyValues(map[string]any{"name": rName, "region": "par"})).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) + materiakvBlock := helper.NewRessource( + "clevercloud_keycloak", + rName, + helper.SetKeyValues(map[string]any{"name": rName, "region": "par"}), + ) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -55,7 +59,7 @@ func TestAccKeycloak_basic(t *testing.T) { }, Steps: []resource.TestStep{{ ResourceName: rName, - Config: providerBlock + materiakvBlock, + Config: providerBlock.Append(materiakvBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^keycloak_.*`)), resource.TestMatchResourceAttr(fullName, "host", regexp.MustCompile(`^.*clever-cloud.com$`)), diff --git a/pkg/resources/materiakv/materiakv_test.go b/pkg/resources/materiakv/materiakv_test.go index 4adc960..0647167 100644 --- a/pkg/resources/materiakv/materiakv_test.go +++ b/pkg/resources/materiakv/materiakv_test.go @@ -29,8 +29,8 @@ func TestAccMateriaKV_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_materia_kv.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() - materiakvBlock := helper.NewRessource("clevercloud_materia_kv", rName, helper.SetKeyValues(map[string]any{"name": rName, "region": "par"})).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) + materiakvBlock := helper.NewRessource("clevercloud_materia_kv", rName, helper.SetKeyValues(map[string]any{"name": rName, "region": "par"})) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -58,7 +58,7 @@ func TestAccMateriaKV_basic(t *testing.T) { }, Steps: []resource.TestStep{{ ResourceName: rName, - Config: providerBlock + materiakvBlock, + Config: providerBlock.Append(materiakvBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^kv_.*`)), resource.TestMatchResourceAttr(fullName, "host", regexp.MustCompile(`^.*clever-cloud.com$`)), diff --git a/pkg/resources/metabase/metabase_test.go b/pkg/resources/metabase/metabase_test.go index d5a29ce..fa6d362 100644 --- a/pkg/resources/metabase/metabase_test.go +++ b/pkg/resources/metabase/metabase_test.go @@ -29,8 +29,12 @@ func TestAccMetabase_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_metabase.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() - metabaseBlock := helper.NewRessource("clevercloud_metabase", rName, helper.SetKeyValues(map[string]any{"name": rName, "plan": "beta", "region": "par"})).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) + metabaseBlock := helper.NewRessource( + "clevercloud_metabase", + rName, + helper.SetKeyValues(map[string]any{"name": rName, "plan": "beta", "region": "par"}), + ) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -58,7 +62,7 @@ func TestAccMetabase_basic(t *testing.T) { }, Steps: []resource.TestStep{{ ResourceName: rName, - Config: providerBlock + metabaseBlock, + Config: providerBlock.Append(metabaseBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^addon_.*`)), ), diff --git a/pkg/resources/mongodb/mongodb_test.go b/pkg/resources/mongodb/mongodb_test.go index 4a7cb01..313238b 100644 --- a/pkg/resources/mongodb/mongodb_test.go +++ b/pkg/resources/mongodb/mongodb_test.go @@ -28,8 +28,8 @@ func TestAccMongoDB_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_mongodb.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() - mongodbBlock := helper.NewRessource("clevercloud_mongodb", rName, helper.SetKeyValues(map[string]any{"name": rName, "plan": "xs_med", "region": "par"})).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) + mongodbBlock := helper.NewRessource("clevercloud_mongodb", rName, helper.SetKeyValues(map[string]any{"name": rName, "plan": "xs_med", "region": "par"})) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -57,7 +57,7 @@ func TestAccMongoDB_basic(t *testing.T) { }, Steps: []resource.TestStep{{ ResourceName: rName, - Config: providerBlock + mongodbBlock, + Config: providerBlock.Append(mongodbBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^addon_.*`)), ), @@ -70,8 +70,8 @@ func TestAccMongoDB_RefreshDeleted(t *testing.T) { //fullName := fmt.Sprintf("clevercloud_mongodb.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() - mongodbBlock2 := helper.NewRessource("clevercloud_mongodb", rName, helper.SetKeyValues(map[string]any{"name": rName, "plan": "xs_med", "region": "par"})).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) + mongodbBlock2 := helper.NewRessource("clevercloud_mongodb", rName, helper.SetKeyValues(map[string]any{"name": rName, "plan": "xs_med", "region": "par"})) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -101,7 +101,7 @@ func TestAccMongoDB_RefreshDeleted(t *testing.T) { // create a database instance on first step { ResourceName: rName, - Config: providerBlock + mongodbBlock2, + Config: providerBlock.Append(mongodbBlock2).String(), }, { ResourceName: rName, diff --git a/pkg/resources/nodejs/nodejs_test.go b/pkg/resources/nodejs/nodejs_test.go index 2a98715..b88577d 100644 --- a/pkg/resources/nodejs/nodejs_test.go +++ b/pkg/resources/nodejs/nodejs_test.go @@ -33,7 +33,7 @@ func TestAccNodejs_basic(t *testing.T) { fullName2 := fmt.Sprintf("clevercloud_nodejs.%s", rName2) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) nodejsBlock := helper.NewRessource( "clevercloud_nodejs", rName, @@ -51,7 +51,7 @@ func TestAccNodejs_basic(t *testing.T) { "dependencies": []string{}, }), helper.SetBlockValues("hooks", map[string]any{"post_build": "echo \"build is OK!\""}), - ).String() + ) nodejsBlock2 := helper.NewRessource( "clevercloud_nodejs", rName2, @@ -63,7 +63,7 @@ func TestAccNodejs_basic(t *testing.T) { "smallest_flavor": "XS", "biggest_flavor": "M", }), - helper.SetBlockValues("deployment", map[string]any{"repository": "https://github.com/CleverCloud/nodejs-example.git"})).String() + helper.SetBlockValues("deployment", map[string]any{"repository": "https://github.com/CleverCloud/nodejs-example.git"})) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -91,7 +91,7 @@ func TestAccNodejs_basic(t *testing.T) { }, Steps: []resource.TestStep{{ ResourceName: rName, - Config: providerBlock + nodejsBlock, + Config: providerBlock.Append(nodejsBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( // Test the state for provider's populated values resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^app_.*$`)), @@ -169,7 +169,7 @@ func TestAccNodejs_basic(t *testing.T) { ), }, { ResourceName: rName2, - Config: providerBlock + nodejsBlock2, + Config: providerBlock.Append(nodejsBlock2).String(), Check: func(state *terraform.State) error { id := state.RootModule().Resources[fullName2].Primary.ID diff --git a/pkg/resources/php/crud.go b/pkg/resources/php/crud.go index 461ec2f..95a4d7d 100644 --- a/pkg/resources/php/crud.go +++ b/pkg/resources/php/crud.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-log/tflog" "go.clever-cloud.com/terraform-provider/pkg" "go.clever-cloud.com/terraform-provider/pkg/application" + "go.clever-cloud.com/terraform-provider/pkg/helper" "go.clever-cloud.com/terraform-provider/pkg/provider" "go.clever-cloud.com/terraform-provider/pkg/tmp" ) @@ -34,9 +35,8 @@ func (r *ResourcePHP) Configure(ctx context.Context, req resource.ConfigureReque // Create a new resource func (r *ResourcePHP) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { - plan := PHP{} - - resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + tflog.Debug(ctx, "ResourcePHP.Create()") + plan := helper.PlanFrom[PHP](ctx, req.Plan, resp.Diagnostics) if resp.Diagnostics.HasError() { return } @@ -88,10 +88,11 @@ func (r *ResourcePHP) Create(ctx context.Context, req resource.CreateRequest, re return } - tflog.Debug(ctx, "BUILD FLAVOR RES"+createAppRes.Application.BuildFlavor.Name, map[string]interface{}{}) + tflog.Debug(ctx, "BUILD FLAVOR RES", map[string]interface{}{"flavor": createAppRes.Application.BuildFlavor.Name}) plan.ID = pkg.FromStr(createAppRes.Application.ID) plan.DeployURL = pkg.FromStr(createAppRes.Application.DeployURL) plan.VHost = pkg.FromStr(createAppRes.Application.Vhosts[0].Fqdn) + //plan.AdditionalVHosts = createAppRes.Application.Vhosts resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) if resp.Diagnostics.HasError() { @@ -101,9 +102,8 @@ func (r *ResourcePHP) Create(ctx context.Context, req resource.CreateRequest, re // Read resource information func (r *ResourcePHP) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var state PHP - - resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + tflog.Debug(ctx, "ResourcePHP.Read()") + state := helper.StateFrom[PHP](ctx, req.State, resp.Diagnostics) if resp.Diagnostics.HasError() { return } @@ -163,11 +163,96 @@ func (r *ResourcePHP) Read(ctx context.Context, req resource.ReadRequest, resp * // Update resource func (r *ResourcePHP) Update(ctx context.Context, req resource.UpdateRequest, res *resource.UpdateResponse) { - // TODO + tflog.Debug(ctx, "ResourcePHP.Update()") + + plan := helper.PlanFrom[PHP](ctx, req.Plan, res.Diagnostics) + if res.Diagnostics.HasError() { + return + } + + state := helper.StateFrom[PHP](ctx, req.State, res.Diagnostics) + if res.Diagnostics.HasError() { + return + } + + instance := application.LookupInstance(ctx, r.cc, "php", "PHP", res.Diagnostics) + if res.Diagnostics.HasError() { + return + } + + environment := plan.toEnv(ctx, res.Diagnostics) + if res.Diagnostics.HasError() { + return + } + + vhosts := []string{} + if res.Diagnostics.Append(plan.AdditionalVHosts.ElementsAs(ctx, &vhosts, false)...); res.Diagnostics.HasError() { + return + } + + updateAppReq := application.UpdateReq{ + ID: state.ID.ValueString(), + Client: r.cc, + Organization: r.org, + Application: tmp.UpdateAppReq{ + Name: plan.Name.ValueString(), + Deploy: "git", + Description: plan.Description.ValueString(), + InstanceType: instance.Type, + InstanceVariant: instance.Variant.ID, + InstanceVersion: instance.Version, + BuildFlavor: plan.BuildFlavor.ValueString(), + MinFlavor: plan.SmallestFlavor.ValueString(), + MaxFlavor: plan.BiggestFlavor.ValueString(), + MinInstances: plan.MinInstanceCount.ValueInt64(), + MaxInstances: plan.MaxInstanceCount.ValueInt64(), + StickySessions: plan.StickySessions.ValueBool(), + ForceHttps: application.FromForceHTTPS(plan.RedirectHTTPS.ValueBool()), + Zone: plan.Region.ValueString(), + CancelOnPush: false, + }, + Environment: environment, + VHosts: vhosts, + Deployment: plan.toDeployment(), + } + + _, diags := application.UpdateApp(ctx, updateAppReq) + res.Diagnostics.Append(diags...) + if res.Diagnostics.HasError() { + return + } + + hasDefaultVHost := pkg.HasSome(updateAppReq.VHosts, func(vhost string) bool { + return pkg.VhostCleverAppsRegExp.MatchString(vhost) + }) + if hasDefaultVHost { + cleverapps := *pkg.First(vhosts, func(vhost string) bool { + return pkg.VhostCleverAppsRegExp.MatchString(vhost) + }) + plan.VHost = pkg.FromStr(cleverapps) + } else { + plan.VHost = types.StringNull() + } + + vhostsWithoutDefault := pkg.Filter(updateAppReq.VHosts, func(vhost string) bool { + ok := pkg.VhostCleverAppsRegExp.MatchString(vhost) + return !ok + }) + if len(vhostsWithoutDefault) > 0 { + plan.AdditionalVHosts = pkg.FromListString(vhostsWithoutDefault) + } else { + plan.AdditionalVHosts = types.ListNull(types.StringType) + } + + res.Diagnostics.Append(res.State.Set(ctx, plan)...) + if res.Diagnostics.HasError() { + return + } } // Delete resource func (r *ResourcePHP) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + tflog.Debug(ctx, "ResourcePHP.Delete()") var state PHP resp.Diagnostics.Append(req.State.Get(ctx, &state)...) @@ -191,6 +276,7 @@ func (r *ResourcePHP) Delete(ctx context.Context, req resource.DeleteRequest, re // Import resource func (r *ResourcePHP) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + tflog.Debug(ctx, "ResourcePHP.ImportState()") // Save the import identifier in the id attribute // and call Read() to fill fields attr := path.Root("id") diff --git a/pkg/resources/php/php_test.go b/pkg/resources/php/php_test.go index cb19d4b..8a9b49f 100644 --- a/pkg/resources/php/php_test.go +++ b/pkg/resources/php/php_test.go @@ -24,12 +24,13 @@ var protoV6Provider = map[string]func() (tfprotov6.ProviderServer, error){ } func TestAccPHP_basic(t *testing.T) { + t.Logf("starting....") ctx := context.Background() rName := fmt.Sprintf("tf-test-php-%d", time.Now().UnixMilli()) fullName := fmt.Sprintf("clevercloud_php.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) phpBlock := helper.NewRessource( "clevercloud_php", rName, @@ -42,7 +43,7 @@ func TestAccPHP_basic(t *testing.T) { "biggest_flavor": "M", "php_version": "8", "additional_vhosts": [1]string{"toto-tf5283457829345.com"}, - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -52,14 +53,22 @@ func TestAccPHP_basic(t *testing.T) { }, ProtoV6ProviderFactories: protoV6Provider, Steps: []resource.TestStep{{ - Destroy: false, ResourceName: rName, - Config: providerBlock + phpBlock, + Config: providerBlock.Append(phpBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^app_.*$`)), resource.TestMatchResourceAttr(fullName, "deploy_url", regexp.MustCompile(`^git\+ssh.*\.git$`)), resource.TestCheckResourceAttr(fullName, "region", "par"), ), + }, { + ResourceName: rName, + Config: providerBlock.Append( + phpBlock.SetOneValue("min_instance_count", 2).SetOneValue("max_instance_count", 6), + ).String(), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr(fullName, "min_instance_count", "2"), + resource.TestCheckResourceAttr(fullName, "max_instance_count", "6"), + ), }}, CheckDestroy: func(state *terraform.State) error { for _, resource := range state.RootModule().Resources { diff --git a/pkg/resources/postgresql/postgresql_test.go b/pkg/resources/postgresql/postgresql_test.go index df081c9..c8a0d31 100644 --- a/pkg/resources/postgresql/postgresql_test.go +++ b/pkg/resources/postgresql/postgresql_test.go @@ -28,7 +28,7 @@ func TestAccPostgreSQL_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_postgresql.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) postgresqlBlock := helper.NewRessource( "clevercloud_postgresql", rName, @@ -36,7 +36,7 @@ func TestAccPostgreSQL_basic(t *testing.T) { "name": rName, "region": "par", "plan": "dev", - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -64,7 +64,7 @@ func TestAccPostgreSQL_basic(t *testing.T) { }, Steps: []resource.TestStep{{ ResourceName: rName, - Config: providerBlock + postgresqlBlock, + Config: providerBlock.Append(postgresqlBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^addon_.*`)), resource.TestMatchResourceAttr(fullName, "host", regexp.MustCompile(`^.*-postgresql\.services\.clever-cloud\.com$`)), @@ -82,7 +82,7 @@ func TestAccPostgreSQL_RefreshDeleted(t *testing.T) { //fullName := fmt.Sprintf("clevercloud_postgresql.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) postgresqlBlock := helper.NewRessource( "clevercloud_postgresql", rName, @@ -90,7 +90,7 @@ func TestAccPostgreSQL_RefreshDeleted(t *testing.T) { "name": rName, "region": "par", "plan": "dev", - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -120,7 +120,7 @@ func TestAccPostgreSQL_RefreshDeleted(t *testing.T) { // create a database instance on first step { ResourceName: rName, - Config: providerBlock + postgresqlBlock, + Config: providerBlock.Append(postgresqlBlock).String(), }, { ResourceName: rName, diff --git a/pkg/resources/scala/scala_test.go b/pkg/resources/scala/scala_test.go index 4d4bb44..c2c0acf 100644 --- a/pkg/resources/scala/scala_test.go +++ b/pkg/resources/scala/scala_test.go @@ -29,7 +29,7 @@ func TestAccScala_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_scala.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) scalaBlock := helper.NewRessource( "clevercloud_scala", rName, @@ -40,7 +40,7 @@ func TestAccScala_basic(t *testing.T) { "max_instance_count": 2, "smallest_flavor": "XS", "biggest_flavor": "M", - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -52,7 +52,7 @@ func TestAccScala_basic(t *testing.T) { Steps: []resource.TestStep{{ Destroy: false, ResourceName: rName, - Config: providerBlock + scalaBlock, + Config: providerBlock.Append(scalaBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^app_.*$`)), resource.TestMatchResourceAttr(fullName, "deploy_url", regexp.MustCompile(`^git\+ssh.*\.git$`)), diff --git a/pkg/resources/static/static_test.go b/pkg/resources/static/static_test.go index 10e4d81..53ff441 100644 --- a/pkg/resources/static/static_test.go +++ b/pkg/resources/static/static_test.go @@ -29,7 +29,7 @@ func TestAccStatic_basic(t *testing.T) { fullName := fmt.Sprintf("clevercloud_static.%s", rName) cc := client.New(client.WithAutoOauthConfig()) org := os.Getenv("ORGANISATION") - providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org).String() + providerBlock := helper.NewProvider("clevercloud").SetOrganisation(org) staticBlock := helper.NewRessource( "clevercloud_static", rName, @@ -40,7 +40,7 @@ func TestAccStatic_basic(t *testing.T) { "max_instance_count": 2, "smallest_flavor": "XS", "biggest_flavor": "M", - })).String() + })) resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -52,7 +52,7 @@ func TestAccStatic_basic(t *testing.T) { Steps: []resource.TestStep{{ Destroy: false, ResourceName: rName, - Config: providerBlock + staticBlock, + Config: providerBlock.Append(staticBlock).String(), Check: resource.ComposeAggregateTestCheckFunc( resource.TestMatchResourceAttr(fullName, "id", regexp.MustCompile(`^app_.*$`)), resource.TestMatchResourceAttr(fullName, "deploy_url", regexp.MustCompile(`^git\+ssh.*\.git$`)), diff --git a/pkg/tmp/app.go b/pkg/tmp/app.go index 2cead5e..63f6050 100644 --- a/pkg/tmp/app.go +++ b/pkg/tmp/app.go @@ -213,15 +213,21 @@ func GetProductInstance(ctx context.Context, cc *client.Client) client.Response[ } type UpdateAppReq struct { - CancelOnPush bool `json:"cancelOnPush"` - Description string `json:"description"` - ForceHTTPS string `json:"forceHttps"` - Homogeneous bool `json:"homogeneous"` - AppID string `json:"id"` - Name string `json:"name"` - SeparateBuild bool `json:"separateBuild"` - StickySessions bool `json:"stickySessions"` - Zone string `json:"zone"` + Name string `json:"name" example:"SOME_NAME"` + Deploy string `json:"deploy" example:"git"` + Description string `json:"description" example:"SOME_DESC"` + InstanceType string `json:"instanceType" example:"node"` + InstanceVariant string `json:"instanceVariant" example:"395103fb-d6e2-4fdd-93bc-bc99146f1ea2"` + InstanceVersion string `json:"instanceVersion" example:"20220330"` + MinFlavor string `json:"minFlavor" example:"pico"` + MaxFlavor string `json:"maxFlavor" example:"M"` + BuildFlavor string `json:"buildFlavor" example:"XL"` + MinInstances int64 `json:"minInstances" example:"1"` + MaxInstances int64 `json:"maxInstances" example:"4"` + Zone string `json:"zone" example:"par"` + CancelOnPush bool `json:"cancelOnPush"` + StickySessions bool `json:"stickySessions"` + ForceHttps string `json:"forceHttps"` } func UpdateApp(ctx context.Context, cc *client.Client, organisationID, applicationID string, req UpdateAppReq) client.Response[CreatAppResponse] {