all:
  children:
    zuul_unreachable:
      hosts: {}
  hosts:
    debian-bookworm:
      ansible_connection: ssh
      ansible_host: 2a13:1a81:8000:3124:f816:3eff:fe96:e472
      ansible_port: 22
      ansible_python_interpreter: auto
      ansible_user: zuul
      nodepool:
        az: nova
        cloud: regiocloud-a-ci
        external_id: 4f380989-adcf-4412-bac1-24deb68544e1
        host_id: 0d3d02185f810c959252bd1d303ec55040bf5bb0b401cceef814c3a7
        interface_ip: 2a13:1a81:8000:3124:f816:3eff:fe96:e472
        label: debian-bookworm
        node_properties: {}
        private_ipv4: 10.128.0.107
        private_ipv6: null
        provider: regiocloud-a
        public_ipv4: 81.163.192.189
        public_ipv6: 2a13:1a81:8000:3124:f816:3eff:fe96:e472
        region: null
        slot: null
  vars:
    zuul:
      _inheritance_path:
      - '<Job base explicit: None implied: {MatchAny:{ImpliedBranchMatcher:main}}
        source: osism/zuul-config/zuul.d/jobs.yaml@main#2>'
      - '<Job yamllint explicit: None implied: {MatchAny:{ImpliedBranchMatcher:main}}
        source: osism/zuul-jobs/.zuul.yaml@main#59>'
      - '<Job yamllint explicit: None implied: None source: osism/netbox-manager/.zuul.yaml@main#32>'
      ansible_version: '9'
      attempts: 1
      branch: main
      build: 7d0add742f84422e82f15d8dbd4903ad
      build_refs:
      - branch: main
        change: '245'
        change_message: "Disambiguate duplicate interface labels on multi-homed nodes\n\n##
          Problem\n\n`netbox-manager autoconf` propagates a switch's `device_interface_label`
          custom field (e.g. `data1`) onto every connected node interface. The label
          value comes from the **switch**, not the port, so it is applied identically
          to all node interfaces connected to that switch.\n\nWhen a single server
          has **more than one link to the same switch**, both node interfaces receive
          the identical label `data1`, producing duplicate, ambiguous interface labels
          on that node.\n\n## Fix\n\nDetect duplicates per `(node device, label)`
          and disambiguate them by appending suffixes: `data1a`, `data1b`, ...\n\n-
          **Ordering**: suffixes are assigned by natural sort of the node interface
          name (e.g. `Ethernet3` \u2192 `data1a`, `Ethernet5` \u2192 `data1b`).\n-
          **Scope**: any two interfaces on the same node with the same label are disambiguated,
          regardless of source switch.\n- Labels occurring only once are left unchanged
          (backward compatible \u2014 existing `leaf1`/`leaf2` topologies are untouched).\n-
          Tasks without a label pass through untouched.\n\n### Changes\n\n- `netbox_manager/main.py`:
          three pure, side-effect-free helpers above `_generate_device_interface_labels()`:\n
          \ - `_natural_sort_key()` \u2014 numeric-aware sort (`Ethernet2` < `Ethernet10`)\n
          \ - `_label_suffix()` \u2014 index \u2192 `a, b, \u2026, z, aa, ab, \u2026`
          (robust beyond 26 links)\n  - `_disambiguate_interface_labels()` \u2014
          groups by `(device, label)`, renames duplicates, logs each renamed group\n-
          `tests/unit/netbox_manager/test_interface_labels.py`: 11 unit tests for
          the pure helpers (no NetBox mocking required)\n\n## Verification\n\n- `flake8`:
          clean\n- `mypy netbox_manager/`: no new errors\n- `pytest tests/unit`: 14
          passed\n\nCloses #243\n\n\U0001F916 Generated with [Claude Code](https://claude.com/claude-code)"
        change_url: https://github.com/osism/netbox-manager/pull/245
        commit_id: 30e255a9b447fa792a6576dbd69ea04ac158c6e4
        patchset: 30e255a9b447fa792a6576dbd69ea04ac158c6e4
        project:
          canonical_hostname: github.com
          canonical_name: github.com/osism/netbox-manager
          name: osism/netbox-manager
          short_name: netbox-manager
        src_dir: src/github.com/osism/netbox-manager
        topic: null
      buildset: 2f93d32a12ab4c0e85ed496176f1a4a4
      buildset_refs:
      - branch: main
        change: '245'
        change_message: "Disambiguate duplicate interface labels on multi-homed nodes\n\n##
          Problem\n\n`netbox-manager autoconf` propagates a switch's `device_interface_label`
          custom field (e.g. `data1`) onto every connected node interface. The label
          value comes from the **switch**, not the port, so it is applied identically
          to all node interfaces connected to that switch.\n\nWhen a single server
          has **more than one link to the same switch**, both node interfaces receive
          the identical label `data1`, producing duplicate, ambiguous interface labels
          on that node.\n\n## Fix\n\nDetect duplicates per `(node device, label)`
          and disambiguate them by appending suffixes: `data1a`, `data1b`, ...\n\n-
          **Ordering**: suffixes are assigned by natural sort of the node interface
          name (e.g. `Ethernet3` \u2192 `data1a`, `Ethernet5` \u2192 `data1b`).\n-
          **Scope**: any two interfaces on the same node with the same label are disambiguated,
          regardless of source switch.\n- Labels occurring only once are left unchanged
          (backward compatible \u2014 existing `leaf1`/`leaf2` topologies are untouched).\n-
          Tasks without a label pass through untouched.\n\n### Changes\n\n- `netbox_manager/main.py`:
          three pure, side-effect-free helpers above `_generate_device_interface_labels()`:\n
          \ - `_natural_sort_key()` \u2014 numeric-aware sort (`Ethernet2` < `Ethernet10`)\n
          \ - `_label_suffix()` \u2014 index \u2192 `a, b, \u2026, z, aa, ab, \u2026`
          (robust beyond 26 links)\n  - `_disambiguate_interface_labels()` \u2014
          groups by `(device, label)`, renames duplicates, logs each renamed group\n-
          `tests/unit/netbox_manager/test_interface_labels.py`: 11 unit tests for
          the pure helpers (no NetBox mocking required)\n\n## Verification\n\n- `flake8`:
          clean\n- `mypy netbox_manager/`: no new errors\n- `pytest tests/unit`: 14
          passed\n\nCloses #243\n\n\U0001F916 Generated with [Claude Code](https://claude.com/claude-code)"
        change_url: https://github.com/osism/netbox-manager/pull/245
        commit_id: 30e255a9b447fa792a6576dbd69ea04ac158c6e4
        patchset: 30e255a9b447fa792a6576dbd69ea04ac158c6e4
        project:
          canonical_hostname: github.com
          canonical_name: github.com/osism/netbox-manager
          name: osism/netbox-manager
          short_name: netbox-manager
        src_dir: src/github.com/osism/netbox-manager
        topic: null
      change: '245'
      change_message: "Disambiguate duplicate interface labels on multi-homed nodes\n\n##
        Problem\n\n`netbox-manager autoconf` propagates a switch's `device_interface_label`
        custom field (e.g. `data1`) onto every connected node interface. The label
        value comes from the **switch**, not the port, so it is applied identically
        to all node interfaces connected to that switch.\n\nWhen a single server has
        **more than one link to the same switch**, both node interfaces receive the
        identical label `data1`, producing duplicate, ambiguous interface labels on
        that node.\n\n## Fix\n\nDetect duplicates per `(node device, label)` and disambiguate
        them by appending suffixes: `data1a`, `data1b`, ...\n\n- **Ordering**: suffixes
        are assigned by natural sort of the node interface name (e.g. `Ethernet3`
        \u2192 `data1a`, `Ethernet5` \u2192 `data1b`).\n- **Scope**: any two interfaces
        on the same node with the same label are disambiguated, regardless of source
        switch.\n- Labels occurring only once are left unchanged (backward compatible
        \u2014 existing `leaf1`/`leaf2` topologies are untouched).\n- Tasks without
        a label pass through untouched.\n\n### Changes\n\n- `netbox_manager/main.py`:
        three pure, side-effect-free helpers above `_generate_device_interface_labels()`:\n
        \ - `_natural_sort_key()` \u2014 numeric-aware sort (`Ethernet2` < `Ethernet10`)\n
        \ - `_label_suffix()` \u2014 index \u2192 `a, b, \u2026, z, aa, ab, \u2026`
        (robust beyond 26 links)\n  - `_disambiguate_interface_labels()` \u2014 groups
        by `(device, label)`, renames duplicates, logs each renamed group\n- `tests/unit/netbox_manager/test_interface_labels.py`:
        11 unit tests for the pure helpers (no NetBox mocking required)\n\n## Verification\n\n-
        `flake8`: clean\n- `mypy netbox_manager/`: no new errors\n- `pytest tests/unit`:
        14 passed\n\nCloses #243\n\n\U0001F916 Generated with [Claude Code](https://claude.com/claude-code)"
      change_url: https://github.com/osism/netbox-manager/pull/245
      child_jobs: []
      commit_id: 30e255a9b447fa792a6576dbd69ea04ac158c6e4
      event_id: ce19b4f0-63f3-11f1-95ff-67cbe532cafb
      executor:
        hostname: 521e9411259a
        inventory_file: /var/lib/zuul/builds/7d0add742f84422e82f15d8dbd4903ad/ansible/inventory.yaml
        log_root: /var/lib/zuul/builds/7d0add742f84422e82f15d8dbd4903ad/work/logs
        result_data_file: /var/lib/zuul/builds/7d0add742f84422e82f15d8dbd4903ad/work/results.json
        src_root: /var/lib/zuul/builds/7d0add742f84422e82f15d8dbd4903ad/work/src
        work_root: /var/lib/zuul/builds/7d0add742f84422e82f15d8dbd4903ad/work
      include_vars: []
      items:
      - branch: main
        change: '245'
        change_message: "Disambiguate duplicate interface labels on multi-homed nodes\n\n##
          Problem\n\n`netbox-manager autoconf` propagates a switch's `device_interface_label`
          custom field (e.g. `data1`) onto every connected node interface. The label
          value comes from the **switch**, not the port, so it is applied identically
          to all node interfaces connected to that switch.\n\nWhen a single server
          has **more than one link to the same switch**, both node interfaces receive
          the identical label `data1`, producing duplicate, ambiguous interface labels
          on that node.\n\n## Fix\n\nDetect duplicates per `(node device, label)`
          and disambiguate them by appending suffixes: `data1a`, `data1b`, ...\n\n-
          **Ordering**: suffixes are assigned by natural sort of the node interface
          name (e.g. `Ethernet3` \u2192 `data1a`, `Ethernet5` \u2192 `data1b`).\n-
          **Scope**: any two interfaces on the same node with the same label are disambiguated,
          regardless of source switch.\n- Labels occurring only once are left unchanged
          (backward compatible \u2014 existing `leaf1`/`leaf2` topologies are untouched).\n-
          Tasks without a label pass through untouched.\n\n### Changes\n\n- `netbox_manager/main.py`:
          three pure, side-effect-free helpers above `_generate_device_interface_labels()`:\n
          \ - `_natural_sort_key()` \u2014 numeric-aware sort (`Ethernet2` < `Ethernet10`)\n
          \ - `_label_suffix()` \u2014 index \u2192 `a, b, \u2026, z, aa, ab, \u2026`
          (robust beyond 26 links)\n  - `_disambiguate_interface_labels()` \u2014
          groups by `(device, label)`, renames duplicates, logs each renamed group\n-
          `tests/unit/netbox_manager/test_interface_labels.py`: 11 unit tests for
          the pure helpers (no NetBox mocking required)\n\n## Verification\n\n- `flake8`:
          clean\n- `mypy netbox_manager/`: no new errors\n- `pytest tests/unit`: 14
          passed\n\nCloses #243\n\n\U0001F916 Generated with [Claude Code](https://claude.com/claude-code)"
        change_url: https://github.com/osism/netbox-manager/pull/245
        commit_id: 30e255a9b447fa792a6576dbd69ea04ac158c6e4
        patchset: 30e255a9b447fa792a6576dbd69ea04ac158c6e4
        project:
          canonical_hostname: github.com
          canonical_name: github.com/osism/netbox-manager
          name: osism/netbox-manager
          short_name: netbox-manager
          src_dir: src/github.com/osism/netbox-manager
        topic: null
      job: yamllint
      jobtags: []
      max_attempts: 3
      message: RGlzYW1iaWd1YXRlIGR1cGxpY2F0ZSBpbnRlcmZhY2UgbGFiZWxzIG9uIG11bHRpLWhvbWVkIG5vZGVzCgojIyBQcm9ibGVtCgpgbmV0Ym94LW1hbmFnZXIgYXV0b2NvbmZgIHByb3BhZ2F0ZXMgYSBzd2l0Y2gncyBgZGV2aWNlX2ludGVyZmFjZV9sYWJlbGAgY3VzdG9tIGZpZWxkIChlLmcuIGBkYXRhMWApIG9udG8gZXZlcnkgY29ubmVjdGVkIG5vZGUgaW50ZXJmYWNlLiBUaGUgbGFiZWwgdmFsdWUgY29tZXMgZnJvbSB0aGUgKipzd2l0Y2gqKiwgbm90IHRoZSBwb3J0LCBzbyBpdCBpcyBhcHBsaWVkIGlkZW50aWNhbGx5IHRvIGFsbCBub2RlIGludGVyZmFjZXMgY29ubmVjdGVkIHRvIHRoYXQgc3dpdGNoLgoKV2hlbiBhIHNpbmdsZSBzZXJ2ZXIgaGFzICoqbW9yZSB0aGFuIG9uZSBsaW5rIHRvIHRoZSBzYW1lIHN3aXRjaCoqLCBib3RoIG5vZGUgaW50ZXJmYWNlcyByZWNlaXZlIHRoZSBpZGVudGljYWwgbGFiZWwgYGRhdGExYCwgcHJvZHVjaW5nIGR1cGxpY2F0ZSwgYW1iaWd1b3VzIGludGVyZmFjZSBsYWJlbHMgb24gdGhhdCBub2RlLgoKIyMgRml4CgpEZXRlY3QgZHVwbGljYXRlcyBwZXIgYChub2RlIGRldmljZSwgbGFiZWwpYCBhbmQgZGlzYW1iaWd1YXRlIHRoZW0gYnkgYXBwZW5kaW5nIHN1ZmZpeGVzOiBgZGF0YTFhYCwgYGRhdGExYmAsIC4uLgoKLSAqKk9yZGVyaW5nKio6IHN1ZmZpeGVzIGFyZSBhc3NpZ25lZCBieSBuYXR1cmFsIHNvcnQgb2YgdGhlIG5vZGUgaW50ZXJmYWNlIG5hbWUgKGUuZy4gYEV0aGVybmV0M2Ag4oaSIGBkYXRhMWFgLCBgRXRoZXJuZXQ1YCDihpIgYGRhdGExYmApLgotICoqU2NvcGUqKjogYW55IHR3byBpbnRlcmZhY2VzIG9uIHRoZSBzYW1lIG5vZGUgd2l0aCB0aGUgc2FtZSBsYWJlbCBhcmUgZGlzYW1iaWd1YXRlZCwgcmVnYXJkbGVzcyBvZiBzb3VyY2Ugc3dpdGNoLgotIExhYmVscyBvY2N1cnJpbmcgb25seSBvbmNlIGFyZSBsZWZ0IHVuY2hhbmdlZCAoYmFja3dhcmQgY29tcGF0aWJsZSDigJQgZXhpc3RpbmcgYGxlYWYxYC9gbGVhZjJgIHRvcG9sb2dpZXMgYXJlIHVudG91Y2hlZCkuCi0gVGFza3Mgd2l0aG91dCBhIGxhYmVsIHBhc3MgdGhyb3VnaCB1bnRvdWNoZWQuCgojIyMgQ2hhbmdlcwoKLSBgbmV0Ym94X21hbmFnZXIvbWFpbi5weWA6IHRocmVlIHB1cmUsIHNpZGUtZWZmZWN0LWZyZWUgaGVscGVycyBhYm92ZSBgX2dlbmVyYXRlX2RldmljZV9pbnRlcmZhY2VfbGFiZWxzKClgOgogIC0gYF9uYXR1cmFsX3NvcnRfa2V5KClgIOKAlCBudW1lcmljLWF3YXJlIHNvcnQgKGBFdGhlcm5ldDJgIDwgYEV0aGVybmV0MTBgKQogIC0gYF9sYWJlbF9zdWZmaXgoKWAg4oCUIGluZGV4IOKGkiBgYSwgYiwg4oCmLCB6LCBhYSwgYWIsIOKApmAgKHJvYnVzdCBiZXlvbmQgMjYgbGlua3MpCiAgLSBgX2Rpc2FtYmlndWF0ZV9pbnRlcmZhY2VfbGFiZWxzKClgIOKAlCBncm91cHMgYnkgYChkZXZpY2UsIGxhYmVsKWAsIHJlbmFtZXMgZHVwbGljYXRlcywgbG9ncyBlYWNoIHJlbmFtZWQgZ3JvdXAKLSBgdGVzdHMvdW5pdC9uZXRib3hfbWFuYWdlci90ZXN0X2ludGVyZmFjZV9sYWJlbHMucHlgOiAxMSB1bml0IHRlc3RzIGZvciB0aGUgcHVyZSBoZWxwZXJzIChubyBOZXRCb3ggbW9ja2luZyByZXF1aXJlZCkKCiMjIFZlcmlmaWNhdGlvbgoKLSBgZmxha2U4YDogY2xlYW4KLSBgbXlweSBuZXRib3hfbWFuYWdlci9gOiBubyBuZXcgZXJyb3JzCi0gYHB5dGVzdCB0ZXN0cy91bml0YDogMTQgcGFzc2VkCgpDbG9zZXMgIzI0MwoK8J+kliBHZW5lcmF0ZWQgd2l0aCBbQ2xhdWRlIENvZGVdKGh0dHBzOi8vY2xhdWRlLmNvbS9jbGF1ZGUtY29kZSk=
      patchset: 30e255a9b447fa792a6576dbd69ea04ac158c6e4
      pipeline: check
      playbook_context:
        playbook_projects:
          trusted/project_0/github.com/osism/zuul-config:
            canonical_name: github.com/osism/zuul-config
            checkout: main
            commit: 019f0261a526db7d8989ff1abefc2299a8c0ffbc
          trusted/project_1/github.com/osism/openinfra-zuul-jobs:
            canonical_name: github.com/osism/openinfra-zuul-jobs
            checkout: master
            commit: 038dd8b856c62af4433c8477c5cb3d0480847059
          trusted/project_2/github.com/osism/zuul-jobs:
            canonical_name: github.com/osism/zuul-jobs
            checkout: main
            commit: 0c74c57cedff2b36bb37ca68a5338d1c49991496
          untrusted/project_0/github.com/osism/zuul-jobs:
            canonical_name: github.com/osism/zuul-jobs
            checkout: main
            commit: 0c74c57cedff2b36bb37ca68a5338d1c49991496
          untrusted/project_1/github.com/osism/zuul-config:
            canonical_name: github.com/osism/zuul-config
            checkout: main
            commit: 019f0261a526db7d8989ff1abefc2299a8c0ffbc
          untrusted/project_2/github.com/osism/openinfra-zuul-jobs:
            canonical_name: github.com/osism/openinfra-zuul-jobs
            checkout: master
            commit: 038dd8b856c62af4433c8477c5cb3d0480847059
        playbooks:
        - path: untrusted/project_0/github.com/osism/zuul-jobs/playbooks/yamllint/run.yaml
          roles:
          - checkout: main
            checkout_description: zuul branch
            link_name: ansible/playbook_0/role_0/zuul-config
            link_target: untrusted/project_1/github.com/osism/zuul-config
            role_path: ansible/playbook_0/role_0/zuul-config/roles
          - checkout: master
            checkout_description: project default branch
            link_name: ansible/playbook_0/role_1/openinfra-zuul-jobs
            link_target: untrusted/project_2/github.com/osism/openinfra-zuul-jobs
            role_path: ansible/playbook_0/role_1/openinfra-zuul-jobs/roles
          - checkout: main
            checkout_description: playbook branch
            link_name: ansible/playbook_0/role_2/zuul-jobs
            link_target: untrusted/project_0/github.com/osism/zuul-jobs
            role_path: ansible/playbook_0/role_2/zuul-jobs/roles
      post_review: false
      post_timeout: null
      pre_timeout: null
      project:
        canonical_hostname: github.com
        canonical_name: github.com/osism/netbox-manager
        name: osism/netbox-manager
        short_name: netbox-manager
        src_dir: src/github.com/osism/netbox-manager
      projects:
        github.com/osism/netbox-manager:
          canonical_hostname: github.com
          canonical_name: github.com/osism/netbox-manager
          checkout: main
          checkout_description: zuul branch
          commit: d6a2d003b7b31e16e705fc136547ac92307172a6
          name: osism/netbox-manager
          required: false
          short_name: netbox-manager
          src_dir: src/github.com/osism/netbox-manager
      ref: refs/pull/245/head
      resources: {}
      tenant: osism
      timeout: 1800
      topic: null
      voting: true
