DontShaveTheYak / cf2tf

Convert Cloudformation templates to Terraform.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ValueError: Fn::Sub not allowed to be nested in Fn::Equals.

cl33n opened this issue · comments

Template is from the AWS X-Ray sample app (cf-resources.yaml, converted to txt, attached.)
cf-resources.txt

Python 3.12.2
cf2tf version 0.6.2 output:
out.txt

commented

This has been fixed in release v0.7.0. You can upgrade with pip install -U cf2tf

Here is your converted template:

data "aws_caller_identity" "current" {}

data "aws_region" "current" {}

locals {
  UseT2MicroInstance = anytrue([anytrue(["${data.aws_region.current.name}" == "us-east-1", "${data.aws_region.current.name}" == "us-east-2", "${data.aws_region.current.name}" == "us-west-1", "${data.aws_region.current.name}" == "us-west-2", "${data.aws_region.current.name}" == "ap-south-1", "${data.aws_region.current.name}" == "ap-northeast-3", "${data.aws_region.current.name}" == "ap-northeast-2", "${data.aws_region.current.name}" == "ap-southeast-1", "${data.aws_region.current.name}" == "ap-southeast-2", "${data.aws_region.current.name}" == "ap-northeast-1"]), anytrue(["${data.aws_region.current.name}" == "ca-central-1", "${data.aws_region.current.name}" == "eu-central-1", "${data.aws_region.current.name}" == "eu-west-1", "${data.aws_region.current.name}" == "eu-west-2", "${data.aws_region.current.name}" == "eu-west-3", "${data.aws_region.current.name}" == "sa-east-1", "${data.aws_region.current.name}" == "cn-northwest-1"])])
  CreateEC2LCWithKeyPair = !var.key_name == ""
  SetEndpointToECSAgent = !var.ecs_endpoint == ""
  CreateNewSecurityGroup = var.security_group_id == ""
  CreateNewVpc = var.vpc_id == ""
  CreateSubnet1 = alltrue([
  !var.subnet_cidr1 == "",
  local.CreateNewVpc
])
  CreateSubnet2 = alltrue([
  !var.subnet_cidr2 == "",
  local.CreateSubnet1
])
  CreateSubnet3 = alltrue([
  !var.subnet_cidr3 == "",
  local.CreateSubnet2
])
  CreateWithSpot = var.use_spot == "true"
  CreateWithASG = !local.CreateWithSpot
  CreateWithSpotPrice = !var.spot_price == ""
  IsConfiguringRootVolume = var.configure_root_volume == "true"
  IsConfiguringDataVolume = var.configure_data_volume == "true"
  IsInheritPublicIp = var.auto_assign_public_ip == "INHERIT"
  stack_name = "cf-resources"
}

variable email {
  type = string
  default = "UPDATE_ME"
}

variable frontend_image_uri {
  type = string
  default = "public.ecr.aws/xray/scorekeep-frontend:latest"
}

variable backend_image_uri {
  type = string
  default = "public.ecr.aws/xray/scorekeep-api:latest"
}

variable ecs_cluster_name {
  description = "Specifies the ECS Cluster Name with which the resources would be associated
"
  type = string
  default = "scorekeep-cluster"
}

variable ecs_ami_id {
  description = "AMI ID"
  type = string
  default = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended/image_id"
}

variable ecs_instance_type_t2 {
  description = "Specifies the EC2 instance type for your container instances. Defaults to t2.micro.
"
  type = string
  default = "t2.micro"
}

variable ecs_instance_type_t3 {
  description = "Specifies the EC2 instance type for your container instances. Defaults to t3.micro.
"
  type = string
  default = "t3.micro"
}

variable key_name {
  description = "Optional - Specifies the name of an existing Amazon EC2 key pair to enable SSH access to the EC2 instances in your cluster.
"
  type = string
}

variable vpc_id {
  description = "Optional - Specifies the ID of an existing VPC in which to launch your container instances. If you specify a VPC ID, you must specify a list of existing subnets in that VPC. If you do not specify a VPC ID, a new VPC is created with atleast 1 subnet.
"
  type = string
}

variable subnet_ids {
  description = "Optional - Specifies the Comma separated list of existing VPC Subnet Ids where ECS instances will run
"
  type = string
}

variable security_group_id {
  description = "Optional - Specifies the Security Group Id of an existing Security Group. Leave blank to have a new Security Group created
"
  type = string
}

variable vpc_cidr {
  description = "Optional - Specifies the CIDR Block of VPC"
  type = string
  default = "10.173.0.0/16"
}

variable subnet_cidr1 {
  description = "Specifies the CIDR Block of Subnet 1"
  type = string
  default = "10.173.0.0/24"
}

variable subnet_cidr2 {
  description = "Specifies the CIDR Block of Subnet 2"
  type = string
  default = "10.173.1.0/24"
}

variable subnet_cidr3 {
  description = "Specifies the CIDR Block of Subnet 3"
  type = string
}

variable asg_max_size {
  description = "Specifies the number of instances to launch and register to the cluster. Defaults to 1.
"
  type = string
  default = "1"
}

variable iam_role_instance_profile {
  description = "Specifies the Name or the Amazon Resource Name (ARN) of the instance profile associated with the IAM role for the instance
"
  type = string
  default = "ScorekeepInstanceProfile"
}

variable security_ingress_from_port {
  description = "Optional - Specifies the Start of Security Group port to open on ECS instances - defaults to port 0
"
  type = string
  default = "80"
}

variable security_ingress_to_port {
  description = "Optional - Specifies the End of Security Group port to open on ECS instances - defaults to port 65535
"
  type = string
  default = "80"
}

variable security_ingress_cidr_ip {
  description = "Optional - Specifies the CIDR/IP range for Security Ports - defaults to 0.0.0.0/0
"
  type = string
  default = "0.0.0.0/0"
}

variable ecs_endpoint {
  description = "Optional - Specifies the ECS Endpoint for the ECS Agent to connect to
"
  type = string
}

variable root_ebs_volume_size {
  description = "Optional - Specifies the Size in GBs of the root EBS volume
"
  type = string
  default = 30
}

variable ebs_volume_size {
  description = "Optional - Specifies the Size in GBs of the data storage EBS volume used by the Docker in the AL1 ECS-optimized AMI
"
  type = string
  default = 22
}

variable ebs_volume_type {
  description = "Optional - Specifies the Type of (Amazon EBS) volume"
  type = string
  default = "gp2"
}

variable root_device_name {
  description = "Optional - Specifies the device mapping for the root EBS volume."
  type = string
  default = "/dev/xvda"
}

variable device_name {
  description = "Optional - Specifies the device mapping for the EBS volume used for data storage. Only applicable to AL1."
  type = string
  default = "/dev/xvdcz"
}

variable use_spot {
  type = string
  default = "false"
}

variable iam_spot_fleet_role_arn {
  type = string
}

variable spot_price {
  type = string
}

variable spot_allocation_strategy {
  type = string
  default = "diversified"
}

variable user_data {
  type = string
  default = "#!/bin/bash
echo ECS_CLUSTER=scorekeep-cluster >> /etc/ecs/ecs.config;echo ECS_BACKEND_HOST= >> /etc/ecs/ecs.config;
"
}

variable is_windows {
  type = string
  default = "false"
}

variable configure_root_volume {
  description = "Optional - Specifies if there should be customization of the root volume"
  type = string
  default = "true"
}

variable configure_data_volume {
  description = "Optional - Specifies if there should be customization of the data volume"
  type = string
  default = "false"
}

variable auto_assign_public_ip {
  type = string
  default = "INHERIT"
}

resource "aws_ecs_task_definition" "scorekeep_task_definition" {
  container_definitions = [
    {
      Cpu = "256"
      Image = var.frontend_image_uri
      MemoryReservation = "256"
      Name = "scorekeep-frontend"
      PortMappings = [
        {
          ContainerPort = "80"
        }
      ]
    },
    {
      Cpu = "512"
      Environment = [
        {
          Name = "AWS_REGION"
          Value = "${data.aws_region.current.name}"
        },
        {
          Name = "NOTIFICATION_TOPIC"
          Value = "arn:aws:sns:${data.aws_region.current.name}:${data.aws_caller_identity.current.account_id}:scorekeep-notifications"
        },
        {
          Name = "NOTIFICATION_EMAIL"
          Value = var.email
        }
      ]
      Image = var.backend_image_uri
      MemoryReservation = "512"
      Name = "scorekeep-api"
      PortMappings = [
        {
          ContainerPort = "5000"
        }
      ]
    },
    {
      Cpu = "256"
      Essential = true
      Image = "amazon/aws-xray-daemon"
      MemoryReservation = "128"
      Name = "xray-daemon"
      PortMappings = [
        {
          ContainerPort = "2000"
          HostPort = "2000"
          Protocol = "udp"
        }
      ]
    }
  ]
  cpu = "1024"
  execution_role_arn = aws_iam_role.ecs_execution_role.arn
  family = "scorekeep"
  memory = "900"
  network_mode = "host"
  requires_compatibilities = [
    "EC2"
  ]
  task_role_arn = "scorekeepRole"
}

resource "aws_dynamodb_table" "user_table" {
  name = "scorekeep-user"
  // CF Property(KeySchema) = {
  //   HashKeyElement = {
  //     AttributeName = "id"
  //     AttributeType = "S"
  //   }
  // }
  // CF Property(ProvisionedThroughput) = {
  //   ReadCapacityUnits = 2
  //   WriteCapacityUnits = 2
  // }
}

resource "aws_dynamodb_table" "session_table" {
  name = "scorekeep-session"
  // CF Property(KeySchema) = {
  //   HashKeyElement = {
  //     AttributeName = "id"
  //     AttributeType = "S"
  //   }
  // }
  // CF Property(ProvisionedThroughput) = {
  //   ReadCapacityUnits = 2
  //   WriteCapacityUnits = 2
  // }
}

resource "aws_dynamodb_table" "game_table" {
  name = "scorekeep-game"
  attribute = [
    {
      name = "id"
      type = "S"
    },
    {
      name = "session"
      type = "S"
    }
  ]
  // CF Property(KeySchema) = [
  //   {
  //     AttributeName = "id"
  //     KeyType = "HASH"
  //   }
  // ]
  global_secondary_index = [
    {
      name = "session-index"
      non_key_attributes = [
        {
          AttributeName = "session"
          KeyType = "HASH"
        }
      ]
      ProvisionedThroughput =       // CF Property(ProvisionedThroughput) = {
      //   ReadCapacityUnits = 2
      //   WriteCapacityUnits = 2
      // }
      projection_type = {
        ProjectionType = "ALL"
      }
    }
  ]
  // CF Property(ProvisionedThroughput) = {
  //   ReadCapacityUnits = 2
  //   WriteCapacityUnits = 2
  // }
}

resource "aws_dynamodb_table" "move_table" {
  name = "scorekeep-move"
  attribute = [
    {
      name = "id"
      type = "S"
    },
    {
      name = "game"
      type = "S"
    }
  ]
  // CF Property(KeySchema) = [
  //   {
  //     AttributeName = "id"
  //     KeyType = "HASH"
  //   }
  // ]
  global_secondary_index = [
    {
      name = "game-index"
      non_key_attributes = [
        {
          AttributeName = "game"
          KeyType = "HASH"
        }
      ]
      ProvisionedThroughput =       // CF Property(ProvisionedThroughput) = {
      //   ReadCapacityUnits = 2
      //   WriteCapacityUnits = 2
      // }
      projection_type = {
        ProjectionType = "ALL"
      }
    }
  ]
  // CF Property(ProvisionedThroughput) = {
  //   ReadCapacityUnits = 2
  //   WriteCapacityUnits = 2
  // }
}

resource "aws_dynamodb_table" "state_table" {
  name = "scorekeep-state"
  attribute = [
    {
      name = "id"
      type = "S"
    },
    {
      name = "game"
      type = "S"
    }
  ]
  // CF Property(KeySchema) = [
  //   {
  //     AttributeName = "id"
  //     KeyType = "HASH"
  //   }
  // ]
  global_secondary_index = [
    {
      name = "game-index"
      non_key_attributes = [
        {
          AttributeName = "game"
          KeyType = "HASH"
        }
      ]
      ProvisionedThroughput =       // CF Property(ProvisionedThroughput) = {
      //   ReadCapacityUnits = 2
      //   WriteCapacityUnits = 2
      // }
      projection_type = {
        ProjectionType = "ALL"
      }
    }
  ]
  // CF Property(ProvisionedThroughput) = {
  //   ReadCapacityUnits = 2
  //   WriteCapacityUnits = 2
  // }
}

resource "aws_sns_topic" "notification_topic" {
  name = "scorekeep-notifications"
}

resource "aws_iam_role" "ecs_execution_role" {
  assume_role_policy = {
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = [
            "ecs-tasks.amazonaws.com"
          ]
        }
        Action = [
          "sts:AssumeRole"
        ]
      }
    ]
  }
  managed_policy_arns = [
    "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly"
  ]
  name = "scorekeepExecutionRole"
}

resource "aws_iam_role" "ecs_task_role" {
  assume_role_policy = {
    Version = "2012-10-17"
    Statement = [
      {
        Effect = "Allow"
        Principal = {
          Service = [
            "ecs-tasks.amazonaws.com"
          ]
        }
        Action = [
          "sts:AssumeRole"
        ]
      }
    ]
  }
  managed_policy_arns = [
    "arn:aws:iam::aws:policy/AmazonDynamoDBFullAccess",
    "arn:aws:iam::aws:policy/AmazonSNSFullAccess",
    "arn:aws:iam::aws:policy/AWSXrayFullAccess"
  ]
  name = "scorekeepRole"
}

resource "aws_iam_role" "scorekeep_ecs_role" {
  name = "ScorekeepECSRole"
  assume_role_policy = {
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Principal = {
          Service = [
            "ec2.amazonaws.com"
          ]
        }
        Effect = "Allow"
      }
    ]
  }
  managed_policy_arns = [
    "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
  ]
}

resource "aws_iam_instance_profile" "scorekeep_instance_profile" {
  name = var.iam_role_instance_profile
  role = [
    "ScorekeepECSRole"
  ]
}

resource "aws_ecs_cluster" "scorekeep_ecs_cluster" {
  name = var.ecs_cluster_name
}

resource "aws_vpc" "vpc" {
  count = local.CreateSubnet1 ? 1 : 0
  cidr_block = var.vpc_cidr
  enable_dns_support = true
  enable_dns_hostnames = true
  tags = {
    Name = join("_", [local.stack_name])
  }
}

resource "aws_subnet" "pub_subnet_az1" {
  count = local.CreateSubnet1 ? 1 : 0
  vpc_id = aws_vpc.vpc[0].arn
  cidr_block = var.subnet_cidr1
  availability_zone = element(data.aws_availability_zones.available.names, 0)
  map_public_ip_on_launch = true
}

resource "aws_subnet" "pub_subnet_az2" {
  count = local.CreateSubnet2 ? 1 : 0
  vpc_id = aws_vpc.vpc[0].arn
  cidr_block = var.subnet_cidr2
  availability_zone = element(data.aws_availability_zones.available.names, 1)
  map_public_ip_on_launch = true
}

resource "aws_subnet" "pub_subnet_az3" {
  count = local.CreateSubnet3 ? 1 : 0
  vpc_id = aws_vpc.vpc[0].arn
  cidr_block = var.subnet_cidr3
  availability_zone = element(data.aws_availability_zones.available.names, 2)
  map_public_ip_on_launch = true
}

resource "aws_internet_gateway" "internet_gateway" {
  count = local.CreateSubnet1 ? 1 : 0
}

resource "aws_vpn_gateway_attachment" "attach_gateway" {
  count = local.CreateSubnet1 ? 1 : 0
  vpc_id = aws_internet_gateway.internet_gateway[0].id
}

resource "aws_route_table" "route_via_igw" {
  count = local.CreateSubnet1 ? 1 : 0
  vpc_id = aws_vpc.vpc[0].arn
}

resource "aws_route" "public_route_via_igw" {
  count = local.CreateSubnet1 ? 1 : 0
  route_table_id = aws_route_table.route_via_igw[0].id
  destination_cidr_block = "0.0.0.0/0"
  gateway_id = aws_internet_gateway.internet_gateway[0].id
}

resource "aws_route_table_association" "pub_subnet1_route_table_association" {
  count = local.CreateSubnet1 ? 1 : 0
  subnet_id = aws_subnet.pub_subnet_az1[0].id
  route_table_id = aws_route_table.route_via_igw[0].id
}

resource "aws_route_table_association" "pub_subnet2_route_table_association" {
  count = local.CreateSubnet2 ? 1 : 0
  subnet_id = aws_subnet.pub_subnet_az2[0].id
  route_table_id = aws_route_table.route_via_igw[0].id
}

resource "aws_route_table_association" "pub_subnet3_route_table_association" {
  count = local.CreateSubnet3 ? 1 : 0
  subnet_id = aws_subnet.pub_subnet_az3[0].id
  route_table_id = aws_route_table.route_via_igw[0].id
}

resource "aws_security_group" "ecs_security_group" {
  count = local.CreateNewSecurityGroup ? 1 : 0
  description = "ECS Allowed Ports"
  vpc_id = local.CreateSubnet1 ? aws_vpc.vpc[0].arn : var.vpc_id
  ingress = [
    {
      protocol = "tcp"
      from_port = "80"
      to_port = "80"
      cidr_blocks = "0.0.0.0/0"
    }
  ]
}

resource "aws_launch_configuration" "ecs_instance_lc" {
  count = local.CreateWithASG ? 1 : 0
  image_id = var.ecs_ami_id
  instance_type = element(local.UseT2MicroInstance ? var.ecs_instance_type_t2 : var.ecs_instance_type_t3, 0)
  associate_public_ip_address = local.IsInheritPublicIp ? null : var.auto_assign_public_ip
  iam_instance_profile = var.iam_role_instance_profile
  key_name = local.CreateEC2LCWithKeyPair ? var.key_name : null
  security_groups = [
    local.CreateNewSecurityGroup ? aws_security_group.ecs_security_group[0].arn : var.security_group_id
  ]
  ebs_block_device = [
        // local.IsConfiguringRootVolume ? {
    //   DeviceName = var.root_device_name
    //   Ebs = {
    //     VolumeSize = var.root_ebs_volume_size
    //     VolumeType = var.ebs_volume_type
    //   }
    // } : null,
        // local.IsConfiguringRootVolume ? {
    //   DeviceName = var.root_device_name
    //   Ebs = {
    //     VolumeSize = var.root_ebs_volume_size
    //     VolumeType = var.ebs_volume_type
    //   }
    // } : null,
        // local.IsConfiguringDataVolume ? {
    //   DeviceName = var.device_name
    //   Ebs = {
    //     VolumeSize = var.ebs_volume_size
    //     VolumeType = var.ebs_volume_type
    //   }
    // } : null,
        // local.IsConfiguringDataVolume ? {
    //   DeviceName = var.device_name
    //   Ebs = {
    //     VolumeSize = var.ebs_volume_size
    //     VolumeType = var.ebs_volume_type
    //   }
    // } : null
  ]
  user_data = base64encode(var.user_data)
}

resource "aws_autoscalingplans_scaling_plan" "ecs_instance_asg" {
  count = local.CreateWithASG ? 1 : 0
  // CF Property(VPCZoneIdentifier) = local.CreateSubnet1 ? local.CreateSubnet2 ? local.CreateSubnet3 ? [
  //   "${aws_subnet.pub_subnet_az1[0].id}, ${aws_subnet.pub_subnet_az2[0].id}, ${aws_subnet.pub_subnet_az3[0].id}"
  // ] : [
  //   "${aws_subnet.pub_subnet_az1[0].id}, ${aws_subnet.pub_subnet_az2[0].id}"
  // ] : [
  //   "${aws_subnet.pub_subnet_az1[0].id}"
  // ] : var.subnet_ids
  name = aws_launch_configuration.ecs_instance_lc[0].id
  min_capacity = "0"
  max_capacity = var.asg_max_size
  predictive_scaling_max_capacity_behavior = var.asg_max_size
  target_tracking_configuration = [
    aws_lb_target_group_attachment.scorekeep_target_group.id
  ]
  // CF Property(tags) = {
  //   Name = "ECS Instance - ${local.stack_name}"
  //   Description = "This instance is the part of the Auto Scaling group which was created through ECS Console"
  // }
}

resource "aws_ecs_service" "scorekeep_service" {
  cluster = "scorekeep-cluster"
  // CF Property(DeploymentConfiguration) = {
  //   MaximumPercent = 100
  //   MinimumHealthyPercent = 0
  // }
  desired_count = 1
  launch_type = "EC2"
  scheduling_strategy = "REPLICA"
  name = "scorekeep-service"
  task_definition = aws_ecs_task_definition.scorekeep_task_definition.arn
}

resource "aws_lb_target_group_attachment" "scorekeep_target_group" {
  // CF Property(Name) = "ScorekeepTargetGroup"
  // CF Property(TargetType) = "instance"
  port = 80
  // CF Property(Protocol) = "HTTP"
  target_id = aws_vpc.vpc[0].arn
}

resource "aws_load_balancer_listener_policy" "scorekeep_load_balancer" {
  load_balancer_name = "scorekeep-lb"
  // CF Property(Scheme) = "internet-facing"
  // CF Property(SecurityGroups) = [
  //   aws_security_group.ecs_security_group[0].arn
  // ]
  // CF Property(Subnets) = local.CreateSubnet1 ? local.CreateSubnet2 ? local.CreateSubnet3 ? [
  //   aws_subnet.pub_subnet_az1[0].id,
  //   aws_subnet.pub_subnet_az2[0].id,
  //   aws_subnet.pub_subnet_az3[0].id
  // ] : [
  //   aws_subnet.pub_subnet_az1[0].id,
  //   aws_subnet.pub_subnet_az2[0].id
  // ] : [
  //   aws_subnet.pub_subnet_az1[0].id
  // ] : var.subnet_ids
  // CF Property(Type) = "application"
  // CF Property(tags) = {
  //   Name = join("_", [local.stack_name])
  // }
}

resource "aws_load_balancer_listener_policy" "scorekeep_load_balancer_listener" {
  // CF Property(DefaultActions) = [
  //   {
  //     Type = "forward"
  //     TargetGroupArn = aws_lb_target_group_attachment.scorekeep_target_group.id
  //   }
  // ]
  load_balancer_name = aws_load_balancer_listener_policy.scorekeep_load_balancer.id
  load_balancer_port = 80
  // CF Property(Protocol) = "HTTP"
}

output "load_balancer_url" {
  description = "The URL of the ALB"
  value = aws_load_balancer_listener_policy.scorekeep_load_balancer.load_balancer_name
}