From 6151d2dd7992cb8993c873bc7e38ccafedd0849e Mon Sep 17 00:00:00 2001 From: Douglas Harcourt Parsons Date: Wed, 1 May 2024 17:10:52 +0100 Subject: [PATCH 1/2] Add support for managing Function CPU - New resource can adjust the function cpu settings for a project. I've not added resource tests, as the data source tests cover all that is needed and more. --- client/project_function_cpu.go | 86 ++++++ docs/data-sources/project_function_cpu.md | 42 +++ docs/resources/project_function_cpu.md | 57 ++++ .../data-source.tf | 7 + .../vercel_project_function_cpu/import.sh | 4 + .../vercel_project_function_cpu/resource.tf | 8 + vercel/data_source_project_function_cpu.go | 113 ++++++++ .../data_source_project_function_cpu_test.go | 80 ++++++ vercel/provider.go | 4 +- vercel/resource_project_function_cpu.go | 248 ++++++++++++++++++ 10 files changed, 648 insertions(+), 1 deletion(-) create mode 100644 client/project_function_cpu.go create mode 100644 docs/data-sources/project_function_cpu.md create mode 100644 docs/resources/project_function_cpu.md create mode 100644 examples/data-sources/vercel_project_function_cpu/data-source.tf create mode 100644 examples/resources/vercel_project_function_cpu/import.sh create mode 100644 examples/resources/vercel_project_function_cpu/resource.tf create mode 100644 vercel/data_source_project_function_cpu.go create mode 100644 vercel/data_source_project_function_cpu_test.go create mode 100644 vercel/resource_project_function_cpu.go diff --git a/client/project_function_cpu.go b/client/project_function_cpu.go new file mode 100644 index 00000000..75961b93 --- /dev/null +++ b/client/project_function_cpu.go @@ -0,0 +1,86 @@ +package client + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-log/tflog" +) + +type ProjectFunctionCPURequest struct { + ProjectID string + TeamID string + CPU string +} + +type functionCPU struct { + DefaultMemoryType string `json:"defaultMemoryType"` +} + +type ProjectFunctionCPU struct { + ProjectID string + TeamID string + CPU string +} + +var toCPUNetwork = map[string]string{ + "basic": "standard_legacy", + "standard": "standard", + "performance": "performance", +} + +var fromCPUNetwork = map[string]string{ + "standard_legacy": "basic", + "standard": "standard", + "performance": "performance", +} + +func (c *Client) GetProjectFunctionCPU(ctx context.Context, projectID, teamID string) (p ProjectFunctionCPU, err error) { + url := fmt.Sprintf("%s/v1/projects/%s/resource-config", c.baseURL, projectID) + if c.teamID(teamID) != "" { + url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(teamID)) + } + tflog.Info(ctx, "get project function cpu", map[string]interface{}{ + "url": url, + }) + var f functionCPU + err = c.doRequest(clientRequest{ + ctx: ctx, + method: "GET", + url: url, + }, &f) + if err != nil { + return p, err + } + return ProjectFunctionCPU{ + ProjectID: projectID, + TeamID: teamID, + CPU: fromCPUNetwork[f.DefaultMemoryType], + }, err +} + +func (c *Client) UpdateProjectFunctionCPU(ctx context.Context, request ProjectFunctionCPURequest) (p ProjectFunctionCPU, err error) { + url := fmt.Sprintf("%s/v1/projects/%s/resource-config", c.baseURL, request.ProjectID) + if c.teamID(request.TeamID) != "" { + url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(request.TeamID)) + } + + payload := string(mustMarshal(functionCPU{ + DefaultMemoryType: toCPUNetwork[request.CPU], + })) + var f functionCPU + err = c.doRequest(clientRequest{ + ctx: ctx, + method: "PATCH", + url: url, + body: payload, + }, &f) + if err != nil { + return p, err + } + return ProjectFunctionCPU{ + ProjectID: request.ProjectID, + TeamID: request.TeamID, + CPU: fromCPUNetwork[f.DefaultMemoryType], + }, err +} diff --git a/docs/data-sources/project_function_cpu.md b/docs/data-sources/project_function_cpu.md new file mode 100644 index 00000000..0e47dc70 --- /dev/null +++ b/docs/data-sources/project_function_cpu.md @@ -0,0 +1,42 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "vercel_project_function_cpu Data Source - terraform-provider-vercel" +subcategory: "" +description: |- + Provides information about a Project's Function CPU setting. + This controls the maximum amount of CPU utilization your Serverless Functions can use while executing. Standard is optimal for most frontend workloads. You can override this per function using the vercel.json file. +--- + +# vercel_project_function_cpu (Data Source) + +Provides information about a Project's Function CPU setting. + +This controls the maximum amount of CPU utilization your Serverless Functions can use while executing. Standard is optimal for most frontend workloads. You can override this per function using the vercel.json file. + +## Example Usage + +```terraform +data "vercel_project" "example" { + name = "example" +} + +data "vercel_project_function_cpu" "example" { + project_id = data.vercel_project.example.id +} +``` + + +## Schema + +### Required + +- `project_id` (String) The ID of the Project to read the Function CPU setting for. + +### Optional + +- `team_id` (String) The ID of the team the Project exists under. Required when configuring a team resource if a default team has not been set in the provider. + +### Read-Only + +- `cpu` (String) The amount of CPU available to your Serverless Functions. Should be one of 'basic' (0.6vCPU), 'standard' (1vCPU) or 'performance' (1.7vCPUs). +- `id` (String) The ID of the resource. diff --git a/docs/resources/project_function_cpu.md b/docs/resources/project_function_cpu.md new file mode 100644 index 00000000..92ef60af --- /dev/null +++ b/docs/resources/project_function_cpu.md @@ -0,0 +1,57 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "vercel_project_function_cpu Resource - terraform-provider-vercel" +subcategory: "" +description: |- + Provides a Function CPU resource for a Project. + This controls the maximum amount of CPU utilization your Serverless Functions can use while executing. Standard is optimal for most frontend workloads. You can override this per function using the vercel.json file. + A new Deployment is required for your changes to take effect. +--- + +# vercel_project_function_cpu (Resource) + +Provides a Function CPU resource for a Project. + +This controls the maximum amount of CPU utilization your Serverless Functions can use while executing. Standard is optimal for most frontend workloads. You can override this per function using the vercel.json file. + +A new Deployment is required for your changes to take effect. + +## Example Usage + +```terraform +resource "vercel_project" "example" { + name = "example" +} + +resource "vercel_project_function_cpu" "example" { + project_id = vercel_project.example.id + cpu = "performance" +} +``` + + +## Schema + +### Required + +- `cpu` (String) The amount of CPU available to your Serverless Functions. Should be one of 'basic' (0.6vCPU), 'standard' (1vCPU) or 'performance' (1.7vCPUs). +- `project_id` (String) The ID of the Project to adjust the CPU for. + +### Optional + +- `team_id` (String) The ID of the team the Project exists under. Required when configuring a team resource if a default team has not been set in the provider. + +### Read-Only + +- `id` (String) The ID of the resource. + +## Import + +Import is supported using the following syntax: + +```shell +# You can import via the team_id and project_id. +# - team_id can be found in the team `settings` tab in the Vercel UI. +# - project_id can be found in the project `settings` tab in the Vercel UI. +terraform import vercel_project_function_cpu.example team_xxxxxxxxxxxxxxxxxxxxxxxx/prj_xxxxxxxxxxxxxxxxxxxxxxxxxxxx +``` diff --git a/examples/data-sources/vercel_project_function_cpu/data-source.tf b/examples/data-sources/vercel_project_function_cpu/data-source.tf new file mode 100644 index 00000000..7e34053b --- /dev/null +++ b/examples/data-sources/vercel_project_function_cpu/data-source.tf @@ -0,0 +1,7 @@ +data "vercel_project" "example" { + name = "example" +} + +data "vercel_project_function_cpu" "example" { + project_id = data.vercel_project.example.id +} diff --git a/examples/resources/vercel_project_function_cpu/import.sh b/examples/resources/vercel_project_function_cpu/import.sh new file mode 100644 index 00000000..59885053 --- /dev/null +++ b/examples/resources/vercel_project_function_cpu/import.sh @@ -0,0 +1,4 @@ +# You can import via the team_id and project_id. +# - team_id can be found in the team `settings` tab in the Vercel UI. +# - project_id can be found in the project `settings` tab in the Vercel UI. +terraform import vercel_project_function_cpu.example team_xxxxxxxxxxxxxxxxxxxxxxxx/prj_xxxxxxxxxxxxxxxxxxxxxxxxxxxx diff --git a/examples/resources/vercel_project_function_cpu/resource.tf b/examples/resources/vercel_project_function_cpu/resource.tf new file mode 100644 index 00000000..399cbfba --- /dev/null +++ b/examples/resources/vercel_project_function_cpu/resource.tf @@ -0,0 +1,8 @@ +resource "vercel_project" "example" { + name = "example" +} + +resource "vercel_project_function_cpu" "example" { + project_id = vercel_project.example.id + cpu = "performance" +} diff --git a/vercel/data_source_project_function_cpu.go b/vercel/data_source_project_function_cpu.go new file mode 100644 index 00000000..8b4a77a3 --- /dev/null +++ b/vercel/data_source_project_function_cpu.go @@ -0,0 +1,113 @@ +package vercel + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/vercel/terraform-provider-vercel/client" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ datasource.DataSource = &projectFunctionCPUDataSource{} + _ datasource.DataSourceWithConfigure = &projectFunctionCPUDataSource{} +) + +func newProjectFunctionCPUDataSource() datasource.DataSource { + return &projectFunctionCPUDataSource{} +} + +type projectFunctionCPUDataSource struct { + client *client.Client +} + +func (d *projectFunctionCPUDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_project_function_cpu" +} + +func (d *projectFunctionCPUDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Data Source Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + d.client = client +} + +func (r *projectFunctionCPUDataSource) Schema(_ context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: `Provides information about a Project's Function CPU setting. + +This controls the maximum amount of CPU utilization your Serverless Functions can use while executing. Standard is optimal for most frontend workloads. You can override this per function using the vercel.json file. +`, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of the resource.", + Computed: true, + }, + "project_id": schema.StringAttribute{ + Description: "The ID of the Project to read the Function CPU setting for.", + Required: true, + }, + "team_id": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "The ID of the team the Project exists under. Required when configuring a team resource if a default team has not been set in the provider.", + }, + "cpu": schema.StringAttribute{ + Description: "The amount of CPU available to your Serverless Functions. Should be one of 'basic' (0.6vCPU), 'standard' (1vCPU) or 'performance' (1.7vCPUs).", + Computed: true, + }, + }, + } +} + +func (d *projectFunctionCPUDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + var config ProjectFunctionCPU + diags := req.Config.Get(ctx, &config) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + out, err := d.client.GetProjectFunctionCPU(ctx, config.ProjectID.ValueString(), config.TeamID.ValueString()) + if client.NotFound(err) { + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError( + "Error reading project Function CPU", + fmt.Sprintf("Could not get Project Function CPU %s %s, unexpected error: %s", + config.TeamID.ValueString(), + config.ProjectID.ValueString(), + err, + ), + ) + return + } + + result := convertResponseToProjectFunctionCPU(out) + tflog.Info(ctx, "read project function cpu", map[string]interface{}{ + "team_id": result.TeamID.ValueString(), + "project_id": result.ProjectID.ValueString(), + }) + + diags = resp.State.Set(ctx, result) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} diff --git a/vercel/data_source_project_function_cpu_test.go b/vercel/data_source_project_function_cpu_test.go new file mode 100644 index 00000000..f7627f63 --- /dev/null +++ b/vercel/data_source_project_function_cpu_test.go @@ -0,0 +1,80 @@ +package vercel_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" +) + +func TestAcc_ProjectFunctionCPUDataSource(t *testing.T) { + name := acctest.RandString(16) + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProtoV6ProviderFactories: testAccProtoV6ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccProjectFunctionCPUDataSourceConfig(name, teamIDConfig()), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("data.vercel_project_function_cpu.basic", "cpu", "basic"), + resource.TestCheckResourceAttr("data.vercel_project_function_cpu.standard", "cpu", "standard"), + resource.TestCheckResourceAttr("data.vercel_project_function_cpu.performance", "cpu", "performance"), + ), + }, + }, + }) +} + +func testAccProjectFunctionCPUDataSourceConfig(name, teamID string) string { + return fmt.Sprintf(` +resource "vercel_project" "basic" { + name = "test-acc-%[1]s" + %[2]s +} + +resource "vercel_project_function_cpu" "basic" { + project_id = vercel_project.basic.id + cpu = "basic" + %[2]s +} + +data "vercel_project_function_cpu" "basic" { + project_id = vercel_project_function_cpu.basic.project_id + %[2]s +} + +resource "vercel_project" "standard" { + name = "test-acc-%[1]s-standard" + %[2]s +} + +resource "vercel_project_function_cpu" "standard" { + project_id = vercel_project.standard.id + cpu = "standard" + %[2]s +} + +data "vercel_project_function_cpu" "standard" { + project_id = vercel_project_function_cpu.standard.project_id + %[2]s +} + +resource "vercel_project" "performance" { + name = "test-acc-%[1]s-performance" + %[2]s +} + +resource "vercel_project_function_cpu" "performance" { + project_id = vercel_project.performance.id + cpu = "performance" + %[2]s +} + +data "vercel_project_function_cpu" "performance" { + project_id = vercel_project_function_cpu.performance.project_id + %[2]s +} + +`, name, teamID) +} diff --git a/vercel/provider.go b/vercel/provider.go index beee5a15..c4bf887b 100644 --- a/vercel/provider.go +++ b/vercel/provider.go @@ -59,6 +59,7 @@ func (p *vercelProvider) Resources(_ context.Context) []func() resource.Resource newLogDrainResource, newProjectDomainResource, newProjectEnvironmentVariableResource, + newProjectFunctionCPUResource, newProjectResource, newSharedEnvironmentVariableResource, newWebhookResource, @@ -74,11 +75,12 @@ func (p *vercelProvider) DataSources(_ context.Context) []func() datasource.Data newEdgeConfigTokenDataSource, newEndpointVerificationDataSource, newFileDataSource, + newLogDrainDataSource, newPrebuiltProjectDataSource, newProjectDataSource, newProjectDirectoryDataSource, + newProjectFunctionCPUDataSource, newSharedEnvironmentVariableDataSource, - newLogDrainDataSource, } } diff --git a/vercel/resource_project_function_cpu.go b/vercel/resource_project_function_cpu.go new file mode 100644 index 00000000..4116366c --- /dev/null +++ b/vercel/resource_project_function_cpu.go @@ -0,0 +1,248 @@ +package vercel + +import ( + "context" + "fmt" + + "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/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/vercel/terraform-provider-vercel/client" +) + +// Ensure the implementation satisfies the expected interfaces. +var ( + _ resource.Resource = &projectFunctionCPUResource{} + _ resource.ResourceWithConfigure = &projectFunctionCPUResource{} + _ resource.ResourceWithImportState = &projectFunctionCPUResource{} +) + +func newProjectFunctionCPUResource() resource.Resource { + return &projectFunctionCPUResource{} +} + +type projectFunctionCPUResource struct { + client *client.Client +} + +func (r *projectFunctionCPUResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_project_function_cpu" +} + +func (r *projectFunctionCPUResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*client.Client) + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *client.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + return + } + + r.client = client +} + +// Schema returns the schema information for an alias resource. +func (r *projectFunctionCPUResource) Schema(_ context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Description: `Provides a Function CPU resource for a Project. + +This controls the maximum amount of CPU utilization your Serverless Functions can use while executing. Standard is optimal for most frontend workloads. You can override this per function using the vercel.json file. + +A new Deployment is required for your changes to take effect. +`, + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Description: "The ID of the resource.", + Computed: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.UseStateForUnknown()}, + }, + "project_id": schema.StringAttribute{ + Description: "The ID of the Project to adjust the CPU for.", + Required: true, + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplace()}, + }, + "team_id": schema.StringAttribute{ + Optional: true, + Computed: true, + Description: "The ID of the team the Project exists under. Required when configuring a team resource if a default team has not been set in the provider.", + PlanModifiers: []planmodifier.String{stringplanmodifier.RequiresReplaceIfConfigured(), stringplanmodifier.UseStateForUnknown()}, + }, + "cpu": schema.StringAttribute{ + Description: "The amount of CPU available to your Serverless Functions. Should be one of 'basic' (0.6vCPU), 'standard' (1vCPU) or 'performance' (1.7vCPUs).", + Required: true, + }, + }, + } +} + +type ProjectFunctionCPU struct { + ID types.String `tfsdk:"id"` + ProjectID types.String `tfsdk:"project_id"` + TeamID types.String `tfsdk:"team_id"` + CPU types.String `tfsdk:"cpu"` +} + +func convertResponseToProjectFunctionCPU(response client.ProjectFunctionCPU) ProjectFunctionCPU { + return ProjectFunctionCPU{ + ID: types.StringValue(response.ProjectID), + TeamID: toTeamID(response.TeamID), + ProjectID: types.StringValue(response.ProjectID), + CPU: types.StringValue(response.CPU), + } +} + +func (r *projectFunctionCPUResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan ProjectFunctionCPU + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + out, err := r.client.UpdateProjectFunctionCPU(ctx, client.ProjectFunctionCPURequest{ + ProjectID: plan.ProjectID.ValueString(), + CPU: plan.CPU.ValueString(), + TeamID: plan.TeamID.ValueString(), + }) + if err != nil { + resp.Diagnostics.AddError( + "Error updating project Function CPU", + "Could not update function CPU, unexpected error: "+err.Error(), + ) + return + } + + result := convertResponseToProjectFunctionCPU(out) + tflog.Info(ctx, "created project function cpu", map[string]interface{}{ + "team_id": plan.TeamID.ValueString(), + "project_id": plan.ProjectID.ValueString(), + "cpu": result.CPU.ValueString(), + }) + + diags = resp.State.Set(ctx, result) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *projectFunctionCPUResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state ProjectFunctionCPU + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + out, err := r.client.GetProjectFunctionCPU(ctx, state.ProjectID.ValueString(), state.TeamID.ValueString()) + if client.NotFound(err) { + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError( + "Error reading project Function CPU", + fmt.Sprintf("Could not get Project Function CPU %s %s, unexpected error: %s", + state.TeamID.ValueString(), + state.ProjectID.ValueString(), + err, + ), + ) + return + } + + result := convertResponseToProjectFunctionCPU(out) + tflog.Info(ctx, "read project function cpu", map[string]interface{}{ + "team_id": result.TeamID.ValueString(), + "project_id": result.ProjectID.ValueString(), + }) + + diags = resp.State.Set(ctx, result) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *projectFunctionCPUResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan ProjectFunctionCPU + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + out, err := r.client.UpdateProjectFunctionCPU(ctx, client.ProjectFunctionCPURequest{ + ProjectID: plan.ProjectID.ValueString(), + CPU: plan.CPU.ValueString(), + TeamID: plan.TeamID.ValueString(), + }) + if err != nil { + resp.Diagnostics.AddError( + "Error updating project Function CPU", + "Could not update function CPU, unexpected error: "+err.Error(), + ) + return + } + + result := convertResponseToProjectFunctionCPU(out) + tflog.Info(ctx, "created project function cpu", map[string]interface{}{ + "team_id": plan.TeamID.ValueString(), + "project_id": plan.ProjectID.ValueString(), + "cpu": result.CPU.ValueString(), + }) + + diags = resp.State.Set(ctx, result) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +func (r *projectFunctionCPUResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + tflog.Info(ctx, "deleted project function cpu", map[string]interface{}{}) +} + +func (r *projectFunctionCPUResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + teamID, projectID, ok := splitInto1Or2(req.ID) + if !ok { + resp.Diagnostics.AddError( + "Error importing Project Function CPU", + fmt.Sprintf("Invalid id '%s' specified. should be in format \"team_id/project_id\" or \"project_id\"", req.ID), + ) + } + + out, err := r.client.GetProjectFunctionCPU(ctx, projectID, teamID) + if err != nil { + resp.Diagnostics.AddError( + "Error reading Project Function CPU", + fmt.Sprintf("Could not get Project Function CPU %s %s, unexpected error: %s", + teamID, + projectID, + err, + ), + ) + return + } + + result := convertResponseToProjectFunctionCPU(out) + tflog.Info(ctx, "import project function cpu", map[string]interface{}{ + "team_id": result.TeamID.ValueString(), + "project_id": result.ProjectID.ValueString(), + }) + + diags := resp.State.Set(ctx, result) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} From 423787dc6708d6e1d01f66a50f35ff072e41dce4 Mon Sep 17 00:00:00 2001 From: Douglas Harcourt Parsons Date: Thu, 2 May 2024 11:08:57 +0100 Subject: [PATCH 2/2] Allow null for read state --- client/project_function_cpu.go | 21 ++++++++++++++++----- vercel/resource_project_function_cpu.go | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/client/project_function_cpu.go b/client/project_function_cpu.go index 75961b93..7d46c243 100644 --- a/client/project_function_cpu.go +++ b/client/project_function_cpu.go @@ -14,13 +14,13 @@ type ProjectFunctionCPURequest struct { } type functionCPU struct { - DefaultMemoryType string `json:"defaultMemoryType"` + DefaultMemoryType *string `json:"defaultMemoryType"` } type ProjectFunctionCPU struct { ProjectID string TeamID string - CPU string + CPU *string } var toCPUNetwork = map[string]string{ @@ -52,10 +52,15 @@ func (c *Client) GetProjectFunctionCPU(ctx context.Context, projectID, teamID st if err != nil { return p, err } + var cpu *string + if f.DefaultMemoryType != nil { + v := fromCPUNetwork[*f.DefaultMemoryType] + cpu = &v + } return ProjectFunctionCPU{ ProjectID: projectID, TeamID: teamID, - CPU: fromCPUNetwork[f.DefaultMemoryType], + CPU: cpu, }, err } @@ -65,8 +70,9 @@ func (c *Client) UpdateProjectFunctionCPU(ctx context.Context, request ProjectFu url = fmt.Sprintf("%s?teamId=%s", url, c.teamID(request.TeamID)) } + v := toCPUNetwork[request.CPU] payload := string(mustMarshal(functionCPU{ - DefaultMemoryType: toCPUNetwork[request.CPU], + DefaultMemoryType: &v, })) var f functionCPU err = c.doRequest(clientRequest{ @@ -78,9 +84,14 @@ func (c *Client) UpdateProjectFunctionCPU(ctx context.Context, request ProjectFu if err != nil { return p, err } + var cpu *string + if f.DefaultMemoryType != nil { + v := fromCPUNetwork[*f.DefaultMemoryType] + cpu = &v + } return ProjectFunctionCPU{ ProjectID: request.ProjectID, TeamID: request.TeamID, - CPU: fromCPUNetwork[f.DefaultMemoryType], + CPU: cpu, }, err } diff --git a/vercel/resource_project_function_cpu.go b/vercel/resource_project_function_cpu.go index 4116366c..6b871498 100644 --- a/vercel/resource_project_function_cpu.go +++ b/vercel/resource_project_function_cpu.go @@ -96,7 +96,7 @@ func convertResponseToProjectFunctionCPU(response client.ProjectFunctionCPU) Pro ID: types.StringValue(response.ProjectID), TeamID: toTeamID(response.TeamID), ProjectID: types.StringValue(response.ProjectID), - CPU: types.StringValue(response.CPU), + CPU: types.StringPointerValue(response.CPU), } }