Skip to content

[Bug]: NetBox API caching logic has issues #1106

Closed
@sc68cal

Description

@sc68cal

Ansible NetBox Collection version

v3.14.0

Ansible version

There appears to be an issue with the cache code inside the fetch_api_docs function, where if the response from the NetBox server is not able to be written to the filesystem, and then subsequently read back out sucessfully, the logic ends up setting endpoint_url to be "/api/docs/?format=openapi" - which is not correct on NetBox server versions > v3.5.0 - because the plugin tries to access that endpoint, which 404's and then the plugin attempts to parse it, fails, and then gives up.

I run a container built by ansible-build inside ConcourseCI, which appears to lay things out in such a way where the filesystem is not writable, even by the root user. This appears to include DEFAULT_LOCAL_TMP.

Fetching: https://netbox.REDACTED.net/api/status

Fetching: https://netbox.REDACTED.net/api/docs/?format=openapi

    14 1698248940.41606: auto failed while attempting to parse /tmp/build/a082d71e/code_repo/netbox.yml

    14 1698248940.41668: Attempting to use plugin yaml (/usr/local/lib/python3.10/site-packages/ansible/plugins/inventory/yaml.py)

    14 1698248940.41696: Loading data from /tmp/build/a082d71e/code_repo/netbox.yml

    14 1698248940.41849: /tmp/build/a082d71e/code_repo/netbox.yml was not parsable by yaml

    14 1698248940.41868: Attempting to use plugin ini (/usr/local/lib/python3.10/site-packages/ansible/plugins/inventory/ini.py)

    14 1698248940.41948: /tmp/build/a082d71e/code_repo/netbox.yml was not parsable by ini

    14 1698248940.41966: Attempting to use plugin toml (/usr/local/lib/python3.10/site-packages/ansible/plugins/inventory/toml.py)

toml declined parsing /tmp/build/a082d71e/code_repo/netbox.yml as it did not pass its verify_file() method

[WARNING]:  * Failed to parse /tmp/build/a082d71e/code_repo/netbox.yml with auto plugin:     <!DOCTYPE html> <html   lang="en"   data-netbox-url-name=""   data-netbox-base-path=""               data-netbox-color-mode="unset"           >   <head>     <meta charset="UTF-8" />     <meta       name="viewport"       content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width, viewport-fit=cover"     />           <title>Page Not Found | NetBox</title>      <script

type="text/javascript"       src="/static/setmode.js"       onerror="window.location='/media-failure/?filename=setmode.js'">     </script>      <script type="text/javascript">       (function () {           initMode()       })();       window.CSRF_TOKEN = "Sd7d273elhUcOCrLMhSEogOe0zKIp2vEMmhtNztYuGBNtdQN030q0SQeArvSjSe5";     </script>           <link       rel="stylesheet"       href="/static/netbox-external.css?v=3.5.3"       onerror="window.location='/media-failure/?filename=netbox-

external.css'"     />     <link       rel="stylesheet"       href="/static/netbox-light.css?v=3.5.3"       onerror="window.location='/media-failure/?filename=netbox-light.css'"     />     <link       rel="stylesheet"       href="/static/netbox-dark.css?v=3.5.3"       onerror="window.location='/media-failure/?filename=netbox-dark.css'"     />     <link       rel="stylesheet"       media="print"       href="/static/netbox-print.css?v=3.5.3"       onerror="window.location='/media-

failure/?filename=netbox-print.css'"     />     <link rel="icon" type="image/png" href="/static/netbox.ico" />     <link rel="apple-touch-icon" type="image/png" href="/static/netbox_touch-icon-180.png" />           <script       type="text/javascript"       src="/static/netbox.js?v=3.5.3"       onerror="window.location='/media-failure/?filename=netbox.js'">     </script>              </head>    <body>     <script type="text/javascript">       function checkSideNav() {         // Check

localStorage to see if the sidebar should be pinned.         var sideNavRaw = localStorage.getItem('netbox-sidenav');         // Determine if the device has a small screeen. This media query is equivalent to         // bootstrap's media-breakpoint-down(lg) breakpoint mixin, which is what the sidenav's         // CSS uses.         var isSmallScreen = window.matchMedia('(max-width: 991.98px)').matches;         if (typeof sideNavRaw === 'string') {           var sideNavState =

JSON.parse(sideNavRaw);           if (sideNavState.pinned === true && !isSmallScreen) {             // If the sidebar should be pinned and this is not a small screen, set the appropriate             // body attributes prior to the rest of the content rendering. This prevents             // jumpy/glitchy behavior on page reloads.             document.body.setAttribute('data-sidenav-pinned', '');             document.body.setAttribute('data-sidenav-show', '');

document.body.removeAttribute('data-sidenav-hidden');           } else {             document.body.removeAttribute('data-sidenav-pinned');             document.body.setAttribute('data-sidenav-hidden', '');           }         }       }       window.addEventListener('resize', function(){ checkSideNav() });       checkSideNav();     </script>               <div class="container-fluid px-0">     <main class="layout">             <nav class="sidenav noprint" id="sidenav" data-simplebar>   <div

class="sidenav-header">               <a class="sidenav-brand" href="/">       <img src="/static/netbox_logo.svg" height="48" class="sidenav-brand-img" alt="NetBox Logo">     </a>           <a class="sidenav-brand-icon" href="/">       <img src="/static/netbox_icon.svg" height="32" class="sidenav-brand-img" alt="NetBox Logo">     </a>           <button class="btn btn-sm btn-ghost-primary sidenav-toggle">       <div class="sidenav-toggle-icon">         <i class="mdi mdi-pin"></i>       </div>

</button>    </div>    <div class="sidenav-inner h-100 mb-auto">           <div class="collapse sidenav-collapse pb-4">                 <ul class="navbar-nav">    </ul>       </div>           <div class="profile-button-container">          <div class="btn-group">     <a class="btn btn-primary ws-nowrap" type="button" href="/login/?next=/api/docs/">       <i class="mdi mdi-login-variant"></i> Log In     </a>     <button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split"

data-bs-toggle="dropdown">       <span class="visually-hidden">Toggle Dropdown</span>     </button>     <ul class="dropdown-menu dropdown-menu-end">       <li>         <button class="dropdown-item color-mode-toggle">           <i class="color-mode-icon mdi mdi-lightbulb"></i>           <span class="color-mode-text">Dark Mode</span>         </button>       </li>     </ul>   </div>       </div>   </div> </nav>                <div class="content-container" tabindex="-2">                   <div

class="p-2 printonly">           <img src="/static/netbox_logo.svg" alt="NetBox logo" width="200px" />         </div>                   <nav class="navbar navbar-light sticky-top flex-md-nowrap p-1 mb-3 search container-fluid noprint">                           <div class="nav-mobile">               <div class="nav-mobile-top">                 <a class="sidebar-logo p-2 d-block" href="/">                   <img src="/static/netbox_logo.svg" alt="NetBox logo" height="40" />                 </a>

<button type="button" aria-label="Toggle Navigation" class="navbar-toggler sidenav-toggle-mobile">                   <span class="navbar-toggler-icon"></span>                 </button>               </div>               <div class="d-flex my-1 flex-grow-1 justify-content-center w-100">                 <form class="input-group" action="/search/" method="get">   <input name="q" type="text" aria-label="Search" placeholder="Search" class="form-control" />   <button class="btn btn-primary"

type="submit">     <i class="mdi mdi-magnify"></i>   </button> </form>                </div>             </div>                           <div class="row search-container">                               <div class="col-3 d-flex flex-grow-1 ps-0"></div>                               <div class="col-6 d-flex flex-grow-1 justify-content-center">                 <form class="input-group" action="/search/" method="get">   <input name="q" type="text" aria-label="Search" placeholder="Search"

class="form-control" />   <button class="btn btn-primary" type="submit">     <i class="mdi mdi-magnify"></i>   </button> </form>                </div>                               <div class="col-3 d-flex flex-grow-1 pe-0 justify-content-end">                    <div class="btn-group">     <a class="btn btn-primary ws-nowrap" type="button" href="/login/?next=/api/docs/">       <i class="mdi mdi-login-variant"></i> Log In     </a>     <button type="button" class="btn btn-primary dropdown-toggle

dropdown-toggle-split" data-bs-toggle="dropdown">       <span class="visually-hidden">Toggle Dropdown</span>     </button>     <ul class="dropdown-menu dropdown-menu-end">       <li>         <button class="dropdown-item color-mode-toggle">           <i class="color-mode-icon mdi mdi-lightbulb"></i>           <span class="color-mode-text">Dark Mode</span>         </button>       </li>     </ul>   </div>                 </div>              </div>          </nav>

<div class="title-container px-3 pb-3">                           <div id="content-title">                              <h1 class="h2 w-100">Page Not Found</h1>                            </div>                                       </div>                            <div id="content" class="container-fluid content px-0 m-0">                                   <div class="px-3">                <div class="row my-5">     <div class="col-6 offset-3">         <div class="card">             <h5

class="card-header text-danger">                 /api/docs/             </h5>             <div class="card-body">                      The requested page does not exist.              </div>             <div class="card-footer text-end">                 <a href="/" class="btn btn-sm btn-primary">Home Page</a>             </div>         </div>     </div> </div>              </div>                                          </div>                                      <footer class="footer container-

fluid">                        <div class="row align-items-center justify-content-between mx-0">                <div class="col-sm-12 col-md-auto fs-4 noprint">                 <nav class="nav justify-content-center justify-content-lg-start">                                                             <a type="button" class="nav-link" href="/static/docs/" target="_blank">                       <i title="Docs" class="mdi mdi-book-open-variant text-primary" data-bs-placement="top" data-bs-

toggle="tooltip"></i>                     </a>                                           <a type="button" class="nav-link" href="/api/" target="_blank">                       <i title="REST API" class="mdi mdi-cloud-braces text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>                     </a>                                           <a type="button" class="nav-link" href="/api/schema/swagger-ui/" target="_blank">                       <i title="REST API documentation"

class="mdi mdi-book text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>                     </a>                                                                <a type="button" class="nav-link" href="/graphql/" target="_blank">                       <i title="GraphQL API" class="mdi mdi-graphql text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>                     </a>                                                                <a type="button" class="nav-

link" href="/netbox-community/netbox" target="_blank">                       <i title="Source Code" class="mdi mdi-github text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>                     </a>                                           <a type="button" class="nav-link" href="https://netdev.chat/" target="_blank">                       <i title="Community" class="mdi mdi-slack text-primary" data-bs-placement="top" data-bs-toggle="tooltip"></i>

</a>                                    </nav>               </div>                <div class="col-sm-12 col-md-auto text-center text-lg-end text-muted">                 <span class="d-block d-md-inline"><span title="Oct. 25, 2023 3:49 p.m.">2023-10-25 15:49</span> UTC</span>                 <span class="ms-md-3 d-block d-md-inline">netbox-as-i1p-248708.sys.comcast.net (v3.5.3)</span>               </div>              </div>                    </footer>        </div>      </main>   </div>

<div id="django-messages" class="toast-container">                </div>            <div id="netbox-data" style="display: none!important; visibility: hidden!important">            </div>    </body> </html>

  File "/usr/local/lib/python3.10/site-packages/ansible/inventory/manager.py", line 290, in parse_source

    plugin.parse(self._inventory, self._loader, source, cache=cache)

  File "/usr/local/lib/python3.10/site-packages/ansible/plugins/inventory/auto.py", line 59, in parse

    plugin.parse(inventory, loader, path, cache=cache)

  File "/usr/local/lib/python3.10/site-packages/ansible_collections/netbox/netbox/plugins/inventory/nb_inventory.py", line 1895, in parse

    self.main()

  File "/usr/local/lib/python3.10/site-packages/ansible_collections/netbox/netbox/plugins/inventory/nb_inventory.py", line 1767, in main

    self.fetch_api_docs()

  File "/usr/local/lib/python3.10/site-packages/ansible_collections/netbox/netbox/plugins/inventory/nb_inventory.py", line 1395, in fetch_api_docs

    openapi = self._fetch_information(

  File "/usr/local/lib/python3.10/site-packages/ansible_collections/netbox/netbox/plugins/inventory/nb_inventory.py", line 380, in _fetch_information

    raise AnsibleError(to_native(e.fp.read()))

[WARNING]:  * Failed to parse /tmp/build/a082d71e/code_repo/netbox.yml with yaml plugin: Plugin configuration YAML file, not YAML inventory

  File "/usr/local/lib/python3.10/site-packages/ansible/inventory/manager.py", line 290, in parse_source

    plugin.parse(self._inventory, self._loader, source, cache=cache)

  File "/usr/local/lib/python3.10/site-packages/ansible/plugins/inventory/yaml.py", line 114, in parse

    raise AnsibleParserError('Plugin configuration YAML file, not YAML inventory')

[WARNING]:  * Failed to parse /tmp/build/a082d71e/code_repo/netbox.yml with ini plugin: Invalid host pattern 'plugin:' supplied, ending in ':' is not allowed, this character is reserved to provide a port.

  File "/usr/local/lib/python3.10/site-packages/ansible/inventory/manager.py", line 290, in parse_source

    plugin.parse(self._inventory, self._loader, source, cache=cache)

  File "/usr/local/lib/python3.10/site-packages/ansible/plugins/inventory/ini.py", line 136, in parse

    raise AnsibleParserError(e)

[WARNING]: Unable to parse /tmp/build/a082d71e/code_repo/netbox.yml as an inventory source

NetBox version

v3.5.3

Python version

3.9

Steps to Reproduce

Run a container with NetBox inventory plugin in a ConcourseCI server install

Expected Behavior

Inventory should have been parsed

Observed Behavior

Inventory did not get parsed

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions