<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="http://www.automate.nyc/feed.xml" rel="self" type="application/atom+xml" /><link href="http://www.automate.nyc/" rel="alternate" type="text/html" /><updated>2026-04-10T17:56:21+00:00</updated><id>http://www.automate.nyc/feed.xml</id><title type="html">Automate NYC!</title><subtitle>Snippet of IT stuff</subtitle><author><name>Eric Chong</name></author><entry><title type="html">Searching in AAP inventory using chain filter</title><link href="http://www.automate.nyc/ansible/aap-search-using-chain/" rel="alternate" type="text/html" title="Searching in AAP inventory using chain filter" /><published>2026-04-10T00:00:00+00:00</published><updated>2026-04-10T00:00:00+00:00</updated><id>http://www.automate.nyc/ansible/aap-search-using-chain</id><content type="html" xml:base="http://www.automate.nyc/ansible/aap-search-using-chain/"><![CDATA[<p>Within an inventory, we need to find hosts that are imported today from one source but not from the other.  This will require the chain filter.  Mindful of the double underscore “_” characters.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Create API query to get list of hosts that are created today and only from in source A but not from source B</span>
  <span class="na">ansible.builtin.set_fact</span><span class="pi">:</span>
    <span class="na">_api_query</span><span class="pi">:</span> <span class="s2">"</span><span class="s">?chain__inventory_sources__name={{</span><span class="nv"> </span><span class="s">source_A</span><span class="nv"> </span><span class="s">}}</span><span class="se">\
</span>                 <span class="s">&amp;chain__not__inventory_sources__name={{</span><span class="nv"> </span><span class="s">source_B</span><span class="nv"> </span><span class="s">}}</span><span class="se">\
</span>                 <span class="s">&amp;created_lt={{</span><span class="nv"> </span><span class="s">_today.stdout}}</span><span class="se">\
</span>                 <span class="s">&amp;page_size=1000"</span>

<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Get list of hosts from API query</span>
  <span class="na">ansible.builtin.uri</span><span class="pi">:</span>
    <span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://{{</span><span class="nv"> </span><span class="s">aap_hostname}}/api/controller/v2/hosts/{{</span><span class="nv"> </span><span class="s">_api_query</span><span class="nv"> </span><span class="s">}}"</span>
    <span class="na">method</span><span class="pi">:</span> <span class="s">Get</span>
    <span class="na">return content</span><span class="pi">:</span> <span class="no">true</span>
    <span class="na">headers</span><span class="pi">:</span>
      <span class="na">Authorization</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Bearer</span><span class="nv"> </span><span class="s">{{</span><span class="nv"> </span><span class="s">_oauthtoken.json.token</span><span class="nv"> </span><span class="s">}}"</span>
    <span class="na">validate_certs</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">controller_validate_certs</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">default(true)</span><span class="nv"> </span><span class="s">}}"</span>
  <span class="na">register</span><span class="pi">:</span> <span class="s">_host_list</span>
  <span class="na">no_log</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">_no_log</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">default(true)</span><span class="nv"> </span><span class="s">}}"</span>

<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">List of hosts to be removed</span>
  <span class="na">ansible.builtin.debug</span><span class="pi">:</span>
    <span class="na">msg</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{_host_list.json.results</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">map(attribute='name')</span><span class="nv"> </span><span class="s">}}"</span>
</code></pre></div></div>]]></content><author><name>Eric Chong</name></author><category term="Ansible" /><category term="aap" /><category term="api" /><category term="ansible" /><summary type="html"><![CDATA[AAP - Find hosts that are imported from one inventory source but not from the other in an inventory]]></summary></entry><entry><title type="html">Using AAP Oauth Application</title><link href="http://www.automate.nyc/ansible/create-oauth-application-token/" rel="alternate" type="text/html" title="Using AAP Oauth Application" /><published>2025-09-19T00:00:00+00:00</published><updated>2025-09-19T00:00:00+00:00</updated><id>http://www.automate.nyc/ansible/create-oauth-application-token</id><content type="html" xml:base="http://www.automate.nyc/ansible/create-oauth-application-token/"><![CDATA[<p>OAuth users are blocked to create token by default.  We would still want to create token to allow other applications that use NPID users to able to connect to AAP but maintaining RBAC rules applied to the users.</p>

<p>Perform these steps as user with AAP admin right.</p>

<h2 id="create-an-oauth-application">Create an OAuth Application</h2>
<p>Creating the OAuth Application via the GUI (Access Management -&gt; OAuth Applications) directly won’t allow to attach to a user, so do either one of these instead.</p>
<h3 id="using-a-ansibleplatform-collection">Using a ansible.platform collection</h3>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">AAP</span><span class="nv"> </span><span class="s">OAuth</span><span class="nv"> </span><span class="s">Application</span><span class="nv"> </span><span class="s">Example"</span>
  <span class="na">hosts</span><span class="pi">:</span> <span class="s">localhost</span>
  <span class="na">ignore_errors</span><span class="pi">:</span> <span class="no">true</span>
  <span class="na">vars</span><span class="pi">:</span>
    <span class="na">aap</span><span class="pi">:</span> <span class="s">aap-node1.lab.automate.nyc</span>
    <span class="na">username</span><span class="pi">:</span> <span class="s">admin</span>
    <span class="na">password</span><span class="pi">:</span> <span class="s">your password</span>
    <span class="na">default_org</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ABC"</span>
    <span class="na">token_user</span><span class="pi">:</span> <span class="s2">"</span><span class="s">eric@lab.automate.nyc"</span>

  <span class="na">tasks</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Login</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">AAP</span><span class="nv"> </span><span class="s">and</span><span class="nv"> </span><span class="s">create</span><span class="nv"> </span><span class="s">AAP</span><span class="nv"> </span><span class="s">token"</span>
    <span class="na">ansible.platform.token</span><span class="pi">:</span>
      <span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">OAuth</span><span class="nv"> </span><span class="s">token"</span>
      <span class="na">scope</span><span class="pi">:</span> <span class="s">write</span>
      <span class="na">state</span><span class="pi">:</span> <span class="s">present</span>
      <span class="na">gateway_hostname</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
      <span class="na">gateway_username</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
      <span class="na">gateway_password</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
      <span class="na">gateway_validate_certs</span><span class="pi">:</span> <span class="no">false</span>
    <span class="na">tags</span><span class="pi">:</span> <span class="s">always</span>

  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Create</span><span class="nv"> </span><span class="s">OAuth</span><span class="nv"> </span><span class="s">Application</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">association</span><span class="nv"> </span><span class="s">with</span><span class="nv"> </span><span class="s">user</span><span class="nv"> </span><span class="s">"</span>
    <span class="na">ansible.platform.application</span><span class="pi">:</span>
      <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">OAuth</span><span class="nv"> </span><span class="s">Application</span><span class="nv"> </span><span class="s">Token</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">"</span>
      <span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">OAuth</span><span class="nv"> </span><span class="s">Application</span><span class="nv"> </span><span class="s">Example"</span>
      <span class="na">organization</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
      <span class="na">state</span><span class="pi">:</span> <span class="s">present</span>
      <span class="na">authorization_grant_type</span><span class="pi">:</span> <span class="s">authorization-code</span>
      <span class="na">client_type</span><span class="pi">:</span> <span class="s">confidential</span>
      <span class="na">redirect_uris</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="s">https:///api/gateway/v1/</span>
      <span class="na">gateway_hostname</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
      <span class="na">gateway_token</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
      <span class="na">gateway_validate_certs</span><span class="pi">:</span> <span class="no">false</span>
      <span class="na">user</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
    <span class="na">register</span><span class="pi">:</span> <span class="s">_oauth_application</span>
    <span class="na">tags</span><span class="pi">:</span> <span class="s">gateway</span>

  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Output</span><span class="nv"> </span><span class="s">OAuth</span><span class="nv"> </span><span class="s">Application</span><span class="nv"> </span><span class="s">Info</span><span class="nv"> </span><span class="s">"</span>
    <span class="na">ansible.builtin.debug</span><span class="pi">:</span>
      <span class="na">msg</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
</code></pre></div></div>

<p>Save the <code class="language-plaintext highlighter-rouge">client_id</code> and <code class="language-plaintext highlighter-rouge">client_secret</code> for later use</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">TASK [Output OAuth Application Info] ***************************************************************************************************</span>
<span class="na">ok</span><span class="pi">:</span> <span class="pi">[</span><span class="nv">localhost</span><span class="pi">]</span> <span class="s">=&gt; {</span>
    <span class="s">"msg"</span><span class="err">:</span> <span class="pi">{</span>
        <span class="s2">"</span><span class="s">changed"</span><span class="pi">:</span> <span class="nv">true</span><span class="pi">,</span>
        <span class="s2">"</span><span class="s">client_id"</span><span class="pi">:</span> <span class="s2">"</span><span class="s">KtWnWDJOrLhhxKyVgGIxc4ObnXlh3GUVwK9x3LK0"</span><span class="pi">,</span>
        <span class="s2">"</span><span class="s">client_secret"</span><span class="pi">:</span> <span class="s2">"</span><span class="s">zgGTk4iuzO2YL96QTVLjc0T1wsxkaQHCqHlHusi7BBnYjRXXMTMlXqzHVWrEXmpZWLVI3YNsfMmkISwniH2srvxS7bo46ClZCJrd4B2TU8OOtt4ZgQqpZebQrbN1at4q"</span><span class="pi">,</span>
        <span class="s2">"</span><span class="s">failed"</span><span class="pi">:</span> <span class="nv">false</span><span class="pi">,</span>
        <span class="s2">"</span><span class="s">id"</span><span class="pi">:</span> <span class="nv">9</span><span class="pi">,</span>
        <span class="s2">"</span><span class="s">name"</span><span class="pi">:</span> <span class="s2">"</span><span class="s">OAuth</span><span class="nv"> </span><span class="s">Application</span><span class="nv"> </span><span class="s">Token</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">eric@lab.automate.nyc"</span>
    <span class="pi">}</span>
<span class="err">}</span>
</code></pre></div></div>

<h3 id="via-api-page">Via API page</h3>
<ul>
  <li>Visit https://hostname/api/gateway/v1/applications/ API page</li>
  <li>Fill in the same info as in the playbook above</li>
  <li>Save the <code class="language-plaintext highlighter-rouge">client_id</code> and <code class="language-plaintext highlighter-rouge">client_secret</code> for later use</li>
</ul>

<h2 id="create-a-token-linked-to-oauth-application">Create a token linked to OAuth Application</h2>
<h3 id="via-gui">Via GUI</h3>
<ul>
  <li>Still as user with admin right, go to User Details -&gt; Token tab and create a token with created OAuth application <img src="/assets/images/2025/2025-09-19-oauth-applications-token-1.jpg" alt="Token Creation" /></li>
  <li>Record the <code class="language-plaintext highlighter-rouge">Token</code> and <code class="language-plaintext highlighter-rouge">Refresh Token</code>.  Noted the <code class="language-plaintext highlighter-rouge">Expires</code> date for the token <img src="/assets/images/2025/2025-09-19-oauth-applications-token-2.jpg" alt="Tokens" /></li>
</ul>

<h3 id="via-ansibleplatform-collection">Via ansible.platform collection</h3>
<p>For example</p>
<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Create</span><span class="nv"> </span><span class="s">token"</span>
    <span class="na">ansible.platform.token</span><span class="pi">:</span>
      <span class="na">description</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Token</span><span class="nv"> </span><span class="s">Example"</span>
      <span class="na">organization</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
      <span class="na">gateway_hostname</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
      <span class="na">gateway_token</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
      <span class="na">gateway_validate_certs</span><span class="pi">:</span> <span class="no">false</span>
      <span class="na">state</span><span class="pi">:</span> <span class="s">present</span>
      <span class="na">scope</span><span class="pi">:</span> <span class="s">write</span>
      <span class="na">application</span><span class="pi">:</span> <span class="s2">"</span><span class="s">OAuth</span><span class="nv"> </span><span class="s">Application</span><span class="nv"> </span><span class="s">Token</span><span class="nv"> </span><span class="s">for</span><span class="nv"> </span><span class="s">"</span>
    <span class="na">register</span><span class="pi">:</span> <span class="s">_token</span>
    <span class="na">tags</span><span class="pi">:</span> <span class="s">gateway</span>
</code></pre></div></div>

<p>Noted that the created token won’t be under the login admin user’s personal access token tab.  Instead it will be found under the OAuth application token tab <img src="/assets/images/2025/2025-09-19-oauth-applications-token-3.jpg" alt="Token list" /></p>

<p>There is no way to see the token detail on the GUI.  We will have to follow the OAuth Application ID on the API page to see them.  For example: https://AAP_hostname/api/gateway/v1/applications/9/tokens/</p>

<h2 id="test">Test</h2>
<p>Now the token is generated, it can be used as regular Bearer token until expiration date.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">--silent</span> <span class="nt">-X</span> GET <span class="nt">-H</span> <span class="s2">"Content-Type: application/json"</span> <span class="nt">-H</span> <span class="s2">"Authorization: Bearer </span><span class="nv">$TOKEN</span><span class="s2">"</span> https://AAP_hostname/api/gateway/v1/me/ | jq <span class="nb">.</span>
</code></pre></div></div>
<p>It will show the OAuth Application user info, instead of the admin user that created the bearer token</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"count"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
  </span><span class="nl">"next"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
  </span><span class="nl">"previous"</span><span class="p">:</span><span class="w"> </span><span class="kc">null</span><span class="p">,</span><span class="w">
  </span><span class="nl">"results"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
    </span><span class="p">{</span><span class="w">
      </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">15</span><span class="p">,</span><span class="w">
      </span><span class="nl">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/api/gateway/v1/users/15/"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"related"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"activity_stream"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/api/gateway/v1/activitystream/?content_type=1&amp;object_id=15"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"created_by"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/api/gateway/v1/users/1/"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"modified_by"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/api/gateway/v1/users/1/"</span><span class="p">,</span><span class="w">
        </span><span class="nl">"authenticators"</span><span class="p">:</span><span class="w"> </span><span class="s2">"/api/gateway/v1/users/15/authenticators/"</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"summary_fields"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"modified_by"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
          </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"_system"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
          </span><span class="nl">"last_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"created_by"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
          </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"_system"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
          </span><span class="nl">"last_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
        </span><span class="p">},</span><span class="w">
        </span><span class="nl">"resource"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"ansible_id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"021be5c1-84fe-4e62-bd1f-4e4292311de3"</span><span class="p">,</span><span class="w">
          </span><span class="nl">"resource_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"shared.user"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"created"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-07-09T19:56:44.973831Z"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"created_by"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
      </span><span class="nl">"modified"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-09-19T15:27:03.543688Z"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"modified_by"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
      </span><span class="nl">"username"</span><span class="p">:</span><span class="w"> </span><span class="s2">"eric@lab.automate.nyc"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"email"</span><span class="p">:</span><span class="w"> </span><span class="s2">"eric@lab.automate.nyc"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"first_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Eric"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"last_name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Chong"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"last_login"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-09-19T15:27:03.580508Z"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"password"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Password Disabled"</span><span class="p">,</span><span class="w">
      </span><span class="nl">"is_superuser"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
      </span><span class="nl">"is_platform_auditor"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
      </span><span class="nl">"managed"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
      </span><span class="nl">"last_login_results"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
        </span><span class="nl">"13"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
          </span><span class="nl">"access_allowed"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
          </span><span class="nl">"last_login_map_results"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
            </span><span class="p">{</span><span class="w">
              </span><span class="nl">"11"</span><span class="p">:</span><span class="w"> </span><span class="s2">"skipped"</span><span class="p">,</span><span class="w">
              </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
            </span><span class="p">},</span><span class="w">
            </span><span class="p">{</span><span class="w">
              </span><span class="nl">"13"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
              </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
            </span><span class="p">},</span><span class="w">
            </span><span class="p">{</span><span class="w">
              </span><span class="nl">"12"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
              </span><span class="nl">"enabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
            </span><span class="p">}</span><span class="w">
          </span><span class="p">],</span><span class="w">
          </span><span class="nl">"last_login_attempt"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2025-09-19T15:27:03.512089Z"</span><span class="w">
        </span><span class="p">}</span><span class="w">
      </span><span class="p">},</span><span class="w">
      </span><span class="nl">"authenticators"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="mi">13</span><span class="w">
      </span><span class="p">],</span><span class="w">
      </span><span class="nl">"authenticator_uid"</span><span class="p">:</span><span class="w"> </span><span class="s2">"251247971"</span><span class="w">
    </span><span class="p">}</span><span class="w">
  </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<h2 id="managing-the-tokens">Managing the tokens</h2>
<h3 id="renew-the-token">Renew the token</h3>
<p>To renew the token, we will need the <code class="language-plaintext highlighter-rouge">refresh_token</code>, <code class="language-plaintext highlighter-rouge">client_id</code> and <code class="language-plaintext highlighter-rouge">client_secret</code> from previous steps</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">--silent</span> <span class="nt">-X</span> POST <span class="nt">-u</span> <span class="nv">$CLIENT_ID</span>:<span class="nv">$CLIENT_SECRET</span> <span class="se">\</span>
<span class="nt">-d</span> <span class="s2">"grant_type=refresh_token&amp;refresh_token=</span><span class="nv">$REFRESH_TOKEN</span><span class="s2">"</span> <span class="se">\</span>
https://aap-node1.lab.automate.nyc/o/token/ | jq <span class="nb">.</span>
</code></pre></div></div>
<p>Save the new <code class="language-plaintext highlighter-rouge">token</code> and <code class="language-plaintext highlighter-rouge">refresh_token</code></p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"access_token"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2nrR64trurN1bPJO0VTbo9OoAuXMaU"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"expires_in"</span><span class="p">:</span><span class="w"> </span><span class="mi">31536000</span><span class="p">,</span><span class="w">
  </span><span class="nl">"token_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Bearer"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"scope"</span><span class="p">:</span><span class="w"> </span><span class="s2">"write"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"refresh_token"</span><span class="p">:</span><span class="w"> </span><span class="s2">"vw4bqEsAzymEjcMCR0t6P8NfJnjUGi"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Note: Refreshing the token seems to change its ownership and hence the permission.  Need further investigation.</p>

<h3 id="revoke-the-token">Revoke the token</h3>
<p>Delete the token from the GUI or via API</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">--silent</span> <span class="nt">-X</span> POST <span class="nt">-u</span> <span class="nv">$CLIENT_ID</span>:<span class="nv">$CLIENT_SECRET</span> <span class="nt">-d</span> <span class="s2">"token=</span><span class="nv">$TOKEN</span><span class="s2">"</span> https://aap-node1.lab.automate.nyc/o/revoke_token/
</code></pre></div></div>]]></content><author><name>Eric Chong</name></author><category term="Ansible" /><category term="ansible" /><category term="aap" /><category term="api" /><category term="session" /><category term="token" /><category term="oauth" /><category term="platform" /><summary type="html"><![CDATA[AAP - Creating OAuth application token linked to an OAuth user]]></summary></entry><entry><title type="html">Using AAP session authentication for API calls</title><link href="http://www.automate.nyc/ansible/aap-api-authentication/" rel="alternate" type="text/html" title="Using AAP session authentication for API calls" /><published>2025-07-21T00:00:00+00:00</published><updated>2025-07-21T00:00:00+00:00</updated><id>http://www.automate.nyc/ansible/aap-api-authentication</id><content type="html" xml:base="http://www.automate.nyc/ansible/aap-api-authentication/"><![CDATA[<p>While reading the <a href="https://docs.redhat.com/en/documentation/red_hat_ansible_automation_platform/2.5/html/automation_execution_api_overview/controller-api-auth-methods">Automation execution API overview</a> doc, I noticed that beside <a href="https://www.automate.nyc/ansible/How_to_authenticate_with_auth_token/">OAuth 2 token</a>, and basic auth with username and password, we can also use gateway session ID cookie.</p>

<p>Here is a quick summary of steps using CURL and shell script.</p>

<h2 id="get-the-csrf-token">Get the CSRF Token</h2>
<p>Hitting the login page with curl</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-s</span> <span class="nt">-c</span> - https://<span class="nv">$AAP_HOSTNAME</span>/api/gateway/v1/login/
</code></pre></div></div>
<p>will generate the <code class="language-plaintext highlighter-rouge">csrfToken</code> somewhere in the output like</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>...
&lt;/div&gt;

      &lt;script <span class="nb">type</span><span class="o">=</span><span class="s2">"application/json"</span> <span class="nb">id</span><span class="o">=</span><span class="s2">"drf_csrf"</span><span class="o">&gt;</span>
        <span class="o">{</span>
          <span class="s2">"csrfHeaderName"</span>: <span class="s2">"X-CSRFToken"</span>,
          <span class="s2">"csrfToken"</span>: <span class="s2">"eC1zNXSLZHTE6xqu9xwC6TU57HS91b8uDAfwVsac6Uaonmi31D4cB8tFcPcqzGwn"</span>
        <span class="o">}</span>
      &lt;/script&gt;
      &lt;script <span class="nv">src</span><span class="o">=</span><span class="s2">"/static/rest_framework/js/jquery-3.7.1.min.js"</span><span class="o">&gt;</span>&lt;/script&gt;
      &lt;script <span class="nv">src</span><span class="o">=</span><span class="s2">"/static/rest_framework/js/ajax-form.js"</span><span class="o">&gt;</span>&lt;/script&gt;
...
</code></pre></div></div>

<h3 id="get-the-gateway_sessionid-cookie">Get the gateway_sessionid cookie</h3>
<p>Using the <code class="language-plaintext highlighter-rouge">csrfToken</code>, login with <code class="language-plaintext highlighter-rouge">username</code> and <code class="language-plaintext highlighter-rouge">password</code></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-s</span> <span class="nt">-X</span> POST <span class="nt">-D</span> - <span class="nt">-H</span> <span class="s1">'Content-Type: application/x-www-form-urlencoded'</span> <span class="se">\</span>
<span class="nt">--referer</span> https://<span class="nv">$AAP_HOSTNAME</span>/api/gateway/v1/login/ <span class="se">\</span>
<span class="nt">-H</span> <span class="s2">"X-CSRFToken: </span><span class="nv">$CSRFTOKEN</span><span class="s2">"</span> <span class="se">\</span>
<span class="nt">--data</span> <span class="s2">"username=</span><span class="nv">$AAP_USERNAME</span><span class="s2">&amp;password=</span><span class="nv">$AAP_PASSWORD</span><span class="s2">"</span> <span class="se">\</span>
<span class="nt">--cookie</span> <span class="s2">"csrftoken=</span><span class="nv">$CSRFTOKEN</span><span class="s2">"</span> <span class="se">\</span>
https://<span class="nv">$AAP_HOSTNAME</span>/api/gateway/v1/login/
</code></pre></div></div>
<p>Check the header output of the response and look for <code class="language-plaintext highlighter-rouge">gateway_sessionid</code> cookie</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>HTTP/1.1 302 Found
server: envoy
<span class="nb">date</span>: Mon, 21 Jul 2025 21:41:23 GMT
content-type: text/html<span class="p">;</span> <span class="nv">charset</span><span class="o">=</span>utf-8
content-length: 0
location: /api/gateway/v1/
expires: Mon, 21 Jul 2025 21:41:23 GMT
cache-control: max-age<span class="o">=</span>0, no-cache, no-store, must-revalidate, private
vary: Cookie
x-frame-options: DENY
x-content-type-options: nosniff
referrer-policy: same-origin
cross-origin-opener-policy: same-origin
set-cookie: <span class="nv">csrftoken</span><span class="o">=</span>CoVFnyrQg4QZDthOpsqmIyUNJ7W2JBvJ<span class="p">;</span> <span class="nv">expires</span><span class="o">=</span>Mon, 20 Jul 2026 21:41:23 GMT<span class="p">;</span> Max-Age<span class="o">=</span>31449600<span class="p">;</span> <span class="nv">Path</span><span class="o">=</span>/<span class="p">;</span> <span class="nv">SameSite</span><span class="o">=</span>Lax<span class="p">;</span> Secure
set-cookie: <span class="nv">gateway_sessionid</span><span class="o">=</span>9tltx97vwynzpdw0xbohp2vtwo2suvbu<span class="p">;</span> <span class="nv">expires</span><span class="o">=</span>Mon, 21 Jul 2025 21:56:23 GMT<span class="p">;</span> HttpOnly<span class="p">;</span> Max-Age<span class="o">=</span>900<span class="p">;</span> <span class="nv">Path</span><span class="o">=</span>/<span class="p">;</span> <span class="nv">SameSite</span><span class="o">=</span>Lax<span class="p">;</span> Secure
strict-transport-security: max-age<span class="o">=</span>63072000
x-content-type-options: nosniff
x-envoy-upstream-service-time: 260
</code></pre></div></div>
<p>Now we can access other APIs using this <code class="language-plaintext highlighter-rouge">gateway_sessionid</code> cookie.  For example, to check the status</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl <span class="nt">-X</span> GET <span class="nt">-H</span> <span class="s1">'Cookie: gateway_sessionid=9tltx97vwynzpdw0xbohp2vtwo2suvbu;'</span>  https://<span class="nv">$AAP_HOSTNAME</span>/api/gateway/v1/status/
</code></pre></div></div>

<h3 id="note">Note</h3>
<ul>
  <li>No OAuth2 token will be generated under the authenticated user</li>
  <li>The session ID expiration is controlled by Settings -&gt; Platform gateway -&gt; Session cookie age</li>
</ul>

<h3 id="complete-shell-script">Complete shell script</h3>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">AAP_HOSTNAME</span><span class="o">=</span><span class="nb">hostname
</span><span class="nv">AAP_USERNAME</span><span class="o">=</span>username
<span class="nv">AAP_PASSWORD</span><span class="o">=</span>password

<span class="nv">CSRF_TOKEN</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">-s</span> <span class="nt">-c</span> - https://<span class="nv">$AAP_HOSTNAME</span>/api/gateway/v1/login/ | <span class="nb">awk</span> <span class="s1">'/&lt;script type="application\/json" id="drf_csrf"&gt;/{flag=1; next} /&lt;\/script&gt;/{flag=0} flag'</span> | jq .csrfToken<span class="si">)</span>

<span class="nv">SESSIONID</span><span class="o">=</span><span class="si">$(</span>curl <span class="nt">-s</span> <span class="nt">-X</span> POST <span class="nt">-D</span> - <span class="nt">-H</span> <span class="s1">'Content-Type: application/x-www-form-urlencoded'</span> <span class="se">\</span>
<span class="nt">--referer</span> https://<span class="nv">$AAP_HOSTNAME</span>/api/gateway/v1/login/ <span class="se">\</span>
<span class="nt">-H</span> <span class="s2">"X-CSRFToken: </span><span class="nv">$CSRFTOKEN</span><span class="s2">"</span> <span class="se">\</span>
<span class="nt">--data</span> <span class="s2">"username=</span><span class="nv">$AAP_USERNAME</span><span class="s2">&amp;password=</span><span class="nv">$AAP_PASSWORD</span><span class="s2">"</span> <span class="se">\</span>
<span class="nt">--cookie</span> <span class="s2">"csrftoken=</span><span class="nv">$CSRFTOKEN</span><span class="s2">"</span> <span class="se">\</span>
https://<span class="nv">$AAP_HOSTNAME</span>/api/gateway/v1/login/ | <span class="nb">awk</span> <span class="s1">'/gateway_sessionid/ {print $2}'</span><span class="si">)</span>

curl <span class="nt">-X</span> GET <span class="nt">-H</span> <span class="s2">"Cookie: </span><span class="nv">$SESSIONID</span><span class="s2">"</span>  https://<span class="nv">$AAP_HOSTNAME</span>/api/gateway/v1/status/ | jq <span class="nb">.</span>
</code></pre></div></div>]]></content><author><name>Eric Chong</name></author><category term="Ansible" /><category term="ansible" /><category term="aap" /><category term="api" /><category term="session" /><category term="token" /><summary type="html"><![CDATA[AAP - Using AAP session authentication for API calls]]></summary></entry><entry><title type="html">Setting up Windows VM on RHEL with GPU passthru</title><link href="http://www.automate.nyc/rhel/kvm-gpu-passthru/" rel="alternate" type="text/html" title="Setting up Windows VM on RHEL with GPU passthru" /><published>2025-01-19T00:00:00+00:00</published><updated>2025-09-16T00:00:00+00:00</updated><id>http://www.automate.nyc/rhel/kvm-gpu-passthru</id><content type="html" xml:base="http://www.automate.nyc/rhel/kvm-gpu-passthru/"><![CDATA[<h3 id="background">Background</h3>
<p>Instead of dual boot my PC, I want to use RHEL as my main OS and run the Windows 11 as a VM on top.  However, gaming will be terrible without a dedicated GPU for the Windows VM.  Here is my experience turning setting up GPU passthru for my setup.</p>

<h3 id="hardware">Hardware</h3>
<ul>
  <li>CPU: AMD Ryzen 5 7600X with Radeon Graphics</li>
  <li>GPU: RTX 3060</li>
  <li>Motherboard: Gigabyte B650 Eagle AX that support onboard graphic</li>
  <li>Memory: 64 GB</li>
</ul>

<p>We will be using the onboard GPU for RHEL OS.  The discrete GPU will be dedicated to the VM.</p>

<h3 id="kernel-parameters">Kernel parameters</h3>
<h4 id="ignore-the-discrete-gpu">Ignore the discrete GPU</h4>
<p>Find the hardware addresses of the video card using <code class="language-plaintext highlighter-rouge">lspci</code> command.  The are in the <code class="language-plaintext highlighter-rouge">[]</code></p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>root@ryzen5-7k ~]# lspci <span class="nt">-Dnn</span> | <span class="nb">grep </span>NVIDIA
0000:01:00.0 VGA compatible controller <span class="o">[</span>0300]: NVIDIA Corporation GA104 <span class="o">[</span>GeForce RTX 3060] <span class="o">[</span>10de:2487] <span class="o">(</span>rev a1<span class="o">)</span>
0000:01:00.1 Audio device <span class="o">[</span>0403]: NVIDIA Corporation GA104 High Definition Audio Controller <span class="o">[</span>10de:228b] <span class="o">(</span>rev a1<span class="o">)</span>
</code></pre></div></div>
<p>Setup these kernel argument to ignore the NVIDIA graphic card</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>grubby <span class="nt">--args</span><span class="o">=</span><span class="s2">"pci-stub.ids=10de:2487,10de:228b"</span> <span class="nt">--update-kernel</span> ALL
</code></pre></div></div>

<h4 id="allocate-hugepage-memory-block-for-the-vm">Allocate Hugepage memory block for the VM</h4>
<p>Allocate 16 GB of RAM (in 1GB block) for the VM using Hupage</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>root@ryzen5-7k ~]# grubby <span class="nt">--update-kernel</span><span class="o">=</span>ALL <span class="nt">--args</span><span class="o">=</span><span class="s2">"default_hugepagesz=1G hugepagesz=1G hugepages=16"</span>
</code></pre></div></div>

<h4 id="verify">Verify</h4>
<p>Verify the kernel parameters are added.  We will have to rerun the command if new kernel is installed.</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>root@ryzen5-7k ~]# grubby <span class="nt">--info</span><span class="o">=</span>/boot/vmlinuz-5.14.0-503.19.1.el9_5.x86_64
<span class="nv">index</span><span class="o">=</span>0
<span class="nv">kernel</span><span class="o">=</span><span class="s2">"/boot/vmlinuz-5.14.0-503.19.1.el9_5.x86_64"</span>
<span class="nv">args</span><span class="o">=</span><span class="s2">"ro crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M resume=/dev/mapper/vg_root-swap rd.lvm.lv=vg_root/lv_root rd.lvm.lv=vg_root/swap rhgb iommu=pt pci-stub.ids=10de:2487,10de:228b default_hugepagesz=1G hugepagesz=1G hugepages=16"</span>
<span class="nv">root</span><span class="o">=</span><span class="s2">"/dev/mapper/vg_root-lv_root"</span>
<span class="nv">initrd</span><span class="o">=</span><span class="s2">"/boot/initramfs-5.14.0-503.19.1.el9_5.x86_64.img </span><span class="nv">$tuned_initrd</span><span class="s2">"</span>
<span class="nv">title</span><span class="o">=</span><span class="s2">"Red Hat Enterprise Linux (5.14.0-503.19.1.el9_5.x86_64) 9.5 (Plow)"</span>
<span class="nb">id</span><span class="o">=</span><span class="s2">"a0b8e89423bd44eda123e83b2776fa61-5.14.0-503.19.1.el9_5.x86_64"</span>
</code></pre></div></div>
<p>We should also see 16GB RAM of Hugepage allocated</p>
<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span>root@ryzen5-7k ~]# <span class="nb">cat</span> /proc/meminfo | <span class="nb">grep </span>Huge
AnonHugePages:    352256 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:      16
HugePages_Free:       16
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:    1048576 kB
Hugetlb:        16777216 kB
</code></pre></div></div>

<h3 id="vm-settings">VM settings</h3>
<p>Assuming the Windows 11 VM is already installed.  Following configurations need to be added to the XML of the VM.</p>

<h4 id="hugepage">Hugepage</h4>
<p>Add <code class="language-plaintext highlighter-rouge">memoryBacking</code> to use Hugepages</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nt">&lt;memoryBacking&gt;</span>
    <span class="nt">&lt;hugepages/&gt;</span>
  <span class="nt">&lt;/memoryBacking&gt;</span>
</code></pre></div></div>

<h4 id="keyboard-and-mouse">Keyboard and Mouse</h4>
<p>Update the domain line</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;domain</span> <span class="na">type=</span><span class="s">'kvm'</span> <span class="na">id=</span><span class="s">'6'</span> <span class="na">xmlns:qemu=</span><span class="s">'http://libvirt.org/schemas/domain/qemu/1.0'</span><span class="nt">&gt;</span>
</code></pre></div></div>
<p>Also add these to specify the RHEL host’s keyboard and mouse</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="nt">&lt;qemu:commandline&gt;</span>
    <span class="nt">&lt;qemu:arg</span> <span class="na">value=</span><span class="s">'-object'</span><span class="nt">/&gt;</span>
    <span class="nt">&lt;qemu:arg</span> <span class="na">value=</span><span class="s">'input-linux,id=kbd1,evdev=/dev/input/by-id/usb-COOLER_MASTER_SK622_Mechanical_Keyboard_-_Black_Edition-event-kbd,grab_all=on,repeat=on'</span><span class="nt">/&gt;</span>
    <span class="nt">&lt;qemu:arg</span> <span class="na">value=</span><span class="s">'-object'</span><span class="nt">/&gt;</span>
    <span class="nt">&lt;qemu:arg</span> <span class="na">value=</span><span class="s">'input-linux,id=kbd2,evdev=/dev/input/by-id/usb-COOLER_MASTER_SK622_Mechanical_Keyboard_-_Black_Edition-if02-event-kbd,grab_all=on,repeat=on'</span><span class="nt">/&gt;</span> 
    <span class="nt">&lt;qemu:arg</span> <span class="na">value=</span><span class="s">'-object'</span><span class="nt">/&gt;</span>
    <span class="nt">&lt;qemu:arg</span> <span class="na">value=</span><span class="s">'input-linux,id=mouse1,evdev=/dev/input/by-id/usb-COOLER_MASTER_SK622_Mechanical_Keyboard_-_Black_Edition-if02-event-mouse'</span><span class="nt">/&gt;</span>
    <span class="nt">&lt;qemu:arg</span> <span class="na">value=</span><span class="s">'-object'</span><span class="nt">/&gt;</span>
    <span class="nt">&lt;qemu:arg</span> <span class="na">value=</span><span class="s">'input-linux,id=mouse2,evdev=/dev/input/by-id/usb-Logitech_USB_Receiver-event-mouse'</span><span class="nt">/&gt;</span>
  <span class="nt">&lt;/qemu:commandline&gt;</span>
</code></pre></div></div>

<p>Also need to add a USB mouse for the scroll wheel to work</p>
<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>    <span class="nt">&lt;input</span> <span class="na">type=</span><span class="s">'mouse'</span> <span class="na">bus=</span><span class="s">'usb'</span><span class="nt">&gt;</span>
      <span class="nt">&lt;alias</span> <span class="na">name=</span><span class="s">'input0'</span><span class="nt">/&gt;</span>
      <span class="nt">&lt;address</span> <span class="na">type=</span><span class="s">'usb'</span> <span class="na">bus=</span><span class="s">'0'</span> <span class="na">port=</span><span class="s">'1'</span><span class="nt">/&gt;</span>
    <span class="nt">&lt;/input&gt;</span>
</code></pre></div></div>

<p>Checkout these references of <code class="language-plaintext highlighter-rouge">evdev_helper</code>:</p>
<ul>
  <li><a href="https://www.youtube.com/watch?v=4XDvHQbgujI&amp;t=4s">Evdev guide: sharing mouse and keyboard between host and VM</a></li>
  <li><a href="https://github.com/pavolelsig/evdev_helper/blob/main/README.md">README</a></li>
</ul>

<h4 id="audio">Audio</h4>
<p>The <code class="language-plaintext highlighter-rouge">pipewire</code> media server seems to work fine as generic Windows audio device.  User must login to host system to here to audio.</p>

<h4 id="cpu-pinning">CPU pinning</h4>
<p>TBD</p>]]></content><author><name>Eric Chong</name></author><category term="RHEL" /><category term="rhel" /><category term="windows" /><category term="vm" /><category term="kvm" /><category term="libvirt" /><category term="gpu" /><summary type="html"><![CDATA[RHEL - Setting up Windows VM on RHEL with GPU passthru]]></summary></entry><entry><title type="html">Using HashiCorp Vault Signed SSH with AAP</title><link href="http://www.automate.nyc/ansible/aap-hashicorp-signed-ssh/" rel="alternate" type="text/html" title="Using HashiCorp Vault Signed SSH with AAP" /><published>2024-08-27T00:00:00+00:00</published><updated>2025-09-16T00:00:00+00:00</updated><id>http://www.automate.nyc/ansible/aap-hashicorp-signed-ssh</id><content type="html" xml:base="http://www.automate.nyc/ansible/aap-hashicorp-signed-ssh/"><![CDATA[<p>In this post <a href="https://www.automate.nyc/ansible/aap-signed-ssh-cert/">Using signed SSH certificate in AAP</a>, we sign the the SSH key on command line before we create the AAP machine credential.  In this article, we will use HashiCorp Vault to sign the SSH key on-the-fly from AAP machine credential.</p>

<h3 id="enable-the-hashicorp-vault-ssh-secret-engine">Enable the HashiCorp Vault SSH secret engine</h3>
<p>See the HashiCorp doc on setting up <a href="https://developer.hashicorp.com/vault/docs/secrets/ssh/signed-ssh-certificates">Signed SSH  certificates</a></p>

<p>We will be setting a <code class="language-plaintext highlighter-rouge">-path</code> called <code class="language-plaintext highlighter-rouge">ssh</code> and generate a signing key.</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vault secrets enable -path=ssh ssh
vault write ssh/config/ca generate_signing_key=true
</code></pre></div></div>

<p>Create a <code class="language-plaintext highlighter-rouge">role</code> called <code class="language-plaintext highlighter-rouge">my-role</code> with default user <code class="language-plaintext highlighter-rouge">root</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>vault write ssh/roles/my-role -&lt;&lt;"EOH"
{
  "algorithm_signer": "rsa-sha2-256",
  "allow_user_certificates": true,
  "allowed_users": "*",
  "allowed_extensions": "permit-pty,permit-port-forwarding",
  "default_extensions": {
    "permit-pty": ""
  },
  "key_type": "ca",
  "default_user": "root",
  "ttl": "30m0s"
}
EOH
</code></pre></div></div>
<p>From HashiCorp Vault console, it will look like
<img src="/assets/images/2024/2024-08-27-hashicorp-vault-ssh.png" alt="HashiCorp Vault SSH" /></p>

<h3 id="setup-managed-hosts">Setup Managed Hosts</h3>
<p>Download the signing public key from HashiCorp Vault to managed host</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>curl -o /etc/ssh/trusted-user-ca-keys.pem https://infra-1.lab.automate.nyc:8200/v1/ssh/public_key
</code></pre></div></div>

<p>Add the public key to <code class="language-plaintext highlighter-rouge">sshd</code> trusted user CA keys in <code class="language-plaintext highlighter-rouge">/etc/ssh/sshd_config</code></p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pem
</code></pre></div></div>
<p>Restart <code class="language-plaintext highlighter-rouge">sshd</code> service</p>

<h3 id="setup-aap-credentials">Setup AAP Credentials</h3>
<p>Setup <code class="language-plaintext highlighter-rouge">HashiCorp Vault Signed SSH</code> lookup credential using any supported authentication method with HashiCorp Vault.
<img src="/assets/images/2024/2024-08-27-aap-hashicorp-vault-signed-ssh.png" alt="HashiCorp Vault Signed SSH" /></p>

<p>Generate a SSH key pair using <code class="language-plaintext highlighter-rouge">ssh-keygen</code> on command line.  The public and private keys will be used in next step.</p>

<p>Setup <code class="language-plaintext highlighter-rouge">Machine</code> credential in AAP.  Copy generated private key to <code class="language-plaintext highlighter-rouge">SSH Private Key</code> text box.
<img src="/assets/images/2024/2024-08-27-aap-machine-credential.png" alt="AAP Machine credential" /></p>

<p>Selected the created <code class="language-plaintext highlighter-rouge">HashiCorp Vault Signed SSH</code> lookup credential for <code class="language-plaintext highlighter-rouge">Signed SSH Certificate</code>. Copy generated public key to <code class="language-plaintext highlighter-rouge">Unsigned Public Key</code> text box.  Enter the <code class="language-plaintext highlighter-rouge">-path</code> we created for the HashiCorp Vault secret engine (<code class="language-plaintext highlighter-rouge">ssh</code> in this example).  Enter the <code class="language-plaintext highlighter-rouge">role</code> we created for the secret engine (<code class="language-plaintext highlighter-rouge">my-role</code> in this example) 
<img src="/assets/images/2024/2024-08-27-aap-machine-credential-lookup.png" alt="AAP Machine credential lookup" /></p>

<p>Use the <code class="language-plaintext highlighter-rouge">Test</code> button to confirm the configuration.</p>

<h3 id="testing">Testing</h3>
<p>At runtime, a new certificate will be added to the execution environment on AAP.  Following message will be added to the job output:</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Identity added: /runner/artifacts/4261/ssh_key_data (root@node79.lab.automate.nyc)
Certificate added: /runner/artifacts/4261/ssh_key_data-cert.pub (vault-root-ebdeb8a00c160ad918e6e8238bf92c27dfea3ec340e230de3ea59093e3773c38)
</code></pre></div></div>

<p>On the client side, you should see the syslog message indicating that the certificate being used for login</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Aug 27 13:14:07 node79.lab.automate.nyc sshd[1490]: Accepted publickey for root from 192.168.0.101 port 42668 ssh2: RSA-CERT SHA256:6964oAwWCtkY5ugji/ksJ9/qPsNA4jDePqWQk+N3PDg ID vault-root-ebdeb8a00c160ad918e6e8238bf92c27dfea3ec340e230de3ea59093e3773c38 (serial 10466434135153983140) CA RSA SHA256:HUT+GSDsOwFaCfW9l/CvOg+7GYu2UIQS1Yfcwr1uuYo
</code></pre></div></div>

<h3 id="update">Update</h3>
<p>2025-09-16 Checkout this blog post from Hashicorp: <a href="https://www.hashicorp.com/en/blog/managing-ansible-automation-platform-aap-credentials-at-scale-with-vault?sc_cid=701f2000000txokAAA&amp;utm_source=bambu&amp;utm_medium=organic_social_">Managing Ansible Automation Platform (AAP) credentials at scale with Vault</a></p>]]></content><author><name>Eric Chong</name></author><category term="Ansible" /><category term="ansible" /><category term="aap" /><category term="hashicorp" /><category term="vault" /><category term="ssh" /><category term="tower" /><category term="certificate" /><summary type="html"><![CDATA[AAP - Using HashiCorp Vault Signed SSH with AAP]]></summary></entry><entry><title type="html">Using Datadog as External Logging for AAP</title><link href="http://www.automate.nyc/ansible/aap-datadog-logging/" rel="alternate" type="text/html" title="Using Datadog as External Logging for AAP" /><published>2024-06-07T00:00:00+00:00</published><updated>2024-06-07T00:00:00+00:00</updated><id>http://www.automate.nyc/ansible/aap-datadog-logging</id><content type="html" xml:base="http://www.automate.nyc/ansible/aap-datadog-logging/"><![CDATA[<p>If you want to integrate Datadog logging directly with the playbooks or projects, check out this article <a href="https://access.redhat.com/solutions/3982961">KB3982961</a> and <a href="https://github.com/DataDog/ansible-datadog-callback">Datadog callback plugin</a></p>

<p>Datadog is not a support external logger for AAP.  Here we will set it up by creating a customize rsyslog configuration and trick AAP dumping events to a discard port.</p>

<ol>
  <li>Create a rsyslog config file <code class="language-plaintext highlighter-rouge">/var/lib/awx/rsyslog/conf.d/datadog_rsyslog.conf</code>
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>template( name="awx_datadog" type="list") {
  constant(value="{")
  constant(value="\"ddsource\": \"aap\", ")
  constant(value="\"ddtags\": \"env:LAB,type:ansible,application:ansible\", ")
  constant(value="\"hostname\": \"")
  property(name="hostname")
  constant(value="\", ")
  constant(value="\"message\": ")
  property(name="rawmsg-after-pri")
  constant(value="}\n")
}
module(load="omhttp")
action(
  type="omhttp"
  server="http-intake.logs.datadoghq.com"
  restpath="api/v2/logs"
  serverport="443"
  usehttps="on"
  allowunsignedcerts="off"
  skipverifyhost="off"
  action.resumeRetryCount="-1"
  template="awx_datadog"
  action.resumeInterval="5"
  errorfile="/var/log/tower/rsyslog.err"
  queue.spoolDirectory="/var/lib/awx"
  queue.filename="awx-datadog-logger-action-queue"
  queue.maxDiskSpace="1g"
  queue.maxFileSize="100m"
  queue.type="LinkedList"
  queue.saveOnShutdown="on"
  queue.syncqueuefiles="on"
  queue.checkpointInterval="1000"
  queue.size="131072"
  queue.highwaterMark="98304"
  queue.discardMark="117964"
  queue.discardSeverity="5"
  httpheaders=[ "DD-API-KEY: XXXXXXXXXXXXXXXXXXXXXXXXXXX" ]
)
</code></pre></div>    </div>
    <p>This generate an JSON output that follow <a href="https://docs.datadoghq.com/api/latest/logs/#send-logs">this Datadog doc</a>.  The <code class="language-plaintext highlighter-rouge">DD-API-KEY</code> header should contain the API key to authenticate with Datadog.</p>
  </li>
  <li>
    <p>AAP won’t send events to external logger unless an aggregator is configured.  We will setup a dummy aggregator by sending events to discard port (9/udp) on localhost.  Since it is a privilege port, normal user should not be able to listen to these events. <img src="/assets/images/2024/2024-06-07-datadog-aap-setting.png" alt="External Logging Settings" /></p>
  </li>
  <li>To see the AAP Rsyslog debug message, enable the <code class="language-plaintext highlighter-rouge">LOG_AGGREGATOR_RSYSLOGD_DEBUG</code> via the REST API <code class="language-plaintext highlighter-rouge">https://AAP Controller/api/v2/settings/logging/</code>.  This is not the <code class="language-plaintext highlighter-rouge">LOG_AGGREGATOR_LEVEL</code> parameter that can be set via the web GUI.  Once enabled, AAP Rsyslog debug messages can be found in <code class="language-plaintext highlighter-rouge">/var/log/supervisor/awx-rsyslog.log</code></li>
</ol>]]></content><author><name>Eric Chong</name></author><category term="Ansible" /><category term="ansible" /><category term="aap" /><category term="datadog" /><category term="rsyslog" /><category term="logging" /><summary type="html"><![CDATA[AAP - Using Datadog as external logging aggregator]]></summary></entry><entry><title type="html">Some useful examples of using map</title><link href="http://www.automate.nyc/ansible/map-examples/" rel="alternate" type="text/html" title="Some useful examples of using map" /><published>2024-03-11T00:00:00+00:00</published><updated>2024-03-11T00:00:00+00:00</updated><id>http://www.automate.nyc/ansible/map-examples</id><content type="html" xml:base="http://www.automate.nyc/ansible/map-examples/"><![CDATA[<p>Apped some string to a list of string</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>  <span class="na">vars</span><span class="pi">:</span>
    <span class="na">file_name</span><span class="pi">:</span>
      <span class="pi">-</span> <span class="s1">'</span><span class="s">my_file'</span>
      <span class="pi">-</span> <span class="s1">'</span><span class="s">some_other_file'</span>
  <span class="na">tasks</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">List all similar files</span> 
      <span class="na">ansible.builtin.find</span><span class="pi">:</span>
        <span class="na">paths</span><span class="pi">:</span>
          <span class="pi">-</span> <span class="s2">"</span><span class="s">/tmp/"</span>
        <span class="na">patterns</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">['*']</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">product(file_name)</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">map('join')</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">list</span><span class="nv"> </span><span class="s">}}"</span>
      <span class="na">register</span><span class="pi">:</span> <span class="s">_matched</span>
</code></pre></div></div>

<p>or</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>        patterns: "{{ file_name | map('regex_replace', '^(.*)$', '*\\1*') }}"
</code></pre></div></div>]]></content><author><name>Eric Chong</name></author><category term="Ansible" /><category term="ansible" /><category term="map" /><summary type="html"><![CDATA[Ansible - Some examples using map]]></summary></entry><entry><title type="html">Install Ansible Collection Directly from console.redhat.com</title><link href="http://www.automate.nyc/ansible/install-collection-from-console-redhat-com/" rel="alternate" type="text/html" title="Install Ansible Collection Directly from console.redhat.com" /><published>2024-02-15T00:00:00+00:00</published><updated>2024-02-15T00:00:00+00:00</updated><id>http://www.automate.nyc/ansible/install-collection-from-console-redhat-com</id><content type="html" xml:base="http://www.automate.nyc/ansible/install-collection-from-console-redhat-com/"><![CDATA[<p>We generated the offline token from <a href="https://console.redhat.com/ansible/automation-hub/token">Red Hat Hybrid Cloud Console</a>, and setup it up on Private Automation Hub to pull collections to Hub.  What if we want to use the same token to installation the collections directly onto our workstation from console.redhat.com, instead of pulling from Private Automation Hub?</p>

<div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[galaxy]</span>
<span class="py">server_list</span> <span class="p">=</span> <span class="s">rh-certified_repo</span>

<span class="nn">[galaxy_server.rh-certified_repo]</span>
<span class="py">url</span><span class="p">=</span><span class="s">https://console.redhat.com/api/automation-hub/content/published/</span>
<span class="py">auth_url</span><span class="p">=</span><span class="s">https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token</span>
<span class="py">token</span><span class="p">=</span><span class="s">eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhZDUyMjdhMy1iY2ZkLTRjZjAtYTdiNi....</span>
</code></pre></div></div>

<p>Note the <code class="language-plaintext highlighter-rouge">auth_url</code> attribute is needed if we want to authenticate with token.  It is not required if we just pointing it to Private Automation Hub.</p>]]></content><author><name>Eric Chong</name></author><category term="Ansible" /><category term="ansible" /><category term="aap" /><category term="pah" /><category term="hub" /><category term="collection" /><summary type="html"><![CDATA[Ansible Galaxy - Installing collections directly from console.redhat.com]]></summary></entry><entry><title type="html">Automation Hub Private Repository</title><link href="http://www.automate.nyc/ansible/automation-hub-private-repo/" rel="alternate" type="text/html" title="Automation Hub Private Repository" /><published>2023-10-27T00:00:00+00:00</published><updated>2023-09-29T00:00:00+00:00</updated><id>http://www.automate.nyc/ansible/automation-hub-private-repo</id><content type="html" xml:base="http://www.automate.nyc/ansible/automation-hub-private-repo/"><![CDATA[<h2 id="background">Background</h2>
<p>We want to allow users to create they own collection under company namespace, but not sharing with the rest of the Hub users</p>

<h2 id="procedures">Procedures</h2>
<ol>
  <li>Create a Automation Hub group, but not adding any role to it.</li>
  <li>Assign the user to the group.  For example, <code class="language-plaintext highlighter-rouge">hub_user2</code> is in <code class="language-plaintext highlighter-rouge">hub_group2</code>
<img src="/assets/images/2023/2023-10-27-hub-user-group.png" alt="User and group" /></li>
  <li>Create a private Automation Hub repository.  Make sure <code class="language-plaintext highlighter-rouge">Create Distribution</code> check box is selected.  Set <code class="language-plaintext highlighter-rouge">Pipeline</code> to <code class="language-plaintext highlighter-rouge">None</code>, otherwise the approval process will publish to the public <code class="language-plaintext highlighter-rouge">published</code> repo. <img src="/assets/images/2023/2023-10-27-private-repository.png" alt="Private repo" /></li>
  <li>Go to <code class="language-plaintext highlighter-rouge">Access</code> tab of the created repository, select the group created above <img src="/assets/images/2023/2023-10-27-private-repository-access-group.png" alt="Access group" /></li>
  <li>Select <code class="language-plaintext highlighter-rouge">galaxy.ansible_repository_owner</code> role on the next step, and then click <code class="language-plaintext highlighter-rouge">Add</code> to complete <img src="/assets/images/2023/2023-10-27-private-repository-access-role.png" alt="Access role" /></li>
  <li>
    <p>We can add exisiting collection under the <code class="language-plaintext highlighter-rouge">Collection versions</code> tab, but we will push a new collection via command line.  Copy the info from the pop-up window by clicking <code class="language-plaintext highlighter-rouge">Copy CLI configuration</code> button on top right.  Update the <code class="language-plaintext highlighter-rouge">ansible.cfg</code> file with this new repo info.</p>

    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> [galaxy]
 server_list = developer_repo
    
 [galaxy_server.developer_repo]
 url=https://aap-hub1.lab.automate.nyc/api/galaxy/content/developer_repo/
 token=my_token
</code></pre></div>    </div>
  </li>
  <li>Create the namesapce <code class="language-plaintext highlighter-rouge">automate_nyc</code> for our collection.</li>
  <li>Under the <code class="language-plaintext highlighter-rouge">Access</code> tab of the created namespace, select the created group from above <img src="/assets/images/2023/2023-10-27-private-repository-namespace-group.png" alt="Namespace group" /></li>
  <li>Select both <code class="language-plaintext highlighter-rouge">galaxy.collection_namespace_owner</code> and <code class="language-plaintext highlighter-rouge">galaxy.collection_publisher</code> to give the group full access to the repository content <img src="/assets/images/2023/2023-10-27-private-repository-namespace-role.png" alt="Namespace role" /></li>
  <li>With the updated <code class="language-plaintext highlighter-rouge">ansible.cfg</code> pointing to <code class="language-plaintext highlighter-rouge">developer_repo</code>, push the collection using <code class="language-plaintext highlighter-rouge">ansible-galaxy</code>
    <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ansible-galaxy collection publish automate_nyc-test-1.0.5.tar.gz
</code></pre></div>    </div>
  </li>
  <li>Verify the collection under the repository <img src="/assets/images/2023/2023-10-27-private-repository-collection.png" alt="Collection" /></li>
  <li>But we won’t be able to see it under <code class="language-plaintext highlighter-rouge">automate_nyc</code> namespace because the <code class="language-plaintext highlighter-rouge">Hide from search</code> option of the repository <img src="/assets/images/2023/2023-10-27-private-repository-collection-namepace.png" alt="Namespace" /></li>
  <li>Other Hub users won’t be able to see the repository or collection neither.</li>
  <li>To use the collection in AAP, we will need to add a <code class="language-plaintext highlighter-rouge">Ansible Galaxy/Automation Hub API Token</code> specificly for this repository, similar to what we added to <code class="language-plaintext highlighter-rouge">ansible.cfg</code>, and assign to the organization</li>
</ol>]]></content><author><name>Eric Chong</name></author><category term="Ansible" /><category term="ansible" /><category term="aap" /><category term="pah" /><category term="hub" /><summary type="html"><![CDATA[Automation Hub - How to configure a private repository]]></summary></entry><entry><title type="html">Importing a single host from Satellite to AAP inventory</title><link href="http://www.automate.nyc/ansible/import-single-host-from-satellite/" rel="alternate" type="text/html" title="Importing a single host from Satellite to AAP inventory" /><published>2023-09-29T00:00:00+00:00</published><updated>2023-09-29T00:00:00+00:00</updated><id>http://www.automate.nyc/ansible/import-single-host-from-satellite</id><content type="html" xml:base="http://www.automate.nyc/ansible/import-single-host-from-satellite/"><![CDATA[<p>In the new virtual machine provisioning process, vRO creates the machine and registered it to the Satellite host group selected by user.  Now AAP will take over to configure the VM.  Before the playbooks can run against this new VM, we will need to import it from Satellite into AAP inventory.  The regular Satellite inventory sync takes a long time to run because it queries all hosts managed by Satellite.  It is not feasible to run Satellite inventory sync to just import one host.  We can use <code class="language-plaintext highlighter-rouge">host_filters</code> attribute, but the AAP inventory source does not accept variable.  So the solution is to run <code class="language-plaintext highlighter-rouge">ansible-inventory</code> directly with <code class="language-plaintext highlighter-rouge">host_filters</code> for the target VM.  Captures the output which includes all Satellite parameters associated with the VM and import them into AAP using the <code class="language-plaintext highlighter-rouge">infra.controller_configuration.hosts</code> role to create the host in AAP inventory</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span>
<span class="c1"># Required Collection</span>
<span class="c1">#   infra.controller_configuration</span>
<span class="c1"># Rquired Variables</span>
<span class="c1">#   controller_*: credential for AAP</span>
<span class="c1">#   satellite_*: credential for Satellite</span>
<span class="c1">#   target_host: host to be imported</span>
<span class="c1">#   controller_inventory: AAP inventory name</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Import single host from Satellite</span> 
  <span class="na">hosts</span><span class="pi">:</span> <span class="s">localhost</span>
  <span class="na">connection</span><span class="pi">:</span> <span class="s">local</span>
  <span class="na">gather_facts</span><span class="pi">:</span> <span class="no">false</span>

  <span class="na">vars</span><span class="pi">:</span>
    <span class="na">controller_hostname</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
    <span class="na">controller_username</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
    <span class="na">controller_password</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
    <span class="na">controller_oauth_token</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
    <span class="na">controller_validate_certs</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
    <span class="na">satellite_url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
    <span class="na">satellite_user</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
    <span class="na">satellite_password</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
    <span class="na">working_dir</span><span class="pi">:</span> <span class="s">/tmp</span>

  <span class="na">tasks</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Import single host</span>
      <span class="na">block</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Stage Foreman inventory plugin file</span>
          <span class="na">ansible.builtin.copy</span><span class="pi">:</span>
            <span class="na">dest</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/my.foreman.yml"</span>
            <span class="na">mode</span><span class="pi">:</span> <span class="s2">"</span><span class="s">0600"</span>
            <span class="na">content</span><span class="pi">:</span> <span class="pi">|</span>
              <span class="s">plugin: redhat.satellite.foreman</span>
              <span class="s">url: ""</span>
              <span class="s">user: ""</span>
              <span class="s">password: ""</span>
              <span class="s">validate_certs: no</span>
              <span class="s">want_host_group: yes</span>
              <span class="s">want_params: yes</span>
              <span class="s">want_host_collections: yes</span>
              <span class="s">want_facts: yes</span>
              <span class="s">use_reports_api: yes</span>
              <span class="s">host_filters: 'name='</span>

        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Run Foreman inventory plugin</span>
          <span class="na">ansible.builtin.shell</span><span class="pi">:</span>
            <span class="na">cmd</span><span class="pi">:</span> <span class="s2">"</span><span class="s">ansible-inventory</span><span class="nv"> </span><span class="s">-i</span><span class="nv"> </span><span class="s">my.foreman.yml</span><span class="nv"> </span><span class="s">--host</span><span class="nv"> </span><span class="s">"</span>
            <span class="na">chdir</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
          <span class="na">register</span><span class="pi">:</span> <span class="s">_output</span>

        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">DEBUG</span>
          <span class="na">ansible.builtin.debug</span><span class="pi">:</span>
            <span class="na">msg</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
            <span class="na">verbosity</span><span class="pi">:</span> <span class="m">1</span>

        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set host parameter variables</span>
          <span class="na">ansible.builtin.set_fact</span><span class="pi">:</span>
            <span class="na">import_host_vars</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>

        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">DEBUG</span>
          <span class="na">ansible.builtin.debug</span><span class="pi">:</span>
            <span class="na">msg</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
            <span class="na">verbosity</span><span class="pi">:</span> <span class="m">1</span>

        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Add host to AAP inventory</span>
          <span class="na">ansible.builtin.include_role</span><span class="pi">:</span>
            <span class="na">name</span><span class="pi">:</span> <span class="s">infra.controller_configuration.hosts</span>
          <span class="na">vars</span><span class="pi">:</span>
            <span class="na">controller_hosts</span><span class="pi">:</span>
              <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
                <span class="na">inventory</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
                <span class="na">variables</span><span class="pi">:</span> <span class="s2">"</span><span class="s">"</span>
          <span class="na">register</span><span class="pi">:</span> <span class="s">_import_host_output</span>

      <span class="na">always</span><span class="pi">:</span>
        <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Remove Foreman inventory plugin file</span>
          <span class="na">ansible.builtin.file</span><span class="pi">:</span>
            <span class="na">path</span><span class="pi">:</span> <span class="s2">"</span><span class="s">/my.foreman.yml"</span>
            <span class="na">state</span><span class="pi">:</span> <span class="s">absent</span>
</code></pre></div></div>]]></content><author><name>Eric Chong</name></author><category term="Ansible" /><category term="ansible" /><category term="aap" /><category term="tower" /><category term="satellite" /><summary type="html"><![CDATA[Ansible Automation Platform - Importing a single host from Satellite to AAP inventory]]></summary></entry></feed>