outscale / terraform-provider-outscale

Mozilla Public License 2.0
28 stars 30 forks source link

Load balancer attributes and listener rules on different modules destroy each other on update #84

Open Startouf opened 2 years ago

Startouf commented 2 years ago

Terraform Version

Terraform v1.1.6
on darwin_amd64
+ provider registry.terraform.io/outscale-dev/outscale v0.5.2

Terraform Configuration Files

# On one terragrunt module
# /tf/env/[dev|prod]/outscale/networking/terragtunt.hcl exporting outputs of load balancer for second module
# /tf/modules/outscale/networking/load_balancer.tf
resource "outscale_load_balancer" "app_load_balancer" {
  load_balancer_name = "${var.project}-${var.environment}-lb"
  # Need one subnet but available everywhere
  subnets = [
    outscale_subnet.public_1.subnet_id,
  ]
  load_balancer_type = "internet-facing"

  # HTTP -> HTTPS redirection
  listeners {
    backend_port = 8080
    backend_protocol = "HTTP"
    load_balancer_protocol = "HTTP"
    load_balancer_port = 80
  }

  # SSL Termination at load balancer
  listeners {
    backend_port = 8080
    backend_protocol = "HTTP"
    load_balancer_protocol = "HTTPS"
    load_balancer_port = 443
    server_certificate_id = var.certificate_arn
    /* server_certificate_id = data.outscale_server_certificate.app_load_balancer_certificate.id */
  }

  security_groups = [outscale_security_group.app_lb_security_group.security_group_id]

  dynamic "tags" {
    for_each = merge(local.tags, {"name" = "${var.project}-${var.environment}-public-lb"})
    content {
      key = tags.key
      value = tags.value
    }
  }

  depends_on = [
    outscale_route_table_link.route_table_link_public_subnet_1,
    outscale_route_table_link.route_table_link_public_subnet_2,
    outscale_route.public_subnets_internet_route,
  ]
}

resource "outscale_load_balancer_attributes" "app_load_balancer_health_check" {
  load_balancer_name = outscale_load_balancer.app_load_balancer.id
  health_check {
    healthy_threshold   = 3
    check_interval      = 30
    path                = "/healthcheck"
    port                = 8080
    protocol            = "HTTP"
    timeout             = 5
    unhealthy_threshold = 5
  }
}

# On a second terragrunt module
# /tf/env/[dev|prod]/outscale/apps/terragtunt.hcl importing output of previous module
# /tf/modules/outscale/apps/load_balancer_rules.tf
resource "outscale_load_balancer_listener_rule" "app_load_balancer_rule" {
  listener  {
    load_balancer_name = var.load_balancer_name
    load_balancer_port = 443
  }
  listener_rule {
    action             = "forward"
    listener_rule_name = "fullstack-app-listener-rule"
    host_name_pattern  = "app.*"
    priority           = 1
  }
  vm_ids = [outscale_vm.rails_fullstack_app_1.vm_id]
}

Crash Output : N/A

Expected Behavior

Suppose you have two terraform modules defining Module 1 (networking with VPS, etc. + load balancer + load balancer main listeners + healthcheck Module 2 (listener rules for applications)

The module 1 is applied first, and then the second is applied on top (config is DRYed with terragrunt)

Now suppose you have to make changes to the module A (like changing healthcheck config, etc), then when updating the module 1, changes should be applied without conflicting with module 2 since the attributes changed are different

I infer that trying to keep the base networking infrastructure in one TF module and setting up application specific listener rules in a different module is not really supported anyways, but this would be an interesting use case. Or do you have some other approach to suggest ?

Actual Behavior

The module 1 is applied first, and then the second is applied on top (config is DRYed with terragrunt) After making changes to the module A (like changing healthcheck config, etc), then when updating the module 1, all listener rules from the module 2 are destroyed and need to be re-applied, but this causes problem wince the state was not updated (since this is a different module) and it complains with errors

Error: can't find listener rule │ │ with outscale_load_balancer_listener_rule.app_load_balancer_rule, │ on load_balancer_rules.tf line 1, in resource "outscale_load_balancer_listener_rule" "app_load_balancer_rule": │ 1: resource "outscale_load_balancer_listener_rule" "app_load_balancer_rule" { │

Then I have to manually clean the state of the second module, and then only I can reinstall the listener rules

terraform state rm outscale_load_balancer_listener_rule.app_load_balancer_rule

Steps to Reproduce

cd module 1
terraform apply
cd module 2
terraform apply
cd module 1 
# [make some changes : like changing healthcheck interval]
terraform apply
cd module 2
terraform apply

Debug Output

Here is waht happens on my console (sorry fulls logs not available yet, I will do this when I have time)

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of Terraform since the
last "terraform apply":

  # outscale_load_balancer.app_load_balancer has changed
  ~ resource "outscale_load_balancer" "app_load_balancer" {
      ~ health_check                         = {
          ~ "healthy_threshold"   = "10" -> "3"
          ~ "protocol"            = "TCP" -> "HTTP"
          ~ "unhealthy_threshold" = "2" -> "5"
            # (4 unchanged elements hidden)
        }
        id                                   = "mjg-outscale-dev-lb"
        # (12 unchanged attributes hidden)

        # (8 unchanged blocks hidden)
    }

  # outscale_load_balancer_attributes.app_load_balancer_logs has changed
  ~ resource "outscale_load_balancer_attributes" "app_load_balancer_logs" {
        id                                   = "mjg-outscale-dev-lb"
      ~ listeners                            = [
            {
                backend_port           = 8080
                backend_protocol       = "HTTP"
                load_balancer_port     = 80
                load_balancer_protocol = "HTTP"
                policy_names           = []
                server_certificate_id  = ""
            },
          ~ {
              ~ server_certificate_id  = "XXXXX"
                # (5 unchanged elements hidden)
            },
        ]
        # (9 unchanged attributes hidden)

      ~ health_check {
          ~ healthy_threshold   = "10" -> "3"
          ~ protocol            = "TCP" -> "HTTP"
          ~ unhealthy_threshold = "2" -> "5"
            # (4 unchanged attributes hidden)
        }

        # (7 unchanged blocks hidden)
    }

Unless you have made equivalent changes to your configuration, or ignored the
relevant attributes using ignore_changes, the following plan may include
actions to undo or respond to these changes.

─────────────────────────────────────────────────────────────────────────────

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # outscale_load_balancer.app_load_balancer will be updated in-place
  ~ resource "outscale_load_balancer" "app_load_balancer" {
        id                                   = "mjg-outscale-dev-lb"
        # (13 unchanged attributes hidden)

      + listeners {
          + backend_port           = 8080
          + backend_protocol       = "HTTP"
          + load_balancer_port     = 443
          + load_balancer_protocol = "HTTPS"
          + policy_names           = (known after apply)
          + server_certificate_id  = "[CHANGED]"
        }
      - listeners {
          - backend_port           = 8080 -> null
          - backend_protocol       = "HTTP" -> null
          - load_balancer_port     = 443 -> null
          - load_balancer_protocol = "HTTPS" -> null
          - policy_names           = [] -> null
          - server_certificate_id  = "[XXX]" -> null
        }
      - listeners {
          - backend_port           = 8080 -> null
          - backend_protocol       = "HTTP" -> null
          - load_balancer_port     = 80 -> null
          - load_balancer_protocol = "HTTP" -> null
          - policy_names           = [] -> null
        }
      + listeners {
          + backend_port           = 8080
          + backend_protocol       = "HTTP"
          + load_balancer_port     = 80
          + load_balancer_protocol = "HTTP"
          + policy_names           = []
        }

        # (6 unchanged blocks hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

outscale_load_balancer.app_load_balancer: Modifying... [id=mjg-outscale-dev-lb]
outscale_load_balancer.app_load_balancer: Modifications complete after 1s [id=mjg-outscale-dev-lb]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

Additional Context

References

outscale-toa commented 2 years ago

Hello @Startouf,

Thanks for reaching us, we are looking at your issue

Best regards,

outscale-rce commented 1 month ago

We do not know or use Terragrunt, so this needs to be tested in your particular context.