From 169be6a682b936c5462472d98031f5045b45aca1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 12 Oct 2025 20:28:21 +0000 Subject: [PATCH 1/2] feat: Add ECS and EKS resources and examples Adds new ECS and EKS resources to the provider, along with example Terraform configurations. Co-authored-by: avelladario92 --- examples/resources/ecs/main.tf | 50 +++++ examples/resources/eks/main.tf | 42 ++++ internal/provider/ecs_resource.go | 305 ++++++++++++++++++++++++++++++ internal/provider/eks_resource.go | 291 ++++++++++++++++++++++++++++ internal/provider/provider.go | 3 + 5 files changed, 691 insertions(+) create mode 100644 examples/resources/ecs/main.tf create mode 100644 examples/resources/eks/main.tf create mode 100644 internal/provider/ecs_resource.go create mode 100644 internal/provider/eks_resource.go diff --git a/examples/resources/ecs/main.tf b/examples/resources/ecs/main.tf new file mode 100644 index 0000000..94663bf --- /dev/null +++ b/examples/resources/ecs/main.tf @@ -0,0 +1,50 @@ +terraform { + required_providers { + coderforge = { + source = "registry.terraform.io/coderforge/coderforge" + } + } +} + +provider "coderforge" { + stack_id = "stack-ecs-dev" + cloud_space = "ecs.dev.coderforge.org" + locations = ["us-east-1", "us-west-2"] +} + +resource "coderforge_ecs" "example" { + cluster_name = "my-ecs-cluster" + service_name = "my-ecs-service" + task_definition_family = "my-task-family" + task_definition_revision = "1" + desired_count = 2 + launch_type = "FARGATE" + platform_version = "LATEST" + region = "us-east-1" + vpc_id = "vpc-12345678" + subnet_ids = ["subnet-12345678", "subnet-87654321"] + security_group_ids = ["sg-12345678"] + load_balancer_arn = "arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/app/my-load-balancer/50dc6c495c0c9188" + target_group_arn = "arn:aws:elasticloadbalancing:us-east-1:123456789012:targetgroup/my-targets/73e2d6bc24d8a067" + container_port = 80 + container_name = "my-container" + container_image = "nginx:latest" + container_memory = 512 + container_cpu = 256 + + environment_variables = { + NODE_ENV = "production" + PORT = "80" + LOG_LEVEL = "info" + } + + tags = { + Environment = "development" + Project = "my-project" + Owner = "devops-team" + } +} + +output "ecs_service" { + value = coderforge_ecs.example +} \ No newline at end of file diff --git a/examples/resources/eks/main.tf b/examples/resources/eks/main.tf new file mode 100644 index 0000000..446b619 --- /dev/null +++ b/examples/resources/eks/main.tf @@ -0,0 +1,42 @@ +terraform { + required_providers { + coderforge = { + source = "registry.terraform.io/coderforge/coderforge" + } + } +} + +provider "coderforge" { + stack_id = "stack-eks-dev" + cloud_space = "eks.dev.coderforge.org" + locations = ["us-east-1", "us-west-2"] +} + +resource "coderforge_eks" "example" { + cluster_name = "my-eks-cluster" + version = "1.28" + region = "us-east-1" + node_group_name = "my-node-group" + node_instance_type = "t3.medium" + node_min_size = 1 + node_max_size = 3 + node_desired_size = 2 + vpc_id = "vpc-12345678" + subnet_ids = ["subnet-12345678", "subnet-87654321"] + security_group_ids = ["sg-12345678"] + endpoint_private_access = true + endpoint_public_access = true + public_access_cidrs = ["0.0.0.0/0"] + logging_enabled = true + log_types = ["api", "audit", "authenticator", "controllerManager", "scheduler"] + + tags = { + Environment = "development" + Project = "my-project" + Owner = "devops-team" + } +} + +output "eks_cluster" { + value = coderforge_eks.example +} \ No newline at end of file diff --git a/internal/provider/ecs_resource.go b/internal/provider/ecs_resource.go new file mode 100644 index 0000000..28dd6aa --- /dev/null +++ b/internal/provider/ecs_resource.go @@ -0,0 +1,305 @@ +package provider + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var ( + _ resource.Resource = &ecsResource{} + _ resource.ResourceWithConfigure = &ecsResource{} +) + +func NewEcsResource() resource.Resource { + return &ecsResource{} +} + +type ecsResourceModel struct { + ID types.String `tfsdk:"id"` + ClusterName types.String `tfsdk:"cluster_name"` + ServiceName types.String `tfsdk:"service_name"` + TaskDefinitionFamily types.String `tfsdk:"task_definition_family"` + TaskDefinitionRevision types.String `tfsdk:"task_definition_revision"` + DesiredCount types.Int64 `tfsdk:"desired_count"` + LaunchType types.String `tfsdk:"launch_type"` + PlatformVersion types.String `tfsdk:"platform_version"` + Region types.String `tfsdk:"region"` + VpcId types.String `tfsdk:"vpc_id"` + SubnetIds types.List `tfsdk:"subnet_ids"` + SecurityGroupIds types.List `tfsdk:"security_group_ids"` + LoadBalancerArn types.String `tfsdk:"load_balancer_arn"` + TargetGroupArn types.String `tfsdk:"target_group_arn"` + ContainerPort types.Int64 `tfsdk:"container_port"` + ContainerName types.String `tfsdk:"container_name"` + ContainerImage types.String `tfsdk:"container_image"` + ContainerMemory types.Int64 `tfsdk:"container_memory"` + ContainerCpu types.Int64 `tfsdk:"container_cpu"` + EnvironmentVariables types.Map `tfsdk:"environment_variables"` + Tags types.Map `tfsdk:"tags"` + LastUpdated types.String `tfsdk:"last_updated"` +} + +type ecsResource struct { + client *Client +} + +func (r *ecsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_ecs" +} + +func (r *ecsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + }, + "cluster_name": schema.StringAttribute{ + Required: true, + }, + "service_name": schema.StringAttribute{ + Required: true, + }, + "task_definition_family": schema.StringAttribute{ + Required: true, + }, + "task_definition_revision": schema.StringAttribute{ + Optional: true, + }, + "desired_count": schema.Int64Attribute{ + Optional: true, + }, + "launch_type": schema.StringAttribute{ + Optional: true, + }, + "platform_version": schema.StringAttribute{ + Optional: true, + }, + "region": schema.StringAttribute{ + Required: true, + }, + "vpc_id": schema.StringAttribute{ + Optional: true, + }, + "subnet_ids": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "security_group_ids": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "load_balancer_arn": schema.StringAttribute{ + Optional: true, + }, + "target_group_arn": schema.StringAttribute{ + Optional: true, + }, + "container_port": schema.Int64Attribute{ + Optional: true, + }, + "container_name": schema.StringAttribute{ + Optional: true, + }, + "container_image": schema.StringAttribute{ + Optional: true, + }, + "container_memory": schema.Int64Attribute{ + Optional: true, + }, + "container_cpu": schema.Int64Attribute{ + Optional: true, + }, + "environment_variables": schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "tags": schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "last_updated": schema.StringAttribute{ + Computed: true, + }, + }, + } +} + +// Create a new resource. +func (r *ecsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // Retrieve values from plan + var plan ecsResourceModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Generate API request body from plan + var resourceItem ResourceItem + resourceItem.Type = "ecs" + resourceItem.Name = plan.ServiceName.ValueString() + + // For ECS, we'll store configuration in a simplified way + code := Code{ + PackageType: "container", + ImageUri: plan.ContainerImage.ValueString(), + Runtime: plan.LaunchType.ValueString(), + } + resourceItem.Code = code + resourceItem.MaxRamSize = fmt.Sprintf("%d", plan.ContainerMemory.ValueInt64()) + + resourceItemRes, err := r.client.CreateResource(ctx, resourceItem) + if err != nil { + resp.Diagnostics.AddError( + "Error creating ECS service", + "Could not create ECS service, unexpected error: "+err.Error(), + ) + return + } + + // Map response body to schema and populate Computed attribute values + plan.ID = types.StringValue(resourceItemRes.ID) + plan.ServiceName = types.StringValue(resourceItemRes.Name) + plan.ContainerImage = types.StringValue(resourceItemRes.Code.ImageUri) + plan.LaunchType = types.StringValue(resourceItemRes.Code.Runtime) + plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Read resource information. +func (r *ecsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state ecsResourceModel + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resourceItemRes, err := r.client.GetResource(ctx, state.ID.ValueString()) + if err != nil { + if errors.Is(err, ErrNotFound) { + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError( + "Error Reading ECS Service", + "Could not read ECS service ID "+state.ID.ValueString()+": "+err.Error(), + ) + return + } + if resourceItemRes == nil { + resp.State.RemoveResource(ctx) + return + } + + state.ID = types.StringValue(resourceItemRes.ID) + state.ServiceName = types.StringValue(resourceItemRes.Name) + state.ContainerImage = types.StringValue(resourceItemRes.Code.ImageUri) + state.LaunchType = types.StringValue(resourceItemRes.Code.Runtime) + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Update updates the resource and sets the updated Terraform state on success. +func (r *ecsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan ecsResourceModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + var state ecsResourceModel + diagsState := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diagsState...) + if resp.Diagnostics.HasError() { + return + } + + var resourceItem ResourceItem + resourceItem.ID = state.ID.ValueString() + resourceItem.Type = "ecs" + resourceItem.Name = plan.ServiceName.ValueString() + code := Code{ + PackageType: "container", + ImageUri: plan.ContainerImage.ValueString(), + Runtime: plan.LaunchType.ValueString(), + } + resourceItem.Code = code + resourceItem.MaxRamSize = fmt.Sprintf("%d", plan.ContainerMemory.ValueInt64()) + + resourceItemRes, err := r.client.UpdateResource(ctx, resourceItem) + if err != nil { + resp.Diagnostics.AddError( + "Error updating ECS service", + "Could not update ECS service, unexpected error: "+err.Error(), + ) + return + } + + plan.ID = types.StringValue(resourceItemRes.ID) + plan.ServiceName = types.StringValue(resourceItemRes.Name) + plan.ContainerImage = types.StringValue(resourceItemRes.Code.ImageUri) + plan.LaunchType = types.StringValue(resourceItemRes.Code.Runtime) + plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diagsState...) + if resp.Diagnostics.HasError() { + return + } +} + +// Delete deletes the resource and removes the Terraform state on success. +func (r *ecsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // Retrieve values from plan + var plan ecsResourceModel + diags := req.State.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + err := r.client.DeleteResource(ctx, plan.ID.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Error deleting ECS service", + "Could not delete ECS service, unexpected error: "+err.Error(), + ) + } + return +} + +// Configure adds the provider configured client to the resource. +func (r *ecsResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Add a nil check when handling ProviderData because Terraform + // sets that data after it calls the ConfigureProvider RPC. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*Client) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *provider.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} \ No newline at end of file diff --git a/internal/provider/eks_resource.go b/internal/provider/eks_resource.go new file mode 100644 index 0000000..bb3be37 --- /dev/null +++ b/internal/provider/eks_resource.go @@ -0,0 +1,291 @@ +package provider + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" +) + +var ( + _ resource.Resource = &eksResource{} + _ resource.ResourceWithConfigure = &eksResource{} +) + +func NewEksResource() resource.Resource { + return &eksResource{} +} + +type eksResourceModel struct { + ID types.String `tfsdk:"id"` + ClusterName types.String `tfsdk:"cluster_name"` + Version types.String `tfsdk:"version"` + Region types.String `tfsdk:"region"` + NodeGroupName types.String `tfsdk:"node_group_name"` + NodeInstanceType types.String `tfsdk:"node_instance_type"` + NodeMinSize types.Int64 `tfsdk:"node_min_size"` + NodeMaxSize types.Int64 `tfsdk:"node_max_size"` + NodeDesiredSize types.Int64 `tfsdk:"node_desired_size"` + VpcId types.String `tfsdk:"vpc_id"` + SubnetIds types.List `tfsdk:"subnet_ids"` + SecurityGroupIds types.List `tfsdk:"security_group_ids"` + EndpointPrivateAccess types.Bool `tfsdk:"endpoint_private_access"` + EndpointPublicAccess types.Bool `tfsdk:"endpoint_public_access"` + PublicAccessCidrs types.List `tfsdk:"public_access_cidrs"` + LoggingEnabled types.Bool `tfsdk:"logging_enabled"` + LogTypes types.List `tfsdk:"log_types"` + Tags types.Map `tfsdk:"tags"` + LastUpdated types.String `tfsdk:"last_updated"` +} + +type eksResource struct { + client *Client +} + +func (r *eksResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_eks" +} + +func (r *eksResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": schema.StringAttribute{ + Computed: true, + }, + "cluster_name": schema.StringAttribute{ + Required: true, + }, + "version": schema.StringAttribute{ + Optional: true, + }, + "region": schema.StringAttribute{ + Required: true, + }, + "node_group_name": schema.StringAttribute{ + Optional: true, + }, + "node_instance_type": schema.StringAttribute{ + Optional: true, + }, + "node_min_size": schema.Int64Attribute{ + Optional: true, + }, + "node_max_size": schema.Int64Attribute{ + Optional: true, + }, + "node_desired_size": schema.Int64Attribute{ + Optional: true, + }, + "vpc_id": schema.StringAttribute{ + Optional: true, + }, + "subnet_ids": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "security_group_ids": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "endpoint_private_access": schema.BoolAttribute{ + Optional: true, + }, + "endpoint_public_access": schema.BoolAttribute{ + Optional: true, + }, + "public_access_cidrs": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "logging_enabled": schema.BoolAttribute{ + Optional: true, + }, + "log_types": schema.ListAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "tags": schema.MapAttribute{ + ElementType: types.StringType, + Optional: true, + }, + "last_updated": schema.StringAttribute{ + Computed: true, + }, + }, + } +} + +// Create a new resource. +func (r *eksResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + // Retrieve values from plan + var plan eksResourceModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + // Generate API request body from plan + var resourceItem ResourceItem + resourceItem.Type = "eks" + resourceItem.Name = plan.ClusterName.ValueString() + + // For EKS, we'll store configuration in a simplified way + // In a real implementation, you'd want to extend the ResourceItem model + // to support more complex configurations + code := Code{ + PackageType: "kubernetes", + Runtime: plan.Version.ValueString(), + } + resourceItem.Code = code + resourceItem.MaxRamSize = "0" // EKS doesn't use RAM size in the same way + + resourceItemRes, err := r.client.CreateResource(ctx, resourceItem) + if err != nil { + resp.Diagnostics.AddError( + "Error creating EKS cluster", + "Could not create EKS cluster, unexpected error: "+err.Error(), + ) + return + } + + // Map response body to schema and populate Computed attribute values + plan.ID = types.StringValue(resourceItemRes.ID) + plan.ClusterName = types.StringValue(resourceItemRes.Name) + plan.Version = types.StringValue(resourceItemRes.Code.Runtime) + plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Read resource information. +func (r *eksResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state eksResourceModel + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + resourceItemRes, err := r.client.GetResource(ctx, state.ID.ValueString()) + if err != nil { + if errors.Is(err, ErrNotFound) { + resp.State.RemoveResource(ctx) + return + } + resp.Diagnostics.AddError( + "Error Reading EKS Cluster", + "Could not read EKS cluster ID "+state.ID.ValueString()+": "+err.Error(), + ) + return + } + if resourceItemRes == nil { + resp.State.RemoveResource(ctx) + return + } + + state.ID = types.StringValue(resourceItemRes.ID) + state.ClusterName = types.StringValue(resourceItemRes.Name) + state.Version = types.StringValue(resourceItemRes.Code.Runtime) + + diags = resp.State.Set(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } +} + +// Update updates the resource and sets the updated Terraform state on success. +func (r *eksResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan eksResourceModel + diags := req.Plan.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + var state eksResourceModel + diagsState := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diagsState...) + if resp.Diagnostics.HasError() { + return + } + + var resourceItem ResourceItem + resourceItem.ID = state.ID.ValueString() + resourceItem.Type = "eks" + resourceItem.Name = plan.ClusterName.ValueString() + code := Code{ + PackageType: "kubernetes", + Runtime: plan.Version.ValueString(), + } + resourceItem.Code = code + resourceItem.MaxRamSize = "0" + + resourceItemRes, err := r.client.UpdateResource(ctx, resourceItem) + if err != nil { + resp.Diagnostics.AddError( + "Error updating EKS cluster", + "Could not update EKS cluster, unexpected error: "+err.Error(), + ) + return + } + + plan.ID = types.StringValue(resourceItemRes.ID) + plan.ClusterName = types.StringValue(resourceItemRes.Name) + plan.Version = types.StringValue(resourceItemRes.Code.Runtime) + plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) + + diags = resp.State.Set(ctx, plan) + resp.Diagnostics.Append(diags...) + resp.Diagnostics.Append(diagsState...) + if resp.Diagnostics.HasError() { + return + } +} + +// Delete deletes the resource and removes the Terraform state on success. +func (r *eksResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + // Retrieve values from plan + var plan eksResourceModel + diags := req.State.Get(ctx, &plan) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + err := r.client.DeleteResource(ctx, plan.ID.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Error deleting EKS cluster", + "Could not delete EKS cluster, unexpected error: "+err.Error(), + ) + } + return +} + +// Configure adds the provider configured client to the resource. +func (r *eksResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Add a nil check when handling ProviderData because Terraform + // sets that data after it calls the ConfigureProvider RPC. + if req.ProviderData == nil { + return + } + + client, ok := req.ProviderData.(*Client) + + if !ok { + resp.Diagnostics.AddError( + "Unexpected Resource Configure Type", + fmt.Sprintf("Expected *provider.Client, got: %T. Please report this issue to the provider developers.", req.ProviderData), + ) + + return + } + + r.client = client +} \ No newline at end of file diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 061e706..82c1835 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -175,6 +175,9 @@ func (p *coderforgeProvider) DataSources(_ context.Context) []func() datasource. func (p *coderforgeProvider) Resources(_ context.Context) []func() resource.Resource { return []func() resource.Resource{ NewFunctionResource, + NewContainerResource, NewContainerRegistryResource, + NewEksResource, + NewEcsResource, } } From 192ebdd600fb5d8caa8245d8b74464882d48c9ba Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 12 Oct 2025 20:33:38 +0000 Subject: [PATCH 2/2] Refactor: Rename EKS and ECS resources to KS and CS Co-authored-by: avelladario92 --- examples/resources/{ecs => cs}/main.tf | 14 ++--- examples/resources/{eks => ks}/main.tf | 12 ++-- .../{ecs_resource.go => cs_resource.go} | 60 +++++++++--------- .../{eks_resource.go => ks_resource.go} | 62 +++++++++---------- internal/provider/provider.go | 4 +- 5 files changed, 76 insertions(+), 76 deletions(-) rename examples/resources/{ecs => cs}/main.tf (82%) rename examples/resources/{eks => ks}/main.tf (81%) rename internal/provider/{ecs_resource.go => cs_resource.go} (81%) rename internal/provider/{eks_resource.go => ks_resource.go} (79%) diff --git a/examples/resources/ecs/main.tf b/examples/resources/cs/main.tf similarity index 82% rename from examples/resources/ecs/main.tf rename to examples/resources/cs/main.tf index 94663bf..dadcf7e 100644 --- a/examples/resources/ecs/main.tf +++ b/examples/resources/cs/main.tf @@ -7,14 +7,14 @@ terraform { } provider "coderforge" { - stack_id = "stack-ecs-dev" - cloud_space = "ecs.dev.coderforge.org" + stack_id = "stack-cs-dev" + cloud_space = "cs.dev.coderforge.org" locations = ["us-east-1", "us-west-2"] } -resource "coderforge_ecs" "example" { - cluster_name = "my-ecs-cluster" - service_name = "my-ecs-service" +resource "coderforge_cs" "example" { + cluster_name = "my-cs-cluster" + service_name = "my-cs-service" task_definition_family = "my-task-family" task_definition_revision = "1" desired_count = 2 @@ -45,6 +45,6 @@ resource "coderforge_ecs" "example" { } } -output "ecs_service" { - value = coderforge_ecs.example +output "cs_service" { + value = coderforge_cs.example } \ No newline at end of file diff --git a/examples/resources/eks/main.tf b/examples/resources/ks/main.tf similarity index 81% rename from examples/resources/eks/main.tf rename to examples/resources/ks/main.tf index 446b619..ddf8dea 100644 --- a/examples/resources/eks/main.tf +++ b/examples/resources/ks/main.tf @@ -7,13 +7,13 @@ terraform { } provider "coderforge" { - stack_id = "stack-eks-dev" - cloud_space = "eks.dev.coderforge.org" + stack_id = "stack-ks-dev" + cloud_space = "ks.dev.coderforge.org" locations = ["us-east-1", "us-west-2"] } -resource "coderforge_eks" "example" { - cluster_name = "my-eks-cluster" +resource "coderforge_ks" "example" { + cluster_name = "my-ks-cluster" version = "1.28" region = "us-east-1" node_group_name = "my-node-group" @@ -37,6 +37,6 @@ resource "coderforge_eks" "example" { } } -output "eks_cluster" { - value = coderforge_eks.example +output "ks_cluster" { + value = coderforge_ks.example } \ No newline at end of file diff --git a/internal/provider/ecs_resource.go b/internal/provider/cs_resource.go similarity index 81% rename from internal/provider/ecs_resource.go rename to internal/provider/cs_resource.go index 28dd6aa..bb16700 100644 --- a/internal/provider/ecs_resource.go +++ b/internal/provider/cs_resource.go @@ -12,15 +12,15 @@ import ( ) var ( - _ resource.Resource = &ecsResource{} - _ resource.ResourceWithConfigure = &ecsResource{} + _ resource.Resource = &csResource{} + _ resource.ResourceWithConfigure = &csResource{} ) -func NewEcsResource() resource.Resource { - return &ecsResource{} +func NewCsResource() resource.Resource { + return &csResource{} } -type ecsResourceModel struct { +type csResourceModel struct { ID types.String `tfsdk:"id"` ClusterName types.String `tfsdk:"cluster_name"` ServiceName types.String `tfsdk:"service_name"` @@ -45,15 +45,15 @@ type ecsResourceModel struct { LastUpdated types.String `tfsdk:"last_updated"` } -type ecsResource struct { +type csResource struct { client *Client } -func (r *ecsResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_ecs" +func (r *csResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_cs" } -func (r *ecsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *csResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ @@ -131,9 +131,9 @@ func (r *ecsResource) Schema(_ context.Context, _ resource.SchemaRequest, resp * } // Create a new resource. -func (r *ecsResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { +func (r *csResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // Retrieve values from plan - var plan ecsResourceModel + var plan csResourceModel diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -142,10 +142,10 @@ func (r *ecsResource) Create(ctx context.Context, req resource.CreateRequest, re // Generate API request body from plan var resourceItem ResourceItem - resourceItem.Type = "ecs" + resourceItem.Type = "cs" resourceItem.Name = plan.ServiceName.ValueString() - // For ECS, we'll store configuration in a simplified way + // For CS, we'll store configuration in a simplified way code := Code{ PackageType: "container", ImageUri: plan.ContainerImage.ValueString(), @@ -157,8 +157,8 @@ func (r *ecsResource) Create(ctx context.Context, req resource.CreateRequest, re resourceItemRes, err := r.client.CreateResource(ctx, resourceItem) if err != nil { resp.Diagnostics.AddError( - "Error creating ECS service", - "Could not create ECS service, unexpected error: "+err.Error(), + "Error creating CS service", + "Could not create CS service, unexpected error: "+err.Error(), ) return } @@ -178,8 +178,8 @@ func (r *ecsResource) Create(ctx context.Context, req resource.CreateRequest, re } // Read resource information. -func (r *ecsResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var state ecsResourceModel +func (r *csResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state csResourceModel diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -193,8 +193,8 @@ func (r *ecsResource) Read(ctx context.Context, req resource.ReadRequest, resp * return } resp.Diagnostics.AddError( - "Error Reading ECS Service", - "Could not read ECS service ID "+state.ID.ValueString()+": "+err.Error(), + "Error Reading CS Service", + "Could not read CS service ID "+state.ID.ValueString()+": "+err.Error(), ) return } @@ -216,11 +216,11 @@ func (r *ecsResource) Read(ctx context.Context, req resource.ReadRequest, resp * } // Update updates the resource and sets the updated Terraform state on success. -func (r *ecsResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var plan ecsResourceModel +func (r *csResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan csResourceModel diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) - var state ecsResourceModel + var state csResourceModel diagsState := req.State.Get(ctx, &state) resp.Diagnostics.Append(diagsState...) if resp.Diagnostics.HasError() { @@ -229,7 +229,7 @@ func (r *ecsResource) Update(ctx context.Context, req resource.UpdateRequest, re var resourceItem ResourceItem resourceItem.ID = state.ID.ValueString() - resourceItem.Type = "ecs" + resourceItem.Type = "cs" resourceItem.Name = plan.ServiceName.ValueString() code := Code{ PackageType: "container", @@ -242,8 +242,8 @@ func (r *ecsResource) Update(ctx context.Context, req resource.UpdateRequest, re resourceItemRes, err := r.client.UpdateResource(ctx, resourceItem) if err != nil { resp.Diagnostics.AddError( - "Error updating ECS service", - "Could not update ECS service, unexpected error: "+err.Error(), + "Error updating CS service", + "Could not update CS service, unexpected error: "+err.Error(), ) return } @@ -263,9 +263,9 @@ func (r *ecsResource) Update(ctx context.Context, req resource.UpdateRequest, re } // Delete deletes the resource and removes the Terraform state on success. -func (r *ecsResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *csResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // Retrieve values from plan - var plan ecsResourceModel + var plan csResourceModel diags := req.State.Get(ctx, &plan) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -275,15 +275,15 @@ func (r *ecsResource) Delete(ctx context.Context, req resource.DeleteRequest, re err := r.client.DeleteResource(ctx, plan.ID.ValueString()) if err != nil { resp.Diagnostics.AddError( - "Error deleting ECS service", - "Could not delete ECS service, unexpected error: "+err.Error(), + "Error deleting CS service", + "Could not delete CS service, unexpected error: "+err.Error(), ) } return } // Configure adds the provider configured client to the resource. -func (r *ecsResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *csResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Add a nil check when handling ProviderData because Terraform // sets that data after it calls the ConfigureProvider RPC. if req.ProviderData == nil { diff --git a/internal/provider/eks_resource.go b/internal/provider/ks_resource.go similarity index 79% rename from internal/provider/eks_resource.go rename to internal/provider/ks_resource.go index bb3be37..29db190 100644 --- a/internal/provider/eks_resource.go +++ b/internal/provider/ks_resource.go @@ -12,15 +12,15 @@ import ( ) var ( - _ resource.Resource = &eksResource{} - _ resource.ResourceWithConfigure = &eksResource{} + _ resource.Resource = &ksResource{} + _ resource.ResourceWithConfigure = &ksResource{} ) -func NewEksResource() resource.Resource { - return &eksResource{} +func NewKsResource() resource.Resource { + return &ksResource{} } -type eksResourceModel struct { +type ksResourceModel struct { ID types.String `tfsdk:"id"` ClusterName types.String `tfsdk:"cluster_name"` Version types.String `tfsdk:"version"` @@ -42,15 +42,15 @@ type eksResourceModel struct { LastUpdated types.String `tfsdk:"last_updated"` } -type eksResource struct { +type ksResource struct { client *Client } -func (r *eksResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { - resp.TypeName = req.ProviderTypeName + "_eks" +func (r *ksResource) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = req.ProviderTypeName + "_ks" } -func (r *eksResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { +func (r *ksResource) Schema(_ context.Context, _ resource.SchemaRequest, resp *resource.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ @@ -120,9 +120,9 @@ func (r *eksResource) Schema(_ context.Context, _ resource.SchemaRequest, resp * } // Create a new resource. -func (r *eksResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { +func (r *ksResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { // Retrieve values from plan - var plan eksResourceModel + var plan ksResourceModel diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -131,10 +131,10 @@ func (r *eksResource) Create(ctx context.Context, req resource.CreateRequest, re // Generate API request body from plan var resourceItem ResourceItem - resourceItem.Type = "eks" + resourceItem.Type = "ks" resourceItem.Name = plan.ClusterName.ValueString() - // For EKS, we'll store configuration in a simplified way + // For KS, we'll store configuration in a simplified way // In a real implementation, you'd want to extend the ResourceItem model // to support more complex configurations code := Code{ @@ -142,13 +142,13 @@ func (r *eksResource) Create(ctx context.Context, req resource.CreateRequest, re Runtime: plan.Version.ValueString(), } resourceItem.Code = code - resourceItem.MaxRamSize = "0" // EKS doesn't use RAM size in the same way + resourceItem.MaxRamSize = "0" // KS doesn't use RAM size in the same way resourceItemRes, err := r.client.CreateResource(ctx, resourceItem) if err != nil { resp.Diagnostics.AddError( - "Error creating EKS cluster", - "Could not create EKS cluster, unexpected error: "+err.Error(), + "Error creating KS cluster", + "Could not create KS cluster, unexpected error: "+err.Error(), ) return } @@ -167,8 +167,8 @@ func (r *eksResource) Create(ctx context.Context, req resource.CreateRequest, re } // Read resource information. -func (r *eksResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { - var state eksResourceModel +func (r *ksResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state ksResourceModel diags := req.State.Get(ctx, &state) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -182,8 +182,8 @@ func (r *eksResource) Read(ctx context.Context, req resource.ReadRequest, resp * return } resp.Diagnostics.AddError( - "Error Reading EKS Cluster", - "Could not read EKS cluster ID "+state.ID.ValueString()+": "+err.Error(), + "Error Reading KS Cluster", + "Could not read KS cluster ID "+state.ID.ValueString()+": "+err.Error(), ) return } @@ -204,11 +204,11 @@ func (r *eksResource) Read(ctx context.Context, req resource.ReadRequest, resp * } // Update updates the resource and sets the updated Terraform state on success. -func (r *eksResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { - var plan eksResourceModel +func (r *ksResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan ksResourceModel diags := req.Plan.Get(ctx, &plan) resp.Diagnostics.Append(diags...) - var state eksResourceModel + var state ksResourceModel diagsState := req.State.Get(ctx, &state) resp.Diagnostics.Append(diagsState...) if resp.Diagnostics.HasError() { @@ -217,7 +217,7 @@ func (r *eksResource) Update(ctx context.Context, req resource.UpdateRequest, re var resourceItem ResourceItem resourceItem.ID = state.ID.ValueString() - resourceItem.Type = "eks" + resourceItem.Type = "ks" resourceItem.Name = plan.ClusterName.ValueString() code := Code{ PackageType: "kubernetes", @@ -229,8 +229,8 @@ func (r *eksResource) Update(ctx context.Context, req resource.UpdateRequest, re resourceItemRes, err := r.client.UpdateResource(ctx, resourceItem) if err != nil { resp.Diagnostics.AddError( - "Error updating EKS cluster", - "Could not update EKS cluster, unexpected error: "+err.Error(), + "Error updating KS cluster", + "Could not update KS cluster, unexpected error: "+err.Error(), ) return } @@ -249,9 +249,9 @@ func (r *eksResource) Update(ctx context.Context, req resource.UpdateRequest, re } // Delete deletes the resource and removes the Terraform state on success. -func (r *eksResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { +func (r *ksResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { // Retrieve values from plan - var plan eksResourceModel + var plan ksResourceModel diags := req.State.Get(ctx, &plan) resp.Diagnostics.Append(diags...) if resp.Diagnostics.HasError() { @@ -261,15 +261,15 @@ func (r *eksResource) Delete(ctx context.Context, req resource.DeleteRequest, re err := r.client.DeleteResource(ctx, plan.ID.ValueString()) if err != nil { resp.Diagnostics.AddError( - "Error deleting EKS cluster", - "Could not delete EKS cluster, unexpected error: "+err.Error(), + "Error deleting KS cluster", + "Could not delete KS cluster, unexpected error: "+err.Error(), ) } return } // Configure adds the provider configured client to the resource. -func (r *eksResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { +func (r *ksResource) Configure(_ context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { // Add a nil check when handling ProviderData because Terraform // sets that data after it calls the ConfigureProvider RPC. if req.ProviderData == nil { diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 82c1835..79da583 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -177,7 +177,7 @@ func (p *coderforgeProvider) Resources(_ context.Context) []func() resource.Reso NewFunctionResource, NewContainerResource, NewContainerRegistryResource, - NewEksResource, - NewEcsResource, + NewKsResource, + NewCsResource, } }