Create VPS in GCP via Terraform module using count - terraform

getting stuck with problem.
Need a terraform expert help. I want to create VPS in GCP with count using module. How to correct create and attach google_compute_address and google_compute_disk to each VPS with different names
Any help, please
Module code:
resource "google_compute_instance" "vps" {
count = var.server_count
name = var.server_count > 1 ? "${var.server_name}-${count.index}" : var.server_name
description = var.server_description
machine_type = var.server_type
zone = var.server_datacenter
deletion_protection = var.server_delete_protection
labels = var.server_labels
metadata = var.server_metadata
tags = var.server_tags
boot_disk {
auto_delete = false
initialize_params {
size = var.boot_volume_size
type = var.boot_volume_type
image = var.boot_volume_image
labels = var.boot_volume_labels
}
}
dynamic "attached_disk" {
for_each = var.volumes
content {
source = attached_disk.value["volume_name"]
}
}
dynamic "network_interface" {
for_each = var.server_network
content {
subnetwork = network_interface.value["subnetwork_name"]
network_ip = network_interface.value["subnetwork_ip"]
dynamic "access_config" {
for_each = network_interface.value.nat_ip ? [1] : []
content {
nat_ip = google_compute_address.static_ip.address
}
}
}
}
}
resource "google_compute_disk" "volume" {
for_each = var.volumes
name = each.value["volume_name"]
type = each.value["volume_type"]
size = each.value["volume_size"]
zone = var.server_datacenter
labels = each.value["volume_labels"]
}
resource "google_compute_address" "static_ip" {
count = var.server_count
name = var.server_count > 1 ? "${var.server_name}-${count.index}" : var.server_name
region = var.server_region
}
Using example:
module "vps-test" {
source = "../module"
credentials_file = "../../../../main/vault/prod/.tf/terraform-bb-prod-ground.json"
server_count = 2
server_name = "example-vps"
server_description = "simple vps for module testing"
server_type = "e2-small"
server_region = "europe-west4"
server_datacenter = "europe-west4-c"
server_labels = {
project = "terraform"
environment = "test"
}
server_metadata = {
groups = "parent_group.child_group"
}
boot_volume_image = "debian-cloud/debian-11"
boot_volume_size = 30
boot_volume_labels = {
environment = "production"
project = "v3"
type = "system"
}
server_tags = ["postgres", "production", "disable-gce-firewall"]
server_delete_protection = true
server_network = {
common_network = {
subnetwork_name = "${data.terraform_remote_state.network.outputs.subnetwork_vpc_production_common_name}"
subnetwork_ip = ""
nat_ip = true
} # },
# custom_network = {
# subnetwork_name = (data.terraform_remote_state.network.outputs.subnetwork_vpc_production_k8s_name)
# subnetwork_ip = ""
# nat_ip = false
# }
}
volumes = {
volume_data1 = {
volume_name = "v3-postgres-saga-import-test-storage"
volume_size = "40"
volume_type = "pd-ssd"
volume_labels = {
environment = "production"
project = "v3"
type = "storage"
}
},
volume_data2 = {
volume_name = "volume-vpstest2"
volume_size = "20"
volume_type = "pd-ssd"
volume_labels = {
environment = "production"
project = "v2"
type = "storage"
}
}
}
}
Now error is: Because google_compute_address.static_ip has "count" set, its attributes must be accessed on specific instances And i know, error with same disk name will come

Related

for each module reference between modules with a map object

im trying to create an instance group with reference to an GCE, but im unable to refer to the id from instance group to link to the GCE
variable "compute_engine_instances" {
type = map(object({
instance_name = string
machine_type = string
zone = string
tags = list(string)
image_name = string
image_project = string
labels =object({
app_id = number
cost_center = string
owner = string
email = string
})
}))
}
module "qat_hosted_pacs_compute_engines" {
source = "../modules/compute_engine"
for_each = var.compute_engine_instances
project_id = var.project_id
instance_name = each.value.instance_name
machine_type = each.value.machine_type
tags = each.value.tags
labels = each.value.labels
subnetwork = var.subnetwork
zone = each.value.zone
image_name = each.value.image_name
image_project = each.value.image_project
}
variable "instance_group" {
type = map(object({
group_manager_name = string
zone = string
}))
}
module "qat_hosted_pacs_app_grp" {
source = "../modules/instance_groups"
for_each = var.instance_group
group_manager_name = each.value.group_manager_name
zone = each.value.zone
project_id = var.project_id
instances = module.qat_hosted_pacs_compute_engines.vm_name #unable to figure out how to reference the GCE
}
#output.tf looks like this for compute engine module
output "compute_engine_instances" {
value = {
for k, v in module.qat_hosted_pacs_compute_engines : k => v.vm_name
}
}
The root module looks like this for compute engine
data "google_compute_image" "compute_image" {
name = var.image_name
project = var.image_project
}
resource "google_compute_instance" "generic_instance" {
project = var.project_id
name = var.instance_name
machine_type = var.machine_type
zone = var.zone
tags = var.tags
labels = var.labels
boot_disk {
initialize_params {
image = data.google_compute_image.compute_image.self_link
}
auto_delete = true
}
network_interface {
subnetwork = var.subnetwork
}
}
#outputs.tf here looks like this for gce resource
output "vm_name" {
value = google_compute_instance.generic_instance.id
description = "The name of the VM"
}
And the instance group manager looks like this
resource "google_compute_instance_group" "igm" {
name = var.group_manager_name
zone = var.zone
project = var.project_id
instances = var.instances
named_port {
name = "http"
port = "8080"
}
named_port {
name = "https"
port = "8443"
}
lifecycle {
create_before_destroy = true
}
}
i get the foll. error
Error: Unsupported attribute
on main.tf line 45, in module "qat_hosted_pacs_app_grp":
45: instances = module.qat_hosted_pacs_compute_engines.vm_name
|----------------
| module.qat_hosted_pacs_compute_engines is object with 2 attributes
This object does not have an attribute named "vm_name".
terraform tf vars file
compute_engine_instances ={
"test-adi"={
instance_name = "test-vm"
machine_type = "n1-standard-1"
zone = "us-east4-b"
tags = ["foo","bar"]
image_name = "gold-centos-7"
image_project = "dev-cietools"
labels = {
app_id = "56"
cost_center = "156"
owner = "ops"
email = "ops"
}}
"test-adi-2"={
instance_name = "test-vm-2"
machine_type = "n1-standard-1"
zone = "us-east4-b"
tags = ["foo","bar"]
image_name = "centos-7"
image_project = "dev-cietools"
labels = {
app_id = "56"
cost_center = "856"
owner = "ops"
email = "ops"
}
}
}
subnetwork = "sandbox-us-east4"
project_id = "cloudops-dev01-sb"
instance_group = {
"igm" = {
group_manager_name = "test"
zone = "us-east4-b"
}
}
Since you used for_each in your google_compute_instance_group module, you have to use key to refer to individual instances of the module, e.g.
instances = module.qat_hosted_pacs_compute_engines["test-adi"].vm_name
or if you want to pass all vm_name created for all values of for_each, you can do:
instances = values(module.qat_hosted_pacs_compute_engines)[*].vm_name

Terraform modules forces to define all the blocks defined in resources, is there any way to make dynamic import from resources

I am trying to create aws codepipeline using resources in TF. here is my resources section in m,y TF.
resource "aws_codepipeline" "codepipeline" {
name = var.name
role_arn = var.role_arn
artifact_store {
location = var.location
type = var.type
}
stage {
name = var.stage1_name
action {
name = var.action1_name
category = var.source_category
owner = var.source_owner
provider = var.source_provider
version = var.source_version
output_artifacts = var.source_output_artifacts
configuration = {
ConnectionArn = var.connection_arn
FullRepositoryId = var.full_repository_id
BranchName = var.branch_name
OutputArtifactFormat = var.output_artifact_format
}
}
}
stage {
name = var.stage2_name
action {
name = var.action2_name
category = var.build_category
owner = var.build_owner
provider = var.build_provider
input_artifacts = var.input_artifacts
output_artifacts = var.build_output_artifacts
version = var.build_version
configuration = {
ProjectName = var.project_name
EnvironmentVariables = var.environment_variables /*jsonencode(
[
{
name = var.environment_name
type = var.environment_type
value = var.environment_value
}
]
) */
}
}
}
}
In my TF modules section, creating codepipeline by calling the resources given above. my modules code is
module "codepipeline_notification" {
source = "../../modules/codepipeline"
name = var.codepipeline_lambda_notification_name
role_arn = aws_iam_role.cp_lambda_deploy_role.arn #var.codepipeline_lambda_notification_role_arn
location = module.s3_codepipeline_artifact.s3_bucket_account_id #var.codepipeline_lambda_notification_location
type = var.codepipeline_lambda_notification_type
stage1_name = var.codepipeline_lambda_notification_stage1_name
action1_name = var.codepipeline_lambda_notification_action1_name
source_category = var.codepipeline_lambda_notification_source_category
source_owner = var.codepipeline_lambda_notification_source_owner
source_provider = var.codepipeline_lambda_notification_source_provider
source_version = var.codepipeline_lambda_notification_source_version
source_output_artifacts = var.codepipeline_lambda_notification_source_output_artifacts
full_repository_id = var.codepipeline_lambda_notification_full_repository_id
branch_name = var.codepipeline_lambda_notification_branch_name
output_artifact_format = var.codepipeline_lambda_notification_output_artifact_format
environment_variables = jsonencode(
[
{
name = var.codepipeline_lambda_notification_environment_name
type = var.codepipeline_lambda_notification_environment_type
value = var.codepipeline_lambda_notification_environment_value
}
]
)
build_output_artifacts = var.codepipeline_lambda_notification_build_output_artifacts
connection_arn = module.codestarconnections.arn
stage2_name = var.codepipeline_lambda_notification_stage2_name
action2_name = var.codepipeline_lambda_notification_action2_name
build_category = var.codepipeline_lambda_notification_build_category
build_owner = var.codepipeline_lambda_notification_build_owner
build_provider = var.codepipeline_lambda_notification_build_provider
build_version = var.codepipeline_lambda_notification_build_version
input_artifacts = var.codepipeline_lambda_notification_input_artifacts
project_name = module.codebuild_notification.name
}
with this approach, I am trying to create 4 pipelines where one pipeline has only 2 stages and other 2 pipeline has 3 stages, If I define 3 stages in resources then Terraform forces the modules to create 3 stages in all pipelines where I need onyl two stages. Is there any way in terraform to define in resources and use the resource in modules based on condition
Not sure if you ever got an answer to your question, but yes, there is a way. It's called Dynamic Pipeline. I have a repository that walks you through the usage of the dynamic pipeline. In short, you treat the resource like a dynamic resource using each statement and passing in the configuration as a map.
The module looks like this:
resource "aws_codepipeline" "codepipeline" {
for_each = var.code_pipeline
name = "${local.name_prefix}-${var.AppName}"
role_arn = each.value["code_pipeline_role_arn"]
tags = {
Pipeline_Key = each.key
}
artifact_store {
type = lookup(each.value, "artifact_store", null) == null ? "" : lookup(each.value.artifact_store, "type", "S3")
location = lookup(each.value, "artifact_store", null) == null ? null : lookup(each.value.artifact_store, "artifact_bucket", null)
}
dynamic "stage" {
for_each = lookup(each.value, "stages", {})
iterator = stage
content {
name = lookup(stage.value, "name")
dynamic "action" {
for_each = lookup(stage.value, "actions", {}) //[stage.key]
iterator = action
content {
name = action.value["name"]
category = action.value["category"]
owner = action.value["owner"]
provider = action.value["provider"]
version = action.value["version"]
run_order = action.value["run_order"]
input_artifacts = lookup(action.value, "input_artifacts", null)
output_artifacts = lookup(action.value, "output_artifacts", null)
configuration = action.value["configuration"]
namespace = lookup(action.value, "namespace", null)
}
}
}
}
}
Executing Module
module "code_pipeline" {
source = "../module-aws-codepipeline" #using module locally
#source = "your-github-repository/aws-codepipeline" #using github repository
AppName = "My_new_pipeline"
code_pipeline = local.code_pipeline
}
Sample locals.tf with pipeline variable
locals {
/*
DECLARE enviornment variables. Note each Action does not require environment variables
*/
action_second_stage_variables = [
{
name = "PIPELINE_EXECUTION_ID"
type = "PLAINTEXT"
value = "#{codepipeline.PipelineExecutionId}"
},
{
name = "NamespaceVariable"
type = "PLAINTEXT"
value = "some_value"
},
]
action_third_stage_variables = [
{
name = "PL_VARIABLE_1"
type = "PLAINTEXT"
value = "VALUE1"
},
{
name = "PL_VARIABLE 2"
type = "PLAINTEXT"
value = "VALUE2"
},
{
name = "PL_VARIABLE_3"
type = "PLAINTEXT"
value = "VAUE3"
},
{
name = "PL_VARIABLE_4"
type = "PLAINTEXT"
value = "#{BLD.NamespaceVariable}"
},
]
/*
BUILD YOUR STAGES
*/
code_pipeline = {
codepipeline-configs = {
code_pipeline_role_arn = "arn:aws:iam::aws_account_name:role/role_name"
artifact_store = {
type = "S3"
artifact_bucket = "your-aws-bucket-name"
}
stages = {
stage_1 = {
name = "Download"
actions = {
action_1 = {
run_order = 1
category = "Source"
name = "First_Stage"
owner = "AWS"
provider = "CodeCommit"
version = "1"
output_artifacts = ["download_ouput"]
configuration = {
RepositoryName = "Codecommit_target_repo"
BranchName = "main"
PollForSourceChanges = true
OutputArtifactFormat = "CODE_ZIP"
}
}
}
}
stage_2 = {
name = "Build"
actions = {
action_1 = {
run_order = 2
category = "Build"
name = "Second_Stage"
owner = "AWS"
provider = "CodeBuild"
version = "1"
namespace = "BLD"
input_artifacts = ["Download_ouput"]
output_artifacts = ["build_outputs"]
configuration = {
ProjectName = "codebuild_project_name_for_second_stage"
EnvironmentVariables = jsonencode(local.action_second_stage_variables)
}
}
}
}
stage_3 = {
name = "Validation"
actions = {
action_1 = {
run_order = 1
name = "Third_Stage"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["build_outputs"]
output_artifacts = ["validation_outputs"]
configuration = {
ProjectName = "codebuild_project_name_for_third_stage"
EnvironmentVariables = jsonencode(local.action_third_stage_variables)
}
}
}
}
}
}
}
}
The full use of the module can be found in this GitHub repository. In your case, you could pass in multiple resources to create various pipelines in one module with unique and custom stages and actions. I hope this helps.

unknown block type dns_config

i am getting error "Blocks of type "dns_config" are not expected here" in my terraform
main.tf file. Here is my code.
I am trying this in GCP
This code is breaking at dns_config section.
provider google {
project = var.project
region = var.region
version = "4.22.0"
credentials = var.credentials
}
resource "google_container_cluster" "primary" {
name = "${var.service-name}-${lower(var.site-id)}"
location = var.region
node_locations = [var.zone]
network = var.vpc-id
subnetwork = var.subnet-id
enable_autopilot = true
initial_node_count = var.initial-node-count
dns_config {
cluster_dns = "CLOUD_DNS"
cluster_dns_domain = "cluster.qg${var.site-id}stream"
cluster_dns_scope = "CLUSTER_SCOPE"
}
ip_allocation_policy {
cluster_secondary_range_name = var.subnet-pod-ip-range-name
services_secondary_range_name = var.subnet-service-ip-range-name
}
dynamic "release_channel" {
for_each = var.release-channel != null ? [{ channel : var.release-channel }] : []
content {
channel = var.release-channel
}
}
logging_service = var.logging_service
monitoring_service = var.monitoring_service
}
terraform {
backend "pg" {}
}

How to ignore a block in terraform

I have a terraform code that is creating kubernetes cluster resource in Oracle cloud.
I want to ignore endpoint_config block when the cluster is public and execute this block when the cluster is private. How can I achieve that
resource "oci_containerengine_cluster" "cluster" {
count = var.deploy_oke_cluster ? 1 : 0
compartment_id = var.compartment_id
kubernetes_version = var.cluster_kubernetes_version
name = "oke-${var.environment}"
vcn_id = oci_core_virtual_network.base_vcn.id
endpoint_config {
is_public_ip_enabled = false
subnet_id = oci_core_subnet.snet-apiserver.id
}
options {
add_ons {
is_kubernetes_dashboard_enabled = true
is_tiller_enabled = false
}
kubernetes_network_config {
pods_cidr = var.pods_cidr
services_cidr = var.services_cidr
}
service_lb_subnet_ids = [oci_core_subnet.snet-pub-lb.id]
}
}
You can do this with dynamic blocks:
resource "oci_containerengine_cluster" "cluster" {
count = var.deploy_oke_cluster ? 1 : 0
compartment_id = var.compartment_id
kubernetes_version = var.cluster_kubernetes_version
name = "oke-${var.environment}"
vcn_id = oci_core_virtual_network.base_vcn.id
dynamic "endpoint_config" {
for_each = var.is_public == true ? [1] : []
content {
is_public_ip_enabled = false
subnet_id = oci_core_subnet.snet-apiserver.id
}
}
options {
add_ons {
is_kubernetes_dashboard_enabled = true
is_tiller_enabled = false
}
kubernetes_network_config {
pods_cidr = var.pods_cidr
services_cidr = var.services_cidr
}
service_lb_subnet_ids = [oci_core_subnet.snet-pub-lb.id]
}
}

Incrementing tag index in terraform

I am looking for a way to differentiate the tag names in my module, and know that there is a road block there as you can't use count in modules, I would like to increment my tag name, based of the position of the public subnet, how would I do this?
variable "public_subnet_count" {
default = 3
}
variable "public_subnet_name" {
default = {
0 = "cp-net0"
1 = "k8s-net0"
2 = "um-net0"
}
}
module "vpc" {
source = "github.com/terraform-aws-modules/terraform-aws-vpc"
name = "apigee"
cidr = "10.0.0.0/16"
azs = data.aws_availability_zones.available.names
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24"]
assign_generated_ipv6_cidr_block = true
enable_nat_gateway = true
single_nat_gateway = true
public_subnet_tags = {
Name = lookup(var.public_subnet_name, count.index) // will not work
}
tags = {
Owner = "212743998"
Environment = "sandbox"
}
vpc_tags = {
Name = "apigee"
}
}

Resources