From f73dcfed470493469bfa5d13ce754b7b160c295a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Conall=20=C3=93=20Cofaigh?= Date: Mon, 25 Nov 2024 10:56:06 +0000 Subject: [PATCH] feat: several updates to module template (#848) --- .github/CODEOWNERS | 2 +- .secrets.baseline | 15 +++++++++-- README.md | 48 ++++++++++++++++++++++++++++++---- cra-config.yaml | 18 ++++++++----- examples/advanced/main.tf | 35 ++++++++++++++++++++++--- examples/advanced/outputs.tf | 37 ++++++++++++++++++-------- examples/advanced/variables.tf | 24 ++++++++++++----- examples/advanced/version.tf | 12 ++++++--- examples/basic/README.md | 2 +- examples/basic/main.tf | 19 +++++++++----- examples/basic/outputs.tf | 30 +++++++++++++++++---- examples/basic/variables.tf | 20 +++++++++----- examples/basic/version.tf | 12 ++++++--- main.tf | 16 +++++++++--- outputs.tf | 30 ++++++++++++++++++--- tests/other_test.go | 16 ------------ tests/pr_test.go | 19 ++++++++++++-- variables.tf | 37 ++++++++++++++++++++++---- version.tf | 24 ++++++++++------- 19 files changed, 315 insertions(+), 101 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1f65b1e..d545b87 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1,2 @@ # Primary owner should be listed first in list of global owners, followed by any secondary owners -* @SirSpidey @ocofaigh +* @ocofaigh @daniel-butler-irl diff --git a/.secrets.baseline b/.secrets.baseline index 83c2fe0..0a4efa4 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-09T06:39:44Z", + "generated_at": "2024-11-22T17:36:38Z", "plugins_used": [ { "name": "AWSKeyDetector" @@ -76,7 +76,18 @@ "name": "TwilioKeyDetector" } ], - "results": {}, + "results": { + "README.md": [ + { + "hashed_secret": "ff9ee043d85595eb255c05dfe32ece02a53efbb2", + "is_secret": false, + "is_verified": false, + "line_number": 74, + "type": "Secret Keyword", + "verified_result": null + } + ] + }, "version": "0.13.1+ibm.62.dss", "word_list": { "file": null, diff --git a/README.md b/README.md index 212594c..b8d632c 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,32 @@ unless real values don't help users know what to change. --> ```hcl - +terraform { + required_version = ">= 1.9.0" + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = "X.Y.Z" # Lock into a provider version that satisfies the module constraints + } + } +} + +locals { + region = "us-south" +} + +provider "ibm" { + ibmcloud_api_key = "XXXXXXXXXX" # replace with apikey value + region = local.region +} + +module "module_template" { + source = "terraform-ibm-modules//ibm" + version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release + region = local.region + name = "instance-name" + resource_group_id = "xxXXxxXXxXxXXXXxxXxxxXXXXxXXXXX" # Replace with the actual ID of resource group to use +} ``` ### Required access policies @@ -97,7 +122,8 @@ statement instead the previous block. | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 1.3.0 | +| [terraform](#requirement\_terraform) | >= 1.9.0 | +| [ibm](#requirement\_ibm) | >= 1.71.2, < 2.0.0 | ### Modules @@ -105,15 +131,27 @@ No modules. ### Resources -No resources. +| Name | Type | +|------|------| +| [ibm_resource_instance.cos_instance](https://registry.terraform.io/providers/IBM-Cloud/ibm/latest/docs/resources/resource_instance) | resource | ### Inputs -No inputs. +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [name](#input\_name) | A descriptive name used to identify the resource instance. | `string` | n/a | yes | +| [plan](#input\_plan) | The name of the plan type supported by service. | `string` | `"standard"` | no | +| [resource\_group\_id](#input\_resource\_group\_id) | The ID of the resource group where you want to create the service. | `string` | n/a | yes | +| [resource\_tags](#input\_resource\_tags) | List of resource tag to associate with the instance. | `list(string)` | `[]` | no | ### Outputs -No outputs. +| Name | Description | +|------|-------------| +| [account\_id](#output\_account\_id) | An alpha-numeric value identifying the account ID. | +| [crn](#output\_crn) | The CRN of the resource instance. | +| [guid](#output\_guid) | The GUID of the resource instance. | +| [id](#output\_id) | The unique identifier of the resource instance. | diff --git a/cra-config.yaml b/cra-config.yaml index 02d79f0..9a4c7fa 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,11 +1,17 @@ -# More info about this file at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml +# +# Developer tips: +# - CRA = Code Risk Analyzer (more info on CRA: https://cloud.ibm.com/docs/code-risk-analyzer-cli-plugin?topic=code-risk-analyzer-cli-plugin-cra-cli-plugin) +# - Multiple directories can be scanned by CRA. Ensure if there are any deployable architecture in the repository that they are all scanned +# - More info about supported configurations at https://github.com/terraform-ibm-modules/common-pipeline-assets/blob/main/.github/workflows/terraform-test-pipeline.md#cra-config-yaml +# + version: "v1" CRA_TARGETS: - CRA_TARGET: "examples/advanced" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. - CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" # CRA Ignore file to use. If not provided, it checks the repo root directory for `cra-tf-validate-ignore-rules.json` - PROFILE_ID: "0e6e7b5a-817d-4344-ab6f-e5d7a9c49520" # SCC profile ID (currently set to the FSCloud 1.4.0 profile). + CRA_IGNORE_RULES_FILE: "cra-tf-validate-ignore-rules.json" + PROFILE_ID: "fe96bd4d-9b37-40f2-b39f-a62760e326a3" # SCC profile ID (currently set to 'IBM Cloud Framework for Financial Services' '1.7.0' profile). # SCC_INSTANCE_ID: "" # The SCC instance ID to use to download profile for CRA scan. If not provided, a default global value will be used. # SCC_REGION: "" # The IBM Cloud region that the SCC instance is in. If not provided, a default global value will be used. - # CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. - # TF_VAR_sample: "sample value" - # TF_VAR_other: "another value" + CRA_ENVIRONMENT_VARIABLES: # An optional map of environment variables for CRA, where the key is the variable name and value is the value. Useful for providing TF_VARs. + TF_VAR_prefix: "mock" + TF_VAR_region: "us-south" diff --git a/examples/advanced/main.tf b/examples/advanced/main.tf index 558c210..29e4104 100644 --- a/examples/advanced/main.tf +++ b/examples/advanced/main.tf @@ -1,3 +1,32 @@ -############################################################################## -# Complete example -############################################################################## +######################################################################################################################## +# Resource group +######################################################################################################################## + +module "resource_group" { + source = "terraform-ibm-modules/resource-group/ibm" + version = "1.1.6" + # if an existing resource group is not set (null) create a new one using prefix + resource_group_name = var.resource_group == null ? "${var.prefix}-resource-group" : null + existing_resource_group_name = var.resource_group +} + +######################################################################################################################## +# COS +######################################################################################################################## + +# +# Developer tips: +# - Call the local module / modules in the example to show how they can be consumed +# - Include the actual module source as a code comment like below so consumers know how to consume from correct location +# + +module "cos" { + source = "../.." + # remove the above line and uncomment the below 2 lines to consume the module from the registry + # source = "terraform-ibm-modules//ibm" + # version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release + name = "${var.prefix}-cos" + resource_group_id = module.resource_group.resource_group_id + resource_tags = var.resource_tags + plan = "cos-one-rate-plan" +} diff --git a/examples/advanced/outputs.tf b/examples/advanced/outputs.tf index addadea..316751f 100644 --- a/examples/advanced/outputs.tf +++ b/examples/advanced/outputs.tf @@ -2,22 +2,37 @@ # Outputs ############################################################################## -output "region" { - description = "The region all resources were provisioned in" - value = var.region +# +# Developer tips: +# - Include all relevant outputs from the modules being called in the example +# + +output "account_id" { + description = "An alpha-numeric value identifying the account ID." + value = module.cos.account_id +} + +output "guid" { + description = "The GUID of the resource instance." + value = module.cos.account_id +} + +output "id" { + description = "The unique identifier of the resource instance." + value = module.cos.id } -output "prefix" { - description = "The prefix used to name all provisioned resources" - value = var.prefix +output "crn" { + description = "The CRN of the resource instance." + value = module.cos.crn } output "resource_group_name" { - description = "The name of the resource group used" - value = var.resource_group + description = "Resource group name." + value = module.resource_group.resource_group_name } -output "resource_tags" { - description = "List of resource tags" - value = var.resource_tags +output "resource_group_id" { + description = "Resource group ID." + value = module.resource_group.resource_group_id } diff --git a/examples/advanced/variables.tf b/examples/advanced/variables.tf index 170a5ab..d460364 100644 --- a/examples/advanced/variables.tf +++ b/examples/advanced/variables.tf @@ -1,29 +1,39 @@ +######################################################################################################################## +# Input variables +######################################################################################################################## + +# +# Module developer tips: +# - Examples are references that consumers can use to see how the module can be consumed. They are not designed to be +# flexible re-usable solutions for general consumption, so do not expose any more variables here and instead hard +# code things in the example main.tf with code comments explaining the different configurations. +# - For the same reason as above, do not add default values to the example inputs. +# + variable "ibmcloud_api_key" { type = string - description = "The IBM Cloud API Key" + 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" + description = "Region to provision all resources created by this example." } variable "prefix" { type = string - description = "Prefix to append to all resources created by this example" - default = "complete" + description = "A string value to prefix to all resources created by this example." } variable "resource_group" { type = string - description = "An existing resource group name to use for this example, if unset a new resource group will be created" + description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable." default = null } variable "resource_tags" { type = list(string) - description = "Optional list of tags to be added to created resources" + description = "List of resource tag to associate with all resource instances created by this example." default = [] } diff --git a/examples/advanced/version.tf b/examples/advanced/version.tf index 398bd44..ecfa978 100644 --- a/examples/advanced/version.tf +++ b/examples/advanced/version.tf @@ -1,12 +1,16 @@ terraform { - required_version = ">= 1.3.0" + required_version = ">= 1.9.0" + + # + # Developer tips: + # - Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main + # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. + # - # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main - # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. required_providers { ibm = { source = "IBM-Cloud/ibm" - version = ">= 1.49.0, < 2.0.0" + version = ">= 1.71.2, < 2.0.0" } } } diff --git a/examples/basic/README.md b/examples/basic/README.md index 86eab8e..e5977ae 100644 --- a/examples/basic/README.md +++ b/examples/basic/README.md @@ -8,4 +8,4 @@ The text below should describe exactly what resources are provisioned / configur An end-to-end basic example that will provision the following: - A new resource group if one is not passed in. -- A new Cloud Object Storage instance. +- A new standard plan Cloud Object Storage instance using the root level module. diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 95cc2a6..410054a 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -11,14 +11,21 @@ module "resource_group" { } ######################################################################################################################## -# COS instance +# COS ######################################################################################################################## -resource "ibm_resource_instance" "cos_instance" { +# +# Developer tips: +# - Call the local module / modules in the example to show how they can be consumed +# - include the actual module source as a code comment like below so consumers know how to consume from correct location +# + +module "cos" { + source = "../.." + # remove the above line and uncomment the below 2 lines to consume the module from the registry + # source = "terraform-ibm-modules//ibm" + # version = "X.Y.Z" # Replace "X.Y.Z" with a release version to lock into a specific release name = "${var.prefix}-cos" resource_group_id = module.resource_group.resource_group_id - service = "cloud-object-storage" - plan = "standard" - location = "global" - tags = var.resource_tags + resource_tags = var.resource_tags } diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index 04b196e..552db48 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -2,17 +2,37 @@ # Outputs ######################################################################################################################## -output "cos_instance_id" { - description = "COS instance id" - value = ibm_resource_instance.cos_instance.id +# +# Developer tips: +# - Include all relevant outputs from the modules being called in the example +# + +output "account_id" { + description = "An alpha-numeric value identifying the account ID." + value = module.cos.account_id +} + +output "guid" { + description = "The GUID of the resource instance." + value = module.cos.account_id +} + +output "id" { + description = "The unique identifier of the resource instance." + value = module.cos.id +} + +output "crn" { + description = "The CRN of the resource instance." + value = module.cos.crn } output "resource_group_name" { - description = "Resource group name" + description = "Resource group name." value = module.resource_group.resource_group_name } output "resource_group_id" { - description = "Resource group ID" + description = "Resource group ID." value = module.resource_group.resource_group_id } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index dd0d0af..d460364 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -2,32 +2,38 @@ # Input variables ######################################################################################################################## +# +# Module developer tips: +# - Examples are references that consumers can use to see how the module can be consumed. They are not designed to be +# flexible re-usable solutions for general consumption, so do not expose any more variables here and instead hard +# code things in the example main.tf with code comments explaining the different configurations. +# - For the same reason as above, do not add default values to the example inputs. +# + variable "ibmcloud_api_key" { type = string - description = "The IBM Cloud API Key" + 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" + description = "Region to provision all resources created by this example." } variable "prefix" { type = string - description = "Prefix to append to all resources created by this example" - default = "basic" + description = "A string value to prefix to all resources created by this example." } variable "resource_group" { type = string - description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable" + description = "The name of an existing resource group to provision resources in to. If not set a new resource group will be created using the prefix variable." default = null } variable "resource_tags" { type = list(string) - description = "Optional list of tags to be added to created resources" + description = "List of resource tag to associate with all resource instances created by this example." default = [] } diff --git a/examples/basic/version.tf b/examples/basic/version.tf index 2b99b89..401504c 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -1,12 +1,16 @@ terraform { - required_version = ">= 1.3.0" + required_version = ">= 1.9.0" + + # + # Developer tips: + # - Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main + # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. + # - # Ensure that there is always 1 example locked into the lowest provider version of the range defined in the main - # module's version.tf (usually a basic example), and 1 example that will always use the latest provider version. required_providers { ibm = { source = "IBM-Cloud/ibm" - version = "1.49.0" + version = "1.71.2" } } } diff --git a/main.tf b/main.tf index 0b919ea..b6b879e 100644 --- a/main.tf +++ b/main.tf @@ -1,3 +1,13 @@ -/******************************************************************** -This file is used to implement the ROOT module. -*********************************************************************/ +# +# Developer tips: +# - Below code should be replaced with the code for the root level module +# + +resource "ibm_resource_instance" "cos_instance" { + name = var.name + resource_group_id = var.resource_group_id + service = "cloud-object-storage" + plan = var.plan + location = "global" + tags = var.resource_tags +} diff --git a/outputs.tf b/outputs.tf index bb6ea66..1c0cf4c 100644 --- a/outputs.tf +++ b/outputs.tf @@ -2,7 +2,29 @@ # Outputs ######################################################################################################################## -#output "myoutput" { -# description = "Description of my output" -# value = "value" -#} +# +# Developer tips: +# - Below are some good practise sample outputs +# - They should be updated for outputs applicable to the module being added +# - Use variable validation when possible +# + +output "account_id" { + description = "An alpha-numeric value identifying the account ID." + value = ibm_resource_instance.cos_instance.account_id +} + +output "guid" { + description = "The GUID of the resource instance." + value = ibm_resource_instance.cos_instance.account_id +} + +output "id" { + description = "The unique identifier of the resource instance." + value = ibm_resource_instance.cos_instance.id +} + +output "crn" { + description = "The CRN of the resource instance." + value = ibm_resource_instance.cos_instance.crn +} diff --git a/tests/other_test.go b/tests/other_test.go index d03784f..88d360d 100644 --- a/tests/other_test.go +++ b/tests/other_test.go @@ -1,18 +1,2 @@ // Tests in this file are NOT run in the PR pipeline. They are run in the continuous testing pipeline along with the ones in pr_test.go package test - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestRunBasicExample(t *testing.T) { - t.Parallel() - - options := setupOptions(t, "mod-template-basic", "examples/basic") - - output, err := options.RunTestConsistency() - assert.Nil(t, err, "This should not have errored") - assert.NotNil(t, output, "Expected some output") -} diff --git a/tests/pr_test.go b/tests/pr_test.go index 370bfac..8867ed0 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -10,7 +10,10 @@ import ( // Use existing resource group const resourceGroup = "geretain-test-resources" + +// Ensure every example directory has a corresponding test const advancedExampleDir = "examples/advanced" +const basicExampleDir = "examples/basic" func setupOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptions { options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ @@ -22,20 +25,32 @@ func setupOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptio return options } +// Consistency test for the basic example +func TestRunBasicExample(t *testing.T) { + t.Parallel() + + options := setupOptions(t, "mod-template-basic", basicExampleDir) + + output, err := options.RunTestConsistency() + assert.Nil(t, err, "This should not have errored") + assert.NotNil(t, output, "Expected some output") +} + func TestRunAdvancedExample(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template", advancedExampleDir) + options := setupOptions(t, "mod-template-adv", advancedExampleDir) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } +// Upgrade test (using advanced example) func TestRunUpgradeExample(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-upg", advancedExampleDir) + options := setupOptions(t, "mod-template-adv-upg", advancedExampleDir) output, err := options.RunTestUpgrade() if !options.UpgradeTestSkipped { diff --git a/variables.tf b/variables.tf index df60434..a9d9899 100644 --- a/variables.tf +++ b/variables.tf @@ -2,8 +2,35 @@ # Input Variables ######################################################################################################################## -#variable "my_variable" { -# type = string -# description = "A description of my variable" -# default = "default_value" -#} +# +# Developer tips: +# - Below are some common module input variables +# - They should be updated for input variables applicable to the module being added +# - Use variable validation when possible +# + +variable "name" { + type = string + description = "A descriptive name used to identify the resource instance." +} + +variable "plan" { + type = string + description = "The name of the plan type supported by service." + default = "standard" + validation { + condition = contains(["standard", "cos-one-rate-plan"], var.plan) + error_message = "The specified pricing plan is not available. The following plans are supported: 'standard', 'cos-one-rate-plan'" + } +} + +variable "resource_group_id" { + type = string + description = "The ID of the resource group where you want to create the service." +} + +variable "resource_tags" { + type = list(string) + description = "List of resource tag to associate with the instance." + default = [] +} diff --git a/version.tf b/version.tf index f15f603..e51de7f 100644 --- a/version.tf +++ b/version.tf @@ -1,12 +1,18 @@ terraform { - required_version = ">= 1.3.0" - # If your module requires any terraform providers, uncomment the "required_providers" section below and add all required providers. - # Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions. + # require 1.9 or later to make use of cross-object referencing for input variable validations + # more info: https://www.hashicorp.com/blog/terraform-1-9-enhances-input-variable-validations + required_version = ">= 1.9.0" - # required_providers { - # ibm = { - # source = "IBM-Cloud/ibm" - # version = ">= 1.64.0, < 2.0.0" - # } - # } + # + # Developer tips: + # - If your module requires any terraform providers, add them the "required_providers" section below. + # - Each required provider's version should be a flexible range to future proof the module's usage with upcoming minor and patch versions. + # + + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.71.2, < 2.0.0" + } + } }