<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Nickelblog]]></title><description><![CDATA[Nickelblog]]></description><link>https://blog.ncbt.org</link><generator>RSS for Node</generator><lastBuildDate>Wed, 09 Sep 2026 01:23:36 GMT</lastBuildDate><atom:link href="https://blog.ncbt.org/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Fixing a WiFi (actually DHCP) issue on my Mac]]></title><description><![CDATA[In general over the years, my Macs have just worked. I've seen none of the weird behavior with them that I have with Windows. However last week I encountered something new.
On startup or login, I would see the WiFi indicator pulse as it tried to get ...]]></description><link>https://blog.ncbt.org/fixing-a-wifi-actually-dhcp-issue-on-my-mac</link><guid isPermaLink="true">https://blog.ncbt.org/fixing-a-wifi-actually-dhcp-issue-on-my-mac</guid><category><![CDATA[macOS]]></category><category><![CDATA[wifi]]></category><category><![CDATA[networking]]></category><dc:creator><![CDATA[C. R. Oldham]]></dc:creator><pubDate>Mon, 17 Oct 2022 15:59:38 GMT</pubDate><content:encoded><![CDATA[<p>In general over the years, my Macs have <em>just worked</em>. I've seen none of the weird behavior with them that I have with Windows. However last week I encountered something new.</p>
<p>On startup or login, I would see the WiFi indicator pulse as it tried to get an IP address from my local DHCP server. After the requisite 30 seconds it would give up and the WiFi icon would get the <strong>!</strong> overlay indicating it had self-assigned an IP from the 169 range. All the other devices in my house had no trouble getting an IP address. If I tethered my Mac to my iPhone or iPad, it would pull an IP without any trouble. Furthermore, I also have a wired ethernet adapter on this machine and it could not get an IP either. If I assigned an IP manually to either device, network traffic would flow normally, so I knew that the WiFi was successfully associating to the AP and the wired ethernet was passing traffic as well.</p>
<p>I first suspected my network, but all the other devices didn't have any trouble. Logs for my DHCP server showed DHCPREQUEST from the Mac and DHCPOFFER from the DHCP server, but no DHCPACKs.</p>
<p>I tried the following:</p>
<ul>
<li><p>Removing the WiFi network entry from the list of known SSIDs and re-associating the Mac with the SSID (required re-entering the WiFi password)</p>
</li>
<li><p>Manually assigning an IP address to the WiFi's MAC address in my DHCP server.</p>
</li>
<li><p>Creating a new "Network Location" in the Network control panel.</p>
</li>
<li><p>Restarting the machine, as well as powering off the machine fully and doing a cold boot.</p>
</li>
<li><p>Manually removing the IP address leases for my Mac from the lease database on my DHCP server.</p>
</li>
</ul>
<p>I did not try turning off the macOS Firewall, as this is a machine managed by my work, and they have that setting locked.</p>
<p>What did finally work was to create a new administrator account and login to that account. At that point both the wireless and wired devices could pull an IP over DHCP. DHCP continued to work after restarting and logging into my original account.</p>
<p>My guess is one or more of the files macOS uses to keep track of network status had become corrupted such that the Mac would never accept a DHCP offered IP, but only for my network (which is in the 172 block). I wish I knew where those files were, as there doesn't seem to be an easier way for them to get rewritten.</p>
]]></content:encoded></item><item><title><![CDATA[Flashing the QNAP QNA-UC5G1T on a Mac]]></title><description><![CDATA[Note that since I managed to brick one adapter trying to do this I disclaim responsibility if you, dear reader, try it and fail. On the other hand, I searched the Internet high and low for anyone else that was successful flashing these adapters witho...]]></description><link>https://blog.ncbt.org/flashing-the-qnap-qna-uc5g1t-on-a-mac-ac931c904ba4</link><guid isPermaLink="true">https://blog.ncbt.org/flashing-the-qnap-qna-uc5g1t-on-a-mac-ac931c904ba4</guid><dc:creator><![CDATA[C. R. Oldham]]></dc:creator><pubDate>Sat, 07 Nov 2020 04:40:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1612748267870/cWknEjM45.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Note that since I managed to brick one adapter trying to do this I disclaim responsibility if you, dear reader, try it and fail. On the other hand, I searched the Internet high and low for anyone else that was successful flashing these adapters without a physical Windows machine. Finding nothing, it seemed wise to write up my success.</p>
<h2 id="tldr">TL;DR</h2>
<ol>
<li><p>Start Fusion 12 and a Windows 10 VM.</p>
</li>
<li><p>Download the <a target="_blank" href="https://www.qnap.com/en-us/download?model=qna-uc5g1t&amp;category=driver">drivers for the adapter</a> and the updated <a target="_blank" href="https://www.qnap.com/en-us/download?model=qna-uc5g1t&amp;category=firmware">firmware</a> onto the Windows VM</p>
</li>
<li><p>Install the drivers for the adapter in Windows before plugging it in.</p>
</li>
<li><p>Plug in the adapter. MacOS will claim it.</p>
</li>
<li><p>Unload the driver and the ECM kext bundle from a Terminal prompt:</p>
</li>
</ol>
<pre><code>sudo kextunload /<span class="hljs-keyword">System</span>/Library/DriverExtensions/AppleUserECM.dext sudo kextunload -v -c com.apple.driver.usb.cdc.ecm
</code></pre><p>Finally, attach the adapter to the VM with the Virtual Machine-&gt;Bluetooth and USB menu option in Fusion. Run the autorun.bat file as an Administrator and it should flash successfully.</p>
<h2 id="the-long-story">The long story.</h2>
<p>I am in the process of reconstructing my home lab and have several NUC-form-factor machines that don’t have any free PCIe slots, but do have USB 3.1. As I just upgraded to a Mikrotik 10 GbE switch, I would like to have faster than 1 Gb ethernet to them, so I purchased 4 <a target="_blank" href="https://www.qnap.com/en-us/product/qna-uc5g1t">QNA-UC5G1T</a> adapters. William Lam’s excellent website <a target="_blank" href="https://www.virtuallyghetto.com/2019/09/usb-native-driver-fling-for-esxi-adds-support-for-multi-gig-1g-2-5g-5g-adapter.html">had an article on them</a> indicating they should have their firmware flashed to 3.1.6 (available <a target="_blank" href="https://www.qnap.com/en-us/download?model=qna-uc5g1t&amp;category=firmware">here</a>) to get the best performance. Unfortunately the flash utility only works under Windows.</p>
<p>My first attempt at flashing the adapter under VMware Fusion 11 was a failure. I bricked the device, and QNAP was kind enough to RMA it for me and send me a new one.</p>
<p>I’ve since upgraded to Fusion 12. Starting my Windows 10 VM, I plugged the adapter in and told Fusion to attach it to the VM instead of the Mac. I was greeted with a message indicating the host machine had already claimed the device.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1612748264502/kGiWrjzjP.png" alt /></p>
<p>I found the device in the Network PrefPane and removed it, but that did not help. I realized I would have to go a little deeper.</p>
<p>MacOS’s System Information tool showed me that the driver being used for the adapter was /System/Library/DriverExtensions/AppleUserECM.dext. I unloaded this kext from the terminal</p>
<pre><code>sudo kextunload /<span class="hljs-keyword">System</span>/Library/DriverExtensions/AppleUserECM.dext
</code></pre><p>and also unloaded the ECM bundle</p>
<pre><code><span class="hljs-selector-tag">sudo</span> <span class="hljs-selector-tag">kextunload</span> <span class="hljs-selector-tag">com</span><span class="hljs-selector-class">.apple</span><span class="hljs-selector-class">.driver</span><span class="hljs-selector-class">.usb</span><span class="hljs-selector-class">.cdc</span><span class="hljs-selector-class">.ecm</span>
</code></pre><p>At that point I was able to attach the adapter to the Fusion VM. Following the instructions in the firmware zip file, I successfully flashed the adapter.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1612748266239/MQGlRBq8f.png" alt /></p>
<p><em>Originally published at <a target="_blank" href="https://blog.ncbt.org/2020/11/06/flashing-the-qnap-qna-uc5g1t-on-a-mac/">http://blog.ncbt.org</a> on November 7, 2020. Permalink: <a target="_blank" href="https://blog.ncbt.org/2020/11/06/flashing-the-qnap-qna-uc5g1t-on-a-mac/">https://blog.ncbt.org/2020/11/06/flashing-the-qnap-qna-uc5g1t-on-a-mac/</a></em></p>
]]></content:encoded></item><item><title><![CDATA[Keyboard.io’s Atreus]]></title><description><![CDATA[This might be the best keyboard I have ever used.
The Atreus. Image courtesy of keyboard.io.
There’s something about computer keyboards…even in this age of tablets and phones they remain the primary way we get significant amounts of text and code int...]]></description><link>https://blog.ncbt.org/keyboard-ios-atreus-ed6bb643bd1b</link><guid isPermaLink="true">https://blog.ncbt.org/keyboard-ios-atreus-ed6bb643bd1b</guid><dc:creator><![CDATA[C. R. Oldham]]></dc:creator><pubDate>Sat, 10 Oct 2020 02:16:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1612748274332/g4b1oxcu1.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This might be the best keyboard I have ever used.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1612748271196/U4beIaAOf.jpeg" alt="The Atreus. Image courtesy of keyboard.io." /><em>The Atreus. Image courtesy of keyboard.io.</em></p>
<p>There’s something about computer keyboards…even in this age of tablets and phones they remain the primary way we get significant amounts of text and code into computers. I’ve spent time with the original <a target="_blank" href="https://en.wikipedia.org/wiki/Buckling_spring">IBM Model M “buckling spring”</a>, the first generation <a target="_blank" href="https://en.wikipedia.org/wiki/Kinesis_(keyboard">Kinesis Advantage</a>), ThinkPad keyboards (still one of the absolute best laptop keyboards ever), the abysmal Dell Latitude d610 (stiff as a board, required significant force just to press the keys), the Apple Extended Keyboard, various MacBook Pro keyboards, as well as lots of terrible rubber-dome and membrane keyboards.</p>
<p>I’m in the minority in that I actually like the 3rd generation butterfly keyboard on the 2019 and later MacBook Pros. I like its tactile feel and the short travel of the keys.</p>
<p>When I started at SaltStack I was introduced to the mechanical keyboard community by some co-workers. Some of the above might qualify as “mechanical” keyboards, but I had no idea that there was such a <a target="_blank" href="https://deskthority.net">cult</a> <a target="_blank" href="https://geekhack.org">surrounding</a> <a target="_blank" href="https://www.reddit.com/r/MechanicalKeyboards/">them</a>.</p>
<p>I was intrigued by the <a target="_blank" href="https://ergodox.io">ErgoDox</a> and participated in the MassDrop for the unassembled keyboard, bought a soldering iron, and like a <a target="_blank" href="https://www.cbr.com/star-wars-how-are-lightsabers-made/">Jedi padawan</a>, I constructed my own keyboard.</p>
<p>I used it for about 8 or 9 months, and sold it in favor of a <a target="_blank" href="https://www.amazon.com/Filco-Majestouch-2-Tenkeyless-FKBN87M-EB2/dp/B004WOF7QM/ref=psdc_12879431_t2_B004VKUSG6">Filco Majestouch 2</a> with Cherry MX Brown switches. That was a great keyboard, and I still have it.</p>
<p>When the <a target="_blank" href="https://shop.keyboard.io">Keyboard.io</a> folks initiated their Kickstarter for the <a target="_blank" href="https://shop.keyboard.io/products/model-01-keyboard?variant=30996744405065">Model 01</a>, I was completely hooked. I ended up getting two of those (one for work, one for home). The learning curve was surprisingly steep, but I grew to really appreciate the palm buttons.</p>
<p>Through a fortunate happenstance another co-worker participated in the kickstarter for Keyboard.io’s latest creation, the <a target="_blank" href="https://shop.keyboard.io/collections/keyboardio-atreus/products/keyboardio-atreus">Atreus</a>. He had irreconcilable differences with it, and was willing to sell it to me. I’ve spent the last few days with it, tweaking the layout and getting used to it, and I think it might be the best keyboard I have ever owned.</p>
<p>This unit came with Kailh BOX Brown switches (<a target="_blank" href="https://www.keyboardco.com/blog/index.php/2017/11/an-introduction-to-kailh-switches-including-speed-box/">here’s a comparison article on Kailh switches</a>), these are tactile but non-clicky like CherryMX Brown switches, which I had on my Majestouch and ErgoDox. I like these much more, however. They seem “tighter” somehow, there’s no discernible wiggle in the keycaps. Actuation force is slightly less than my other keyboards. My typing speed on the alpha characters actually increased over my Model 01.</p>
<p>I had been eyeing the Atreus for a while but was highly concerned that I would not be able to get used to the lack of a number row at the top of the keyboard. Losing real function and Escape keys to the Apple TouchBar has been a sore spot. I took a closer look at the layout and realized there were plenty of keys available to use for layer shifting.</p>
<p>Paradoxically I’ve noticed that fewer keys enables more accuracy for me. I think it’s because the keyboard is so small my fingers don’t get “lost” as easily.</p>
<p>It will take a while to get used to my custom layout. I include an image below for anyone who finds this article and is curious about how others have setup their Atreus.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1612748272740/DDEqub0T2.png" alt /></p>
<p>The above is from <a target="_blank" href="https://docs.google.com/spreadsheets/d/1_d-ymDszaH8G2PaNho7XyRnFGL-c4ibGB2b79jyoeU4/edit?usp=sharing">this Google Sheet</a>. Feel free to copy if you want to make your own layout. Many thanks to Github user <a target="_blank" href="https://github.com/mattmc3">mattmc3</a> who created that sheet and posted it in <a target="_blank" href="https://github.com/keyboardio/Kaleidoscope/pull/706#issuecomment-628370192">this PR discussion</a> on adding Atreus layouts that are similar to the Model 01's.</p>
<p><em>Originally published at <a target="_blank" href="https://blog.ncbt.org/2020/10/09/keyboardio-atreus/">http://blog.ncbt.org</a> on October 10, 2020. Permalink: <a target="_blank" href="https://blog.ncbt.org/2020/10/09/keyboardio-atreus/">https://blog.ncbt.org/2020/10/09/keyboardio-atreus/</a></em></p>
]]></content:encoded></item><item><title><![CDATA[LXC on OpenSUSE Tumbleweed]]></title><description><![CDATA[I’ve been enjoying OpenSUSE’s Tumbleweed distribution. It has all of the benefits of a rolling release like Arch without some of the instability. Unfortunately, my standby for lots of testing, LXC, doesn’t quite work out of the box. You can retrieve ...]]></description><link>https://blog.ncbt.org/lxc-on-opensuse-tumbleweed-4006a7c70589</link><guid isPermaLink="true">https://blog.ncbt.org/lxc-on-opensuse-tumbleweed-4006a7c70589</guid><dc:creator><![CDATA[C. R. Oldham]]></dc:creator><pubDate>Tue, 16 Feb 2016 20:14:18 GMT</pubDate><content:encoded><![CDATA[<p>I’ve been enjoying OpenSUSE’s Tumbleweed distribution. It has all of the benefits of a rolling release like Arch without some of the instability. Unfortunately, my standby for lots of testing, LXC, doesn’t quite work out of the box. You can retrieve images with lxc-create -n name -t download but the images won’t start.</p>
<p>Extensive Googling did not reveal the specific reason for this, but I finally figured it out and decided to document it here.</p>
<p>SUSE has <strong>excellent</strong> support for libvirt, and libvirt has rapidly improving support for LXC. So, we’ll install the libvirt suite alongside LXC. A huge advantage here is that we’re going to get a single bridge (br0) that will work for libvirt and lxc. One frustration point I’ve had with LXC on other platforms is I’d often end up with an lxcbr0 alongside other bridges for other container/virtualization options.</p>
<p>To install the tools you need, it’s quickest to start with Yast. Start Yast as root, select <em>Virtualization</em> in the left pane, then <em>Install Hypervisor and Tools</em>. In the next dialog, pick just <em>KVM Tools</em> and <em>libvirt LXC daemon</em> — that’s all you need.</p>
<pre><code>┌───────────────────────────────────────────────────────────┐
│                                                           │
│ ┌Choose Hypervisor(s) to <span class="hljs-keyword">install</span>────────────────────────┐ │
│ │<span class="hljs-keyword">Server</span>: Minimal <span class="hljs-keyword">system</span> <span class="hljs-keyword">to</span> <span class="hljs-keyword">get</span> a running Hypervisor     │ │
│ │Tools: Configure, manage <span class="hljs-keyword">and</span> monitor <span class="hljs-keyword">virtual</span> machines  │ │
│ └───────────────────────────────────────────────────────┘ │
│                                                           │
│ ┌Xen Hypervisor─────────────────────────────────────────┐ │
│ │[ ] Xen <span class="hljs-keyword">server</span> [ ] Xen tools                           │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌KVM Hypervisor─────────────────────────────────────────┐ │
│ │[ ] KVM <span class="hljs-keyword">server</span> [x] KVM tools                           │ │
│ └───────────────────────────────────────────────────────┘ │
│ ┌libvirt LXC containers─────────────────────────────────┐ │
│ │[x] libvirt LXC daemon                                 │ │
│ └───────────────────────────────────────────────────────┘ │
│                                                           │
│ [<span class="hljs-keyword">Accept</span>] [<span class="hljs-keyword">Cancel</span>]                                         │
└───────────────────────────────────────────────────────────┘
</code></pre><p>Then make sure you have lxc and apparmor installed with <em>zypper in lxc</em>.</p>
<pre><code><span class="hljs-comment"># zypper in lxc apparmor apparmor-utils apparmor-abstractions</span>
</code></pre><p>Next, we need to make sure that the apparmor profile for lxc containers is loaded</p>
<pre><code><span class="hljs-comment"># apparmor_parser /etc/apparmor.d/lxc-containers</span>
</code></pre><p>If you look in <em>/etc/lxc/default.conf</em>, you’ll see that there is no network type established. Things will work better if we add a more sane configuration there:</p>
<pre><code><span class="hljs-comment"># Network configuration</span>
<span class="hljs-attr">lxc.network.type</span> = veth
<span class="hljs-attr">lxc.network.link</span> = br0
<span class="hljs-attr">lxc.network.flags</span> = up
</code></pre><p>Now pull an image — let’s use Ubuntu 14.04:</p>
<pre><code>lxc-<span class="hljs-keyword">create</span> -B btrfs -n ubuntu -t download

Setting up the GPG keyring
Downloading the image <span class="hljs-keyword">index</span>

&lt;<span class="hljs-keyword">list</span> <span class="hljs-keyword">of</span> distros omitted&gt;

Distribution: ubuntu
<span class="hljs-keyword">Release</span>: trusty
Architecture: amd64

<span class="hljs-keyword">Using</span> image <span class="hljs-keyword">from</span> <span class="hljs-keyword">local</span> <span class="hljs-keyword">cache</span>
Unpacking the rootfs

— -
You just created an Ubuntu <span class="hljs-keyword">container</span> (<span class="hljs-keyword">release</span>=trusty, arch=amd64, variant=<span class="hljs-keyword">default</span>)

<span class="hljs-keyword">To</span> <span class="hljs-keyword">enable</span> sshd, run: apt-<span class="hljs-keyword">get</span> <span class="hljs-keyword">install</span> openssh-<span class="hljs-keyword">server</span>

<span class="hljs-keyword">For</span> <span class="hljs-keyword">security</span> reason, <span class="hljs-keyword">container</span> images ship <span class="hljs-keyword">without</span> <span class="hljs-keyword">user</span> accounts <span class="hljs-keyword">and</span> <span class="hljs-keyword">without</span> a root password.

<span class="hljs-keyword">Use</span> lxc-attach <span class="hljs-keyword">or</span> chroot directly <span class="hljs-keyword">into</span> the rootfs <span class="hljs-keyword">to</span> <span class="hljs-keyword">set</span> a root <span class="hljs-keyword">password</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">create</span> <span class="hljs-keyword">user</span> accounts.
</code></pre><p>Let’s try to start and attach to it.</p>
<pre><code>lxc-<span class="hljs-keyword">start</span> -n ubuntu -F
lxc-<span class="hljs-keyword">start</span>: utils.c: open_without_symlink: <span class="hljs-number">1626</span> <span class="hljs-keyword">No</span> such <span class="hljs-keyword">file</span> <span class="hljs-keyword">or</span> <span class="hljs-keyword">directory</span> — <span class="hljs-keyword">Error</span> examining fuse <span class="hljs-keyword">in</span> /usr/lib64/lxc/rootfs/<span class="hljs-keyword">sys</span>/fs/fuse/connections
lxc-<span class="hljs-keyword">start</span>: lsm/apparmor.c: apparmor_process_label_set: <span class="hljs-number">169</span> <span class="hljs-keyword">If</span> you really want <span class="hljs-keyword">to</span> <span class="hljs-keyword">start</span> this <span class="hljs-keyword">container</span>, <span class="hljs-keyword">set</span>
lxc-<span class="hljs-keyword">start</span>: lsm/apparmor.c: apparmor_process_label_set: <span class="hljs-number">170</span> lxc.aa_allow_incomplete = <span class="hljs-number">1</span>
lxc-<span class="hljs-keyword">start</span>: lsm/apparmor.c: apparmor_process_label_set: <span class="hljs-number">171</span> <span class="hljs-keyword">in</span> your <span class="hljs-keyword">container</span> configuration <span class="hljs-keyword">file</span>
lxc-<span class="hljs-keyword">start</span>: sync.c: __sync_wait: <span class="hljs-number">51</span> invalid <span class="hljs-keyword">sequence</span> <span class="hljs-built_in">number</span> <span class="hljs-number">1.</span> expected <span class="hljs-number">4</span>
lxc-<span class="hljs-keyword">start</span>: start.c: __lxc_start: <span class="hljs-number">1192</span> <span class="hljs-keyword">failed</span> <span class="hljs-keyword">to</span> spawn ‘ubuntu’
lxc-<span class="hljs-keyword">start</span>: lxc_start.c: <span class="hljs-keyword">main</span>: <span class="hljs-number">344</span> The <span class="hljs-keyword">container</span> <span class="hljs-keyword">failed</span> <span class="hljs-keyword">to</span> start.
lxc-<span class="hljs-keyword">start</span>: lxc_start.c: <span class="hljs-keyword">main</span>: <span class="hljs-number">348</span> Additional information can be obtained <span class="hljs-keyword">by</span> setting the — <span class="hljs-keyword">logfile</span> <span class="hljs-keyword">and</span> — logpriority options.
</code></pre><p>Ooh. Ouch. What is <em>aa_allow_incomplete</em>?</p>
<pre><code>man <span class="hljs-number">5</span> lxc.container.conf

[…]

lxc.aa_allow_incomplete

Apparmor profiles are pathname based. Therefore many file restrictions require mount restrictions <span class="hljs-keyword">to</span> be effective against a determined attacker. However, these mount restrictions are <span class="hljs-keyword">not</span> yet implemented <span class="hljs-keyword">in</span> the upstream kernel. <span class="hljs-keyword">Without</span> the mount restrictions, the apparmor profiles still protect against accidental damage.

<span class="hljs-keyword">If</span> this flag <span class="hljs-keyword">is</span> <span class="hljs-number">0</span> (<span class="hljs-keyword">default</span>), <span class="hljs-keyword">then</span> the container will <span class="hljs-keyword">not</span> be started <span class="hljs-keyword">if</span> the kernel lacks the apparmor mount features, so that a regression <span class="hljs-keyword">after</span> a kernel upgrade will be detected. <span class="hljs-keyword">To</span> <span class="hljs-keyword">start</span> the container under partial apparmor protection, <span class="hljs-keyword">set</span> this flag <span class="hljs-keyword">to</span> <span class="hljs-number">1.</span>

[…]
</code></pre><p>Well, I’m OK with that, since I use my containers basically for testing. You may not be, if you need more security inside your containers.
So let’s add that to <em>/etc/lxc/default.conf</em> and try again.</p>
<pre><code><span class="hljs-comment"># lxc-start -n ubuntu -F</span>
<span class="hljs-string">…</span> 
<span class="hljs-string">Ubuntu</span> <span class="hljs-number">14.04</span><span class="hljs-number">.3</span> <span class="hljs-string">LTS</span> <span class="hljs-string">ubuntu</span> <span class="hljs-string">console</span>

<span class="hljs-attr">ubuntu login:</span> <span class="hljs-string">_</span>
</code></pre><p>QED.</p>
<p>Note that this setup attaches the machine’s primary ethernet adapter to the
bridge, and adapters inside subsequent containers to the same bridge. This means the container will get an IP address via DHCP on the same network as the host. Also if you run VMware Workstation or Fusion, VMware will complain that a VM is placing a network adapter in promiscuous mode and will ask for administrator credentials.</p>
<p>EDIT: regarding admin credentials when Fusion VMs try to set network adapters into promiscuous mode, I had forgotten there is a checkbox in later Fusion versions (I’m on 8.1.0). Go to the Preferences dialog in Fusion, select the Network pref sheet, and in the bottom left corner there is a checkbox to turn off the credentials requirement. Note this does introduce the possibility that a malicious VM could monitor all network traffic to and from your host machine.</p>
<p>Resources:</p>
<p><a target="_blank" href="https://www.berrange.com/posts/2011/09/27/getting-started-with-lxc-using-libvirt/">https://www.berrange.com/posts/2011/09/27/getting-started-with-lxc-using-libvirt/</a> (a little dated)
<a target="_blank" href="http://blog.scottlowe.org/2013/11/27/linux-containers-via-lxc-and-libvirt/">http://blog.scottlowe.org/2013/11/27/linux-containers-via-lxc-and-libvirt/</a>
<a target="_blank" href="https://libvirt.org/drvlxc.html">https://libvirt.org/drvlxc.html</a>
<a target="_blank" href="https://forums.opensuse.org/showthread.php/511258-Cannot-boot-LXC-in-leap-42-1">https://forums.opensuse.org/showthread.php/511258-Cannot-boot-LXC-in-leap-42-1</a></p>
]]></content:encoded></item><item><title><![CDATA[Mitigating GHOST with Salt]]></title><description><![CDATA[Using SaltStack to recover from CVE-2015–0235 (Qualys Security Advisory, GHOST: glibc gethostbyname buffer overflow)
Most of us sysadmin types were pounded with this announcement this morning. The GHOST vulnerability is worth patching against—most Li...]]></description><link>https://blog.ncbt.org/mitigating-ghost-with-salt-2a28b6eb9e4b</link><guid isPermaLink="true">https://blog.ncbt.org/mitigating-ghost-with-salt-2a28b6eb9e4b</guid><dc:creator><![CDATA[C. R. Oldham]]></dc:creator><pubDate>Tue, 27 Jan 2015 21:09:28 GMT</pubDate><content:encoded><![CDATA[<p>Using SaltStack to recover from CVE-2015–0235 (Qualys Security Advisory, GHOST: glibc gethostbyname buffer overflow)</p>
<p>Most of us sysadmin types were pounded with <a target="_blank" href="http://www.openwall.com/lists/oss-security/2015/01/27/9">this announcement</a> this morning. The GHOST vulnerability is worth patching against—most Linux distros have already released patches—but it’s useful to know if your machines are vulnerable, or if after patching, <strong><em>the patch was successful</em></strong>.</p>
<p>The canonical way to test for the vulnerability is with a short C program:</p>
<pre><code><span class="hljs-comment">/* ghost.c */</span>
<span class="hljs-comment">/* Code taken from CVE announcement */</span>
<span class="hljs-comment">/* See
[http://www.openwall.com/lists/oss-security/2015/01/27/9](http://www.openwall.com/lists/oss-security/2015/01/27/9)
*/</span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;netdb.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdio.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;stdlib.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;string.h&gt;</span></span>
<span class="hljs-meta">#<span class="hljs-meta-keyword">include</span> <span class="hljs-meta-string">&lt;errno.h&gt;</span></span>

<span class="hljs-meta">#<span class="hljs-meta-keyword">define</span> CANARY <span class="hljs-meta-string">"in_the_coal_mine"</span></span>

<span class="hljs-class"><span class="hljs-keyword">struct</span> {</span>
    <span class="hljs-keyword">char</span> buffer[<span class="hljs-number">1024</span>];
    <span class="hljs-keyword">char</span> canary[<span class="hljs-keyword">sizeof</span>(CANARY)];
} temp = { <span class="hljs-string">"buffer"</span>, CANARY };

<span class="hljs-function"><span class="hljs-keyword">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">hostent</span> <span class="hljs-title">resbuf</span>;</span>
    <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">hostent</span> *<span class="hljs-title">result</span>;</span>
    <span class="hljs-keyword">int</span> herrno;
    <span class="hljs-keyword">int</span> retval;

<span class="hljs-comment">/*** strlen (name) = size_needed — sizeof (*host_addr) — sizeof (*h_addr_ptrs) — 1; ***/</span>

    <span class="hljs-keyword">size_t</span> len = <span class="hljs-keyword">sizeof</span>(temp.buffer) 
                 - <span class="hljs-number">16</span>*<span class="hljs-keyword">sizeof</span>(<span class="hljs-keyword">unsigned</span> <span class="hljs-keyword">char</span>) 
                 — <span class="hljs-number">2</span>*<span class="hljs-keyword">sizeof</span>(<span class="hljs-keyword">char</span> *) — <span class="hljs-number">1</span>;
    <span class="hljs-keyword">char</span> name[<span class="hljs-keyword">sizeof</span>(temp.buffer)];

    <span class="hljs-built_in">memset</span>(name, <span class="hljs-string">'0'</span>, len);
    name[len] = <span class="hljs-string">'\0'</span>;
    retval = gethostbyname_r(name, &amp;resbuf, temp.buffer,
                 <span class="hljs-keyword">sizeof</span>(temp.buffer), &amp;result, &amp;herrno);
    <span class="hljs-keyword">if</span> (<span class="hljs-built_in">strcmp</span>(temp.canary, CANARY) != <span class="hljs-number">0</span>) {
        <span class="hljs-built_in">puts</span>(<span class="hljs-string">"vulnerable"</span>);
        <span class="hljs-built_in">exit</span>(EXIT_FAILURE);
    }

    <span class="hljs-keyword">if</span> (retval == ERANGE) {
        <span class="hljs-built_in">puts</span>(<span class="hljs-string">"not vulnerable"</span>);
        <span class="hljs-built_in">exit</span>(EXIT_SUCCESS);
    }
    <span class="hljs-built_in">puts</span>(<span class="hljs-string">"test aborted: should not happen"</span>);
    <span class="hljs-built_in">exit</span>(EXIT_FAILURE);
}
</code></pre><p>Which can then be saved to a file “ghost.c” and compiled on most Linux machines with</p>
<pre><code><span class="hljs-selector-tag">gcc</span> <span class="hljs-selector-tag">ghost</span><span class="hljs-selector-class">.c</span> <span class="hljs-selector-tag">-o</span> <span class="hljs-selector-tag">ghost</span>
</code></pre><p>Running it with ‘./ghost’ should produce either “not vulnerable” with an exit code of 0, or “vulnerable” with an exit code of 1.</p>
<p>But let’s say you have 1000 machines, all with running salt-minions. How can we test for this on all of them?</p>
<p>We’ll assume first that they are all the same distro as your Salt master. Yes, I know that’s a degenerate case, but to start with let’s just consider the easy route.</p>
<p>First, save <em>ghost.c</em> to a directory on your master and compile it as describe above. Then put the executable in your <em>/srv/salt</em> directory (or wherever your file_roots points). Put this sls file in the same directory:</p>
<pre><code><span class="hljs-comment"># /srv/salt/ghosttest.sls</span>

<span class="hljs-string">/tmp/ghost:</span>
  <span class="hljs-attr">file.managed:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">source:</span> <span class="hljs-string">salt://ghost</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">owner:</span> <span class="hljs-string">root</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">mode:</span> <span class="hljs-string">'0644'</span>

<span class="hljs-attr">runghost:</span>
  <span class="hljs-attr">cmd.run:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">/tmp/ghost</span>
</code></pre><p>Now you can fire off this on all your minions with</p>
<pre><code><span class="hljs-selector-tag">salt</span> \* <span class="hljs-selector-tag">state</span><span class="hljs-selector-class">.sls</span> <span class="hljs-selector-tag">ghosttest</span>
</code></pre><p>Because Salt will treat the result of cmd.run as a failure if the executed command returns a non-zero exit status, all vulnerable minions will show “FAILED”. Successfully patched minions will show “SUCCESS.”</p>
<p>Note that all vulnerable services will need to be restarted after a patch (or the affected system will need to be rebooted). Salt can help with this if, in fact, you need to restart individual services rather than restart an entire box.</p>
<p>There are a couple of odd results you can get back from this. First, on one of my machines I got</p>
<pre><code><span class="hljs-attr">w01:</span>
<span class="hljs-string">—————</span>
       <span class="hljs-attr">ID:</span> <span class="hljs-string">/tmp/ghost</span>
 <span class="hljs-attr">Function:</span> <span class="hljs-string">file.managed</span>
   <span class="hljs-attr">Result:</span> <span class="hljs-literal">True</span>
  <span class="hljs-attr">Comment:</span> <span class="hljs-string">File</span> <span class="hljs-string">/tmp/ghost</span> <span class="hljs-string">is</span> <span class="hljs-string">in</span> <span class="hljs-string">the</span> <span class="hljs-string">correct</span> <span class="hljs-string">state</span>
  <span class="hljs-attr">Started:</span> <span class="hljs-number">11</span><span class="hljs-string">:06:30.632664</span>
 <span class="hljs-attr">Duration:</span> <span class="hljs-number">779.398</span> <span class="hljs-string">ms</span>
  <span class="hljs-attr">Changes:</span>
<span class="hljs-string">—————</span>
       <span class="hljs-attr">ID:</span> <span class="hljs-string">runghost</span>
 <span class="hljs-attr">Function:</span> <span class="hljs-string">cmd.run</span>
     <span class="hljs-attr">Name:</span> <span class="hljs-string">/tmp/ghost</span>
   <span class="hljs-attr">Result:</span> <span class="hljs-literal">False</span>
  <span class="hljs-attr">Comment:</span> <span class="hljs-string">Command</span> <span class="hljs-string">“/tmp/ghost”</span> <span class="hljs-string">run</span>
  <span class="hljs-attr">Started:</span> <span class="hljs-number">11</span><span class="hljs-string">:06:31.412444</span>
 <span class="hljs-attr">Duration:</span> <span class="hljs-number">60.247</span> <span class="hljs-string">ms</span>
  <span class="hljs-attr">Changes:</span>
           <span class="hljs-string">—————</span>
           <span class="hljs-attr">pid:</span>
               <span class="hljs-number">28508</span>
           <span class="hljs-attr">retcode:</span>
               <span class="hljs-number">127</span>
           <span class="hljs-attr">stderr:</span>
               <span class="hljs-string">/bin/bash:</span> <span class="hljs-string">/tmp/ghost:</span> <span class="hljs-literal">No</span> <span class="hljs-string">such</span> <span class="hljs-string">file</span> <span class="hljs-string">or</span> <span class="hljs-string">directory</span>
           <span class="hljs-attr">stdout:</span>
</code></pre><p>Salt told me the file was present and in the correct state, but bash said “No such file or directory.” Bug in Salt, right? I mean, that’s happened before.</p>
<p>No, not today! If I logged into the machine and ran the executable by hand I got the same message. In this case it was because all my other machines are 64-bit, but this one is 32-bit, and the test executable was linked against the 64-bit glibc. So the message was correct, but confusing since the missing file is not the executable but the library.</p>
<p>Let’s fix this. I happen to have development tools installed on that box, so let’s build a 32-bit compiled version there, put it back on the master, and also modify the sls file so the correct executable will get copied to 64 or 32 bit machines.</p>
<pre><code><span class="hljs-string">/tmp/ghost.c:</span>
  <span class="hljs-attr">file.managed:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">source:</span> <span class="hljs-string">salt://ghost.c</span>

<span class="hljs-attr">gcc ghost.c -o ghost:</span>
  <span class="hljs-attr">cmd.run:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">user:</span> <span class="hljs-string">root</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">cwd:</span> <span class="hljs-string">/tmp</span>

<span class="hljs-comment"># Note this will not work unless file_recv is 'True' in the</span>
<span class="hljs-comment"># salt-master config</span>
<span class="hljs-attr">cp.push:</span>
  <span class="hljs-attr">module.run:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">path:</span> <span class="hljs-string">/tmp/ghost</span>
</code></pre><p>Then, run this sls and copy the file out of the cache directory (see <a target="_blank" href="http://docs.saltstack.com/en/latest/ref/modules/all/salt.modules.cp.html#salt.modules.cp.push">cp.push</a> documentation)</p>
<pre><code><span class="hljs-meta"># salt <span class="hljs-meta-string">&lt;32bitminion&gt; state.sls ghostbuild</span></span>
<span class="hljs-meta"># cp /var/cache/salt/master/minions/<span class="hljs-meta-string">&lt;32bitminion&gt; /tmp/ghost \</span></span>
     /srv/salt/ghost32
</code></pre><p>(replace <strong><em>32bitminion</em></strong> with the minion_id where you did the build)</p>
<p>Now change your ghostcheck.sls to look like this</p>
<pre><code><span class="hljs-string">/tmp/ghost:</span>
  <span class="hljs-attr">file.managed:</span>
{<span class="hljs-string">%</span> <span class="hljs-string">if</span> <span class="hljs-string">grains</span>[<span class="hljs-string">'osarch'</span>] <span class="hljs-string">==</span> <span class="hljs-string">'i386'</span> <span class="hljs-string">%</span>}
  <span class="hljs-string">—</span> <span class="hljs-attr">source:</span> <span class="hljs-string">salt://ghost32</span>
{<span class="hljs-string">%</span> <span class="hljs-string">else</span> <span class="hljs-string">%</span>}
  <span class="hljs-string">—</span> <span class="hljs-attr">source:</span> <span class="hljs-string">salt://ghost</span>
{<span class="hljs-string">%</span> <span class="hljs-string">endif</span> <span class="hljs-string">%</span>}
  <span class="hljs-string">—</span> <span class="hljs-attr">owner:</span> <span class="hljs-string">root</span>
  <span class="hljs-string">—</span> <span class="hljs-attr">mode:</span> <span class="hljs-string">'0700'</span>

<span class="hljs-attr">runghost:</span>
  <span class="hljs-attr">cmd.run:</span>
    <span class="hljs-string">—</span> <span class="hljs-attr">name:</span> <span class="hljs-string">/tmp/ghost</span>
    <span class="hljs-string">—</span> <span class="hljs-attr">cwd:</span> <span class="hljs-string">/tmp</span>
    <span class="hljs-string">—</span> <span class="hljs-attr">user:</span> <span class="hljs-string">root</span>
    <span class="hljs-string">—</span> <span class="hljs-attr">require:</span>
      <span class="hljs-string">—</span> <span class="hljs-attr">file:</span> <span class="hljs-string">/tmp/ghost</span>
</code></pre><p>Now I get accurate results from all my minions, 32-bit or 64-bit.</p>
<p>Obviously the simpler way to do this would be to build and run ghost.c on all minions, but many folks don’t keep gcc and friends on things like webservers.</p>
<p>Finally, if you don’t want to reboot all your machines, you just want to restart affected services, you can do the following (props to the <a target="_blank" href="https://news.ycombinator.com/item?id=8953992">hackernews discussion</a> for this snippet)</p>
<pre><code><span class="hljs-attribute">salt</span> \* cmd.run 'netstat -lnp | grep -e <span class="hljs-string">"\(tcp.*LISTEN\|udp\)"</span> | cut -d / -f <span class="hljs-number">2</span>- | sort -u'
</code></pre><p>which will tell you which services on which machines need to be restarted. Then for each of these services and machines you can say</p>
<pre><code>salt <span class="hljs-tag">&lt;<span class="hljs-name">affectedminion</span>&gt;</span> service.restart <span class="hljs-tag">&lt;<span class="hljs-name">affectedservice</span>&gt;</span>
</code></pre><p>Finally, shameless plug for the <a target="_blank" href="http://saltstack.com">awesome company</a> I work for—if you want to learn more about Salt, <a target="_blank" href="http://saltconf.com">**SaltConf</a>** would be a great place to do it! March 3–5, 2015, Grand America Hotel, Salt Lake City.</p>
]]></content:encoded></item><item><title><![CDATA[Removing WireLurker with Salt · Nickelblog]]></title><description><![CDATA[Claud Xiao from Palo Alto Networks has been in touch with me and I updated this script with his recommendations.
Please note I don’t plan to add Windows support, the anti-malware vendors do a great job maintaining signatures and removing stuff like t...]]></description><link>https://blog.ncbt.org/removing-wirelurker-with-salt-nickelblog-f3759e494c8c</link><guid isPermaLink="true">https://blog.ncbt.org/removing-wirelurker-with-salt-nickelblog-f3759e494c8c</guid><dc:creator><![CDATA[C. R. Oldham]]></dc:creator><pubDate>Sun, 25 Jan 2015 01:42:49 GMT</pubDate><content:encoded><![CDATA[<p>Claud Xiao from Palo Alto Networks has been in touch with me and I updated this script with his recommendations.</p>
<p>Please note I don’t plan to add Windows support, the anti-malware vendors do a great job maintaining signatures and removing stuff like this.</p>
<p>The news hit the fan early yesterday morning—lots of Apple haters were giddy with excitement at the revelation of the WireLurker trojan that infects iOS devices via their host Macintosh when the devices are plugged in via USB.</p>
<p>Publicized by Palo Alto Networks, details on <a target="_blank" href="http://researchcenter.paloaltonetworks.com/2014/11/wirelurker-new-era-os-x-ios-malware/">WireLurker</a> can be found at their website. Helpfully, Palo Alto also <a target="_blank" href="https://github.com/PaloAltoNetworks-BD/WireLurkerDetector">published a Python script</a> that can detect the infection. Removing the infection from an iOS device is a matter of backing up the device, erasing it completely by restoring it to factory defaults, and then restoring the backup. Props to Topher Kessler of MacIssues for <a target="_blank" href="http://www.macissues.com/2014/11/06/faq-on-how-to-detect-and-remove-wirelurker-from-os-x-and-ios/">documenting this process</a></p>
<p>I took Palo Alto’s script and modified it so it can either be run from the command line or as a Salt execution module. From the command line:</p>
<pre><code><span class="hljs-selector-tag">python</span> <span class="hljs-selector-tag">wireunlurk</span><span class="hljs-selector-class">.py</span>
</code></pre><p>will scan your Mac for signs of WireLurker. -h for help (not much there) or -c for “clean”.</p>
<p>wireunlurk.py will move any infected files to a dynamically-created directory in /tmp that starts with wireunlurk_bk.</p>
<p>If you want to run this in your Salt infrastructure, put wireunlurk.py in /srv/salt/_modules (or equivalent directory if you have customized it) and run the following on your Salt master:</p>
<pre><code><span class="hljs-attribute">salt</span> -G <span class="hljs-string">'os:MacOS'</span> saltutil.sync_modules salt -G<span class="hljs-string">'os:MacOS'</span> wireunlurk.scan
</code></pre><p>Add clean=True if you want to clean up the infection as well.</p>
<p>This saved me a significant amount of time scanning my Macs just at home—we have 7 Macs on my home network and rather than ssh’ing to each one, or using a tool like <a target="_blank" href="https://code.google.com/p/csshx/">csshX</a>, as soon as I got the script running and ‘saltified’ I executed the above command and could sleep with peace of mind knowing none of our devices were infected.</p>
<p>You can find my modified script here: <a target="_blank" href="https://github.com/saltstack/salt-contrib/tree/master/modules/wireunlurk">https://github.com/saltstack/salt-contrib/tree/master/modules/wireunlurk</a></p>
]]></content:encoded></item><item><title><![CDATA[Installing Mac OS X 10.9.2 with Salt. · Nickelblog]]></title><description><![CDATA[Several weeks ago I installed Salt on all my Macs. I have 7 currently, two of which cannot run Mavericks and are stuck at Lion (10.7). I know you can configure them to install updates automatically, but a couple of these are development machines and ...]]></description><link>https://blog.ncbt.org/installing-mac-os-x-10-9-2-with-salt-nickelblog-72b24fdd4edb</link><guid isPermaLink="true">https://blog.ncbt.org/installing-mac-os-x-10-9-2-with-salt-nickelblog-72b24fdd4edb</guid><dc:creator><![CDATA[C. R. Oldham]]></dc:creator><pubDate>Sun, 25 Jan 2015 01:41:50 GMT</pubDate><content:encoded><![CDATA[<p>Several weeks ago I installed Salt on all my Macs. I have 7 currently, two of which cannot run Mavericks and are stuck at Lion (10.7). I know you can configure them to install updates automatically, but a couple of these are development machines and one is a server, and I just don’t like the idea of having them install updates and reboot whenever they feel like it.</p>
<p>Furthermore, the 10.9.2 release contains an important fix—the so called ‘gotofail’ security vulnerablity, fully documented here: <a target="_blank" href="https://www.imperialviolet.org/2014/02/22/applebug.html">https://www.imperialviolet.org/2014/02/22/applebug.html</a>. You can check to see if you are vulnerable with <a target="_blank" href="http://gotofail.com/">http://gotofail.com</a>.</p>
<p>I was dreading manually going to each of these machines and running Software Update, waiting for it to figure out if there were really packages to install (why does that take so long, anyway?), and doing the click dance to get it installed.</p>
<p>Enter Salt.</p>
<p>(full disclaimer—I do work for <a target="_blank" href="http://www.saltstack.com/">SaltStack</a>, the company behind open source Salt)</p>
<p>Using Salt turned probably an hour of updating into 3 commands executed at my leisure. Note, I run my salt-master on Ubuntu in a Fusion VM on my Mac Mini server. After downloading the combo updater from <a target="_blank" href="http://support.apple.com/downloads/DL1725/en_US/OSXUpd10.9.2.dmg">Apple’s support site</a>, I mounted it and extracted the .pkg file from it, then copied that file to my Salt master’s /srv directory (/srv/salt/OSXUpd10.9.2.pkg).</p>
<p>Then:</p>
<pre><code><span class="hljs-attribute">salt</span>-master# salt -C 'G@os:MacOS and G@osrelease:<span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">1</span>' cp.get_file \ OSXUpd<span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">2</span>.pkg /tmp/OSXUpd<span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">2</span>.pkg salt-master# salt -C 'G@os:MacOS and G@osrelease:<span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">1</span>' cmd.run \ 'installer -pkg /tmp/OSXUpd<span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">2</span>.pkg -target /' salt-master# salt -C 'G@os:MacOS and G@osrelease:<span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">1</span>' cmd.run \ 'shutdown -r now'
</code></pre><p>So what the above says is</p>
<ol>
<li><p>For all MacOS machines that are on 10.9.1, copy the package file to the /tmp directory on the machine (thus avoiding my Lion machines). The -C says this is a <a target="_blank" href="http://docs.saltstack.com/topics/targeting/compound.html">compound target</a>, and the command will match against both the os grain (to be “MacOS”) and the osrelease grain (to be “10.9.1").</p>
</li>
<li><p>For those same machines, run Apple’s <a target="_blank" href="https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man8/installer.8.html">package utility</a> in unattended mode on the package file, and install that to the boot volume.</p>
</li>
<li><p>Finally, reboot the machine.</p>
</li>
</ol>
<p>The response I got back was identical for each machine, and looks like</p>
<pre><code>mini-<span class="hljs-keyword">server</span>: installer: Package <span class="hljs-type">name</span> <span class="hljs-keyword">is</span> OS X <span class="hljs-keyword">Update</span> installer: Installing at base <span class="hljs-type">path</span> / installer: The install was successful. installer: The install requires restarting now.
</code></pre><p>So, did it work? After waiting for the machines to come back up (use salt-run manage.status on the Salt master to see when they are all online again), the following will show the OS release number for all my Macs.</p>
<pre><code><span class="hljs-attribute">salt</span>-master# salt -C 'G@os:MacOS' grains.item osrelease

<span class="hljs-attribute">mini</span>-server: osrelease: <span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">2</span> imac-<span class="hljs-number">01</span>: osrelease: <span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">2</span> air-<span class="hljs-number">01</span>: osrelease: <span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">2</span> mini-<span class="hljs-number">01</span>: osrelease: <span class="hljs-number">10</span>.<span class="hljs-number">7</span>.<span class="hljs-number">5</span> macbookpro-<span class="hljs-number">01</span>: osrelease: <span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">2</span> macbookpro-<span class="hljs-number">02</span>: osrelease: <span class="hljs-number">10</span>.<span class="hljs-number">9</span>.<span class="hljs-number">2</span> white-macbook: osrelease: <span class="hljs-number">10</span>.<span class="hljs-number">7</span>.<span class="hljs-number">5</span>
</code></pre><p>(Just to be clear, names sanitized)</p>
<p>Voila!</p>
<p><em>Originally published at <a target="_blank" href="http://ncbt.org/install-10-9-2-with-salt.html">ncbt.org</a>.</em></p>
]]></content:encoded></item><item><title><![CDATA[Experimenting with Sup · Nickelblog]]></title><description><![CDATA[For years I have sought the perfect email program. I’ve probably used 20 or 30 over my college years and career—starting with the venerable ‘mail’ on Dynix (caslon.cs.arizona.edu anyone?), moving to Elm, then Pine on SunOS 4, Pine as an IMAP client o...]]></description><link>https://blog.ncbt.org/experimenting-with-sup-nickelblog-5891133b8d5d</link><guid isPermaLink="true">https://blog.ncbt.org/experimenting-with-sup-nickelblog-5891133b8d5d</guid><dc:creator><![CDATA[C. R. Oldham]]></dc:creator><pubDate>Sun, 25 Jan 2015 01:40:54 GMT</pubDate><content:encoded><![CDATA[<p>For years I have sought the perfect email program. I’ve probably used 20 or 30 over my college years and career—starting with the venerable ‘mail’ on Dynix (caslon.cs.arizona.edu anyone?), moving to Elm, then Pine on SunOS 4, Pine as an IMAP client on OS/2, PMMail on OS/2, Pine on NT, Outlook on Windows, Apple Mail, Postbox, Airmail, and those are just the ones I can remember. Nevermind the line-oriented BBS message editors from my younger computing days.</p>
<p>I never could develop a taste for Gmail’s web client even though all my backends are Gmail now.</p>
<p>Some things I’d like to have:</p>
<ul>
<li><p>Complete Vim keybindings</p>
</li>
<li><p>Complete keyboard control</p>
</li>
<li><p>Powerful search</p>
</li>
<li><p>Ability to write email in plain text, Markdown, or reStructuredText.</p>
</li>
<li><p><strong>REAL </strong>threading support</p>
</li>
<li><p>Gmail-style tagging with or without virtual mailboxes</p>
</li>
<li><p>Integrated GPG support</p>
</li>
</ul>
<p>Several months ago when I was hired at <a target="_blank" href="http://saltstack.com/">SaltStack</a>. I tried the old-school retro thing and messed with <a target="_blank" href="http://www.mutt.org/">Mutt</a>. I am sad that development has all but stopped, the one thing that Mutt has going for it is that it is <strong>incredibly </strong>fast with local mailstores. Couple that with <a target="_blank" href="http://notmuchmail.org/">notmuch</a>, the mail indexer, and it’s a power-user’s dream.</p>
<p>Then I discovered <a target="_blank" href="http://www.supmua.org/">Sup</a>. I’m currently experimenting with it now. Here are some things I’ve learned and wanted to communicate in case others come along this road.</p>
<ol>
<li><p>Sup does not fetch mail—for that you want <a target="_blank" href="http://offlineimap.org/">offlineimap</a>. My first hurdle was figuring out how to get Sup to index my 25+ year-old mailstore, all neatly organized into folders. That’s not how Sup works. It fully embraces the ‘one monstrous email archive’ concept brought to us by Google. You want to configure offlineimap to retrieve only your All Mail folder and let it index that. The handy part of that is it solved another issue I was having with offlineimap—the fact that each IDLE folder you define requires a separate open connection to the server. I want to have emails delivered into a number of different folders but Gmail is unhappy if you keep too many connections open. Solution: Just do IDLE for only All Mail, and let Gmail’s tags do the rest.</p>
</li>
<li><p>A HUGE advantage to this is getting rid of the biggest pain of shoehorning Gmail’s concept of email into IMAP—Gmail’s IMAP duplicates messages. Since Gmail exposes tags (labels) as IMAP folders, if a message has 3 tags, a separate copy will appear in each of 3 folders.</p>
</li>
<li><p>After I wrote this I discovered that the Sup maintainer has <a target="_blank" href="https://github.com/gauteh/sup/tree/maildir-root">branch</a> that handles folders (discussion <a target="_blank" href="http://rubyforge.org/pipermail/sup-devel/2013-November/001455.html">here</a>). I haven’t tried this yet. It seems to support hardlinking identical messages.</p>
</li>
<li><p>Sup does not send mail—for that you want one of the null-mailers like msmtp or your distro’s “real” MTA like sendmail, postfix, or exim.</p>
</li>
</ol>
<p><em>Originally published at <a target="_blank" href="http://ncbt.org/experiment-with-sup.html">ncbt.org</a>.</em></p>
]]></content:encoded></item></channel></rss>