gitlab_user_runner import does not populate project_id, causing forced replacement (analog of #6745)

Bug Report

Relevant Terraform Configuration

resource "gitlab_user_runner" "admins_base" {
  runner_type     = "project_type"
  project_id      = 43019853
  description     = "Admins base runner"
  untagged        = true
  tag_list        = ["admins-base"]
  maximum_timeout = 10800
}

Relevant Terraform Command

terraform plan

Relevant Log Output

gitlab_user_runner.admins_base: Refreshing state... [id=41145067]

Terraform used the selected providers to generate the following execution plan. Resource actions are
indicated with the following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # gitlab_user_runner.admins_base must be replaced
-/+ resource "gitlab_user_runner" "admins_base" {
      ~ access_level     = "not_protected" -> (known after apply)
      ~ id               = "41145067" -> (known after apply)
      ~ locked           = false -> (known after apply)
      + maintenance_note = (known after apply)
      ~ paused           = false -> (known after apply)
      + project_id       = 43019853 # forces replacement
      + token            = (sensitive value)
        # (5 unchanged attributes hidden)
    }

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

Additional Details

  • GitLab Terraform Provider Version: 19.2.0
  • GitLab Instance Version: GitLab Enterprise Edition 19.3.0-pre c0922f822a3
  • Terraform Version: v1.9.2
  • License Tier: Free|Premium|Ultimate

Bug Report

Importing an existing gitlab_user_runner does not populate the project_id attribute in state. On every subsequent terraform plan, project_id shows as a brand-new attribute (+ project_id = ... # forces replacement) rather than a value already present in state, forcing replacement

This appears to be the project_id analog of #6745 (closed). That fix does not appear to cover the project_id case.

Root cause appears to be that the underlying GitLab API endpoint (GET /runners/:id) does not return a project_id (or any other single "owning project") field at all. Confirmed via:

glab api "runners/<runner_id>" | jq '{project_id, owner_project, projects: (.projects | length)}'

which returns:

{
  "project_id": null,
  "owner_project": null,
  "projects": 187
}

Runner was originally created under the old gitlab_runner resource (registration-token flow), then migrated to gitlab_user_runner as part of upgrading the provider from 18.1.1 to 19.2.0, and imported via:

terraform state rm gitlab_user_runner.admins_base
terraform import gitlab_user_runner.admins_base 41145067

terraform state show gitlab_user_runner.admins_base immediately after import shows project_id missing:

resource "gitlab_user_runner" "admins_base" {
    access_level     = "not_protected"
    description      = "Admins base runner"
    id               = "41145067"
    locked           = false
    maintenance_note = null
    maximum_timeout  = 10800
    paused           = false
    runner_type      = "project_type"
    tag_list         = [
        "admins-base",
    ]
    untagged         = true
}

Implementation Plan

  • Follow the CONTRIBUTING.md guide for setting up your local development environment.
  • Clone the community fork of this project.
  • Add runner_id as a new attribute to internal/provider/resource_gitlab_user_runner.go as a duplicate of the existing ID.
  • Add a warning notice to the resource description about the ID changing in 20.0 and to use runner_id if you are using the resource id for any reason.
  • Amend the Import function to take a custom ID. It needs to detect and handle the import ID containing an optional runner type, an optional namespace id and the runner id. For example:
    • Project type:project-id:runner-id -> "project:123:999"
    • Group type:group-id:runner-id -> "group:456:999"
    • Instance type:runner-id -> "instance:999"
    • Basic runner-id -> "999"
  • Add specific import tests to cover all four combinations.
Edited by 🤖 GitLab Bot 🤖