diff --git a/backend.tf b/backend.tf new file mode 100644 index 0000000..d0252b1 --- /dev/null +++ b/backend.tf @@ -0,0 +1,9 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "4.12.0" + } + } + required_version = ">= 1.6.3" +} diff --git a/cosmos_db_database_container.tf b/cosmos_db_database_container.tf new file mode 100644 index 0000000..8ff9181 --- /dev/null +++ b/cosmos_db_database_container.tf @@ -0,0 +1,46 @@ +resource "azurerm_cosmosdb_sql_container" "main" { + name = var.cosmosdb_sql_database_container_name + resource_group_name = data.azurerm_cosmosdb_account.main.resource_group_name + account_name = data.azurerm_cosmosdb_account.main.name + database_name = var.cosmosdb_sql_database_name + partition_key_paths = var.cosmosdb_sql_database_container_partition_key_paths + partition_key_version = var.cosmosdb_sql_database_container_partition_key_version + default_ttl = var.default_ttl != null ? var.default_ttl : null + + dynamic "unique_key" { + for_each = var.unique_keys != null ? var.unique_keys : [] + content { + paths = unique_key.value["paths"] + } + } + + dynamic "conflict_resolution_policy" { + for_each = var.conflict_resolution_policy != null ? [var.conflict_resolution_policy] : [] + content { + mode = conflict_resolution_policy.value["mode"] + conflict_resolution_path = conflict_resolution_policy.value["conflict_resolution_path"] + } + } + + dynamic "indexing_policy" { + for_each = var.indexing_policy != null ? [var.indexing_policy] : [] + content { + indexing_mode = indexing_policy.value["indexing_mode"] + + dynamic "included_path" { + for_each = indexing_policy.value["included_paths"] != null ? indexing_policy.value["included_paths"] : [] + content { + path = included_path.value["path"] + } + } + + dynamic "excluded_path" { + for_each = indexing_policy.value["excluded_paths"] != null ? indexing_policy.value["excluded_paths"] : [] + content { + path = excluded_path.value["path"] + } + } + + } + } +} diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..31aee00 --- /dev/null +++ b/main.tf @@ -0,0 +1,10 @@ +data "azurerm_client_config" "current" {} + +data "azurerm_resource_group" "rg" { + name = var.resource_group_name +} + +data "azurerm_cosmosdb_account" "main" { + name = var.cosmosdb_account_name + resource_group_name = data.azurerm_resource_group.rg.name +} diff --git a/output.tf b/output.tf new file mode 100644 index 0000000..392c99d --- /dev/null +++ b/output.tf @@ -0,0 +1,5 @@ +output "id" { + description = "The CosmosDB Database container ID." + value = azurerm_cosmosdb_sql_container.main.id + sensitive = false +} diff --git a/pipelines/azure-pipelines-pr.yaml b/pipelines/azure-pipelines-pr.yaml new file mode 100644 index 0000000..9d7f7ff --- /dev/null +++ b/pipelines/azure-pipelines-pr.yaml @@ -0,0 +1,80 @@ +name: $(MODULE_NAME)-$(date:yyyyMMdd)-$(rev:.r) +trigger: none +pr: + branches: + include: + - refs/heads/master + - refs/heads/main +resources: + repositories: + - repository: self +variables: + - name: TERRAFORM_SEC_VERSION + value: "v1.26.0" + - name: GITHUB_REPO + value: "Think-Cube/terraform-azure-cosmosdb-database-container" + - group: GITHUB-PAT-TOKEN + - name: VM_IMAGE + value: ubuntu-latest + - name: MODULE_NAME + value: "terraform-azure-cosmosdb-database-container" +pool: + vmImage: $(VM_IMAGE) +stages: + - stage: Validate_Terraform_Module + displayName: 'Validate Terraform Module' + jobs: + - job: Validate_Terraform_Module + displayName: 'Validate Terraform Module' + steps: + - checkout: self + displayName: 'Checkout Module' + fetchDepth: 1 + - task: TerraformCLI@0 + displayName: 'Terraform Init' + inputs: + command: 'init' + allowTelemetryCollection: false + - task: TerraformCLI@0 + displayName: 'Terraform Validate' + inputs: + command: 'validate' + allowTelemetryCollection: false + - task: tfsec@1 + displayName: 'Terraform SEC check' + inputs: + version: '$(TERRAFORM_SEC_VERSION)' + dir: '$(System.DefaultWorkingDirectory)' + - script: | + cd /tmp + curl -sSLo /tmp/terraform-docs.tar.gz https://terraform-docs.io/dl/v0.19.0/terraform-docs-v0.19.0-$(uname)-amd64.tar.gz + tar -xzf /tmp/terraform-docs.tar.gz + chmod +x /tmp/terraform-docs + displayName: 'Download terraform-docs' + - script: | + # Variables + github_token="$(GITHUB_TOKEN)" + # Generate or update README.md + /tmp/terraform-docs markdown table . > README.md + + # Check if README.md has been updated or created and add to PR + if [ -f README.md ]; then + echo "README.md file generated/updated." + git config --global user.email "devops-bot@example.com" + git config --global user.name "DevOps Bot" + git add README.md + git commit -m "Update README.md with module documentation" + + # Set remote URL with authentication token + git remote set-url origin https://$(GITHUB_TOKEN)@github.com/Think-Cube/terraform-azure-cosmosdb-database-container.git + + # Pull the latest changes to avoid conflicts (source branch of the PR) + git pull origin $(System.PullRequest.SourceBranch) --rebase + + # Push changes + git push origin HEAD:$(System.PullRequest.SourceBranch) + else + echo "Failed to generate README.md" + exit 1 + fi + displayName: 'Generate and Update README.md Documentation' diff --git a/pipelines/azure-pipelines.yaml b/pipelines/azure-pipelines.yaml new file mode 100644 index 0000000..d0c6b34 --- /dev/null +++ b/pipelines/azure-pipelines.yaml @@ -0,0 +1,117 @@ +name: $(MODULE_NAME)-$(date:yyyyMMdd)-$(rev:.r) +parameters: +- name: publish_module + displayName: 'Publish Module ???' + type: string + default: 'false' + values: + - true + - false +trigger: + branches: + include: + - refs/heads/master + - refs/heads/main +resources: + repositories: + - repository: self +variables: + - name: TERRAFORM_SEC_VERSION + value: "v1.26.0" + - name: GITHUB_REPO + value: "Think-Cube/terraform-azure-cosmosdb-database-container" + - group: GITHUB-PAT-TOKEN + - name: PUBLISH_MODULE + value: ${{parameters.publish_module}} + - name: VM_IMAGE + value: ubuntu-latest + - name: MODULE_NAME + value: "terraform-azure-cosmosdb-database-container" + - name: MODULE_DESCRIPTION + value: "Terraform module for azure cosmosdb database container" +pool: + vmImage: $(VM_IMAGE) +stages: + - stage: Validate_Terraform_Module + displayName: 'Validate Terraform Module' + jobs: + - job: Validate_Terraform_Module + displayName: 'Validate Terraform Module' + steps: + - checkout: self + displayName: 'Checkout Module' + fetchDepth: 1 + - task: CmdLine@2 + displayName: 'Terraform Init' + inputs: + script: | + terraform init + workingDirectory: '$(System.DefaultWorkingDirectory)' + - task: CmdLine@2 + displayName: 'Terraform Validate' + inputs: + script: | + terraform validate + workingDirectory: '$(System.DefaultWorkingDirectory)' + - task: tfsec@1 + displayName: 'Terraform SEC check' + inputs: + version: '$(TERRAFORM_SEC_VERSION)' + dir: '$(System.DefaultWorkingDirectory)' + - stage: Publish_Terraform_Module + condition: eq('${{parameters.publish_module}}', 'true') + displayName: 'Publish Terraform Module' + jobs: + - job: Publish_Terraform_Module + displayName: 'Publish Terraform Module' + steps: + - checkout: self + - task: CopyFiles@2 + displayName: 'Copy Terraform module files' + inputs: + SourceFolder: $(System.DefaultWorkingDirectory) + Contents: '**.tf' + TargetFolder: $(System.DefaultWorkingDirectory)/$(MODULE_NAME) + - task: CmdLine@2 + displayName: 'Fetch latest version and increment' + inputs: + script: | + # Variables + module_path="$(System.DefaultWorkingDirectory)/$(MODULE_NAME)" + github_repo="$(GITHUB_REPO)" + github_token="$(GITHUB_TOKEN)" + description="New $(MODULE_DESCRIPTION) release" + + # Remove unnecessary files from the module directory + find "$module_path" -name ".git" -type d -exec rm -rf {} + + find "$module_path" -name ".github" -type d -exec rm -rf {} + + + # Fetch the latest tag and increment version + latest_tag=$(git tag --list "v*" | sort -V | tail -n1) + new_version="0.0.1" + if [ -n "$latest_tag" ]; then + IFS='.' read -r major minor patch <<< "${latest_tag#v}" + if (( patch < 999 )); then + patch=$((patch + 1)) + else + patch=0 + if (( minor < 999 )); then + minor=$((minor + 1)) + else + minor=0 + major=$((major + 1)) + fi + fi + new_version="$major.$minor.$patch" + fi + + # Create a tarball of the module + tarball_name="$(MODULE_NAME)-v$new_version.tar.gz" + tar -czf "$tarball_name" -C "$module_path" . + + # Publish to GitHub Releases using gh CLI + echo "$github_token" | gh auth login --with-token + gh release create "v$new_version" "$tarball_name" \ + --repo "$github_repo" \ + --title "$(MODULE_NAME) v$new_version" \ + --notes "$description" diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..2a35f36 --- /dev/null +++ b/variables.tf @@ -0,0 +1,85 @@ +variable "environment" { + description = "The environment name used for backend container naming (e.g., dev, staging, prod)." + type = string + default = "dev" +} + +variable "resource_group_location" { + description = "The Azure location where the resource group is created. Changing this value forces the creation of a new resource." + type = string + default = "West Europe" +} + +variable "resource_group_name" { + description = "The name of the resource group in which to create the Cosmos DB SQL container. Changing this value forces the creation of a new resource." + type = string +} + +variable "cosmosdb_account_name" { + description = "The name of the Cosmos DB account. Changing this value forces the creation of a new resource." + type = string +} + +variable "cosmosdb_sql_database_name" { + description = "The name of the Cosmos DB SQL database. Changing this value forces the creation of a new resource." + type = string +} + +variable "cosmosdb_sql_database_container_name" { + description = "The name of the Cosmos DB SQL container to be created." + type = string +} + +variable "cosmosdb_sql_database_container_partition_key_paths" { + description = "A list of partition key paths for the Cosmos DB SQL container. Partition keys are essential for scalable performance in Cosmos DB." + type = list(string) + default = ["/myPartitionKey"] +} + +variable "cosmosdb_sql_database_container_partition_key_version" { + description = "The version of the partition key for the Cosmos DB SQL container. Defaults to 1." + type = number + default = 1 +} + +variable "sql_database_container_paths" { + description = "List of Cosmos DB SQL containers to create. Some parameters are inherited from the Cosmos DB account." + type = string +} + +variable "conflict_resolution_policy" { + description = "The conflict resolution policy for the Cosmos DB SQL container, which determines how conflicting changes are resolved." + type = object({ + mode = string # E.g., 'LastWriterWins' or 'Custom'. + conflict_resolution_path = string # Path used for resolving conflicts, applicable for 'LastWriterWins' mode. + }) + default = null +} + +variable "unique_keys" { + description = "A list of unique keys for the Cosmos DB SQL container to ensure uniqueness of specified paths." + type = list(object({ + paths = list(string) # Paths defining the unique key constraints. + })) + default = null +} + +variable "indexing_policy" { + description = "The indexing policy for the Cosmos DB SQL container, which specifies how items are indexed for queries." + type = object({ + indexing_mode = string # Either 'consistent' or 'none'. + included_paths = list(object({ + path = string # Paths explicitly included in the index. + })) + excluded_paths = list(object({ + path = string # Paths explicitly excluded from the index. + })) + }) + default = null +} + +variable "default_ttl" { + description = "Default time-to-live (TTL) for the Cosmos DB SQL container, specified in seconds. If null, TTL is not configured." + type = number + default = null +}