ValueError: Unable to solve nested GetAttr Endpoint.Address
rkhyd opened this issue · comments
Not able to convert the yml file with the above error. The file i am trying to convert is attached.
root@cicd:~# cf2tf MoodleQuickStart.yml >main.tf // Converting MoodleQuickStart.yml to Terraform! Traceback (most recent call last): File "/usr/local/bin/cf2tf", line 8, in <module> sys.exit(cli()) File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 1130, in __call__ return self.main(*args, **kwargs) File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 1055, in main rv = self.invoke(ctx) File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 1404, in invoke return ctx.invoke(self.callback, **ctx.params) File "/usr/local/lib/python3.8/dist-packages/click/core.py", line 760, in invoke return __callback(*args, **kwargs) File "/usr/local/lib/python3.8/dist-packages/cf2tf/app.py", line 44, in cli config = TemplateConverter(tmpl_path.stem, cf_template, search_manger).convert() File "/usr/local/lib/python3.8/dist-packages/cf2tf/convert.py", line 94, in convert tf_resources = self.convert_to_tf(self.manifest) File "/usr/local/lib/python3.8/dist-packages/cf2tf/convert.py", line 146, in convert_to_tf tf_resources.extend(converter(resources)) File "/usr/local/lib/python3.8/dist-packages/cf2tf/convert.py", line 380, in convert_outputs resolved_args = self.resolve_values(converted_args, functions.ALL_FUNCTIONS) File "/usr/local/lib/python3.8/dist-packages/cf2tf/convert.py", line 181, in resolve_values data[key] = self.resolve_values( File "/usr/local/lib/python3.8/dist-packages/cf2tf/convert.py", line 193, in resolve_values return allowed_func[key](self, value) File "/usr/local/lib/python3.8/dist-packages/cf2tf/conversion/expressions.py", line 428, in get_att return nested_attr(tf_name, tf_type, prop, attribute_name) File "/usr/local/lib/python3.8/dist-packages/cf2tf/conversion/expressions.py", line 438, in nested_attr raise ValueError(f"Unable to solve nested GetAttr {cf_prop}") ValueError: Unable to solve nested GetAttr Endpoint.Address
@rkhyd Thanks for opening this issue. I have looked into it and found the reason why its not working. I will push a fix in the next few days, but here is the rendered template for now.
locals {
stack_name = "MoodleQuickStart"
}
variable "user_prefix" {
description = "Unique ID to be used as resource prefix"
type = string
default = "moodleIOMAD"
}
variable "moodle_volume_size" {
description = "Storage volume size (GB)"
type = string
default = "30"
}
variable "keypair_name" {
description = "Name of the previously created keypair"
type = string
}
variable "db_username" {
description = "Username for MySQL database access"
type = string
}
variable "db_password" {
description = "Password MySQL database access"
type = string
}
resource "aws_iam_user" "plugin_user" {
name = "${var.user_prefix}-moodle-pluginuser"
// CF Property(Groups) = [
// aws_iam_group.moodle_group.id
// ]
}
resource "aws_iam_group" "moodle_group" {
name = "${var.user_prefix}-moodle-group"
// CF Property(ManagedPolicyArns) = [
// aws_fms_policy.moodle_managed_policy.id
// ]
}
resource "aws_iam_user" "moodle_repo_user" {
name = "${var.user_prefix}-moodle-repouser"
// CF Property(Groups) = [
// aws_iam_group.moodle_group.id
// ]
}
resource "aws_s3_bucket" "bucket_images" {
bucket = "${var.user_prefix}-moodle-s3-images"
}
resource "aws_s3_bucket" "bucket_videos" {
bucket = "${var.user_prefix}-moodle-s3-videos"
}
resource "aws_s3_bucket" "bucket_documents" {
bucket = "${var.user_prefix}-moodle-s3-documents"
}
resource "aws_fms_policy" "moodle_managed_policy" {
name = "${var.user_prefix}-moodle-iam-policy"
delete_all_policy_resources = {
Version = "2012-10-17"
Statement = [
{
Sid = "VisualEditor0"
Effect = "Allow"
Action = [
"s3:GetAccessPoint",
"s3:PutAccountPublicAccessBlock",
"s3:GetAccountPublicAccessBlock",
"s3:ListAllMyBuckets",
"s3:ListAccessPoints",
"s3:ListJobs",
"s3:ListBucket",
"s3:CreateJob",
"s3:HeadBucket"
]
Resource = "*"
},
{
Sid = "VisualEditor1"
Effect = "Allow"
Action = [
"s3:PutAnalyticsConfiguration",
"s3:GetObjectVersionTagging",
"s3:DeleteAccessPoint",
"s3:CreateBucket",
"s3:ReplicateObject",
"s3:GetObjectAcl",
"s3:GetBucketObjectLockConfiguration",
"s3:DeleteBucketWebsite",
"s3:PutLifecycleConfiguration",
"s3:GetObjectVersionAcl",
"s3:PutBucketAcl",
"s3:DeleteObject",
"s3:GetBucketPolicyStatus",
"s3:GetObjectRetention",
"s3:GetBucketWebsite",
"s3:PutReplicationConfiguration",
"s3:PutObjectLegalHold",
"s3:GetObjectLegalHold",
"s3:GetBucketNotification",
"s3:PutBucketCORS",
"s3:DeleteBucketPolicy",
"s3:GetReplicationConfiguration",
"s3:ListMultipartUploadParts",
"s3:PutObject",
"s3:GetObject",
"s3:PutBucketNotification",
"s3:DescribeJob",
"s3:PutBucketLogging",
"s3:PutObjectVersionAcl",
"s3:GetAnalyticsConfiguration",
"s3:PutBucketObjectLockConfiguration",
"s3:GetObjectVersionForReplication",
"s3:PutAccessPointPolicy",
"s3:CreateAccessPoint",
"s3:GetLifecycleConfiguration",
"s3:GetInventoryConfiguration",
"s3:GetBucketTagging",
"s3:PutAccelerateConfiguration",
"s3:DeleteObjectVersion",
"s3:GetBucketLogging",
"s3:ListBucketVersions",
"s3:RestoreObject",
"s3:GetAccelerateConfiguration",
"s3:GetBucketPolicy",
"s3:PutEncryptionConfiguration",
"s3:GetEncryptionConfiguration",
"s3:GetObjectVersionTorrent",
"s3:AbortMultipartUpload",
"s3:GetBucketRequestPayment",
"s3:GetAccessPointPolicyStatus",
"s3:UpdateJobPriority",
"s3:GetObjectTagging",
"s3:GetMetricsConfiguration",
"s3:DeleteBucket",
"s3:PutBucketVersioning",
"s3:PutObjectAcl",
"s3:GetBucketPublicAccessBlock",
"s3:ListBucketMultipartUploads",
"s3:PutBucketPublicAccessBlock",
"s3:PutMetricsConfiguration",
"s3:UpdateJobStatus",
"s3:GetBucketVersioning",
"s3:GetBucketAcl",
"s3:BypassGovernanceRetention",
"s3:PutInventoryConfiguration",
"s3:GetObjectTorrent",
"s3:ObjectOwnerOverrideToBucketOwner",
"s3:PutBucketWebsite",
"s3:PutBucketRequestPayment",
"s3:PutObjectRetention",
"s3:GetBucketCORS",
"s3:PutBucketPolicy",
"s3:DeleteAccessPointPolicy",
"s3:GetBucketLocation",
"s3:GetAccessPointPolicy",
"s3:ReplicateDelete",
"s3:GetObjectVersion"
]
Resource = [
"arn:aws:s3:::${var.user_prefix}-moodle-s3-videos/*",
"arn:aws:s3:::${var.user_prefix}-moodle-s3-documents/*",
"arn:aws:s3:::${var.user_prefix}-moodle-s3-images/*"
]
}
]
}
}
resource "aws_db_instance" "moodle_rds" {
vpc_security_group_ids = [
aws_security_group.db_sec_group.id,
aws_security_group.db_sec_group.arn
]
publicly_accessible = False
identifier = "MoodleDbInstance"
db_name = "awsmoodle"
instance_class = "db.t2.micro"
allocated_storage = 20
engine = "MySQL"
engine_version = "8.0.16"
name = var.db_username
password = var.db_password
db_subnet_group_name = aws_db_subnet_group.bd_subnet_group.id
}
resource "aws_security_group" "web_sec_group" {
name = "${var.user_prefix}-moodle-ec2-secgrp-web"
description = "Security group for web server"
ingress = [
{
cidr_blocks = "0.0.0.0/0"
description = "Web"
protocol = "tcp"
from_port = 80
to_port = 80
},
{
cidr_blocks = "0.0.0.0/0"
description = "SSH"
protocol = "tcp"
from_port = 22
to_port = 22
},
{
cidr_blocks = "0.0.0.0/0"
description = "Web Secure"
protocol = "tcp"
from_port = 443
to_port = 443
}
]
vpc_id = aws_vpc.vpc.arn
}
resource "aws_instance" "moodle_web_server" {
instance_type = "t3.small"
key_name = "${var.keypair_name}"
// CF Property(ImageId) = "ami-0cfc497d94c6f79b2"
tags = [
{
Key = "Name"
Value = "${var.user_prefix}-moodle-webserver"
}
]
vpc_security_group_ids = [
aws_security_group.web_sec_group.arn
]
ebs_block_device = [
{
DeviceName = "/dev/xvda"
Ebs = {
VolumeType = "standard"
DeleteOnTermination = "true"
VolumeSize = "${var.moodle_volume_size}"
}
}
]
subnet_id = aws_subnet.public_subnet1.id
}
resource "aws_eip" "moodle_eip" {
// CF Property(Domain) = "vpc"
instance = aws_instance.moodle_web_server.arn
}
resource "aws_security_group" "db_sec_group" {
description = "Security group of DB"
ingress = [
{
cidr_blocks = "${aws_instance.moodle_web_server.private_ip}/32"
description = "MySQL"
protocol = "tcp"
from_port = 3306
to_port = 3306
}
]
vpc_id = aws_vpc.vpc.arn
}
resource "aws_subnet" "private_subnet1" {
availability_zone = "us-east-1a"
cidr_block = "10.1.5.0/24"
map_public_ip_on_launch = False
tags = [
{
Key = "Name"
Value = join("", ["PrivateSubnet1 / ", local.stack_name])
},
{
Key = "SubnetType"
Value = "Private"
}
]
vpc_id = aws_vpc.vpc.arn
}
resource "aws_subnet" "private_subnet2" {
availability_zone = "us-east-1b"
cidr_block = "10.1.6.0/24"
map_public_ip_on_launch = False
tags = [
{
Key = "Name"
Value = join("", ["PrivateSubnet2 / ", local.stack_name])
},
{
Key = "SubnetType"
Value = "Private"
}
]
vpc_id = aws_vpc.vpc.arn
}
resource "aws_route_table_association" "private_subnet1_route_table_association" {
route_table_id = aws_route_table.private_route_table.id
subnet_id = aws_subnet.private_subnet1.id
}
resource "aws_route_table_association" "private_subnet2_route_table_association" {
route_table_id = aws_route_table.private_route_table.id
subnet_id = aws_subnet.private_subnet2.id
}
resource "aws_subnet" "public_subnet1" {
availability_zone = "us-east-1a"
cidr_block = "10.1.1.0/24"
map_public_ip_on_launch = False
tags = [
{
Key = "Name"
Value = join("", ["PublicSubnet1 / ", local.stack_name])
},
{
Key = "SubnetType"
Value = "Public"
}
]
vpc_id = aws_vpc.vpc.arn
}
resource "aws_route_table_association" "public_subnet1_route_table_association" {
route_table_id = aws_route_table.public_route_table.id
subnet_id = aws_subnet.public_subnet1.id
}
resource "aws_internet_gateway" "internet_gateway" {
tags = [
{
Key = "Name"
Value = join("", ["InternetGateway / ", local.stack_name])
}
]
}
resource "aws_ec2_transit_gateway_vpc_attachment" "attach_internet_gateway" {
vpc_id = aws_vpc.vpc.arn
}
resource "aws_route_table" "private_route_table" {
tags = [
{
Key = "Name"
Value = join("", ["PrivateRouteTable / ", local.stack_name])
},
{
Key = "Network"
Value = "Private"
}
]
vpc_id = aws_vpc.vpc.arn
}
resource "aws_route" "public_route" {
route_table_id = aws_route_table.public_route_table.id
destination_cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.internet_gateway.id
}
resource "aws_route_table" "public_route_table" {
tags = [
{
Key = "Name"
Value = join("", ["PublicRouteTable / ", local.stack_name])
},
{
Key = "Network"
Value = "Public"
}
]
vpc_id = aws_vpc.vpc.arn
}
resource "aws_vpc" "vpc" {
cidr_block = "10.1.0.0/16"
enable_dns_hostnames = True
enable_dns_support = True
tags = [
{
Key = "Name"
Value = join("", ["Vpc / ", local.stack_name])
}
]
}
resource "aws_db_subnet_group" "bd_subnet_group" {
description = "RDS Database Subnet Group for Moodle"
subnet_ids = [
aws_subnet.private_subnet1.id,
aws_subnet.private_subnet2.id
]
tags = [
{
Key = "Name"
Value = join("", ["Moodle / ", local.stack_name])
}
]
}
output "plugin_user" {
description = "User for Moodle S3 plugin"
value = aws_iam_user.plugin_user.arn
}
output "repo_user" {
description = "User to manage S3 content"
value = aws_iam_user.moodle_repo_user.arn
}
output "version" {
description = "Latest update of the template"
value = "Dec 1, 2021"
}
output "documents" {
description = "Bucket name to store documents"
value = aws_s3_bucket.bucket_documents.id
}
output "videos" {
description = "Bucket para almacenar videos"
value = aws_s3_bucket.bucket_videos.id
}
output "images" {
description = "Bucket to store images"
value = aws_s3_bucket.bucket_images.id
}
output "moodle_dns" {
description = "Moodle Public IP"
value = aws_eip.moodle_eip.allocation_id
}
output "rds_mysql_dns" {
description = "RDS connection DNS"
value = aws_db_instance.moodle_rds.address
}
output "rds_mysql_port" {
description = "RDS connection port"
value = aws_db_instance.moodle_rds.port
}
Note that this conversion will still need some manual adjustment. I noticed that the internet gateway attachment converted to a transit gateway attachment. So you will want to fix that. You will also need to fix some of the cloudformation properties that failed to convert to terraform. They have been left commented out like // CF Property(Domain) = "vpc"
.