diff --git a/.github/settings.yml b/.github/settings.yml index d8160f0..9ba93e6 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -15,14 +15,14 @@ repository: # By changing this field, you rename the repository. # Uncomment this name property and set the name to the current repo name. - # name: "" + name: "terraform-ibm-enterprise" # The description is displayed under the repository name on the # organization page and in the 'About' section of the repository. # Uncomment this description property # and update the description to the current repo description. - # description: "" + description: "Creates accounts and account-groups in an existing enterprise" # Uncomment this topics property # and add a comma-separated list of topics to set on the repo. diff --git a/.secrets.baseline b/.secrets.baseline index 7460028..74f2f93 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -3,7 +3,7 @@ "files": "go.sum|^.secrets.baseline$", "lines": null }, - "generated_at": "2023-12-09T05:14:35Z", + "generated_at": "2023-12-10T05:14:35Z", "plugins_used": [ { "name": "AWSKeyDetector" diff --git a/README.md b/README.md index 4ff25af..d55e865 100644 --- a/README.md +++ b/README.md @@ -1,156 +1,85 @@ - +# IBM Enterprise Account module - -# Terraform Modules Template Project - -[![Incubating (Not yet consumable)](https://img.shields.io/badge/status-Incubating%20(Not%20yet%20consumable)-red)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) -[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) +[![Stable (Adopted)](https://img.shields.io/badge/Status-Stable%20(Adopted)-yellowgreen?style=plastic)](https://terraform-ibm-modules.github.io/documentation/#/badge-status) [![latest release](https://img.shields.io/github/v/release/terraform-ibm-modules/terraform-ibm-enterprise?logo=GitHub&sort=semver)](https://github.com/terraform-ibm-modules/terraform-ibm-enterprise/releases/latest) +[![pre-commit](https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white)](https://github.com/pre-commit/pre-commit) [![Renovate enabled](https://img.shields.io/badge/renovate-enabled-brightgreen.svg)](https://renovatebot.com/) [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) + +This is a collection of sub modules and which will take tree based enterprise inputs and create child accounts and account-groups in an enterprise +* [dynamic_values](submodules/dynamic_values) +* [enterprise_hierarchy](submodules/enterprise_hierarchy) + + ## Overview * [terraform-ibm-enterprise](#terraform-ibm-enterprise) * [Examples](./examples) + * [Advanced example](./examples/advanced) * [Basic example](./examples/basic) - * [Complete example](./examples/complete) * [Contributing](#contributing) - - -## Submit a new module - -:+1::tada: Thank you for taking the time to contribute! :tada::+1: - -This template repository exists to help you create Terraform modules for IBM Cloud. - -The default structure includes the following files: - -- `README.md`: A description of the module -- `main.tf`: The logic for the module -- `version.tf`: The required terraform and provider versions -- `variables.tf`: The input variables for the module -- `outputs.tf`: The values that are output from the module - -Use nested modules to split complex behavior into smaller modules that advanced users can choose from. Put nested modules under a `/modules` subdirectory. If you include more than one nested module, make the submodules [composable](https://developer.hashicorp.com/terraform/language/modules/develop/composition) by the caller. In other words, don't embed calls between submodules to create a deeply nested tree of modules. -For more information, see [Module structure](https://terraform-ibm-modules.github.io/documentation/#/module-structure) in the project documentation. - -You can add other content to support what your module does and how it works. For example, you might add a `scripts/` directory that contains shell scripts that are run by a `local-exec` `null_resource` in the Terraform module. - -Follow this process to create and submit a Terraform module. - -### Create a repo from this repo template - -1. Create a repository from this repository template by clicking `Use this template` in the upper right of the GitHub UI. -    
For more information about creating a repository from a template, see the [GitHub docs](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template). -1. Select `terraform-ibm-modules` as the owner. -1. Enter a name for the module in format `terraform-ibm-`, where `` reflects the type of infrastructure that the module manages. -    
Use hyphens as delimiters for names with multiple words (for example, terraform-ibm-`activity-tracker`). -1. Provide a short description of the module. -    
The description is displayed under the repository name on the [organization page](https://github.com/terraform-ibm-modules) and in the **About** section of the repository. Use the description to help users understand the purpose of your module. For more information, see [module names and descriptions](https://terraform-ibm-modules.github.io/documentation/#/implementation-guidelines?id=module-names-and-descriptions) in the docs. - -### Clone the repo and set up your development environment - -Locally clone the new repository and set up your development environment by completing the tasks in [Local development setup](https://terraform-ibm-modules.github.io/documentation/#/local-dev-setup) in the project documentation. - -### Update the repo name and description in source control - -To help make sure that the repo name and description are not changed except through pull requests, they are defined in the `settings.yml` file. - -Check to make sure that values are uncommented and correct: - -1. Open the [settings.yml](.github/settings.yml) file. -1. If not already updated, uncomment the `name` and `description` properties and set the values to what you specified when you requested the repo. - -### Update the Terraform files - -Implement the logic for your module by updating the `main.tf`, `version.tf`, `variables.tf`, and `outputs.tf` Terraform files. For more information, see [Creating Terraform on IBM Cloud templates](https://cloud.ibm.com/docs/ibm-cloud-provider-for-terraform?topic=ibm-cloud-provider-for-terraform-create-tf-config). - -### Create examples and tests - -Add one or more examples in the `examples` directory that consume your new module, and configure tests for them in the `tests` directory. For more information about tests, see [Tests](https://terraform-ibm-modules.github.io/documentation/#/tests). - -### Update the content in the readme file - -After you implement the logic for your module and create examples and tests, update this readme file in your repository by following these steps: - -1. Update the title heading and add a description about your module. -1. Update the badge links. -1. Remove all the content in this H2 heading section. -1. Complete the [Usage](#usage) and [Required IAM access policies](#required-iam-access-policies) sections. The [Examples](#examples) and [Requirements](#requirements) section are populated by a pre-commit hook. - -### Commit your code and submit your module for review - -1. Before you commit any code, review [Contributing to the IBM Cloud Terraform modules project](https://terraform-ibm-modules.github.io/documentation/#/contribute-module) in the project documentation. -1. Create a pull request for review. - -### Post-merge steps - -After the first PR for your module is merged, follow these post-merge steps: - - -### Reference architectures - - + +## terraform-ibm-enterprise ### Usage - +Full examples are in the [examples](./examples/) folder, but basic usage is as follows for creation of enterprise children is ```hcl - +provider "ibm" { + ibmcloud_api_key = "XXXXXXXX" # pragma: allowlist secret +} + +data "ibm_enterprises" "enterprise" { + name = "my-enterprise-account" +} + +module "enterprise" { + source = "terraform-ibm-modules/terraform-ibm-enterprise" + enterprise_crn = data.ibm_enterprises.enterprise.enterprises[0].crn + enterprise_primary_contact_iam_id = data.ibm_enterprises.enterprise.enterprises[0].primary_contact_iam_id + enterprise_account_groups = [ + { + key_name = "group-key-1" + name = "account_group_1" + parent_key_name = null + }] + + enterprise_accounts = [ + { + key_name = "acct-key-1" + name = "account_1" + parent_key_name = null + } + ] + } ``` ### Required IAM access policies - - - - - - - - + - **Enterprise** service + - `Administrator` platform access + + ### Requirements | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >= 1.3.0, <1.7.0 | +| [ibm](#requirement\_ibm) | >= 1.54.0, < 2.0.0 | ### Modules -No modules. +| Name | Source | Version | +|------|--------|---------| +| [dynamic\_values](#module\_dynamic\_values) | ./submodules/dynamic_values | n/a | +| [enterprise\_hierarchy\_depth\_0](#module\_enterprise\_hierarchy\_depth\_0) | ./submodules/enterprise_hierarchy | n/a | +| [enterprise\_hierarchy\_depth\_1](#module\_enterprise\_hierarchy\_depth\_1) | ./submodules/enterprise_hierarchy | n/a | +| [enterprise\_hierarchy\_depth\_2](#module\_enterprise\_hierarchy\_depth\_2) | ./submodules/enterprise_hierarchy | n/a | ### Resources @@ -158,20 +87,24 @@ No resources. ### Inputs -No inputs. +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [enterprise\_account\_groups](#input\_enterprise\_account\_groups) | List of enterprise child account\_groups in the enterprise | `list(object({ name = string, key_name = string, parent_key_name = optional(string, null), owner_iam_id = optional(string, null) }))` | n/a | yes | +| [enterprise\_accounts](#input\_enterprise\_accounts) | List of enterprise child accounts in the enterprise | `list(object({ name = string, key_name = string, parent_key_name = optional(string, null), owner_iam_id = optional(string, null) }))` | n/a | yes | +| [enterprise\_crn](#input\_enterprise\_crn) | The CRN of the parent Enterprise account to use. | `string` | n/a | yes | +| [enterprise\_primary\_contact\_iam\_id](#input\_enterprise\_primary\_contact\_iam\_id) | The IAM id of the parent Enterprise account owner. | `string` | n/a | yes | ### Outputs -No outputs. +| Name | Description | +|------|-------------| +| [enterprise\_account\_groups](#output\_enterprise\_account\_groups) | List of account groups created in an Enterprise | +| [enterprise\_accounts](#output\_enterprise\_accounts) | List of accounts created in an Enterprise | - - ## Contributing You can report issues and request features for this module in GitHub issues in the module repo. See [Report an issue or request a feature](https://github.com/terraform-ibm-modules/.github/blob/main/.github/SUPPORT.md). To set up your local development environment, see [Local development setup](https://terraform-ibm-modules.github.io/documentation/#/local-dev-setup) in the project documentation. - - diff --git a/cra-config.yaml b/cra-config.yaml index 7ec59e3..c3d932b 100644 --- a/cra-config.yaml +++ b/cra-config.yaml @@ -1,11 +1,10 @@ # 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 version: "v1" CRA_TARGETS: - - CRA_TARGET: "examples/basic" # Target directory for CRA scan. If not provided, the CRA Scan will not be run. + - 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). SCC_INSTANCE_ID: "7a2983d7-bcee-40c9-93d3-7b235039920c" # Instance ID in account "DAF Enterprise (1f27e30e31f0486980cb0b2657d483f7) <-> 2716327" SCC_REGION: "us-south" # 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_enterprise_name: "DAF Enterprise" diff --git a/examples/advanced/README.md b/examples/advanced/README.md new file mode 100644 index 0000000..3a64d3f --- /dev/null +++ b/examples/advanced/README.md @@ -0,0 +1,3 @@ +# Advanced example + +This example will create a hierarchy of enterprise child accounts and account groups. diff --git a/examples/advanced/main.tf b/examples/advanced/main.tf new file mode 100644 index 0000000..9c528e4 --- /dev/null +++ b/examples/advanced/main.tf @@ -0,0 +1,34 @@ +# Lookup data from given enterprise account +data "ibm_enterprises" "enterprise" { + name = var.enterprise_name +} + +# Call root level module to create a hierarchy of enterprise child accounts and account groups +module "enterprise" { + source = "../.." + enterprise_crn = data.ibm_enterprises.enterprise.enterprises[0].crn + enterprise_primary_contact_iam_id = data.ibm_enterprises.enterprise.enterprises[0].primary_contact_iam_id + enterprise_account_groups = [ + { + key_name = "${var.prefix}-group-key-1" + name = "${var.prefix}_account_group_1" + parent_key_name = null + }, + { + key_name = "${var.prefix}-group-key-2" + name = "${var.prefix}_account_group_2" + parent_key_name = "${var.prefix}-group-key-1" + }] + enterprise_accounts = [ + { + key_name = "${var.prefix}-acc-key-1" + name = "${var.prefix}_account_1" + parent_key_name = null + }, + { + key_name = "${var.prefix}-acc-key-2" + name = "${var.prefix}_account_2" + parent_key_name = null + } + ] +} diff --git a/examples/complete/main.tf b/examples/advanced/outputs.tf similarity index 50% rename from examples/complete/main.tf rename to examples/advanced/outputs.tf index 558c210..e9e12ec 100644 --- a/examples/complete/main.tf +++ b/examples/advanced/outputs.tf @@ -1,3 +1,3 @@ -############################################################################## -# Complete example -############################################################################## +######################################################################################################################## +# Outputs +######################################################################################################################## diff --git a/examples/advanced/provider.tf b/examples/advanced/provider.tf new file mode 100644 index 0000000..4a12678 --- /dev/null +++ b/examples/advanced/provider.tf @@ -0,0 +1,3 @@ +provider "ibm" { + ibmcloud_api_key = var.ibmcloud_api_key +} diff --git a/examples/advanced/variables.tf b/examples/advanced/variables.tf new file mode 100644 index 0000000..ac49e2d --- /dev/null +++ b/examples/advanced/variables.tf @@ -0,0 +1,16 @@ +variable "ibmcloud_api_key" { + type = string + description = "The IBM Cloud API Key with access to create enterprise sub accounts" + sensitive = true +} + +variable "prefix" { + type = string + description = "Prefix to append to all resources created by this example" + default = "enterprise" +} + +variable "enterprise_name" { + description = "Name of the enterprise account" + type = string +} diff --git a/examples/complete/version.tf b/examples/advanced/version.tf similarity index 60% rename from examples/complete/version.tf rename to examples/advanced/version.tf index d70a9d2..e59176a 100644 --- a/examples/complete/version.tf +++ b/examples/advanced/version.tf @@ -2,11 +2,11 @@ terraform { required_version = ">= 1.3.0, <1.7.0" # 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. + # module's version.tf (basic example), and 1 example that will always use the latest provider version (advanced example). required_providers { ibm = { source = "IBM-Cloud/ibm" - version = ">= 1.49.0, < 2.0.0" + version = ">= 1.54.0, < 2.0.0" } } } diff --git a/examples/basic/README.md b/examples/basic/README.md index 31e62c6..d87f030 100644 --- a/examples/basic/README.md +++ b/examples/basic/README.md @@ -1,8 +1,3 @@ # Basic example - - - -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 simple example that shows how to provision an enterprise account group and account. diff --git a/examples/basic/main.tf b/examples/basic/main.tf index 8215b1e..8f57951 100644 --- a/examples/basic/main.tf +++ b/examples/basic/main.tf @@ -1,24 +1,26 @@ -############################################################################## -# Resource group -############################################################################## - -module "resource_group" { - source = "terraform-ibm-modules/resource-group/ibm" - version = "1.1.5" - # 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 +# Lookup data from given enterprise account +data "ibm_enterprises" "enterprise" { + name = var.enterprise_name } -############################################################################## -# COS instance -############################################################################## +# Call root level module to create 1 account group with 1 account in it +module "enterprise" { + source = "../.." + enterprise_crn = data.ibm_enterprises.enterprise.enterprises[0].crn + enterprise_primary_contact_iam_id = data.ibm_enterprises.enterprise.enterprises[0].primary_contact_iam_id + enterprise_account_groups = [ + { + key_name = "${var.prefix}-group-key-1" + name = "${var.prefix}_account_group_1" + parent_key_name = null + }] + + enterprise_accounts = [ + { + key_name = "${var.prefix}-acct-key-1" + name = "${var.prefix}_account_1" + parent_key_name = null + } + ] -resource "ibm_resource_instance" "cos_instance" { - 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 } diff --git a/examples/basic/outputs.tf b/examples/basic/outputs.tf index 9ed6273..e9e12ec 100644 --- a/examples/basic/outputs.tf +++ b/examples/basic/outputs.tf @@ -1,18 +1,3 @@ -############################################################################## +######################################################################################################################## # Outputs -############################################################################## - -output "cos_instance_id" { - description = "COS instance id" - value = ibm_resource_instance.cos_instance.id -} - -output "resource_group_name" { - description = "Resource group name" - value = module.resource_group.resource_group_name -} - -output "resource_group_id" { - description = "Resource group ID" - value = module.resource_group.resource_group_id -} +######################################################################################################################## diff --git a/examples/basic/provider.tf b/examples/basic/provider.tf index 2080946..4a12678 100644 --- a/examples/basic/provider.tf +++ b/examples/basic/provider.tf @@ -1,8 +1,3 @@ -############################################################################## -# Provider config -############################################################################## - provider "ibm" { ibmcloud_api_key = var.ibmcloud_api_key - region = var.region } diff --git a/examples/basic/variables.tf b/examples/basic/variables.tf index 48ab01e..ac49e2d 100644 --- a/examples/basic/variables.tf +++ b/examples/basic/variables.tf @@ -1,33 +1,16 @@ -############################################################################## -# Input variables -############################################################################## - variable "ibmcloud_api_key" { type = string - description = "The IBM Cloud API Key" + description = "The IBM Cloud API Key with access to create enterprise sub accounts" 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 = "basic" + default = "enterprise" } -variable "resource_group" { +variable "enterprise_name" { + description = "Name of the enterprise account" 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" - default = null -} - -variable "resource_tags" { - type = list(string) - description = "Optional list of tags to be added to created resources" - default = [] } diff --git a/examples/basic/version.tf b/examples/basic/version.tf index a557e04..f3f50fb 100644 --- a/examples/basic/version.tf +++ b/examples/basic/version.tf @@ -2,11 +2,11 @@ terraform { required_version = ">= 1.3.0, <1.7.0" # 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. + # module's version.tf (basic example), and 1 example that will always use the latest provider version (advanced example). required_providers { ibm = { source = "IBM-Cloud/ibm" - version = "1.49.0" + version = "1.54.0" } } } diff --git a/examples/complete/README.md b/examples/complete/README.md deleted file mode 100644 index 139f8dd..0000000 --- a/examples/complete/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Complete example - - - diff --git a/examples/complete/outputs.tf b/examples/complete/outputs.tf deleted file mode 100644 index addadea..0000000 --- a/examples/complete/outputs.tf +++ /dev/null @@ -1,23 +0,0 @@ -############################################################################## -# Outputs -############################################################################## - -output "region" { - description = "The region all resources were provisioned in" - value = var.region -} - -output "prefix" { - description = "The prefix used to name all provisioned resources" - value = var.prefix -} - -output "resource_group_name" { - description = "The name of the resource group used" - value = var.resource_group -} - -output "resource_tags" { - description = "List of resource tags" - value = var.resource_tags -} diff --git a/examples/complete/provider.tf b/examples/complete/provider.tf deleted file mode 100644 index 2080946..0000000 --- a/examples/complete/provider.tf +++ /dev/null @@ -1,8 +0,0 @@ -############################################################################## -# Provider config -############################################################################## - -provider "ibm" { - ibmcloud_api_key = var.ibmcloud_api_key - region = var.region -} diff --git a/examples/complete/variables.tf b/examples/complete/variables.tf deleted file mode 100644 index 170a5ab..0000000 --- a/examples/complete/variables.tf +++ /dev/null @@ -1,29 +0,0 @@ -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 = "complete" -} - -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" - default = null -} - -variable "resource_tags" { - type = list(string) - description = "Optional list of tags to be added to created resources" - default = [] -} diff --git a/main.tf b/main.tf index 0b919ea..9666b7d 100644 --- a/main.tf +++ b/main.tf @@ -1,3 +1,31 @@ -/******************************************************************** -This file is used to implement the ROOT module. -*********************************************************************/ +module "dynamic_values" { + source = "./submodules/dynamic_values" + enterprise_account_groups = var.enterprise_account_groups + enterprise_accounts = var.enterprise_accounts + enterprise_crn = var.enterprise_crn + enterprise_primary_contact_iam_id = var.enterprise_primary_contact_iam_id +} + +module "enterprise_hierarchy_depth_0" { + source = "./submodules/enterprise_hierarchy" + enterprise_hierarchy = module.dynamic_values.enterprise_hierarchy_depth_0 + parent_account_groups = null + enterprise_crn = var.enterprise_crn + enterprise_primary_contact_iam_id = var.enterprise_primary_contact_iam_id +} + +module "enterprise_hierarchy_depth_1" { + source = "./submodules/enterprise_hierarchy" + enterprise_hierarchy = module.dynamic_values.enterprise_hierarchy_depth_1 + parent_account_groups = module.enterprise_hierarchy_depth_0.account_groups + enterprise_crn = var.enterprise_crn + enterprise_primary_contact_iam_id = var.enterprise_primary_contact_iam_id +} + +module "enterprise_hierarchy_depth_2" { + source = "./submodules/enterprise_hierarchy" + enterprise_hierarchy = module.dynamic_values.enterprise_hierarchy_depth_2 + parent_account_groups = module.enterprise_hierarchy_depth_1.account_groups + enterprise_crn = var.enterprise_crn + enterprise_primary_contact_iam_id = var.enterprise_primary_contact_iam_id +} diff --git a/outputs.tf b/outputs.tf index 4b614c7..aa4323e 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,8 +1,46 @@ -############################################################################## -# Outputs -############################################################################## -#output "myoutput" { -# description = "Description of my output" -# value = "value" -#} +output "enterprise_account_groups" { + description = "List of account groups created in an Enterprise" + value = flatten([[for key, value in module.enterprise_hierarchy_depth_0.account_groups : { + parent : value.parent, + name : value.name, + crn : value.crn, + primary_contact_iam_id : value.primary_contact_iam_id + }], + [for key, value in module.enterprise_hierarchy_depth_1.account_groups : { + parent : value.parent, + name : value.name, + crn : value.crn, + primary_contact_iam_id : value.primary_contact_iam_id + }], + [for key, value in module.enterprise_hierarchy_depth_2.account_groups : { + parent : value.parent, + name : value.name, + crn : value.crn, + primary_contact_iam_id : value.primary_contact_iam_id + }] + ]) +} + +output "enterprise_accounts" { + description = "List of accounts created in an Enterprise" + value = flatten([[for key, value in module.enterprise_hierarchy_depth_0.accounts : { + parent : value.parent, + name : value.name, + crn : value.crn, + owner_iam_id : value.owner_iam_id + }], + [for key, value in module.enterprise_hierarchy_depth_1.accounts : { + parent : value.parent, + name : value.name, + crn : value.crn, + owner_iam_id : value.owner_iam_id + }], + [for key, value in module.enterprise_hierarchy_depth_2.accounts : { + parent : value.parent, + name : value.name, + crn : value.crn, + owner_iam_id : value.owner_iam_id + }] + ]) +} diff --git a/submodules/dynamic_values/README.md b/submodules/dynamic_values/README.md new file mode 100644 index 0000000..cfa61ca --- /dev/null +++ b/submodules/dynamic_values/README.md @@ -0,0 +1,3 @@ +# Dynamic values + +This submodule will simplify the nested enterprise input json and create input for each level(Depth) in enterprise hierarchy diff --git a/submodules/dynamic_values/main.tf b/submodules/dynamic_values/main.tf new file mode 100644 index 0000000..8acf947 --- /dev/null +++ b/submodules/dynamic_values/main.tf @@ -0,0 +1,59 @@ + +// account_groups +locals { + + nested_account_groups = { for value in var.enterprise_account_groups : + value.key_name => value if(value.parent_key_name != null) + } + + nested_accounts = { for value in var.enterprise_accounts : + value.key_name => value if(value.parent_key_name != null) + } + + + depth_0_account_groups = { for value in var.enterprise_account_groups : + value.key_name => value if(value.parent_key_name == null) + } + + depth_0_accounts = { for value in var.enterprise_accounts : + value.key_name => value if(value.parent_key_name == null) + } + + depth_1_account_groups = { + for value in local.nested_account_groups : + value.key_name => value + if contains(keys(local.depth_0_account_groups), value.parent_key_name) + } + + depth_2_account_groups = { + for value in local.nested_account_groups : + value.key_name => value if contains(keys(local.depth_1_account_groups), value.parent_key_name) + } + + depth_1_accounts = { + for value in local.nested_accounts : + value.key_name => value + if contains(keys(local.depth_1_account_groups), value.parent_key_name) + } + + depth_2_accounts = { + for value in local.nested_accounts : + value.key_name => value + if contains(keys(local.depth_2_account_groups), value.parent_key_name) + } + + enterprise_hierarchy_depth_0 = { + "account_groups" = local.depth_0_account_groups + "accounts" = local.depth_0_accounts + } + + enterprise_hierarchy_depth_1 = { + "account_groups" = local.depth_1_account_groups + "accounts" = local.depth_1_accounts + } + + enterprise_hierarchy_depth_2 = { + "account_groups" = local.depth_2_account_groups + "accounts" = local.depth_2_accounts + } +} diff --git a/submodules/dynamic_values/outputs.tf b/submodules/dynamic_values/outputs.tf new file mode 100644 index 0000000..0c0a956 --- /dev/null +++ b/submodules/dynamic_values/outputs.tf @@ -0,0 +1,11 @@ +output "enterprise_hierarchy_depth_0" { + value = local.enterprise_hierarchy_depth_0 +} + +output "enterprise_hierarchy_depth_1" { + value = local.enterprise_hierarchy_depth_1 +} + +output "enterprise_hierarchy_depth_2" { + value = local.enterprise_hierarchy_depth_2 +} diff --git a/submodules/dynamic_values/variables.tf b/submodules/dynamic_values/variables.tf new file mode 100644 index 0000000..de16335 --- /dev/null +++ b/submodules/dynamic_values/variables.tf @@ -0,0 +1,29 @@ +# for now added support for upto 3 level depth of enterprise hierarchy + +variable "enterprise_accounts" { + description = "List of enterprise child accounts in the enterprise" + type = list(object({ name = string, key_name = string, parent_key_name = optional(string, null), owner_iam_id = optional(string, null) })) + validation { + error_message = "Accounts key_name should be unique" + condition = length(distinct(var.enterprise_accounts[*].key_name)) == length(var.enterprise_accounts[*].key_name) + } +} + +variable "enterprise_account_groups" { + description = "List of enterprise child account_groups in the enterprise" + type = list(object({ name = string, key_name = string, parent_key_name = optional(string, null), owner_iam_id = optional(string, null) })) + validation { + error_message = "Account_Groups key_name should be unique" + condition = length(distinct(var.enterprise_account_groups[*].key_name)) == length(var.enterprise_account_groups[*].key_name) + } +} + +variable "enterprise_crn" { + type = string + description = "Enterprise CRN" +} + +variable "enterprise_primary_contact_iam_id" { + type = string + description = "Enterprise owner IAM id" +} diff --git a/submodules/dynamic_values/version.tf b/submodules/dynamic_values/version.tf new file mode 100644 index 0000000..7999c38 --- /dev/null +++ b/submodules/dynamic_values/version.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.3.0, <1.7.0" + + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.54.0, < 2.0.0" + } + } +} diff --git a/submodules/enterprise_hierarchy/README.md b/submodules/enterprise_hierarchy/README.md new file mode 100644 index 0000000..1523df8 --- /dev/null +++ b/submodules/enterprise_hierarchy/README.md @@ -0,0 +1,3 @@ +# Enterprise hierarchy + +This submodule create enterprise child accounts and account groups at multiple depths of an enterprise hierarchy diff --git a/submodules/enterprise_hierarchy/main.tf b/submodules/enterprise_hierarchy/main.tf new file mode 100644 index 0000000..ef95cd6 --- /dev/null +++ b/submodules/enterprise_hierarchy/main.tf @@ -0,0 +1,14 @@ +resource "ibm_enterprise_account_group" "enterprise_account_group" { + for_each = var.enterprise_hierarchy.account_groups + parent = each.value.parent_key_name == null ? var.enterprise_crn : var.parent_account_groups[each.value.parent_key_name].crn + name = each.value.name + primary_contact_iam_id = each.value.owner_iam_id == null ? var.enterprise_primary_contact_iam_id : each.value.owner_iam_id +} + + +resource "ibm_enterprise_account" "enterprise_account" { + for_each = var.enterprise_hierarchy.accounts + parent = each.value.parent_key_name != null ? resource.ibm_enterprise_account_group.enterprise_account_group[each.value.parent_key_name].crn : var.enterprise_crn + name = each.value.name + owner_iam_id = each.value.owner_iam_id == null ? var.enterprise_primary_contact_iam_id : each.value.owner_iam_id +} diff --git a/submodules/enterprise_hierarchy/outputs.tf b/submodules/enterprise_hierarchy/outputs.tf new file mode 100644 index 0000000..c864eb6 --- /dev/null +++ b/submodules/enterprise_hierarchy/outputs.tf @@ -0,0 +1,9 @@ +output "account_groups" { + value = ibm_enterprise_account_group.enterprise_account_group + description = "enterprise account groups" +} + +output "accounts" { + value = ibm_enterprise_account.enterprise_account + description = "enterprise accounts" +} diff --git a/submodules/enterprise_hierarchy/variables.tf b/submodules/enterprise_hierarchy/variables.tf new file mode 100644 index 0000000..913ab00 --- /dev/null +++ b/submodules/enterprise_hierarchy/variables.tf @@ -0,0 +1,29 @@ +variable "enterprise_hierarchy" { + type = map(map(object({ + name = string + parent_key_name = optional(string, null) + owner_iam_id = optional(string, null) + key_name = string + }))) + description = "tree based input for creating enterprise children" +} + +variable "enterprise_crn" { + type = string + description = "Enterprise CRN" +} + +variable "enterprise_primary_contact_iam_id" { + type = string + description = "Enterprise owner IAM id" +} + +variable "parent_account_groups" { + type = map(object({ + crn = string + name = string + parent = string + primary_contact_iam_id = string + })) + description = "account group object" +} diff --git a/submodules/enterprise_hierarchy/version.tf b/submodules/enterprise_hierarchy/version.tf new file mode 100644 index 0000000..7999c38 --- /dev/null +++ b/submodules/enterprise_hierarchy/version.tf @@ -0,0 +1,10 @@ +terraform { + required_version = ">= 1.3.0, <1.7.0" + + required_providers { + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.54.0, < 2.0.0" + } + } +} diff --git a/tests/README.md b/tests/README.md index 581aa04..dfd6842 100644 --- a/tests/README.md +++ b/tests/README.md @@ -1,8 +1,5 @@ - - # Tests For information about how to create and run tests, see [Validation tests](https://terraform-ibm-modules.github.io/documentation/#/tests) in the project documentation. - diff --git a/tests/other_test.go b/tests/other_test.go deleted file mode 100644 index d03784f..0000000 --- a/tests/other_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// 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 896d726..f4387a1 100644 --- a/tests/pr_test.go +++ b/tests/pr_test.go @@ -8,34 +8,48 @@ import ( "github.com/terraform-ibm-modules/ibmcloud-terratest-wrapper/testhelper" ) -// Use existing resource group -const resourceGroup = "geretain-test-resources" -const completeExampleDir = "examples/complete" +const basicExampleDir = "examples/basic" +const advancedExampleDir = "examples/advanced" func setupOptions(t *testing.T, prefix string, dir string) *testhelper.TestOptions { - options := testhelper.TestOptionsDefaultWithVars(&testhelper.TestOptions{ - Testing: t, - TerraformDir: dir, - Prefix: prefix, - ResourceGroup: resourceGroup, + options := testhelper.TestOptionsDefault(&testhelper.TestOptions{ + Testing: t, + TerraformDir: dir, + Prefix: prefix, }) + + options.TerraformVars = map[string]interface{}{ + "prefix": options.Prefix, + "enterprise_name": "DAF Enterprise", + } + return options } -func TestRunCompleteExample(t *testing.T) { +func TestRunBasicExample(t *testing.T) { + t.Parallel() + + options := setupOptions(t, "enterprise-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", completeExampleDir) + options := setupOptions(t, "enterprise-com", advancedExampleDir) output, err := options.RunTestConsistency() assert.Nil(t, err, "This should not have errored") assert.NotNil(t, output, "Expected some output") } -func TestRunUpgradeExample(t *testing.T) { +func TestRunUpgradeAdvancedExample(t *testing.T) { t.Parallel() - options := setupOptions(t, "mod-template-upg", completeExampleDir) + options := setupOptions(t, "enterprise-upg", advancedExampleDir) output, err := options.RunTestUpgrade() if !options.UpgradeTestSkipped { diff --git a/variables.tf b/variables.tf index d9583df..3ecf072 100644 --- a/variables.tf +++ b/variables.tf @@ -1,9 +1,32 @@ -############################################################################## +######################################################################################################################## # Input Variables -############################################################################## +######################################################################################################################## -#variable "my_variable" { -# type = string -# description = "A description of my variable" -# default = "default_value" -#} +variable "enterprise_crn" { + type = string + description = "The CRN of the parent Enterprise account to use." +} + +variable "enterprise_primary_contact_iam_id" { + type = string + description = "The IAM id of the parent Enterprise account owner." +} + + +variable "enterprise_accounts" { + description = "List of enterprise child accounts in the enterprise" + type = list(object({ name = string, key_name = string, parent_key_name = optional(string, null), owner_iam_id = optional(string, null) })) + validation { + error_message = "Accounts key_name should be unique" + condition = length(distinct(var.enterprise_accounts[*].key_name)) == length(var.enterprise_accounts[*].key_name) + } +} + +variable "enterprise_account_groups" { + description = "List of enterprise child account_groups in the enterprise" + type = list(object({ name = string, key_name = string, parent_key_name = optional(string, null), owner_iam_id = optional(string, null) })) + validation { + error_message = "Account_Groups key_name should be unique" + condition = length(distinct(var.enterprise_account_groups[*].key_name)) == length(var.enterprise_account_groups[*].key_name) + } +} diff --git a/version.tf b/version.tf index 8b7c6cf..e81677f 100644 --- a/version.tf +++ b/version.tf @@ -1,11 +1,16 @@ terraform { required_version = ">= 1.3.0, <1.7.0" - # Use a flexible range in modules that future proofs the module's usage with upcoming minor and patch versions - # required_providers { - # ibm = { - # source = "IBM-Cloud/ibm" - # version = ">= 1.49.0, < 2.0.0" - # } - # } + # 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 { + # The below tflint-ignore is required because although the below provider is not directly required by the root level module, + # it is required by consuming submodules, and if not set here, the top level module calling this module will not be + # able to set alternative alias for the provider. + + # tflint-ignore: terraform_unused_required_providers + ibm = { + source = "IBM-Cloud/ibm" + version = ">= 1.54.0, < 2.0.0" + } + } }