diff --git a/.changelog/634.txt b/.changelog/634.txt new file mode 100644 index 000000000..b7ba10bbd --- /dev/null +++ b/.changelog/634.txt @@ -0,0 +1,5 @@ +```release-note:new-resource + - Support for AutoStopping Rules - AWS VM, Azure VM, GCP VM, AWS RDS, AWS ECS + - This version does not support dry run AutoStopping rule creation, provision for hide progress page and tag based ECS rule creation + - Does not have support for schedules feature +``` \ No newline at end of file diff --git a/docs/data-sources/autostopping_rule_ecs.md b/docs/data-sources/autostopping_rule_ecs.md new file mode 100644 index 000000000..badbbdc43 --- /dev/null +++ b/docs/data-sources/autostopping_rule_ecs.md @@ -0,0 +1,73 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harness_autostopping_rule_ecs Data Source - terraform-provider-harness" +subcategory: "Next Gen" +description: |- + Data source for retrieving a Harness Variable. +--- + +# harness_autostopping_rule_ecs (Data Source) + +Data source for retrieving a Harness Variable. + +## Example Usage + +```terraform +data "harness_autostopping_rule_ecs" "example" { + identifier = "identifier" +} +``` + + +## Schema + +### Required + +- `cloud_connector_id` (String) Id of the cloud connector +- `name` (String) Name of the rule + +### Optional + +- `container` (Block List, Max: 1) (see [below for nested schema](#nestedblock--container)) +- `custom_domains` (List of String) Custom URLs used to access the instances +- `depends` (Block List) Dependent rules (see [below for nested schema](#nestedblock--depends)) +- `http` (Block List) Http routing configuration (see [below for nested schema](#nestedblock--http)) +- `idle_time_mins` (Number) Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances. + +### Read-Only + +- `id` (String) The ID of this resource. +- `identifier` (Number) Unique identifier of the resource + + +### Nested Schema for `container` + +Required: + +- `cluster` (String) Name of cluster in which service belong to +- `region` (String) Region of cluster +- `service` (String) Name of service to be onboarded + +Optional: + +- `task_count` (Number) Desired number of tasks on warming up a rule + + + +### Nested Schema for `depends` + +Required: + +- `rule_id` (Number) Rule id of the dependent rule + +Optional: + +- `delay_in_sec` (Number) Number of seconds the rule should wait after warming up the dependent rule + + + +### Nested Schema for `http` + +Required: + +- `proxy_id` (String) Id of the proxy diff --git a/docs/data-sources/autostopping_rule_rds.md b/docs/data-sources/autostopping_rule_rds.md new file mode 100644 index 000000000..ad4d29b3c --- /dev/null +++ b/docs/data-sources/autostopping_rule_rds.md @@ -0,0 +1,82 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harness_autostopping_rule_rds Data Source - terraform-provider-harness" +subcategory: "Next Gen" +description: |- + Data source for retrieving a Harness Variable. +--- + +# harness_autostopping_rule_rds (Data Source) + +Data source for retrieving a Harness Variable. + +## Example Usage + +```terraform +data "harness_autostopping_rule_rds" "example" { + identifier = "identifier" +} +``` + + +## Schema + +### Required + +- `cloud_connector_id` (String) Id of the cloud connector +- `database` (Block List, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--database)) +- `name` (String) Name of the rule + +### Optional + +- `depends` (Block List) Dependent rules (see [below for nested schema](#nestedblock--depends)) +- `idle_time_mins` (Number) Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances. +- `tcp` (Block List) TCP routing configuration (see [below for nested schema](#nestedblock--tcp)) + +### Read-Only + +- `id` (String) The ID of this resource. +- `identifier` (Number) Unique identifier of the resource + + +### Nested Schema for `database` + +Required: + +- `id` (String) ID of the database +- `region` (String) Region to which database belong to + + + +### Nested Schema for `depends` + +Required: + +- `rule_id` (Number) Rule id of the dependent rule + +Optional: + +- `delay_in_sec` (Number) Number of seconds the rule should wait after warming up the dependent rule + + + +### Nested Schema for `tcp` + +Required: + +- `proxy_id` (String) Id of the Proxy + +Optional: + +- `forward_rule` (Block List) Additional tcp forwarding rules (see [below for nested schema](#nestedblock--tcp--forward_rule)) + + +### Nested Schema for `tcp.forward_rule` + +Required: + +- `port` (Number) Port to listen on the vm + +Optional: + +- `connect_on` (Number) Port to listen on the proxy diff --git a/docs/data-sources/autostopping_rule_vm.md b/docs/data-sources/autostopping_rule_vm.md new file mode 100644 index 000000000..5793b0298 --- /dev/null +++ b/docs/data-sources/autostopping_rule_vm.md @@ -0,0 +1,163 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harness_autostopping_rule_vm Data Source - terraform-provider-harness" +subcategory: "Next Gen" +description: |- + Data source for retrieving a Harness Variable. +--- + +# harness_autostopping_rule_vm (Data Source) + +Data source for retrieving a Harness Variable. + +## Example Usage + +```terraform +data "harness_autostopping_rule_vm" "example" { + identifier = "identifier" +} +``` + + +## Schema + +### Required + +- `cloud_connector_id` (String) Id of the cloud connector +- `filter` (Block List, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--filter)) +- `name` (String) Name of the rule + +### Optional + +- `custom_domains` (List of String) Custom URLs used to access the instances +- `depends` (Block List) Dependent rules (see [below for nested schema](#nestedblock--depends)) +- `http` (Block List) Http routing configuration (see [below for nested schema](#nestedblock--http)) +- `idle_time_mins` (Number) Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances. +- `tcp` (Block List) TCP routing configuration (see [below for nested schema](#nestedblock--tcp)) +- `use_spot` (Boolean) Boolean that indicates whether the selected instances should be converted to spot vm + +### Read-Only + +- `id` (String) The ID of this resource. +- `identifier` (Number) Unique identifier of the resource + + +### Nested Schema for `filter` + +Required: + +- `vm_ids` (List of String) Ids of instances that needs to be managed using the AutoStopping rules + +Optional: + +- `regions` (List of String) Regions of instances that needs to be managed using the AutoStopping rules +- `tags` (Block List) Tags of instances that needs to be managed using the AutoStopping rules (see [below for nested schema](#nestedblock--filter--tags)) +- `zones` (List of String) Zones of instances that needs to be managed using the AutoStopping rules + + +### Nested Schema for `filter.tags` + +Required: + +- `key` (String) +- `value` (String) + + + + +### Nested Schema for `depends` + +Required: + +- `rule_id` (Number) Rule id of the dependent rule + +Optional: + +- `delay_in_sec` (Number) Number of seconds the rule should wait after warming up the dependent rule + + + +### Nested Schema for `http` + +Required: + +- `proxy_id` (String) Id of the proxy + +Optional: + +- `health` (Block List) Health Check Details (see [below for nested schema](#nestedblock--http--health)) +- `routing` (Block List) Routing configuration used to access the instances (see [below for nested schema](#nestedblock--http--routing)) + + +### Nested Schema for `http.health` + +Required: + +- `port` (Number) Health check port on the VM +- `protocol` (String) Protocol can be http or https + +Optional: + +- `path` (String) API path to use for health check +- `status_code_from` (Number) Lower limit for acceptable status code +- `status_code_to` (Number) Upper limit for acceptable status code +- `timeout` (Number) Health check timeout + + + +### Nested Schema for `http.routing` + +Required: + +- `source_protocol` (String) Source protocol of the proxy can be http or https +- `target_protocol` (String) Target protocol of the instance can be http or https + +Optional: + +- `action` (String) Organization Identifier for the Entity +- `source_port` (Number) Port on the proxy +- `target_port` (Number) Port on the VM + + + + +### Nested Schema for `tcp` + +Required: + +- `proxy_id` (String) Id of the Proxy + +Optional: + +- `forward_rule` (Block List) Additional tcp forwarding rules (see [below for nested schema](#nestedblock--tcp--forward_rule)) +- `rdp` (Block List) RDP configuration (see [below for nested schema](#nestedblock--tcp--rdp)) +- `ssh` (Block List) SSH configuration (see [below for nested schema](#nestedblock--tcp--ssh)) + + +### Nested Schema for `tcp.forward_rule` + +Required: + +- `port` (Number) Port to listen on the vm + +Optional: + +- `connect_on` (Number) Port to listen on the proxy + + + +### Nested Schema for `tcp.rdp` + +Optional: + +- `connect_on` (Number) Port to listen on the proxy +- `port` (Number) Port to listen on the vm + + + +### Nested Schema for `tcp.ssh` + +Optional: + +- `connect_on` (Number) Port to listen on the proxy +- `port` (Number) Port to listen on the vm diff --git a/docs/resources/autostopping_rule_ecs.md b/docs/resources/autostopping_rule_ecs.md new file mode 100644 index 000000000..4f359bb80 --- /dev/null +++ b/docs/resources/autostopping_rule_ecs.md @@ -0,0 +1,91 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harness_autostopping_rule_ecs Resource - terraform-provider-harness" +subcategory: "Next Gen" +description: |- + Resource for creating a Harness Variables. +--- + +# harness_autostopping_rule_ecs (Resource) + +Resource for creating a Harness Variables. + +## Example Usage + +```terraform +resource "harness_autostopping_rule_ecs" "test" { + name = "name" + cloud_connector_id = "cloud_connector_id" + idle_time_mins = 10 + container { + cluster = "cluster" + service = "service" + region = "us-east-1" + task_count = 1 + } + tcp { + proxy_id = "proxy_id" + forward_rule { + port = 2233 + } + } + depends { + rule_id = 24576 + delay_in_sec = 5 + } +} +``` + + +## Schema + +### Required + +- `cloud_connector_id` (String) Id of the cloud connector +- `name` (String) Name of the rule + +### Optional + +- `container` (Block List, Max: 1) (see [below for nested schema](#nestedblock--container)) +- `custom_domains` (List of String) Custom URLs used to access the instances +- `depends` (Block List) Dependent rules (see [below for nested schema](#nestedblock--depends)) +- `http` (Block List) Http routing configuration (see [below for nested schema](#nestedblock--http)) +- `idle_time_mins` (Number) Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances. + +### Read-Only + +- `id` (String) The ID of this resource. +- `identifier` (Number) Unique identifier of the resource + + +### Nested Schema for `container` + +Required: + +- `cluster` (String) Name of cluster in which service belong to +- `region` (String) Region of cluster +- `service` (String) Name of service to be onboarded + +Optional: + +- `task_count` (Number) Desired number of tasks on warming up a rule + + + +### Nested Schema for `depends` + +Required: + +- `rule_id` (Number) Rule id of the dependent rule + +Optional: + +- `delay_in_sec` (Number) Number of seconds the rule should wait after warming up the dependent rule + + + +### Nested Schema for `http` + +Required: + +- `proxy_id` (String) Id of the proxy diff --git a/docs/resources/autostopping_rule_rds.md b/docs/resources/autostopping_rule_rds.md new file mode 100644 index 000000000..357f8d93c --- /dev/null +++ b/docs/resources/autostopping_rule_rds.md @@ -0,0 +1,94 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harness_autostopping_rule_rds Resource - terraform-provider-harness" +subcategory: "Next Gen" +description: |- + Resource for creating a Harness Variables. +--- + +# harness_autostopping_rule_rds (Resource) + +Resource for creating a Harness Variables. + +## Example Usage + +```terraform +resource "harness_autostopping_rule_rds" "test" { + name = "name" + cloud_connector_id = "cloud_connector_id" + idle_time_mins = 10 + database { + id = "database_id" + region = "region" + } + tcp { + proxy_id = "proxy_id" + forward_rule { + port = 2233 + } + } +} +``` + + +## Schema + +### Required + +- `cloud_connector_id` (String) Id of the cloud connector +- `database` (Block List, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--database)) +- `name` (String) Name of the rule + +### Optional + +- `depends` (Block List) Dependent rules (see [below for nested schema](#nestedblock--depends)) +- `idle_time_mins` (Number) Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances. +- `tcp` (Block List) TCP routing configuration (see [below for nested schema](#nestedblock--tcp)) + +### Read-Only + +- `id` (String) The ID of this resource. +- `identifier` (Number) Unique identifier of the resource + + +### Nested Schema for `database` + +Required: + +- `id` (String) ID of the database +- `region` (String) Region to which database belong to + + + +### Nested Schema for `depends` + +Required: + +- `rule_id` (Number) Rule id of the dependent rule + +Optional: + +- `delay_in_sec` (Number) Number of seconds the rule should wait after warming up the dependent rule + + + +### Nested Schema for `tcp` + +Required: + +- `proxy_id` (String) Id of the Proxy + +Optional: + +- `forward_rule` (Block List) Additional tcp forwarding rules (see [below for nested schema](#nestedblock--tcp--forward_rule)) + + +### Nested Schema for `tcp.forward_rule` + +Required: + +- `port` (Number) Port to listen on the vm + +Optional: + +- `connect_on` (Number) Port to listen on the proxy diff --git a/docs/resources/autostopping_rule_vm.md b/docs/resources/autostopping_rule_vm.md new file mode 100644 index 000000000..482cb1722 --- /dev/null +++ b/docs/resources/autostopping_rule_vm.md @@ -0,0 +1,210 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "harness_autostopping_rule_vm Resource - terraform-provider-harness" +subcategory: "Next Gen" +description: |- + Resource for creating a Harness Variables. +--- + +# harness_autostopping_rule_vm (Resource) + +Resource for creating a Harness Variables. + +## Example Usage + +```terraform +resource "harness_autostopping_rule_vm" "test" { + name = "name" + cloud_connector_id = "cloud_connector_id" + idle_time_mins = 10 + filter { + vm_ids = ["/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Compute/virtualMachines/virtual_machine"] + regions = ["useast2"] + } + http { + proxy_id = "proxy_id" + routing { + source_protocol = "https" + target_protocol = "https" + source_port = 443 + target_port = 443 + action = "forward" + } + routing { + source_protocol = "http" + target_protocol = "http" + source_port = 80 + target_port = 80 + action = "forward" + } + health { + protocol = "http" + port = 80 + path = "/" + timeout = 30 + status_code_from = 200 + status_code_to = 299 + } + } + tcp { + proxy_id = "proxy_id" + ssh { + port = 22 + } + rdp { + port = 3389 + } + forward_rule { + port = 2233 + } + } + depends { + rule_id = 24576 + delay_in_sec = 5 + } +} +``` + + +## Schema + +### Required + +- `cloud_connector_id` (String) Id of the cloud connector +- `filter` (Block List, Min: 1, Max: 1) (see [below for nested schema](#nestedblock--filter)) +- `name` (String) Name of the rule + +### Optional + +- `custom_domains` (List of String) Custom URLs used to access the instances +- `depends` (Block List) Dependent rules (see [below for nested schema](#nestedblock--depends)) +- `http` (Block List) Http routing configuration (see [below for nested schema](#nestedblock--http)) +- `idle_time_mins` (Number) Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances. +- `tcp` (Block List) TCP routing configuration (see [below for nested schema](#nestedblock--tcp)) +- `use_spot` (Boolean) Boolean that indicates whether the selected instances should be converted to spot vm + +### Read-Only + +- `id` (String) The ID of this resource. +- `identifier` (Number) Unique identifier of the resource + + +### Nested Schema for `filter` + +Required: + +- `vm_ids` (List of String) Ids of instances that needs to be managed using the AutoStopping rules + +Optional: + +- `regions` (List of String) Regions of instances that needs to be managed using the AutoStopping rules +- `tags` (Block List) Tags of instances that needs to be managed using the AutoStopping rules (see [below for nested schema](#nestedblock--filter--tags)) +- `zones` (List of String) Zones of instances that needs to be managed using the AutoStopping rules + + +### Nested Schema for `filter.tags` + +Required: + +- `key` (String) +- `value` (String) + + + + +### Nested Schema for `depends` + +Required: + +- `rule_id` (Number) Rule id of the dependent rule + +Optional: + +- `delay_in_sec` (Number) Number of seconds the rule should wait after warming up the dependent rule + + + +### Nested Schema for `http` + +Required: + +- `proxy_id` (String) Id of the proxy + +Optional: + +- `health` (Block List) Health Check Details (see [below for nested schema](#nestedblock--http--health)) +- `routing` (Block List) Routing configuration used to access the instances (see [below for nested schema](#nestedblock--http--routing)) + + +### Nested Schema for `http.health` + +Required: + +- `port` (Number) Health check port on the VM +- `protocol` (String) Protocol can be http or https + +Optional: + +- `path` (String) API path to use for health check +- `status_code_from` (Number) Lower limit for acceptable status code +- `status_code_to` (Number) Upper limit for acceptable status code +- `timeout` (Number) Health check timeout + + + +### Nested Schema for `http.routing` + +Required: + +- `source_protocol` (String) Source protocol of the proxy can be http or https +- `target_protocol` (String) Target protocol of the instance can be http or https + +Optional: + +- `action` (String) Organization Identifier for the Entity +- `source_port` (Number) Port on the proxy +- `target_port` (Number) Port on the VM + + + + +### Nested Schema for `tcp` + +Required: + +- `proxy_id` (String) Id of the Proxy + +Optional: + +- `forward_rule` (Block List) Additional tcp forwarding rules (see [below for nested schema](#nestedblock--tcp--forward_rule)) +- `rdp` (Block List) RDP configuration (see [below for nested schema](#nestedblock--tcp--rdp)) +- `ssh` (Block List) SSH configuration (see [below for nested schema](#nestedblock--tcp--ssh)) + + +### Nested Schema for `tcp.forward_rule` + +Required: + +- `port` (Number) Port to listen on the vm + +Optional: + +- `connect_on` (Number) Port to listen on the proxy + + + +### Nested Schema for `tcp.rdp` + +Optional: + +- `connect_on` (Number) Port to listen on the proxy +- `port` (Number) Port to listen on the vm + + + +### Nested Schema for `tcp.ssh` + +Optional: + +- `connect_on` (Number) Port to listen on the proxy +- `port` (Number) Port to listen on the vm diff --git a/examples/data-sources/harness_autostopping_rule_ecs/data-source.tf b/examples/data-sources/harness_autostopping_rule_ecs/data-source.tf new file mode 100644 index 000000000..d8b5de01b --- /dev/null +++ b/examples/data-sources/harness_autostopping_rule_ecs/data-source.tf @@ -0,0 +1,3 @@ +data "harness_autostopping_rule_ecs" "example" { + identifier = "identifier" +} diff --git a/examples/data-sources/harness_autostopping_rule_rds/data-source.tf b/examples/data-sources/harness_autostopping_rule_rds/data-source.tf new file mode 100644 index 000000000..f818e0844 --- /dev/null +++ b/examples/data-sources/harness_autostopping_rule_rds/data-source.tf @@ -0,0 +1,3 @@ +data "harness_autostopping_rule_rds" "example" { + identifier = "identifier" +} diff --git a/examples/data-sources/harness_autostopping_rule_vm/data-source.tf b/examples/data-sources/harness_autostopping_rule_vm/data-source.tf new file mode 100644 index 000000000..c6a4cd782 --- /dev/null +++ b/examples/data-sources/harness_autostopping_rule_vm/data-source.tf @@ -0,0 +1,3 @@ +data "harness_autostopping_rule_vm" "example" { + identifier = "identifier" +} diff --git a/examples/resources/harness_autostopping_azure_proxy/resource.tf b/examples/resources/harness_autostopping_azure_proxy/resource.tf index 8e300746c..4c6d71f4f 100644 --- a/examples/resources/harness_autostopping_azure_proxy/resource.tf +++ b/examples/resources/harness_autostopping_azure_proxy/resource.tf @@ -1,15 +1,15 @@ resource "harness_autostopping_azure_proxy" "test" { - name = "name" - cloud_connector_id = "cloud_connector_id" - host_name = "host_name" - region = "eastus2" - resource_group = "resource_group" - vpc = "/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Network/virtualNetworks/virtual_network" - subnet_id = "/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Network/virtualNetworks/virtual_network/subnets/subnet_id" - security_groups =["/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Network/networkSecurityGroups/network_security_group"] - allocate_static_ip = true - machine_type = "Standard_D2s_v3" - keypair = "" - api_key = "" + name = "name" + cloud_connector_id = "cloud_connector_id" + host_name = "host_name" + region = "eastus2" + resource_group = "resource_group" + vpc = "/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Network/virtualNetworks/virtual_network" + subnet_id = "/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Network/virtualNetworks/virtual_network/subnets/subnet_id" + security_groups = ["/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Network/networkSecurityGroups/network_security_group"] + allocate_static_ip = true + machine_type = "Standard_D2s_v3" + keypair = "" + api_key = "" } diff --git a/examples/resources/harness_autostopping_rule_ecs/resource.tf b/examples/resources/harness_autostopping_rule_ecs/resource.tf new file mode 100644 index 000000000..afa78890e --- /dev/null +++ b/examples/resources/harness_autostopping_rule_ecs/resource.tf @@ -0,0 +1,21 @@ +resource "harness_autostopping_rule_ecs" "test" { + name = "name" + cloud_connector_id = "cloud_connector_id" + idle_time_mins = 10 + container { + cluster = "cluster" + service = "service" + region = "us-east-1" + task_count = 1 + } + tcp { + proxy_id = "proxy_id" + forward_rule { + port = 2233 + } + } + depends { + rule_id = 24576 + delay_in_sec = 5 + } +} diff --git a/examples/resources/harness_autostopping_rule_rds/resource.tf b/examples/resources/harness_autostopping_rule_rds/resource.tf new file mode 100644 index 000000000..7ff8a985f --- /dev/null +++ b/examples/resources/harness_autostopping_rule_rds/resource.tf @@ -0,0 +1,15 @@ +resource "harness_autostopping_rule_rds" "test" { + name = "name" + cloud_connector_id = "cloud_connector_id" + idle_time_mins = 10 + database { + id = "database_id" + region = "region" + } + tcp { + proxy_id = "proxy_id" + forward_rule { + port = 2233 + } + } +} diff --git a/examples/resources/harness_autostopping_rule_vm/resource.tf b/examples/resources/harness_autostopping_rule_vm/resource.tf new file mode 100644 index 000000000..63637076d --- /dev/null +++ b/examples/resources/harness_autostopping_rule_vm/resource.tf @@ -0,0 +1,50 @@ +resource "harness_autostopping_rule_vm" "test" { + name = "name" + cloud_connector_id = "cloud_connector_id" + idle_time_mins = 10 + filter { + vm_ids = ["/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Compute/virtualMachines/virtual_machine"] + regions = ["useast2"] + } + http { + proxy_id = "proxy_id" + routing { + source_protocol = "https" + target_protocol = "https" + source_port = 443 + target_port = 443 + action = "forward" + } + routing { + source_protocol = "http" + target_protocol = "http" + source_port = 80 + target_port = 80 + action = "forward" + } + health { + protocol = "http" + port = 80 + path = "/" + timeout = 30 + status_code_from = 200 + status_code_to = 299 + } + } + tcp { + proxy_id = "proxy_id" + ssh { + port = 22 + } + rdp { + port = 3389 + } + forward_rule { + port = 2233 + } + } + depends { + rule_id = 24576 + delay_in_sec = 5 + } +} diff --git a/internal/provider/provider.go b/internal/provider/provider.go index c97c203c0..b922205d9 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -36,6 +36,7 @@ import ( "github.com/harness/terraform-provider-harness/internal/service/cd/yamlconfig" pl_apikey "github.com/harness/terraform-provider-harness/internal/service/platform/api_key" "github.com/harness/terraform-provider-harness/internal/service/platform/autostopping/load_balancer" + as_rule "github.com/harness/terraform-provider-harness/internal/service/platform/autostopping/rule" "github.com/harness/terraform-provider-harness/internal/service/platform/ccm_filters" "github.com/harness/terraform-provider-harness/internal/service/platform/connector" pl_current_user "github.com/harness/terraform-provider-harness/internal/service/platform/current_user" @@ -54,6 +55,7 @@ import ( gitops_repo_cert "github.com/harness/terraform-provider-harness/internal/service/platform/gitops/repository_certificates" gitops_repo_cred "github.com/harness/terraform-provider-harness/internal/service/platform/gitops/repository_credentials" pl_infrastructure "github.com/harness/terraform-provider-harness/internal/service/platform/infrastructure" + "github.com/harness/terraform-provider-harness/internal/service/platform/input_set" "github.com/harness/terraform-provider-harness/internal/service/platform/monitored_service" "github.com/harness/terraform-provider-harness/internal/service/platform/organization" @@ -229,6 +231,9 @@ func Provider(version string) func() *schema.Provider { "harness_platform_connector_service_now": connector.DataSourceConnectorSerivceNow(), "harness_platform_apikey": pl_apikey.DataSourceApiKey(), "harness_platform_token": pl_token.DataSourceToken(), + "harness_autostopping_rule_vm": as_rule.DataSourceVMRule(), + "harness_autostopping_rule_rds": as_rule.DataSourceRDSRule(), + "harness_autostopping_rule_ecs": as_rule.DataSourceECSRule(), "harness_platform_file_store_file": file_store.DataSourceFileStoreNodeFile(), "harness_platform_file_store_folder": file_store.DataSourceFileStoreNodeFolder(), "harness_autostopping_azure_proxy": load_balancer.DataSourceAzureProxy(), @@ -352,6 +357,9 @@ func Provider(version string) func() *schema.Provider { "harness_platform_connector_service_now": connector.ResourceConnectorServiceNow(), "harness_platform_apikey": pl_apikey.ResourceApiKey(), "harness_platform_token": pl_token.ResourceToken(), + "harness_autostopping_rule_vm": as_rule.ResourceVMRule(), + "harness_autostopping_rule_rds": as_rule.ResourceRDSRule(), + "harness_autostopping_rule_ecs": as_rule.ResourceECSRule(), "harness_platform_file_store_file": file_store.ResourceFileStoreNodeFile(), "harness_platform_file_store_folder": file_store.ResourceFileStoreNodeFolder(), "harness_autostopping_azure_proxy": load_balancer.ResourceAzureProxy(), diff --git a/internal/service/platform/autostopping/rule/as_ecs.go b/internal/service/platform/autostopping/rule/as_ecs.go new file mode 100644 index 000000000..03c60dc68 --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_ecs.go @@ -0,0 +1,125 @@ +package as_rule + +import ( + "context" + + "github.com/harness/terraform-provider-harness/helpers" + "github.com/harness/terraform-provider-harness/internal" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceECSRule() *schema.Resource { + resource := &schema.Resource{ + Description: "Resource for creating a Harness Variables.", + + ReadContext: resourceASRuleRead, + CreateContext: resourceECSRuleCreateOrUpdate, + UpdateContext: resourceECSRuleCreateOrUpdate, + DeleteContext: resourceASRuleDelete, + Importer: helpers.MultiLevelResourceImporter, + Schema: map[string]*schema.Schema{ + "identifier": { + Description: "Unique identifier of the resource", + Type: schema.TypeFloat, + Computed: true, + }, + "name": { + Description: "Name of the rule", + Type: schema.TypeString, + Required: true, + }, + "cloud_connector_id": { + Description: "Id of the cloud connector", + Type: schema.TypeString, + Required: true, + }, + "idle_time_mins": { + Description: "Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances.", + Type: schema.TypeInt, + Optional: true, + Default: 15, + }, + "custom_domains": { + Description: "Custom URLs used to access the instances", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "container": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster": { + Type: schema.TypeString, + Description: "Name of cluster in which service belong to", + Required: true, + }, + "service": { + Type: schema.TypeString, + Description: "Name of service to be onboarded", + Required: true, + }, + "region": { + Type: schema.TypeString, + Description: "Region of cluster", + Required: true, + }, + "task_count": { + Type: schema.TypeInt, + Description: "Desired number of tasks on warming up a rule", + Optional: true, + Default: 1, + }, + }, + }, + }, + "http": { + Description: "Http routing configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "proxy_id": { + Description: "Id of the proxy", + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "depends": { + Description: "Dependent rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Description: "Rule id of the dependent rule", + Type: schema.TypeInt, + Required: true, + }, + "delay_in_sec": { + Description: "Number of seconds the rule should wait after warming up the dependent rule", + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + }, + }, + }, + }, + } + + return resource +} + +func resourceECSRuleCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + saveServiceRequestV2 := buildASRule(d, ECS, c.AccountId) + return resourceASRuleCreateOrUpdate(ctx, d, meta, saveServiceRequestV2) +} diff --git a/internal/service/platform/autostopping/rule/as_ecs_data_source.go b/internal/service/platform/autostopping/rule/as_ecs_data_source.go new file mode 100644 index 000000000..ea7af0bc4 --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_ecs_data_source.go @@ -0,0 +1,110 @@ +package as_rule + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceECSRule() *schema.Resource { + resource := &schema.Resource{ + Description: "Data source for retrieving a Harness Variable.", + ReadContext: resourceASRuleRead, + + Schema: map[string]*schema.Schema{ + "identifier": { + Description: "Unique identifier of the resource", + Type: schema.TypeFloat, + Computed: true, + }, + "name": { + Description: "Name of the rule", + Type: schema.TypeString, + Required: true, + }, + "cloud_connector_id": { + Description: "Id of the cloud connector", + Type: schema.TypeString, + Required: true, + }, + "idle_time_mins": { + Description: "Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances.", + Type: schema.TypeInt, + Optional: true, + Default: 15, + }, + "custom_domains": { + Description: "Custom URLs used to access the instances", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "container": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cluster": { + Type: schema.TypeString, + Description: "Name of cluster in which service belong to", + Required: true, + }, + "service": { + Type: schema.TypeString, + Description: "Name of service to be onboarded", + Required: true, + }, + "region": { + Type: schema.TypeString, + Description: "Region of cluster", + Required: true, + }, + "task_count": { + Type: schema.TypeInt, + Description: "Desired number of tasks on warming up a rule", + Optional: true, + Default: 1, + }, + }, + }, + }, + "http": { + Description: "Http routing configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "proxy_id": { + Description: "Id of the proxy", + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "depends": { + Description: "Dependent rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Description: "Rule id of the dependent rule", + Type: schema.TypeInt, + Required: true, + }, + "delay_in_sec": { + Description: "Number of seconds the rule should wait after warming up the dependent rule", + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + }, + }, + }, + }, + } + + return resource +} diff --git a/internal/service/platform/autostopping/rule/as_ecs_test.go b/internal/service/platform/autostopping/rule/as_ecs_test.go new file mode 100644 index 000000000..726ff4d4d --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_ecs_test.go @@ -0,0 +1,51 @@ +package as_rule_test + +import ( + "fmt" + "testing" + + "github.com/harness/terraform-provider-harness/internal/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestResourceECSRule(t *testing.T) { + name := "terraform-rule-test" + resourceName := "harness_autostopping_rule_ecs.test" + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + // CheckDestroy: testRuleDestroy(resourceName), + Steps: []resource.TestStep{ + { + Config: testECSRule(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", name), + ), + }, + }, + }) +} + +func testECSRule(name string) string { + return fmt.Sprintf(` + resource "harness_autostopping_rule_ecs" "test" { + name = "%[1]s" + cloud_connector_id = "Azure_SE" + idle_time_mins = 10 + container { + cluster = "cluster" + service = "service" + region = "us-east-1" + task_count = 1 + } + http { + proxy_id = "ap-chdpf8f83v0c1aj69oog" + } + depends { + rule_id = 24576 + delay_in_sec = 5 + } + } +`, name) +} diff --git a/internal/service/platform/autostopping/rule/as_rds.go b/internal/service/platform/autostopping/rule/as_rds.go new file mode 100644 index 000000000..e239748a5 --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_rds.go @@ -0,0 +1,125 @@ +package as_rule + +import ( + "context" + + "github.com/harness/terraform-provider-harness/helpers" + "github.com/harness/terraform-provider-harness/internal" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceRDSRule() *schema.Resource { + resource := &schema.Resource{ + Description: "Resource for creating a Harness Variables.", + + ReadContext: resourceASRuleRead, + UpdateContext: resourceRDSRuleCreateOrUpdate, + DeleteContext: resourceASRuleDelete, + CreateContext: resourceRDSRuleCreateOrUpdate, + Importer: helpers.MultiLevelResourceImporter, + Schema: map[string]*schema.Schema{ + "identifier": { + Description: "Unique identifier of the resource", + Type: schema.TypeFloat, + Computed: true, + }, + "name": { + Description: "Name of the rule", + Type: schema.TypeString, + Required: true, + }, + "cloud_connector_id": { + Description: "Id of the cloud connector", + Type: schema.TypeString, + Required: true, + }, + "idle_time_mins": { + Description: "Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances.", + Type: schema.TypeInt, + Optional: true, + Default: 15, + }, + "database": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + Description: "ID of the database", + }, + "region": { + Type: schema.TypeString, + Required: true, + Description: "Region to which database belong to", + }, + }, + }, + }, + "tcp": { + Description: "TCP routing configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "proxy_id": { + Description: "Id of the Proxy", + Type: schema.TypeString, + Required: true, + }, + "forward_rule": { + Description: "Additional tcp forwarding rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connect_on": { + Description: "Port to listen on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "port": { + Description: "Port to listen on the vm", + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "depends": { + Description: "Dependent rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Description: "Rule id of the dependent rule", + Type: schema.TypeInt, + Required: true, + }, + "delay_in_sec": { + Description: "Number of seconds the rule should wait after warming up the dependent rule", + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + }, + }, + }, + }, + } + + return resource +} + +func resourceRDSRuleCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + saveServiceRequestV2 := buildASRule(d, Database, c.AccountId) + return resourceASRuleCreateOrUpdate(ctx, d, meta, saveServiceRequestV2) +} diff --git a/internal/service/platform/autostopping/rule/as_rds_data_source.go b/internal/service/platform/autostopping/rule/as_rds_data_source.go new file mode 100644 index 000000000..298addce7 --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_rds_data_source.go @@ -0,0 +1,110 @@ +package as_rule + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceRDSRule() *schema.Resource { + resource := &schema.Resource{ + Description: "Data source for retrieving a Harness Variable.", + ReadContext: resourceASRuleRead, + + Schema: map[string]*schema.Schema{ + "identifier": { + Description: "Unique identifier of the resource", + Type: schema.TypeFloat, + Computed: true, + }, + "name": { + Description: "Name of the rule", + Type: schema.TypeString, + Required: true, + }, + "cloud_connector_id": { + Description: "Id of the cloud connector", + Type: schema.TypeString, + Required: true, + }, + "idle_time_mins": { + Description: "Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances.", + Type: schema.TypeInt, + Optional: true, + Default: 15, + }, + "database": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "id": { + Type: schema.TypeString, + Required: true, + Description: "ID of the database", + }, + "region": { + Type: schema.TypeString, + Required: true, + Description: "Region to which database belong to", + }, + }, + }, + }, + "tcp": { + Description: "TCP routing configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "proxy_id": { + Description: "Id of the Proxy", + Type: schema.TypeString, + Required: true, + }, + "forward_rule": { + Description: "Additional tcp forwarding rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connect_on": { + Description: "Port to listen on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "port": { + Description: "Port to listen on the vm", + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "depends": { + Description: "Dependent rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Description: "Rule id of the dependent rule", + Type: schema.TypeInt, + Required: true, + }, + "delay_in_sec": { + Description: "Number of seconds the rule should wait after warming up the dependent rule", + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + }, + }, + }, + }, + } + + return resource +} diff --git a/internal/service/platform/autostopping/rule/as_rds_test.go b/internal/service/platform/autostopping/rule/as_rds_test.go new file mode 100644 index 000000000..131acfd7c --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_rds_test.go @@ -0,0 +1,75 @@ +package as_rule_test + +import ( + "fmt" + "testing" + + "github.com/harness/terraform-provider-harness/internal/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestResourceRDSRule(t *testing.T) { + name := "terraform-rule-test-rds" + resourceName := "harness_autostopping_rule_rds.test" + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + // CheckDestroy: testRuleDestroy(resourceName), + Steps: []resource.TestStep{ + { + Config: testRDSRule(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", name), + ), + }, + { + Config: testRDSRuleUpdate(name, "15"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", name), + resource.TestCheckResourceAttr(resourceName, "idle_time_mins", "15"), + ), + }, + }, + }) +} + +func testRDSRule(name string) string { + return fmt.Sprintf(` + resource "harness_autostopping_rule_rds" "test" { + name = "%[1]s" + cloud_connector_id = "DoNotDelete_LightwingNonProd" + idle_time_mins = 10 + database { + id = "database_id" + region = "us-east-1" + } + tcp { + proxy_id = "ap-ciun1635us1fhpjiotfg" + forward_rule { + port = 2233 + } + } + } +`, name) +} + +func testRDSRuleUpdate(name string, idleTime string) string { + return fmt.Sprintf(` + resource "harness_autostopping_rule_rds" "test" { + name = "%[1]s" + cloud_connector_id = "DoNotDelete_LightwingNonProd" + idle_time_mins = %[2]s + database { + id = "database_id" + region = "us-east-1" + } + tcp { + proxy_id = "ap-ciun1635us1fhpjiotfg" + forward_rule { + port = 2233 + } + } + } +`, name, idleTime) +} diff --git a/internal/service/platform/autostopping/rule/as_rule.go b/internal/service/platform/autostopping/rule/as_rule.go new file mode 100644 index 000000000..190c29d9d --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_rule.go @@ -0,0 +1,364 @@ +package as_rule + +import ( + "context" + "net/http" + "strconv" + + "github.com/harness/harness-go-sdk/harness/nextgen" + "github.com/harness/terraform-provider-harness/helpers" + "github.com/harness/terraform-provider-harness/internal" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +const ( + Database = "database" + Instance = "instance" + ECS = "containers" +) + +func resourceASRuleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + + ruleId, err := strconv.ParseFloat(d.Id(), 64) + if err != nil { + return diag.Errorf("invalid rule id") + } + resp, httpResp, err := c.CloudCostAutoStoppingRulesApi.AutoStoppingRuleDetails(ctx, c.AccountId, ruleId, c.AccountId) + + if err != nil { + return helpers.HandleReadApiError(err, d, httpResp) + } + + if resp.Response != nil { + readASRule(d, resp.Response.Service.Id) + } + + return nil +} + +func resourceASRuleCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}, rule nextgen.SaveServiceRequestV2) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + + var err error + var resp nextgen.RuleResponse + var httpResp *http.Response + + id := d.Id() + + if id == "" { + resp, httpResp, err = c.CloudCostAutoStoppingRulesV2Api.CreateAutoStoppingRuleV2(ctx, rule, c.AccountId, c.AccountId) + } else { + resp, httpResp, err = c.CloudCostAutoStoppingRulesV2Api.UpdateAutoStoppingRuleV2(ctx, rule, c.AccountId, c.AccountId, id) + } + + if err != nil { + return helpers.HandleApiError(err, d, httpResp) + } + + if resp.Response != nil { + readASRule(d, resp.Response.Id) + } + + return nil +} + +func resourceASRuleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + ruleId, err := strconv.ParseFloat(d.Id(), 64) + if err != nil { + return diag.Errorf("invalid rule id") + } + httpResp, err := c.CloudCostAutoStoppingRulesApi.DeleteAutoStoppingRule(ctx, ruleId, c.AccountId, c.AccountId) + if err != nil { + return helpers.HandleApiError(err, d, httpResp) + } + return nil +} + +func buildASRule(d *schema.ResourceData, kind string, accountId string) nextgen.SaveServiceRequestV2 { + serviceV2 := &nextgen.ServiceV2{} + serviceV2.AccountIdentifier = accountId + serviceV2.Kind = kind + if attr, ok := d.GetOk("name"); ok { + serviceV2.Name = attr.(string) + } + + if attr, ok := d.GetOk("cloud_connector_id"); ok { + serviceV2.CloudAccountId = attr.(string) + } + serviceV2.Fulfilment = "ondemand" + if attr, ok := d.GetOk("use_spot"); ok { + onDemand := attr.(bool) + if onDemand { + serviceV2.Fulfilment = "ondemand" + } else { + serviceV2.Fulfilment = "spot" + } + } + serviceV2.IdleTimeMins = 15 + if attr, ok := d.GetOk("idle_time_mins"); ok { + serviceV2.IdleTimeMins = attr.(int) + } + + if attr, ok := d.GetOk("custom_domains"); ok { + domains := make([]string, 0) + for _, v := range attr.([]interface{}) { + domains = append(domains, v.(string)) + } + serviceV2.CustomDomains = domains + } + routingData := &nextgen.RoutingDataV2{} + httpProxy, tcpProxy, healthCheck := getRoutingConfigurations(d) + if httpProxy != nil { + routingData.Http = httpProxy + } + if tcpProxy != nil { + routingData.Tcp = tcpProxy + } + if healthCheck != nil { + serviceV2.HealthCheck = healthCheck + } + + rdsDatabase := getDatabaseConfig(d) + if rdsDatabase != nil { + routingData.Database = rdsDatabase + } + + containerSvc := getContainerConfig(d) + if containerSvc != nil { + routingData.ContainerSvc = containerSvc + } + + if attr, ok := d.GetOk("filter"); ok { + filter := &nextgen.FilterObject{} + filterObj := attr.([]interface{})[0].(map[string]interface{}) + if attr, ok := filterObj["vm_ids"]; ok { + vmIds := make([]string, 0) + for _, v := range attr.([]interface{}) { + vmIds = append(vmIds, v.(string)) + } + filter.Ids = vmIds + } + if attr, ok := filterObj["regions"]; ok { + regions := make([]string, 0) + for _, v := range attr.([]interface{}) { + regions = append(regions, v.(string)) + } + filter.Regions = regions + } + if attr, ok := filterObj["zones"]; ok { + zones := make([]string, 0) + for _, v := range attr.([]interface{}) { + zones = append(zones, v.(string)) + } + filter.Zones = zones + } + if attr, ok := filterObj["tags"]; ok { + filter.Tags = make(map[string]string) + for _, tag := range attr.([]interface{}) { + item := tag.(map[string]interface{}) + filter.Tags[item["key"].(string)] = item["value"].(string) + } + } + routingData.Instance = &nextgen.InstanceBasedRoutingDataV2{} + routingData.Instance.Filter = filter + } + + serviceV2.Routing = routingData + deps := getDependencies(d) + saveServiceRequestV2 := &nextgen.SaveServiceRequestV2{ + Service: serviceV2, + Deps: deps, + } + return *saveServiceRequestV2 +} + +func getDatabaseConfig(d *schema.ResourceData) *nextgen.RdsDatabase { + var rdsDatabase *nextgen.RdsDatabase + if attr, ok := d.GetOk("database"); ok { + rdsDatabase = &nextgen.RdsDatabase{} + databaseObj := attr.([]interface{})[0].(map[string]interface{}) + if attr, ok := databaseObj["id"]; ok { + rdsDatabase.Id = attr.(string) + } + if attr, ok := databaseObj["region"]; ok { + rdsDatabase.Region = attr.(string) + } + } + return rdsDatabase +} + +func getContainerConfig(d *schema.ResourceData) *nextgen.ContainerSvc { + var containerSvc *nextgen.ContainerSvc + if attr, ok := d.GetOk("container"); ok { + containerSvc = &nextgen.ContainerSvc{} + databaseObj := attr.([]interface{})[0].(map[string]interface{}) + if attr, ok := databaseObj["cluster"]; ok { + containerSvc.Cluster = attr.(string) + } + if attr, ok := databaseObj["region"]; ok { + containerSvc.Region = attr.(string) + } + if attr, ok := databaseObj["service"]; ok { + containerSvc.Service = attr.(string) + } + containerSvc.TaskCount = 1 + if attr, ok := databaseObj["task_count"]; ok { + desCount, ok := attr.(int64) + if ok { + containerSvc.TaskCount = float64(desCount) + } + } + } + return containerSvc +} + +func getDependencies(d *schema.ResourceData) []nextgen.ServiceDep { + dependencies := d.Get("depends").([]interface{}) + dependencyList := make([]nextgen.ServiceDep, 0) + if len(dependencies) == 0 { + return dependencyList + } + for _, dep := range dependencies { + id := dep.(map[string]interface{})["rule_id"].(int) + delay := dep.(map[string]interface{})["delay_in_sec"].(int) + dependency := &nextgen.ServiceDep{ + DepId: int64(id), + DelaySecs: int32(delay), + } + dependencyList = append(dependencyList, *dependency) + } + return dependencyList +} + +func getRoutingConfigurations(d *schema.ResourceData) (*nextgen.HttpProxy, *nextgen.TcpProxy, *nextgen.HealthCheck) { + var httpProxy *nextgen.HttpProxy + var tcpProxy *nextgen.TcpProxy + var healthCheck *nextgen.HealthCheck + if attr, ok := d.GetOk("http"); ok { + httpProxy = &nextgen.HttpProxy{} + httpRoutingObj := attr.([]interface{})[0].(map[string]interface{}) + + if attr, ok := httpRoutingObj["proxy_id"]; ok { + proxy := &nextgen.Proxy{ + Id: attr.(string), + } + httpProxy.Proxy = proxy + } + if attr, ok := httpRoutingObj["routing"]; ok { + routingConfigs := attr.([]interface{}) + portConfigsList := make([]nextgen.PortConfig, 0) + for _, routingConfig := range routingConfigs { + routingObj := routingConfig.(map[string]interface{}) + portConfig := &nextgen.PortConfig{} + if attr, ok := routingObj["source_protocol"]; ok { + portConfig.Protocol = attr.(string) + } + if attr, ok := routingObj["target_protocol"]; ok { + portConfig.TargetProtocol = attr.(string) + } + if attr, ok := routingObj["source_port"]; ok { + portConfig.Port = attr.(int) + } + if attr, ok := routingObj["target_port"]; ok { + portConfig.TargetPort = attr.(int) + } + if attr, ok := routingObj["action"]; ok { + portConfig.Action = attr.(string) + } + portConfig.RoutingRules = []nextgen.RoutingRule{} + + portConfigsList = append(portConfigsList, *portConfig) + } + httpProxy.Ports = portConfigsList + } + if attr, ok := httpRoutingObj["health"]; ok { + healthCheck = &nextgen.HealthCheck{} + healthConfig := attr.([]interface{})[0].(map[string]interface{}) + if attr, ok := healthConfig["protocol"]; ok { + healthCheck.Protocol = attr.(string) + } + if attr, ok := healthConfig["port"]; ok { + healthCheck.Port = attr.(int) + } + if attr, ok := healthConfig["path"]; ok { + healthCheck.Path = attr.(string) + } + if attr, ok := healthConfig["timeout"]; ok { + healthCheck.Timeout = attr.(int) + } + if attr, ok := healthConfig["status_code_from"]; ok { + healthCheck.StatusCodeFrom = attr.(int) + } + if attr, ok := healthConfig["status_code_to"]; ok { + healthCheck.StatusCodeTo = attr.(int) + } + } + } + + if attr, ok := d.GetOk("tcp"); ok { + tcpProxy = &nextgen.TcpProxy{} + tcpRoutingObj := attr.([]interface{})[0].(map[string]interface{}) + + if attr, ok := tcpRoutingObj["proxy_id"]; ok { + proxy := &nextgen.Proxy{ + Id: attr.(string), + } + tcpProxy.Proxy = proxy + } + if attr, ok := tcpRoutingObj["ssh"]; ok { + if valArr, ok := attr.([]interface{}); ok && len(valArr) > 0 { + sshConfig := valArr[0].(map[string]interface{}) + ssh := &nextgen.ServiceRoutingTcpPort{} + if attr, ok := sshConfig["connect_on"]; ok { + ssh.Source = attr.(int) + } + ssh.Target = 22 + if attr, ok := sshConfig["port"]; ok { + ssh.Target = attr.(int) + } + tcpProxy.SshConf = ssh + } + } + if attr, ok := tcpRoutingObj["rdp"]; ok { + if valArr, ok := attr.([]interface{}); ok && len(valArr) > 0 { + rdpConfig := valArr[0].(map[string]interface{}) + rdp := &nextgen.ServiceRoutingTcpPort{} + if attr, ok := rdpConfig["connect_on"]; ok { + rdp.Source = attr.(int) + } + rdp.Target = 3389 + if attr, ok := rdpConfig["port"]; ok { + rdp.Target = attr.(int) + } + tcpProxy.RdpConf = rdp + } + } + if attr, ok := tcpRoutingObj["forward_rule"]; ok { + forwardRules := attr.([]interface{}) + tcpPortList := make([]nextgen.ServiceRoutingTcpPort, 0) + for _, forwardRule := range forwardRules { + rule := forwardRule.(map[string]interface{}) + tcpPort := &nextgen.ServiceRoutingTcpPort{} + if attr, ok := rule["connect_on"]; ok { + tcpPort.Source = attr.(int) + } + if attr, ok := rule["port"]; ok { + tcpPort.Target = attr.(int) + } + tcpPortList = append(tcpPortList, *tcpPort) + } + tcpProxy.CustomPorts = tcpPortList + } + } + + return httpProxy, tcpProxy, healthCheck +} + +func readASRule(d *schema.ResourceData, id int64) { + identifier := strconv.Itoa(int(id)) + d.SetId(identifier) + d.Set("identifier", identifier) +} diff --git a/internal/service/platform/autostopping/rule/as_vm.go b/internal/service/platform/autostopping/rule/as_vm.go new file mode 100644 index 000000000..32fb71772 --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_vm.go @@ -0,0 +1,298 @@ +package as_rule + +import ( + "context" + + "github.com/harness/terraform-provider-harness/helpers" + "github.com/harness/terraform-provider-harness/internal" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func ResourceVMRule() *schema.Resource { + resource := &schema.Resource{ + Description: "Resource for creating a Harness Variables.", + + ReadContext: resourceASRuleRead, + UpdateContext: resourceVMRuleCreateOrUpdate, + DeleteContext: resourceASRuleDelete, + CreateContext: resourceVMRuleCreateOrUpdate, + Importer: helpers.MultiLevelResourceImporter, + Schema: map[string]*schema.Schema{ + "identifier": { + Description: "Unique identifier of the resource", + Type: schema.TypeFloat, + Computed: true, + }, + "name": { + Description: "Name of the rule", + Type: schema.TypeString, + Required: true, + }, + "cloud_connector_id": { + Description: "Id of the cloud connector", + Type: schema.TypeString, + Required: true, + }, + "idle_time_mins": { + Description: "Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances.", + Type: schema.TypeInt, + Optional: true, + Default: 15, + }, + "use_spot": { + Description: "Boolean that indicates whether the selected instances should be converted to spot vm", + Type: schema.TypeBool, + Default: false, + Optional: true, + }, + "custom_domains": { + Description: "Custom URLs used to access the instances", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "filter": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "vm_ids": { + Description: "Ids of instances that needs to be managed using the AutoStopping rules", + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "tags": { + Description: "Tags of instances that needs to be managed using the AutoStopping rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "regions": { + Description: "Regions of instances that needs to be managed using the AutoStopping rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "zones": { + Description: "Zones of instances that needs to be managed using the AutoStopping rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "http": { + Description: "Http routing configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "proxy_id": { + Description: "Id of the proxy", + Type: schema.TypeString, + Required: true, + }, + "routing": { + Description: "Routing configuration used to access the instances", + Type: schema.TypeList, + MinItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_protocol": { + Description: "Source protocol of the proxy can be http or https", + Type: schema.TypeString, + Required: true, + }, + "target_protocol": { + Description: "Target protocol of the instance can be http or https", + Type: schema.TypeString, + Required: true, + }, + "source_port": { + Description: "Port on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "target_port": { + Description: "Port on the VM", + Type: schema.TypeInt, + Optional: true, + }, + "action": { + Description: "Organization Identifier for the Entity", + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "health": { + Description: "Health Check Details", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "protocol": { + Description: "Protocol can be http or https", + Type: schema.TypeString, + Required: true, + }, + "port": { + Description: "Health check port on the VM", + Type: schema.TypeInt, + Required: true, + }, + "path": { + Description: "API path to use for health check", + Type: schema.TypeString, + Optional: true, + }, + "timeout": { + Description: "Health check timeout", + Type: schema.TypeInt, + Optional: true, + }, + "status_code_from": { + Description: "Lower limit for acceptable status code", + Type: schema.TypeInt, + Optional: true, + }, + "status_code_to": { + Description: "Upper limit for acceptable status code", + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "tcp": { + Description: "TCP routing configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "proxy_id": { + Description: "Id of the Proxy", + Type: schema.TypeString, + Required: true, + }, + "ssh": { + Description: "SSH configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connect_on": { + Description: "Port to listen on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "port": { + Description: "Port to listen on the vm", + Type: schema.TypeInt, + Optional: true, + Default: 22, + }, + }, + }, + }, + "rdp": { + Description: "RDP configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connect_on": { + Description: "Port to listen on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "port": { + Description: "Port to listen on the vm", + Type: schema.TypeInt, + Optional: true, + Default: 3389, + }, + }, + }, + }, + "forward_rule": { + Description: "Additional tcp forwarding rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connect_on": { + Description: "Port to listen on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "port": { + Description: "Port to listen on the vm", + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "depends": { + Description: "Dependent rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Description: "Rule id of the dependent rule", + Type: schema.TypeInt, + Required: true, + }, + "delay_in_sec": { + Description: "Number of seconds the rule should wait after warming up the dependent rule", + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + }, + }, + }, + }, + } + + return resource +} + +func resourceVMRuleCreateOrUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + c, ctx := meta.(*internal.Session).GetPlatformClientWithContext(ctx) + saveServiceRequestV2 := buildASRule(d, Instance, c.AccountId) + return resourceASRuleCreateOrUpdate(ctx, d, meta, saveServiceRequestV2) +} diff --git a/internal/service/platform/autostopping/rule/as_vm_data_source.go b/internal/service/platform/autostopping/rule/as_vm_data_source.go new file mode 100644 index 000000000..146773894 --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_vm_data_source.go @@ -0,0 +1,284 @@ +package as_rule + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func DataSourceVMRule() *schema.Resource { + resource := &schema.Resource{ + Description: "Data source for retrieving a Harness Variable.", + + ReadContext: resourceASRuleRead, + + Schema: map[string]*schema.Schema{ + "identifier": { + Description: "Unique identifier of the resource", + Type: schema.TypeFloat, + Computed: true, + }, + "name": { + Description: "Name of the rule", + Type: schema.TypeString, + Required: true, + }, + "cloud_connector_id": { + Description: "Id of the cloud connector", + Type: schema.TypeString, + Required: true, + }, + "idle_time_mins": { + Description: "Idle time in minutes. This is the time that the AutoStopping rule waits before stopping the idle instances.", + Type: schema.TypeInt, + Optional: true, + Default: 15, + }, + "use_spot": { + Description: "Boolean that indicates whether the selected instances should be converted to spot vm", + Type: schema.TypeBool, + Default: false, + Optional: true, + }, + "custom_domains": { + Description: "Custom URLs used to access the instances", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "filter": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "vm_ids": { + Description: "Ids of instances that needs to be managed using the AutoStopping rules", + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "tags": { + Description: "Tags of instances that needs to be managed using the AutoStopping rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "regions": { + Description: "Regions of instances that needs to be managed using the AutoStopping rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + "zones": { + Description: "Zones of instances that needs to be managed using the AutoStopping rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + }, + }, + "http": { + Description: "Http routing configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "proxy_id": { + Description: "Id of the proxy", + Type: schema.TypeString, + Required: true, + }, + "routing": { + Description: "Routing configuration used to access the instances", + Type: schema.TypeList, + MinItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "source_protocol": { + Description: "Source protocol of the proxy can be http or https", + Type: schema.TypeString, + Required: true, + }, + "target_protocol": { + Description: "Target protocol of the instance can be http or https", + Type: schema.TypeString, + Required: true, + }, + "source_port": { + Description: "Port on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "target_port": { + Description: "Port on the VM", + Type: schema.TypeInt, + Optional: true, + }, + "action": { + Description: "Organization Identifier for the Entity", + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "health": { + Description: "Health Check Details", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "protocol": { + Description: "Protocol can be http or https", + Type: schema.TypeString, + Required: true, + }, + "port": { + Description: "Health check port on the VM", + Type: schema.TypeInt, + Required: true, + }, + "path": { + Description: "API path to use for health check", + Type: schema.TypeString, + Optional: true, + }, + "timeout": { + Description: "Health check timeout", + Type: schema.TypeInt, + Optional: true, + }, + "status_code_from": { + Description: "Lower limit for acceptable status code", + Type: schema.TypeInt, + Optional: true, + }, + "status_code_to": { + Description: "Upper limit for acceptable status code", + Type: schema.TypeInt, + Optional: true, + }, + }, + }, + }, + }, + }, + }, + "tcp": { + Description: "TCP routing configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "proxy_id": { + Description: "Id of the Proxy", + Type: schema.TypeString, + Required: true, + }, + "ssh": { + Description: "SSH configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connect_on": { + Description: "Port to listen on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "port": { + Description: "Port to listen on the vm", + Type: schema.TypeInt, + Optional: true, + Default: 22, + }, + }, + }, + }, + "rdp": { + Description: "RDP configuration", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connect_on": { + Description: "Port to listen on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "port": { + Description: "Port to listen on the vm", + Type: schema.TypeInt, + Optional: true, + Default: 3389, + }, + }, + }, + }, + "forward_rule": { + Description: "Additional tcp forwarding rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connect_on": { + Description: "Port to listen on the proxy", + Type: schema.TypeInt, + Optional: true, + }, + "port": { + Description: "Port to listen on the vm", + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, + "depends": { + Description: "Dependent rules", + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "rule_id": { + Description: "Rule id of the dependent rule", + Type: schema.TypeInt, + Required: true, + }, + "delay_in_sec": { + Description: "Number of seconds the rule should wait after warming up the dependent rule", + Type: schema.TypeInt, + Optional: true, + Default: 5, + }, + }, + }, + }, + }, + } + + return resource +} diff --git a/internal/service/platform/autostopping/rule/as_vm_test.go b/internal/service/platform/autostopping/rule/as_vm_test.go new file mode 100644 index 000000000..a33164e25 --- /dev/null +++ b/internal/service/platform/autostopping/rule/as_vm_test.go @@ -0,0 +1,112 @@ +package as_rule_test + +import ( + "fmt" + "strconv" + "testing" + + "github.com/harness/harness-go-sdk/harness/nextgen" + "github.com/harness/terraform-provider-harness/internal/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestResourceVMRule(t *testing.T) { + name := "terraform-rule-test" + resourceName := "harness_autostopping_rule_vm.test" + + resource.UnitTest(t, resource.TestCase{ + PreCheck: func() { acctest.TestAccPreCheck(t) }, + ProviderFactories: acctest.ProviderFactories, + // CheckDestroy: testRuleDestroy(resourceName), + Steps: []resource.TestStep{ + { + Config: testVMRule(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "name", name), + ), + }, + }, + }) +} + +func testRuleDestroy(resourceName string) resource.TestCheckFunc { + return func(state *terraform.State) error { + rule, _ := testGetRule(resourceName, state) + if rule != nil { + return fmt.Errorf("Found vm rule: %d", rule.Id) + } + return nil + } +} + +func testGetRule(resourceName string, state *terraform.State) (*nextgen.Service, error) { + r := acctest.TestAccGetResource(resourceName, state) + c, ctx := acctest.TestAccGetPlatformClientWithContext() + ruleId, err := strconv.ParseFloat(r.Primary.ID, 64) + if err != nil { + return nil, err + } + resp, _, err := c.CloudCostAutoStoppingRulesApi.AutoStoppingRuleDetails(ctx, c.AccountId, ruleId, c.AccountId) + + if err != nil { + return nil, err + } + + return resp.Response.Service, nil +} + +func testVMRule(name string) string { + return fmt.Sprintf(` + resource "harness_autostopping_rule_vm" "test" { + name = "%[1]s" + cloud_connector_id = "Azure_SE" + idle_time_mins = 10 + filter { + vm_ids = ["/subscriptions/subscription_id/resourceGroups/resource_group/providers/Microsoft.Compute/virtualMachines/virtual_machine"] + regions = ["useast2"] + } + http { + proxy_id = "ap-chdpf8f83v0c1aj69oog" + routing { + source_protocol = "https" + target_protocol = "https" + source_port = 443 + target_port = 443 + action = "forward" + } + routing { + source_protocol = "http" + target_protocol = "http" + source_port = 80 + target_port = 80 + action = "forward" + } + health { + protocol = "http" + port = 80 + path = "/" + timeout = 30 + status_code_from = 200 + status_code_to = 299 + } + } + tcp { + proxy_id = "ap-chdpf8f83v0c1aj69oog" + ssh { + port = 22 + } + rdp { + port = 3389 + } + forward_rule { + port = 2233 + } + } + depends { + rule_id = 24576 + delay_in_sec = 5 + } + } +`, name) +}