From 43f2401937e94c7dbef31a4b0c673fbef1c60be9 Mon Sep 17 00:00:00 2001 From: zhukun <2019229048@tju.edu.cn> Date: Mon, 20 Nov 2023 17:17:27 +0800 Subject: [PATCH] feat(apig_signature): import apig_signature resource, unit test and document. --- docs/resources/apig_signature.md | 117 +++++ docs/resources/apig_signature_associate.md | 57 +++ flexibleengine/acceptance/acceptance.go | 1 + ...bleengine_apig_signature_associate_test.go | 319 ++++++++++++++ ...urce_flexibleengine_apig_signature_test.go | 413 ++++++++++++++++++ flexibleengine/provider.go | 3 + 6 files changed, 910 insertions(+) create mode 100644 docs/resources/apig_signature.md create mode 100644 docs/resources/apig_signature_associate.md create mode 100644 flexibleengine/acceptance/resource_flexibleengine_apig_signature_associate_test.go create mode 100644 flexibleengine/acceptance/resource_flexibleengine_apig_signature_test.go diff --git a/docs/resources/apig_signature.md b/docs/resources/apig_signature.md new file mode 100644 index 00000000..04a88824 --- /dev/null +++ b/docs/resources/apig_signature.md @@ -0,0 +1,117 @@ +--- +subcategory: "API Gateway (Dedicated APIG)" +--- + +# flexibleengine_apig_signature + +Manages a signature resource within FlexibleEngine. + +## Example Usage + +### Create a signature of the HMAC type + +```hcl +variable "instance_id" {} +variable "signature_name" {} +variable "signature_key" {} +variable "signature_secret" {} + +resource "flexibleengine_apig_signature" "test" { + instance_id = var.instance_id + name = var.signature_name + type = "hmac" + key = var.signature_key + secret = var.signature_secret +} +``` + +### Create a signature and automatically generate key and secret + +```hcl +variable "instance_id" {} +variable "signature_name" {} + +resource "flexibleengine_apig_signature" "test" { + instance_id = var.instance_id + name = var.signature_name + type = "hmac" +} +``` + +### Create a signature of the AES type + +```hcl +variable "instance_id" {} +variable "signature_name" {} +variable "signature_key" {} +variable "signature_secret" {} + +resource "flexibleengine_apig_signature" "test" { + instance_id = var.instance_id + name = var.signature_name + type = "aes" + algorithm = "aes-128-cfb" + key = var.signature_key + secret = var.signature_secret +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) Specifies the region where the signature is located. + If omitted, the provider-level region will be used. + Changing this will create a new resource. + +* `instance_id` - (Required, String, ForceNew) Specifies the ID of the dedicated instance to which the signature + belongs. + Changing this will create a new resource. + +* `name` - (Required, String) Specifies the signature name. + The valid length is limited from `3` to `64`, only English letters, Chinese characters, digits and underscores (_) are + allowed. The name must start with an English letter or Chinese character. + +* `type` - (Required, String) Specifies the type of signature. + The valid values are as follows: + + **basic**: Basic auth type. + + **hmac**: HMAC type. + + **aes**: AES type + +* `key` - (Optional, String) Specifies the signature key. + + For `basic` type: The value contains `4` to `32` characters, including letters, digits, underscores (_) and + hyphens (-). It must start with a letter. + + For `hmac` type: The value contains `8` to `32` characters, including letters, digits, underscores (_) and + hyphens (-). It must start with a letter or digit. + + For `aes` type: The value contains `16` characters if the `aes-128-cfb` algorithm is used, or `32` characters if the + `aes-256-cfb` algorithm is used. Only letters, digits, and special characters (`_-!@#$%+/=`) are allowed. + It must start with a letter, digit, plus sign (+), or slash (/). + + If not specified, the key will automatically generated. The auto-generation is only supported on first creation. + +* `secret` - (Optional, String) Specifies the signature secret. + If not specified, the secret will automatically generated. The auto-generation is only supported on first creation. + +* `algorithm` - (Optional, String) Specifies the signature algorithm. + This parameter is required and only available when signature `type` is `aes`. + The valid values are as follows: + + **aes-128-cfb** + + **aes-256-cfb** + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the signature. + +* `created_at` - The creation time of the signature. + +* `updated_at` - The latest update time of the signature. + +## Import + +Signatures can be imported using their `id` and related dedicated instance ID, separated by a slash, e.g. + +```bash +$ terraform import flexibleengine_apig_signature.test / +``` diff --git a/docs/resources/apig_signature_associate.md b/docs/resources/apig_signature_associate.md new file mode 100644 index 00000000..b299e5e6 --- /dev/null +++ b/docs/resources/apig_signature_associate.md @@ -0,0 +1,57 @@ +--- +subcategory: "API Gateway (Dedicated APIG)" +--- + +# flexibleengine_apig_signature_associate + +Use this resource to bind the APIs to the signature within FlexibleEngine. + +-> A signature can only create one `flexibleengine_apig_signature_associate` resource. + And a published ID for API can only bind a signature. + +## Example Usage + +```hcl +variable "instance_id" {} +variable "signature_id" {} +variable "api_publish_ids" { + type = list(string) +} + +resource "flexibleengine_apig_signature_associate" "test" { + instance_id = var.instance_id + signature_id = var.signature_id + publish_ids = var.api_publish_ids +} +``` + +## Argument Reference + +The following arguments are supported: + +* `region` - (Optional, String, ForceNew) Specifies the region where the signature and the APIs are located. + If omitted, the provider-level region will be used. Changing this will create a new resource. + +* `instance_id` - (Required, String, ForceNew) Specifies the ID of the dedicated instance to which the APIs and the + signature belong. + Changing this will create a new resource. + +* `signature_id` - (Required, String, ForceNew) Specifies the signature ID for APIs binding. + Changing this will create a new resource. + +* `publish_ids` - (Required, List) Specifies the publish IDs corresponding to the APIs bound by the signature. + +## Attribute Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - Resource ID. The format is `/`. + +## Import + +Associate resources can be imported using their `signature_id` and the APIG dedicated instance ID to which the signature +belongs, separated by a slash, e.g. + +```bash +$ terraform import flexibleengine_apig_signature_associate.test / +``` diff --git a/flexibleengine/acceptance/acceptance.go b/flexibleengine/acceptance/acceptance.go index 265460d8..db7590fc 100644 --- a/flexibleengine/acceptance/acceptance.go +++ b/flexibleengine/acceptance/acceptance.go @@ -21,6 +21,7 @@ var ( OS_ACCESS_KEY = os.Getenv("OS_ACCESS_KEY") OS_SECRET_KEY = os.Getenv("OS_SECRET_KEY") OS_PROJECT_ID = os.Getenv("OS_PROJECT_ID") + OS_USER_ID = os.Getenv("OS_USER_ID") OS_VPC_ID = os.Getenv("OS_VPC_ID") OS_NETWORK_ID = os.Getenv("OS_NETWORK_ID") diff --git a/flexibleengine/acceptance/resource_flexibleengine_apig_signature_associate_test.go b/flexibleengine/acceptance/resource_flexibleengine_apig_signature_associate_test.go new file mode 100644 index 00000000..b5bd1460 --- /dev/null +++ b/flexibleengine/acceptance/resource_flexibleengine_apig_signature_associate_test.go @@ -0,0 +1,319 @@ +package acceptance + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/chnsz/golangsdk" + "github.com/chnsz/golangsdk/openstack/apigw/dedicated/v2/signs" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" +) + +func getSignatureAssociateFunc(conf *config.Config, state *terraform.ResourceState) (interface{}, error) { + c, err := conf.ApigV2Client(OS_REGION_NAME) + if err != nil { + return nil, fmt.Errorf("error creating APIG v2 client: %s", err) + } + opts := signs.ListBindOpts{ + InstanceId: state.Primary.Attributes["instance_id"], + SignatureId: state.Primary.Attributes["signature_id"], + Limit: 500, + } + resp, err := signs.ListBind(c, opts) + if err != nil { + return nil, err + } + if len(resp) < 1 { + return nil, golangsdk.ErrDefault404{} + } + return resp, nil +} + +func TestAccSignatureAssociate_basic(t *testing.T) { + var ( + apiDetails []signs.SignBindApiInfo + + name = acceptance.RandomAccResourceName() + rName1 = "flexibleengine_apig_signature_associate.basic_bind" + rName2 = "flexibleengine_apig_signature_associate.hmac_bind" + rName3 = "flexibleengine_apig_signature_associate.aes_bind" + + rc1 = acceptance.InitResourceCheck(rName1, &apiDetails, getSignatureAssociateFunc) + rc2 = acceptance.InitResourceCheck(rName2, &apiDetails, getSignatureAssociateFunc) + rc3 = acceptance.InitResourceCheck(rName3, &apiDetails, getSignatureAssociateFunc) + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc1.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccSignatureAssociate_basic_step1(name), + Check: resource.ComposeTestCheckFunc( + rc1.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName1, "instance_id", + "flexibleengine_apig_instance.test", "id"), + resource.TestCheckResourceAttrPair(rName1, "signature_id", + "flexibleengine_apig_signature.basic", "id"), + resource.TestCheckResourceAttr(rName1, "publish_ids.#", "2"), + rc2.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName2, "instance_id", + "flexibleengine_apig_instance.test", "id"), + resource.TestCheckResourceAttrPair(rName2, "signature_id", + "flexibleengine_apig_signature.hmac", "id"), + resource.TestCheckResourceAttr(rName2, "publish_ids.#", "2"), + rc3.CheckResourceExists(), + resource.TestCheckResourceAttrPair(rName3, "instance_id", + "flexibleengine_apig_instance.test", "id"), + resource.TestCheckResourceAttrPair(rName3, "signature_id", + "flexibleengine_apig_signature.aes", "id"), + resource.TestCheckResourceAttr(rName3, "publish_ids.#", "2"), + ), + }, + { + Config: testAccSignatureAssociate_basic_step2(name), + Check: resource.ComposeTestCheckFunc( + rc1.CheckResourceExists(), + resource.TestCheckResourceAttr(rName1, "publish_ids.#", "2"), + rc2.CheckResourceExists(), + resource.TestCheckResourceAttr(rName2, "publish_ids.#", "2"), + rc3.CheckResourceExists(), + resource.TestCheckResourceAttr(rName3, "publish_ids.#", "2"), + ), + }, + { + ResourceName: rName1, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccSignatureAssociateImportStateFunc(rName1), + }, + { + ResourceName: rName2, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccSignatureAssociateImportStateFunc(rName2), + }, + { + ResourceName: rName3, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccSignatureAssociateImportStateFunc(rName3), + }, + }, + }) +} + +func testAccSignatureAssociateImportStateFunc(rName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[rName] + if !ok { + return "", fmt.Errorf("resource (%s) not found: %s", rName, rs) + } + if rs.Primary.Attributes["instance_id"] == "" || rs.Primary.Attributes["signature_id"] == "" { + return "", fmt.Errorf("invalid format specified for import ID, want '/', but got '%s/%s'", + rs.Primary.Attributes["instance_id"], rs.Primary.Attributes["signature_id"]) + } + return fmt.Sprintf("%s/%s", rs.Primary.Attributes["instance_id"], rs.Primary.Attributes["signature_id"]), nil + } +} + +func testAccSignatureAssociate_base(name string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_apig_instance" "test" { + name = "%[2]s" + edition = "BASIC" + vpc_id = flexibleengine_vpc_v1.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + security_group_id = flexibleengine_networking_secgroup_v2.test.id + enterprise_project_id = "0" + + availability_zones = try(slice(data.flexibleengine_availability_zones.test.names, 0, 1), null) +} + +resource "flexibleengine_compute_instance_v2" "test" { + name = "%[2]s" + image_id = data.flexibleengine_images_image_v2.test.id + flavor_id = data.flexibleengine_compute_flavors_v2.test.flavors[0] + availability_zone = data.flexibleengine_availability_zones.test.names[0] + + network { + uuid = flexibleengine_vpc_subnet_v1.test.id + } +} + +resource "flexibleengine_apig_group" "test" { + name = "%[2]s" + instance_id = flexibleengine_apig_instance.test.id +} + +resource "flexibleengine_apig_vpc_channel" "test" { + name = "%[2]s" + instance_id = flexibleengine_apig_instance.test.id + port = 80 + algorithm = "WRR" + protocol = "HTTP" + path = "/" + http_code = "201" + + members { + id = flexibleengine_compute_instance_v2.test.id + } +} + +resource "flexibleengine_apig_api" "test" { + instance_id = flexibleengine_apig_instance.test.id + group_id = flexibleengine_apig_group.test.id + name = "%[2]s" + type = "Public" + request_protocol = "HTTP" + request_method = "GET" + request_path = "/user_info/{user_age}" + security_authentication = "APP" + matching = "Exact" + success_response = "Success response" + failure_response = "Failed response" + description = "Created by script" + + request_params { + name = "user_age" + type = "NUMBER" + location = "PATH" + required = true + maximum = 200 + minimum = 0 + } + + backend_params { + type = "REQUEST" + name = "userAge" + location = "PATH" + value = "user_age" + } + + web { + path = "/getUserAge/{userAge}" + vpc_channel_id = flexibleengine_apig_vpc_channel.test.id + request_method = "GET" + request_protocol = "HTTP" + timeout = 30000 + } + + web_policy { + name = "%[2]s_policy1" + request_protocol = "HTTP" + request_method = "GET" + effective_mode = "ANY" + path = "/getUserAge/{userAge}" + timeout = 30000 + vpc_channel_id = flexibleengine_apig_vpc_channel.test.id + + backend_params { + type = "REQUEST" + name = "userAge" + location = "PATH" + value = "user_age" + } + + conditions { + source = "param" + param_name = "user_age" + type = "Equal" + value = "28" + } + } +} + +resource "flexibleengine_apig_environment" "test" { + count = 6 + + name = "%[2]s_${count.index}" + instance_id = flexibleengine_apig_instance.test.id +} + +resource "flexibleengine_apig_api_publishment" "test" { + count = 6 + + instance_id = flexibleengine_apig_instance.test.id + api_id = flexibleengine_apig_api.test.id + env_id = flexibleengine_apig_environment.test[count.index].id +} + +resource "flexibleengine_apig_signature" "basic" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_basic" + type = "basic" +} + +resource "flexibleengine_apig_signature" "hmac" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_hmac" + type = "hmac" +} + +resource "flexibleengine_apig_signature" "aes" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_aes" + type = "aes" + algorithm = "aes-128-cfb" +} +`, testBaseComputeResources(name), name) +} + +func testAccSignatureAssociate_basic_step1(name string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_apig_signature_associate" "basic_bind" { + instance_id = flexibleengine_apig_instance.test.id + signature_id = flexibleengine_apig_signature.basic.id + publish_ids = slice(flexibleengine_apig_api_publishment.test[*].publish_id, 0, 2) +} + +resource "flexibleengine_apig_signature_associate" "hmac_bind" { + instance_id = flexibleengine_apig_instance.test.id + signature_id = flexibleengine_apig_signature.hmac.id + publish_ids = slice(flexibleengine_apig_api_publishment.test[*].publish_id, 2, 4) +} + +resource "flexibleengine_apig_signature_associate" "aes_bind" { + instance_id = flexibleengine_apig_instance.test.id + signature_id = flexibleengine_apig_signature.aes.id + publish_ids = slice(flexibleengine_apig_api_publishment.test[*].publish_id, 4, 6) +} +`, testAccSignatureAssociate_base(name)) +} + +func testAccSignatureAssociate_basic_step2(name string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_apig_signature_associate" "basic_bind" { + instance_id = flexibleengine_apig_instance.test.id + signature_id = flexibleengine_apig_signature.basic.id + publish_ids = slice(flexibleengine_apig_api_publishment.test[*].publish_id, 1, 3) +} + +resource "flexibleengine_apig_signature_associate" "hmac_bind" { + instance_id = flexibleengine_apig_instance.test.id + signature_id = flexibleengine_apig_signature.hmac.id + publish_ids = slice(flexibleengine_apig_api_publishment.test[*].publish_id, 3, 5) +} + +resource "flexibleengine_apig_signature_associate" "aes_bind" { + instance_id = flexibleengine_apig_instance.test.id + signature_id = flexibleengine_apig_signature.aes.id + publish_ids = setunion(slice(flexibleengine_apig_api_publishment.test[*].publish_id, 0, 1), + slice(flexibleengine_apig_api_publishment.test[*].publish_id, 5, 6)) +} +`, testAccSignatureAssociate_base(name)) +} diff --git a/flexibleengine/acceptance/resource_flexibleengine_apig_signature_test.go b/flexibleengine/acceptance/resource_flexibleengine_apig_signature_test.go new file mode 100644 index 00000000..b4f40a20 --- /dev/null +++ b/flexibleengine/acceptance/resource_flexibleengine_apig_signature_test.go @@ -0,0 +1,413 @@ +package acceptance + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + + "github.com/chnsz/golangsdk" + "github.com/chnsz/golangsdk/openstack/apigw/dedicated/v2/signs" + + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/config" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/services/acceptance" + "github.com/huaweicloud/terraform-provider-huaweicloud/huaweicloud/utils" +) + +func getSignatureFunc(cfg *config.Config, state *terraform.ResourceState) (interface{}, error) { + client, err := cfg.ApigV2Client(OS_REGION_NAME) + if err != nil { + return nil, fmt.Errorf("error creating APIG v2 client: %s", err) + } + opts := signs.ListOpts{ + InstanceId: state.Primary.Attributes["instance_id"], + ID: state.Primary.ID, + } + resp, err := signs.List(client, opts) + if err != nil { + return nil, err + } + if len(resp) < 1 { + return nil, golangsdk.ErrDefault404{} + } + return resp[0], nil +} + +func TestAccSignature_basic(t *testing.T) { + var ( + signature signs.Signature + + rName1 = "flexibleengine_apig_signature.with_key" + rName2 = "flexibleengine_apig_signature.without_key" + name = acceptance.RandomAccResourceName() + + // lintignore:AT009 + signKey = acctest.RandStringFromCharSet(16, acctest.CharSetAlphaNum) + revSignKey = utils.Reverse(signKey) + // lintignore:AT009 + signSecret = acctest.RandStringFromCharSet(16, acctest.CharSetAlphaNum) + revSignSecret = utils.Reverse(signSecret) + + rc1 = acceptance.InitResourceCheck(rName1, &signature, getSignatureFunc) + rc2 = acceptance.InitResourceCheck(rName2, &signature, getSignatureFunc) + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc1.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccSignature_basic_step1(name, signKey, signSecret), + Check: resource.ComposeTestCheckFunc( + rc1.CheckResourceExists(), + resource.TestCheckResourceAttr(rName1, "name", name+"_with_key"), + resource.TestCheckResourceAttr(rName1, "type", "basic"), + resource.TestCheckResourceAttr(rName1, "key", signKey), + resource.TestCheckResourceAttr(rName1, "secret", signSecret), + rc2.CheckResourceExists(), + resource.TestCheckResourceAttr(rName2, "name", name+"_without_key"), + resource.TestCheckResourceAttr(rName2, "type", "basic"), + resource.TestCheckResourceAttrSet(rName2, "key"), + resource.TestCheckResourceAttrSet(rName2, "secret"), + ), + }, + { + Config: testAccSignature_basic_step2(name, revSignKey, revSignSecret), + Check: resource.ComposeTestCheckFunc( + rc1.CheckResourceExists(), + resource.TestCheckResourceAttr(rName1, "name", name+"_with_key_update"), + resource.TestCheckResourceAttr(rName1, "key", revSignKey), + resource.TestCheckResourceAttr(rName1, "secret", revSignSecret), + rc2.CheckResourceExists(), + resource.TestCheckResourceAttr(rName2, "name", name+"_without_key_update"), + resource.TestCheckResourceAttr(rName2, "key", revSignKey), + resource.TestCheckResourceAttr(rName2, "secret", revSignSecret), + ), + }, + { + ResourceName: rName1, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccSignatureImportStateFunc(rName1), + }, + { + ResourceName: rName2, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccSignatureImportStateFunc(rName2), + }, + }, + }) +} + +func testAccSignatureImportStateFunc(rName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[rName] + if !ok { + return "", fmt.Errorf("resource (%s) not found: %s", rName, rs) + } + if rs.Primary.Attributes["instance_id"] == "" { + return "", fmt.Errorf("invalid format specified for import ID, want '/', but got '%s/%s'", + rs.Primary.Attributes["instance_id"], rs.Primary.ID) + } + return fmt.Sprintf("%s/%s", rs.Primary.Attributes["instance_id"], rs.Primary.ID), nil + } +} + +func testAccSignature_base(name string) string { + return fmt.Sprintf(` +%[1]s + +data "flexibleengine_availability_zones" "test" {} + +resource "flexibleengine_apig_instance" "test" { + name = "%[2]s" + edition = "BASIC" + vpc_id = flexibleengine_vpc_v1.test.id + subnet_id = flexibleengine_vpc_subnet_v1.test.id + security_group_id = flexibleengine_networking_secgroup_v2.test.id + enterprise_project_id = "0" + + availability_zones = [ + data.flexibleengine_availability_zones.test.names[0], + ] +} +`, testBaseNetwork(name), name) +} + +func testAccSignature_basic_step1(name, signKey, signSecret string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_apig_signature" "with_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_with_key" + type = "basic" + key = "%[3]s" + secret = "%[4]s" +} + +resource "flexibleengine_apig_signature" "without_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_without_key" + type = "basic" +} +`, testAccSignature_base(name), name, signKey, signSecret) +} + +func testAccSignature_basic_step2(name, signKey, signSecret string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_apig_signature" "with_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_with_key_update" + type = "basic" + key = "%[3]s" + secret = "%[4]s" +} + +resource "flexibleengine_apig_signature" "without_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_without_key_update" + type = "basic" + key = "%[3]s" + secret = "%[4]s" +} +`, testAccSignature_base(name), name, signKey, signSecret) +} + +func TestAccSignature_hmac(t *testing.T) { + var ( + signature signs.Signature + + rName1 = "flexibleengine_apig_signature.with_key" + rName2 = "flexibleengine_apig_signature.without_key" + name = acceptance.RandomAccResourceName() + + // lintignore:AT009 + signKey = acctest.RandStringFromCharSet(16, acctest.CharSetAlphaNum) + revSignKey = utils.Reverse(signKey) + // lintignore:AT009 + signSecret = acctest.RandStringFromCharSet(16, acctest.CharSetAlphaNum) + revSignSecret = utils.Reverse(signSecret) + + rc1 = acceptance.InitResourceCheck(rName1, &signature, getSignatureFunc) + rc2 = acceptance.InitResourceCheck(rName2, &signature, getSignatureFunc) + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc1.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccSignature_hmac_step1(name, signKey, signSecret), + Check: resource.ComposeTestCheckFunc( + rc1.CheckResourceExists(), + resource.TestCheckResourceAttr(rName1, "name", name+"_with_key"), + resource.TestCheckResourceAttr(rName1, "type", "hmac"), + resource.TestCheckResourceAttr(rName1, "key", signKey), + resource.TestCheckResourceAttr(rName1, "secret", signSecret), + rc2.CheckResourceExists(), + resource.TestCheckResourceAttr(rName2, "name", name+"_without_key"), + resource.TestCheckResourceAttr(rName2, "type", "hmac"), + resource.TestCheckResourceAttrSet(rName2, "key"), + resource.TestCheckResourceAttrSet(rName2, "secret"), + ), + }, + { + Config: testAccSignature_hmac_step2(name, revSignKey, revSignSecret), + Check: resource.ComposeTestCheckFunc( + rc1.CheckResourceExists(), + resource.TestCheckResourceAttr(rName1, "name", name+"_with_key_update"), + resource.TestCheckResourceAttr(rName1, "key", revSignKey), + resource.TestCheckResourceAttr(rName1, "secret", revSignSecret), + rc2.CheckResourceExists(), + resource.TestCheckResourceAttr(rName2, "name", name+"_without_key_update"), + resource.TestCheckResourceAttr(rName2, "key", revSignKey), + resource.TestCheckResourceAttr(rName2, "secret", revSignSecret), + ), + }, + { + ResourceName: rName1, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccSignatureImportStateFunc(rName1), + }, + { + ResourceName: rName2, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccSignatureImportStateFunc(rName2), + }, + }, + }) +} + +func testAccSignature_hmac_step1(name, signKey, signSecret string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_apig_signature" "with_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_with_key" + type = "hmac" + key = "%[3]s" + secret = "%[4]s" +} + +resource "flexibleengine_apig_signature" "without_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_without_key" + type = "hmac" +} +`, testAccSignature_base(name), name, signKey, signSecret) +} + +func testAccSignature_hmac_step2(name, signKey, signSecret string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_apig_signature" "with_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_with_key_update" + type = "hmac" + key = "%[3]s" + secret = "%[4]s" +} + +resource "flexibleengine_apig_signature" "without_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_without_key_update" + type = "hmac" + key = "%[3]s" + secret = "%[4]s" +} +`, testAccSignature_base(name), name, signKey, signSecret) +} + +func TestAccSignature_aes(t *testing.T) { + var ( + signature signs.Signature + + rName1 = "flexibleengine_apig_signature.with_key" + rName2 = "flexibleengine_apig_signature.without_key" + name = acceptance.RandomAccResourceName() + + // lintignore:AT009 + signKey = acctest.RandStringFromCharSet(16, acctest.CharSetAlphaNum) + revSignKey = utils.Reverse(signKey) + // lintignore:AT009 + signSecret = acctest.RandStringFromCharSet(16, acctest.CharSetAlphaNum) + revSignSecret = utils.Reverse(signSecret) + + rc1 = acceptance.InitResourceCheck(rName1, &signature, getSignatureFunc) + rc2 = acceptance.InitResourceCheck(rName2, &signature, getSignatureFunc) + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + }, + ProviderFactories: TestAccProviderFactories, + CheckDestroy: rc1.CheckResourceDestroy(), + Steps: []resource.TestStep{ + { + Config: testAccSignature_aes_step1(name, signKey, signSecret), + Check: resource.ComposeTestCheckFunc( + rc1.CheckResourceExists(), + resource.TestCheckResourceAttr(rName1, "name", name+"_with_key"), + resource.TestCheckResourceAttr(rName1, "type", "aes"), + resource.TestCheckResourceAttr(rName1, "algorithm", "aes-128-cfb"), + resource.TestCheckResourceAttr(rName1, "key", signKey), + resource.TestCheckResourceAttr(rName1, "secret", signSecret), + rc2.CheckResourceExists(), + resource.TestCheckResourceAttr(rName2, "name", name+"_without_key"), + resource.TestCheckResourceAttr(rName2, "type", "aes"), + resource.TestCheckResourceAttrSet(rName2, "key"), + resource.TestCheckResourceAttrSet(rName2, "secret"), + ), + }, + { + Config: testAccSignature_aes_step2(name, revSignKey, revSignSecret), + Check: resource.ComposeTestCheckFunc( + rc1.CheckResourceExists(), + resource.TestCheckResourceAttr(rName1, "name", name+"_with_key_update"), + resource.TestCheckResourceAttr(rName1, "key", revSignKey), + resource.TestCheckResourceAttr(rName1, "secret", revSignSecret), + rc2.CheckResourceExists(), + resource.TestCheckResourceAttr(rName2, "name", name+"_without_key_update"), + resource.TestCheckResourceAttr(rName2, "key", revSignKey+signKey), + resource.TestCheckResourceAttr(rName2, "secret", revSignSecret), + ), + }, + { + ResourceName: rName1, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccSignatureImportStateFunc(rName1), + }, + { + ResourceName: rName2, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccSignatureImportStateFunc(rName2), + }, + }, + }) +} + +func testAccSignature_aes_step1(name, signKey, signSecret string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_apig_signature" "with_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_with_key" + type = "aes" + algorithm = "aes-128-cfb" + key = "%[3]s" + secret = "%[4]s" +} + +resource "flexibleengine_apig_signature" "without_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_without_key" + type = "aes" + algorithm = "aes-256-cfb" +} +`, testAccSignature_base(name), name, signKey, signSecret) +} + +// The length of the signature key and signature secret are both 16. +func testAccSignature_aes_step2(name, signKey, signSecret string) string { + return fmt.Sprintf(` +%[1]s + +resource "flexibleengine_apig_signature" "with_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_with_key_update" + type = "aes" + algorithm = "aes-128-cfb" + key = "%[3]s" + secret = "%[4]s" +} + +resource "flexibleengine_apig_signature" "without_key" { + instance_id = flexibleengine_apig_instance.test.id + name = "%[2]s_without_key_update" + type = "aes" + algorithm = "aes-256-cfb" + key = format("%%s%%s", "%[3]s", strrev("%[3]s")) # the length of the 256 signature key is 32. + secret = "%[4]s" +} +`, testAccSignature_base(name), name, signKey, signSecret) +} diff --git a/flexibleengine/provider.go b/flexibleengine/provider.go index 92d9261d..baefdda2 100644 --- a/flexibleengine/provider.go +++ b/flexibleengine/provider.go @@ -465,7 +465,10 @@ func Provider() *schema.Provider { "flexibleengine_apig_custom_authorizer": apig.ResourceApigCustomAuthorizerV2(), "flexibleengine_apig_environment": apig.ResourceApigEnvironmentV2(), "flexibleengine_apig_group": apig.ResourceApigGroupV2(), + "flexibleengine_apig_plugin": apig.ResourcePlugin(), "flexibleengine_apig_response": apig.ResourceApigResponseV2(), + "flexibleengine_apig_signature": apig.ResourceSignature(), + "flexibleengine_apig_signature_associate": apig.ResourceSignatureAssociate(), "flexibleengine_apig_throttling_policy_associate": apig.ResourceThrottlingPolicyAssociate(), "flexibleengine_apig_throttling_policy": apig.ResourceApigThrottlingPolicyV2(),