gitlab_project_variable: a version 0 state with a two-part ID is upgraded to a quoted scope and drops out of state
Bug Report
When a gitlab_project_variable is still at schema version 0 in the state with a two-part <project>:<key> ID, the first plan with 17.9.0 or later wants to create it again although it still exists in GitLab, and the apply fails and leaves it out of the state.
The version 0 upgrader builds the new ID with fmt.Sprintf("%s:%s:%s", project, key, environmentScope), where environmentScope is a types.String, which %s prints in Go quotes, so 123:MY_KEY becomes 123:MY_KEY:"*" (L334-341). Read then filters on "*", quotes included, gets a 404 and removes the resource from the state (L168-194).
16.0.0 and earlier wrote version 0, and a two-part ID comes from an import by <project>:<key>. The SDK upgrader added in 16.0.1 joined the plain scope; the framework one that replaced it in 17.9.0 adds the quotes. A three-part ID is not affected.
Steps to reproduce
- With provider
15.11.0, import an existing variable by its two-part ID,terraform import gitlab_project_variable.example '28:MY_KEY', with the configuration below. The state holds it at schema version 0 with"id": "28:MY_KEY". - Change the provider version to
19.5.0, then runterraform init -upgradeandterraform plan.
I reproduced it with Terraform 1.4.0 against GitLab CE 19.5.0.
Current behaviour
The refresh reads the variable as 28:MY_KEY:"*", finds nothing, and the plan wants to create it. terraform apply then fails with (MY_KEY) has already been taken, and the variable is no longer in the state.
Expected behaviour
The state is upgraded to the ID 28:MY_KEY:*, and the plan shows no changes.
Workaround
Once the variable is out of the state (after that apply, or with terraform state rm), import it again by its three-part ID: terraform import gitlab_project_variable.example '28:MY_KEY:*'. With 19.5.0 the plan then shows no changes.
Relevant Terraform Configuration
The main.tf I ran, with the token left out; step 1 used the same file with version = "15.11.0".
terraform {
required_providers {
gitlab = {
source = "gitlabhq/gitlab"
version = "19.5.0"
}
}
}
provider "gitlab" {
base_url = "http://127.0.0.1:18524/api/v4"
token = "<token>"
}
resource "gitlab_project_variable" "example" {
project = "28"
key = "MY_KEY"
value = "my_value"
}Relevant Terraform Command
terraform planRelevant Log Output
terraform plan and terraform apply with 19.5.0, on the state 15.11.0 wrote:
gitlab_project_variable.example: Refreshing state... [id=28:MY_KEY:"*"]
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
# gitlab_project_variable.example will be created
+ resource "gitlab_project_variable" "example" {
+ description = (known after apply)
+ environment_scope = "*"
+ hidden = (known after apply)
+ id = (known after apply)
+ key = "MY_KEY"
+ masked = (known after apply)
+ project = "28"
+ protected = (known after apply)
+ raw = (known after apply)
+ value = "my_value"
+ variable_type = (known after apply)
}
Plan: 1 to add, 0 to change, 0 to destroy.gitlab_project_variable.example: Creating...
Error: GitLab API error occurred
with gitlab_project_variable.example,
on main.tf line 15, in resource "gitlab_project_variable" "example":
15: resource "gitlab_project_variable" "example" {
Unable to create project variable: POST
http://127.0.0.1:18524/api/v4/projects/28/variables: 400 {message: {key:
[(MY_KEY) has already been taken]}}Additional Details
- GitLab Terraform Provider Version:
17.9.0and later; reproduced with19.5.0and withmainat dba01c37 - GitLab Instance Version:
19.5.0(CE) - Terraform Version:
1.4.0 - License Tier:
Free
Possible fix
Build the ID from data.EnvironmentScope.ValueString() in the upgrader. I have a merge request ready for it.