all:
  children:
    zuul_unreachable:
      hosts: {}
  hosts:
    debian-bookworm:
      ansible_connection: ssh
      ansible_host: 2a13:1a81:8000:3124:f816:3eff:fe09:d745
      ansible_port: 22
      ansible_python_interpreter: auto
      ansible_user: zuul
      nodepool:
        az: nova
        cloud: regiocloud-a-ci
        external_id: e73dcc2e-0383-47cd-bb1c-b0d77cf30153
        host_id: df70f2a3f3d0c26428f22685cfc722ebc48099d99e7332c39e017195
        interface_ip: 2a13:1a81:8000:3124:f816:3eff:fe09:d745
        label: debian-bookworm
        node_properties: {}
        private_ipv4: 10.128.0.108
        private_ipv6: null
        provider: regiocloud-a
        public_ipv4: 81.163.193.93
        public_ipv6: 2a13:1a81:8000:3124:f816:3eff:fe09:d745
        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 flake8 explicit: None implied: {MatchAny:{ImpliedBranchMatcher:main}}
        source: osism/zuul-jobs/.zuul.yaml@main#32>'
      - '<Job flake8 explicit: None implied: None source: osism/python-osism/.zuul.yaml@main#138>'
      ansible_version: '9'
      attempts: 1
      branch: main
      build: 99f14e9149de4d5db2ab8dad04ab4d5c
      build_refs:
      - branch: main
        change: '2333'
        change_message: "Add unit tests for SONiC sync and exporter modules and fix
          issues found in review\n\nCloses #2224. Part of the Tier 3 SONiC unit-test
          effort (#2199), follow-up\nto #2192 / #2193.\n\nAdds two test modules covering
          the SONiC sync pipeline. Both mirror the\nexisting `tests/unit/tasks/conductor/sonic/`
          conventions: the shared\n`mock_nb` / `loguru_logs` fixtures, `SimpleNamespace`
          device stubs, and a\nper-module fixture that stubs collaborators at their
          import site (the\n`patch_orchestrator_helpers` pattern).\n\nThe review surfaced
          seven real defects in `exporter.py` / `sync.py` that the\ninitial tests
          would otherwise have pinned as intended behavior. Since the\nrequested regression
          tests only pass against fixed sources, the fixes are\nincluded here as separate
          commits (see below), so the PR is no longer\ntests-only.\n\n## Change set
          (commit order)\n\n1. **Add unit tests for SONiC exporter module** \u2014
          `test_exporter.py`\n   - `save_config_to_netbox`: first-time create, no-change
          (`DeepDiff` empty,\n     no save), changed config (unified diff + journal
          entry + save), journal\n     failure still saves. Both the tuple (`return_diff=True`)
          and bool return\n     forms are asserted.\n   - `export_config_to_file`:
          filename selection (hostname vs. serial-number,\n     empty/missing serial
          falls back to hostname with a warning), diff\n     handling (missing / identical
          / changed / unreadable file), symlink\n     handling (absent target, existing
          regular file, dangling symlink,\n     `os.symlink` failure, hostname mode
          / falsy serial skip), and the outer\n     `os.makedirs` failure path.\n
          \  - File-export tests use a real `tmp_path` filesystem where that reads
          more\n     clearly (the symlink end-state proves remove-then-symlink ordering),
          and\n     patch `os.*` only to inject the symlink / makedirs failures.\n\n2.
          **Add unit tests for SONiC sync orchestrator** \u2014 `test_sync.py`\n   -
          Cache lifecycle: exact start/end clear ordering via `attach_mock`, and\n
          \    the metalbox / VIP loads called once per invocation.\n   - Single-device
          path: allowed role processed; disallowed role, `role=None`,\n     not-found,
          and lookup-raises each return `{}`; single spine triggers the\n     full
          spine fetch (`nb.dcim.devices.filter`), single leaf does not.\n   - Multi-device
          path: only allowed roles kept; role-less devices skipped.\n   - Per-device:
          missing / unsupported / valid HWSKU; `config_version` read\n     from custom
          fields.\n   - AS mapping: computed per spine group, propagated into\n     `generate_sonic_config`,
          and a `min_as=None` group is not propagated.\n   - Diff handling: diff streamed
          to task output, first-time message,\n     no-change still exports, `show_diff=False`
          calls save without\n     `return_diff`.\n   - Task output gated on `task_id`;
          cache-stats logged only when non-empty.\n\n   `generate_sonic_config` and
          `find_interconnected_devices` are stubbed (they\n   have their own issues
          under #2199), per the issue's instructions.\n\n## Review feedback fixes
          (each with regression tests)\n\n3. **Own only the sonic_config key in NetBox
          local context** (review finding 1)\n   \u2014 `save_config_to_netbox` no
          longer replaces the device's entire\n   `local_context_data` dict; sibling
          keys such as `frr_parameters` /\n   `netplan_parameters` survive, and diffing
          covers only the owned\n   `sonic_config` key (mirrors the #2297 partitioned-ownership
          model).\n\n4. **Create SONiC journal entry only after successful save**
          (finding 7)\n   \u2014 a failed `device.save()` can no longer leave an orphaned
          journal entry\n   claiming the update succeeded.\n\n5. **Write SONiC config
          exports atomically** (finding 3)\n   \u2014 temp file + `os.replace()` so
          a mid-write failure (ENOSPC, killed\n   process) cannot truncate the previous
          export.\n\n6. **Reconcile hostname symlink independently of config changes**\n
          \  (findings 2 + 4) \u2014 a missing/stale link is repaired even when the
          config\n   content is unchanged, the reconciliation is idempotent, and a\n
          \  `hostname == serial` device no longer destroys its own config via a\n
          \  self-referential symlink.\n\n7. **Always clean up caches and finish task
          output in sync_sonic** (finding 5)\n   \u2014 `try/finally` around the sync
          body; early returns and per-device\n   failures no longer leak the module-level
          caches into the next run, finish\n   the task with `rc=1`, and a failing
          device no longer aborts the remaining\n   devices. The summary log no longer
          raises on `PORT`-less configs.\n\n8. **Raise on SONiC persistence failures
          instead of reporting no change**\n   (finding 6) \u2014 failed NetBox saves
          and file exports raise instead of\n   returning the same value as \"no changes\";
          `sync_sonic` reports them via\n   `rc=1` instead of finishing failed syncs
          with `rc=0`.\n\n## Local verification\n\n- `black --check` \u2014 pass\n-
          `flake8` \u2014 pass\n- `pytest` \u2014 not run locally; the unit-test suite
          runs in the\n  `python-osism-unit-tests` Zuul job. The coverage gate\n  (`--cov=...sync`/`...exporter`
          >= 90 %) is verified there."
        change_url: https://github.com/osism/python-osism/pull/2333
        commit_id: cbf7708d907344c119f6e7252d731cbd688c8d1b
        patchset: cbf7708d907344c119f6e7252d731cbd688c8d1b
        project:
          canonical_hostname: github.com
          canonical_name: github.com/osism/python-osism
          name: osism/python-osism
          short_name: python-osism
        src_dir: src/github.com/osism/python-osism
        topic: null
      buildset: 2481c4aa73324793bc0554b8c0ca38a2
      buildset_refs:
      - branch: main
        change: '2333'
        change_message: "Add unit tests for SONiC sync and exporter modules and fix
          issues found in review\n\nCloses #2224. Part of the Tier 3 SONiC unit-test
          effort (#2199), follow-up\nto #2192 / #2193.\n\nAdds two test modules covering
          the SONiC sync pipeline. Both mirror the\nexisting `tests/unit/tasks/conductor/sonic/`
          conventions: the shared\n`mock_nb` / `loguru_logs` fixtures, `SimpleNamespace`
          device stubs, and a\nper-module fixture that stubs collaborators at their
          import site (the\n`patch_orchestrator_helpers` pattern).\n\nThe review surfaced
          seven real defects in `exporter.py` / `sync.py` that the\ninitial tests
          would otherwise have pinned as intended behavior. Since the\nrequested regression
          tests only pass against fixed sources, the fixes are\nincluded here as separate
          commits (see below), so the PR is no longer\ntests-only.\n\n## Change set
          (commit order)\n\n1. **Add unit tests for SONiC exporter module** \u2014
          `test_exporter.py`\n   - `save_config_to_netbox`: first-time create, no-change
          (`DeepDiff` empty,\n     no save), changed config (unified diff + journal
          entry + save), journal\n     failure still saves. Both the tuple (`return_diff=True`)
          and bool return\n     forms are asserted.\n   - `export_config_to_file`:
          filename selection (hostname vs. serial-number,\n     empty/missing serial
          falls back to hostname with a warning), diff\n     handling (missing / identical
          / changed / unreadable file), symlink\n     handling (absent target, existing
          regular file, dangling symlink,\n     `os.symlink` failure, hostname mode
          / falsy serial skip), and the outer\n     `os.makedirs` failure path.\n
          \  - File-export tests use a real `tmp_path` filesystem where that reads
          more\n     clearly (the symlink end-state proves remove-then-symlink ordering),
          and\n     patch `os.*` only to inject the symlink / makedirs failures.\n\n2.
          **Add unit tests for SONiC sync orchestrator** \u2014 `test_sync.py`\n   -
          Cache lifecycle: exact start/end clear ordering via `attach_mock`, and\n
          \    the metalbox / VIP loads called once per invocation.\n   - Single-device
          path: allowed role processed; disallowed role, `role=None`,\n     not-found,
          and lookup-raises each return `{}`; single spine triggers the\n     full
          spine fetch (`nb.dcim.devices.filter`), single leaf does not.\n   - Multi-device
          path: only allowed roles kept; role-less devices skipped.\n   - Per-device:
          missing / unsupported / valid HWSKU; `config_version` read\n     from custom
          fields.\n   - AS mapping: computed per spine group, propagated into\n     `generate_sonic_config`,
          and a `min_as=None` group is not propagated.\n   - Diff handling: diff streamed
          to task output, first-time message,\n     no-change still exports, `show_diff=False`
          calls save without\n     `return_diff`.\n   - Task output gated on `task_id`;
          cache-stats logged only when non-empty.\n\n   `generate_sonic_config` and
          `find_interconnected_devices` are stubbed (they\n   have their own issues
          under #2199), per the issue's instructions.\n\n## Review feedback fixes
          (each with regression tests)\n\n3. **Own only the sonic_config key in NetBox
          local context** (review finding 1)\n   \u2014 `save_config_to_netbox` no
          longer replaces the device's entire\n   `local_context_data` dict; sibling
          keys such as `frr_parameters` /\n   `netplan_parameters` survive, and diffing
          covers only the owned\n   `sonic_config` key (mirrors the #2297 partitioned-ownership
          model).\n\n4. **Create SONiC journal entry only after successful save**
          (finding 7)\n   \u2014 a failed `device.save()` can no longer leave an orphaned
          journal entry\n   claiming the update succeeded.\n\n5. **Write SONiC config
          exports atomically** (finding 3)\n   \u2014 temp file + `os.replace()` so
          a mid-write failure (ENOSPC, killed\n   process) cannot truncate the previous
          export.\n\n6. **Reconcile hostname symlink independently of config changes**\n
          \  (findings 2 + 4) \u2014 a missing/stale link is repaired even when the
          config\n   content is unchanged, the reconciliation is idempotent, and a\n
          \  `hostname == serial` device no longer destroys its own config via a\n
          \  self-referential symlink.\n\n7. **Always clean up caches and finish task
          output in sync_sonic** (finding 5)\n   \u2014 `try/finally` around the sync
          body; early returns and per-device\n   failures no longer leak the module-level
          caches into the next run, finish\n   the task with `rc=1`, and a failing
          device no longer aborts the remaining\n   devices. The summary log no longer
          raises on `PORT`-less configs.\n\n8. **Raise on SONiC persistence failures
          instead of reporting no change**\n   (finding 6) \u2014 failed NetBox saves
          and file exports raise instead of\n   returning the same value as \"no changes\";
          `sync_sonic` reports them via\n   `rc=1` instead of finishing failed syncs
          with `rc=0`.\n\n## Local verification\n\n- `black --check` \u2014 pass\n-
          `flake8` \u2014 pass\n- `pytest` \u2014 not run locally; the unit-test suite
          runs in the\n  `python-osism-unit-tests` Zuul job. The coverage gate\n  (`--cov=...sync`/`...exporter`
          >= 90 %) is verified there."
        change_url: https://github.com/osism/python-osism/pull/2333
        commit_id: cbf7708d907344c119f6e7252d731cbd688c8d1b
        patchset: cbf7708d907344c119f6e7252d731cbd688c8d1b
        project:
          canonical_hostname: github.com
          canonical_name: github.com/osism/python-osism
          name: osism/python-osism
          short_name: python-osism
        src_dir: src/github.com/osism/python-osism
        topic: null
      change: '2333'
      change_message: "Add unit tests for SONiC sync and exporter modules and fix
        issues found in review\n\nCloses #2224. Part of the Tier 3 SONiC unit-test
        effort (#2199), follow-up\nto #2192 / #2193.\n\nAdds two test modules covering
        the SONiC sync pipeline. Both mirror the\nexisting `tests/unit/tasks/conductor/sonic/`
        conventions: the shared\n`mock_nb` / `loguru_logs` fixtures, `SimpleNamespace`
        device stubs, and a\nper-module fixture that stubs collaborators at their
        import site (the\n`patch_orchestrator_helpers` pattern).\n\nThe review surfaced
        seven real defects in `exporter.py` / `sync.py` that the\ninitial tests would
        otherwise have pinned as intended behavior. Since the\nrequested regression
        tests only pass against fixed sources, the fixes are\nincluded here as separate
        commits (see below), so the PR is no longer\ntests-only.\n\n## Change set
        (commit order)\n\n1. **Add unit tests for SONiC exporter module** \u2014 `test_exporter.py`\n
        \  - `save_config_to_netbox`: first-time create, no-change (`DeepDiff` empty,\n
        \    no save), changed config (unified diff + journal entry + save), journal\n
        \    failure still saves. Both the tuple (`return_diff=True`) and bool return\n
        \    forms are asserted.\n   - `export_config_to_file`: filename selection
        (hostname vs. serial-number,\n     empty/missing serial falls back to hostname
        with a warning), diff\n     handling (missing / identical / changed / unreadable
        file), symlink\n     handling (absent target, existing regular file, dangling
        symlink,\n     `os.symlink` failure, hostname mode / falsy serial skip), and
        the outer\n     `os.makedirs` failure path.\n   - File-export tests use a
        real `tmp_path` filesystem where that reads more\n     clearly (the symlink
        end-state proves remove-then-symlink ordering), and\n     patch `os.*` only
        to inject the symlink / makedirs failures.\n\n2. **Add unit tests for SONiC
        sync orchestrator** \u2014 `test_sync.py`\n   - Cache lifecycle: exact start/end
        clear ordering via `attach_mock`, and\n     the metalbox / VIP loads called
        once per invocation.\n   - Single-device path: allowed role processed; disallowed
        role, `role=None`,\n     not-found, and lookup-raises each return `{}`; single
        spine triggers the\n     full spine fetch (`nb.dcim.devices.filter`), single
        leaf does not.\n   - Multi-device path: only allowed roles kept; role-less
        devices skipped.\n   - Per-device: missing / unsupported / valid HWSKU; `config_version`
        read\n     from custom fields.\n   - AS mapping: computed per spine group,
        propagated into\n     `generate_sonic_config`, and a `min_as=None` group is
        not propagated.\n   - Diff handling: diff streamed to task output, first-time
        message,\n     no-change still exports, `show_diff=False` calls save without\n
        \    `return_diff`.\n   - Task output gated on `task_id`; cache-stats logged
        only when non-empty.\n\n   `generate_sonic_config` and `find_interconnected_devices`
        are stubbed (they\n   have their own issues under #2199), per the issue's
        instructions.\n\n## Review feedback fixes (each with regression tests)\n\n3.
        **Own only the sonic_config key in NetBox local context** (review finding
        1)\n   \u2014 `save_config_to_netbox` no longer replaces the device's entire\n
        \  `local_context_data` dict; sibling keys such as `frr_parameters` /\n   `netplan_parameters`
        survive, and diffing covers only the owned\n   `sonic_config` key (mirrors
        the #2297 partitioned-ownership model).\n\n4. **Create SONiC journal entry
        only after successful save** (finding 7)\n   \u2014 a failed `device.save()`
        can no longer leave an orphaned journal entry\n   claiming the update succeeded.\n\n5.
        **Write SONiC config exports atomically** (finding 3)\n   \u2014 temp file
        + `os.replace()` so a mid-write failure (ENOSPC, killed\n   process) cannot
        truncate the previous export.\n\n6. **Reconcile hostname symlink independently
        of config changes**\n   (findings 2 + 4) \u2014 a missing/stale link is repaired
        even when the config\n   content is unchanged, the reconciliation is idempotent,
        and a\n   `hostname == serial` device no longer destroys its own config via
        a\n   self-referential symlink.\n\n7. **Always clean up caches and finish
        task output in sync_sonic** (finding 5)\n   \u2014 `try/finally` around the
        sync body; early returns and per-device\n   failures no longer leak the module-level
        caches into the next run, finish\n   the task with `rc=1`, and a failing device
        no longer aborts the remaining\n   devices. The summary log no longer raises
        on `PORT`-less configs.\n\n8. **Raise on SONiC persistence failures instead
        of reporting no change**\n   (finding 6) \u2014 failed NetBox saves and file
        exports raise instead of\n   returning the same value as \"no changes\"; `sync_sonic`
        reports them via\n   `rc=1` instead of finishing failed syncs with `rc=0`.\n\n##
        Local verification\n\n- `black --check` \u2014 pass\n- `flake8` \u2014 pass\n-
        `pytest` \u2014 not run locally; the unit-test suite runs in the\n  `python-osism-unit-tests`
        Zuul job. The coverage gate\n  (`--cov=...sync`/`...exporter` >= 90 %) is
        verified there."
      change_url: https://github.com/osism/python-osism/pull/2333
      child_jobs: []
      commit_id: cbf7708d907344c119f6e7252d731cbd688c8d1b
      event_id: 588378d0-6492-11f1-88db-d5e56a1b8b37
      executor:
        hostname: 521e9411259a
        inventory_file: /var/lib/zuul/builds/99f14e9149de4d5db2ab8dad04ab4d5c/ansible/inventory.yaml
        log_root: /var/lib/zuul/builds/99f14e9149de4d5db2ab8dad04ab4d5c/work/logs
        result_data_file: /var/lib/zuul/builds/99f14e9149de4d5db2ab8dad04ab4d5c/work/results.json
        src_root: /var/lib/zuul/builds/99f14e9149de4d5db2ab8dad04ab4d5c/work/src
        work_root: /var/lib/zuul/builds/99f14e9149de4d5db2ab8dad04ab4d5c/work
      include_vars: []
      items:
      - branch: main
        change: '2333'
        change_message: "Add unit tests for SONiC sync and exporter modules and fix
          issues found in review\n\nCloses #2224. Part of the Tier 3 SONiC unit-test
          effort (#2199), follow-up\nto #2192 / #2193.\n\nAdds two test modules covering
          the SONiC sync pipeline. Both mirror the\nexisting `tests/unit/tasks/conductor/sonic/`
          conventions: the shared\n`mock_nb` / `loguru_logs` fixtures, `SimpleNamespace`
          device stubs, and a\nper-module fixture that stubs collaborators at their
          import site (the\n`patch_orchestrator_helpers` pattern).\n\nThe review surfaced
          seven real defects in `exporter.py` / `sync.py` that the\ninitial tests
          would otherwise have pinned as intended behavior. Since the\nrequested regression
          tests only pass against fixed sources, the fixes are\nincluded here as separate
          commits (see below), so the PR is no longer\ntests-only.\n\n## Change set
          (commit order)\n\n1. **Add unit tests for SONiC exporter module** \u2014
          `test_exporter.py`\n   - `save_config_to_netbox`: first-time create, no-change
          (`DeepDiff` empty,\n     no save), changed config (unified diff + journal
          entry + save), journal\n     failure still saves. Both the tuple (`return_diff=True`)
          and bool return\n     forms are asserted.\n   - `export_config_to_file`:
          filename selection (hostname vs. serial-number,\n     empty/missing serial
          falls back to hostname with a warning), diff\n     handling (missing / identical
          / changed / unreadable file), symlink\n     handling (absent target, existing
          regular file, dangling symlink,\n     `os.symlink` failure, hostname mode
          / falsy serial skip), and the outer\n     `os.makedirs` failure path.\n
          \  - File-export tests use a real `tmp_path` filesystem where that reads
          more\n     clearly (the symlink end-state proves remove-then-symlink ordering),
          and\n     patch `os.*` only to inject the symlink / makedirs failures.\n\n2.
          **Add unit tests for SONiC sync orchestrator** \u2014 `test_sync.py`\n   -
          Cache lifecycle: exact start/end clear ordering via `attach_mock`, and\n
          \    the metalbox / VIP loads called once per invocation.\n   - Single-device
          path: allowed role processed; disallowed role, `role=None`,\n     not-found,
          and lookup-raises each return `{}`; single spine triggers the\n     full
          spine fetch (`nb.dcim.devices.filter`), single leaf does not.\n   - Multi-device
          path: only allowed roles kept; role-less devices skipped.\n   - Per-device:
          missing / unsupported / valid HWSKU; `config_version` read\n     from custom
          fields.\n   - AS mapping: computed per spine group, propagated into\n     `generate_sonic_config`,
          and a `min_as=None` group is not propagated.\n   - Diff handling: diff streamed
          to task output, first-time message,\n     no-change still exports, `show_diff=False`
          calls save without\n     `return_diff`.\n   - Task output gated on `task_id`;
          cache-stats logged only when non-empty.\n\n   `generate_sonic_config` and
          `find_interconnected_devices` are stubbed (they\n   have their own issues
          under #2199), per the issue's instructions.\n\n## Review feedback fixes
          (each with regression tests)\n\n3. **Own only the sonic_config key in NetBox
          local context** (review finding 1)\n   \u2014 `save_config_to_netbox` no
          longer replaces the device's entire\n   `local_context_data` dict; sibling
          keys such as `frr_parameters` /\n   `netplan_parameters` survive, and diffing
          covers only the owned\n   `sonic_config` key (mirrors the #2297 partitioned-ownership
          model).\n\n4. **Create SONiC journal entry only after successful save**
          (finding 7)\n   \u2014 a failed `device.save()` can no longer leave an orphaned
          journal entry\n   claiming the update succeeded.\n\n5. **Write SONiC config
          exports atomically** (finding 3)\n   \u2014 temp file + `os.replace()` so
          a mid-write failure (ENOSPC, killed\n   process) cannot truncate the previous
          export.\n\n6. **Reconcile hostname symlink independently of config changes**\n
          \  (findings 2 + 4) \u2014 a missing/stale link is repaired even when the
          config\n   content is unchanged, the reconciliation is idempotent, and a\n
          \  `hostname == serial` device no longer destroys its own config via a\n
          \  self-referential symlink.\n\n7. **Always clean up caches and finish task
          output in sync_sonic** (finding 5)\n   \u2014 `try/finally` around the sync
          body; early returns and per-device\n   failures no longer leak the module-level
          caches into the next run, finish\n   the task with `rc=1`, and a failing
          device no longer aborts the remaining\n   devices. The summary log no longer
          raises on `PORT`-less configs.\n\n8. **Raise on SONiC persistence failures
          instead of reporting no change**\n   (finding 6) \u2014 failed NetBox saves
          and file exports raise instead of\n   returning the same value as \"no changes\";
          `sync_sonic` reports them via\n   `rc=1` instead of finishing failed syncs
          with `rc=0`.\n\n## Local verification\n\n- `black --check` \u2014 pass\n-
          `flake8` \u2014 pass\n- `pytest` \u2014 not run locally; the unit-test suite
          runs in the\n  `python-osism-unit-tests` Zuul job. The coverage gate\n  (`--cov=...sync`/`...exporter`
          >= 90 %) is verified there."
        change_url: https://github.com/osism/python-osism/pull/2333
        commit_id: cbf7708d907344c119f6e7252d731cbd688c8d1b
        patchset: cbf7708d907344c119f6e7252d731cbd688c8d1b
        project:
          canonical_hostname: github.com
          canonical_name: github.com/osism/python-osism
          name: osism/python-osism
          short_name: python-osism
          src_dir: src/github.com/osism/python-osism
        topic: null
      job: flake8
      jobtags: []
      max_attempts: 3
      message: QWRkIHVuaXQgdGVzdHMgZm9yIFNPTmlDIHN5bmMgYW5kIGV4cG9ydGVyIG1vZHVsZXMgYW5kIGZpeCBpc3N1ZXMgZm91bmQgaW4gcmV2aWV3CgpDbG9zZXMgIzIyMjQuIFBhcnQgb2YgdGhlIFRpZXIgMyBTT05pQyB1bml0LXRlc3QgZWZmb3J0ICgjMjE5OSksIGZvbGxvdy11cAp0byAjMjE5MiAvICMyMTkzLgoKQWRkcyB0d28gdGVzdCBtb2R1bGVzIGNvdmVyaW5nIHRoZSBTT05pQyBzeW5jIHBpcGVsaW5lLiBCb3RoIG1pcnJvciB0aGUKZXhpc3RpbmcgYHRlc3RzL3VuaXQvdGFza3MvY29uZHVjdG9yL3NvbmljL2AgY29udmVudGlvbnM6IHRoZSBzaGFyZWQKYG1vY2tfbmJgIC8gYGxvZ3VydV9sb2dzYCBmaXh0dXJlcywgYFNpbXBsZU5hbWVzcGFjZWAgZGV2aWNlIHN0dWJzLCBhbmQgYQpwZXItbW9kdWxlIGZpeHR1cmUgdGhhdCBzdHVicyBjb2xsYWJvcmF0b3JzIGF0IHRoZWlyIGltcG9ydCBzaXRlICh0aGUKYHBhdGNoX29yY2hlc3RyYXRvcl9oZWxwZXJzYCBwYXR0ZXJuKS4KClRoZSByZXZpZXcgc3VyZmFjZWQgc2V2ZW4gcmVhbCBkZWZlY3RzIGluIGBleHBvcnRlci5weWAgLyBgc3luYy5weWAgdGhhdCB0aGUKaW5pdGlhbCB0ZXN0cyB3b3VsZCBvdGhlcndpc2UgaGF2ZSBwaW5uZWQgYXMgaW50ZW5kZWQgYmVoYXZpb3IuIFNpbmNlIHRoZQpyZXF1ZXN0ZWQgcmVncmVzc2lvbiB0ZXN0cyBvbmx5IHBhc3MgYWdhaW5zdCBmaXhlZCBzb3VyY2VzLCB0aGUgZml4ZXMgYXJlCmluY2x1ZGVkIGhlcmUgYXMgc2VwYXJhdGUgY29tbWl0cyAoc2VlIGJlbG93KSwgc28gdGhlIFBSIGlzIG5vIGxvbmdlcgp0ZXN0cy1vbmx5LgoKIyMgQ2hhbmdlIHNldCAoY29tbWl0IG9yZGVyKQoKMS4gKipBZGQgdW5pdCB0ZXN0cyBmb3IgU09OaUMgZXhwb3J0ZXIgbW9kdWxlKiog4oCUIGB0ZXN0X2V4cG9ydGVyLnB5YAogICAtIGBzYXZlX2NvbmZpZ190b19uZXRib3hgOiBmaXJzdC10aW1lIGNyZWF0ZSwgbm8tY2hhbmdlIChgRGVlcERpZmZgIGVtcHR5LAogICAgIG5vIHNhdmUpLCBjaGFuZ2VkIGNvbmZpZyAodW5pZmllZCBkaWZmICsgam91cm5hbCBlbnRyeSArIHNhdmUpLCBqb3VybmFsCiAgICAgZmFpbHVyZSBzdGlsbCBzYXZlcy4gQm90aCB0aGUgdHVwbGUgKGByZXR1cm5fZGlmZj1UcnVlYCkgYW5kIGJvb2wgcmV0dXJuCiAgICAgZm9ybXMgYXJlIGFzc2VydGVkLgogICAtIGBleHBvcnRfY29uZmlnX3RvX2ZpbGVgOiBmaWxlbmFtZSBzZWxlY3Rpb24gKGhvc3RuYW1lIHZzLiBzZXJpYWwtbnVtYmVyLAogICAgIGVtcHR5L21pc3Npbmcgc2VyaWFsIGZhbGxzIGJhY2sgdG8gaG9zdG5hbWUgd2l0aCBhIHdhcm5pbmcpLCBkaWZmCiAgICAgaGFuZGxpbmcgKG1pc3NpbmcgLyBpZGVudGljYWwgLyBjaGFuZ2VkIC8gdW5yZWFkYWJsZSBmaWxlKSwgc3ltbGluawogICAgIGhhbmRsaW5nIChhYnNlbnQgdGFyZ2V0LCBleGlzdGluZyByZWd1bGFyIGZpbGUsIGRhbmdsaW5nIHN5bWxpbmssCiAgICAgYG9zLnN5bWxpbmtgIGZhaWx1cmUsIGhvc3RuYW1lIG1vZGUgLyBmYWxzeSBzZXJpYWwgc2tpcCksIGFuZCB0aGUgb3V0ZXIKICAgICBgb3MubWFrZWRpcnNgIGZhaWx1cmUgcGF0aC4KICAgLSBGaWxlLWV4cG9ydCB0ZXN0cyB1c2UgYSByZWFsIGB0bXBfcGF0aGAgZmlsZXN5c3RlbSB3aGVyZSB0aGF0IHJlYWRzIG1vcmUKICAgICBjbGVhcmx5ICh0aGUgc3ltbGluayBlbmQtc3RhdGUgcHJvdmVzIHJlbW92ZS10aGVuLXN5bWxpbmsgb3JkZXJpbmcpLCBhbmQKICAgICBwYXRjaCBgb3MuKmAgb25seSB0byBpbmplY3QgdGhlIHN5bWxpbmsgLyBtYWtlZGlycyBmYWlsdXJlcy4KCjIuICoqQWRkIHVuaXQgdGVzdHMgZm9yIFNPTmlDIHN5bmMgb3JjaGVzdHJhdG9yKiog4oCUIGB0ZXN0X3N5bmMucHlgCiAgIC0gQ2FjaGUgbGlmZWN5Y2xlOiBleGFjdCBzdGFydC9lbmQgY2xlYXIgb3JkZXJpbmcgdmlhIGBhdHRhY2hfbW9ja2AsIGFuZAogICAgIHRoZSBtZXRhbGJveCAvIFZJUCBsb2FkcyBjYWxsZWQgb25jZSBwZXIgaW52b2NhdGlvbi4KICAgLSBTaW5nbGUtZGV2aWNlIHBhdGg6IGFsbG93ZWQgcm9sZSBwcm9jZXNzZWQ7IGRpc2FsbG93ZWQgcm9sZSwgYHJvbGU9Tm9uZWAsCiAgICAgbm90LWZvdW5kLCBhbmQgbG9va3VwLXJhaXNlcyBlYWNoIHJldHVybiBge31gOyBzaW5nbGUgc3BpbmUgdHJpZ2dlcnMgdGhlCiAgICAgZnVsbCBzcGluZSBmZXRjaCAoYG5iLmRjaW0uZGV2aWNlcy5maWx0ZXJgKSwgc2luZ2xlIGxlYWYgZG9lcyBub3QuCiAgIC0gTXVsdGktZGV2aWNlIHBhdGg6IG9ubHkgYWxsb3dlZCByb2xlcyBrZXB0OyByb2xlLWxlc3MgZGV2aWNlcyBza2lwcGVkLgogICAtIFBlci1kZXZpY2U6IG1pc3NpbmcgLyB1bnN1cHBvcnRlZCAvIHZhbGlkIEhXU0tVOyBgY29uZmlnX3ZlcnNpb25gIHJlYWQKICAgICBmcm9tIGN1c3RvbSBmaWVsZHMuCiAgIC0gQVMgbWFwcGluZzogY29tcHV0ZWQgcGVyIHNwaW5lIGdyb3VwLCBwcm9wYWdhdGVkIGludG8KICAgICBgZ2VuZXJhdGVfc29uaWNfY29uZmlnYCwgYW5kIGEgYG1pbl9hcz1Ob25lYCBncm91cCBpcyBub3QgcHJvcGFnYXRlZC4KICAgLSBEaWZmIGhhbmRsaW5nOiBkaWZmIHN0cmVhbWVkIHRvIHRhc2sgb3V0cHV0LCBmaXJzdC10aW1lIG1lc3NhZ2UsCiAgICAgbm8tY2hhbmdlIHN0aWxsIGV4cG9ydHMsIGBzaG93X2RpZmY9RmFsc2VgIGNhbGxzIHNhdmUgd2l0aG91dAogICAgIGByZXR1cm5fZGlmZmAuCiAgIC0gVGFzayBvdXRwdXQgZ2F0ZWQgb24gYHRhc2tfaWRgOyBjYWNoZS1zdGF0cyBsb2dnZWQgb25seSB3aGVuIG5vbi1lbXB0eS4KCiAgIGBnZW5lcmF0ZV9zb25pY19jb25maWdgIGFuZCBgZmluZF9pbnRlcmNvbm5lY3RlZF9kZXZpY2VzYCBhcmUgc3R1YmJlZCAodGhleQogICBoYXZlIHRoZWlyIG93biBpc3N1ZXMgdW5kZXIgIzIxOTkpLCBwZXIgdGhlIGlzc3VlJ3MgaW5zdHJ1Y3Rpb25zLgoKIyMgUmV2aWV3IGZlZWRiYWNrIGZpeGVzIChlYWNoIHdpdGggcmVncmVzc2lvbiB0ZXN0cykKCjMuICoqT3duIG9ubHkgdGhlIHNvbmljX2NvbmZpZyBrZXkgaW4gTmV0Qm94IGxvY2FsIGNvbnRleHQqKiAocmV2aWV3IGZpbmRpbmcgMSkKICAg4oCUIGBzYXZlX2NvbmZpZ190b19uZXRib3hgIG5vIGxvbmdlciByZXBsYWNlcyB0aGUgZGV2aWNlJ3MgZW50aXJlCiAgIGBsb2NhbF9jb250ZXh0X2RhdGFgIGRpY3Q7IHNpYmxpbmcga2V5cyBzdWNoIGFzIGBmcnJfcGFyYW1ldGVyc2AgLwogICBgbmV0cGxhbl9wYXJhbWV0ZXJzYCBzdXJ2aXZlLCBhbmQgZGlmZmluZyBjb3ZlcnMgb25seSB0aGUgb3duZWQKICAgYHNvbmljX2NvbmZpZ2Aga2V5IChtaXJyb3JzIHRoZSAjMjI5NyBwYXJ0aXRpb25lZC1vd25lcnNoaXAgbW9kZWwpLgoKNC4gKipDcmVhdGUgU09OaUMgam91cm5hbCBlbnRyeSBvbmx5IGFmdGVyIHN1Y2Nlc3NmdWwgc2F2ZSoqIChmaW5kaW5nIDcpCiAgIOKAlCBhIGZhaWxlZCBgZGV2aWNlLnNhdmUoKWAgY2FuIG5vIGxvbmdlciBsZWF2ZSBhbiBvcnBoYW5lZCBqb3VybmFsIGVudHJ5CiAgIGNsYWltaW5nIHRoZSB1cGRhdGUgc3VjY2VlZGVkLgoKNS4gKipXcml0ZSBTT05pQyBjb25maWcgZXhwb3J0cyBhdG9taWNhbGx5KiogKGZpbmRpbmcgMykKICAg4oCUIHRlbXAgZmlsZSArIGBvcy5yZXBsYWNlKClgIHNvIGEgbWlkLXdyaXRlIGZhaWx1cmUgKEVOT1NQQywga2lsbGVkCiAgIHByb2Nlc3MpIGNhbm5vdCB0cnVuY2F0ZSB0aGUgcHJldmlvdXMgZXhwb3J0LgoKNi4gKipSZWNvbmNpbGUgaG9zdG5hbWUgc3ltbGluayBpbmRlcGVuZGVudGx5IG9mIGNvbmZpZyBjaGFuZ2VzKioKICAgKGZpbmRpbmdzIDIgKyA0KSDigJQgYSBtaXNzaW5nL3N0YWxlIGxpbmsgaXMgcmVwYWlyZWQgZXZlbiB3aGVuIHRoZSBjb25maWcKICAgY29udGVudCBpcyB1bmNoYW5nZWQsIHRoZSByZWNvbmNpbGlhdGlvbiBpcyBpZGVtcG90ZW50LCBhbmQgYQogICBgaG9zdG5hbWUgPT0gc2VyaWFsYCBkZXZpY2Ugbm8gbG9uZ2VyIGRlc3Ryb3lzIGl0cyBvd24gY29uZmlnIHZpYSBhCiAgIHNlbGYtcmVmZXJlbnRpYWwgc3ltbGluay4KCjcuICoqQWx3YXlzIGNsZWFuIHVwIGNhY2hlcyBhbmQgZmluaXNoIHRhc2sgb3V0cHV0IGluIHN5bmNfc29uaWMqKiAoZmluZGluZyA1KQogICDigJQgYHRyeS9maW5hbGx5YCBhcm91bmQgdGhlIHN5bmMgYm9keTsgZWFybHkgcmV0dXJucyBhbmQgcGVyLWRldmljZQogICBmYWlsdXJlcyBubyBsb25nZXIgbGVhayB0aGUgbW9kdWxlLWxldmVsIGNhY2hlcyBpbnRvIHRoZSBuZXh0IHJ1biwgZmluaXNoCiAgIHRoZSB0YXNrIHdpdGggYHJjPTFgLCBhbmQgYSBmYWlsaW5nIGRldmljZSBubyBsb25nZXIgYWJvcnRzIHRoZSByZW1haW5pbmcKICAgZGV2aWNlcy4gVGhlIHN1bW1hcnkgbG9nIG5vIGxvbmdlciByYWlzZXMgb24gYFBPUlRgLWxlc3MgY29uZmlncy4KCjguICoqUmFpc2Ugb24gU09OaUMgcGVyc2lzdGVuY2UgZmFpbHVyZXMgaW5zdGVhZCBvZiByZXBvcnRpbmcgbm8gY2hhbmdlKioKICAgKGZpbmRpbmcgNikg4oCUIGZhaWxlZCBOZXRCb3ggc2F2ZXMgYW5kIGZpbGUgZXhwb3J0cyByYWlzZSBpbnN0ZWFkIG9mCiAgIHJldHVybmluZyB0aGUgc2FtZSB2YWx1ZSBhcyAibm8gY2hhbmdlcyI7IGBzeW5jX3NvbmljYCByZXBvcnRzIHRoZW0gdmlhCiAgIGByYz0xYCBpbnN0ZWFkIG9mIGZpbmlzaGluZyBmYWlsZWQgc3luY3Mgd2l0aCBgcmM9MGAuCgojIyBMb2NhbCB2ZXJpZmljYXRpb24KCi0gYGJsYWNrIC0tY2hlY2tgIOKAlCBwYXNzCi0gYGZsYWtlOGAg4oCUIHBhc3MKLSBgcHl0ZXN0YCDigJQgbm90IHJ1biBsb2NhbGx5OyB0aGUgdW5pdC10ZXN0IHN1aXRlIHJ1bnMgaW4gdGhlCiAgYHB5dGhvbi1vc2lzbS11bml0LXRlc3RzYCBadXVsIGpvYi4gVGhlIGNvdmVyYWdlIGdhdGUKICAoYC0tY292PS4uLnN5bmNgL2AuLi5leHBvcnRlcmAgPj0gOTAgJSkgaXMgdmVyaWZpZWQgdGhlcmUu
      patchset: cbf7708d907344c119f6e7252d731cbd688c8d1b
      pipeline: check
      playbook_context:
        playbook_projects:
          trusted/project_0/github.com/osism/zuul-config:
            canonical_name: github.com/osism/zuul-config
            checkout: main
            commit: 688445d15ac2c497396b682f69c57ccd484f5f25
          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: 688445d15ac2c497396b682f69c57ccd484f5f25
          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/flake8/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/python-osism
        name: osism/python-osism
        short_name: python-osism
        src_dir: src/github.com/osism/python-osism
      projects:
        github.com/osism/python-osism:
          canonical_hostname: github.com
          canonical_name: github.com/osism/python-osism
          checkout: main
          checkout_description: zuul branch
          commit: 43e46991f5543b3ff12e1df328013d2b4a9db420
          name: osism/python-osism
          required: false
          short_name: python-osism
          src_dir: src/github.com/osism/python-osism
      ref: refs/pull/2333/head
      resources: {}
      tenant: osism
      timeout: 1800
      topic: null
      voting: true
