Skip to content

by_config_toml: duplicate [runners.feature_flags] when an unmanaged section already exists #444

Description

@cchaudier

Origin of the issue

I recently renamed one of my runners, and that is when I started seeing this error.

Problem description

With gitlab_runner_config_update_mode: by_config_toml, the role produces an invalid TOML configuration when a runner already contains an unmarked [runners.feature_flags] section.

The Set feature flag options task uses ansible.builtin.blockinfile with the # BEGIN/END runners.feature_flags markers. Since blockinfile does not detect the existing TOML section, it adds a second [runners.feature_flags] section at the end of the runner configuration.

GitLab Runner then rejects the candidate file during validation in the Assemble new config.toml task.

Versions

  • Tag: v2.1.2
  • GitLab Runner: 19.2.4
  • OS: Linux
  • gitlab_runner_config_update_mode: by_config_toml (default)

Minimal Ansible configuration

gitlab_runner_runners:
  - name: "shared-default-name"
    executor: docker
    feature_flags:
      - FF_USE_ADAPTIVE_REQUEST_CONCURRENCY

Existing configuration

Before the update, the runner already contains an unmarked section:

[[runners]]
  name = "shared-default-name"
  executor = "docker"

  [runners.feature_flags]
    FF_USE_ADAPTIVE_REQUEST_CONCURRENCY = true

  [runners.docker]
    image = "docker:29.0.4"

Observed result

The task adds a second block:

  [runners.feature_flags]
    FF_USE_ADAPTIVE_REQUEST_CONCURRENCY = true

# BEGIN runners.feature_flags
  [runners.feature_flags]
    FF_USE_ADAPTIVE_REQUEST_CONCURRENCY = true
# END runners.feature_flags

Validation fails with:

FATAL: decoding configuration file: toml: line 394
(last key "runners"): Key 'runners.feature_flags' has already been defined.

Identified cause

The relevant task is:

#### [runners.feature_flags] section #####

It systematically appends the marked block at EOF. It does not migrate or replace an existing [runners.feature_flags] table that does not have the role's markers.

The temporary file already contains the first section because tasks/config-runners.yml splits the existing config.toml, then tasks/config-runner.yml copies each fragment as-is before running update-config-runner.yml.

Expected behavior

The role should produce exactly one [runners.feature_flags] table per runner, including when the existing config.toml contains a section that is not managed by blockinfile.

Suggested fix

Before the blockinfile task, remove or migrate only [runners.feature_flags] tables that are not surrounded by the role's markers, then let blockinfile manage the section idempotently.

A by_config_toml integration test should cover:

  1. an initial config.toml containing an unmarked [runners.feature_flags] table;
  2. successful convergence without a parsing error;
  3. exactly one table in the resulting file;
  4. a second idempotent convergence.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions