zzz.buzz Code dream, dream coding. A personal blog keeping notes and thoughts. https://zzz.buzz/ Tue, 28 Dec 2021 14:12:27 +0800 Tue, 28 Dec 2021 14:12:27 +0800 Jekyll v3.9.1 Ansible Truth Table <p>Everything in an Ansible playbook is first <em>YAML</em>, then it's <em>Ansible</em>.</p> <h2 id="rules">Rules</h2> <p>Values specified in YAML go through the following stages:</p> <ol> <li> <p><strong>Parse as YAML as specified by YAML syntax;</strong></p> <ul> <li><code class="language-plaintext highlighter-rouge">true</code>, <code class="language-plaintext highlighter-rouge">True</code>, <code class="language-plaintext highlighter-rouge">TRUE</code>, <code class="language-plaintext highlighter-rouge">false</code>, <code class="language-plaintext highlighter-rouge">False</code>, <code class="language-plaintext highlighter-rouge">FALSE</code> -&gt; boolean</li> <li><code class="language-plaintext highlighter-rouge">tRUE</code>, <code class="language-plaintext highlighter-rouge">TrUe</code>, <code class="language-plaintext highlighter-rouge">fALSE</code>, <code class="language-plaintext highlighter-rouge">FaLsE</code>, … -&gt; string</li> <li> <p><code class="language-plaintext highlighter-rouge">"true"</code>, <code class="language-plaintext highlighter-rouge">"True"</code>, <code class="language-plaintext highlighter-rouge">"TRUE"</code>, <code class="language-plaintext highlighter-rouge">"false"</code>, <code class="language-plaintext highlighter-rouge">"False"</code>, <code class="language-plaintext highlighter-rouge">"FALSE"</code>, … -&gt; string</p> </li> <li><code class="language-plaintext highlighter-rouge">yes</code>, <code class="language-plaintext highlighter-rouge">Yes</code>, <code class="language-plaintext highlighter-rouge">YES</code>, <code class="language-plaintext highlighter-rouge">no</code>, <code class="language-plaintext highlighter-rouge">No</code>, <code class="language-plaintext highlighter-rouge">NO</code> -&gt; boolean</li> <li><code class="language-plaintext highlighter-rouge">yES</code>, <code class="language-plaintext highlighter-rouge">YeS</code>, <code class="language-plaintext highlighter-rouge">nO</code>, … -&gt; string</li> <li> <p><code class="language-plaintext highlighter-rouge">"yes"</code>, <code class="language-plaintext highlighter-rouge">"Yes"</code>, <code class="language-plaintext highlighter-rouge">"YES"</code>, <code class="language-plaintext highlighter-rouge">"no"</code>, <code class="language-plaintext highlighter-rouge">"No"</code>, <code class="language-plaintext highlighter-rouge">"NO"</code>, … -&gt; string</p> </li> <li><code class="language-plaintext highlighter-rouge">on</code>, <code class="language-plaintext highlighter-rouge">On</code>, <code class="language-plaintext highlighter-rouge">ON</code>, <code class="language-plaintext highlighter-rouge">off</code>, <code class="language-plaintext highlighter-rouge">Off</code>, <code class="language-plaintext highlighter-rouge">OFF</code> -&gt; boolean</li> <li><code class="language-plaintext highlighter-rouge">oN</code>, <code class="language-plaintext highlighter-rouge">oFF</code>, <code class="language-plaintext highlighter-rouge">oFf</code>, … -&gt; string</li> <li> <p><code class="language-plaintext highlighter-rouge">"on"</code>, <code class="language-plaintext highlighter-rouge">"On"</code>, <code class="language-plaintext highlighter-rouge">"ON"</code>, <code class="language-plaintext highlighter-rouge">"off"</code>, <code class="language-plaintext highlighter-rouge">"Off"</code>, <code class="language-plaintext highlighter-rouge">"OFF"</code>, … -&gt; string</p> </li> <li><code class="language-plaintext highlighter-rouge">y</code>, <code class="language-plaintext highlighter-rouge">Y</code>, <code class="language-plaintext highlighter-rouge">n</code>, <code class="language-plaintext highlighter-rouge">N</code> -&gt; string</li> <li> <p><code class="language-plaintext highlighter-rouge">"y"</code>, <code class="language-plaintext highlighter-rouge">"Y"</code>, <code class="language-plaintext highlighter-rouge">"n"</code>, <code class="language-plaintext highlighter-rouge">"N"</code> -&gt; string</p> </li> <li><code class="language-plaintext highlighter-rouge">0</code>, <code class="language-plaintext highlighter-rouge">1</code> -&gt; number</li> <li><code class="language-plaintext highlighter-rouge">"0"</code>, <code class="language-plaintext highlighter-rouge">"1"</code> -&gt; string</li> </ul> </li> <li> <p><strong>Parse as Ansible syntax.</strong></p> <p>This step converts the following string (<strong>case insensitively</strong>) to boolean:</p> <ul> <li><code class="language-plaintext highlighter-rouge">"true"</code></li> <li><code class="language-plaintext highlighter-rouge">"false"</code></li> <li><code class="language-plaintext highlighter-rouge">"yes"</code></li> <li><code class="language-plaintext highlighter-rouge">"no"</code></li> </ul> </li> <li> <ol> <li> <p><strong>If variable goes through <em>bool</em> filter, it additionaly converts the following string (<em>case-insensitively</em>) and numbers to boolean:</strong></p> <ul> <li><code class="language-plaintext highlighter-rouge">"on"</code> -&gt; boolean True</li> <li> <p><code class="language-plaintext highlighter-rouge">"off"</code> -&gt; boolean False</p> </li> <li><code class="language-plaintext highlighter-rouge">"1"</code> -&gt; boolean True</li> <li><code class="language-plaintext highlighter-rouge">"0"</code> -&gt; boolean False</li> <li> <p>Any other string -&gt; boolean False</p> </li> <li><code class="language-plaintext highlighter-rouge">1</code> -&gt; boolean True</li> <li><code class="language-plaintext highlighter-rouge">0</code> -&gt; boolean False</li> <li>Any other number -&gt; boolean False</li> </ul> </li> <li> <p><strong>If variable is prefixed with <code class="language-plaintext highlighter-rouge">not</code> operator:</strong></p> <ul> <li> <p>all non empty string is treated as <code class="language-plaintext highlighter-rouge">True</code>, with <code class="language-plaintext highlighter-rouge">not</code> operator, the result becomes <code class="language-plaintext highlighter-rouge">False</code>;</p> </li> <li> <p>0 treated as <code class="language-plaintext highlighter-rouge">False</code>, 1 and any other number as <code class="language-plaintext highlighter-rouge">True</code>; with <code class="language-plaintext highlighter-rouge">not</code> operator, they become <code class="language-plaintext highlighter-rouge">True</code> and <code class="language-plaintext highlighter-rouge">False</code> respectively.</p> </li> </ul> </li> </ol> </li> </ol> <h2 id="truth-table">Truth Table</h2> <p>The following is a truth table for the rules above:</p> <table style="font-family: monospace;"> <tr> <td><code>var</code></td> <td><code>{{ var }}</code></td> <td><code>{{ var|bool }}</code></td> <td><code>{{ not var }}</code></td> </tr> <tr> <td>1</td> <td>1</td> <td>true</td> <td>false</td> </tr> <tr> <td>"1"</td> <td>"1"</td> <td>true</td> <td>false</td> </tr> <tr> <td>true, True, TRUE</td> <td>true</td> <td>true</td> <td>false</td> </tr> <tr> <td>"true", "True", "TRUE", ...</td> <td>true</td> <td>true</td> <td>false</td> </tr> <tr> <td>yes, Yes, YES</td> <td>true</td> <td>true</td> <td>false</td> </tr> <tr> <td>"yes", "Yes", "YES", ...</td> <td>true</td> <td>true</td> <td>false</td> </tr> <tr> <td>on, On, ON</td> <td>true</td> <td>true</td> <td>false</td> </tr> <tr> <td>"on", "On", "ON", ...</td> <td>"on", "On", "ON", ...</td> <td>true</td> <td>false</td> </tr> <tr> <td>y, Y</td> <td>"y", "Y"</td> <td>false</td> <td>false</td> </tr> <tr> <td>"y", "Y"</td> <td>"y", "Y"</td> <td>false</td> <td>false</td> </tr> <tr> <td>"True\n"</td> <td>"True\n"</td> <td>false</td> <td>false</td> </tr> <tr> <td><code>var</code></td> <td><code>{{ var }}</code></td> <td><code>{{ var|bool }}</code></td> <td><code>{{ not var }}</code></td> </tr> <tr> <td>0</td> <td>0</td> <td>false</td> <td>true</td> </tr> <tr> <td>"0"</td> <td>"0"</td> <td>false</td> <td>false</td> </tr> <tr> <td>false, False, FALSE</td> <td>false</td> <td>false</td> <td>true</td> </tr> <tr> <td>"false", "False", "FALSE", ...</td> <td>false</td> <td>false</td> <td>true</td> </tr> <tr> <td>no, No, NO</td> <td>false</td> <td>false</td> <td>true</td> </tr> <tr> <td>"no", "No", "NO", ...</td> <td>false</td> <td>false</td> <td>true</td> </tr> <tr> <td>off, Off, OFF</td> <td>false</td> <td>false</td> <td>true</td> </tr> <tr> <td>"off", "Off", "OFF", ...</td> <td>"off", "Off", "OFF", ...</td> <td>false</td> <td>false</td> </tr> <tr> <td>n, N</td> <td>"n", "N"</td> <td>false</td> <td>false</td> </tr> <tr> <td>"n", "N"</td> <td>"n", "N"</td> <td>false</td> <td>false</td> </tr> <tr> <td>"False\n"</td> <td>"False\n"</td> <td>false</td> <td>false</td> </tr> <tr> <td><code>var</code></td> <td><code>{{ var }}</code></td> <td><code>{{ var|bool }}</code></td> <td><code>{{ not var }}</code></td> </tr> </table> <h2 id="test-playbook">Test Playbook</h2> <p>Test it yourself with the following ansible playbook:</p> <div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">hosts</span><span class="pi">:</span> <span class="s">localhost</span> <span class="na">gather_facts</span><span class="pi">:</span> <span class="s">no</span> <span class="na">tasks</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">set_fact</span><span class="pi">:</span> <span class="na">t0</span><span class="pi">:</span> <span class="m">1</span> <span class="na">t1</span><span class="pi">:</span> <span class="s2">"</span><span class="s">1"</span> <span class="na">t2</span><span class="pi">:</span> <span class="no">true</span> <span class="na">t3</span><span class="pi">:</span> <span class="s2">"</span><span class="s">true"</span> <span class="na">t4</span><span class="pi">:</span> <span class="s">yes</span> <span class="na">t5</span><span class="pi">:</span> <span class="s2">"</span><span class="s">yes"</span> <span class="na">t6</span><span class="pi">:</span> <span class="s">on</span> <span class="na">t7</span><span class="pi">:</span> <span class="s2">"</span><span class="s">on"</span> <span class="na">t8</span><span class="pi">:</span> <span class="s">y</span> <span class="na">t9</span><span class="pi">:</span> <span class="s2">"</span><span class="s">y"</span> <span class="na">f0</span><span class="pi">:</span> <span class="m">0</span> <span class="na">f1</span><span class="pi">:</span> <span class="s2">"</span><span class="s">0"</span> <span class="na">f2</span><span class="pi">:</span> <span class="no">false</span> <span class="na">f3</span><span class="pi">:</span> <span class="s2">"</span><span class="s">false"</span> <span class="na">f4</span><span class="pi">:</span> <span class="s">no</span> <span class="na">f5</span><span class="pi">:</span> <span class="s2">"</span><span class="s">no"</span> <span class="na">f6</span><span class="pi">:</span> <span class="s">off</span> <span class="na">f7</span><span class="pi">:</span> <span class="s2">"</span><span class="s">off"</span> <span class="na">f8</span><span class="pi">:</span> <span class="s">n</span> <span class="na">f9</span><span class="pi">:</span> <span class="s2">"</span><span class="s">n"</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">var"</span> <span class="na">debug</span><span class="pi">:</span> <span class="s">var=item</span> <span class="na">loop</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">[t0,</span><span class="nv"> </span><span class="s">t1,</span><span class="nv"> </span><span class="s">t2,</span><span class="nv"> </span><span class="s">t3,</span><span class="nv"> </span><span class="s">t4,</span><span class="nv"> </span><span class="s">t5,</span><span class="nv"> </span><span class="s">t6,</span><span class="nv"> </span><span class="s">t7,</span><span class="nv"> </span><span class="s">t8,</span><span class="nv"> </span><span class="s">t9,</span><span class="nv"> </span><span class="s">f0,</span><span class="nv"> </span><span class="s">f1,</span><span class="nv"> </span><span class="s">f2,</span><span class="nv"> </span><span class="s">f3,</span><span class="nv"> </span><span class="s">f4,</span><span class="nv"> </span><span class="s">f5,</span><span class="nv"> </span><span class="s">f6,</span><span class="nv"> </span><span class="s">f7,</span><span class="nv"> </span><span class="s">f8,</span><span class="nv"> </span><span class="s">f9]</span><span class="nv"> </span><span class="s">}}"</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">var|bool</span><span class="nv"> </span><span class="s">}}"</span> <span class="na">debug</span><span class="pi">:</span> <span class="s">msg={{ item|bool }}</span> <span class="na">loop</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">[t0,</span><span class="nv"> </span><span class="s">t1,</span><span class="nv"> </span><span class="s">t2,</span><span class="nv"> </span><span class="s">t3,</span><span class="nv"> </span><span class="s">t4,</span><span class="nv"> </span><span class="s">t5,</span><span class="nv"> </span><span class="s">t6,</span><span class="nv"> </span><span class="s">t7,</span><span class="nv"> </span><span class="s">t8,</span><span class="nv"> </span><span class="s">t9,</span><span class="nv"> </span><span class="s">f0,</span><span class="nv"> </span><span class="s">f1,</span><span class="nv"> </span><span class="s">f2,</span><span class="nv"> </span><span class="s">f3,</span><span class="nv"> </span><span class="s">f4,</span><span class="nv"> </span><span class="s">f5,</span><span class="nv"> </span><span class="s">f6,</span><span class="nv"> </span><span class="s">f7,</span><span class="nv"> </span><span class="s">f8,</span><span class="nv"> </span><span class="s">f9]</span><span class="nv"> </span><span class="s">}}"</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">not</span><span class="nv"> </span><span class="s">var</span><span class="nv"> </span><span class="s">}}"</span> <span class="na">debug</span><span class="pi">:</span> <span class="s">msg={{ not item }}</span> <span class="na">loop</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">[t0,</span><span class="nv"> </span><span class="s">t1,</span><span class="nv"> </span><span class="s">t2,</span><span class="nv"> </span><span class="s">t3,</span><span class="nv"> </span><span class="s">t4,</span><span class="nv"> </span><span class="s">t5,</span><span class="nv"> </span><span class="s">t6,</span><span class="nv"> </span><span class="s">t7,</span><span class="nv"> </span><span class="s">t8,</span><span class="nv"> </span><span class="s">t9,</span><span class="nv"> </span><span class="s">f0,</span><span class="nv"> </span><span class="s">f1,</span><span class="nv"> </span><span class="s">f2,</span><span class="nv"> </span><span class="s">f3,</span><span class="nv"> </span><span class="s">f4,</span><span class="nv"> </span><span class="s">f5,</span><span class="nv"> </span><span class="s">f6,</span><span class="nv"> </span><span class="s">f7,</span><span class="nv"> </span><span class="s">f8,</span><span class="nv"> </span><span class="s">f9]</span><span class="nv"> </span><span class="s">}}"</span> </code></pre></div></div> Sun, 31 May 2020 14:47:46 +0800 https://zzz.buzz/notes/ansible-truth-table/ https://zzz.buzz/notes/ansible-truth-table/ Ansible notes Convert between JSON and JSON Lines Using jq <p>With <a href="https://stedolan.github.io/jq/"><code class="language-plaintext highlighter-rouge">jq</code></a>, we can easily convert between JSON and JSON lines.</p> <h3 id="json---json-lines">JSON -&gt; JSON Lines</h3> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">printf</span> <span class="s1">'[{"A":"B"},{"C":"D"}]'</span> | jq <span class="nt">-c</span> .[] <span class="go">{"A":"B"} {"C":"D"} </span></code></pre></div></div> <p>Note: <code class="language-plaintext highlighter-rouge">-c</code> (<code class="language-plaintext highlighter-rouge">--compact-output</code>) option is important to put each JSON object on a single line.</p> <h3 id="json-lines---json">JSON Lines -&gt; JSON</h3> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">printf</span> <span class="s1">'{"A":"B"}\n{"C":"D"}'</span> | jq <span class="nt">-s</span> <span class="go">[ { "A": "B" }, { "C": "D" } ] </span></code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">-s</code> (<code class="language-plaintext highlighter-rouge">--slurp</code>) option wraps the whole input into a large array.</p> <p>Add <code class="language-plaintext highlighter-rouge">-c</code> (<code class="language-plaintext highlighter-rouge">--compact-output</code>) option to make the whole array on a single line.</p> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">printf</span> <span class="s1">'{"A":"B"}\n{"C":"D"}'</span> | jq <span class="nt">-cs</span> <span class="go">[{"A":"B"},{"C":"D"}] </span></code></pre></div></div> <h3 id="deal-with-json-lines-mixed-with-plain-text">Deal with JSON lines mixed with plain text</h3> <p>If you're dealing with programs which output JSON lines along with plain text, you can extract only the JSON lines with:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat </span>mixed.jsonl | jq <span class="nt">-Rc</span> <span class="s1">'fromjson?'</span> </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">-R</code> (<code class="language-plaintext highlighter-rouge">--raw-input</code>) parses each line of text as a string;<br /> <a href="https://stedolan.github.io/jq/manual/#Convertto/fromJSON"><code class="language-plaintext highlighter-rouge">fromjson</code></a> converts the string back into JSON object;<br /> <a href="https://stedolan.github.io/jq/manual/#ErrorSuppression/OptionalOperator:?"><code class="language-plaintext highlighter-rouge">?</code></a> tries to do the conversion and ignores those don't convert;<br /> <code class="language-plaintext highlighter-rouge">-c</code> (<code class="language-plaintext highlighter-rouge">--compact-output</code>) puts each JSON object on a single line.</p> <h4 id="example">Example</h4> <p>Input:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>calling cmd Listening for transport dt_socket at address: 8787 {"@timestamp":"2020-06-09T02:46:14.635Z","@version":"1","message":"\nMetrics for local node (to disable set 'metricsLogFrequency' to 0)\n ^-- Node [id=f8807a97, uptime=00:21:00.130]\n ^-- H/N/C [hosts=5, nodes=5, CPUs=34]\n ^-- CPU [cur=0.4%, avg=15.09%, GC=0%]\n ^-- PageMemory [pages=2256]\n ^-- Heap [used=3304MB, free=77.31%, comm=9370MB]\n ^-- Non heap [used=101MB, free=96.95%, comm=102MB]\n ^-- Public thread pool [active=0, idle=0, qSize=0]\n ^-- System thread pool [active=0, idle=6, qSize=0]\n ^-- Outbound messages queue [size=0]","thread_name":"grid-timeout-worker-#23","level":"INFO","level_value":20000} </code></pre></div></div> <p>Command:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat </span>input | jq <span class="nt">-Rrc</span> <span class="s1">'fromjson?|.message'</span> </code></pre></div></div> <p>Output:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Metrics for local node (to disable set 'metricsLogFrequency' to 0) ^-- Node [id=f8807a97, uptime=00:21:00.130] ^-- H/N/C [hosts=5, nodes=5, CPUs=34] ^-- CPU [cur=0.4%, avg=15.09%, GC=0%] ^-- PageMemory [pages=2256] ^-- Heap [used=3304MB, free=77.31%, comm=9370MB] ^-- Non heap [used=101MB, free=96.95%, comm=102MB] ^-- Public thread pool [active=0, idle=0, qSize=0] ^-- System thread pool [active=0, idle=6, qSize=0] ^-- Outbound messages queue [size=0] </code></pre></div></div> <p>Note that <code class="language-plaintext highlighter-rouge">-r</code> (<code class="language-plaintext highlighter-rouge">--raw-output</code>) parses escape sequences within the string.</p> Mon, 11 May 2020 08:48:53 +0800 https://zzz.buzz/2020/05/11/convert-between-json-and-json-lines-using-jq/ https://zzz.buzz/2020/05/11/convert-between-json-and-json-lines-using-jq/ Forward Multiple Remote SMB Servers on Windows <!-- BEGIN _includes/variables --> <!-- END _includes/variables --> <p>First of all, there are some limitations on Windows we need to be aware of:</p> <ul> <li>Port of target SMB server must be <strong>445</strong>;</li> <li>For SMB server, the only loopback address Windows connects to is <strong>127.0.0.1</strong>. Other loopback addresses 127.x.x.x won't work.</li> </ul> <p>With these limitations in mind, we have a solution of following steps:</p> <h2 id="disable-windows-lanmanserver-server-service">Disable Windows <em>LanmanServer (Server)</em> Service</h2> <p>Windows has a service named <strong>LanmanServer</strong> (Dispaly name: <strong>Server</strong>) running by default which binds to <code class="language-plaintext highlighter-rouge">0.0.0.0:445</code>. We have to disable it first so that we can bind our forwarded SMB server on port 445.</p> <pre><code class="language-cmd">sc.exe config LanmanServer start= disabled sc.exe stop LanmanServer </code></pre> <p>If the commands above failed, you will need to disable the following dependent services and then try again.</p> <ol> <li> <p>If <em>SMB 1.0/CIFS File Sharing Support</em> is enabled on your system, disable <strong>Browser</strong> service first and then try again.</p> <pre><code class="language-cmd">sc.exe config Browser start= disabled sc.exe stop Browser </code></pre> </li> <li> <p>If you are using Docker Desktop on Windows, you will need to stop the application, and stop <strong>Docker Desktop Service</strong> and then try again.</p> <pre><code class="language-cmd">sc.exe config com.docker.service start= demand sc.exe stop com.docker.service </code></pre> </li> </ol> <p>A restart is requried to release the port 445.</p> <h2 id="add-loopback-adapter">Add Loopback Adapter</h2> <p>To generate more loopback addresses, we can add loopback adapters:</p> <ul> <li>Run <code class="language-plaintext highlighter-rouge">hdwwiz.exe</code> (<em>Add Hardware Wizard</em>);</li> <li>Choose "Install the hardware that I manually select from a list (Advanced)";</li> <li>Choose "Network adapters" from the list;</li> <li>Select Manufacturer "Microsoft" and Model "Microsoft KM-TEST Loopback Adapter";</li> <li>Finish.</li> </ul> <p><img src="/content/2020/04/add-network-adapters.png" alt="Add Network Adapters" /> <img src="/content/2020/04/select-the-device-driver.png" alt="Select the device driver" /></p> <p>You can now find the newly created network adapter in <code class="language-plaintext highlighter-rouge">ncpa.cpl</code> (Network Connections of Control Panel).</p> <p><img src="/content/2020/04/network-connections.png" alt="Network Connections" /></p> <h2 id="configure-the-newly-added-loopback-adapter">Configure the newly added loopback adapter</h2> <ul> <li>Right click the adapter, choose <em>Properties</em>;</li> <li>Remove all the items except <em>Internet Protocol Version 4 (TCP/IPv4)</em> and the IPv6 one if you need it;</li> <li>Configure to use a IP of your choice with subnet mask <em>255.255.255.255</em>.</li> </ul> <p><img src="/content/2020/04/loopback-adapter-properties.png" alt="Loopback Adapter - Properties - IPv4 Properties" /></p> <h2 id="forward-remote-smb-servers">Forward remote SMB servers</h2> <p>Now you can forward multiple remote SMB servers to your local machine. One for each adapter you added as above using the configured IP, and one more for <code class="language-plaintext highlighter-rouge">127.0.0.1</code>.</p> <p>You may use <code class="language-plaintext highlighter-rouge">ssh -L</code> command, <a href="https://www.bitvise.com/ssh-client-download">Bitvise SSH Client</a>, <a href="https://www.putty.org/">putty</a>, or any application of your choice to the actual forward.</p> <p><img src="/content/2020/04/multiple-forwarded-smb-servers.png" alt="Multiple Forwarded SMB Servers" /></p> <p>Check your listening ports with <code class="language-plaintext highlighter-rouge">resmon.exe</code> (Resource Monitor):</p> <p><img src="/content/2020/04/resmon-445.png" alt="Resource Monitor - Port 445" /></p> <h2 id="references">References</h2> <ul> <li><a href="https://support.microsoft.com/en-gb/help/2777200/installing-the-microsoft-loopback-adapter-in-windows-8-and-windows-ser">Installing the Microsoft Loopback Adapter in Windows 8 and Windows Server 2012</a></li> <li><a href="https://superuser.com/questions/1094931/ssh-tunnel-on-windows-10-to-linux-samba">SSH tunnel on Windows 10 to Linux Samba - Super User</a></li> <li><a href="https://social.technet.microsoft.com/Forums/azure/en-US/d30d3c98-58c5-47f6-b5a5-f5620882020d/port-forwarding-445-for-smb-and-ssh-problem?forum=itprovistanetworking#b93f3fbb-16f7-4ef9-b1ed-28575b3fe215">Port forwarding 445 for SMB and SSH problem</a></li> </ul> Sun, 26 Apr 2020 16:32:19 +0800 https://zzz.buzz/2020/04/26/forward-multiple-remote-smb-servers-on-windows/ https://zzz.buzz/2020/04/26/forward-multiple-remote-smb-servers-on-windows/ Inconsistent Behaviors among cp, rsync, and Others <p>Inconsistent behaviors for coping directory among <code class="language-plaintext highlighter-rouge">cp</code>, <code class="language-plaintext highlighter-rouge">rsync</code>, <code class="language-plaintext highlighter-rouge">aws s3 cp</code>, <code class="language-plaintext highlighter-rouge">aws s3 sync</code>, <code class="language-plaintext highlighter-rouge">az storage copy</code> and <code class="language-plaintext highlighter-rouge">gsutil cp</code> are sometimes confusing. Here is a list of their behaviors and examples for you to better understand them.</p> <p>Assume we have the following directory structure in current directory and cloud storage before running following commands:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>. ├── dir1 │   └── file1 ├── dir2 │   └── file2 └── dir3 └── file3 </code></pre></div></div> <h2 id="cp">cp</h2> <ul> <li>When destination directory does NOT exist, <ul> <li>the destination directory is created, and the content of source directory is copied.</li> </ul> </li> <li>When destination directory exists, <ul> <li>by default, both the directory itself and its content are copied to the destination directory;</li> <li>unless the source directory is <code class="language-plaintext highlighter-rouge">.</code> , or is suffixed with <code class="language-plaintext highlighter-rouge">/.</code> , by then, only the content of source directory is copied.</li> </ul> </li> </ul> <p>Note: Suffix a directory with <code class="language-plaintext highlighter-rouge">/</code> is the same as not suffixing it.</p> <p>Note: The behavior of <code class="language-plaintext highlighter-rouge">cp</code> is consistent with <code class="language-plaintext highlighter-rouge">mv</code>.</p> <h3 id="cp-examples">cp Examples</h3> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Destination not exists</span> <span class="gp">$</span><span class="w"> </span><span class="nb">cp</span> <span class="nt">-r</span> <span class="nt">-v</span> dir1 dir4 <span class="gp">'dir1' -&gt;</span><span class="w"> </span><span class="s1">'dir4'</span> <span class="gp">'dir1/file1' -&gt;</span><span class="w"> </span><span class="s1">'dir4/file1'</span> </code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Source dir suffixed with /.</span> <span class="gp">$</span><span class="w"> </span><span class="c"># Destination dir not exists</span> <span class="gp">$</span><span class="w"> </span><span class="nb">cp</span> <span class="nt">-r</span> <span class="nt">-v</span> dir1/. dir5 <span class="gp">'dir1/.' -&gt;</span><span class="w"> </span><span class="s1">'dir5'</span> <span class="gp">'dir1/./file1' -&gt;</span><span class="w"> </span><span class="s1">'dir5/file1'</span> </code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Destination dir exists</span> <span class="gp">$</span><span class="w"> </span><span class="nb">cp</span> <span class="nt">-r</span> <span class="nt">-v</span> dir1 dir2 <span class="gp">'dir1' -&gt;</span><span class="w"> </span><span class="s1">'dir2/dir1'</span> <span class="gp">'dir1/file1' -&gt;</span><span class="w"> </span><span class="s1">'dir2/dir1/file1'</span> </code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Source dir suffixed with /.</span> <span class="gp">$</span><span class="w"> </span><span class="c"># Destination dir exists</span> <span class="gp">$</span><span class="w"> </span><span class="nb">cp</span> <span class="nt">-r</span> <span class="nt">-v</span> dir1/. dir3 <span class="gp">'dir1/./file1' -&gt;</span><span class="w"> </span><span class="s1">'dir3/./file1'</span> </code></pre></div></div> <h2 id="rsync">rsync</h2> <ol> <li>If destination directory does NOT exist, it's created;</li> <li> <ul> <li>by default, both the directory itself and its content are copied to the destination directory;</li> <li>unless the source directory is <code class="language-plaintext highlighter-rouge">.</code> , or is suffixed with <code class="language-plaintext highlighter-rouge">/</code> or <code class="language-plaintext highlighter-rouge">/.</code> , by then, only the content of source directory is copied.</li> </ul> </li> </ol> <p>Note: Suffix a directory with <code class="language-plaintext highlighter-rouge">/</code> is the same as suffixing it with <code class="language-plaintext highlighter-rouge">/.</code> .</p> <h3 id="rsync-examples">rsync Examples</h3> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Destination not exists</span> <span class="gp">$</span><span class="w"> </span>rsync <span class="nt">-r</span> dir1 dir4 <span class="gp">$</span><span class="w"> </span>tree dir4 <span class="go">dir4 └── dir1 └── file1 1 directory, 1 file </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Source dir suffixed with /.</span> <span class="gp">$</span><span class="w"> </span><span class="c"># Destination not exists</span> <span class="gp">$</span><span class="w"> </span>rsync <span class="nt">-r</span> dir1/. dir5 <span class="gp">$</span><span class="w"> </span>tree dir5 <span class="go">dir5 └── file1 0 directories, 1 file </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Destination dir exists</span> <span class="gp">$</span><span class="w"> </span>rsync <span class="nt">-r</span> dir1 dir2 <span class="gp">$</span><span class="w"> </span>tree dir2 <span class="go">dir2 ├── dir1 │   └── file1 └── file2 </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Source dir suffixed with /.</span> <span class="gp">$</span><span class="w"> </span><span class="c"># Destination dir exists</span> <span class="gp">$</span><span class="w"> </span>rsync <span class="nt">-r</span> dir1/. dir3 <span class="gp">$</span><span class="w"> </span>tree dir3 <span class="go">dir3 └── file1 0 directories, 1 file </span></code></pre></div></div> <h2 id="aws-s3-cp--aws-s3-sync">aws s3 cp / aws s3 sync</h2> <p>It's always the content of source directory are copied to the destination directory.</p> <p>Note: Suffix a directory with <code class="language-plaintext highlighter-rouge">/</code> is the same as not suffixing it or suffixing it with <code class="language-plaintext highlighter-rouge">/.</code> .</p> <h3 id="aws-examples">aws Examples</h3> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">cp</span> <span class="nt">--recursive</span> dir1 s3://zzz.buzz/dir2 <span class="go">upload: dir1/file1 to s3://zzz.buzz/dir2/file1 </span><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">cp</span> <span class="nt">--recursive</span> dir1/. s3://zzz.buzz/dir3 <span class="go">upload: dir1/file1 to s3://zzz.buzz/dir3/file1 </span><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">cp</span> <span class="nt">--recursive</span> dir1 s3://zzz.buzz/dir4 <span class="go">upload: dir1/file1 to s3://zzz.buzz/dir4/file1 </span><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">cp</span> <span class="nt">--recursive</span> dir1/. s3://zzz.buzz/dir5 <span class="go">upload: dir1/file1 to s3://zzz.buzz/dir5/file1 </span><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">cp</span> <span class="nt">--recursive</span> s3://zzz.buzz/dir2 dir1 <span class="go">download: s3://zzz.buzz/dir2/file1 to dir1/file1 </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">sync </span>dir1 s3://zzz.buzz/dir2 <span class="go">upload: dir1/file1 to s3://zzz.buzz/dir2/file1 </span><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">sync </span>dir1/. s3://zzz.buzz/dir3 <span class="go">upload: dir1/file1 to s3://zzz.buzz/dir3/file1 </span><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">sync </span>dir1 s3://zzz.buzz/dir4 <span class="go">upload: dir1/file1 to s3://zzz.buzz/dir4/file1 </span><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">sync </span>dir1/. s3://zzz.buzz/dir5 <span class="go">upload: dir1/file1 to s3://zzz.buzz/dir5/file1 </span><span class="gp">$</span><span class="w"> </span>aws s3 <span class="nb">sync </span>s3://zzz.buzz/dir2 dir1 <span class="go">download: s3://zzz.buzz/dir2/file1 to dir1/file1 </span></code></pre></div></div> <h2 id="az-storage-copy">az storage copy</h2> <p>It's always the directory iteself and its content get copied to the destination directory.</p> <p>Note: Suffix a directory with <code class="language-plaintext highlighter-rouge">/</code> is the same as not suffixing it or suffixing it with <code class="language-plaintext highlighter-rouge">/.</code> .</p> <h3 id="az-examples">az Examples</h3> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>az storage copy <span class="nt">-r</span> <span class="nt">-s</span> dir1 <span class="nt">-d</span> https://zzzbuzz.blob.core.windows.net/container/dir2 <span class="go"> </span><span class="gp">$</span><span class="w"> </span>az storage blob list <span class="nt">--account-name</span> zzzbuzz <span class="nt">-c</span> container <span class="nt">--prefix</span> dir2 <span class="nt">--query</span> <span class="s2">"[].{name:name}"</span> <span class="nt">--output</span> tsv <span class="go">dir2/dir1/file1 dir2/file2 </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>az storage copy <span class="nt">-r</span> <span class="nt">-s</span> dir1/. <span class="nt">-d</span> https://zzzbuzz.blob.core.windows.net/container/dir3 <span class="go"> </span><span class="gp">$</span><span class="w"> </span>az storage blob list <span class="nt">--account-name</span> zzzbuzz <span class="nt">-c</span> container <span class="nt">--prefix</span> dir3 <span class="nt">--query</span> <span class="s2">"[].{name:name}"</span> <span class="nt">--output</span> tsv <span class="go">dir3/dir1/file1 dir3/file3 </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>az storage copy <span class="nt">-r</span> <span class="nt">-s</span> dir1 <span class="nt">-d</span> https://zzzbuzz.blob.core.windows.net/container/dir4 <span class="go"> </span><span class="gp">$</span><span class="w"> </span>az storage blob list <span class="nt">--account-name</span> zzzbuzz <span class="nt">-c</span> container <span class="nt">--prefix</span> dir4 <span class="nt">--query</span> <span class="s2">"[].{name:name}"</span> <span class="nt">--output</span> tsv <span class="go">dir4/dir1/file1 </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>az storage copy <span class="nt">-r</span> <span class="nt">-s</span> dir1/. <span class="nt">-d</span> https://zzzbuzz.blob.core.windows.net/container/dir5 <span class="go"> </span><span class="gp">$</span><span class="w"> </span>az storage blob list <span class="nt">--account-name</span> zzzbuzz <span class="nt">-c</span> container <span class="nt">--prefix</span> dir5 <span class="nt">--query</span> <span class="s2">"[].{name:name}"</span> <span class="nt">--output</span> tsv <span class="go">dir5/dir1/file1 </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>az storage copy <span class="nt">-r</span> <span class="nt">-s</span> https://zzzbuzz.blob.core.windows.net/container/dir1 <span class="nt">-d</span> download <span class="go"> </span><span class="gp">$</span><span class="w"> </span>tree download <span class="go">download └── dir1 └── file1 1 directory, 1 file </span></code></pre></div></div> <h2 id="gsutil-cp">gsutil cp</h2> <ul> <li>When destination directory does NOT exist, <ul> <li>the destination directory is created, and the content of source directory is copied.</li> </ul> </li> <li>When destination directory exists, <ul> <li>by default, both the directory itself and its content are copied to the destination directory;</li> <li>unless the source directory is <code class="language-plaintext highlighter-rouge">.</code>, or is suffixed with <code class="language-plaintext highlighter-rouge">/.</code>, by then, only the content of source directory is copied.</li> </ul> </li> </ul> <p>Note: Suffix a directory with <code class="language-plaintext highlighter-rouge">/</code> is the same as not suffixing it.</p> <p>Note: The behavior of <code class="language-plaintext highlighter-rouge">gsutil cp</code> is consistent with <code class="language-plaintext highlighter-rouge">cp</code>.</p> <h3 id="gsutil-examples">gsutil Examples</h3> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Destination not exists</span> <span class="gp">$</span><span class="w"> </span>gsutil <span class="nb">cp</span> <span class="nt">-r</span> dir1 gs://zzz.buzz/dir4 <span class="gp">$</span><span class="w"> </span>gsutil <span class="nb">ls</span> <span class="nt">-r</span> gs://zzz.buzz <span class="go">gs://zzz.buzz/dir4/: gs://zzz.buzz/dir4/file1 </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Source dir suffixed with /.</span> <span class="gp">$</span><span class="w"> </span><span class="c"># Destination not exists</span> <span class="gp">$</span><span class="w"> </span>gsutil <span class="nb">cp</span> <span class="nt">-r</span> dir1/. gs://zzz.buzz/dir5 <span class="gp">$</span><span class="w"> </span>gsutil <span class="nb">ls</span> <span class="nt">-r</span> gs://zzz.buzz <span class="go">gs://zzz.buzz/dir5/: gs://zzz.buzz/dir5/file1 </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Destination dir exists</span> <span class="gp">$</span><span class="w"> </span>gsutil <span class="nb">cp</span> <span class="nt">-r</span> dir1 gs://zzz.buzz/dir2 <span class="gp">$</span><span class="w"> </span>gsutil <span class="nb">ls</span> <span class="nt">-r</span> gs://zzz.buzz <span class="go">gs://zzz.buzz/dir2/: gs://zzz.buzz/dir2/file2 gs://zzz.buzz/dir2/dir1/: gs://zzz.buzz/dir2/dir1/file1 </span></code></pre></div></div> <div class="language-console highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="c"># Source dir suffixed with /.</span> <span class="gp">$</span><span class="w"> </span><span class="c"># Destination dir exists</span> <span class="gp">$</span><span class="w"> </span>gsutil <span class="nb">cp</span> <span class="nt">-r</span> dir1/. gs://zzz.buzz/dir3 <span class="gp">$</span><span class="w"> </span>gsutil <span class="nb">ls</span> <span class="nt">-r</span> gs://zzz.buzz <span class="go">gs://zzz.buzz/dir3/: gs://zzz.buzz/dir3/file1 gs://zzz.buzz/dir3/file3 </span></code></pre></div></div> Mon, 13 Apr 2020 19:19:42 +0800 https://zzz.buzz/2020/04/13/inconsistent-behaviors-among-cp-rsync-and-others/ https://zzz.buzz/2020/04/13/inconsistent-behaviors-among-cp-rsync-and-others/ Chrome OS Devices Support <p>Here are links for Chrome OS devices support on AUE, Android Apps and Linux Apps.</p> <h2 id="aue-auto-update-expiration--eol-end-of-life">AUE (Auto Update Expiration) / EOL (End of Life)</h2> <p>Chrome devices (e.g. Chromebook, Chromebox, Chromebase, Chromebit) receive automatic updates until it reaches its Auto Update Expiration (“AUE”). For a list of product and their Auto Update Expiration date, see <a href="https://support.google.com/chrome/a/answer/6220366">https://support.google.com/chrome/a/answer/6220366</a>.</p> <h2 id="android-apps-support">Android Apps Support</h2> <p>All devices that have launched in or after 2019 will support Android Apps.</p> <p>The Chromebooks, Chromeboxes, and Chromebases that were launched before 2019 that are able to install Android apps are listed at <a href="https://www.chromium.org/chromium-os/chrome-os-systems-supporting-android-apps">https://www.chromium.org/chromium-os/chrome-os-systems-supporting-android-apps</a>.</p> <h2 id="linux-crostini-support">Linux (Crostini) Support</h2> <p>All devices launched in or after 2019 will support Linux (Beta).</p> <p>The Chromebooks, Chromeboxes, and Chromebases launched before 2019 that support Linux (Beta) are listed at <a href="https://sites.google.com/a/chromium.org/dev/chromium-os/chrome-os-systems-supporting-linux">https://sites.google.com/a/chromium.org/dev/chromium-os/chrome-os-systems-supporting-linux</a>.</p> <p>And <a href="https://www.reddit.com/r/Crostini/wiki/getstarted/crostini-enabled-devices#wiki_known_working_devices">https://www.reddit.com/r/Crostini/wiki/getstarted/crostini-enabled-devices#wiki_known_working_devices</a>.</p> <p>Alternatively, check the supported boards:</p> <p><a href="https://chromium.googlesource.com/chromiumos/docs/+/master/containers_and_vms.md#supported-now">https://chromium.googlesource.com/chromiumos/docs/+/master/containers_and_vms.md#supported-now</a></p> <p>And here is the list for devices that will never get Crostini:</p> <p><a href="https://www.reddit.com/r/Crostini/wiki/faq/devices-that-will-never-get-crostini">https://www.reddit.com/r/Crostini/wiki/faq/devices-that-will-never-get-crostini</a></p> <hr /> <h2 id="chrome-os-devices-table">Chrome OS Devices Table</h2> <p>Release, OEM, Model, Code name, Board name(s), Base board, User ABI, Kernel, Kernel ABI, Platform, Form Factor, First Release, EOL/AUE, USB Gadget, Closed Case Debugging:</p> <p><a href="http://dev.chromium.org/chromium-os/developer-information-for-chrome-os-devices">http://dev.chromium.org/chromium-os/developer-information-for-chrome-os-devices</a></p> Wed, 08 Apr 2020 16:53:16 +0800 https://zzz.buzz/2020/04/08/chrome-os-devices-support/ https://zzz.buzz/2020/04/08/chrome-os-devices-support/ Ansible Tips <p>Some useful Ansible tips for quick reference.</p> <h2 id="install-a-local-ansible-role">Install a local ansible role</h2> <p>The following installs the role in the current directory.</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ansible-galaxy <span class="nb">install</span> <span class="s2">"git+file://</span><span class="si">$(</span><span class="nb">realpath</span> .<span class="si">)</span><span class="s2">"</span> </code></pre></div></div> <p>Replace <code class="language-plaintext highlighter-rouge">.</code> with other relative or absolute dir to install role located at other directory.</p> <h2 id="order-of-operations-for-a-play">Order of operations for a play</h2> <ol> <li>Fact gathering</li> <li>Variable loading</li> <li>The pre_tasks execution</li> <li>Handlers notified from the pre_tasks execution</li> <li>Roles execution (Each role listed in roles will execute in turn. Any role dependencies defined in the roles meta/main.yml will be run first, subject to tag filtering and conditionals.)</li> <li>Tasks execution</li> <li>Handlers notified from roles or tasks execution</li> <li>The post_tasks execution</li> <li>Handlers notified from the post_tasks execution</li> </ol> <div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span> <span class="pi">-</span> <span class="na">hosts</span><span class="pi">:</span> <span class="s">localhost</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="pi">-</span> <span class="na">a_var</span><span class="pi">:</span> <span class="s">derp</span> <span class="na">pre_tasks</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">pretask</span> <span class="na">debug</span><span class="pi">:</span> <span class="na">msg</span><span class="pi">:</span> <span class="s2">"</span><span class="s">a</span><span class="nv"> </span><span class="s">pre</span><span class="nv"> </span><span class="s">task"</span> <span class="na">changed_when</span><span class="pi">:</span> <span class="no">true</span> <span class="na">notify</span><span class="pi">:</span> <span class="s">say hi</span> <span class="na">roles</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">role</span><span class="pi">:</span> <span class="s">simple</span> <span class="na">derp</span><span class="pi">:</span> <span class="s">newval</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">task</span> <span class="na">debug</span><span class="pi">:</span> <span class="na">msg</span><span class="pi">:</span> <span class="s2">"</span><span class="s">a</span><span class="nv"> </span><span class="s">task"</span> <span class="na">changed_when</span><span class="pi">:</span> <span class="no">true</span> <span class="na">notify</span><span class="pi">:</span> <span class="s">say hi</span> <span class="na">post_tasks</span><span class="pi">:</span> <span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">posttask</span> <span class="na">debug</span><span class="pi">:</span> <span class="na">msg</span><span class="pi">:</span> <span class="s2">"</span><span class="s">a</span><span class="nv"> </span><span class="s">post</span><span class="nv"> </span><span class="s">task"</span> <span class="na">changed_when</span><span class="pi">:</span> <span class="no">true</span> <span class="na">notify</span><span class="pi">:</span> <span class="s">say hi</span> </code></pre></div></div> <p>Ref: <a href="https://learning.oreilly.com/library/view/mastering-ansible-/9781789951547/e5066899-f41e-43fd-a846-448cd3d6b71d.xhtml">Order of operations - Mastering Ansible - Third Edition</a></p> <h2 id="run-task-locally">Run task locally</h2> <ol> <li> <p><code class="language-plaintext highlighter-rouge">delegate_to: localhost</code> directive</p> <div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">take out of load balancer pool</span> <span class="na">command</span><span class="pi">:</span> <span class="s">/usr/bin/take_out_of_pool</span> <span class="na">delegate_to</span><span class="pi">:</span> <span class="s">127.0.0.1</span> </code></pre></div> </div> </li> <li> <p><code class="language-plaintext highlighter-rouge">local_action</code> module</p> <div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><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">take out of load balancer pool</span> <span class="na">local_action</span><span class="pi">:</span> <span class="s">command /usr/bin/take_out_of_pool</span> </code></pre></div> </div> <p>This one is basically the same as <code class="language-plaintext highlighter-rouge">delegate_to: localhost</code>, but deprecated for the <a href="https://github.com/ansible/ansible-lint/issues/475#issuecomment-460276739">reason</a>:</p> <blockquote> <p>To increase readability and match the style of typical ansible tasks, use delegate_to: localhost to replicate the functionality of local_action.</p> </blockquote> <p>And here is the output from <code class="language-plaintext highlighter-rouge">ansible-lint</code> if <code class="language-plaintext highlighter-rouge">local_action</code> is used:</p> <blockquote> <p>[504] Do not use 'local_action', use 'delegate_to: localhost'</p> </blockquote> </li> <li> <p><code class="language-plaintext highlighter-rouge">connection: local</code> directive</p> <div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">---</span> <span class="pi">-</span> <span class="na">hosts</span><span class="pi">:</span> <span class="s">127.0.0.1</span> <span class="na">connection</span><span class="pi">:</span> <span class="s">local</span> </code></pre></div> </div> <p><code class="language-plaintext highlighter-rouge">connection: local</code> runs the entire play locally.</p> <p><a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_delegation.html#local-playbooks">Note</a>: If you set the connection to local and there is no <code class="language-plaintext highlighter-rouge">ansible_python_interpreter</code> set, modules will run under <code class="language-plaintext highlighter-rouge">/usr/bin/python</code> and not under ``. Be sure to set <code class="language-plaintext highlighter-rouge">ansible_python_interpreter: ""</code> in <code class="language-plaintext highlighter-rouge">host_vars/localhost.yml</code>, for example. You can avoid this issue by using <code class="language-plaintext highlighter-rouge">local_action</code> or <code class="language-plaintext highlighter-rouge">delegate_to: localhost</code> instead.</p> <p>In addition, the connection directive can be overridden on commnad line:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ansible-playbook <span class="nt">-c</span> <span class="nb">local</span> ... </code></pre></div> </div> </li> </ol> <h2 id="debug-inventory">Debug inventory</h2> <p>Inventory can be specified with env var <code class="language-plaintext highlighter-rouge">ANSIBLE_INVENTORY</code>, or on command line via <code class="language-plaintext highlighter-rouge">-i &lt;file&gt;</code>, or in <code class="language-plaintext highlighter-rouge">ansible.cfg</code>:</p> <div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nn">[defaults]</span> <span class="py">inventory</span> <span class="p">=</span> <span class="s">path/to/inventory</span> </code></pre></div></div> <p>To list hosts matched by a group or graph an inventory, use the following methods:</p> <ol> <li> <p><code class="language-plaintext highlighter-rouge">ansible --list-hosts all</code></p> <p>Replace <code class="language-plaintext highlighter-rouge">all</code> with the group you want to list.</p> </li> <li> <p><code class="language-plaintext highlighter-rouge">ansible-inventory --graph</code></p> </li> <li> <p>Use variable <code class="language-plaintext highlighter-rouge">play_hosts</code> and <code class="language-plaintext highlighter-rouge">inventory_hostname</code> in a play.</p> </li> </ol> Mon, 06 Apr 2020 14:17:56 +0800 https://zzz.buzz/notes/ansible-tips/ https://zzz.buzz/notes/ansible-tips/ Ansible notes OpenSSL Commands for Certificate Management <p>The following are commands for dealing with SSL/TLS certificates using <code class="language-plaintext highlighter-rouge">openssl</code> I found useful. Categorized in <em>X509 Certificate</em>, <em>Certificate Private Key</em> or <em>PKCS #8</em>, <em>PFX</em> or <em>PKCS #12</em>, and <em>CSR</em>.</p> <h2 id="x509-certificate">X509 Certificate</h2> <h3 id="inspect-certificate">Inspect Certificate</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># List all info about the certificate</span> openssl x509 <span class="nt">-in</span> cert.pem <span class="nt">-noout</span> <span class="nt">-text</span> <span class="c"># Serial number</span> openssl x509 <span class="nt">-in</span> cert.pem <span class="nt">-noout</span> <span class="nt">-serial</span> <span class="c"># Start Date (Not Before)</span> openssl x509 <span class="nt">-in</span> cert.pem <span class="nt">-noout</span> <span class="nt">-startdate</span> <span class="c"># End Date (Not After)</span> openssl x509 <span class="nt">-in</span> cert.pem <span class="nt">-noout</span> <span class="nt">-enddate</span> <span class="c"># Subject</span> openssl x509 <span class="nt">-in</span> cert.pem <span class="nt">-noout</span> <span class="nt">-subject</span> <span class="c"># Subject Alternative Name (SAN)</span> openssl x509 <span class="nt">-in</span> cert.pem <span class="nt">-noout</span> <span class="nt">-text</span> | <span class="nb">grep </span>DNS <span class="c"># OCSP URI</span> openssl x509 <span class="nt">-in</span> cert.pem <span class="nt">-noout</span> <span class="nt">-ocsp_uri</span> </code></pre></div></div> <h3 id="check-certificate-revocation">Check Certificate Revocation</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">ocsp_uri</span><span class="o">=</span><span class="si">$(</span>openssl x509 <span class="nt">-in</span> cert.pem <span class="nt">-noout</span> <span class="nt">-ocsp_uri</span><span class="si">)</span> openssl ocsp <span class="nt">-issuer</span> chain.pem <span class="nt">-cert</span> cert.pem <span class="nt">-url</span> <span class="nv">$ocsp_uri</span> <span class="nt">-text</span> </code></pre></div></div> <h2 id="certificate-private-key-or-pkcs-8">Certificate Private Key or PKCS #8</h2> <h3 id="remove-private-key-password-decrypt">Remove Private Key Password (Decrypt)</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl pkcs8 <span class="nt">-in</span> encrypted-privkey.pem <span class="nt">-out</span> privkey.pem <span class="nt">-passin</span> pass:YourPasswordString <span class="c"># or</span> openssl pkcs8 <span class="nt">-in</span> encrypted-privkey.pem <span class="nt">-out</span> privkey.pem <span class="nt">-passin</span> <span class="nb">env</span>:YourPasswordEnvVar </code></pre></div></div> <h3 id="add-a-password-to-private-key-encrypt">Add a Password to Private Key (Encrypt)</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl pkcs8 <span class="nt">-in</span> privkey.pem <span class="nt">-topk8</span> <span class="nt">-passout</span> pass:YourPasswordString <span class="c"># or</span> openssl pkcs8 <span class="nt">-in</span> privkey.pem <span class="nt">-topk8</span> <span class="nt">-passout</span> <span class="nb">env</span>:YourPasswordEnvVar </code></pre></div></div> <h3 id="match-certificate-and-private-key">Match Certificate and Private Key</h3> <p>Online Tool: <a href="https://decoder.link/matcher">https://decoder.link/matcher</a></p> <p>Or use <em>openssl</em> command:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl x509 <span class="nt">-noout</span> <span class="nt">-modulus</span> <span class="nt">-in</span> cert.pem <span class="o">&gt;</span> cert.modulus openssl rsa <span class="nt">-noout</span> <span class="nt">-modulus</span> <span class="nt">-in</span> privkey.pem <span class="o">&gt;</span> key.modulus diff <span class="nt">-s</span> cert.modulus key.modulus </code></pre></div></div> <p>If your private key is password protected, add <code class="language-plaintext highlighter-rouge">-passin pass:YourPasswordString</code> or <code class="language-plaintext highlighter-rouge">-passin env:YourPasswordEnvVar</code>.</p> <h2 id="pfx-or-pkcs-12">PFX or PKCS #12</h2> <h3 id="combine-certificate-chain-and-key-files-into-a-single-pfx-file">Combine certificate (chain) and key files into a single pfx file</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl pkcs12 <span class="nt">-in</span> fullchain.pem <span class="nt">-inkey</span> privkey.pem <span class="nt">-export</span> <span class="nt">-out</span> fullchain.pfx <span class="nt">-password</span> pass:YourPasswordString <span class="c"># or</span> openssl pkcs12 <span class="nt">-in</span> fullchain.pem <span class="nt">-inkey</span> privkey.pem <span class="nt">-export</span> <span class="nt">-out</span> fullchain.pfx <span class="nt">-password</span> <span class="nb">env</span>:YourPasswordEnvVar </code></pre></div></div> <h3 id="split-pfx-file-into-certs-and-key">Split pfx file into certs and key</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Get Certificates (Full Chain)</span> openssl pkcs12 <span class="nt">-in</span> fullchain.pfx <span class="nt">-passin</span> pass:YourPasswordString <span class="nt">-nokeys</span> <span class="nt">-out</span> fullchain.pem <span class="c"># Get Client Certificate Only</span> openssl pkcs12 <span class="nt">-in</span> fullchain.pfx <span class="nt">-passin</span> pass:YourPasswordString <span class="nt">-nokeys</span> <span class="nt">-clcerts</span> <span class="nt">-out</span> cert.pem <span class="c"># Get CA/Intermediate Certificate Only</span> openssl pkcs12 <span class="nt">-in</span> fullchain.pfx <span class="nt">-passin</span> pass:YourPasswordString <span class="nt">-nokeys</span> <span class="nt">-cacerts</span> <span class="nt">-out</span> chain.pem <span class="c"># Get Private Key</span> openssl pkcs12 <span class="nt">-in</span> fullchain.pfx <span class="nt">-passin</span> pass:YourPasswordString <span class="nt">-nocerts</span> <span class="nt">-nodes</span> <span class="nt">-out</span> privkey.pem </code></pre></div></div> <h2 id="csr-certificate-signing-request">CSR (Certificate Signing Request)</h2> <h3 id="csr-generation-with-config-file">CSR Generation with config file</h3> <div class="language-ini highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># example.com.cnf </span> <span class="nn">[ req ]</span> <span class="py">default_bits</span> <span class="p">=</span> <span class="s">2048</span> <span class="py">default_md</span> <span class="p">=</span> <span class="s">sha256</span> <span class="py">prompt</span> <span class="p">=</span> <span class="s">no</span> <span class="py">encrypt_key</span> <span class="p">=</span> <span class="s">no</span> <span class="py">distinguished_name</span> <span class="p">=</span> <span class="s">dn</span> <span class="py">req_extensions</span> <span class="p">=</span> <span class="s">req_ext</span> <span class="nn">[ dn ]</span> <span class="py">CN</span> <span class="p">=</span> <span class="s">*.example.com</span> <span class="nn">[ req_ext ]</span> <span class="py">subjectAltName</span> <span class="p">=</span> <span class="s">@alt_names</span> <span class="nn">[ alt_names ]</span> <span class="py">DNS.1</span> <span class="p">=</span> <span class="s">*.example.com</span> <span class="py">DNS.2</span> <span class="p">=</span> <span class="s">example.com</span> </code></pre></div></div> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl req <span class="nt">-new</span> <span class="nt">-config</span> example.com.cnf <span class="nt">-keyout</span> example.com.key <span class="nt">-out</span> example.com.csr </code></pre></div></div> <h3 id="csr-generation-without-config-file">CSR Generation without config file</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl req <span class="nt">-subj</span> /CN<span class="o">=</span><span class="k">*</span>.example.com <span class="nt">-newkey</span> rsa:2048 <span class="nt">-nodes</span> <span class="nt">-keyout</span> example.com.key <span class="nt">-out</span> example.com.csr </code></pre></div></div> <p>Note: It's not easy to create CSR with Subject Alternative Name (SAN) without using a config file. <a href="https://security.stackexchange.com/questions/74345/provide-subjectaltname-to-openssl-directly-on-the-command-line">Click for more info.</a></p> <h3 id="csr-inspection">CSR Inspection</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl req <span class="nt">-in</span> example.com.csr <span class="nt">-noout</span> <span class="nt">-text</span> </code></pre></div></div> <h3 id="generate-a-self-signed-certificate">Generate a Self-Signed Certificate</h3> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl x509 <span class="nt">-req</span> <span class="nt">-days</span> 366 <span class="nt">-in</span> example.com.csr <span class="nt">-signkey</span> example.com.key <span class="nt">-out</span> example.com.crt </code></pre></div></div> <h3 id="match-csr-and-private-key">Match CSR and Private Key</h3> <p>Online Tool: <a href="https://decoder.link/matcher">https://decoder.link/matcher</a></p> <p>Or use <em>openssl</em> command:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>openssl req <span class="nt">-noout</span> <span class="nt">-modulus</span> <span class="nt">-in</span> example.com.csr <span class="o">&gt;</span> csr.modulus openssl rsa <span class="nt">-noout</span> <span class="nt">-modulus</span> <span class="nt">-in</span> example.com.key <span class="o">&gt;</span> key.modulus diff <span class="nt">-s</span> csr.modulus key.modulus </code></pre></div></div> <p>If your private key is password protected, add <code class="language-plaintext highlighter-rouge">-passin pass:YourPasswordString</code> or <code class="language-plaintext highlighter-rouge">-passin env:YourPasswordEnvVar</code>.</p> <h1 id="references">References</h1> <ul> <li><a href="https://www.openssl.org/docs/man1.1.1/man1/openssl-req.html"><code class="language-plaintext highlighter-rouge">man openssl-req</code></a></li> <li><a href="https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs">OpenSSL Essentials: Working with SSL Certificates, Private Keys and CSRs | DigitalOcean</a></li> </ul> Wed, 11 Mar 2020 21:42:35 +0800 https://zzz.buzz/2020/03/11/openssl-commands-for-certificate-management/ https://zzz.buzz/2020/03/11/openssl-commands-for-certificate-management/ Fix Boot Stuck Caused by X11 Configuration or GPU Driver <!-- BEGIN _includes/variables --> <!-- END _includes/variables --> <p>If you are running Linux on a dedicated disk, and boot it sometimes from bare metal, and other times from VMware or Virutal Box. You may have experienced boot stuck which may be caused by X11 config or display driver.</p> <p>Note that the same problem may occur if you are changing the GPU card between different vendors or attach the OS disk to another computer.</p> <p><img src="/content/2020/03/manjaro-boot-stuck.png" alt="Manjaro boot stuck" /></p> <h2 id="manjaro">Manjaro</h2> <p>I'm using Manjaro to explain the problem and the fix, but the idea should apply to other Linux distros as well.</p> <p>First, we need to escape from the boot screen. Press <kbd>Alt</kbd> + <kbd>F2</kbd> to switch <em>tty2</em> and login.</p> <h3 id="install-driver">Install driver</h3> <p>If you are running Manjaro Linux, use <code class="language-plaintext highlighter-rouge">mhwd</code> to install apropriate video drivers for your current hardware (<code class="language-plaintext highlighter-rouge">video-virutalmachine</code> or <code class="language-plaintext highlighter-rouge">video-vmware</code> if running in VMware, <code class="language-plaintext highlighter-rouge">video-nvidia-xxxxx</code> if running on bare metal with Nvidia cards, etc.)</p> <p>For example, the following command would result in the automatic detection and installation of the best available proprietary driver for a pci-connected graphics card:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mhwd <span class="nt">-a</span> pci free 0300 </code></pre></div></div> <p>Otherwise, the following command would result in the automatic detection and installation of the best available free driver for a pci-connected graphics card:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mhwd <span class="nt">-a</span> pci free 0300 </code></pre></div></div> <p>Use <code class="language-plaintext highlighter-rouge">mhwd -li</code> to check current installed drivers.</p> <h3 id="configure-x11">Configure X11</h3> <p>The next step is to configure X11 to use the correct config.</p> <p>If you are running on nvidia gpu, the following should work:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mhwd-gpu <span class="nt">--setmod</span> nvidia <span class="nt">--setxorg</span> /etc/X11/mhwd.d/nvidia.conf </code></pre></div></div> <p>If running in VMware, use the following:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo </span>mhwd-gpu <span class="nt">--setxorg</span> /etc/X11/mhwd.d/vmware.conf </code></pre></div></div> <p>You can always check what configs are available by:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> /etc/X11/mhwd.d </code></pre></div></div> <p>And check current used config via:</p> <div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">ls</span> <span class="nt">-l</span> /etc/X11/xorg.conf.d/90-mhwd.conf </code></pre></div></div> <p>After applying the fix, reboot your machine with <code class="language-plaintext highlighter-rouge">reboot</code> command to see if it works.</p> <h2 id="references">References</h2> <ul> <li><a href="https://wiki.manjaro.org/index.php/Configure_Graphics_Cards">Configure Graphics Cards - Manjaro Linux</a></li> <li><a href="https://wiki.manjaro.org/index.php?title=Configure_NVIDIA_(non-free)_settings_and_load_them_on_Startup">Configure NVIDIA (non-free) settings and load them on Startup - Manjaro Linux</a></li> </ul> Tue, 03 Mar 2020 15:28:44 +0800 https://zzz.buzz/2020/03/03/fix-boot-stuck-caused-by-x11-configuration-or-gpu-driver/ https://zzz.buzz/2020/03/03/fix-boot-stuck-caused-by-x11-configuration-or-gpu-driver/ Azure Monitor Log Query with Full Time Range <!-- BEGIN _includes/variables --> <!-- END _includes/variables --> <p>Query for Azure Monitor Log is by default set with a <strong>Last 24 hours</strong> time range, and we may also choose from a dropdown <em>Last hour</em>, <em>Last 7 days</em>, …, or use a datetime picker for a range. However, it's not easy to query without a time range restriction in UI.</p> <p>To achieve that, we can use the filter <code class="language-plaintext highlighter-rouge">| TimeGenerated &lt; now()</code> in a query to retrieve every single entry in the log table.</p> <p><img src="/content/2020/02/azure-monitor-log-query-editor.png" alt="Azure Monitor Log Query Editor" /></p> <p>Try it yourself with the demo platform for Log Analytics at <a href="https://aka.ms/LADemo">https://aka.ms/LADemo</a>!</p> Wed, 12 Feb 2020 17:15:03 +0800 https://zzz.buzz/2020/02/12/azure-monitor-log-query-with-full-time-range/ https://zzz.buzz/2020/02/12/azure-monitor-log-query-with-full-time-range/ Proxy localhost and loopback addresses in Chrome <!-- BEGIN _includes/variables --> <!-- END _includes/variables --> <p>Since Chrome 72, requests to localhost (127.0.0.1) or link-local IP do not go through a proxy by default.</p> <p><a href="https://chromium.googlesource.com/chromium/src/+/master/net/docs/proxy.md#Implicit-bypass-rules">Implicit bypass rules</a>:</p> <blockquote> <p>Requests to certain hosts will not be sent through a proxy, and will instead be sent directly.</p> <p>We call these the <em>implicit bypass rules</em>. The implicit bypass rules match URLs whose host portion is either a localhost name or a link-local IP literal. Essentially it matches:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> localhost *.localhost [::1] 127.0.0.1/8 169.254/16 [FE80::]/10 </code></pre></div> </div> <p>The complete rules are slightly more complicated. For instance on Windows we will also recognize <code class="language-plaintext highlighter-rouge">loopback</code>, and there is special casing of <code class="language-plaintext highlighter-rouge">localhost6</code> and <code class="language-plaintext highlighter-rouge">localhost6.localdomain6</code> in Chrome's localhost matching.</p> </blockquote> <h2 id="workaround">Workaround</h2> <p>The easiest workaround is to simply access your remote localhost via a globally resolvable hostname, e.g.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>local.test.cab *.local.test.cab </code></pre></div></div> <p>But if your remote localhost is configured to allow connections from hostname <em>localhost</em> only, then you need to configure chrome to ignore the implicit bypass rule.</p> <h2 id="override-chrome-implicit-bypass-rule-via-cmdshell">Override Chrome Implicit Bypass Rule via cmd/shell</h2> <p>To override the implicit bypass rule, you can run chrome with the following command line flag on Windows:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"%LocalAppData%\Google\Chrome SxS\Application\chrome.exe" --proxy-bypass-list="&lt;-loopback&gt;" </code></pre></div></div> <p>or on Linux:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>google-chrome --proxy-bypass-list="&lt;-loopback&gt;" chromium --proxy-bypass-list="&lt;-loopback&gt;" </code></pre></div></div> <h2 id="override-chrome-implicit-bypass-rule-via-switchyomega">Override Chrome Implicit Bypass Rule via SwitchyOmega</h2> <p>If using <a href="https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif">SwitchyOmega</a> Chrome extension, proxy of Chrome is controlled by it, so we need to add <code class="language-plaintext highlighter-rouge">&lt;-loopback&gt;</code> into <em>Bypass List</em> of the profile configured in the extension.</p> <p><img src="/content/2019/12/switchyomega.png" alt="SwithyOmega" /></p> <h2 id="fix-err_connection_refused">Fix ERR_CONNECTION_REFUSED</h2> <p><img src="/content/2019/12/err_connection_refused.png" alt="This site can’t be reached. localhost refused to connect. ERR_CONNECTION_REFUSED" /></p> <p>When you see this error, it may be caused by your request not going to the proxy server. Please recheck you've configured chrome to override implicit bypass rules correctly.</p> <h2 id="fix-err_empty_response">Fix ERR_EMPTY_RESPONSE</h2> <p>If you've configured chrome to ignore the implicit bypass rules, but still can't get access to the website hosted on your proxy server via <code class="language-plaintext highlighter-rouge">localhost</code>:</p> <p><img src="/content/2019/12/err_empty_response.png" alt="This page isn't working. localhost didn't send any data. ERR_EMPTY_RESPONSE" /></p> <p>You need to check whether you've input the correct port number.</p> <p>And to check whether there is an entry for localhost in <code class="language-plaintext highlighter-rouge">/etc/hosts</code> file on the <strong>proxy server</strong>:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>127.0.0.1 localhost </code></pre></div></div> <p>If not, add the above line to the file, and try reloading the page.</p> <p>Alternatively, simply access it via IP address <code class="language-plaintext highlighter-rouge">127.0.0.1</code></p> <h2 id="fix-err_ssl_protocol_error">Fix ERR_SSL_PROTOCOL_ERROR</h2> <p><img src="/content/2019/12/err_ssl_protocol_error.png" alt="This site can’t provide a secure connection. localhost sent an invalid response. ERR_SSL_PROTOCOL_ERROR" /></p> <p>If you see the SSL error, you're accessing an HTTP site via HTTPS.</p> <p>This may be caused by either incorrectly entering <code class="language-plaintext highlighter-rouge">https://</code> instead of <code class="language-plaintext highlighter-rouge">http://</code>, or <a href="https://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security">HSTS</a> policy set to the localhost domain.</p> <p>You can query and clear the HSTS status in chrome via &lt;chrome://net-internals/#hsts&gt; <em>Query Expect-CT domain</em> and <em>Delete domain security policies</em>.</p> <p><img src="/content/2019/12/chrome-hsts.png" alt="Chrome net-internals HSTS" /></p> <h2 id="if-things-are-still-not-working">If things are still not working…</h2> <p>Check the log of your proxy server. Please note that some proxy servers are configured to disallow connections to localhost, so you may have to configure the proxy sever itself.</p> <h2 id="references">References</h2> <ul> <li><a href="https://superuser.com/questions/1418848/how-to-avoid-google-chrome-proxy-bypass-for-localhost">How to avoid google chrome proxy bypass for localhost? - Super User</a></li> <li><a href="https://superuser.com/questions/1280827/why-does-the-registered-domain-name-localtest-me-resolve-to-127-0-0-1">networking - Why does the registered domain name “localtest.me” resolve to 127.0.0.1? - Super User</a></li> </ul> Thu, 12 Dec 2019 15:48:33 +0800 https://zzz.buzz/2019/12/12/proxy-localhost-and-loopback-in-chrome/ https://zzz.buzz/2019/12/12/proxy-localhost-and-loopback-in-chrome/