ilijamt/terraform-provider-awx

Bug when applying with inconsistent result

Closed this issue · 14 comments

Hi,

When applying my plan, I get the following changes (the value of variables changed because I edited the inventory using the interface):

 # awx_inventory.this will be updated in-place
  ~ resource "awx_inventory" "this" {
      + host_filter                     = (known after apply)
        id                              = 187
        name                            = "Inventory"
      - variables                       = "---" -> null
        # (10 unchanged attributes hidden)
    }

And after aply, I obtain the following error:

│ Error: Provider produced inconsistent result after apply
│ 
│ When applying changes to awx_inventory.this, provider "provider[\"registry.opentofu.org/ilijamt/awx\"]" produced an unexpected new value:
│ .variables: was cty.StringVal(""), but now cty.StringVal("---").
│ 
│ This is a bug in the provider, which should be reported in the provider's own issue tracker.

I don't know if this is relevant, but I'm using the latest version and OpenTofu to apply the plan.
Let me know if you need more information.

Does this happen all the time?

Can you share a plan that can replicate this? So I can test and fix it. I haven't tried the provider with OpenTofu, but I will give it a try.

No, it happens only on specific case, here are the steps to reproduce the error:

  1. Apply a resource like this:
    # Create an inventory on AWX that will be used to relate with job template.
    resource "awx_inventory" "this" {
      name         = "Example inventory"
      organization = var.organization_id
    }
    
  2. Go to AWX interface and edit the created resource and save. You don't need to change something, but AWX will change the variables field to ---, which before was defined as null.
  3. Run again the terraform apply and the error will popup.

I've never worked with Go, and I'm new to the Terraform providers, but after looking at the code, the problem may be caused by variables having a default value defined: https://github.com/ilijamt/terraform-provider-awx/blob/main/internal/awx/gen_obj_inventory_resource.go#L137.

I think this could mean that if you don't define a `variables' on your inventory resource, the provider will update/create the resource with that default value, even if your intention was not to manage those variables on your terraform, and if you change the state directly on the AWX instance it will clash with the saved state.

The problem is that AWX can store the data both in JSON and in YAML format. So depending on what you chose when you start, it can be different.

So I'll fix it by storing it and converting it internally consistently to one single format. That should fix the issue.

Would you be willing to test the fix? Can you tell me what OS version you need? I'll build it and attach it to the issue so you can test it.

I'll be pleased to help, I don't know how to do it 😅, but I will look into it.
I use Ubuntu 22.04.

What does uname -a show you when you run it in the terminal?

Linux 6.5.0-18-generic #18~22.04.1-Ubuntu GNU/Linux

Create a file called .terraformrc and make sure that you put the provider in attachment in a directory you have access. In the example below it's /tmp

provider_installation {
  dev_overrides {
    "ilijamt/awx" = "/tmp"
  }

  direct {}
}

After this you can run terraform command and it will use that provider after setting up the env variable to point to that file

export TF_CLI_CONFIG_FILE=/path/to/.terraformrc

terraform-provider-awx.zip

I've tested and yes, it fixed the error when applying.

I realize what you've done, but is it the behavior intended? Furthermore, I ask this because, let's say I don't want to manage the variables in my inventory through terraform. What's happening now is that if I add variables to my inventory in the AWX interface and run the terraform plan, it suggests I change the value I entered to jsondecode({}).

OpenTofu will perform the following actions:

  # awx_inventory.this will be updated in-place
  ~ resource "awx_inventory" "this" {
      + host_filter                     = (known after apply)
        id                              = 190
        name                            = "Project inventory"
      ~ variables                       = jsonencode(
          ~ {
              - test = true
            }
        )
        # (10 unchanged attributes hidden)
    }

Ideally, and looking at the behavior that other terraform providers give, if I change the variables in my inventory directly in AWX via the interface, and I haven't explicitly declared a value for variables in the resource (example below), then the provider should simply ignore this and not change the value that was entered manually.

resource "awx_inventory" "this" {
  name         = "Project inventory"
  organization = 4
}

Isn't the whole point if you manage the items from terraform to be fully managed by terraform? I've seen a situation where a recreation from scratch didn't work because people added stuff manually to the resources, and it didn't work because of the manually managed stuff.

Also, if you check the AWX API, they provide defaults for everything you can access it on their api/v2 endpoint. Or you can see them in the repo. https://github.com/ilijamt/terraform-provider-awx/tree/main/resources/api they are in the payload directory. They are downloaded from the API so the provider can be generated.

Yes, you're right, but, if possible to use in hybrid way, I think it can be powerful and can help in some use cases.
For instance, I use terraform to manage GitLab projects, but only to ensure that all the base configurations are equal cross projects, like default protected branch, and other things. But I don't create those projects with Terraform, I instead import them to the state and apply the necessary rules. But there's configuration that are applied directly on GitLab and are not managed on the terraform state, like activate docker registry and the provider don't send that value when communicating with the API, allowing have this hybrid behavior.

Relating to the API default, the default being defined on the server side is different from being defined on the provider, because the provider has no clue if the parameter has already some value defined, and the server has that kind of power.

Maybe what I'm suggesting doesn't make sense, I don't know, I'm new to terraform 😅.

Relating to the API default, the default being defined on the server side is different from being defined on the provider, because the provider has no clue if the parameter has already some value defined, and the server has that kind of power.

The defaults are the same as server side, the provider is generated from the data provided by the API.

Yes, you're right, but, if possible to use in hybrid way, I think it can be powerful and can help in some use cases.

I need to check if that is possible, but it will be a breaking change for all the other users. The reason I build it like this is that I would prefer if it's explicit.

I've released the version so you can use the provider you need.

v23.5.1-0
v23.6.0-0
v23.7.0-0
v23.8.1-0