Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

instance_profile error with invalid count on first apply #194

Open
wesleung opened this issue Apr 30, 2024 · 4 comments
Open

instance_profile error with invalid count on first apply #194

wesleung opened this issue Apr 30, 2024 · 4 comments
Labels
bug 🐛 An issue with the system

Comments

@wesleung
Copy link

wesleung commented Apr 30, 2024

Describe the Bug

Input instance_profile will throw the below error on apply

│ Error: Invalid count argument
│ 
│   on .terraform/modules/instance/main.tf line 85, in data "aws_iam_instance_profile" "given":
│   85:   count = local.enabled && var.instance_profile_enabled && var.instance_profile != "" ? 1 : 0
│ 
│ The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work
│ around this, use the -target argument to first apply only the resources that the count depends on.
╵
╷
│ Error: Invalid count argument
│ 
│   on .terraform/modules/instance/main.tf line 96, in resource "aws_iam_role" "default":
│   96:   count                = var.instance_profile_enabled ? local.instance_profile_count : 0
│ 
│ The "count" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will be created. To work
│ around this, use the -target argument to first apply only the resources that the count depends on.

Expected Behavior

Expected behavior is that the instance will use the precreated instance profile

Steps to Reproduce

resource "aws_iam_role" "default" {
  depends_on = [aws_iam_policy.default]
  name = "test-role"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": [
          "ec2.amazonaws.com"
        ]
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

resource "aws_iam_policy" "default" {
  name        = "test-policy"
  path        = "/"
  description = "IAM  Policy"

  policy = jsonencode({
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": "s3:ListBucket",
            "Resource": *,
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:PutObject*",
                "s3:GetObject*",
                "s3:DeleteObject*"
            ],
            "Resource": *,
            "Effect": "Allow"
        }
    ]
})
}

resource "aws_iam_role_policy_attachment" "default" {
  depends_on = [aws_iam_policy.default, aws_iam_role.default ]
  policy_arn = aws_iam_policy.default.arn
  role       = aws_iam_role.default.name
}

resource "aws_iam_role_policy_attachment" "ssm_attach" {
  role       = aws_iam_role.default.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

resource "aws_iam_instance_profile" "default" {
  name        = "${var.aws_profile}-${local.service}"
  role        = aws_iam_role.default.name
  depends_on  = [aws_iam_policy.default, aws_iam_role.default, aws_iam_role_policy_attachment.default ]
}

Module

module "instance" {
  source  = "cloudposse/ec2-instance/aws"
  version = "1.4.0"

  ssh_key_pair                = var.ssh_key_pair
  instance_type               = var.instance_type
  instance_profile      = aws_iam_instance_profile.default.id
  vpc_id                      = var.vpc_id
  security_groups             = var.security_groups
  subnet                      = var.subnet
  name                        = "ec2"
}

Will throw the earlier Error "Invalid count argument"
Comment instance_profile and it will work

module "instance" {
  source  = "cloudposse/ec2-instance/aws"
  version = "1.4.0"

  ssh_key_pair                = var.ssh_key_pair
  instance_type               = var.instance_type
  #instance_profile      = aws_iam_instance_profile.default.id
  vpc_id                      = var.vpc_id
  security_groups             = var.security_groups
  subnet                      = var.subnet
  name                        = "ec2"
}

After initial apply, you can then un-comment instance_profile and it will apply

module "instance" {
  source  = "cloudposse/ec2-instance/aws"
  version = "1.4.0"

  ssh_key_pair                = var.ssh_key_pair
  instance_type               = var.instance_type
  instance_profile      = aws_iam_instance_profile.default.id
  vpc_id                      = var.vpc_id
  security_groups             = var.security_groups
  subnet                      = var.subnet
  name                        = "ec2"
}

Screenshots

No response

Environment

Mac OS
TF 1.8.2

Additional Context

No response

@wesleung wesleung added the bug 🐛 An issue with the system label Apr 30, 2024
@irl
Copy link
Contributor

irl commented Nov 23, 2024

I am still seeing this error with the 1.6.0 tag.

OpenTofu v1.8.5
on darwin_arm64
+ provider registry.opentofu.org/hashicorp/aws v5.77.0

@irl
Copy link
Contributor

irl commented Nov 23, 2024

The cause is:

https://github.com/cloudposse/terraform-aws-ec2-instance/blame/8e754f8620742138c7fea981dc3ec77230b73685/main.tf#L6

locals {
  instance_profile_count = module.this.enabled && var.instance_profile_enabled && var.instance_profile == "" ? 1 : 0
}

This is then subsequently used as a count, but it depends on knowing the name of the instance profile before it can be calculated. If your instance profile name is being generated by a module, rather than by declaring the resource directly in the same module as occurs in the example used for testing, then this causes the error as seen above.

The only workaround currently seems to be if you can predict the name of the created profile and just have that as a string literal passed to the instance_profile variable.

@nitrocode
Copy link
Member

Or you can change it to

locals {
-  instance_profile_count = module.this.enabled && var.instance_profile_enabled && var.instance_profile == "" ? 1 : 0
+  instance_profile_count = module.this.enabled && var.instance_profile_enabled ? 1 : 0
}

Also side note that it seems like a bug that var.instance_profile == "" is part of the condition to enable the instance profile. Sounds more like it should be !=. However, even if it were, it would most likely still cause OP's error.

@irl
Copy link
Contributor

irl commented Nov 25, 2024

I don't think that is a bug. There are three modes:

  • no instance profile should be used (var.instance_profile_enabled == false)
  • a default instance profile should be created and used (var.instance_profile_enabled && var.instance_profile == "")
  • a given instance profile should be used and no default created (var.instance_profile_enabled && var.instance_profile != "")

I think breaking those last two out with a boolean flag like create_instance_profile and assigning it the name in var.instance_profile, or simply using var.instance_profile if creation is disabled, would be the way to go. But this would be a breaking change as it modifies the semantics of the inputs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 An issue with the system
Projects
None yet
Development

No branches or pull requests

3 participants