DontShaveTheYak / cf2tf

Convert Cloudformation templates to Terraform.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

MoodleQuickStart.zip

commented

@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".