<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Ansible on 0x2142 | Networking Nonsense</title>
    <link>https://0x2142.com/tags/ansible/</link>
    <description>Recent content in Ansible on 0x2142 | Networking Nonsense</description>
    <image>
      <title>0x2142 | Networking Nonsense</title>
      <url>https://0x2142.com/logo.jpg</url>
      <link>https://0x2142.com/logo.jpg</link>
    </image>
    <generator>Hugo -- 0.143.1</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 31 Jan 2024 23:01:48 +0000</lastBuildDate>
    <atom:link href="https://0x2142.com/tags/ansible/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>[Quick Fix] Nexus 9k &amp; Ansible: &#34;Request without namespace and filter is an unsupported operation&#34;</title>
      <link>https://0x2142.com/quick-fix-nexus-9k-ansible-netconf/</link>
      <pubDate>Wed, 31 Jan 2024 23:01:48 +0000</pubDate>
      <guid>https://0x2142.com/quick-fix-nexus-9k-ansible-netconf/</guid>
      <description>A quick blog post on how to fix an error with Ansible and Cisco Nexus 9k via NETCONF: &amp;ldquo;Request without namespace and filter is an unsupported operation&amp;rdquo;</description>
      <content:encoded><![CDATA[<p>Hey there everyone, I hope you&rsquo;ve had a great start to the year so far!</p>
<p>In this blog post, I wanted to spend just a few minutes going over how to solve an issue one of my peers ran into recently.</p>
<h2 id="the-issue">The Issue</h2>
<p>Let&rsquo;s say we were trying to use Ansible to update the interface admin state on a Cisco Nexus switch. In this case, I&rsquo;m using a virtual Nexus 9000 which is running NX-OS version 10.2(6).</p>
<p>This switch has a loopback interface (lo100), which we want to disable.</p>
<p>Reading the <a href="https://docs.ansible.com/ansible/latest/collections/ansible/netcommon/netconf_config_module.html#examples">Ansible documentation</a> for the NETCONF module, we might assume that the following would be enough to get the job done:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl">- <span class="nt">name </span><span class="p">:</span><span class="w"> </span><span class="l">NX-OS Interface Updates</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">hosts</span><span class="p">:</span><span class="w"> </span><span class="l">all</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">connection</span><span class="p">:</span><span class="w"> </span><span class="l">netconf</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">gather_facts</span><span class="p">:</span><span class="w"> </span><span class="kc">no</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">tasks</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Update Interface State</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">ansible.netcommon.netconf_config</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">content</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">            &lt;config&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">              &lt;System xmlns=&#34;http://cisco.com/ns/yang/cisco-nx-os-device&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                &lt;intf-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                  &lt;lb-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                    &lt;LbRtdIf-list&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                      &lt;id&gt;lo100&lt;/id&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                      &lt;adminSt&gt;down&lt;/adminSt&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                    &lt;/LbRtdIf-list&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                  &lt;/lb-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                &lt;/intf-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">              &lt;/System&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">            &lt;/config&gt;</span><span class="w">
</span></span></span></code></pre></div><p>However, once we run that playbook, we&rsquo;ll get an error back:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">(</span>ansible<span class="o">)</span> matt@ansible-dev:~/ansible/nxos$ ansible-playbook nx-update-interface.yaml -i inventory.yml
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">PLAY <span class="o">[</span>NX-OS Interface Updates<span class="o">]</span> **********************************************************************************************************
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">TASK <span class="o">[</span>Update Interface State<span class="o">]</span> ***********************************************************************************************************
</span></span><span class="line"><span class="cl">fatal: <span class="o">[</span>10.122.2.229<span class="o">]</span>: FAILED! <span class="o">=</span>&gt; <span class="o">{</span><span class="s2">&#34;changed&#34;</span>: false, <span class="s2">&#34;msg&#34;</span>: <span class="s2">&#34;Request without namespace and filter is an unsupported operation&#34;</span><span class="o">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">PLAY RECAP ******************************************************************************************************************************
</span></span><span class="line"><span class="cl">10.122.2.229               : <span class="nv">ok</span><span class="o">=</span><span class="m">0</span>    <span class="nv">changed</span><span class="o">=</span><span class="m">0</span>    <span class="nv">unreachable</span><span class="o">=</span><span class="m">0</span>    <span class="nv">failed</span><span class="o">=</span><span class="m">1</span>    <span class="nv">skipped</span><span class="o">=</span><span class="m">0</span>    <span class="nv">rescued</span><span class="o">=</span><span class="m">0</span>    <span class="nv">ignored</span><span class="o">=</span><span class="m">0</span>
</span></span></code></pre></div><h2 id="the-fix">The Fix</h2>
<p>Luckily, this has an easy solution.</p>
<p>According to the Cisco <a href="https://www.cisco.com/c/en/us/td/docs/switches/datacenter/nexus9000/sw/93x/progammability/guide/b-cisco-nexus-9000-series-nx-os-programmability-guide-93x/b-cisco-nexus-9000-series-nx-os-programmability-guide-93x_chapter_0100110.html#id_72426">NX-OS Documentation</a>, there was a change in version 9.3(1) that requires a filter to be sent along with any GET or GET-CONFIG request.</p>
<p>But wait - aren&rsquo;t we updating the config via an EDIT-CONFIG request? We shouldn&rsquo;t need to send a filter, since it&rsquo;s not a GET or GET-CONFIG, right?</p>
<p>Well because of the way Ansible works, we actually send two GET-CONFIG requests along with our EDIT-CONFIG. One <a href="https://github.com/ansible-collections/ansible.netcommon/blob/95d2f6bd66ce5841d951b26790298cf97e3d591b/plugins/modules/netconf_config.py#L622">before</a> the change, and another one <a href="https://github.com/ansible-collections/ansible.netcommon/blob/95d2f6bd66ce5841d951b26790298cf97e3d591b/plugins/modules/netconf_config.py#L673">after</a> making the change.</p>
<p>These are used to validate that we actually updated the config. Ansible uses these two GET-CONFIG requests to compare &amp; see if there is actually any difference between the two.</p>
<p>So to address our error above - when we send our config change in Ansible, we also need to include the get_filter parameter. This will give Ansible a NETCONF filter use when it issues the GET-CONFIG requests to validate our changes.</p>
<p>In our case, that GET-CONFIG filter could look something like this:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;System</span> <span class="na">xmlns=</span><span class="s">&#34;http://cisco.com/ns/yang/cisco-nx-os-device&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;intf-items&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;lb-items&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;LbRtdIf-list&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;id&gt;</span>lo100<span class="nt">&lt;/id&gt;</span>
</span></span><span class="line"><span class="cl">        <span class="nt">&lt;adminSt/&gt;</span>
</span></span><span class="line"><span class="cl">      <span class="nt">&lt;/LbRtdIf-list&gt;</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&lt;/lb-items&gt;</span>
</span></span><span class="line"><span class="cl">  <span class="nt">&lt;/intf-items&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/System&gt;</span>
</span></span></code></pre></div><p>That filter would pull back just the admin state for our lo100 interface, which then Ansible could use to compare after we issue our request to disable the interface.</p>
<p>For what it&rsquo;s worth, we don&rsquo;t necessarily have to be that specific with our filter. We just need to ensure that whatever config returned by the filter would also include the section we intend to change.</p>
<p>So for example, we could actually just filter by System and this would still work:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-xml" data-lang="xml"><span class="line"><span class="cl"><span class="nt">&lt;System</span> <span class="na">xmlns=</span><span class="s">&#34;http://cisco.com/ns/yang/cisco-nx-os-device&#34;</span><span class="nt">&gt;</span>
</span></span><span class="line"><span class="cl"><span class="nt">&lt;/System&gt;</span>
</span></span></code></pre></div><p>The main difference here is that the switch would return a much larger amount of data, which then Ansible would also need to process to detect the change. So for efficiency &amp; accuracy, it&rsquo;s probably still helpful to keep our get_filter scoped to a reasonably narrow amount.</p>
<p>With all that covered, here&rsquo;s the example of our final playbook with the new filter:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl">- <span class="nt">name </span><span class="p">:</span><span class="w"> </span><span class="l">NX-OS Interface Updates</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">hosts</span><span class="p">:</span><span class="w"> </span><span class="l">all</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">connection</span><span class="p">:</span><span class="w"> </span><span class="l">netconf</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">gather_facts</span><span class="p">:</span><span class="w"> </span><span class="kc">no</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">tasks</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">Update Interface State</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">ansible.netcommon.netconf_config</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">get_filter</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">          &lt;System xmlns=&#34;http://cisco.com/ns/yang/cisco-nx-os-device&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                &lt;intf-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                  &lt;lb-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                    &lt;LbRtdIf-list&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                      &lt;id&gt;lo100&lt;/id&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                      &lt;adminSt/&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                    &lt;/LbRtdIf-list&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                  &lt;/lb-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                &lt;/intf-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">              &lt;/System&gt;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">content</span><span class="p">:</span><span class="w"> </span><span class="p">|</span><span class="sd">
</span></span></span><span class="line"><span class="cl"><span class="sd">            &lt;config&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">              &lt;System xmlns=&#34;http://cisco.com/ns/yang/cisco-nx-os-device&#34;&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                &lt;intf-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                  &lt;lb-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                    &lt;LbRtdIf-list&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                      &lt;id&gt;lo100&lt;/id&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                      &lt;adminSt&gt;down&lt;/adminSt&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                    &lt;/LbRtdIf-list&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                  &lt;/lb-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">                &lt;/intf-items&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">              &lt;/System&gt;
</span></span></span><span class="line"><span class="cl"><span class="sd">            &lt;/config&gt;</span><span class="w">
</span></span></span></code></pre></div><p>And, if we try to run the playbook again:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="cl"><span class="o">(</span>ansible<span class="o">)</span> matt@ansible-dev:~/ansible/nxos$ ansible-playbook nx-update-interface.yaml -i inventory.yml
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">PLAY <span class="o">[</span>NX-OS Interface Updates<span class="o">]</span> **********************************************************************************************************
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">TASK <span class="o">[</span>Update Interface State<span class="o">]</span> ***********************************************************************************************************
</span></span><span class="line"><span class="cl">changed: <span class="o">[</span>10.122.2.229<span class="o">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">PLAY RECAP ******************************************************************************************************************************
</span></span><span class="line"><span class="cl">10.122.2.229               : <span class="nv">ok</span><span class="o">=</span><span class="m">1</span>    <span class="nv">changed</span><span class="o">=</span><span class="m">1</span>    <span class="nv">unreachable</span><span class="o">=</span><span class="m">0</span>    <span class="nv">failed</span><span class="o">=</span><span class="m">0</span>    <span class="nv">skipped</span><span class="o">=</span><span class="m">0</span>    <span class="nv">rescued</span><span class="o">=</span><span class="m">0</span>    <span class="nv">ignored</span><span class="o">=</span><span class="m">0</span>
</span></span></code></pre></div><p>That looks much better!</p>
<hr>
<p>Thanks so much for reading this blog post. I really hope it was helpful to you!</p>
<p>If you found value in this, please let me know! Feel free to leave me a comment below, or follow me on <a href="https://www.youtube.com/@0x2142">YouTube</a>!</p>
<p>Oh, and for those of you on Mastodon - You can find me at <a href="https://0x2142.com/@matt">@matt@0x2142.com</a>.</p>
<p>Thanks again!</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
