diff --git a/examples/complete/main.tf b/examples/complete/main.tf index a4efc58b..f4e7912f 100644 --- a/examples/complete/main.tf +++ b/examples/complete/main.tf @@ -45,21 +45,21 @@ module "vpc" { prefix = var.prefix name = "vpc" tags = var.resource_tags + network_acls = var.vpc_network_acls } ############################################################################## # Security group ############################################################################## -resource "ibm_is_security_group" "sg1" { - name = "${var.prefix}-sg1" - vpc = module.vpc.vpc_id -} - -# wait 30 secs after security group is destroyed before destroying VPE to workaround race condition -resource "time_sleep" "wait_30_seconds" { - depends_on = [ibm_is_security_group.sg1] - destroy_duration = "30s" +module "create_sgr_rule_pg" { + source = "terraform-ibm-modules/security-group/ibm" + version = "v2.0.0" + add_ibm_cloud_internal_rules = false + security_group_name = "${var.prefix}-security-group-pg" + resource_group = module.resource_group.resource_group_id + vpc_id = module.vpc.vpc_id + target_ids = [for crn in module.vpe.crn : element(split(":", crn), length(split(":", crn)) - 1)] } ############################################################################## @@ -139,12 +139,10 @@ module "vpe" { crn = module.postgresql_db.crn }, ] - vpc_id = module.vpc.vpc_id - subnet_zone_list = module.vpc.subnet_zone_list - resource_group_id = module.resource_group.resource_group_id - security_group_ids = [ibm_is_security_group.sg1.id] + vpc_id = module.vpc.vpc_id + subnet_zone_list = module.vpc.subnet_zone_list + resource_group_id = module.resource_group.resource_group_id depends_on = [ - time_sleep.wait_120_seconds, - time_sleep.wait_30_seconds + time_sleep.wait_120_seconds ] } diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf index 3383a7e2..3f168731 100644 --- a/examples/complete/outputs.tf +++ b/examples/complete/outputs.tf @@ -42,3 +42,18 @@ output "port" { description = "Postgresql instance port" value = module.postgresql_db.port } + +output "vpc_id" { + description = "ID of VPC created" + value = module.vpc.vpc_id +} + +output "subnet_ids" { + description = "list of subnet IDs" + value = module.vpc.subnet_ids +} + +output "resource_group_id" { + description = "ID of resource_group created" + value = module.resource_group.resource_group_id +} diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf index a39af312..84af6dd5 100644 --- a/examples/complete/variables.tf +++ b/examples/complete/variables.tf @@ -69,3 +69,56 @@ variable "service_credential_names" { "postgressql_editor" : "Editor", } } + + +variable "vpc_network_acls" { + description = "The list of ACLs to create. Provide at least one rule for each ACL." + type = list( + object({ + name = string + add_ibm_cloud_internal_rules = optional(bool) + add_vpc_connectivity_rules = optional(bool) + prepend_ibm_rules = optional(bool) + rules = list( + object({ + name = string + action = string + destination = string + direction = string + source = string + tcp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + source_port_max = optional(number) + source_port_min = optional(number) + }) + ) + udp = optional( + object({ + port_max = optional(number) + port_min = optional(number) + source_port_max = optional(number) + source_port_min = optional(number) + }) + ) + icmp = optional( + object({ + type = optional(number) + code = optional(number) + }) + ) + }) + ) + }) + ) + default = [ + { + name = "vpc-acl" + add_ibm_cloud_internal_rules = true + add_vpc_connectivity_rules = true + prepend_ibm_rules = true + rules = [] + } + ] +} diff --git a/tests/pr_test.go b/tests/pr_test.go index 813729bf..53c6b539 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -72,6 +72,76 @@ func TestRunFSCloudExample(t *testing.T) { options.TestTearDown() } +func TestRunDBConnectivity(t *testing.T) { + t.Parallel() + + prefix := "postgres-db-connectivity" + options_postgres := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ + Testing: t, + TerraformDir: "examples/complete", + Prefix: prefix, + Region: "us-south", + ResourceGroup: resourceGroup, + TerraformVars: map[string]interface{}{ + "vpc_network_acls": `[{ + name = "vpc-acl" + add_ibm_cloud_internal_rules = true + add_vpc_connectivity_rules = true + prepend_ibm_rules = true + rules = [ + { + name = "allow-all-inbound" + action = "allow" + direction = "inbound" + destination = "10.10.10.64/32" + source = "0.0.0.0/0" + }, + { + name = "allow-all-outbound" + action = "allow" + direction = "outbound" + destination = "0.0.0.0/0" + source = "10.10.10.64/32" + } + ] + }]`, + }, + }) + options_postgres.SkipTestTearDown = true + output_postgres, err_postgres := options_postgres.RunTest() + assert.Nil(t, err_postgres, "This should not have errored") + assert.NotNil(t, output_postgres, "Expected some output") + + outputs := terraform.OutputAll(options_postgres.Testing, options_postgres.TerraformOptions) + + var serviceCredential interface{} + for _, data := range outputs["service_credentials_json"].(map[string]interface{}) { + serviceCredential = data.(string) + break + } + assert.NotNil(t, serviceCredential, "Unable to access service credentials") + + options_vsi := testhelper.TestOptionsDefault(&testhelper.TestOptions{ + Testing: t, + TerraformDir: "tests/resources", + Prefix: prefix, + Region: "us-south", + TerraformVars: map[string]interface{}{ + "resource_group_id": outputs["resource_group_id"], + "service_credential": serviceCredential, + "vpc_id": outputs["vpc_id"], + "subnet_ids": outputs["subnet_ids"], + "vsi_reserved_ip": "10.10.10.64", + }, + }) + output_vsi, err_vsi := options_vsi.RunTestConsistency() + options_postgres.TestTearDown() + assert.Nil(t, err_vsi, "This should not have errored") + assert.NotNil(t, output_vsi, "Expected some output") + +} + + func TestRunUpgradeCompleteExample(t *testing.T) { t.Parallel() diff --git a/tests/resources/main.tf b/tests/resources/main.tf new file mode 100644 index 00000000..8d45cd6d --- /dev/null +++ b/tests/resources/main.tf @@ -0,0 +1,135 @@ + +module "create_sgr_rule_vsi" { + source = "terraform-ibm-modules/security-group/ibm" + version = "v2.0.0" + add_ibm_cloud_internal_rules = false + security_group_name = "${var.prefix}-security-group-vsi" + resource_group = var.resource_group_id + vpc_id = var.vpc_id + security_group_rules = [{ + name = "allow-ssh-inbound" + direction = "inbound" + remote = "0.0.0.0/0" + tcp = { + port_min = 22 + port_max = 22 + } + }, { + name = "allow-http-inbound" + direction = "inbound" + remote = "0.0.0.0/0" + tcp = { + port_min = 80 + port_max = 80 + } + }, { + name = "allow-https-inbound" + direction = "inbound" + remote = "0.0.0.0/0" + tcp = { + port_min = 443 + port_max = 443 + } + }, { + name = "allow-ping-inbound" + direction = "inbound" + remote = "0.0.0.0/0" + icmp = { + type = 8 + } + }] + target_ids = [ibm_is_instance.vsi.primary_network_interface[0].id] +} + + +############################################################################## +# Floating IP +############################################################################## + +resource "ibm_is_floating_ip" "vsi_fip" { + name = "${var.prefix}-fip" + resource_group = var.resource_group_id + target = ibm_is_instance.vsi.primary_network_interface[0].id +} + +############################################################################## +# SSH Key +############################################################################## + +resource "tls_private_key" "tls_key" { + algorithm = "RSA" + rsa_bits = 4096 +} + +resource "ibm_is_ssh_key" "ssh_key" { + name = "${var.prefix}-ssh-key" + public_key = tls_private_key.tls_key.public_key_openssh + resource_group = var.resource_group_id +} + +############################################################################## +# VSI +############################################################################## + +resource "ibm_is_instance" "vsi" { + name = "${var.prefix}-vsi" + image = "r006-fedc50ed-8ea3-4a66-9559-c482c4e6ed88" + profile = "cx2-2x4" + resource_group = var.resource_group_id + vpc = var.vpc_id + zone = "${var.region}-1" + keys = [ibm_is_ssh_key.ssh_key.id] + + + lifecycle { + ignore_changes = [ + image + ] + } + + primary_network_interface { + subnet = var.subnet_ids[0] + name = "${var.prefix}-eth" + primary_ip { + address = var.vsi_reserved_ip + auto_delete = true + } + } + + timeouts { + create = "15m" + update = "15m" + delete = "15m" + } +} +locals { + composed_string = replace(jsondecode(var.service_credential).connection.cli.composed[0], "sslmode=verify-full", "sslmode=require") +} + +resource "null_resource" "db_connection" { + depends_on = [ + ibm_is_instance.vsi, + module.create_sgr_rule_vsi, + ] + + provisioner "remote-exec" { + inline = [ + "sudo apt-get update -y", + "sudo apt-get install postgresql-client -y", + + "${local.composed_string} -c 'CREATE TABLE test (id serial PRIMARY KEY, marks serial);'", + "${local.composed_string} -c 'INSERT INTO test (id, marks) VALUES (101, 100);'", + "${local.composed_string} -c 'INSERT INTO test (id, marks) VALUES (102, 200);'", + "${local.composed_string} -c 'INSERT INTO test (id, marks) VALUES (103, 300);'", + "${local.composed_string} -c 'INSERT INTO test (id, marks) VALUES (104, 400);'", + "${local.composed_string} -c 'SELECT * FROM test;'", + ] + connection { + type = "ssh" + host = ibm_is_floating_ip.vsi_fip.address + user = "root" + private_key = tls_private_key.tls_key.private_key_pem + } + on_failure = fail + } +} diff --git a/tests/resources/outputs.tf b/tests/resources/outputs.tf new file mode 100644 index 00000000..b16a1a35 --- /dev/null +++ b/tests/resources/outputs.tf @@ -0,0 +1,3 @@ +############################################################################## +# Outputs +############################################################################## diff --git a/tests/resources/provider.tf b/tests/resources/provider.tf new file mode 100644 index 00000000..df45ef50 --- /dev/null +++ b/tests/resources/provider.tf @@ -0,0 +1,4 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key + region = var.region +} diff --git a/tests/resources/variables.tf b/tests/resources/variables.tf new file mode 100644 index 00000000..1e6d217a --- /dev/null +++ b/tests/resources/variables.tf @@ -0,0 +1,42 @@ +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API Key" + sensitive = true +} + +variable "region" { + type = string + description = "Region to provision all resources created by this example." + default = "us-south" +} + +variable "prefix" { + type = string + description = "Prefix to append to all resources created by this example" + default = "postgres" +} + +variable "service_credential" { + type = string + description = "Database service credential" +} + +variable "resource_group_id" { + type = string + description = "Id of existing resource_group" +} + +variable "vpc_id" { + type = string + description = "Id of existing vpc" +} + +variable "subnet_ids" { + type = list(string) + description = "List of subnet ids" +} + +variable "vsi_reserved_ip" { + type = string + description = "Reserved IP for vsi" +} diff --git a/tests/resources/version.tf b/tests/resources/version.tf new file mode 100644 index 00000000..d6b63f25 --- /dev/null +++ b/tests/resources/version.tf @@ -0,0 +1,19 @@ +terraform { + required_version = ">= 1.3.0, <1.6.0" + required_providers { + # Use latest version of provider in non-basic examples to verify latest version works with module + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.56.1" + } + null = { + source = "hashicorp/null" + version = ">= 3.2.1" + } + + tls = { + source = "hashicorp/tls" + version = ">= 4.0.4" + } + } +}