Nitin Kumar
Nitin Kumar

Reputation: 199

A managed resource has not been declared in module

I've a two modules under modules directory named as prienv and vpc

nnice@MPL-G8WW7D3:~/terra-test/modules/prienv$ pwd
/home/nnice/terra-test/modules/prienv
nnice@MPL-G8WW7D3:~/terra-test/modules/prienv$ ls
data.tf  main.tf  variable.tf

Here is my data.tf file under prienv module

nnice@MPL-G8WW7D3:~/terra-test/modules/prienv$ cat data.tf
data "aws_security_groups" "mysg-data" {
  filter {
    name   = "tag:Name"
    values = ["MySG"]
  }
  depends_on = [aws_security_groups.mysg]
}

data "aws_subnet" "myprisn-data" {
  filter {
    name   = "tag:Name"
    values = ["MyPriSN"]
  }
  depends_on = [aws_subnet.myprisn]
}

Here is my variable.tf file under prienv module

variable "pri_av" {
  description = "for private availability zone"
  type        = string
  default     = "us-east-1b"
}

variable "ami" {
  description = "ami for ec2"
  type        = string
  default     = "ami-03ededff12e34e59e"
}

variable "instance_type" {
  description = "Instance type t2.micro"
  type        = string
  default     = "t2.micro" #will use double quotes for string type
}

variable "key_pair" {
  description = "key pair for ec2"
  type        = string
  default     = "learner_key"
}

variable "instance_count" {
  description = "EC2 instance count"
  type        = number
  default     = 1 #here we're using it to create two private instances
}

variable "project_environment" {
  description = "project name and environment for private instances"
  type        = map(string)
  default = {
    project     = "private", # it works upon key value pair where project is for key and environment is value
    environment = "testing"  # you will find them under tag on aws console
  }
}

And this is my main.tf file under prienv module

resource "aws_instance" "mypriec2" {
  ami               = var.ami
  instance_type     = var.instance_type
  count             = var.instance_count
  availability_zone = var.pri_av
  #subnet_id              = aws_subnet.myprisn.id
  subnet_id = data.aws_subnet.myprisn-data.id
  #vpc_security_group_ids = [aws_security_group.mysg.id]
  vpc_security_group_ids = data.aws_security_groups.mysg-data.ids
  key_name               = var.key_pair
  # disable_api_termination = true
  tags = var.project_environment
}

resource "aws_key_pair" "mykeypair" {
  key_name   = var.key_pair
  public_key = "ssh-rsa AAAAB3NaffrWscf59juCakElys9F3+zVuz0ta4gRUtKgWVPIj6ACr00VNDzsTTW2/sSjYtE5zWolVKCITlhqiIhgRKUDLKoxclxUKnK6IGIafdaefafaheiufa;fdaeoasfdkQvNtGrrHzY5/dbZhIUTxDUyvT5O5U= nnice@MPL-G8WW7D3"
}

and here is my vpc moduls

nnice@MPL-G8WW7D3:~/terra-test/modules/vpc$ pwd
/home/nnice/terra-test/modules/vpc
nnice@MPL-G8WW7D3:~/terra-test/modules/vpc$ ls
data.tf  main.tf  variable.tf

This is my data.tf file under vpc module

nnice@MPL-G8WW7D3:~/terra-test/modules/vpc$ cat data.tf
data "aws_vpc" "myvpc-data" {
  filter {
    name   = "tag:Name"
    values = ["MyVPC"]
  }
  depends_on = [aws_vpc.myvpc]
}

data "aws_subnet" "mypubsn-data" {
  filter {
    name   = "tag:Name"
    values = ["MyPubSN"]
  }
  depends_on = [aws_subnet.mypubsn]
}

data "aws_subnet" "myprisn-data" {
  filter {
    name   = "tag:Name"
    values = ["MyPriSN"]
  }
  depends_on = [aws_subnet.myprisn]
}

This is my main.tf file under vpc module

nnice@MPL-G8WW7D3:~/terra-test/modules/vpc$ cat main.tf
##################################################################
############################## VPC ###############################
##################################################################

resource "aws_vpc" "myvpc" {
  cidr_block       = var.vpc_cidr
  instance_tenancy = var.vpc_tenancy

  tags = {
    Name = var.vpc_tag
  }
}

##################################################################
############################# Subnet #############################
##################################################################

#PUBLIC SUBNET
resource "aws_subnet" "mypubsn" {
  #vpc_id                 = aws_vpc.myvpc.id
  vpc_id                  = data.aws_vpc.myvpc-data.id
  cidr_block              = var.mypubsn_cidr
  availability_zone       = var.pub_av
  map_public_ip_on_launch = var.map_public_ip_on_launch
  tags = {
    Name = var.mypubsn_tag
  }
}

#PRIVATE SUBNET
resource "aws_subnet" "myprisn" {
  #vpc_id            = aws_vpc.myvpc.id
  vpc_id            = data.aws_vpc.myvpc-data.id
  cidr_block        = var.myprisn_cidr
  availability_zone = var.pri_av

  tags = {
    Name = var.myprisn_tag
  }
}

##################################################################
############################### IGW ##############################
##################################################################

resource "aws_internet_gateway" "myigw" {
  #vpc_id = aws_vpc.myvpc.id
  vpc_id = data.aws_vpc.myvpc-data.id
  tags = {
    Name = var.igw_tag
  }
}

##################################################################
############################ Route Table #########################
##################################################################

#PUBLIC RT
resource "aws_route_table" "mypubrt" {
  #vpc_id = aws_vpc.myvpc.id
  vpc_id = data.aws_vpc.myvpc-data.id

  tags = {
    Name = var.mypubsn_tag
  }
}

#PRIVATE RT
resource "aws_route_table" "myprirt" {
  #vpc_id = aws_vpc.myvpc.id
  vpc_id = data.aws_vpc.myvpc-data.id

  tags = {
    Name = var.myprisn_tag
  }
}

####################################################################
######################## Route Table Associate #####################
####################################################################

#PUBLIC RT association
resource "aws_route_table_association" "pub" {
  #subnet_id      = aws_subnet.mypubsn.id
  subnet_id      = data.aws_subnet.mypubsn-data.id
  route_table_id = aws_route_table.mypubrt.id
}

#PRIVATE RT association
resource "aws_route_table_association" "pri" {
  #subnet_id      = aws_subnet.myprisn.id
  subnet_id      = data.aws_subnet.myprisn-data.id
  route_table_id = aws_route_table.myprirt.id
}

###################################################################
########################### Route #################################
###################################################################

#PUBLIC Route
resource "aws_route" "mypubroute" {
  route_table_id         = aws_route_table.mypubrt.id
  destination_cidr_block = var.pubroute
  gateway_id             = aws_internet_gateway.myigw.id
  depends_on             = [aws_route_table.mypubrt]
}

#PRIVATE Route
#resource "aws_route" "mypriroute" {
#  route_table_id            = aws_route_table.myprirt.id
#  destination_cidr_block    = "0.0.0.0/0"
#  gateway_id             = aws_internet_gateway.myigw.id
#  depends_on                = [aws_route_table.myprirt]
#}

###################################################################
############################ SG ###################################
###################################################################

resource "aws_security_group" "mysg" {
  name        = "MySecurityGroup"
  description = "Allow TLS inbound traffic"
  #vpc_id      = aws_vpc.myvpc.id
  vpc_id = data.aws_vpc.myvpc-data.id

  ingress {
    description = "TLS from VPC"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    # cidr_blocks      = [aws_vpc.myvpc.cidr_block]
    cidr_blocks = ["0.0.0.0/0"]
    # ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }

  ingress {
    description = "TLS from VPC"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    # cidr_blocks      = [aws_vpc.myvpc.cidr_block]
    cidr_blocks = ["0.0.0.0/0"]
    # ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block]
  }

  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }

  tags = {
    Name = var.SG_tag
  }
}

And this is my variable.tf file under vpc module

nnice@MPL-G8WW7D3:~/terra-test/modules/vpc$ cat variable.tf
variable "vpc_tenancy" {
  description = "vpc instance tenancy"
  type        = string
  default     = "default"
}

variable "pub_av" {
  description = "for public availability zone"
  type        = string
  default     = "us-east-1a"
}

variable "pri_av" {
  description = "for private availability zone"
  type        = string
  default     = "us-east-1b"
}

variable "vpc_tag" {
  description = "Tag for VPC"
  type        = string
  default     = "MyVPC"
}

variable "vpc_cidr" {
  description = "for vpc cidr"
  type        = string
  default     = "10.0.0.0/16"
}

variable "mypubsn_cidr" {
  description = "for public subnet cidr"
  type        = string
  default     = "10.0.1.0/24"
}

variable "myprisn_cidr" {
  description = "for private subnet cidr"
  type        = string
  default     = "10.0.2.0/24"
}

variable "mypubsn_tag" {
  description = "tag for public subnet"
  type        = string
  default     = "MyPubSN"
}

variable "myprisn_tag" {
  description = "tag for private subnet"
  type        = string
  default     = "MyPriSN"
}

variable "igw_tag" {
  description = "tag for IGW subnet"
  type        = string
  default     = "MyIGW"
}

variable "pubrt_tag" {
  description = "tag for private subnet"
  type        = string
  default     = "MyPubRT"
}

variable "prirt_tag" {
  description = "tag for IGW subnet"
  type        = string
  default     = "MyPriRT"
}

variable "pubroute" {
  description = "cidr for public route"
  type        = string
  default     = "0.0.0.0/0"
}

variable "SG_tag" {
  description = "tag for SG"
  type        = string
  default     = "MySG"
}

variable "map_public_ip_on_launch" {
  description = "auto enable public ip to public subnet"
  type        = bool
  default     = true
}

And there is env directory where I have my main.tf file

nnice@MPL-G8WW7D3:~/terra-test$ ls
env  modules
nnice@MPL-G8WW7D3:~/terra-test$ cd env/private-ec2/
nnice@MPL-G8WW7D3:~/terra-test/env/private-ec2$ pwd
/home/nnice/terra-test/env/private-ec2
nnice@MPL-G8WW7D3:~/terra-test/env/private-ec2$ ls
main.tf
nnice@MPL-G8WW7D3:~/terra-test/env/private-ec2$ cat main.tf
#Provider

provider "aws" {
  region = "us-east-1"
}

#VPC
 
module "vpc" {
  source = "../../modules/vpc"
}

#EC2

module "prienv" {
  source = "../../modules/prienv"
}

When I'm trying to run terraform plan, I'm getting following errors

 Error: Reference to undeclared resource
│
│   on ../../modules/prienv/data.tf line 6, in data "aws_security_groups" "mysg-data":
│    6:   depends_on = [aws_security_groups.mysg]
│
│ A managed resource "aws_security_groups" "mysg" has not been declared in module.prienv.
╵
╷
│ Error: Reference to undeclared resource
│
│   on ../../modules/prienv/data.tf line 14, in data "aws_subnet" "myprisn-data":
│   14:   depends_on = [aws_subnet.myprisn]
│
│ A managed resource "aws_subnet" "myprisn" has not been declared in module.prienv.

Could anyone please let me know its solution? I already using vpc module in my main.tf file

Upvotes: 1

Views: 9227

Answers (1)

stdtom
stdtom

Reputation: 762

The issue you are running into is that aws_security_groups.mysgand aws_subnet.myprisn are locally defined in the vpc module but you are referencing them in the depends_on statement in the prienv module.

Also the Terraform documentation suggests that the depends_on argument

should be used only as a last resort.

So the way to go would be, to define the security group and the subnet as an output in the vpc module, as variable in the prienv module, and then passing the outputs of vpc as parameter values to prienv. This way terraform will recognize the dependencies between the resources from the dependency graph it creates and you won't neet the depends_on argument.

So in consequence, the diffs to your config could look like:

modules/vpc/outputs.tf

output "sec_group" {
  value       = aws_security_group.mysg
  description = "..."
}

output "subnet" {
  value       = aws_subnet.myprisn
  description = "..."
}

modules/prienv/variable.tf

variable "sec_group" {
  description = "..."
}

variable "subnet" {
  description = "..."
}

modules/prienv/main.tf

resource "aws_instance" "mypriec2" {
  ...
  subnet_id              = var.subnet.id
  vpc_security_group_ids = var.sec_group.ids
  ...
}

env/main.tf

module "vpc" {
  source = "../../modules/vpc"
}

#EC2

module "prienv" {
  source    = "../../modules/prienv"
  sec_group = module.vpc.sec_group
  subnet    = module.vpc.subnet
}

Upvotes: 2

Related Questions