Nogweiihttps://evaryont.mehttps://secure.gravatar.com/avatar/efb9a1ec42adeec9615f062e55bf5c3e?size=2562021-07-25T22:41:00+00:00Nogweiihello@evaryont.mehttps://evaryont.meFixing SAML association for a Gitlab userhttps://evaryont.me/blog/2021/07/fixing-saml-association-for-a-gitlab-user.html2021-07-25T22:41:00+00:002021-07-25T23:45:36+00:00<p>After I recently rebuilt my
<a href="https://www.freeipa.org/page/Main_Page">FreeIPA</a> server, even after
restoring a backup, a few different identifiers for my users got
regenerated rather than restored. In particular, this results in
attempts to log in to services that rely on the UUIDs being consistent
to recognize the login as a new user rather than an existing user. In
part, this seems like a combination of FreeIPA,
<a href="https://www.keycloak.org/">Keycloak</a>, and
<a href="https://about.gitlab.com/">Gitlab</a>.</p>
<p>For my setup, Keycloak and Gitlab communicate using SAML, and the
configuration of the SAML details specifically state that the NameID
must be a <a href="https://shibboleth.atlassian.net/wiki/spaces/SHIB2/pages/2577072174/IdPPersistentNameIdentifier">persistent ID</a>, not an email address. So if the UUID is
regenerated, the ID isn't consistent, and so it's a new user not the
same old one.</p>
<p>Because of this, now users will get an HTTP 422 error that
authentication failed because their email has been taken already:</p>
<blockquote><p>Sign-in using <em>foo</em> auth failed</p>
<p>Sign-in failed because Email has already been taken.</p>
<p><em>...</em></p>
<p>If none of the options work, try contacting a GitLab administrator.</p>
</blockquote>
<h2 id="retrieving-the-saml-id">Retrieving the SAML ID</h2>
<p>First up, we need to retrieve the UUID of the user being sent to Gitlab,
so that we may update Gitlab's database to fix the UUID. An easy way is
to pull it from the Gitlab log:</p>
<div class="highlight"><pre class="highlight plaintext"><code>docker exec -it gitlab-omnibus bash
grep -E 'SAML\) Error saving user' /var/log/gitlab/gitlab-rails/application.log
</code></pre></div>
<p>And grab the value between 'user' and the parenthesized email after it.
For my Keycloak setup, that value is a UUID that begins with a <code>G-</code>.</p>
<h2 id="updating-gitlab">Updating Gitlab</h2>
<p>Now that we have the user's email address and the updated SAML ID, let's
launch the Rails console to update their information:</p>
<div class="highlight"><pre class="highlight plaintext"><code>docker exec -it gitlab-omnibus bash
gitlab-rails console
</code></pre></div>
<p>So now we can run the following Ruby code to update the SAML ID saved in
Gitlab's database:</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="c1"># Replace these with the appropriate values from the log messages above</span>
<span class="n">email</span> <span class="o">=</span> <span class="s2">"example@example.com"</span>
<span class="n">saml_id</span> <span class="o">=</span> <span class="s2">"G-00000000-0000-0000-0000-000000000000"</span>
<span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="p">.</span><span class="nf">find_by_any_email</span><span class="p">(</span><span class="n">email</span><span class="p">)</span>
<span class="n">ident</span> <span class="o">=</span> <span class="n">u</span><span class="p">.</span><span class="nf">identities</span><span class="p">.</span><span class="nf">select</span> <span class="p">{</span> <span class="o">|</span><span class="n">i</span><span class="o">|</span> <span class="n">i</span><span class="p">.</span><span class="nf">provider</span> <span class="o">==</span> <span class="s2">"saml"</span> <span class="p">}.</span><span class="nf">first</span>
<span class="n">ident</span><span class="p">.</span><span class="nf">extern_uid</span> <span class="o">=</span> <span class="n">saml_id</span>
<span class="n">ident</span><span class="p">.</span><span class="nf">save!</span>
</code></pre></div>
<p>And that's it! Now the user will be able to log in with the SAML
provider again.</p>
A program to launch the default KDE terminal emulatorhttps://evaryont.me/blog/2021/04/a-program-to-launch-the-default-kde-terminal-emulator.html2021-04-06T05:42:00+00:002021-06-30T05:58:35+00:00<p>So I've been looking for a way to launch the default terminal configured in KDE's system settings.
And unless I've missed something, there isn't a way to launch the default terminal emulator.</p>
<p><img src="/assets/images/screenshots/20210405_224531_system_settings.png" alt="Screenshot of KDE's System Settings showing Default Applciations" width="1430" height="1007" /></p>
<p>So to remedy this <em>egregious</em> 😛 problem I have written a small C++ application to handle this for me.
It's based on the very awesome <a href="https://doc.qt.io/qt-5/qcommandlineparser.html">QCommandLineParser</a> and <a href="https://api.kde.org/frameworks/kservice/html/classKToolInvocation.html">KToolInvocation</a> libraries, which made it very easy to implement this.
Many thanks to the devs of both libraries!
The documentation was very easy to follow and very extensive. The amount of attention that's been put in shows.</p>
<p>The source code is available online, licensed under the same license as the KDE Frameworks, <a href="https://spdx.org/licenses/LGPL-2.0-or-later.html">LGPL-2.0 or later</a>.</p>
<div class='onebox-post-wrap'>
<!-- {:onebox=>"<aside class=\"onebox allowlistedgeneric\">\n <header class=\"source\">\n <img src=\"https://code.aether.earth/assets/favicon-72a2cad5025aa931d6ea56c3201d1f18e68a8cd39788c7c80d5b2b82aa5143ef.png\" class=\"site-icon\">\n\n <a href=\"https://code.aether.earth/nogweii/ktermlaunch\" target=\"_blank\" rel=\"nofollow ugc noopener\">GitLab</a>\n </header>\n\n <article class=\"onebox-body\">\n <img src=\"https://code.aether.earth/uploads/-/system/project/avatar/22/konsole-logo.png\" class=\"thumbnail\">\n\n<h3><a href=\"https://code.aether.earth/nogweii/ktermlaunch\" target=\"_blank\" rel=\"nofollow ugc noopener\">nogweii / KDE Terminal Launcher · GitLab</a></h3>\n\n <p>A very basic program that launches the default configured terminal in KDE's settings</p>\n\n\n </article>\n\n <div class=\"onebox-metadata\">\n \n \n </div>\n\n <div style=\"clear: both\"></div>\n</aside>\n", :preview=>"<aside class=\"onebox allowlistedgeneric\">\n <header class=\"source\">\n <img src=\"https://code.aether.earth/assets/favicon-72a2cad5025aa931d6ea56c3201d1f18e68a8cd39788c7c80d5b2b82aa5143ef.png\" class=\"site-icon\">\n\n <a href=\"https://code.aether.earth/nogweii/ktermlaunch\" target=\"_blank\" rel=\"nofollow ugc noopener\">GitLab</a>\n </header>\n\n <article class=\"onebox-body\">\n <img src=\"https://code.aether.earth/uploads/-/system/project/avatar/22/konsole-logo.png\" class=\"thumbnail\">\n\n<h3><a href=\"https://code.aether.earth/nogweii/ktermlaunch\" target=\"_blank\" rel=\"nofollow ugc noopener\">nogweii / KDE Terminal Launcher · GitLab</a></h3>\n\n <p>A very basic program that launches the default configured terminal in KDE's settings</p>\n\n\n </article>\n\n <div class=\"onebox-metadata\">\n \n \n </div>\n\n <div style=\"clear: both\"></div>\n</aside>\n", :errors=>{}} -->
<aside class="onebox allowlistedgeneric">
<header class="source">
<img src="https://code.aether.earth/assets/favicon-72a2cad5025aa931d6ea56c3201d1f18e68a8cd39788c7c80d5b2b82aa5143ef.png" class="site-icon">
<a href="https://code.aether.earth/nogweii/ktermlaunch" target="_blank" rel="nofollow ugc noopener">GitLab</a>
</header>
<article class="onebox-body">
<img src="https://code.aether.earth/uploads/-/system/project/avatar/22/konsole-logo.png" class="thumbnail">
<h3><a href="https://code.aether.earth/nogweii/ktermlaunch" target="_blank" rel="nofollow ugc noopener">nogweii / KDE Terminal Launcher · GitLab</a></h3>
<p>A very basic program that launches the default configured terminal in KDE's settings</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both"></div>
</aside>
</div>
<p>With that, you can then bind a key to launch the terminal emulator using KHotKeys.
Here's an example file you can import:</p>
<div class='onebox-post-wrap'>
<!-- {:onebox=>"<aside class=\"onebox allowlistedgeneric\">\n <header class=\"source\">\n <img src=\"https://code.aether.earth/assets/favicon-72a2cad5025aa931d6ea56c3201d1f18e68a8cd39788c7c80d5b2b82aa5143ef.png\" class=\"site-icon\">\n\n <a href=\"https://code.aether.earth/-/snippets/3\" target=\"_blank\" rel=\"nofollow ugc noopener\">GitLab</a>\n </header>\n\n <article class=\"onebox-body\">\n <img src=\"https://code.aether.earth/assets/twitter_card-570ddb06edf56a2312253c5872489847a0f385112ddbcd71ccfa1570febab5d2.jpg\" class=\"thumbnail\">\n\n<h3><a href=\"https://code.aether.earth/-/snippets/3\" target=\"_blank\" rel=\"nofollow ugc noopener\">ktermlaunch khotkeys export ($3) · Snippets · GitLab</a></h3>\n\n <p>GitLab Community Edition</p>\n\n\n </article>\n\n <div class=\"onebox-metadata\">\n \n \n </div>\n\n <div style=\"clear: both\"></div>\n</aside>\n", :preview=>"<aside class=\"onebox allowlistedgeneric\">\n <header class=\"source\">\n <img src=\"https://code.aether.earth/assets/favicon-72a2cad5025aa931d6ea56c3201d1f18e68a8cd39788c7c80d5b2b82aa5143ef.png\" class=\"site-icon\">\n\n <a href=\"https://code.aether.earth/-/snippets/3\" target=\"_blank\" rel=\"nofollow ugc noopener\">GitLab</a>\n </header>\n\n <article class=\"onebox-body\">\n <img src=\"https://code.aether.earth/assets/twitter_card-570ddb06edf56a2312253c5872489847a0f385112ddbcd71ccfa1570febab5d2.jpg\" class=\"thumbnail\">\n\n<h3><a href=\"https://code.aether.earth/-/snippets/3\" target=\"_blank\" rel=\"nofollow ugc noopener\">ktermlaunch khotkeys export ($3) · Snippets · GitLab</a></h3>\n\n <p>GitLab Community Edition</p>\n\n\n </article>\n\n <div class=\"onebox-metadata\">\n \n \n </div>\n\n <div style=\"clear: both\"></div>\n</aside>\n", :errors=>{}} -->
<aside class="onebox allowlistedgeneric">
<header class="source">
<img src="https://code.aether.earth/assets/favicon-72a2cad5025aa931d6ea56c3201d1f18e68a8cd39788c7c80d5b2b82aa5143ef.png" class="site-icon">
<a href="https://code.aether.earth/-/snippets/3" target="_blank" rel="nofollow ugc noopener">GitLab</a>
</header>
<article class="onebox-body">
<img src="https://code.aether.earth/assets/twitter_card-570ddb06edf56a2312253c5872489847a0f385112ddbcd71ccfa1570febab5d2.jpg" class="thumbnail">
<h3><a href="https://code.aether.earth/-/snippets/3" target="_blank" rel="nofollow ugc noopener">ktermlaunch khotkeys export ($3) · Snippets · GitLab</a></h3>
<p>GitLab Community Edition</p>
</article>
<div class="onebox-metadata">
</div>
<div style="clear: both"></div>
</aside>
</div>
<p>With it, hitting <kbd>Win</kbd> + <kbd>Enter</kbd> spawns a terminal emulator.
It's one of my must-have shortcuts on any system I use extensively.
And now, that key bind automatically follows my preferences, hurray!</p>
My gaming PChttps://evaryont.me/blog/2021/01/my-gaming-pc-2021.html2021-01-30T06:32:00+00:002021-06-30T05:58:35+00:00<p>New decade, new hardware. A few people have asked what my system looks like, so
here it is rather than repeating myself:</p>
<table><thead>
<tr>
<th>Type</th>
<th>Item</th>
<th>Notes</th>
</tr>
</thead><tbody>
<tr>
<td><strong>CPU</strong></td>
<td><a href="https://www.amd.com/en/products/cpu/amd-ryzen-7-5800x">AMD Ryzen 7 5800X</a></td>
<td>I got lucky on this, I did want a 5900x or 5950 but this might actually be more performant</td>
</tr>
<tr>
<td><strong>CPU Cooler</strong></td>
<td><a href="https://noctua.at/en/nh-d15s">Noctua NH-D15S</a></td>
<td>I honestly meant to get a different model with 2 fans included, but it's probably fine</td>
</tr>
<tr>
<td><strong>Motherboard</strong></td>
<td><a href="https://www.gigabyte.com/Motherboard/X570-AORUS-PRO-WIFI-rev-11-12">Gigabyte X570 AORUS PRO WIFI</a></td>
<td></td>
</tr>
<tr>
<td><strong>RAM</strong></td>
<td><a href="https://www.corsair.com/us/en/Categories/Products/Memory/VENGEANCE-LPX/p/CMK32GX4M2D3600C18">Corsair Vengeance LPX 32 GB (2 x 16 GB) DDR4-3600</a></td>
<td>32GB seems like enough nowadays, I often don't use more than 18 currently</td>
</tr>
<tr>
<td><strong>Storage</strong></td>
<td><a href="https://www.samsung.com/semiconductor/minisite/ssd/product/consumer/970evo/">Samsung 970 Evo 1 TB M.2 NVME SSD</a></td>
<td>Boot drive</td>
</tr>
<tr>
<td><strong>Storage</strong></td>
<td><a href="https://www.samsung.com/semiconductor/minisite/ssd/product/consumer/970evo/">Samsung 970 Evo 1 TB M.2 NVME SSD</a></td>
<td>Personal profile drive, and WSL</td>
</tr>
<tr>
<td><strong>Storage</strong></td>
<td><a href="https://www.crucial.com/products/ssd/crucial-mx500-ssd">Crucial MX500 2 TB 2.5" SSD</a></td>
<td>Rapid storage for video games</td>
</tr>
<tr>
<td><strong>Storage</strong></td>
<td><a href="https://shop.westerndigital.com/products/internal-drives/wd-purple-sata-hdd#WD40PURZ">Western Digital Purple 4TB 3.5" 5400RPM HDD</a></td>
<td>Backup destination for my network, saved to the cloud with Backblaze</td>
</tr>
<tr>
<td><strong>Storage</strong></td>
<td><a href="https://shop.westerndigital.com/products/internal-drives/wd-red-plus-sata-3-5-hdd#WD40EFRX">Western Digital Red Pro 4TB 3.5" 7200RPM HDD</a></td>
<td>Large games storage</td>
</tr>
<tr>
<td><strong>Video Card</strong></td>
<td><a href="https://www.gigabyte.com/Graphics-Card/GV-N208SAORUS-8GC#kf">Gigabyte AORUS RTX 2080 SUPER</a></td>
<td>Didn't want to wait for a new card, I'm bottlenecked on the previous CPU anyways</td>
</tr>
<tr>
<td><strong>Case</strong></td>
<td><a href="https://www.bequiet.com/en/case/1472">be quiet! Dark Base Pro 900 Rev. 2 ATX Full Tower Case</a></td>
<td>It has a USB Type C on the front panel along with a Qi wireless charging pad! Neat!</td>
</tr>
<tr>
<td><strong>Power Supply</strong></td>
<td><a href="https://www.corsair.com/us/en/Categories/Products/Power-Supply-Units/axi-series-config/p/CP-9020036-NA">Corsair AXi 760W 80+ Platinum</a></td>
<td></td>
</tr>
<tr>
<td><strong>Optical Drive</strong></td>
<td><a href="https://www.lg.com/us/burners-drives/lg-WH16NS40-internal-blu-ray-dvd-drive">LG WH16NS40 Blu-Ray/DVD/CD Writer</a></td>
<td>Optical media is still useful, though not frequent</td>
</tr>
<tr>
<td><strong>Case Accessory</strong></td>
<td><a href="https://www.vantecusa.com/products_detail.php?p_id=136&p_name=USB+3.0+Multi-Memory+Internal+Card+Reader&pc_id=18&pc_name=Card+reader&pt_id=5&pt_name=Accessories">Vantec UGT-CR935 Card Reader</a></td>
<td>And SDcards are useful too!</td>
</tr>
<tr>
<td><strong>Operating System</strong></td>
<td><a href="https://www.microsoft.com/en-us/windowsforbusiness/windows-10-pro">Microsoft Windows 10 Pro</a></td>
<td>Got the Windows 8 license for free and the upgrade to 10 was free; why not?</td>
</tr>
<tr>
<td><strong>Monitor</strong></td>
<td><a href="https://www.benq.com/en-us/monitor/designer/pd3200u.html">BenQ PD3200U 32.0" 4k</a></td>
<td>A solid 4K monitor with excellent colors, and a USB hub!</td>
</tr>
<tr>
<td><strong>Keyboard</strong></td>
<td><a href="https://www.razer.com/gaming-keyboards/Razer-BlackWidow/RZ03-02860100-R3M1">Razer BlackWidow Chroma V2</a></td>
<td>Mechanical keyboard. Solid and puts up with my typing.</td>
</tr>
<tr>
<td><strong>Mouse</strong></td>
<td><a href="https://support.logi.com/hc/en-us/articles/360023306914-Logitech-G502-Proteus-Core-Technical-Specifications">Logitech G502 Proteus Core</a></td>
<td></td>
</tr>
<tr>
<td><strong>Headphones</strong></td>
<td><a href="https://steelseries.com/gaming-headsets/siberia-650">SteelSeries Siberia 650 Headset</a></td>
<td>This was a gift, which I very much appreciate!</td>
</tr>
<tr>
<td><strong>Webcam</strong></td>
<td><a href="https://www.logitech.com/en-us/products/webcams/c930e-business-webcam.960-000971.html?crid=34">Logitech C930e Webcam</a></td>
<td></td>
</tr>
</tbody></table>
Caching CI stuff from Gitlab with MinIOhttps://evaryont.me/blog/2020/12/caching-ci-stuff-from-gitlab-with-minio.html2020-12-13T02:24:00+00:002021-07-06T00:24:02+00:00<p>Some notes on how I've gotten a cache to work with Gitlab Runner.</p>
<p>First, install MinIO somewhere. Not going to repeat what's already on the internet a bunch.
Personally, I installed it on my NAS, a Synology, using <a href="https://synocommunity.com/package/minio">the SynoCommunity package</a>.</p>
<p>One thing to watch out for, the character set for the keys are somewhat limited. I ended up sticking to alphanumerics and making the values very long.</p>
<h2 id="minio-client">MinIO client</h2>
<p>In order to administrate a MinIO server, you use it's API.
The built-in web browsing interface doesn't have an admin panel.</p>
<p>Arch Linux packages the client (<a href="https://www.archlinux.org/packages/community/x86_64/minio-client/">community/minio-client</a>), so that is a single command away: <code>pacman -S minio-client</code>.
To avoid conflicting with Midnight Commander, <a href="https://github.com/minio/mc/blob/RELEASE.2018-01-18T21-18-56Z/CONFLICT.md">per the upstream recommendation</a>, the binary is called <code>mcli</code> and not <code>mc</code>.
I'll use that name as well throughout.</p>
<p>Now that it's installed, you must create an alias:</p>
<div class="highlight"><pre class="highlight plaintext"><code>mcli alias set syno http://10.0.0.2:9000 ROOT_ACCESS_KEY ROOT_SECRET_KEY
</code></pre></div>
<h2 id="preparing-minio">Preparing MinIO</h2>
<p>After that's done, in a fresh MinIO installation you will have only 1 user, the root account.
I didn't want to give <code>gitlab-runner</code> that much power, so I created a second account for it:</p>
<div class="highlight"><pre class="highlight plaintext"><code>mcli admin user add syno/ gitlab-runner-1234 SECRET_KEY
</code></pre></div>
<p>I'm keeping the access key somewhat descriptive so that it's obvious what it's purpose is when I come back to this server. </p>
<p>That user doesn't have permission to do anything, so let's make it a bucket for them:</p>
<div class="highlight"><pre class="highlight plaintext"><code>mcli mb syno/gitlab-runner
</code></pre></div>
<p>Then create an security/access policy file that lists the permissions we want to grant.
The <a href="https://github.com/minio/pkg/blob/main/bucket/policy/action.go">list of supported actions</a> can be found in minio's source code.
Unfortunately it's not better documented elsewhere.</p>
<div class="highlight"><pre class="highlight json"><code><span class="p">{</span><span class="w">
</span><span class="nl">"Version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2012-10-17"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Statement"</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">"Effect"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Allow"</span><span class="p">,</span><span class="w">
</span><span class="nl">"Action"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="s2">"s3:GetObject"</span><span class="p">,</span><span class="w">
</span><span class="s2">"s3:PutObject"</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="s2">"arn:aws:s3:::gitlab-runner/*"</span><span class="p">,</span><span class="w"> </span><span class="s2">"arn:aws:s3:::gitlab-runner"</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><span class="p">}</span><span class="w">
</span></code></pre></div>
<p>And attach it to the server:</p>
<div class="highlight"><pre class="highlight plaintext"><code>mcli admin policy add syno gitlab-runner-perms gitlab_runner_policy.json
</code></pre></div>
<p>If you need to make changes to the policy, rerunning the same command is the same as an update.</p>
<p>Now, glue the permissions to the user:</p>
<div class="highlight"><pre class="highlight plaintext"><code>mcli admin policy set syno gitlab-runner-perms user=gitlab-runner-1234
</code></pre></div>
<h2 id="configuring-gitlab-runner">Configuring gitlab-runner</h2>
<p>Cool, now we have a user that can do some stuff in MinIO, time to teach gitlab-runner about that.
All of this can be done in <a href="https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runnerscaches3-section">the configuration file</a>.
Or as environment variables, but I'm using files in my deployment.</p>
<div class="highlight"><pre class="highlight toml"><code> <span class="nn">[runners.cache]</span>
<span class="py">Type</span> <span class="p">=</span> <span class="s">"s3"</span>
<span class="py">Path</span> <span class="p">=</span> <span class="s">"cache"</span>
<span class="py">Shared</span> <span class="p">=</span> <span class="kc">true</span>
<span class="nn">[runners.cache.s3]</span>
<span class="py">ServerAddress</span> <span class="p">=</span> <span class="s">"10.0.0.2:9000"</span>
<span class="py">AccessKey</span> <span class="p">=</span> <span class="s">"gitlab-runner-1234"</span>
<span class="py">SecretKey</span> <span class="p">=</span> <span class="s">"SUPER_SECRET_KEY"</span>
<span class="py">BucketName</span> <span class="p">=</span> <span class="s">"gitlab-runner"</span>
<span class="py">Insecure</span> <span class="p">=</span> <span class="kc">true</span> <span class="c"># since minio is over HTTP</span>
</code></pre></div>
<h2 id="future-work">Future work</h2>
<p>The gitlab runner server is on the same LAN as my NAS, so it's not the worst that it's over HTTP, but I do want to improve that.
I've been working on setting up an internal CA for HTTPS deployments, so hopefully I can flip that <code>Insecure</code> to <q>false</q>!</p>
<p>All of these details are done using CLI tools, which can be scripted, but they aren't super idempotent as they stand.
Thankfully, there are projects that can help with that already, like this <a href="https://github.com/aminueza/terraform-provider-minio">terraform provider for minio</a>.</p>
<h2 id="thanks">Thanks</h2>
<p>This was put together from reading documentation, but also from these lovely blog posts:</p>
<ul>
<li><a href="https://blog.nikhilbhardwaj.in/2020/02/25/minio-bucket-policy/">Minio Bucket Policy Notes</a> by nikhilbhardwaj</li>
<li><a href="https://www.enovate.co.uk/blog/2019/12/11/distributed-gitlab-runner-caching-with-minio">Distributed GitLab Runner Caching with MinIO</a> by Matt Banner</li>
</ul>
Forcing fsck to repair a corrupted CentOS root for systemd based hostshttps://evaryont.me/blog/2019/05/forcing-fsck-to-repair-a-corrupted-root-for-systemd-based-hosts.html2019-05-27T23:01:00+00:002021-06-30T05:58:35+00:00<h1 id="warning-this-is-just-a-pile-of-text-that-isnt-probably-super-useful-to-anyone-including-myself-ive-already-forgotten-how-i-got-some-of-the-data-off-the-disk-in-the-end-i-destroyed-the-vms-disk-and-rebuilt-it-from-scratch">WARNING: This is just a pile of text that isn't probably super useful to anyone, including myself. I've already forgotten how I got some of the data off the disk. In the end, I destroyed the VM's disk and rebuilt it from scratch.</h1>
<p>This last weekend I had an unfortunate incident with one of my remote VMs. The underlying host crashed, hard,
taking my VM down with it in an unclean manner. And lucky me, that left a bunch of docker containers with corrupted filesystems lying around!</p>
<div class="highlight"><pre class="highlight plaintext"><code>May 27 22:38:40 blimp.aether.earth dockerd[9767]: Error starting daemon: error initializing graphdriver: lstat /var/lib/docker/overlay2/280979306bc8a5a038282a1216fc887c
alizing graphdriver: lstat /var/lib/docker/overlay2/280979306bc8a5a038282a1216fc887c443d1b9756a74641c2e15f3259e6aeda: input/output error
ls: cannot access /var/lib/docker/overlay2/280979306bc8a5a038282a1216fc887c443d1b9756a74641c2e15f3259e6aeda: Input/output error
rm: cannot remove ‘/var/lib/docker/overlay2/280979306bc8a5a038282a1216fc887c443d1b9756a74641c2e15f3259e6aeda’: Input/output error
</code></pre></div>
<p>Referring to the documentation of <code>systemd-fsck</code>:
https://www.freedesktop.org/software/systemd/man/systemd-fsck@.service.html</p>
<p>Edit grub config:</p>
<div class="highlight"><pre class="highlight plaintext"><code>vim /etc/default/grub
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
reboot
</code></pre></div>
<h3 id="recovering-dotfiles">recovering dotfiles</h3>
<p>this is the easiest one to fix, since it's all stored in my public gitlab repo:</p>
<div class="highlight"><pre class="highlight plaintext"><code>rm ~/dotfiles
git clone
rake
</code></pre></div>
<h3 id="recovering-yum">recovering yum</h3>
<div class="highlight"><pre class="highlight plaintext"><code>One of the configured repositories failed (Unknown),
and yum doesn't have enough cached data to continue. At this point the only
safe thing yum can do is fail. There are a few ways to work "fix" this:
file is encrypted or is not a database
</code></pre></div>
<p>Running <code>file</code> on the failed repo returns just <q>data</q> rather than recognizing it as an SQLite3 file, indicating it's been corrupted.</p>
<div class="highlight"><pre class="highlight plaintext"><code>file /var/cache/yum/x86_64/7/jdoss-wireguard/gen/primary_db.sqlite
/var/cache/yum/x86_64/7/jdoss-wireguard/gen/primary_db.sqlite: data
</code></pre></div>
<p>deleting it fixes some things but wasn't the complete solution.</p>
<p>delete all of the downloaded sqlite package dbs:</p>
<div class="highlight"><pre class="highlight plaintext"><code>sudo rm /var/cache/yum/x86_64/7/*/*primary.sqlite.bz2
</code></pre></div>
<p>got a step closer, yum changed error message to 'database disk image is malformed'</p>
<div class="highlight"><pre class="highlight plaintext"><code>yum clean all
yum makecache
</code></pre></div>
<p>Seemed to work, but now I'm getting a bunch of rpm errors:</p>
<div class="highlight"><pre class="highlight plaintext"><code>error: rpmdbNextIterator: skipping h# 500 region trailer: BAD, tag 962398765 type 542860144 offset -1969648229 count 1901928553
</code></pre></div>
<p>And yum update is freezing and locking a CPU at 100%.
Rebuild the RPMDB:</p>
<div class="highlight"><pre class="highlight plaintext"><code>rm -f /var/lib/rpm/__db*
rpm --rebuilddb
</code></pre></div>
<p>That worked, but now <code>yum check</code> reports a bunch of errors.</p>
<p>In particular, </p>
<div class="highlight"><pre class="highlight plaintext"><code>/sbin/ldconfig: /lib64/libseaudit.so.4 is not an ELF file - it has the wrong magic bytes at the start.
/sbin/ldconfig: /lib64/libseaudit.so.4 is not a symbolic link
</code></pre></div>
<p>Figured out that <code>libseaudit.so.4</code> is owned by the <code>setools-libs</code> package
So reinstall it fixes that error: <code>sudo yum reinstall setools-libs</code></p>
<p>Then ran <code>yum check obsoleted duplicates dependencies</code> again</p>
Automatically adding UptimeRobot to Gitlab's monitoring whitelist with Ansiblehttps://evaryont.me/blog/2018/10/automatically-adding-uptimerobot-to-gitlab-s-monitoring-whitelist-with-ansible.html2018-10-20T23:51:00+00:002021-06-30T05:58:35+00:00<p>GitLab has a number of <a href="https://gitlab.com/help/user/admin_area/monitoring/health_check.md">monitoring endpoints</a> you can ping to make sure that
not only is the rails process running (and not just your webserver) but that
also the background services Gitlab depends on are running successfully too.</p>
<p>I want to monitor <a href="https://code.aether.earth">my personal Gitlab</a> instance
with <a href="https://uptimerobot.com/">UptimeRobot</a> hitting those endpoints for a more accurate uptime
measurement. Gitlab does have a monitoring token I could append to the URL but
that is deprecated. Instead, you should add the monitoring machines to an <a href="https://gitlab.com/help/administration/monitoring/ip_whitelist.md">IP
whitelist</a>. Thankfully, UptimeRobot provides a list of all of their <a href="https://uptimerobot.com/locations">incoming
IP addresses</a>.</p>
<p>Thing is, I'm lazy. I don't want to have to manually add all of those IP
addresses to the whitelist. I already have the Omnibus GitLab configuration
managed as a template via Ansible, so the best way is to have Ansible
automatically download those lists.</p>
<p>First we'll set the IP URLs as variables:</p>
<div class="highlight"><pre class="highlight yaml"><code><span class="na">uptimerobot_ipv4_url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://uptimerobot.com/inc/files/ips/IPv4.txt"</span>
<span class="na">uptimerobot_ipv6_url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">https://uptimerobot.com/inc/files/ips/IPv6.txt"</span>
</code></pre></div>
<p>Then have Ansible download the remote files and register a local variable:</p>
<div class="highlight"><pre class="highlight yaml"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Download the list of IPv4 address of UptimeRobot network</span>
<span class="na">uri</span><span class="pi">:</span>
<span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">uptimerobot_ipv4_url</span><span class="nv"> </span><span class="s">}}"</span>
<span class="na">return_content</span><span class="pi">:</span> <span class="s">yes</span>
<span class="na">register</span><span class="pi">:</span> <span class="s">_ur_ipv4_uri</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Download the list of IPv6 address of UptimeRobot network</span>
<span class="na">uri</span><span class="pi">:</span>
<span class="na">url</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">uptimerobot_ipv6_url</span><span class="nv"> </span><span class="s">}}"</span>
<span class="na">return_content</span><span class="pi">:</span> <span class="s">yes</span>
<span class="na">register</span><span class="pi">:</span> <span class="s">_ur_ipv6_uri</span>
</code></pre></div>
<p>Now that we have the two variables, <em><em>ur</em>ipv4_uri</em> and <em><em>ur</em>ipv6_uri</em>, we
can split up the plain text list of IP addresses:</p>
<div class="highlight"><pre class="highlight yaml"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Split up the list of IPs</span>
<span class="na">set_fact</span><span class="pi">:</span>
<span class="na">_ur_ipv4_ip_list</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">_ur_ipv4_uri.content.split()</span><span class="nv"> </span><span class="s">}}"</span>
<span class="na">_ur_ipv6_ip_list</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">_ur_ipv6_uri.content.split()</span><span class="nv"> </span><span class="s">}}"</span>
</code></pre></div>
<p>Then we merge the two lists into a single one of all of UptimeRobot's IP
addresses:</p>
<div class="highlight"><pre class="highlight yaml"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Combining the list of IPv4 and IPv6 addresses</span>
<span class="na">set_fact</span><span class="pi">:</span>
<span class="na">_ur_all_ips</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">_ur_ipv4_ip_list</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">union(_ur_ipv6_ip_list)</span><span class="nv"> </span><span class="s">}}"</span>
</code></pre></div>
<p>Lastly, here's the tricky part. I want to include this list of IP addresses
into the monitoring whitelist, while not overriding the current values that
may be included already. Thus, I want to take these two dictionaries:</p>
<table>
<tr>
<th>UptimeRobot IPs</th>
<th>Personal whitelist</th>
</tr>
<tr>
<td>
<pre>
_ur_all_ips:
- 216.144.250.150
- 69.162.124.226
- ...
</pre>
</td>
<td>
<pre>
gitlab_rb:
gitlab_rails:
monitoring_whitelist:
- 127.0.0.1
- 10.0.0.0/8
- ...
</pre>
</td>
</tr>
</table>
<p>And merge them together into the sub-key
<code>gitlab_rb.gitlab_rails.monitoring_whitelist</code>. This is done via the lovely
<a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#combining-hashes-dictionaries"><code>combine</code> filter</a>:</p>
<div class="highlight"><pre class="highlight yaml"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Inject UptimeRobot IP list into monitoring whitelist</span>
<span class="na">set_fact</span><span class="pi">:</span>
<span class="na">gitlab_rb</span><span class="pi">:</span> <span class="s2">"</span><span class="s">{{</span><span class="nv"> </span><span class="s">gitlab_rb</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">combine({'gitlab_rails':</span><span class="nv"> </span><span class="s">{'monitoring_whitelist':</span><span class="nv"> </span><span class="s">gitlab_rb.gitlab_rails.monitoring_whitelist</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">default([])</span><span class="nv"> </span><span class="s">|</span><span class="nv"> </span><span class="s">union(_ur_all_ips)</span><span class="nv"> </span><span class="s">}},</span><span class="nv"> </span><span class="s">recursive=True)</span><span class="nv"> </span><span class="s">}}"</span>
</code></pre></div>
<p>The important magic happens all in that one line. I take the existing gitlab
configuration dictionary and build a new dictionary that matches it's
structure. I then take the current monitoring whitelist (which might not
already exist so I default to an empty list) and do a set union with the
UptimeRobot IP addresses. Both dictionaries are passed to the combine filter,
with recursive set to true to not override any other sibling keys in the
original dictionary.</p>
<p>Simple in concept, but Ansible's defaults don't make it easy. It took a while
to figure out the appropriate combination of filters to make this merge work
out. Hopefully it'll save someone else some time.</p>
A couple of naming schemes for my servershttps://evaryont.me/blog/2018/10/a-couple-of-naming-schemes-for-my-servers.html2018-10-18T22:07:00+00:002021-06-30T05:58:35+00:00<p>I like naming my servers, just like I name my Pokémon. 👨💻 Not every
server gets a cute name, if they are virtualized I tend to use a much more
mechanical name. However, for my homelab I have a number of physical machines.
These machines I take care of much more, like
<a href="https://devops.stackexchange.com/questions/653/what-is-the-definition-of-cattle-not-pets">pets</a>.
And all good pets require good names.</p>
<h2 id="virtualization">Virtualization</h2>
<p>Some of these servers are part of my virtualization cluster. These are bare
metal servers and host other servers that are kinda unreal. This is the
inspiration of my first scheme: virtualization hosts are named after mythical
or other fantastical metals 🤖. Here's a list of metals my servers are named,
that I feel are distinct enough to avoid confusion, along with the source
material.</p>
<ul>
<li><strong>adamantium</strong>, from X-Men</li>
<li><strong>australium</strong>, from Team Fortress 2</li>
<li><strong>carbonite</strong>, from Star Wars</li>
<li><strong>darksteel</strong>, from Magic: The Gathering</li>
<li><strong>dilithium</strong>, from Star Trek</li>
<li><strong>etherium</strong>, from Magic: The Gathering</li>
<li><strong>kryptonite</strong>, from Superman</li>
<li><strong>metal-slime</strong>, from Dragon Quest</li>
<li><strong>mithril</strong>, from every fantasy series</li>
<li><strong>naqahdah</strong>, from Star Gate: SG-1</li>
<li><strong>octarine</strong>, from Dota 2 and Discworld</li>
<li><strong>orichalcum</strong>, from every fantasy series</li>
<li><strong>redstone</strong>, from Minecraft</li>
<li><strong>scarletite</strong>, from Final Fantasy</li>
<li><strong>starmetal</strong>, from Fallout, Elder Scrolls, and D&D</li>
<li><strong>tritanium</strong>, from Star Trek</li>
<li><strong>vibranium</strong>, from Marvel Comics</li>
</ul>
<p>That's 17 names of servers. I <em>hope</em> that would be enough to cover all of the
machines I own now (5), and into the future. If I ever get 18 or more servers
in my cluster, I have lots of problems. I shouldn't ever get to that point.</p>
<h2 id="utility-arm-single-board-computers">Utility ARM <a href="https://en.wikipedia.org/wiki/Single-board_computer">single-board computers</a></h2>
<p>On the opposite spectrum of a machine meant for the virtualization cluster, I
also have a number of utility computers around my apartment as part of the
homelab. The original ones in this group were Raspberry Pis, so I developed
this naming scheme with those in mind. Every one of these computers are named
after a pie 🥧. In particular ones more popular in the United States, where I
grew up.</p>
<ul>
<li><strong>apple-pie</strong></li>
<li><strong>blueberry-pie</strong></li>
<li><strong>caramel-pie</strong></li>
<li><strong>cherry-pie</strong></li>
<li><strong>chocolate-pie</strong></li>
<li><strong>custard-pie</strong></li>
<li><strong>grasshopper-pie</strong></li>
<li><strong>key-lime-pie</strong></li>
<li><strong>meat-pie</strong></li>
<li><strong>meringue-pie</strong></li>
<li><strong>peanut-butter-pie</strong></li>
<li><strong>pecan-pie</strong></li>
<li><strong>pumpkin-pie</strong></li>
<li><strong>raspberry-pie</strong></li>
<li><strong>turtle-pie</strong></li>
</ul>
<p>I only own 4 right now, so this list should also hopefully cover my future needs.</p>
<h2 id="what-about-you">What about you?</h2>
<p>What is your naming scheme? Make sure you have one, any one. A consistent scheme
is much easier to remember and interpret at a later date. Failing that, at least
make sure each server has it's purpose documented in a central wiki.</p>
Getting started with Vagrant and oVirt, from scratchhttps://evaryont.me/blog/2018/09/getting-started-with-vagrant-and-ovirt-from-scratch.html2018-09-17T05:33:00+00:002021-06-30T05:58:35+00:00<p>Recently, I've been playing with clustered virtualization technology.
Specifically, a fully FLOSS stack powered by <a href="https://www.ovirt.org/">oVirt</a>. I'm also a fan of
<a href="https://www.vagrantup.com/">Hashicorp's Vagrant</a> tool, and figured that the hardware powering my
virtualization cluster is going to be speedier than my laptop. Oh, how right I
was!</p>
<p>Unfortunately, it's not immediately obvious how someone would get started, given
a blank and empty cluster. So, how to you go from a freshly installed oVirt
cluster to spinning up development VMs using Vagrant? Well, by using the following
tools to automate most of the tedious work:</p>
<ul>
<li><a href="https://www.ansible.com/">Ansible</a> and the <a href="https://github.com/oVirt/ovirt-ansible-image-template">oVirt.image-template</a> role</li>
<li>The <a href="https://github.com/myoung34/vagrant-ovirt4/">ovirt4 vagrant plugin</a></li>
</ul>
<h2 id="preparing-a-template">Preparing a template</h2>
<p>There's some prep work for getting the oVirt vagrant plugin running. You need to prepare
a template for the plugin to clone. It does not use the box format, so the Vagrant Cloud
isn't much use. Normally, this would be the part that sucks a lot:</p>
<ol>
<li>Manually downloading the ISO</li>
<li>Uploading it to the cluster</li>
<li>Build a base box with all the settings</li>
<li>Run the VM and step through the installer by hand</li>
<li>Reboot the VM</li>
<li>Clean up any artifacts from the installer and prep the system to be cloned</li>
<li>Shutdown the VM and turn it into a template</li>
</ol>
<p>Whew! It was tedious enough to write this out, doing so by hand is even worse.
I did it once. Never again.</p>
<p>Thankfully, the oVirt team has a similar view (they may even agree with me) and
provide modules for Ansible to help it manage oVirt clusters. From there, they
have built roles to automate downloading a pre-existing image and creating a
template from it, along with any settings you may want to set.</p>
<p><q>But where would you get a pre-existing image?</q> you may ask. Thankfully, that's
also already handled for you! Many Linux distributions not only provide an ISO
to download, but also provide other options. For our case, a KVM image provided
by the respective distribution teams is exactly what we want. Many thanks to the
OpenStack team for <a href="https://docs.openstack.org/image-guide/obtain-images.html">maintaining a document</a> on where these images exist for various
Linux distributions, and other OSes.</p>
<h3 id="using-ansible-to-download-the-image">Using Ansible to download the image</h3>
<p>Thanks to the hard work of the distributions and the oVirt team, our task is made much
simpler. All we need is a fairly simple Ansible playbook and the <em>image-template</em> role.
My playbook looks like this:</p>
<div class="highlight"><pre class="highlight yaml"><code><span class="nn">---</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Create a template for Fedora </span><span class="m">28</span>
<span class="na">hosts</span><span class="pi">:</span> <span class="s">ovirt-node-01</span>
<span class="na">gather_facts</span><span class="pi">:</span> <span class="no">false</span>
<span class="na">vars_files</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">vars/vault_ovirt</span>
<span class="pi">-</span> <span class="s">vars/ovirt_roles</span>
<span class="na">vars</span><span class="pi">:</span>
<span class="na">qcow_url</span><span class="pi">:</span> <span class="s1">'</span><span class="s">https://download.fedoraproject.org/pub/fedora/linux/releases/28/Cloud/x86_64/images/Fedora-Cloud-Base-28-1.1.x86_64.qcow2'</span>
<span class="na">template_name</span><span class="pi">:</span> <span class="s">fedora-28</span>
<span class="na">template_operating_system</span><span class="pi">:</span> <span class="s">rhel_7x64</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">Download the ovirt CA certificate</span>
<span class="na">get_url</span><span class="pi">:</span>
<span class="na">url</span><span class="pi">:</span> <span class="s1">'</span><span class="s">{{</span><span class="nv"> </span><span class="s">engine_base_url</span><span class="nv"> </span><span class="s">}}/services/pki-resource?resource=ca-certificate&format=X509-PEM-CA'</span>
<span class="na">dest</span><span class="pi">:</span> <span class="s1">'</span><span class="s">{{</span><span class="nv"> </span><span class="s">engine_cafile</span><span class="nv"> </span><span class="s">}}'</span>
<span class="na">mode</span><span class="pi">:</span> <span class="m">0644</span>
<span class="na">validate_certs</span><span class="pi">:</span> <span class="s">False</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Download the fedora 28 sha256sums file</span>
<span class="na">get_url</span><span class="pi">:</span>
<span class="na">url</span><span class="pi">:</span> <span class="s1">'</span><span class="s">https://download.fedoraproject.org/pub/fedora/linux/releases/28/Cloud/x86_64/images/Fedora-Cloud-28-1.1-x86_64-CHECKSUM'</span>
<span class="na">dest</span><span class="pi">:</span> <span class="s1">'</span><span class="s">/tmp/fedora-28-sha256sums'</span>
<span class="na">mode</span><span class="pi">:</span> <span class="m">0644</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Pull the individual SHA256SUM from the file</span>
<span class="na">command</span><span class="pi">:</span> <span class="s">awk '/^SHA256 \({{ qcow_url|basename }}\)/ { print $4 }' '/tmp/fedora-28-sha256sums'</span>
<span class="na">register</span><span class="pi">:</span> <span class="s">awk_output</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Set image_checksum for the role</span>
<span class="na">set_fact</span><span class="pi">:</span>
<span class="na">image_checksum</span><span class="pi">:</span> <span class="s2">"</span><span class="s">sha256:{{</span><span class="nv"> </span><span class="s">awk_output.stdout</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">delete the sha256sums file</span>
<span class="na">file</span><span class="pi">:</span>
<span class="na">path</span><span class="pi">:</span> <span class="s1">'</span><span class="s">/tmp/fedora-28-sha256sums'</span>
<span class="na">state</span><span class="pi">:</span> <span class="s">absent</span>
<span class="na">roles</span><span class="pi">:</span>
<span class="pi">-</span> <span class="s">ovirt.image-template</span>
</code></pre></div>
<p>Where the files <code>vars/ovirt_roles</code> and <code>vars/vault_ovirt</code> contain a list of
variables used by the template and tasks (some of them encrypted using <a href="https://docs.ansible.com/ansible/2.5/user_guide/vault.html">Ansible
Vault</a>):</p>
<div class="highlight"><pre class="highlight yaml"><code><span class="nn">---</span>
<span class="c1"># path to download the engine self-signed ca pubkey to</span>
<span class="na">engine_cafile</span><span class="pi">:</span> <span class="s">/root/ovirt-ca.pem</span>
<span class="na">template_cluster</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Default'</span> <span class="c1"># cluster name to put templates in</span>
<span class="na">template_disk_storage</span><span class="pi">:</span> <span class="s1">'</span><span class="s">DISK_DOMAIN'</span> <span class="c1"># storage domain name to use</span>
<span class="c1"># Most Linux-es will fit within this, as a base default:</span>
<span class="na">template_memory</span><span class="pi">:</span> <span class="s">2GiB</span>
<span class="na">template_cpu</span><span class="pi">:</span> <span class="m">1</span>
<span class="na">template_disk_size</span><span class="pi">:</span> <span class="s">4GiB</span>
<span class="na">image_path</span><span class="pi">:</span> <span class="s">/var/opt</span>
<span class="na">template_nics</span><span class="pi">:</span>
<span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">nic1</span>
<span class="na">profile_name</span><span class="pi">:</span> <span class="s">ovirtmgmt</span>
<span class="na">interface</span><span class="pi">:</span> <span class="s">virtio</span>
<span class="na">template_type</span><span class="pi">:</span> <span class="s">server</span>
<span class="c1"># The base URL of ovirt-engine</span>
<span class="na">engine_base_url</span><span class="pi">:</span> <span class="s1">'</span><span class="s">https://engine.local/ovirt-engine'</span>
<span class="c1"># ...and the URL to it's API, usually just a subdirectory. </span>
<span class="na">engine_url</span><span class="pi">:</span> <span class="s1">'</span><span class="s">{{</span><span class="nv"> </span><span class="s">engine_base_url</span><span class="nv"> </span><span class="s">}}/api'</span>
<span class="c1"># The user name and password to authenticate to the engine. Recommended to</span>
<span class="c1"># encrypt these with vault!</span>
<span class="na">engine_user</span><span class="pi">:</span> <span class="s">admin@internal</span>
<span class="na">engine_password</span><span class="pi">:</span> <span class="s1">'</span><span class="s">MY_SECRET_PASSWORD'</span>
</code></pre></div>
<p>Run that playbook, and it will download the KVM image for Fedora 28, as an
example for this blog post, download the SHA256 checksum, and pass all the
details to the <em>image-template</em> role. That role will handle uploading it
to the cluster into the appropriate storage domain (aka the folder where
VM disks are stored), registering it with oVirt, and configuring the template
so that any freshly made clones have sane defaults.</p>
<h2 id="getting-vagrant-configured">Getting Vagrant configured</h2>
<p>Now that you have the base KVM image, we need to tell Vagrant to use it.
This is here the vagrant-ovirt4 gem comes in handy. Install it:</p>
<div class="highlight"><pre class="highlight plaintext"><code>vagrant plugin install vagrant-ovirt4
</code></pre></div>
<p>And then create a <code>Vagrantfile</code> to launch our development VM:</p>
<div class="highlight"><pre class="highlight ruby"><code><span class="no">Vagrant</span><span class="p">.</span><span class="nf">configure</span><span class="p">(</span><span class="s2">"2"</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">config</span><span class="o">|</span>
<span class="n">config</span><span class="p">.</span><span class="nf">vm</span><span class="p">.</span><span class="nf">box</span> <span class="o">=</span> <span class="s1">'ovirt4'</span>
<span class="n">config</span><span class="p">.</span><span class="nf">vm</span><span class="p">.</span><span class="nf">hostname</span> <span class="o">=</span> <span class="s2">"fedora-dev"</span>
<span class="n">config</span><span class="p">.</span><span class="nf">vm</span><span class="p">.</span><span class="nf">box_url</span> <span class="o">=</span> <span class="s1">'https://github.com/myoung34/vagrant-ovirt4/blob/master/example_box/dummy.box?raw=true'</span>
<span class="n">config</span><span class="p">.</span><span class="nf">vm</span><span class="p">.</span><span class="nf">network</span> <span class="ss">:private_network</span><span class="p">,</span> <span class="ss">:ovirt__network_name</span> <span class="o">=></span> <span class="s1">'ovirtmgmt'</span>
<span class="n">config</span><span class="p">.</span><span class="nf">vm</span><span class="p">.</span><span class="nf">provider</span> <span class="ss">:ovirt4</span> <span class="k">do</span> <span class="o">|</span><span class="n">ovirt</span><span class="o">|</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">url</span> <span class="o">=</span> <span class="s1">'https://engine.aether.earth/ovirt-engine/api'</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">username</span> <span class="o">=</span> <span class="s2">"admin@internal"</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">password</span> <span class="o">=</span> <span class="s1">'MY_SECRET_PASSWORD'</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">insecure</span> <span class="o">=</span> <span class="kp">true</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">debug</span> <span class="o">=</span> <span class="kp">false</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">cluster</span> <span class="o">=</span> <span class="s1">'Default'</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">template</span> <span class="o">=</span> <span class="s1">'fedora-28'</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">console</span> <span class="o">=</span> <span class="s1">'spice'</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">memory_size</span> <span class="o">=</span> <span class="s1">'768MB'</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">memory_guaranteed</span> <span class="o">=</span> <span class="s1">'768MB'</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">cpu_threads</span> <span class="o">=</span> <span class="mi">2</span>
<span class="n">ovirt</span><span class="p">.</span><span class="nf">cloud_init</span> <span class="o">=</span> <span class="o"><<</span><span class="no">EO_CLOUD_INIT</span><span class="sh">
#cloud-config
user: vagrant
chpasswd:
list: |
root:vagrant
vagrant:vagrant
expire: False
ssh_authorized_keys:
- ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzIw+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoPkcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NOTd0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcWyLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQ== vagrant insecure public key
runcmd:
- echo 'Welcome to your Vagrant-built, oVirt-managed virtual machine.' > /etc/motd
- dnf install -y ovirt-guest-agent-common
- systemctl enable --now ovirt-guest-agent.service
</span><span class="no">EO_CLOUD_INIT</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div>
<p>There are a couple of things to note about this file. Make sure the string
passed to <code>ovirt.template</code> matches the <code>template_name</code> ansible variable! Since
the playbook I use downloads generic Fedora cloud image, I need to use
<a href="https://cloud-init.io/">cloud-init</a> to configure the VM for Vagrant's use as a
<a href="https://www.vagrantup.com/docs/boxes/base.html">base box</a> and install the oVirt
guest agent.</p>
<p>Now you can run <code>vagrant up</code> and a couple of minutes later you have a
development VM! 🎉</p>
<h2 id="expanding-on-this">Expanding on this</h2>
<p>I lied a bit, earlier. My playbook doesn't look exactly like that. I've copied
and pasted it so that the role is run multiple times in the playbook, to
download additional KVM images:</p>
<ul>
<li>Ubuntu 18.04</li>
<li>CentOS 7</li>
<li>And my custom Arch Linux image, which unfortunately doesn't have cloud-init
installed so this Vagrantfile won't work. That's coming soon, I hope.</li>
</ul>
<p>Also, all of this automation is only possible through the <strong>enormous</strong> efforts
of the oVirt, Ansible, Vagrant teams and all of the community members. Open
source is awesome!</p>
tls-grab: A big update!https://evaryont.me/blog/2017/09/tls-grab-a-big-update.html2017-09-21T18:13:00+00:002021-06-30T05:58:35+00:00<p>Huzzah! A new <code>tls-grab</code> has been released. <a href="https://github.com/evaryont/tls-grab/releases/tag/2.0.0">Version
2.0.0</a> is available
now. This version has a number of improvements:</p>
<ul>
<li>It's dumber! Which is a good thing, in this case. The previous version was trying to be too clever and didn't show certificates it should have. Now
<strong><code>tls-grab</code> will show the first certificate in the chain</strong>.</li>
<li>The CLI flag parsing now uses <a href="https://github.com/spf13/pflag">pflag</a> over the stdlib's flag library. This makes <strong>the CLI more GNU-ish</strong>, which in my opinion
is more comfortable.</li>
<li>Debug logging! Not super useful for y'all, but it helps me out.</li>
<li><strong>Proper SNI support</strong>, allowing you to override the hostname provided in the handshake. <code>tls-grab</code> always supported SNI, but you couldn't connect to a server
and use a different hostname. Now you can, with <code>-h</code>/<code>--host</code>.</li>
<li><strong>Removed the <code>-server</code> flag</strong>, just specify the server's name on the command line. Even more comfortable! I wish I had done this earlier, forgetting to include
the flag each time was rather annoying...</li>
</ul>
<p>Next up is creating a man page and some OS packaging. Though that later bit is part of a larger plan, more on that another time.</p>
Hide title bars in GNOME Shellhttps://evaryont.me/blog/2017/08/link-hide-title-bars-in-gnome-shell-josh-sherman.html2017-08-26T05:24:00+00:002021-06-30T05:58:35+00:00<p>Such a lovely trick. I'm using it now. Hopefully I do this better with a fork
of the <a href="https://github.com/franglais125/no-title-bar">no-title-bar</a> extension.
<a href="https://github.com/evaryont/no-title-bar">Follow along on Github!</a></p>
The Hitman's Bodyguard, a reviewhttps://evaryont.me/blog/2017/08/the-hitman-s-bodyguard-a-review.html2017-08-18T20:32:00+00:002021-06-30T05:58:35+00:00<p>I went to the theater last night, going into this blind. Thanks to <q>T-Mobile
Tuesdays</q>, I got a ticket for this movie for cheap. I was already moderately
hopeful that the movie will do well, due to the star power of Ryan Reynolds and
Samuel L Jackson. Thankfully, I was not disappointed!</p>
<p>What I didn't expect from the movie was it's humour. (That's what I get for not
looking up movies a head of time.) I was often laughing out loud at great
moments between Reynold's and Jackson's characters. They have a wonderful
chemistry that isn't forced. The love story between Elodie Yung and Reynold's
character is less great. The sub-plot is a smart diversion from the tropes, and
I appreciate that the male character is the one that ultimately admits
culpability, but man she seems to forgive a bit too easily. Thankfully it isn't
all bad, the movie does pass the Bechdel test.</p>
<p>That being said, it's not the focus of the movie. It's a driving force, no
doubt, but the movie is centered on Reynolds and Jackson. They play well off
each other and the characters are realistic with believable backstories. The
major plot points are predictable, but it's kept from being tired and stale
by minor fresh tweaks to the <q>2 mortal enemies work together</q> plot.</p>
<p>Overall? If you are at the theater, or thinking about going, do keep this one
in mind! I definitely plan on watching it again once it is released on the
streaming services.</p>