<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>blog.oddbit.com</title><link>https://blog.oddbit.com/</link><description>Recent content on blog.oddbit.com</description><generator>Hugo</generator><language>en-us</language><copyright>Lars Kellogg-Stedman</copyright><atom:link href="https://blog.oddbit.com/rss.xml" rel="self" type="application/rss+xml"/><item><title>Things I Made: Fighting words generator</title><link>https://blog.oddbit.com/post/2025-10-11-tim-fightingwords/</link><pubDate>Sat, 11 Oct 2025 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2025-10-11-tim-fightingwords/</guid><description>&lt;p&gt;If you&amp;rsquo;ve ever seen the 1960&amp;rsquo;s live-action Batman TV show, you&amp;rsquo;ll know that one of the defining characteristics of the show was its use of comic-book style words overlaying the action scenes, a technique pioneered in comic books by Roy Crane:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It was Crane who pioneered the use of onomatopoeic sound effects in comics,
adding &amp;ldquo;bam,&amp;rdquo; &amp;ldquo;pow&amp;rdquo; and &amp;ldquo;wham&amp;rdquo; to what had previously been an almost entirely
visual vocabulary. Crane had fun with this, tossing in an occasional
&amp;ldquo;ker-splash&amp;rdquo; or &amp;ldquo;lickety-wop&amp;rdquo; along with what would become the more standard
effects. Words as well as images became vehicles for carrying along his
increasingly fast-paced storylines.&lt;/p&gt;</description></item><item><title>Things I Made: Slow terminal emulation</title><link>https://blog.oddbit.com/post/2025-10-10-tim-slow-terminal/</link><pubDate>Fri, 10 Oct 2025 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2025-10-10-tim-slow-terminal/</guid><description>&lt;p&gt;Ah, the good old days: when computers were chunky, the Internet was a dream of the future, and you could make a cup of coffee while waiting for a screenful of text to display. If you miss that as much as I do, let me introduce you to &lt;a href="https://github.com/larsks/slow"&gt;Slow&lt;/a&gt;, a low bit rate emulator that lets you travel back in time to those simpler days.&lt;/p&gt;
&lt;p&gt;Slow lets you run commands with a reduced output character rate. For example, we can ask for the date at speeds of 50, 75, and 110 bps:&lt;/p&gt;</description></item><item><title>Applying custom configuration to Nginx Gateway Fabric</title><link>https://blog.oddbit.com/post/2023-11-17-nginx-gateway-configuration/</link><pubDate>Fri, 17 Nov 2023 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2023-11-17-nginx-gateway-configuration/</guid><description>&lt;p&gt;In this post, we take a look at how to apply custom Nginx configuration directives when you&amp;rsquo;re using the &lt;a href="https://github.com/nginxinc/nginx-gateway-fabric"&gt;NGINX Gateway Fabric&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="whats-the-nginx-gateway-fabric"&gt;What&amp;rsquo;s the NGINX Gateway Fabric?&lt;/h2&gt;
&lt;p&gt;The NGINX Gateway Fabric is an implementation of the Kubernetes &lt;a href="https://gateway-api.sigs.k8s.io/"&gt;Gateway API&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="whats-the-gateway-api"&gt;What&amp;rsquo;s the Gateway API?&lt;/h2&gt;
&lt;p&gt;The Gateway API is an evolution of the &lt;a href="https://kubernetes.io/docs/concepts/services-networking/ingress/"&gt;Ingress&lt;/a&gt; API; it aims to provide a flexible mechanism for managing north/south network traffic (that is, traffic entering or exiting your Kubernetes cluster), with additional work to support east/west traffic (traffic between pods in your cluster).&lt;/p&gt;</description></item><item><title>Processing deeply nested JSON with jq streams</title><link>https://blog.oddbit.com/post/2023-07-27-jq-streams/</link><pubDate>Thu, 27 Jul 2023 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2023-07-27-jq-streams/</guid><description>&lt;p&gt;I &lt;a href="https://stackoverflow.com/a/76762619/147356"&gt;recently&lt;/a&gt; found myself wanting to perform a few transformations on a large &lt;a href="https://www.openapis.org/"&gt;OpenAPI&lt;/a&gt; schema. In particular, I wanted to take the schema available from the &lt;code&gt;/openapi/v2&lt;/code&gt; endpoint of a Kubernetes server and minimize it by (a) extracting a subset of the definitions and (b) removing all the &lt;code&gt;description&lt;/code&gt; attributes.&lt;/p&gt;
&lt;p&gt;The first task is relatively easy, since everything of interest exists at the same level in the schema. If I want one or more specific definitions, I can simply ask for those by key. For example, if I want the definition of a &lt;a href="https://docs.openshift.com/container-platform/4.13/rest_api/workloads_apis/deploymentconfig-apps-openshift-io-v1.html"&gt;&lt;code&gt;DeploymentConfig&lt;/code&gt;&lt;/a&gt; object, I can run:&lt;/p&gt;</description></item><item><title>Managing containers with Pytest fixtures</title><link>https://blog.oddbit.com/post/2023-07-15-pytest-and-containers/</link><pubDate>Sat, 15 Jul 2023 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2023-07-15-pytest-and-containers/</guid><description>&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Test_fixture#Software"&gt;software fixture&lt;/a&gt; &amp;ldquo;sets up a system for the software testing process by initializing it, thereby satisfying any preconditions the system may have&amp;rdquo;. They allow us to perform setup and teardown tasks, provide state or set up services required for our tests, and perform other initialization tasks. In this article, we&amp;rsquo;re going to explore how to use fixtures in &lt;a href="https://docs.pytest.org/en/7.4.x/"&gt;Pytest&lt;/a&gt; to create and tear down containers as part of a test run.&lt;/p&gt;</description></item><item><title>NAT between identical networks using VRF</title><link>https://blog.oddbit.com/post/2023-02-19-vrf-and-nat/</link><pubDate>Sun, 19 Feb 2023 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2023-02-19-vrf-and-nat/</guid><description>&lt;p&gt;Last week, Oskar Stenberg asked on &lt;a href="https://unix.stackexchange.com/q/735931/4989"&gt;Unix &amp;amp; Linux&lt;/a&gt; if it were possible to configure connectivity between two networks, both using the same address range, without involving network namespaces. That is, given this high level view of the network&amp;hellip;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://excalidraw.com/#json=uuXRRZ2ybaAXiUvbQVkNO,krx3lsbf12c-tDhuWtRjbg"&gt;&lt;img src="https://blog.oddbit.com/post/2023-02-19-vrf-and-nat/the-problem.svg" alt="two networks with the same address range connected by a host named “middleman”"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;hellip;can we set things up so that hosts on the &amp;ldquo;inner&amp;rdquo; network can communicate with hosts on the &amp;ldquo;outer&amp;rdquo; network using the range &lt;code&gt;192.168.3.0/24&lt;/code&gt;, and similarly for communication in the other direction?&lt;/p&gt;</description></item><item><title>Simple error handling in C</title><link>https://blog.oddbit.com/post/2023-02-17-c-error-handling/</link><pubDate>Fri, 17 Feb 2023 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2023-02-17-c-error-handling/</guid><description>&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;I was recently working with someone else&amp;rsquo;s C source and I wanted to add some basic error checking without mucking up the code with a bunch of &lt;code&gt;if&lt;/code&gt; statements and calls to &lt;code&gt;perror&lt;/code&gt;. I ended up implementing a simple &lt;code&gt;must&lt;/code&gt; function that checks the return value of an expression, and exits with an error if the return value is less than 0. You use it like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-c" data-lang="c"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;must&lt;/span&gt;(fd &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;open&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;textfile.txt&amp;#34;&lt;/span&gt;, O_RDONLY));
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Or:&lt;/p&gt;</description></item><item><title>A review of the Garmin Fenix 6(x)</title><link>https://blog.oddbit.com/post/2023-02-15-garmin-fenix-6/</link><pubDate>Wed, 15 Feb 2023 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2023-02-15-garmin-fenix-6/</guid><description>&lt;p&gt;I&amp;rsquo;ve been using a &lt;a href="https://www.garmin.com/en-US/p/641435"&gt;Garmin Fenix 6x&lt;/a&gt; for a couple of weeks and thought it might be interesting to put together a short review.&lt;/p&gt;
&lt;h2 id="is-it-really-a-smartwatch"&gt;Is it really a smartwatch?&lt;/h2&gt;
&lt;p&gt;I think it&amp;rsquo;s a misnomer to call the Fenix a &amp;ldquo;smartwatch&amp;rdquo;. I would call it a highly capable fitness tracker. That&amp;rsquo;s not a knock on the product; I really like it so far, but pretty much everything it does is centered around either fitness tracking or navigation. If you browse around the &lt;a href="https://apps.garmin.com/en-US/"&gt;&amp;ldquo;Connect IQ&amp;rdquo; store&lt;/a&gt;, mostly you&amp;rsquo;ll find (a) watch faces, (b) fitness apps, and (c) navigation apps. It&amp;rsquo;s not able to control your phone (for the most part; there are some apps available that offer remote camera control and some other limited features); you can&amp;rsquo;t check your email on it, or send text messages, and you&amp;rsquo;ll never find a watch version of any major smartphone app.&lt;/p&gt;</description></item><item><title>Packet, packet, who's got the packet?</title><link>https://blog.oddbit.com/post/2023-02-14-whos-got-the-packet/</link><pubDate>Tue, 14 Feb 2023 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2023-02-14-whos-got-the-packet/</guid><description>&lt;p&gt;In &lt;a href="https://unix.stackexchange.com/q/735522/4989"&gt;this question&lt;/a&gt;, August Vrubel has some C code that sets up a &lt;a href="https://docs.kernel.org/networking/tuntap.html"&gt;tun&lt;/a&gt; interface and then injects a packet, but the packet seemed to disappear into the ether. In this post, I&amp;rsquo;d like to take a slightly extended look at &lt;a href="https://unix.stackexchange.com/a/735534/4989"&gt;my answer&lt;/a&gt; because I think it&amp;rsquo;s a great opportunity for learning a bit more about performing network diagnostics.&lt;/p&gt;
&lt;p&gt;The original code looked like this:&lt;/p&gt;



 &lt;div class="collapsable-code"&gt;
 &lt;input id="192487356" type="checkbox" /&gt;
 &lt;label for="192487356"&gt;
 &lt;span class="collapsable-code__language"&gt;c&lt;/span&gt;
 &lt;span class="collapsable-code__title"&gt;original sendpacket.c&lt;/span&gt;
 &lt;span class="collapsable-code__toggle" data-label-expand="△" data-label-collapse="▽"&gt;&lt;/span&gt;
 &lt;/label&gt;
 &lt;pre class="language-c" &gt;&lt;code&gt;

#include &amp;lt;arpa/inet.h&amp;gt;
#include &amp;lt;fcntl.h&amp;gt;
#include &amp;lt;linux/if.h&amp;gt;
#include &amp;lt;linux/if_tun.h&amp;gt;
#include &amp;lt;netinet/in.h&amp;gt;
#include &amp;lt;poll.h&amp;gt;
#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;string.h&amp;gt;
#include &amp;lt;sys/ioctl.h&amp;gt;
#include &amp;lt;sys/socket.h&amp;gt;
#include &amp;lt;sys/stat.h&amp;gt;
#include &amp;lt;sys/types.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;

static int tunAlloc(void) {
 int fd;
 struct ifreq ifr = {.ifr_name = &amp;#34;tun0&amp;#34;, .ifr_flags = IFF_TUN | IFF_NO_PI};

 fd = open(&amp;#34;/dev/net/tun&amp;#34;, O_RDWR);
 ioctl(fd, TUNSETIFF, (void *)&amp;amp;ifr);
 ioctl(fd, TUNSETOWNER, geteuid());
 return fd;
}

// this is a test
static void bringInterfaceUp(void) {
 int sock;
 struct sockaddr_in addr = {.sin_family = AF_INET};
 struct ifreq ifr = {.ifr_name = &amp;#34;tun0&amp;#34;};

 inet_aton(&amp;#34;172.30.0.1&amp;#34;, &amp;amp;addr.sin_addr);
 memcpy(&amp;amp;ifr.ifr_addr, &amp;amp;addr, sizeof(struct sockaddr));

 sock = socket(AF_INET, SOCK_DGRAM, 0);
 ioctl(sock, SIOCSIFADDR, &amp;amp;ifr);
 ioctl(sock, SIOCGIFFLAGS, &amp;amp;ifr);
 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
 ioctl(sock, SIOCSIFFLAGS, &amp;amp;ifr);
 close(sock);
}

static void emitPacket(int tap_fd) {
 unsigned char packet[] = {
 0x45, 0x00, 0x00, 0x3c, 0xd8, 0x6f, 0x40, 0x00, 0x3f, 0x06, 0x08, 0x91,
 172, 30, 0, 1, 192, 168, 255, 8, 0xa2, 0x9a, 0x27, 0x11,
 0x80, 0x0b, 0x63, 0x79, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x02, 0xfa, 0xf0,
 0x89, 0xd8, 0x00, 0x00, 0x02, 0x04, 0x05, 0xb4, 0x04, 0x02, 0x08, 0x0a,
 0x5b, 0x76, 0x5f, 0xd4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0x03, 0x07};

 write(tap_fd, packet, sizeof(packet));
}

int main() {
 int tap_fd;

 tap_fd = tunAlloc();
 bringInterfaceUp();
 emitPacket(tap_fd);
 close(tap_fd);

 return 0;
}



&lt;/code&gt;&lt;/pre&gt;
 &lt;/div&gt;


&lt;p&gt;A problem with the original code is that it creates the interface, sends the packet, and tears down the interface with no delays, making it very difficult to inspect the interface configuration, perform packet captures, or otherwise figure out what&amp;rsquo;s going on.&lt;/p&gt;</description></item><item><title>Setting up an IPv6 VLAN</title><link>https://blog.oddbit.com/post/2022-11-16-home-ipv6-vlan/</link><pubDate>Wed, 16 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2022-11-16-home-ipv6-vlan/</guid><description>&lt;p&gt;My internet service provider (&lt;a href="https://www.verizon.com/home/fios/"&gt;FIOS&lt;/a&gt;) doesn&amp;rsquo;t yet (sad face) offer IPv6 capable service, so I&amp;rsquo;ve set up an IPv6 tunnel using the &lt;a href="https://www.tunnelbroker.net/"&gt;Hurricane Electric&lt;/a&gt; tunnel broker. I want to provide IPv6 connectivity to multiple systems in my house, but not to &lt;strong&gt;all&lt;/strong&gt; systems in my house &lt;sup id="fnref:1"&gt;&lt;a href="#fn:1" class="footnote-ref" role="doc-noteref"&gt;1&lt;/a&gt;&lt;/sup&gt;. In order to meet those requirements, I&amp;rsquo;m going to set up the tunnel on the router, and then expose connectivity over an IPv6-only VLAN. In this post, we&amp;rsquo;ll walk through the steps necessary to set that up.&lt;/p&gt;</description></item><item><title>Using KeyOxide</title><link>https://blog.oddbit.com/post/2022-11-13-using-keyoxide/</link><pubDate>Sun, 13 Nov 2022 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2022-11-13-using-keyoxide/</guid><description>&lt;p&gt;In today&amp;rsquo;s post, we look at &lt;a href="https://keyoxide.org/"&gt;KeyOxide&lt;/a&gt;, a service that allows you to cryptographically assert ownership of online resources using your GPG key. Some aspects of the service are less than obvious; in response to some questions I saw on Mastodon I though I would put together a short guide to making use of the service.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;re going to look at the following high-level tasks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.oddbit.com/post/2022-11-13-using-keyoxide/#step-1-create-a-gpg-keypair"&gt;Create a GPG key&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.oddbit.com/post/2022-11-13-using-keyoxide/#step-2-publish-your-key"&gt;Publish the GPG key&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Delete GitHub workflow runs using the gh cli</title><link>https://blog.oddbit.com/post/2022-09-22-delete-workflow-runs/</link><pubDate>Thu, 22 Sep 2022 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2022-09-22-delete-workflow-runs/</guid><description>&lt;p&gt;Hello, future me. This is for you next time you want to do this.&lt;/p&gt;
&lt;p&gt;When setting up the CI for a project I will sometimes end up with a tremendous clutter of workflow runs. Sometimes they have embarrassing mistakes. Who wants to show that to people? I was trying to figure out how to bulk delete workflow runs from the CLI, and I came up with something that works:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;gh run list --json databaseId -q &amp;#39;.[].databaseId&amp;#39; |
 xargs -IID gh api \
 &amp;#34;repos/$(gh repo view --json nameWithOwner -q .nameWithOwner)/actions/runs/ID&amp;#34; \
 -X DELETE
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will delete &lt;em&gt;all&lt;/em&gt; (well, up to 20, or whatever you set in &lt;code&gt;--limit&lt;/code&gt;) your workflow runs. You can add flags to &lt;code&gt;gh run list&lt;/code&gt; to filter runs by workflow or by triggering user.&lt;/p&gt;</description></item><item><title>Kubernetes, connection timeouts, and the importance of labels</title><link>https://blog.oddbit.com/post/2022-09-10-kubernetes-labels/</link><pubDate>Sat, 10 Sep 2022 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2022-09-10-kubernetes-labels/</guid><description>&lt;p&gt;We are working with an application that produces resource utilization reports for clients of our OpenShift-based cloud environments. The developers working with the application have been reporting mysterious issues concerning connection timeouts between the application and the database (a MariaDB instance). For a long time we had only high-level verbal descriptions of the problem (&amp;ldquo;I&amp;rsquo;m seeing a lot of connection timeouts!&amp;rdquo;) and a variety of unsubstantiated theories (from multiple sources) about the cause. Absent a solid reproducer of the behavior in question, we looked at other aspects of our infrastructure:&lt;/p&gt;</description></item><item><title>Directing different ports to different containers with Traefik</title><link>https://blog.oddbit.com/post/2022-06-20-traefik-multiple-listeners/</link><pubDate>Mon, 20 Jun 2022 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2022-06-20-traefik-multiple-listeners/</guid><description>&lt;p&gt;This post is mostly for myself: I find the &lt;a href="https://traefik.io"&gt;Traefik&lt;/a&gt; documentation hard to navigate, so having figured this out in response to &lt;a href="https://stackoverflow.com/a/72694677/147356"&gt;a question on Stack Overflow&lt;/a&gt;, I&amp;rsquo;m putting it here to help it stick in my head.&lt;/p&gt;
&lt;p&gt;The question asks essentially how to perform port-based routing of requests to containers, so that a request for &lt;code&gt;http://example.com&lt;/code&gt; goes to one container while a request for &lt;code&gt;http://example.com:9090&lt;/code&gt; goes to a different container.&lt;/p&gt;
&lt;h2 id="creating-entrypoints"&gt;Creating entrypoints&lt;/h2&gt;
&lt;p&gt;A default Traefik configuration will already have a listener on port 80, but if we want to accept connections on port 9090 we need to create a new listener: what Traefik calls an &lt;a href="https://doc.traefik.io/traefik/routing/entrypoints/"&gt;entrypoint&lt;/a&gt;. We do this using the &lt;code&gt;--entrypoints.&amp;lt;name&amp;gt;.address&lt;/code&gt; option. For example, &lt;code&gt;--entrypoints.ep1.address=80&lt;/code&gt; creates an entrypoint named &lt;code&gt;ep1&lt;/code&gt; on port 80, while &lt;code&gt;--entrypoints.ep2.address=9090&lt;/code&gt; creates an entrypoint named &lt;code&gt;ep2&lt;/code&gt; on port 9090. Those names are important because we&amp;rsquo;ll use them for mapping containers to the appropriate listener later on.&lt;/p&gt;</description></item><item><title>Udev rules for CH340 serial devices</title><link>https://blog.oddbit.com/post/2022-02-13-wemos-udev-rules/</link><pubDate>Sun, 13 Feb 2022 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2022-02-13-wemos-udev-rules/</guid><description>&lt;p&gt;I like to fiddle with &lt;a href="https://micropython.org"&gt;Micropython&lt;/a&gt;, particularly on the &lt;a href="https://www.wemos.cc/en/latest/d1/d1_mini.html"&gt;Wemos D1 Mini&lt;/a&gt;, because these are such a neat form factor. Unfortunately, they have a cheap CH340 serial adapter on board, which means that from the perspective of Linux these devices are all functionally identical &amp;ndash; there&amp;rsquo;s no way to identify one device from another. This by itself would be a manageable problem, except that the device names assigned to these devices aren&amp;rsquo;t constant: depending on the order in which they get plugged in (and the order in which they are detected at boot), a device might be &lt;code&gt;/dev/ttyUSB0&lt;/code&gt; one day and &lt;code&gt;/dev/ttyUSB2&lt;/code&gt; another day.&lt;/p&gt;</description></item><item><title>A pair of userscripts for cleaning up Stack Exchange sites</title><link>https://blog.oddbit.com/post/2021-09-05-sx-question-filters/</link><pubDate>Sun, 05 Sep 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-09-05-sx-question-filters/</guid><description>&lt;p&gt;I&amp;rsquo;ve been a regular visitor to &lt;a href="https://stackoverflow.com"&gt;Stack Overflow&lt;/a&gt; and other &lt;a href="https://stackexchange.com"&gt;Stack
Exchange&lt;/a&gt; sites over the years, and while I&amp;rsquo;ve mostly enjoyed the
experience, I&amp;rsquo;ve been frustrated by the lack of control I have over
what questions I see. I&amp;rsquo;m not really interested in looking at
questions that have already been closed, or that have a negative
score, but there&amp;rsquo;s no native facility for filtering questions like
this.&lt;/p&gt;
&lt;p&gt;I finally spent the time learning just enough JavaScript ~~~to hurt
myself~~~ to put together a pair of scripts that let me present the
questions that way I want:&lt;/p&gt;</description></item><item><title>Kubernetes External Secrets</title><link>https://blog.oddbit.com/post/2021-09-03-kubernetes-external-secrets/</link><pubDate>Fri, 03 Sep 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-09-03-kubernetes-external-secrets/</guid><description>&lt;p&gt;At &lt;em&gt;$JOB&lt;/em&gt; we maintain the configuration for our OpenShift clusters in a public git repository. Changes in the git repository are applied automatically using &lt;a href="https://argo-cd.readthedocs.io/en/stable/"&gt;ArgoCD&lt;/a&gt; and &lt;a href="https://kustomize.io/"&gt;Kustomize&lt;/a&gt;. This works great, but the public nature of the repository means we need to find a secure solution for managing secrets (such as passwords and other credentials necessary for authenticating to external services). In particular, we need a solution that permits our public repository to be the source of truth for our cluster configuration, without compromising our credentials.&lt;/p&gt;</description></item><item><title>Connecting OpenShift to an External Ceph Cluster</title><link>https://blog.oddbit.com/post/2021-08-23-external-ocs/</link><pubDate>Mon, 23 Aug 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-08-23-external-ocs/</guid><description>&lt;p&gt;Red Hat&amp;rsquo;s &lt;a href="https://www.redhat.com/en/technologies/cloud-computing/openshift-data-foundation"&gt;OpenShift Data Foundation&lt;/a&gt; (formerly &amp;ldquo;OpenShift
Container Storage&amp;rdquo;, or &amp;ldquo;OCS&amp;rdquo;) allows you to either (a) automatically
set up a Ceph cluster as an application running on your OpenShift
cluster, or (b) connect your OpenShift cluster to an externally
managed Ceph cluster. While setting up Ceph as an OpenShift
application is a relatively polished experienced, connecting to an
external cluster still has some rough edges.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; I am not a Ceph expert. If you read this and think I&amp;rsquo;ve made a
mistake with respect to permissions or anything else, please feel free
to leave a comment and I will update the article as necessary. In
particular, I think it may be possible to further restrict the &lt;code&gt;mgr&lt;/code&gt;
permissions shown in this article and I&amp;rsquo;m interested in feedback on
that topic.&lt;/p&gt;</description></item><item><title>Creating a VXLAN overlay network with Open vSwitch</title><link>https://blog.oddbit.com/post/2021-04-17-vm-ovs-vxlan/</link><pubDate>Sat, 17 Apr 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-04-17-vm-ovs-vxlan/</guid><description>&lt;p&gt;In this post, we&amp;rsquo;ll walk through the process of getting virtual
machines on two different hosts to communicate over an overlay network
created using the support for VXLAN in &lt;a href="https://www.openvswitch.org/"&gt;Open vSwitch&lt;/a&gt; (or OVS).&lt;/p&gt;
&lt;h2 id="the-test-environment"&gt;The test environment&lt;/h2&gt;
&lt;p&gt;For this post, I&amp;rsquo;ll be working with two systems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;node0.ovs.virt&lt;/code&gt; at address 192.168.122.107&lt;/li&gt;
&lt;li&gt;&lt;code&gt;node1.ovs.virt&lt;/code&gt; at address 192.168.122.174&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These hosts are running CentOS 8, although once we get past the
package installs the instructions will be similar for other
distributions.&lt;/p&gt;</description></item><item><title>Getting started with KSOPS</title><link>https://blog.oddbit.com/post/2021-03-09-getting-started-with-ksops/</link><pubDate>Tue, 09 Mar 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-03-09-getting-started-with-ksops/</guid><description>&lt;p&gt;&lt;a href="https://kustomize.io/"&gt;Kustomize&lt;/a&gt; is a tool for assembling Kubernetes manifests from a
collection of files. We&amp;rsquo;re making extensive use of Kustomize in the
&lt;a href="https://www.operate-first.cloud/"&gt;operate-first&lt;/a&gt; project. In order to keep secrets stored in our
configuration repositories, we&amp;rsquo;re using the &lt;a href="https://github.com/viaduct-ai/kustomize-sops"&gt;KSOPS&lt;/a&gt; plugin, which
enables Kustomize to use &lt;a href="https://github.com/mozilla/sops"&gt;sops&lt;/a&gt; to encrypt/files using GPG.&lt;/p&gt;
&lt;p&gt;In this post, I&amp;rsquo;d like to walk through the steps necessary to get
everything up and running.&lt;/p&gt;
&lt;h2 id="set-up-gpg"&gt;Set up GPG&lt;/h2&gt;
&lt;p&gt;We encrypt files using GPG, so the first step is making sure that you
have a GPG keypair and that your public key is published where other
people can find it.&lt;/p&gt;</description></item><item><title>Tools for writing about Git</title><link>https://blog.oddbit.com/post/2021-02-27-git-doc-tools/</link><pubDate>Sat, 27 Feb 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-02-27-git-doc-tools/</guid><description>&lt;p&gt;I sometimes find myself writing articles or documentation about
&lt;a href="https://git-scm.org"&gt;git&lt;/a&gt;, so I put together a couple of terrible hacks for generating
reproducible histories and pretty graphs of those histories.&lt;/p&gt;
&lt;h2 id="git-synth"&gt;git synth&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://github.com/larsks/git-snippets/blob/master/git-synth"&gt;&lt;code&gt;git synth&lt;/code&gt;&lt;/a&gt; command reads a &lt;a href="https://yaml.org/"&gt;YAML&lt;/a&gt; description of a
repository and executes the necessary commands to reproduce that
history. It allows you set the name and email address of the author
and committer as well as static date, so you every time you generate
the repository you can identical commit ids.&lt;/p&gt;</description></item><item><title>File reorganization</title><link>https://blog.oddbit.com/post/2021-02-24-file-reorganization/</link><pubDate>Wed, 24 Feb 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-02-24-file-reorganization/</guid><description>&lt;p&gt;This is just a note that I&amp;rsquo;ve substantially changed how the post
sources are organized. I&amp;rsquo;ve tried to ensure that I preserve all the
existing links, but if you spot something missing please feel free to
leave a comment on this post.&lt;/p&gt;</description></item><item><title>Editing a commit message without git rebase</title><link>https://blog.oddbit.com/post/2021-02-18-editing-a-commit-message-witho/</link><pubDate>Thu, 18 Feb 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-02-18-editing-a-commit-message-witho/</guid><description>&lt;p&gt;While working on a pull request I will make liberal use of &lt;a href="https://git-scm.com/docs/git-rebase"&gt;git
rebase&lt;/a&gt; to clean up a series of commits: squashing typos,
re-ordering changes for logical clarity, and so forth. But there are
some times when all I want to do is change a commit message somewhere
down the stack, and I was wondering if I had any options for doing
that without reaching for &lt;code&gt;git rebase&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It turns out the answer is &amp;ldquo;yes&amp;rdquo;, as long as you have a linear
history.&lt;/p&gt;</description></item><item><title>Object storage with OpenShift Container Storage</title><link>https://blog.oddbit.com/post/2021-02-10-object-storage-with-openshift/</link><pubDate>Wed, 10 Feb 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-02-10-object-storage-with-openshift/</guid><description>&lt;p&gt;&lt;a href="https://www.redhat.com/en/technologies/cloud-computing/openshift-container-storage"&gt;OpenShift Container Storage&lt;/a&gt; (OCS) from Red Hat deploys Ceph in your
OpenShift cluster (or allows you to integrate with an external Ceph
cluster). In addition to the file- and block- based volume services
provided by Ceph, OCS includes two S3-api compatible object storage
implementations.&lt;/p&gt;
&lt;p&gt;The first option is the &lt;a href="https://docs.ceph.com/en/latest/radosgw/"&gt;Ceph Object Gateway&lt;/a&gt; (radosgw),
Ceph&amp;rsquo;s native object storage interface. The second option called the
&amp;ldquo;&lt;a href="https://www.openshift.com/blog/introducing-multi-cloud-object-gateway-for-openshift"&gt;Multicloud Object Gateway&lt;/a&gt;&amp;rdquo;, which is in fact a piece of software
named &lt;a href="https://www.noobaa.io/"&gt;Noobaa&lt;/a&gt;, a storage abstraction layer that was &lt;a href="https://www.redhat.com/en/blog/faq-red-hat-acquires-noobaa"&gt;acquired by
Red Hat&lt;/a&gt; in 2018. In this article I&amp;rsquo;d like to demonstrate how to
take advantage of these storage options.&lt;/p&gt;</description></item><item><title>Remediating poor PyPi performance with DevPi</title><link>https://blog.oddbit.com/post/2021-02-08-remediating-poor-pypi-performa/</link><pubDate>Mon, 08 Feb 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-02-08-remediating-poor-pypi-performa/</guid><description>&lt;p&gt;Performance of the primary PyPi service has been so bad lately that
it&amp;rsquo;s become very disruptive. Tasks that used to take a few seconds
will now churn along for 15-20 minutes or longer before completing,
which is incredibly frustrating.&lt;/p&gt;
&lt;p&gt;I first went looking to see if there was a PyPi mirror infrastructure,
like we see with &lt;a href="https://www.cpan.org/"&gt;CPAN&lt;/a&gt; for Perl or &lt;a href="https://ctan.org/"&gt;CTAN&lt;/a&gt; for Tex (and similarly
for most Linux distributions). There is apparently no such beast,&lt;/p&gt;</description></item><item><title>symtool: a tool for interacting with your SYM-1</title><link>https://blog.oddbit.com/post/2021-02-06-symtool-a-tool-for-interacting/</link><pubDate>Sat, 06 Feb 2021 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2021-02-06-symtool-a-tool-for-interacting/</guid><description>&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/SYM-1"&gt;SYM-1&lt;/a&gt; is a &lt;a href="https://en.wikipedia.org/wiki/MOS_Technology_6502"&gt;6502&lt;/a&gt;-based single-board computer produced by
&lt;a href="https://en.wikipedia.org/wiki/Synertek"&gt;Synertek Systems Corp&lt;/a&gt; in the mid 1970&amp;rsquo;s. I&amp;rsquo;ve had one
floating around in a box for many, many years, and after a recent
foray into the world of 6502 assembly language programming I decided
to pull it out, dust it off, and see if it still works.&lt;/p&gt;
&lt;p&gt;The board I have has a whopping 8KB of memory, and in addition to the
standard SUPERMON monitor it has the expansion ROMs for the Synertek
BASIC interpreter (yet another Microsoft BASIC) and RAE (the &amp;ldquo;Resident
Assembler Editor&amp;rdquo;). One interacts with the board either through the
onboard hex keypad and six-digit display, or via a serial connection
at 4800bps (or lower).&lt;/p&gt;</description></item><item><title>To sleep or not to sleep?</title><link>https://blog.oddbit.com/post/2020-12-18-to-sleep-or-not-to-sleep/</link><pubDate>Fri, 18 Dec 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-12-18-to-sleep-or-not-to-sleep/</guid><description>&lt;p&gt;Let&amp;rsquo;s say you have a couple of sensors attached to an ESP8266 running
&lt;a href="https://micropython.org/"&gt;MicroPython&lt;/a&gt;. You&amp;rsquo;d like to sample them at different frequencies
(say, one every 60 seconds and one every five minutes), and you&amp;rsquo;d like
to do it as efficiently as possible in terms of power consumption.
What are your options?&lt;/p&gt;
&lt;p&gt;If we don&amp;rsquo;t care about power efficiency, the simplest solution is
probably a loop like this:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;import machine

lastrun_1 = 0
lastrun_2 = 0

while True:
 now = time.time()

 if (lastrun_1 == 0) or (now - lastrun_1 &amp;gt;= 60):
 read_sensor_1()
 lastrun_1 = now
 if (lastrun_2 == 0) or (now - lastrun_2 &amp;gt;= 300):
 read_sensor_2()
 lastrun_2 = now

 machine.idle()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If we were only reading a single sensor (or multiple sensors at the
same interval), we could drop the loop and juse use the ESP8266&amp;rsquo;s deep
sleep mode (assuming we have &lt;a href="http://docs.micropython.org/en/latest/esp8266/tutorial/powerctrl.html#deep-sleep-mode"&gt;wired things properly&lt;/a&gt;):&lt;/p&gt;</description></item><item><title>Animating a map of Covid in the Northeast US</title><link>https://blog.oddbit.com/post/2020-12-13-animating-a-map-of-covid-in-th/</link><pubDate>Sun, 13 Dec 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-12-13-animating-a-map-of-covid-in-th/</guid><description>&lt;p&gt;I recently put together a short animation showing the spread of Covid
throughout the Northeast United States:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/zGN_zEzd_TE?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;I thought it might be interesting to walk through the process I used to
create the video. The steps described in this article aren&amp;rsquo;t exactly
what I used (I was dealing with data in a &lt;a href="https://postgis.net/"&gt;PostGIS&lt;/a&gt; database, and in
the interests of simplicity I wanted instructions that can be
accomplished with just QGIS), but they end up in the same place.&lt;/p&gt;</description></item><item><title>A note about running gpgv</title><link>https://blog.oddbit.com/post/2020-10-05-a-note-about-running-gpgv/</link><pubDate>Mon, 05 Oct 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-10-05-a-note-about-running-gpgv/</guid><description>&lt;p&gt;I found the following error from &lt;code&gt;gpgv&lt;/code&gt; to be a little opaque:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;gpgv: unknown type of key resource &amp;#39;trustedkeys.kbx&amp;#39;
gpgv: keyblock resource &amp;#39;/home/lars/.gnupg/trustedkeys.kbx&amp;#39;: General error
gpgv: Can&amp;#39;t check signature: No public key
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It turns out that&amp;rsquo;s gpg-speak for &amp;ldquo;your &lt;code&gt;trustedkeys.kbx&lt;/code&gt; keyring doesn&amp;rsquo;t
exist&amp;rdquo;. That took longer to figure out than I care to admit. To get a key
from your regular public keyring into your trusted keyring, you can run
something like the following:&lt;/p&gt;</description></item><item><title>Installing metallb on OpenShift with Kustomize</title><link>https://blog.oddbit.com/post/2020-09-27-installing-metallb-on-openshif/</link><pubDate>Sun, 27 Sep 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-09-27-installing-metallb-on-openshif/</guid><description>&lt;p&gt;Out of the box, OpenShift (4.x) on bare metal doesn&amp;rsquo;t come with any
integrated load balancer support (when installed in a cloud environment,
OpenShift typically makes use of the load balancing features available from
the cloud provider). Fortunately, there are third party solutions available
that are designed to work in bare metal environments. &lt;a href="https://metallb.universe.tf/"&gt;MetalLB&lt;/a&gt; is a
popular choice, but requires some minor fiddling to get it to run properly
on OpenShift.&lt;/p&gt;</description></item><item><title>Vortex Core Keyboard Review</title><link>https://blog.oddbit.com/post/2020-09-26-vortex-core-keyboard-review/</link><pubDate>Sat, 26 Sep 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-09-26-vortex-core-keyboard-review/</guid><description>&lt;p&gt;I&amp;rsquo;ve had my eye on the &lt;a href="http://www.vortexgear.tw/vortex2_2.asp?kind=47&amp;amp;kind2=224&amp;amp;kind3=&amp;amp;kind4=1033"&gt;Vortex Core&lt;/a&gt; keyboard for a few months now, and this
past week I finally broke down and bought one (with Cherry MX Brown switches).
The Vortex Core is a 40% keyboard, which means it consists primarily of letter
keys, a few lonely bits of punctuation, and several modifier keys to activate
different layers on the keyboard.&lt;/p&gt;
&lt;h2 id="physical-impressions"&gt;Physical impressions&lt;/h2&gt;
&lt;p&gt;It&amp;rsquo;s a really cute keyboard. I&amp;rsquo;m a big fan of MX brown switches, and this
keyboard is really a joy to type on, at least when you&amp;rsquo;re working primarily
with the alpha keys. I&amp;rsquo;m still figuring out where some of the punctuation
is, and with a few exceptions I haven&amp;rsquo;t yet spent time trying to remap
things into more convenient positions.&lt;/p&gt;</description></item><item><title>Building multi-architecture images with GitHub Actions</title><link>https://blog.oddbit.com/post/2020-09-25-building-multi-architecture-im/</link><pubDate>Fri, 25 Sep 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-09-25-building-multi-architecture-im/</guid><description>&lt;p&gt;At work we have a cluster of IBM Power 9 systems running OpenShift. The
problem with this environment is that nobody runs Power 9 on their desktop,
and Docker Hub only offers automatic build support for the x86
architecture. This means there&amp;rsquo;s no convenient options for building Power 9
Docker images&amp;hellip;or so I thought.&lt;/p&gt;
&lt;p&gt;It turns out that &lt;a href="https://github.com/docker"&gt;Docker&lt;/a&gt; provides &lt;a href="https://github.com/features/actions"&gt;GitHub actions&lt;/a&gt; that make the process
of producing multi-architecture images quite simple.&lt;/p&gt;</description></item><item><title>OpenShift and CNV: MAC address management in CNV 2.4</title><link>https://blog.oddbit.com/post/2020-08-10-mac-address-management-in-cnv/</link><pubDate>Mon, 10 Aug 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-08-10-mac-address-management-in-cnv/</guid><description>&lt;p&gt;This is part of a &lt;a href="https://blog.oddbit.com/tag/openshift-and-cnv"&gt;series of posts&lt;/a&gt; about my experience working with
&lt;a href="https://www.openshift.com/"&gt;OpenShift&lt;/a&gt; and &lt;a href="https://www.redhat.com/en/topics/containers/what-is-container-native-virtualization"&gt;CNV&lt;/a&gt;. In this post, I&amp;rsquo;ll look at how the
recently released CNV 2.4 resolves some issues in managing virtual
machines that are attached directly to local layer 2 networks&lt;/p&gt;
&lt;p&gt;In &lt;a href="https://blog.oddbit.com/post/2020-07-30-openshift-and-cnv-part-2-expos/"&gt;an earlier post&lt;/a&gt;, I discussed some issues around the
management of virtual machine MAC addresses in CNV 2.3: in particular,
that virtual machines are assigned a random MAC address not just at
creation time but every time they boot. CNV 2.4 (re-)introduces &lt;a href="https://docs.openshift.com/container-platform/4.5/virt/virtual_machines/vm_networking/virt-using-mac-address-pool-for-vms.html"&gt;MAC
address pools&lt;/a&gt; to alleviate these issues. The high level description
reads:&lt;/p&gt;</description></item><item><title>OpenShift and CNV: Exposing virtualized services</title><link>https://blog.oddbit.com/post/2020-07-30-openshift-and-cnv-part-2-expos/</link><pubDate>Thu, 30 Jul 2020 01:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-07-30-openshift-and-cnv-part-2-expos/</guid><description>&lt;p&gt;This is the second in a &lt;a href="https://blog.oddbit.com/tag/openshift-and-cnv"&gt;series of posts&lt;/a&gt; about my experience working
with &lt;a href="https://www.openshift.com/"&gt;OpenShift&lt;/a&gt; and &lt;a href="https://www.redhat.com/en/topics/containers/what-is-container-native-virtualization"&gt;CNV&lt;/a&gt;. In this post, I&amp;rsquo;ll be taking a look
at how to expose services on a virtual machine once you&amp;rsquo;ve git it up
and running.&lt;/p&gt;
&lt;nav id="TableOfContents"&gt;
 &lt;ul&gt;
 &lt;li&gt;&lt;a href="#tldr"&gt;TL;DR&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#overview"&gt;Overview&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#connectivity-options"&gt;Connectivity options&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#direct-attachment"&gt;Direct attachment&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#using-an-openshift-service"&gt;Using an OpenShift Service&lt;/a&gt;
 &lt;ul&gt;
 &lt;li&gt;&lt;a href="#exposing-services-on-nodeports"&gt;Exposing services on NodePorts&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#exposing-services-on-cluster-external-ipso"&gt;Exposing services on cluster external IPso&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#exposing-services-using-a-loadbalancer"&gt;Exposing services using a LoadBalancer&lt;/a&gt;&lt;/li&gt;
 &lt;/ul&gt;
 &lt;/li&gt;
 &lt;/ul&gt;
&lt;/nav&gt;

&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;p&gt;Networking seems to be a weak area for CNV right now. Out of the box,
your options for exposing a service on a virtual machine on a public
address at a well known port are slim.&lt;/p&gt;</description></item><item><title>OpenShift and CNV: Installer network requirements</title><link>https://blog.oddbit.com/post/2020-07-30-openshift-and-cnv-part-1-worki/</link><pubDate>Thu, 30 Jul 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-07-30-openshift-and-cnv-part-1-worki/</guid><description>&lt;p&gt;This is the first in a &lt;a href="https://blog.oddbit.com/tag/openshift-and-cnv"&gt;series of posts&lt;/a&gt; about my experience working
with &lt;a href="https://www.openshift.com/"&gt;OpenShift&lt;/a&gt; and &lt;a href="https://www.redhat.com/en/topics/containers/what-is-container-native-virtualization"&gt;CNV&lt;/a&gt; (&amp;ldquo;Container Native Virtualization&amp;rdquo;, a
technology that allows you to use OpenShift to manage virtualized
workloads in addition to the containerized workloads for which
OpenShift is known). In this post, I&amp;rsquo;ll be taking a look at the
installation experience, and in particular at how restrictions in our
local environment interacted with the network requirements of the installer.&lt;/p&gt;</description></item><item><title>You can't get an N95 mask: Now what?</title><link>https://blog.oddbit.com/post/2020-07-28-you-cant-get-an-n95-mask-now-w/</link><pubDate>Tue, 28 Jul 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-07-28-you-cant-get-an-n95-mask-now-w/</guid><description>&lt;p&gt;[This is a guest post by my partner Alexandra van Geel.]&lt;/p&gt;
&lt;nav id="TableOfContents"&gt;
 &lt;ul&gt;
 &lt;li&gt;&lt;a href="#tldr"&gt;TL;DR&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#hello-everyone"&gt;Hello everyone!&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#the-basics-masks-vs-respirators"&gt;The Basics: Masks vs. Respirators&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#question-what-makes-a-good-mask"&gt;Question: What makes a good mask?&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#commercially-available-options"&gt;Commercially available options&lt;/a&gt;
 &lt;ul&gt;
 &lt;li&gt;&lt;a href="#the-o2-canada-curve-respirator"&gt;The O2 Canada Curve Respirator&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#the-vogmask-valveless-mask"&gt;The Vogmask valveless mask&lt;/a&gt;&lt;/li&gt;
 &lt;/ul&gt;
 &lt;/li&gt;
 &lt;li&gt;&lt;a href="#some-tips-about-comfort"&gt;Some tips about comfort&lt;/a&gt;&lt;/li&gt;
 &lt;li&gt;&lt;a href="#references"&gt;References&lt;/a&gt;&lt;/li&gt;
 &lt;/ul&gt;
&lt;/nav&gt;

&lt;p&gt;Disclaimer: I am not an expert, just a private individual summarizing available
information. Please correct me if I&amp;rsquo;ve gotten something wrong.&lt;/p&gt;
&lt;h2 id="tldr"&gt;TL;DR&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I suggest: (a) the &lt;a href="https://www.vogmask.com/collections/all"&gt;Vogmask valveless mask&lt;/a&gt; or (b) the &lt;a href="https://o2canada.com/products/o2-curve-1-2"&gt;O2 Canada Curve
Respirator&lt;/a&gt;. If (b), make sure you cut some an extra filter into two small
circles and put the material in the respirator to cover the exhale valves.&lt;/p&gt;</description></item><item><title>Grove Beginner Kit for Arduino (part 2): First look</title><link>https://blog.oddbit.com/post/2020-06-07-first-look-seed-grove-beginner/</link><pubDate>Sun, 07 Jun 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-06-07-first-look-seed-grove-beginner/</guid><description>&lt;p&gt;The folks at &lt;a href="https://seeedstudio.com"&gt;Seeed Studio&lt;/a&gt; were kind enough to send me a &lt;a href="https://www.seeedstudio.com/Grove-Beginner-Kit-for-Arduino-p-4549.html"&gt;Grove
Beginner Kit for Arduino&lt;/a&gt; for review. That&amp;rsquo;s a mouthful of a name
for a compact little kit!&lt;/p&gt;
&lt;p&gt;The Grove Beginner Kit for Arduino (henceforth &amp;ldquo;the Kit&amp;rdquo;, because ain&amp;rsquo;t
nobody got time to type that out more than a few times in a single
article) is about 8.5 x 5 x 1 inches. Closed, you could fit two of
them on a piece of 8.5x11 paper with a little room leftover.&lt;/p&gt;</description></item><item><title>Grove Beginner Kit for Arduino (part 1)</title><link>https://blog.oddbit.com/post/2020-04-15-grove-beginner-kit-for-arduino/</link><pubDate>Wed, 15 Apr 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-04-15-grove-beginner-kit-for-arduino/</guid><description>&lt;p&gt;The folks at &lt;a href="https://www.seeedstudio.com/"&gt;Seeed Studio&lt;/a&gt; have just released the &lt;a href="https://www.seeedstudio.com/Grove-Beginner-Kit-for-Arduino-p-4549.html"&gt;Grove Beginner Kit for
Arduino&lt;/a&gt;, and they asked if I would be willing to take a look at it in
exchange for a free kit. At first glance it reminds me of the Radio Shack
(remember when they were cool?) electronics kit I had when I was a kid &amp;ndash; but
somewhat more advanced. I&amp;rsquo;m excited to take a closer look, but given shipping
these days means it&amp;rsquo;s probably a month away at least.&lt;/p&gt;</description></item><item><title>Some thoughts on Mechanical Keyboards</title><link>https://blog.oddbit.com/post/2020-04-15-some-thoughts-on-mechanical-ke/</link><pubDate>Wed, 15 Apr 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-04-15-some-thoughts-on-mechanical-ke/</guid><description>&lt;p&gt;Since we&amp;rsquo;re all stuck in the house and working from home these days, I&amp;rsquo;ve had to make some changes to my home office. One change in particular was requested by my wife, who now shares our rather small home office space with me: after a week or so of calls with me clattering away on my old Das Keyboard 3 Professional in the background, she asked if I could get something that was maybe a little bit quieter.&lt;/p&gt;</description></item><item><title>I see you have the machine that goes ping...</title><link>https://blog.oddbit.com/post/2020-03-20-i-see-you-have-the-machine-tha/</link><pubDate>Fri, 20 Mar 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-03-20-i-see-you-have-the-machine-tha/</guid><description>&lt;p&gt;We&amp;rsquo;re all looking for ways to keep ourselves occupied these days, and
for me that means leaping at the chance to turn a small problem into a
slightly ridiculous electronics project. For reasons that I won&amp;rsquo;t go
into here I wanted to generate an alert when a certain WiFi BSSID
becomes visible. A simple solution to this problem would have been a
few lines of shell script to send me an email&amp;hellip;but this article isn&amp;rsquo;t
about simple solutions!&lt;/p&gt;</description></item><item><title>A passwordless serial console for your Raspberry Pi</title><link>https://blog.oddbit.com/post/2020-02-24-a-passwordless-serial-console/</link><pubDate>Mon, 24 Feb 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-02-24-a-passwordless-serial-console/</guid><description>&lt;p&gt;&lt;code&gt;legendre&lt;/code&gt; on &lt;code&gt;#raspbian&lt;/code&gt; asked:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How can i config rasp lite to open a shell on the serial uart on boot? Params
are 1200-8-N-1 Dont want login running, just straight to sh&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this article, we&amp;rsquo;ll walk through one way of implementing this configuration.&lt;/p&gt;
&lt;h2 id="activate-the-serial-port"&gt;Activate the serial port&lt;/h2&gt;
&lt;p&gt;Raspberry Pi OS automatically starts a &lt;a href="https://en.wikipedia.org/wiki/Getty_%28Unix%29"&gt;&lt;code&gt;getty&lt;/code&gt;&lt;/a&gt; on the serial port if one is available. You should see an &lt;code&gt;agetty&lt;/code&gt; process associated with your serial port when you run &lt;code&gt;ps -ef&lt;/code&gt;. For example:&lt;/p&gt;</description></item><item><title>Configuring Open vSwitch with nmcli</title><link>https://blog.oddbit.com/post/2020-02-15-configuring-open-vswitch-with/</link><pubDate>Sat, 15 Feb 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-02-15-configuring-open-vswitch-with/</guid><description>&lt;p&gt;I recently acquired a managed switch for my home office in order to segment a few devices off onto their own isolated vlan. As part of this, I want to expose these vlans on my desktop using Open vSwitch (OVS), and I wanted to implement the configuration using NetworkManager rather than either relying on the legacy &lt;code&gt;/etc/sysconfig/network-scripts&lt;/code&gt; scripts or rolling my own set of services. These are my notes in case I ever have to do this again.&lt;/p&gt;</description></item><item><title>How long is a cold spell in Boston?</title><link>https://blog.oddbit.com/post/2020-01-23-how-long-is-a-cold-spell/</link><pubDate>Thu, 23 Jan 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-01-23-how-long-is-a-cold-spell/</guid><description>&lt;p&gt;We&amp;rsquo;ve had some wacky weather recently. In the space of a week, the temperature went from a high of about 75°F to a low around 15°F. This got me to thinking about what constitutes &amp;ldquo;normal&amp;rdquo; weather here in the Boston area, and in particular, how common it is to have a string of consecutive days in which the high temperature stays below freezing. While this was an interesting question in itself, it also seemed like a great opportunity to learn a little about &lt;a href="https://pandas.pydata.org"&gt;Pandas&lt;/a&gt;, the Python data analysis framework.&lt;/p&gt;</description></item><item><title>Snarl: A tool for literate blogging</title><link>https://blog.oddbit.com/post/2020-01-15-snarl-a-tool-for-literate-blog/</link><pubDate>Wed, 15 Jan 2020 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2020-01-15-snarl-a-tool-for-literate-blog/</guid><description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Literate_programming"&gt;Literate programming&lt;/a&gt; is a programming paradigm introduced by Donald Knuth in which a program is combined with its documentation to form a single document. Tools are then used to extract the documentation for viewing or typesetting or to extract the program code so it can be compiled and/or run. While I have never been very enthusiastic about literate programming as a development methodology, I was recently inspired to explore these ideas as they relate to the sort of technical writing I do for this blog.&lt;/p&gt;</description></item><item><title>OVN and DHCP: A minimal example</title><link>https://blog.oddbit.com/post/2019-12-19-ovn-and-dhcp/</link><pubDate>Thu, 19 Dec 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-12-19-ovn-and-dhcp/</guid><description>&lt;h1 id="introduction"&gt;Introduction&lt;/h1&gt;
&lt;p&gt;A long time ago, I wrote an article &lt;a href="https://blog.oddbit.com/post/2013-11-14-quantum-in-too-much-detail/"&gt;all about OpenStack Neutron&lt;/a&gt; (which at that time was called Quantum). That served as an excellent reference for a number of years, but if you&amp;rsquo;ve deployed a recent version of OpenStack you may have noticed that the network architecture looks completely different. The network namespaces previously used to implement routers and dhcp servers are gone (along with iptables rules and other features), and have been replaced by OVN (&amp;ldquo;Open Virtual Network&amp;rdquo;). What is OVN? How does it work? In this article, I&amp;rsquo;d like to explore a minimal OVN installation to help answer these questions.&lt;/p&gt;</description></item><item><title>TM-V71A and Linux, part 1: Programming mode</title><link>https://blog.oddbit.com/post/2019-10-03-tm-v71a-linux-part-1/</link><pubDate>Thu, 03 Oct 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-10-03-tm-v71a-linux-part-1/</guid><description>&lt;p&gt;I recently acquired my Technician amateur radio license, and like many folks my first radio purchase was a &lt;a href="https://baofengtech.com/uv-5r?PageSpeed=noscript"&gt;Baofeng UV-5R&lt;/a&gt;. Due to its low cost, this is a very popular radio, and there is excellent open source software available for programming it in the form of the &lt;a href="https://chirp.danplanet.com/projects/chirp/wiki/Home"&gt;CHIRP&lt;/a&gt; project. After futzing around with the UV-5R for a while, I wanted to get something a little nicer for use at home, so I purchased a &lt;a href="https://www.kenwood.com/usa/com/amateur/tm-v71a/"&gt;Kenwood TM-V71A&lt;/a&gt;. CHIRP claims to have support for this radio as well, but it turns out it&amp;rsquo;s not very good: it uses a &amp;ldquo;live&amp;rdquo; connection so every time you edit a channel it tries to update the radio. This result in a slow and flaky UI, especially when trying to make bulk changes (like relocating a block of channels). I ended up using Kenwood&amp;rsquo;s official &lt;a href="https://www.kenwood.com/i/products/info/amateur/mcp_2a.html"&gt;MCP-2A&lt;/a&gt; software running on a Windows guest on my system, which works but isn&amp;rsquo;t ideal. I decided to learn more about how the radio interacts with the computer to see if I could improve the situation.&lt;/p&gt;</description></item><item><title>Avoid rebase hell: squashing without rebasing</title><link>https://blog.oddbit.com/post/2019-06-17-avoid-rebase-hell-squashing-wi/</link><pubDate>Mon, 17 Jun 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-06-17-avoid-rebase-hell-squashing-wi/</guid><description>&lt;p&gt;You&amp;rsquo;re working on a pull request. You&amp;rsquo;ve been working on a pull request for a while, and due to lack of sleep or inebriation you&amp;rsquo;ve been merging changes into your feature branch rather than rebasing. You now have a pull request that looks like this (I&amp;rsquo;ve marked merge commits with the text &lt;code&gt;[merge]&lt;/code&gt;):&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;7e181479 Adds methods for widget sales
0487162 [merge] Merge remote-tracking branch &amp;#39;origin/master&amp;#39; into my_feature
76ee81c [merge] Merge branch &amp;#39;my_feature&amp;#39; of https://github.com/my_user_name/widgets into my_feature
981aab4 Adds api for the widget service.
b048836 Includes fixes suggested by reviewer.
3dd0c22 adds changes requested by reviewer
5891db2 [merge] fixing merge conflicts
2e226e4 fixes suggestions given by the reviewer
da1e85c Adds gadget related API spec
c555cc1 Adds doodad related API spec
e5beb3e Adds api for update and delete of widgets
c43bade Adds api for creating widgets
deaa962 Adds all get methods for listing widgets
9de79ab Adds api for showing a widget and simple data model
8288ab1 Adds api framework for widget service
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You know that&amp;rsquo;s a mess, so you try to fix it by running &lt;code&gt;git rebase -i master&lt;/code&gt; and squashing everything together&amp;hellip;and you find yourself stuck in an endless maze of merge conflicts. There has to be a better way!&lt;/p&gt;</description></item><item><title>Git Etiquette: Commit messages and pull requests</title><link>https://blog.oddbit.com/post/2019-06-14-git-etiquette-commit-messages/</link><pubDate>Fri, 14 Jun 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-06-14-git-etiquette-commit-messages/</guid><description>&lt;h2 id="always-work-on-a-branch-never-commit-on-master"&gt;Always work on a branch (never commit on master)&lt;/h2&gt;
&lt;p&gt;When working with an upstream codebase, always make your changes on a feature branch rather than your local &lt;code&gt;master&lt;/code&gt; branch. This will make it easier to keep your local &lt;code&gt;master&lt;/code&gt; branch current with respect to upstream, and can help avoid situations in which you accidentally overwrite your local changes or introduce unnecessary merge commits into your history.&lt;/p&gt;
&lt;h2 id="rebase-instead-of-merge"&gt;Rebase instead of merge&lt;/h2&gt;
&lt;p&gt;If you need to incorporate changes from the upstream &lt;code&gt;master&lt;/code&gt; branch in the feature branch on which you are currently doing, bring in those changes using &lt;code&gt;git rebase&lt;/code&gt; rather than &lt;code&gt;git merge&lt;/code&gt;. This process will generally start by ensuring that your local copy of the upstream &lt;code&gt;master&lt;/code&gt; is current:&lt;/p&gt;</description></item><item><title>Running Keystone with Docker Compose</title><link>https://blog.oddbit.com/post/2019-06-07-running-keystone-with-docker-c/</link><pubDate>Fri, 07 Jun 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-06-07-running-keystone-with-docker-c/</guid><description>&lt;p&gt;In this article, we will look at what is necessary to run OpenStack&amp;rsquo;s &lt;a href="https://docs.openstack.org/keystone/latest/"&gt;Keystone&lt;/a&gt; service (and the requisite database server) in containers using &lt;a href="https://docs.docker.com/compose/"&gt;Docker Compose&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="running-mariadb"&gt;Running MariaDB&lt;/h2&gt;
&lt;p&gt;The standard &lt;a href="https://hub.docker.com/_/mariadb/"&gt;mariadb docker image&lt;/a&gt; can be configured via a number of environment variables. It also benefits from persistent volume storage, since in most situations you don&amp;rsquo;t want to lose your data when you remove a container. A simple &lt;code&gt;docker&lt;/code&gt; command line for starting MariaDB might look something like:&lt;/p&gt;</description></item><item><title>A DIY CPAP Battery Box</title><link>https://blog.oddbit.com/post/2019-05-14-a-diy-cpap-battery-box/</link><pubDate>Tue, 14 May 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-05-14-a-diy-cpap-battery-box/</guid><description>&lt;p&gt;A year or so ago I was diagnosed with &lt;a href="https://en.wikipedia.org/wiki/Sleep_apnea"&gt;sleep apnea&lt;/a&gt;, and since them I&amp;rsquo;ve been sleeping with a &lt;a href="https://en.wikipedia.org/wiki/Continuous_positive_airway_pressure"&gt;CPAP&lt;/a&gt;. This past weekend, I joined my daughter on a &lt;a href="https://www.scouting.org/scoutsbsa/"&gt;scout&lt;/a&gt; camping trip to a &lt;a href="https://www.mass.gov/locations/harold-parker-state-forest"&gt;campground&lt;/a&gt; without readily accessible electricity. This would be the first time I found myself in this situation, and as the date approached, I realized I was going to have to build or buy some sort of battery solution for my CPAP. I opted for the &amp;ldquo;build&amp;rdquo; option because it seemed like a fun project.&lt;/p&gt;</description></item><item><title>Unpacking a Python regular expression</title><link>https://blog.oddbit.com/post/2019-05-07-unpacking-a-python-regular-exp/</link><pubDate>Tue, 07 May 2019 10:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-05-07-unpacking-a-python-regular-exp/</guid><description>&lt;p&gt;I recently answered &lt;a href="https://stackoverflow.com/q/55965819/147356"&gt;a question&lt;/a&gt; from &lt;a href="https://stackoverflow.com/users/7738974/harsha-nalore"&gt;Harsha Nalore&lt;/a&gt; on &lt;a href="https://stackoverflow.com/"&gt;StackOverflow&lt;/a&gt; that involved using Ansible to extract the output of a command sent to a BigIP device of some sort. My solution &amp;ndash; which I claim to be functional, but probably not optimal &amp;ndash; involved writing an &lt;a href="https://ansible.com/"&gt;Ansible&lt;/a&gt; filter module to parse the output. That filter made use of a complex-looking regular expression. Harsha asked for some details on that regular expression works, and the existing StackOverflow answer didn&amp;rsquo;t really seem the write place for that: so, here we are.&lt;/p&gt;</description></item><item><title>New comment system</title><link>https://blog.oddbit.com/post/2019-05-07-new-comment-system/</link><pubDate>Tue, 07 May 2019 09:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-05-07-new-comment-system/</guid><description>&lt;p&gt;As long as I&amp;rsquo;m switching site generators, it seems like a good idea to refresh the comment system as well. I&amp;rsquo;ve been using &lt;a href="https://disqus.com"&gt;Disqus&lt;/a&gt; for a while, since when I started it was one of the only games in town. There are now alternatives of different sorts, and one in particular caught my eye: &lt;a href="https://utteranc.es/"&gt;Utterances&lt;/a&gt; uses GitHub issues for storing comments, which seems like a fantastic idea.&lt;/p&gt;
&lt;p&gt;That means that comments will finally be stored in the same place as the blog content, which I think is a happy state of affairs.&lt;/p&gt;</description></item><item><title>New static site generator</title><link>https://blog.oddbit.com/post/2019-05-06-new-static-site-generator/</link><pubDate>Mon, 06 May 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-05-06-new-static-site-generator/</guid><description>&lt;p&gt;I&amp;rsquo;ve switched my static site generator from &lt;a href="https://blog.getpelican.com/"&gt;Pelican&lt;/a&gt; to &lt;a href="https://gohugo.io/"&gt;Hugo&lt;/a&gt;. I&amp;rsquo;ve tried to ensure that all the old links continue to work correctly, but if you notice anything missing or otherwise not working as intended, please let me know by &lt;a href="https://github.com/larsks/blog.oddbit.com/issues"&gt;opening an issue&lt;/a&gt;. Thanks!&lt;/p&gt;</description></item><item><title>Adding support for privilege escalation to Ansible's docker connection driver</title><link>https://blog.oddbit.com/post/2019-04-26-adding-support-for-privilege-e/</link><pubDate>Fri, 26 Apr 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-04-26-adding-support-for-privilege-e/</guid><description>&lt;p&gt;&lt;strong&gt;Update 2019-05-09&lt;/strong&gt; Pull request 
&lt;a href="https://github.com/ansible/ansible/pull/55816" class="pull-request"&gt;#55816&lt;/a&gt;
 has merged, so you can now use &lt;code&gt;sudo&lt;/code&gt; with the &lt;code&gt;docker&lt;/code&gt; connection driver even when &lt;code&gt;sudo&lt;/code&gt; is configured to require a password.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I often use Docker to test out Ansible playbooks. While normally that works great, I recently ran into an unexpected problem with privilege escalation. Given a simple playbook like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;---
- hosts: all
 gather_facts: false
 become: true
 tasks:
 - ping:
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And an inventory like this:&lt;/p&gt;</description></item><item><title>Writing Ansible filter plugins</title><link>https://blog.oddbit.com/post/2019-04-25-writing-ansible-filter-plugins/</link><pubDate>Thu, 25 Apr 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-04-25-writing-ansible-filter-plugins/</guid><description>&lt;p&gt;I often see questions from people who are attemping to perform complex text transformations in their &lt;a href="https://www.ansible.com/"&gt;Ansible&lt;/a&gt; playbooks. While I am a huge fan of Ansible, data transformation is not one of its strong points. For example, this past week someone &lt;a href="https://stackoverflow.com/questions/55853384/ansible-build-list-dictionary-with-from-list-of-strings/55854394"&gt;asked a question&lt;/a&gt; on Stack Overflow in which they were attempting to convert the output of the &lt;a href="https://docs.oracle.com/javase/8/docs/technotes/tools/unix/keytool.html"&gt;keytool&lt;/a&gt; command into a list of dictionaries. The output of the &lt;code&gt;keytool -list -v&lt;/code&gt; command looks something like this:&lt;/p&gt;</description></item><item><title>Docker build learns about secrets and ssh agent forwarding</title><link>https://blog.oddbit.com/post/2019-02-24-docker-build-learns-about-secr/</link><pubDate>Sun, 24 Feb 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-02-24-docker-build-learns-about-secr/</guid><description>&lt;p&gt;A common problem for folks working with Docker is accessing resources which require authentication during the image build step. A particularly common use case is getting access to private git repositories using ssh key-based authentication. Until recently there hasn&amp;rsquo;t been a great solution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;you can embed secrets in your image, but now you can&amp;rsquo;t share the image with anybody.&lt;/li&gt;
&lt;li&gt;you can use build arguments, but this requires passing in an unenecrypted private key on the &lt;code&gt;docker build&lt;/code&gt; command line, which is suboptimal for a number of reasons&lt;/li&gt;
&lt;li&gt;you can perform all the steps requiring authentication at runtime, but this can needlessly complicate your container startup process.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With Docker 18.09, there are some experimental features available that makes this much easier. You can read the official announcement &lt;a href="https://docs.docker.com/develop/develop-images/build_enhancements/"&gt;here&lt;/a&gt;, but I wanted to highlight the support for ssh agent forwarding and private keys.&lt;/p&gt;</description></item><item><title>In which I PEBKAC so you don't have to</title><link>https://blog.oddbit.com/post/2019-02-11-in-which-i-pebkac-so-you-dont-/</link><pubDate>Mon, 11 Feb 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-02-11-in-which-i-pebkac-so-you-dont-/</guid><description>&lt;p&gt;Say you have a simple bit of code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &amp;lt;avr/io.h&amp;gt;
#include &amp;lt;util/delay.h&amp;gt; 

#define LED_BUILTIN _BV(PORTB5)

int main(void) 
{
 DDRB |= LED_BUILTIN;

 while (1)
 {
 PORTB |= LED_BUILTIN; // turn on led
 _delay_ms(1000); // delay 1s

 PORTB &amp;amp;= ~LED_BUILTIN; // turn off led
 _delay_ms(1000); // delay 1s
 } 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You have a Makefile that compiles that into an object (&lt;code&gt;.o&lt;/code&gt;) file like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;avr-gcc -mmcu=atmega328p -DF_CPU=16000000 -Os -c blink.c
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you were to forget to set the device type when compiling your &lt;code&gt;.c&lt;/code&gt; file into an object file (&lt;code&gt;.o&lt;/code&gt;), you would get a warning:&lt;/p&gt;</description></item><item><title>ATOMIC_BLOCK magic in avr-libc</title><link>https://blog.oddbit.com/post/2019-02-01-atomicblock-magic-in-avrlibc/</link><pubDate>Fri, 01 Feb 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-02-01-atomicblock-magic-in-avrlibc/</guid><description>&lt;p&gt;The AVR C library, &lt;a href="https://www.nongnu.org/avr-libc/"&gt;avr-libc&lt;/a&gt;, provide an &lt;code&gt;ATOMIC_BLOCK&lt;/code&gt; macro that you can use to wrap critical sections of your code to ensure that interrupts are disabled while the code executes. At high level, the &lt;code&gt;ATOMIC_BLOCK&lt;/code&gt; macro (when called using &lt;code&gt;ATOMIC_FORCEON&lt;/code&gt;) does something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cli();

...your code here...

seti();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But it&amp;rsquo;s more than that. If you read &lt;a href="https://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html#gaaaea265b31dabcfb3098bec7685c39e4"&gt;the documentation&lt;/a&gt; for the macro, it says:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Creates a block of code that is guaranteed to be executed atomically. Upon entering the block the Global Interrupt Status flag in SREG is disabled, and re-enabled upon exiting the block &lt;strong&gt;from any exit path&lt;/strong&gt;.&lt;/p&gt;</description></item><item><title>AVR micro-optimization: Avr-gcc and --short-enums</title><link>https://blog.oddbit.com/post/2019-01-28-avr-gcc-short-enums/</link><pubDate>Mon, 28 Jan 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-01-28-avr-gcc-short-enums/</guid><description>&lt;h2 id="how-big-is-an-enum"&gt;How big is an enum?&lt;/h2&gt;
&lt;p&gt;I noticed something odd while browsing through the assembly output of some AVR C code &lt;a href="https://blog.oddbit.com/post/2019-01-19-pipower-a-raspberry-pi-ups/"&gt;I wrote recently&lt;/a&gt;. In the code, I have the following expression:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;int main() {
 setup();

 while (state != STATE_QUIT) {
 loop();
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, &lt;code&gt;state&lt;/code&gt; is a variable of type &lt;code&gt;enum STATE&lt;/code&gt;, which looks something like this (not exactly like this; there are actually &lt;a href="https://github.com/larsks/pipower/blob/master/states.h"&gt;19 possible values&lt;/a&gt; but I didn&amp;rsquo;t want to clutter this post with unnecessary code listings):&lt;/p&gt;</description></item><item><title>AVR micro-optimization: Losing malloc</title><link>https://blog.oddbit.com/post/2019-01-28-losing-malloc/</link><pubDate>Mon, 28 Jan 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-01-28-losing-malloc/</guid><description>&lt;p&gt;Pssst! Hey&amp;hellip;hey, buddy, wanna get an extra KB for cheap?&lt;/p&gt;
&lt;p&gt;When I write OO-style code in C, I usually start with something like the following, in which I use &lt;code&gt;malloc()&lt;/code&gt; to allocate memory for a variable of a particular type, perform some initialization actions, and then return it to the caller:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Button *button_new(uint8_t pin, uint8_t poll_freq) {
 Button *button = (Button *)malloc(sizeof(Button));
 // do some initialization stuff

 return button;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And when initially writing &lt;a href="https://blog.oddbit.com/post/2019-01-19-pipower-a-raspberry-pi-ups/"&gt;pipower&lt;/a&gt;, that&amp;rsquo;s exactly what I did. But while thinking about it after the fact, I realized the following:&lt;/p&gt;</description></item><item><title>Debugging attiny85 code, part 1: simavr and gdb</title><link>https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-1/</link><pubDate>Tue, 22 Jan 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-1/</guid><description>&lt;p&gt;In a case of awful timing, after my &lt;a href="https://blog.oddbit.com/2019/01/19/pipower-a-raspberry-pi-ups/"&gt;recent project involving some attiny85 programming&lt;/a&gt; I finally got around to learning how to use &lt;a href="https://github.com/buserror/simavr"&gt;simavr&lt;/a&gt; and &lt;code&gt;gdb&lt;/code&gt; to help debug my AVR code. It was too late for me (and I will never get the time back that I spent debugging things with an LED and lots of re-flashing), but maybe this will help someone else!&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve split this into three posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-1/"&gt;Part 1: Using GDB&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Debugging attiny85 code, part 2: Automating GDB with scripts</title><link>https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-2/</link><pubDate>Tue, 22 Jan 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-2/</guid><description>&lt;p&gt;This is the second of three posts about using &lt;code&gt;gdb&lt;/code&gt; and &lt;code&gt;simavr&lt;/code&gt; to debug AVR code. The complete series is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-1/"&gt;Part 1: Using GDB&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A walkthrough of using GDB to manually inspect the behavior of our code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-2/"&gt;Part 2: Automating GDB with scripts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Creating GDB scripts to automatically test the behavior of our code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-3/"&gt;Part 3: Tracing with simavr&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;simavr&lt;/code&gt; to collect information about the state of microcontroller pins while our code is running.&lt;/p&gt;</description></item><item><title>Debugging attiny85 code, part 3: Tracing with simavr</title><link>https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-3/</link><pubDate>Tue, 22 Jan 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-3/</guid><description>&lt;figure&gt;&lt;a href="pipower_trace.png"&gt;&lt;img src="https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-3/pipower_trace.png" width="800"&gt;&lt;/a&gt;
&lt;/figure&gt;

&lt;p&gt;This is the third of three posts about using &lt;code&gt;gdb&lt;/code&gt; and &lt;code&gt;simavr&lt;/code&gt; to debug AVR code. The complete series is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-1/"&gt;Part 1: Using GDB&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A walkthrough of using GDB to manually inspect the behavior of our code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-2/"&gt;Part 2: Automating GDB with scripts&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Creating GDB scripts to automatically test the behavior of our code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://blog.oddbit.com/post/2019-01-22-debugging-attiny-code-pt-3/"&gt;Part 3: Tracing with simavr&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;simavr&lt;/code&gt; to collect information about the state of microcontroller pins while our code is running.&lt;/p&gt;</description></item><item><title>PiPower: A Raspberry Pi UPS</title><link>https://blog.oddbit.com/post/2019-01-19-pipower-a-raspberry-pi-ups/</link><pubDate>Sat, 19 Jan 2019 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2019-01-19-pipower-a-raspberry-pi-ups/</guid><description>&lt;figure&gt;&lt;a href="pipower-top.jpg"&gt;&lt;img src="https://blog.oddbit.com/post/2019-01-19-pipower-a-raspberry-pi-ups/pipower-top.jpg" width="400"&gt;&lt;/a&gt;
&lt;/figure&gt;

&lt;p&gt;I have a Raspberry Pi running &lt;a href="https://retropie.org.uk/"&gt;RetroPie&lt;/a&gt; hooked up to a television. It&amp;rsquo;s powered from a USB port on the TV, which is convenient, but it means that whenever we shut off the TV we&amp;rsquo;re pulling the plug on the Pi. While there haven&amp;rsquo;t been any problems so far, this is a classic recipe for filesystem problems or data loss at some point. I started looking into UPS options to alleviate this issue. I wanted something with the following features:&lt;/p&gt;</description></item><item><title>Integrating Bitwarden with Ansible</title><link>https://blog.oddbit.com/post/2018-10-19-integrating-bitwarden-with-ans/</link><pubDate>Fri, 19 Oct 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-10-19-integrating-bitwarden-with-ans/</guid><description>&lt;p&gt;&lt;a href="https://bitwarden.com"&gt;Bitwarden&lt;/a&gt; is a password management service (like &lt;a href="https://www.lastpass.com/"&gt;LastPass&lt;/a&gt; or
&lt;a href="https://1password.com/"&gt;1Password&lt;/a&gt;). It&amp;rsquo;s unique in that it is built entirely on open
source software. In addition to the the web UI and mobile apps that
you would expect, Bitwarden also provides a &lt;a href="https://help.bitwarden.com/article/cli/"&gt;command-line tool&lt;/a&gt; for
interacting with the your password store.&lt;/p&gt;
&lt;p&gt;At $WORK(-ish) we&amp;rsquo;re looking into Bitwarden because we want a password
sharing and management solution that was better than dropping files
into directories on remote hosts or sharing things over Slack. At
the same time, we are also thinking about bringing more automation to
our operational environment, possibly by making more extensive use of
&lt;a href="https://ansible.com"&gt;Ansible&lt;/a&gt;. It looked like all the pieces were available to use
Bitwarden as a credential storage mechanism for Ansible playbooks, so
I set out to write a lookup plugin to implement the integration&amp;hellip;&lt;/p&gt;</description></item><item><title>Systemd unit for managing USB gadgets</title><link>https://blog.oddbit.com/post/2018-10-19-systemd-unit-for-managing-usb-/</link><pubDate>Fri, 19 Oct 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-10-19-systemd-unit-for-managing-usb-/</guid><description>&lt;p&gt;The Pi Zero (and Zero W) have support for acting as a USB &lt;a href="http://www.linux-usb.org/gadget/"&gt;gadget&lt;/a&gt;:
that means that they can be configured to act as a USB device &amp;ndash; like
a serial port, an ethernet interface, a mass storage device, etc.&lt;/p&gt;
&lt;p&gt;There are two different ways of configuring this support. The first
only allows you to configure a single type of gadget at a time, and
boils down to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enable the dwc2 overlay in &lt;code&gt;/boot/config.txt&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Reboot.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;modprobe g_serial&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This process is more fully documented &lt;a href="https://learn.adafruit.com/turning-your-raspberry-pi-zero-into-a-usb-gadget/overview"&gt;here&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Configuring a static address for wlan0 on Raspbian Stretch</title><link>https://blog.oddbit.com/post/2018-06-14-configuring-a-static-address-f/</link><pubDate>Thu, 14 Jun 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-06-14-configuring-a-static-address-f/</guid><description>&lt;p&gt;Recent releases of Raspbian have adopted the use of &lt;a href="http://manpages.ubuntu.com/manpages/trusty/man8/dhcpcd5.8.html"&gt;dhcpcd&lt;/a&gt; to
manage both dynamic and static interface configuration. If you would
prefer to use the traditional &lt;code&gt;/etc/network/interfaces&lt;/code&gt; mechanism
instead, follow these steps.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, disable &lt;code&gt;dhcpcd&lt;/code&gt; and &lt;code&gt;wpa_supplicant&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; systemctl disable --now dhdpcd wpa_supplicant
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You will need a &lt;code&gt;wpa_supplicant&lt;/code&gt; configuration for &lt;code&gt;wlan0&lt;/code&gt; in
&lt;code&gt;/etc/wpa_supplicant/wpa_supplicant-wlan0.conf&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you already have an appropriate configuration in
&lt;code&gt;/etc/wpa_supplicant/wpa_supplicant.conf&lt;/code&gt;, you can just symlink the
file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; cd /etc/wpa_supplicant
 ln -s wpa_supplicant.conf wpa_supplicant-wlan0.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enable the &lt;code&gt;wpa_supplicant&lt;/code&gt; service for &lt;code&gt;wlan0&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Using a TM1637 LED module with CircuitPython</title><link>https://blog.oddbit.com/post/2018-05-03-using-a-tm-led-module-with-cir/</link><pubDate>Thu, 03 May 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-05-03-using-a-tm-led-module-with-cir/</guid><description>&lt;p&gt;&lt;a href="https://learn.adafruit.com/welcome-to-circuitpython/overview"&gt;CircuitPython&lt;/a&gt; is &amp;ldquo;an education friendly open source derivative of
&lt;a href="https://micropython.org/"&gt;MicroPython&lt;/a&gt;&amp;rdquo;. MicroPython is a port of Python to microcontroller
environments; it can run on boards with very few resources such as the
&lt;a href="https://en.wikipedia.org/wiki/ESP8266"&gt;ESP8266&lt;/a&gt;. I&amp;rsquo;ve recently started experimenting with CircuitPython
on a &lt;a href="https://wiki.wemos.cc/products:d1:d1_mini"&gt;Wemos D1 mini&lt;/a&gt;, which is a small form-factor ESP8266 board.&lt;/p&gt;
&lt;p&gt;I had previously been using Mike Causer&amp;rsquo;s &lt;a href="https://github.com/mcauser/micropython-tm1637/"&gt;micropython-tm1637&lt;/a&gt; for
MicroPython to drive a &lt;a href="http://a.co/gQVPtPr"&gt;4 digit LED display&lt;/a&gt;. I was hoping to
get the same code working under CircuitPython, but when I tried to
build an image that included the &lt;code&gt;tm1637&lt;/code&gt; module I ran into:&lt;/p&gt;</description></item><item><title>Multiple 1-Wire Buses on the Raspberry Pi</title><link>https://blog.oddbit.com/post/2018-03-27-multiple-1-wire-buses-on-the-/</link><pubDate>Tue, 27 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-03-27-multiple-1-wire-buses-on-the-/</guid><description>&lt;p&gt;The DS18B20 is a popular temperature sensor that uses the &lt;a href="https://en.wikipedia.org/wiki/1-Wire"&gt;1-Wire&lt;/a&gt;
protocol for communication. Recent versions of the Linux kernel
include a kernel driver for this protocol, making it relatively
convenient to connect one or more of these devices to a Raspberry Pi
or similar device. 1-Wire devices can be daisy chained, so it is
possible to connect several devices to your Pi using only a single
GPIO pin, and you&amp;rsquo;ll find many articles out there that describe how to
do so.&lt;/p&gt;</description></item><item><title>Using Docker macvlan networks</title><link>https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/</link><pubDate>Mon, 12 Mar 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-03-12-using-docker-macvlan-networks/</guid><description>&lt;p&gt;A question that crops up regularly on &lt;a href="https://docs.docker.com/opensource/ways/#docker-users"&gt;#docker&lt;/a&gt; is &amp;ldquo;How do I attach
a container directly to my local network?&amp;rdquo; One possible answer to that
question is the &lt;a href="https://docs.docker.com/network/macvlan/"&gt;macvlan&lt;/a&gt; network type, which lets you create
&amp;ldquo;clones&amp;rdquo; of a physical interface on your host and use that to attach
containers directly to your local network. For the most part it works
great, but it does come with some minor caveats and limitations. I
would like to explore those here.&lt;/p&gt;</description></item><item><title>Listening for connections on all ports/any port</title><link>https://blog.oddbit.com/post/2018-02-27-listening-for-connections-on-a/</link><pubDate>Tue, 27 Feb 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-02-27-listening-for-connections-on-a/</guid><description>&lt;p&gt;On &lt;a href="https://en.wikipedia.org/wiki/Internet_Relay_Chat"&gt;IRC&lt;/a&gt; &amp;ndash; and other online communities &amp;ndash; it is common to use a
&amp;ldquo;pastebin&amp;rdquo; service to share snippets of code, logs, and other
material, rather than pasting them directly into a conversation.
These services will typically return a URL that you can share with
others so that they can see the content in their browser.&lt;/p&gt;
&lt;p&gt;One of my favorite pastebin services is &lt;a href="http://termbin.com"&gt;termbin.com&lt;/a&gt;, because it
works from the command line using tools you probably already have
installed. Termbin runs the &lt;a href="https://github.com/solusipse/fiche"&gt;fiche&lt;/a&gt; service, which listens for TCP
connections on port 9999, reads any content that you provide, and then
returns a URL. For example, if I wanted to share my &lt;code&gt;iptables&lt;/code&gt;
configuration with someone I could just run:&lt;/p&gt;</description></item><item><title>Grouping aggregation queries in Gnocchi 4.0.x</title><link>https://blog.oddbit.com/post/2018-02-26-grouping-aggregation-queries-i/</link><pubDate>Mon, 26 Feb 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-02-26-grouping-aggregation-queries-i/</guid><description>&lt;p&gt;In this article, we&amp;rsquo;re going to ask Gnocchi (the OpenStack telemetry
storage service) how much memory was used, on average, over the course
of each day by each project in an OpenStack environment.&lt;/p&gt;
&lt;h2 id="environment"&gt;Environment&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;m working with an OpenStack &amp;ldquo;Pike&amp;rdquo; deployment, which means I have
Gnocchi 4.0.x. More recent versions of Gnocchi (4.1.x and later) have
a new aggregation API called &lt;a href="https://gnocchi.xyz/rest.html#dynamic-aggregates"&gt;dynamic aggregates&lt;/a&gt;, but that isn&amp;rsquo;t
available in 4.0.x so in this article we&amp;rsquo;ll be using the legacy
&lt;code&gt;/v1/aggregations&lt;/code&gt; API.&lt;/p&gt;</description></item><item><title>Listing iptables rules with line numbers</title><link>https://blog.oddbit.com/post/2018-02-08-listing-iptables-rules-with-li/</link><pubDate>Thu, 08 Feb 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-02-08-listing-iptables-rules-with-li/</guid><description>&lt;p&gt;You can list &lt;code&gt;iptables&lt;/code&gt; rules with rule numbers using the
&lt;code&gt;--line-numbers&lt;/code&gt; option, but this only works in list (&lt;code&gt;-L&lt;/code&gt;) mode. I
find it much more convenient to view rules using the output from
&lt;code&gt;iptables -S&lt;/code&gt; or &lt;code&gt;iptables-save&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You can augment the output from these commands with rule numbers with
the following &lt;code&gt;awk&lt;/code&gt; script:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/awk -f

state == 0 &amp;amp;&amp;amp; /^-A/ {state=1; chain=$2; counter=1; printf &amp;quot;\n&amp;quot;}
state == 1 &amp;amp;&amp;amp; $2 != chain {chain=$2; counter=1; printf &amp;quot;\n&amp;quot;}
!/^-A/ {state=0}
state == 1 {printf &amp;quot;[%03d] %s\n&amp;quot;, counter++, $0}
state == 0 {print}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will produce output along the lines of:&lt;/p&gt;</description></item><item><title>Pelican and theme update</title><link>https://blog.oddbit.com/post/2018-01-26-pelican-theme-update/</link><pubDate>Fri, 26 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-01-26-pelican-theme-update/</guid><description>&lt;p&gt;I&amp;rsquo;ve just refreshed the version of &lt;a href="https://github.com/getpelican/pelican"&gt;Pelican&lt;/a&gt; used to generate this
blog, along with the associated themes and plugins. It all seems to be
working, but if you spot a problem feel free to &lt;a href="https://github.com/larsks/blog.oddbit.com/issues"&gt;drop me a line&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Fun with devicemapper snapshots</title><link>https://blog.oddbit.com/post/2018-01-25-fun-with-devicemapper-snapshot/</link><pubDate>Thu, 25 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-01-25-fun-with-devicemapper-snapshot/</guid><description>&lt;p&gt;I find myself working with &lt;a href="https://www.raspberrypi.org/downloads/raspbian/"&gt;Raspbian&lt;/a&gt; disk images fairly often. A
typical workflow is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Download the disk image.&lt;/li&gt;
&lt;li&gt;Mount the filesystem somewhere to check something.&lt;/li&gt;
&lt;li&gt;Make some changes or install packages just to check something else.&lt;/li&gt;
&lt;li&gt;Crap I&amp;rsquo;ve made changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;hellip;at which point I need to fetch a new copy of the image next time I
want to start fresh.&lt;/p&gt;
&lt;p&gt;Sure, I could just make a copy of the image and work from there, but
what fun is that? This seemed like a perfect opportunity to learn more
about the &lt;a href="https://www.kernel.org/doc/Documentation/device-mapper/"&gt;device mapper&lt;/a&gt; and in particular how the &lt;a href="https://www.kernel.org/doc/Documentation/device-mapper/snapshot.txt"&gt;snapshot&lt;/a&gt;
target works.&lt;/p&gt;</description></item><item><title>Safely restarting an OpenStack server with Ansible</title><link>https://blog.oddbit.com/post/2018-01-24-safely-restarting-an-openstack/</link><pubDate>Wed, 24 Jan 2018 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2018-01-24-safely-restarting-an-openstack/</guid><description>&lt;p&gt;The other day on &lt;a href="http://docs.ansible.com/ansible/latest/community.html#irc-channel"&gt;#ansible&lt;/a&gt;, someone was looking for a way to safely
shut down a Nova server, wait for it to stop, and then start it up
again using the &lt;code&gt;openstack&lt;/code&gt; cli. The first part seemed easy:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;- hosts: myserver
 tasks:
 - name: shut down the server
 command: poweroff
 become: true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;hellip;but that will actually fail with the following result:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;TASK [shut down server] *************************************
fatal: [myserver]: UNREACHABLE! =&amp;gt; {&amp;quot;changed&amp;quot;: false, &amp;quot;msg&amp;quot;:
&amp;quot;Failed to connect to the host via ssh: Shared connection to
10.0.0.103 closed.\r\n&amp;quot;, &amp;quot;unreachable&amp;quot;: true}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This happens because running &lt;code&gt;poweroff&lt;/code&gt; immediately closes Ansible&amp;rsquo;s
ssh connection. The workaround here is to use a &amp;ldquo;fire-and-forget&amp;rdquo;
&lt;a href="http://docs.ansible.com/ansible/latest/playbooks_async.html"&gt;asynchronous task&lt;/a&gt;:&lt;/p&gt;</description></item><item><title>Some notes on PWM on the Raspberry Pi</title><link>https://blog.oddbit.com/post/2017-09-26-some-notes-on-pwm-on-the-raspb/</link><pubDate>Tue, 26 Sep 2017 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2017-09-26-some-notes-on-pwm-on-the-raspb/</guid><description>&lt;p&gt;I was recently working on a project in which I wanted to drive a
simple &lt;a href="https://www.adafruit.com/product/160"&gt;piezo buzzer&lt;/a&gt; attached to a GPIO pin on a Raspberry Pi. I
was already using the &lt;a href="https://pypi.python.org/pypi/RPi.GPIO"&gt;RPi.GPIO&lt;/a&gt; module in my project so that seemed
like a logical place to start, but I ran into a few issues.&lt;/p&gt;
&lt;p&gt;You drive a piezo buzzer by generating a &lt;a href="https://learn.sparkfun.com/tutorials/pulse-width-modulation"&gt;PWM&lt;/a&gt; signal with the
appropriate frequency. The &lt;code&gt;RPi.GPIO&lt;/code&gt; module implements PWM via
software, which is tricky on a non-realtime system. It&amp;rsquo;s difficult to
get the timing completely accurate, which results in sounds that are a
little wobbly at best. Since I&amp;rsquo;m simply generating tones with a
buzzer (rather than, say, controlling a servo) this is mostly just an
annoyance.&lt;/p&gt;</description></item><item><title>Ansible for Infrastructure Testing</title><link>https://blog.oddbit.com/post/2017-08-02-ansible-for-infrastructure-tes/</link><pubDate>Wed, 02 Aug 2017 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2017-08-02-ansible-for-infrastructure-tes/</guid><description>&lt;p&gt;At &lt;code&gt;$JOB&lt;/code&gt; we often find ourselves at customer sites where we see the
same set of basic problems that we have previously encountered
elsewhere (&amp;ldquo;your clocks aren&amp;rsquo;t in sync&amp;rdquo; or &amp;ldquo;your filesystem is full&amp;rdquo;
or &amp;ldquo;you haven&amp;rsquo;t installed a critical update&amp;rdquo;, etc). We would like a
simple tool that could be run either by the customer or by our own
engineers to test for and report on these common issues.
Fundamentally, we want something that acts like a typical code test
suite, but for infrastructure.&lt;/p&gt;</description></item><item><title>Better bulk filtering for Gmail</title><link>https://blog.oddbit.com/post/2017-07-07-better-bulk-filtering-for-gmai/</link><pubDate>Fri, 07 Jul 2017 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2017-07-07-better-bulk-filtering-for-gmai/</guid><description>&lt;p&gt;I use Gmail extensively for my personal email, and recently my
workplace has been migrated over to Gmail as well. I find that for my
work email I rely much more extensively on filters and labels to
organize things (like zillions of internal and upstream mailing
lists), and that has posed some challenges. While Gmail is in general
fairly snappy, attempting to apply an action to thousands of messages
(for example, trying to mark 16000 messages as &amp;ldquo;read&amp;rdquo;, or applying a
new filter to all your existing messages) results in a very poor
experience: it is not possible to interact with Gmail (in the same
tab) while the action is running, and frequently actions will timeout.&lt;/p&gt;</description></item><item><title>OpenStack, Containers, and Logging</title><link>https://blog.oddbit.com/post/2017-06-14-openstack-containers-and-loggi/</link><pubDate>Wed, 14 Jun 2017 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2017-06-14-openstack-containers-and-loggi/</guid><description>&lt;p&gt;I&amp;rsquo;ve been thinking about logging in the context of OpenStack and containerized service deployments. I&amp;rsquo;d like to lay out some of my thoughts on this topic and see if people think I am talking crazy or not.&lt;/p&gt;
&lt;p&gt;There are effectively three different mechanisms that an application can use to emit log messages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Via some logging-specific API, such as the legacy syslog API&lt;/li&gt;
&lt;li&gt;By writing a byte stream to stdout/stderr&lt;/li&gt;
&lt;li&gt;By writing a byte stream to a file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A substantial advantage to the first mechanism (using a logging API) is that the application is logging &lt;em&gt;messages&lt;/em&gt; rather than &lt;em&gt;bytes&lt;/em&gt;. This means that if you log a message containing embedded newlines (e.g., python or java tracebacks), you can collect that as a single message rather than having to impose some sort of structure on the byte stream after the fact in order to reconstruct those message.&lt;/p&gt;</description></item><item><title>FAA Cannot Require Drone Registration</title><link>https://blog.oddbit.com/post/2017-05-25-faa-cannot-require-drone-regis/</link><pubDate>Thu, 25 May 2017 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2017-05-25-faa-cannot-require-drone-regis/</guid><description>&lt;p&gt;This is now old news if you&amp;rsquo;re already following the drone industry,
but if you&amp;rsquo;re not, I&amp;rsquo;d like to highlight a recent decision made by the
US Court of Appeals regarding the FAA&amp;rsquo;s drone registration
requirements.&lt;/p&gt;
&lt;p&gt;To place this in context, back in 2015 the FAA established a new set
of regulations (the &amp;ldquo;Registration Rule&amp;rdquo;) requiring anyone with a UAV
(&amp;ldquo;unmanned aerial vehicle&amp;rdquo;, or &amp;ldquo;drone&amp;rdquo;) weighing between 0.5 and 55
lbs to register with the FAA. Unfortunately, the 2012 &lt;a href="https://www.congress.gov/bill/112th-congress/house-bill/658/text"&gt;FAA
Modernization and Reform Act says&lt;/a&gt; says (in section 336(a)):&lt;/p&gt;</description></item><item><title>Making sure your Gerrit changes aren't broken</title><link>https://blog.oddbit.com/post/2017-01-22-making-sure-your-gerrit-change/</link><pubDate>Sun, 22 Jan 2017 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2017-01-22-making-sure-your-gerrit-change/</guid><description>&lt;p&gt;It&amp;rsquo;s a bit of an embarrassment when you submit a review to Gerrit only
to have it fail CI checks immediately because of something as simple
as a syntax error or pep8 failure that you should have caught yourself
before submitting&amp;hellip;but you forgot to run your validations before
submitting the change.&lt;/p&gt;
&lt;p&gt;In many cases you can alleviate this through the use of the git
&lt;code&gt;pre-commit&lt;/code&gt; hook, which will run every time you commit changes
locally. You can have the hook run &lt;code&gt;tox&lt;/code&gt; or whatever tool your
project uses for validation on every commit. This works okay for
simple cases, but if the validation takes more than a couple of
seconds the delay can be disruptive to the flow of your work.&lt;/p&gt;</description></item><item><title>Exploring YAQL Expressions</title><link>https://blog.oddbit.com/post/2016-08-11-exploring-yaql-expressions/</link><pubDate>Thu, 11 Aug 2016 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2016-08-11-exploring-yaql-expressions/</guid><description>&lt;p&gt;The Newton release of &lt;a href="https://wiki.openstack.org/wiki/Heat"&gt;Heat&lt;/a&gt; adds support for a &lt;a href="http://docs.openstack.org/developer/heat/template_guide/hot_spec.html#yaql"&gt;yaql&lt;/a&gt;
intrinsic function, which allows you to evaluate &lt;a href="https://yaql.readthedocs.io/en/latest/"&gt;yaql&lt;/a&gt; expressions
in your Heat templates. Unfortunately, the existing yaql
documentation is somewhat limited, and does not offer examples of many
of yaql&amp;rsquo;s more advanced features.&lt;/p&gt;
&lt;p&gt;I am working on a &lt;a href="http://www.fluentd.org/"&gt;Fluentd&lt;/a&gt; composable service for &lt;a href="https://wiki.openstack.org/wiki/TripleO"&gt;TripleO&lt;/a&gt;. I
want to allow each service to specify a logging source configuration
fragment, for example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;parameters:
 NovaAPILoggingSource:
 type: json
 description: Fluentd logging configuration for nova-api.
 default:
 tag: openstack.nova.api
 type: tail
 format: |
 /(?&amp;lt;time&amp;gt;\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d+) (?&amp;lt;pid&amp;gt;\d+) (?&amp;lt;priority&amp;gt;\S+) (?&amp;lt;message&amp;gt;.*)/
 path: /var/log/nova/nova-api.log
 pos_file: /var/run/fluentd/openstack.nova.api.pos
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This generally works, but several parts of this fragment are going to
be the same across all OpenStack services. I wanted to reduce the
above to just the unique attributes, which would look something like:&lt;/p&gt;</description></item><item><title>Connecting another vm to your tripleo-quickstart deployment</title><link>https://blog.oddbit.com/post/2016-05-19-connecting-another-vm-to-your-/</link><pubDate>Thu, 19 May 2016 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2016-05-19-connecting-another-vm-to-your-/</guid><description>&lt;p&gt;Let&amp;rsquo;s say that you have set up an environment using
&lt;a href="https://github.com/openstack/tripleo-quickstart/"&gt;tripleo-quickstart&lt;/a&gt; and you would like to add another virtual
machine to the mix that has both &amp;ldquo;external&amp;rdquo; connectivity (&amp;ldquo;external&amp;rdquo;
in quotes because I am using it in the same way as the quickstart does
w/r/t the undercloud) and connectivity to the overcloud nodes. How
would you go about setting that up?&lt;/p&gt;
&lt;p&gt;For a concrete example, let&amp;rsquo;s presume you have deployed an environment
using the default tripleo-quickstart configuration, which looks like
this:&lt;/p&gt;</description></item><item><title>A collection of git tips</title><link>https://blog.oddbit.com/post/2016-02-19-a-collection-of-git-tips/</link><pubDate>Fri, 19 Feb 2016 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2016-02-19-a-collection-of-git-tips/</guid><description>&lt;p&gt;This is a small collection of simple &lt;code&gt;git&lt;/code&gt; tips and tricks I use to
make my life easier.&lt;/p&gt;
&lt;h2 id="quickly-amend-an-existing-commit-with-new-files"&gt;Quickly amend an existing commit with new files&lt;/h2&gt;
&lt;p&gt;I have this alias in place that will amend the current commit while
automatically re-using the existing commit message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alias.fix=commit --amend -C HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this in place, fixing a review becomes:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ vim some/file/somewhere
$ git add -u
$ git fix
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which I find much more convenient than &lt;code&gt;git commit --amend&lt;/code&gt;, following
by saving the commit message.&lt;/p&gt;</description></item><item><title>Deploying an HA OpenStack development environment with tripleo-quickstart</title><link>https://blog.oddbit.com/post/2016-02-19-deploy-an-ha-openstack-develop/</link><pubDate>Fri, 19 Feb 2016 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2016-02-19-deploy-an-ha-openstack-develop/</guid><description>&lt;p&gt;In this article I would like to introduce &lt;a href="https://github.com/redhat-openstack/tripleo-quickstart"&gt;tripleo-quickstart&lt;/a&gt;, a
tool that will automatically provision a virtual environment and then
use &lt;a href="http://docs.openstack.org/developer/tripleo-docs/"&gt;TripleO&lt;/a&gt; to deploy an HA OpenStack on top of it.&lt;/p&gt;
&lt;h2 id="introducing-tripleo-quickstart"&gt;Introducing Tripleo-Quickstart&lt;/h2&gt;
&lt;p&gt;The goal of the &lt;a href="https://github.com/redhat-openstack/tripleo-quickstart"&gt;Tripleo-Quickstart&lt;/a&gt; project is to replace the
&lt;code&gt;instack-virt-setup&lt;/code&gt; tool for quickly setting up virtual TripleO
environments, and to ultimately become the tool used by both
developers and upstream CI for this purpose. The project is a set of
&lt;a href="http://ansible.com/"&gt;Ansible&lt;/a&gt; playbooks that will take care of:&lt;/p&gt;</description></item><item><title>Gruf gets superpowers</title><link>https://blog.oddbit.com/post/2016-02-19-gruf-gets-superpowers/</link><pubDate>Fri, 19 Feb 2016 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2016-02-19-gruf-gets-superpowers/</guid><description>&lt;p&gt;In my &lt;a href="https://blog.oddbit.com/post/2016-02-16-gruf-a-gerrit-command-line-uti/"&gt;last article&lt;/a&gt; article I introduced &lt;a href="http://github.com/larsks/gruf"&gt;Gruf&lt;/a&gt;, a command line
tool for interacting with &lt;a href="https://www.gerritcodereview.com/"&gt;Gerrit&lt;/a&gt;. Since then, Gruf has gained a
few important new features.&lt;/p&gt;
&lt;h2 id="caching"&gt;Caching&lt;/h2&gt;
&lt;p&gt;Gruf will now by default cache results for five minutes. This avoids
repeatedly querying the server for the same information when you&amp;rsquo;re
just displaying it with different templates (for example, if you run a
&lt;code&gt;gruf query open here&lt;/code&gt; followed by a &lt;code&gt;gruf -t patches query open here&lt;/code&gt;).&lt;/p&gt;</description></item><item><title>Gruf, a Gerrit command line utility</title><link>https://blog.oddbit.com/post/2016-02-16-gruf-a-gerrit-command-line-uti/</link><pubDate>Tue, 16 Feb 2016 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2016-02-16-gruf-a-gerrit-command-line-uti/</guid><description>&lt;p&gt;(See also &lt;a href="https://blog.oddbit.com/post/2016-02-19-gruf-gets-superpowers/"&gt;the followup&lt;/a&gt; to this article.)&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve recently started spending more time interacting with &lt;a href="https://www.gerritcodereview.com/"&gt;Gerrit&lt;/a&gt;,
the code review tool used both by &lt;a href="http://openstack.org/"&gt;OpenStack&lt;/a&gt;, at
&lt;a href="http://review.openstack.org/"&gt;review.openstack.org&lt;/a&gt;, and by a variety of other open source projects
at GerritForge&amp;rsquo;s GitHub-linked &lt;a href="http://review.gerrithub.io/"&gt;review.gerrithub.io&lt;/a&gt;. I went
looking for command line tools and was largely disappointed with what
I found. Many of the solutions out there assume that you&amp;rsquo;re regularly
interacting with a single Gerrit instance, and that&amp;rsquo;s seldom the case:
more often, the Gerrit server in use varies from project to project.&lt;br&gt;
I also found that many of the tools were opinionated in what sort of
output they would produce.&lt;/p&gt;</description></item><item><title>A systemd-nspawn connection driver for Ansible</title><link>https://blog.oddbit.com/post/2016-02-08-a-systemd-nspawn-connection-dr/</link><pubDate>Mon, 08 Feb 2016 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2016-02-08-a-systemd-nspawn-connection-dr/</guid><description>&lt;p&gt;I wrote &lt;a href="https://blog.oddbit.com/post/2016-02-07-systemd-nspawn-for-fun-and-wel/"&gt;earlier&lt;/a&gt; about &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html"&gt;systemd-nspawn&lt;/a&gt;, and how it can take much
of the fiddly work out of setting up functional &lt;code&gt;chroot&lt;/code&gt; environments.
I&amp;rsquo;m a regular &lt;a href="http://ansible.com/"&gt;Ansible&lt;/a&gt; user, and I wanted to be able to apply some
of those techniques to my playbooks.&lt;/p&gt;
&lt;p&gt;Ansible already has a &lt;code&gt;chroot&lt;/code&gt; module, of course, but for some
situations &amp;ndash; such as targeting an emulated &lt;code&gt;chroot&lt;/code&gt; environment &amp;ndash;
that just means a lot of extra work. Using &lt;code&gt;systemd-nspawn&lt;/code&gt; makes
this trivial.&lt;/p&gt;</description></item><item><title>Folding long lines in Ansible inventory files</title><link>https://blog.oddbit.com/post/2016-02-07-folding-long-lines-in-ansible-/</link><pubDate>Sun, 07 Feb 2016 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2016-02-07-folding-long-lines-in-ansible-/</guid><description>&lt;p&gt;If you have an Ansible inventory file that includes lots of per host
variables, it&amp;rsquo;s not unusual for lines to get long enough that they
become unwieldly, particularly if you want to discuss them in an email
or write about them in some context (e.g., a blog post).&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve just submitted pull request &lt;a href="https://github.com/ansible/ansible/pull/14359"&gt;#14359&lt;/a&gt; to Ansible which
implements support for folding long lines using the INI-format
convention of using indent to mark extended logical lines.&lt;/p&gt;</description></item><item><title>Systemd-nspawn for fun and...well, mostly for fun</title><link>https://blog.oddbit.com/post/2016-02-07-systemd-nspawn-for-fun-and-wel/</link><pubDate>Sun, 07 Feb 2016 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2016-02-07-systemd-nspawn-for-fun-and-wel/</guid><description>&lt;p&gt;&lt;code&gt;systemd-nspawn&lt;/code&gt; has been called &lt;a href="https://wiki.archlinux.org/index.php/Systemd-nspawn"&gt;&amp;ldquo;chroot on steroids&amp;rdquo;&lt;/a&gt;,
but if you think of it as &lt;a href="http://docker.com"&gt;Docker&lt;/a&gt; with a slightly different target
you wouldn&amp;rsquo;t be far wrong, either. It can be used to spawn containers
on your host, and has a variety of options for configuring the
containerized environment through the use of private networking, bind
mounts, capability controls, and a variety of other facilities that
give you flexible container management.&lt;/p&gt;
&lt;p&gt;There are many different ways in which it can be used. I&amp;rsquo;m going to
focus on one that&amp;rsquo;s a bit of a corner use case that I find
particularly interesting. In this article we&amp;rsquo;re going to explore how
we can use &lt;a href="https://www.freedesktop.org/software/systemd/man/systemd-nspawn.html"&gt;systemd-nspawn&lt;/a&gt; to spawn lightweight containers for
architectures other than that of our host system.&lt;/p&gt;</description></item><item><title>Installing pyspatialite on Fedora</title><link>https://blog.oddbit.com/post/2015-11-17-installing-pyspatialite-on-fed/</link><pubDate>Tue, 17 Nov 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-11-17-installing-pyspatialite-on-fed/</guid><description>&lt;p&gt;If you should find yourself wanting to install &lt;a href="https://github.com/lokkju/pyspatialite"&gt;pyspatialite&lt;/a&gt; on
Fedora &amp;ndash; perhaps because you want to use the &lt;a href="https://plugins.qgis.org/plugins/processing/"&gt;Processing plugin&lt;/a&gt;
for &lt;a href="http://www.qgis.org/"&gt;QGIS&lt;/a&gt; &amp;ndash; you will first need to install the following
dependencies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;gcc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;python-devel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sqlite-devel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;geos-devel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;proj-devel&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;python-pip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;redhat-rpm-config&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After which you can install &lt;code&gt;pyspatialite&lt;/code&gt; using &lt;code&gt;pip&lt;/code&gt; by running:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;CFLAGS=-I/usr/include pip install pyspatialite
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this point, you should be able to use the &amp;ldquo;Processing&amp;rdquo; plugin.&lt;/p&gt;</description></item><item><title>Ansible 2.0: New OpenStack modules</title><link>https://blog.oddbit.com/post/2015-10-26-ansible-20-new-openstack-modul/</link><pubDate>Mon, 26 Oct 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-10-26-ansible-20-new-openstack-modul/</guid><description>&lt;p&gt;This is the second in a loose sequence of articles looking at new
features in Ansible 2.0. In the previous article I looked at the
&lt;a href="https://blog.oddbit.com/post/2015-10-13-ansible-20-the-docker-connecti/"&gt;Docker connection driver&lt;/a&gt;. In this article, I would like to
provide an overview of the new-and-much-improved suite of modules for
interacting with an &lt;a href="http://www.openstack.org/"&gt;OpenStack&lt;/a&gt; environment, and provide a few
examples of their use.&lt;/p&gt;
&lt;p&gt;In versions of Ansible prior to 2.0, there was a small collection of
OpenStack modules. There was the minimum necessary to boot a Nova
instance:&lt;/p&gt;</description></item><item><title>Automatic git cache</title><link>https://blog.oddbit.com/post/2015-10-19-automatic-git-cache/</link><pubDate>Mon, 19 Oct 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-10-19-automatic-git-cache/</guid><description>&lt;p&gt;This post is in response to a comment someone made on irc earlier
today:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[I] would really like a git lookaside cache which operated on an upstream
repo, but pulled objects locally when they&amp;rsquo;re available&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In this post I present a proof-of-concept solution to this request.
Please note that thisand isn&amp;rsquo;t something that has actually been used
or tested anywhere!&lt;/p&gt;
&lt;p&gt;If you access a git repository via &lt;code&gt;ssh&lt;/code&gt;, it&amp;rsquo;s easy to provide a
wrapper for git operations via the &lt;code&gt;command=&lt;/code&gt; option in an
&lt;code&gt;authorized_keys&lt;/code&gt; file. We can take advantage of this to update a a
local &amp;ldquo;cache&amp;rdquo; repository prior to responding to a &lt;code&gt;clone&lt;/code&gt;/&lt;code&gt;pull&lt;/code&gt;/etc.
operation.&lt;/p&gt;</description></item><item><title>Stupid Ansible Tricks: Running a role from the command line</title><link>https://blog.oddbit.com/post/2015-10-19-stupid-ansible-tricks-running-/</link><pubDate>Mon, 19 Oct 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-10-19-stupid-ansible-tricks-running-/</guid><description>&lt;p&gt;When writing &lt;a href="http://www.ansible.com/"&gt;Ansible&lt;/a&gt; roles I occasionally want a way to just run a
role from the command line, without having to muck about with a
playbook. I&amp;rsquo;ve seen &lt;a href="https://groups.google.com/forum/#!topic/ansible-project/h-SGLuPDRrs"&gt;similar&lt;/a&gt; &lt;a href="https://groups.google.com/forum/#!topic/ansible-devel/GqzZ6zsn6eY"&gt;requests&lt;/a&gt; on the mailing lists
and on irc.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve thrown together a quick wrapper that will allow you (and me!) to
do exactly that, called &lt;a href="http://github.com/larsks/ansible-role"&gt;ansible-role&lt;/a&gt;. The &lt;code&gt;--help&lt;/code&gt; output looks
like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;usage: ansible-role [-h] [--verbose] [--gather] [--no-gather]
 [--extra-vars EXTRA_VARS] [-i INVENTORY] [--hosts HOSTS]
 [--sudo] [--become] [--user USER]
 role

positional arguments:
 role

optional arguments:
 -h, --help show this help message and exit
 --verbose, -v
 --gather, -g
 --no-gather, -G
 --extra-vars EXTRA_VARS, -e EXTRA_VARS

Inventory:
 -i INVENTORY, --inventory INVENTORY
 --hosts HOSTS, -H HOSTS

Identity:
 --sudo, -s
 --become, -b
 --user USER, -u USER
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="example"&gt;Example&lt;/h2&gt;
&lt;p&gt;If you have a role &lt;code&gt;roles/testrole&lt;/code&gt; that contains the following in
&lt;code&gt;tasks/main.yml&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Bootstrapping Ansible on Fedora 23</title><link>https://blog.oddbit.com/post/2015-10-15-bootstrapping-ansible-on-fedor/</link><pubDate>Thu, 15 Oct 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-10-15-bootstrapping-ansible-on-fedor/</guid><description>&lt;p&gt;If you&amp;rsquo;ve tried running &lt;a href="http://ansible.com/"&gt;Ansible&lt;/a&gt; against a &lt;a href="http://fedoraproject.org/"&gt;Fedora&lt;/a&gt; 23 system,
you may have run into the following problem:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fatal: [myserver]: FAILED! =&amp;gt; {&amp;quot;changed&amp;quot;: false, &amp;quot;failed&amp;quot;: true,
&amp;quot;msg&amp;quot;: &amp;quot;/bin/sh: /usr/bin/python: No such file or directory\r\n&amp;quot;,
&amp;quot;parsed&amp;quot;: false}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fedora has recently made the switch to only including Python 3 on the
base system (at least for the &lt;a href="https://getfedora.org/en/cloud/prerelease/"&gt;cloud&lt;/a&gt; variant), while Ansible still
requires Python 2. With Fedora 23, Python 3 is available as
&lt;code&gt;/usr/bin/python3&lt;/code&gt;, and &lt;code&gt;/usr/bin/python&lt;/code&gt; is only available if you
have installed the Python 2 interpreter.&lt;/p&gt;</description></item><item><title>Ansible 2.0: The Docker connection driver</title><link>https://blog.oddbit.com/post/2015-10-13-ansible-20-the-docker-connecti/</link><pubDate>Tue, 13 Oct 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-10-13-ansible-20-the-docker-connecti/</guid><description>&lt;p&gt;As the release of &lt;a href="http://ansible.com/"&gt;Ansible&lt;/a&gt; 2.0 draws closer, I&amp;rsquo;d like to take a
look at some of the new features that are coming down the pipe. In
this post, we&amp;rsquo;ll look at the &lt;code&gt;docker&lt;/code&gt; connection driver.&lt;/p&gt;
&lt;p&gt;A &amp;ldquo;connection driver&amp;rdquo; is the mechanism by which Ansible connects to
your target hosts. These days it uses &lt;code&gt;ssh&lt;/code&gt; by default (which relies
on the OpenSSH command line client for connectivity), and it also
offers the &lt;a href="http://www.paramiko.org/"&gt;Paramiko&lt;/a&gt; library as an alternative ssh implementation
(this was in fact the default driver in earlier versions of Ansible).
Alternative drivers offered by recent versions of ansible included the
&lt;code&gt;winrm&lt;/code&gt; driver, for accessing Windows hosts, the &lt;code&gt;fireball&lt;/code&gt; driver, a
(deprecated) driver that used &lt;a href="http://zeromq.org/"&gt;0mq&lt;/a&gt; for communication, and &lt;code&gt;jail&lt;/code&gt;, a
driver for connecting to FreeBSD jails.&lt;/p&gt;</description></item><item><title>Running NTP in a Container</title><link>https://blog.oddbit.com/post/2015-10-09-running-ntp-in-a-container/</link><pubDate>Fri, 09 Oct 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-10-09-running-ntp-in-a-container/</guid><description>&lt;p&gt;Someone asked on IRC about running ntpd in a container on &lt;a href="http://www.projectatomic.io/"&gt;Atomic&lt;/a&gt;,
so I&amp;rsquo;ve put together a small example. We&amp;rsquo;ll start with a very simple
&lt;code&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM alpine
RUN apk update
RUN apk add openntpd
ENTRYPOINT [&amp;quot;ntpd&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;m using the &lt;code&gt;alpine&lt;/code&gt; image as my starting point because it&amp;rsquo;s very
small, which makes this whole process go a little faster. I&amp;rsquo;m
installing the &lt;a href="http://www.openntpd.org/"&gt;openntpd&lt;/a&gt; package, which provides the &lt;code&gt;ntpd&lt;/code&gt; binary.&lt;/p&gt;
&lt;p&gt;By setting an &lt;code&gt;ENTRYPOINT&lt;/code&gt; here, the &lt;code&gt;ntpd&lt;/code&gt; binary will be started by
default, and any arguments passed to &lt;code&gt;docker run&lt;/code&gt; after the image name
will be passed to &lt;code&gt;ntpd&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Migrating Cinder volumes between OpenStack environments using shared NFS storage</title><link>https://blog.oddbit.com/post/2015-09-29-migrating-cinder-volumes-betwe/</link><pubDate>Tue, 29 Sep 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-09-29-migrating-cinder-volumes-betwe/</guid><description>&lt;p&gt;Many of the upgrade guides for OpenStack focus on in-place upgrades to
your OpenStack environment. Some organizations may opt for a less
risky (but more hardware intensive) option of setting up a parallel
environment, and then migrating data into the new environment. In
this article, we look at how to use Cinder backups with a shared NFS
volume to facilitate the migration of Cinder volumes between two
different OpenStack environments.&lt;/p&gt;</description></item><item><title>Provider external networks (in an appropriate amount of detail)</title><link>https://blog.oddbit.com/post/2015-08-13-provider-external-networks-det/</link><pubDate>Thu, 13 Aug 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-08-13-provider-external-networks-det/</guid><description>&lt;p&gt;In &lt;a href="https://blog.oddbit.com/post/2013-11-14-quantum-in-too-much-detail/"&gt;Quantum in Too Much Detail&lt;/a&gt;, I discussed the architecture of a
Neutron deployment in detail. Since that article was published,
Neutron gained the ability to handle multiple external networks with a
single L3 agent. While I &lt;a href="https://blog.oddbit.com/post/2014-05-28-multiple-external-networks-wit/"&gt;wrote about that&lt;/a&gt; back in 2014, I
covered the configuration side of it in much more detail than I
discussed the underlying network architecture. This post addresses
the architecture side.&lt;/p&gt;
&lt;h2 id="the-players"&gt;The players&lt;/h2&gt;
&lt;p&gt;This document describes the architecture that results from a
particular OpenStack configuration, specifically:&lt;/p&gt;</description></item><item><title>In which we are amazed it doesn't all fall apart</title><link>https://blog.oddbit.com/post/2015-07-26-in-which-we-are-amazed-it-does/</link><pubDate>Sun, 26 Jul 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-07-26-in-which-we-are-amazed-it-does/</guid><description>&lt;p&gt;So, the Kilo release notes say:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nova-manage migrate-flavor-data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But nova-manage says:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nova-manage db migrate_flavor_data
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But that says:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Missing arguments: max_number
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the help says:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;usage: nova-manage db migrate_flavor_data [-h]
 [--max-number &amp;lt;number&amp;gt;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which indicates that &amp;ndash;max-number is optional, but whatever, so you
try:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nova-manage db migrate_flavor_data --max-number 100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that says:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Missing arguments: max_number
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So just for kicks you try:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nova-manage db migrate_flavor_data --max_number 100
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that says:&lt;/p&gt;</description></item><item><title>Mapping local users to Kerberos principals with SSSD</title><link>https://blog.oddbit.com/post/2015-07-16-mapping-local-users-to-kerbero/</link><pubDate>Thu, 16 Jul 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-07-16-mapping-local-users-to-kerbero/</guid><description>&lt;p&gt;I work for an organization that follows the common model of assigning
people systematically generated user ids. Like most technically
inclined employees of this organization, I have local accounts on my
workstation that don&amp;rsquo;t bear any relation to the generated account ids.
For the most part this isn&amp;rsquo;t a problem, except that our organization
uses Kerberos to authenticate access to a variety of resources (such
as the mailserver and a variety of web applications).&lt;/p&gt;</description></item><item><title>OpenStack Networking without DHCP</title><link>https://blog.oddbit.com/post/2015-06-26-openstack-networking-without-d/</link><pubDate>Fri, 26 Jun 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-06-26-openstack-networking-without-d/</guid><description>&lt;p&gt;In an OpenStack environment, &lt;a href="https://cloudinit.readthedocs.org/en/latest/"&gt;cloud-init&lt;/a&gt; generally fetches
information from the metadata service provided by Nova. It also has
support for reading this information from a &lt;em&gt;configuration drive&lt;/em&gt;,
which under OpenStack means a virtual CD-ROM device attached to your
instance containing the same information that would normally be
available via the metadata service.&lt;/p&gt;
&lt;p&gt;It is possible to generate your network configuration from this
configuration drive, rather than relying on the DHCP server provided
by your OpenStack environment. In order to do this you will need to
make the following changes to your Nova configuration:&lt;/p&gt;</description></item><item><title>Heat-kubernetes Demo with Autoscaling</title><link>https://blog.oddbit.com/post/2015-06-19-heatkubernetes-demo-with-autos/</link><pubDate>Fri, 19 Jun 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-06-19-heatkubernetes-demo-with-autos/</guid><description>&lt;p&gt;Next week is the &lt;a href="http://www.redhat.com/summit/"&gt;Red Hat Summit&lt;/a&gt; in Boston, and I&amp;rsquo;ll be taking part
in a &lt;a href="http://www.projectatomic.io/"&gt;Project Atomic&lt;/a&gt; presentation in which I will discuss various
(well, two) options for deploying Atomic into an OpenStack
environment, focusing on my &lt;a href="https://github.com/projectatomic/heat-kubernetes/"&gt;heat-kubernetes&lt;/a&gt; templates.&lt;/p&gt;
&lt;p&gt;As part of that presentation, I&amp;rsquo;ve put together a short demonstration video:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/tS5X0qi04ZU?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;This shows off the autoscaling behavior available with recent versions
of these templates (and also serves as a very brief introduction to
working with Kubernetes).&lt;/p&gt;</description></item><item><title>Teach git about GIT_SSL_CIPHER_LIST</title><link>https://blog.oddbit.com/post/2015-05-08-git-ssl-cipher-list/</link><pubDate>Fri, 08 May 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-05-08-git-ssl-cipher-list/</guid><description>&lt;p&gt;Someone named &lt;a href="https://stackoverflow.com/users/4713895/hithard"&gt;hithard&lt;/a&gt; on &lt;a href="https://stackoverflow.com/"&gt;StackOverflow&lt;/a&gt; was trying to clone a git repository via https, and was &lt;a href="https://stackoverflow.com/a/30090725/147356"&gt;running into an odd error&lt;/a&gt;: &amp;ldquo;Cannot communicate securely with peer: no common encryption algorithm(s).&amp;rdquo;. This was due to the fact that the server (&lt;code&gt;openhatch.org&lt;/code&gt;) was configured to use a cipher suite that was not supported by default in the underlying SSL library (which could be either &lt;a href="https://www.openssl.org/"&gt;OpenSSL&lt;/a&gt; or &lt;a href="https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS"&gt;NSS&lt;/a&gt;, depending on how git was built).&lt;/p&gt;
&lt;p&gt;Many applications allow the user to configure an explicit list of ciphers to consider when negotiating a secure connection. For example, &lt;a href="https://curl.haxx.se/"&gt;curl&lt;/a&gt; has the &lt;a href="https://curl.haxx.se/libcurl/c/CURLOPT_SSL_CIPHER_LIST.html"&gt;CURLOPT_SSL_CIPHER_LIST&lt;/a&gt; option. This turns out to be especially relevant because git relies on &lt;a href="https://curl.haxx.se/libcurl/"&gt;libcurl&lt;/a&gt; for all of its http operations, which means all we need to do is (a) create a new configuration option for git, and then (b) pass that value through to libcurl.&lt;/p&gt;</description></item><item><title>Suggestions for the Docker MAINTAINER directive</title><link>https://blog.oddbit.com/post/2015-04-27-suggestions-for-the-docker-mai/</link><pubDate>Mon, 27 Apr 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-04-27-suggestions-for-the-docker-mai/</guid><description>&lt;p&gt;Because nobody asked for it, this is my opinion on the use of the
&lt;code&gt;MAINTAINER&lt;/code&gt; directive in your Dockerfiles.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://docs.docker.com/reference/builder/#maintainer"&gt;documentation&lt;/a&gt; says simply:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The MAINTAINER instruction allows you to set the Author field of the generated images.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Many people end up putting the name and email address of an actual
person here. I think this is ultimately a bad idea, and does a
disservice both to members of a project that produce Docker images and
to people consuming those images.&lt;/p&gt;</description></item><item><title>Using tools badly: time shifting git commits with Workinghours</title><link>https://blog.oddbit.com/post/2015-04-10-workinghours-time-shifting-git/</link><pubDate>Fri, 10 Apr 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-04-10-workinghours-time-shifting-git/</guid><description>&lt;p&gt;This is a terrible hack. If you are easily offended by bad ideas
implemented poorly, move along!&lt;/p&gt;
&lt;p&gt;You are working on a wonderful open source project&amp;hellip;but you are not
&lt;em&gt;supposed&lt;/em&gt; to be working on that project! You&amp;rsquo;re supposed to be doing
your &lt;em&gt;real&lt;/em&gt; work! Unfortunately, your extra-curricular activity is
well documented in the git history of your project for all to see:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.oddbit.com/post/2015-04-10-workinghours-time-shifting-git/repo-before.png" alt="Heatmap of original commit history"&gt;&lt;/p&gt;
&lt;p&gt;And now your boss knows why the TPS reports are late. You need
&lt;a href="https://github.com/larsks/workinghours.git"&gt;workinghours&lt;/a&gt;, a terrible utility for doing awful things to your
repository history. &lt;a href="https://github.com/larsks/workinghours.git"&gt;Workinghours&lt;/a&gt; will programatically time shift
your git commits so that they appear to have happened within specified
time intervals (for example, &amp;ldquo;between 7PM and midnight&amp;rdquo;).&lt;/p&gt;</description></item><item><title>Booting cloud images with libvirt</title><link>https://blog.oddbit.com/post/2015-03-10-booting-cloud-images-with-libv/</link><pubDate>Tue, 10 Mar 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-03-10-booting-cloud-images-with-libv/</guid><description>&lt;p&gt;Most major distributions now provide &amp;ldquo;cloud-enabled&amp;rdquo; images designed
for use in cloud environments like OpenStack and AWS. These images
are usually differentiated by (a) being relatively small, and (b) running
&lt;a href="http://cloudinit.readthedocs.org/"&gt;cloud-init&lt;/a&gt; at boot to perform initial system configuration tasks
using metadata provided by the cloud environment.&lt;/p&gt;
&lt;p&gt;Because of their small size and support for automatic configuration
(including such useful tasks as provisioning ssh keys), these images
are attractive for use &lt;em&gt;outside&lt;/em&gt; of a cloud environment.
Unfortunately, when people first try to boot them they are met with
frustration as first the image takes forever to boot as it tries to
contact a non-existent metadata service, and then when it finally does
boot they are unable to log in because the images typically only
support key-based login.&lt;/p&gt;</description></item><item><title>Diagnosing problems with an OpenStack deployment</title><link>https://blog.oddbit.com/post/2015-03-09-diagnosing-problems-with-an-op/</link><pubDate>Mon, 09 Mar 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-03-09-diagnosing-problems-with-an-op/</guid><description>&lt;p&gt;I recently had the chance to help a colleague debug some problems in
his OpenStack installation. The environment was unique because it was
booting virtualized &lt;a href="https://fedoraproject.org/wiki/Architectures/AArch64"&gt;aarch64&lt;/a&gt; instances, which at the time did not
have any PCI bus support&amp;hellip;which in turn precluded things like graphic
consoles (i.e., VNC or SPICE consoles) for the Nova instances.&lt;/p&gt;
&lt;p&gt;This post began life as an email summarizing the various configuration
changes we made on the systems to get things up and running. After
writing it, I decided it presented an interesting summary of some
common (and maybe not-so-common) issues, so I am posting it here in
the hopes that other folks will find it interesting.&lt;/p&gt;</description></item><item><title>Converting hexadecimal ip addresses to dotted quads with Bash</title><link>https://blog.oddbit.com/post/2015-03-08-converting-hexadecimal-ip-addr/</link><pubDate>Sun, 08 Mar 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-03-08-converting-hexadecimal-ip-addr/</guid><description>&lt;p&gt;This is another post that is primarily for my own benefit for the next
time I forget how to do this.&lt;/p&gt;
&lt;p&gt;I wanted to read routing information directly from &lt;code&gt;/proc/net/route&lt;/code&gt;
using &lt;code&gt;bash&lt;/code&gt;, because you never know what may or may not be available
in the minimal environment of a Docker container (for example, the
&lt;code&gt;iproute&lt;/code&gt; package is not installed by default in the Fedora Docker
images). The contents of &lt;code&gt;/proc/net/route&lt;/code&gt; looks something like:&lt;/p&gt;</description></item><item><title>Visualizing Pacemaker resource constraints</title><link>https://blog.oddbit.com/post/2015-02-24-visualizing-pacemaker-constrai/</link><pubDate>Tue, 24 Feb 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-02-24-visualizing-pacemaker-constrai/</guid><description>&lt;p&gt;If a picture is worth a thousand words, then code that generates
pictures from words is worth&amp;hellip;uh, anyway, I wrote a script that
produces &lt;a href="http://en.wikipedia.org/wiki/DOT_%28graph_description_language%29"&gt;dot&lt;/a&gt; output from Pacemaker start and colocation
constraints:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/larsks/pacemaker-tools/"&gt;https://github.com/larsks/pacemaker-tools/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can pass this output to &lt;a href="http://www.graphviz.org/"&gt;graphviz&lt;/a&gt; to create visualizations of
your Pacemaker resource constraints.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;graph-constraints.py&lt;/code&gt; script in that repository consumes the
output of &lt;code&gt;cibadmin -Q&lt;/code&gt; and can produce output for either start
constraints (&lt;code&gt;-S&lt;/code&gt;, the default) or colocation constraints (&lt;code&gt;-C&lt;/code&gt;).&lt;/p&gt;</description></item><item><title>Stupid Pacemaker XML tricks</title><link>https://blog.oddbit.com/post/2015-02-19-stupid-pacemaker-xml-tricks/</link><pubDate>Thu, 19 Feb 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-02-19-stupid-pacemaker-xml-tricks/</guid><description>&lt;p&gt;I&amp;rsquo;ve recently spent some time working with &lt;a href="http://clusterlabs.org/"&gt;Pacemaker&lt;/a&gt;, and ended up
with an interesting collection of &lt;a href="http://www.w3.org/TR/xpath/"&gt;XPath&lt;/a&gt; snippets that I am publishing
here for your use and/or amusement.&lt;/p&gt;
&lt;h2 id="check-if-there-are-any-inactive-resources"&gt;Check if there are any inactive resources&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;pcs status xml |
 xmllint --xpath '//resource[@active=&amp;quot;false&amp;quot;]' - &amp;gt;&amp;amp;/dev/null &amp;amp;&amp;amp;
 echo &amp;quot;There are inactive resources&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This selects &lt;em&gt;any&lt;/em&gt; resource (&lt;code&gt;//resource&lt;/code&gt;) in the output of &lt;code&gt;pcs status xml&lt;/code&gt; that has the attribute &lt;code&gt;active&lt;/code&gt; set to &lt;code&gt;false&lt;/code&gt;. If there
are no matches to this query, &lt;code&gt;xmllint&lt;/code&gt; exits with an error code.&lt;/p&gt;</description></item><item><title>Unpacking Docker images with Undocker</title><link>https://blog.oddbit.com/post/2015-02-13-unpacking-docker-images/</link><pubDate>Fri, 13 Feb 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-02-13-unpacking-docker-images/</guid><description>&lt;p&gt;In some ways, the most exciting thing about &lt;a href="http://docker.com/"&gt;Docker&lt;/a&gt; isn&amp;rsquo;t the ability
to start containers. That&amp;rsquo;s been around for a long time in various
forms, such as &lt;a href="https://linuxcontainers.org/"&gt;LXC&lt;/a&gt; or &lt;a href="http://openvz.org/Main_Page"&gt;OpenVZ&lt;/a&gt;. What Docker brought to the
party was a convenient method of building and distributing the
filesystems necessary for running containers. Suddenly, it was easy
to build a containerized service &lt;em&gt;and&lt;/em&gt; to share it with other people.&lt;/p&gt;
&lt;p&gt;I was taking a closer at the &lt;a href="http://www.freedesktop.org/software/systemd/man/systemd-nspawn.html"&gt;systemd-nspawn&lt;/a&gt; command, which it
seems has been developing it&amp;rsquo;s own set of container-related
superpowers recently, including a number of options for setting up the
network environment of a container. Like Docker, &lt;code&gt;systemd-nspawn&lt;/code&gt;
needs a filesystem on which to operate, but &lt;em&gt;unlike&lt;/em&gt; Docker, there is
no convenient distribution mechanism and no ecosystem of existing
images. In fact, the official documentation seems to assume that
you&amp;rsquo;ll be building your own from scratch. Ain&amp;rsquo;t nobody got time for
that&amp;hellip;&lt;/p&gt;</description></item><item><title>Installing nova-docker with devstack</title><link>https://blog.oddbit.com/post/2015-02-11-installing-novadocker-with-dev/</link><pubDate>Wed, 11 Feb 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-02-11-installing-novadocker-with-dev/</guid><description>&lt;p&gt;This is a long-form response to &lt;a href="https://ask.openstack.org/en/question/60679/installing-docker-on-openstack-with-ubuntu/"&gt;this question&lt;/a&gt;, and describes
how to get the &lt;a href="http://github.com/stackforge/nova-docker/"&gt;nova-docker&lt;/a&gt; driver up running with &lt;a href="http://devstack.org/"&gt;devstack&lt;/a&gt;
under Ubuntu 14.04 (Trusty). I wrote a &lt;a href="https://blog.oddbit.com/post/2015-02-06-installing-nova-docker-on-fedo/"&gt;similar post&lt;/a&gt; for Fedora
21, although that one was using the &lt;a href="http://openstack.redhat.com/"&gt;RDO&lt;/a&gt; Juno packages, while this
one is using &lt;a href="http://devstack.org/"&gt;devstack&lt;/a&gt; and the upstream sources.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;We&amp;rsquo;ll be using the &lt;a href="https://cloud-images.ubuntu.com/trusty/current/"&gt;Ubuntu 14.04 cloud image&lt;/a&gt; (because my test
environment runs on &lt;a href="http://www.openstack.org/"&gt;OpenStack&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;First, let&amp;rsquo;s install a few prerequisites:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ sudo apt-get update
$ sudo apt-get -y install git git-review python-pip python-dev
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And generally make sure things are up-to-date:&lt;/p&gt;</description></item><item><title>External networking for Kubernetes services</title><link>https://blog.oddbit.com/post/2015-02-10-external-networking-for-kubern/</link><pubDate>Tue, 10 Feb 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-02-10-external-networking-for-kubern/</guid><description>&lt;p&gt;I have recently started running some &amp;ldquo;real&amp;rdquo; services (that is,
&amp;ldquo;services being consumed by someone other than myself&amp;rdquo;) on top of
Kubernetes (running on bare metal), which means I suddenly had to
confront the question of how to provide external access to Kubernetes
hosted services. Kubernetes provides two solutions to this problem,
neither of which is particularly attractive out of the box:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;There is a field &lt;code&gt;createExternalLoadBalancer&lt;/code&gt; that can be set in a
service description. This is meant to integrate with load
balancers provided by your local cloud environment, but at the
moment there is only support for this when running under &lt;a href="https://cloud.google.com/compute/"&gt;GCE&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Installing nova-docker on Fedora 21/RDO Juno</title><link>https://blog.oddbit.com/post/2015-02-06-installing-nova-docker-on-fedo/</link><pubDate>Fri, 06 Feb 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-02-06-installing-nova-docker-on-fedo/</guid><description>&lt;p&gt;This post comes about indirectly by a request on IRC in &lt;code&gt;#rdo&lt;/code&gt; for help getting &lt;a href="https://github.com/stackforge/nova-docker"&gt;nova-docker&lt;/a&gt; installed on Fedora 21. I ran through the process from start to finish and decided to write everything down for posterity.&lt;/p&gt;
&lt;h2 id="getting-started"&gt;Getting started&lt;/h2&gt;
&lt;p&gt;I started with the &lt;a href="https://getfedora.org/en/cloud/download/"&gt;Fedora 21 Cloud Image&lt;/a&gt;, because I&amp;rsquo;m
installing onto OpenStack and the cloud images include
some features that are useful in this environment.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ll be using OpenStack packages from the &lt;a href="https://repos.fedorapeople.org/repos/openstack/openstack-juno/"&gt;RDO Juno&lt;/a&gt; repository.
Because there is often some skew between the RDO packages and the
current Fedora selinux policy, we&amp;rsquo;re going to start by putting SELinux
into permissive mode (sorry, Dan):&lt;/p&gt;</description></item><item><title>Creating minimal Docker images from dynamically linked ELF binaries</title><link>https://blog.oddbit.com/post/2015-02-05-creating-minimal-docker-images/</link><pubDate>Thu, 05 Feb 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-02-05-creating-minimal-docker-images/</guid><description>&lt;p&gt;In this post, we&amp;rsquo;ll look at a method for building minimal Docker
images for dynamically linked ELF binaries, and then at &lt;a href="https://github.com/larsks/dockerize"&gt;a
tool&lt;/a&gt; for automating this process.&lt;/p&gt;
&lt;p&gt;It is tempting, when creating a simple Docker image, to start with one
of the images provided by the major distributions. For example, if
you need an image that provides &lt;code&gt;tcpdump&lt;/code&gt; for use on your &lt;a href="http://www.projectatomic.io/"&gt;Atomic&lt;/a&gt;
host, you might do something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;FROM fedora
RUN yum -y install tcpdump
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And while this will work, you end up consuming 250MB for &lt;code&gt;tcpdump&lt;/code&gt;.
In theory, the layering mechanism that Docker uses to build images
will reduce the practical impact of this (because other images based on
the &lt;code&gt;fedora&lt;/code&gt; image will share the common layers), but in practice the
size is noticeable, especially if you often find yourself pulling this
image into a fresh environment with no established cache.&lt;/p&gt;</description></item><item><title>Filtering libvirt XML in Nova</title><link>https://blog.oddbit.com/post/2015-02-05-filtering-libvirt-xml-in-nova/</link><pubDate>Thu, 05 Feb 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-02-05-filtering-libvirt-xml-in-nova/</guid><description>&lt;p&gt;I saw a request from a customer float by the other day regarding the
ability to filter the XML used to create Nova instances in libvirt.
The customer effectively wanted to blacklist a variety of devices (and
device types). The consensus seems to be &amp;ldquo;you can&amp;rsquo;t do this right now
and upstream is unlikely to accept patches that implement this
behavior&amp;rdquo;, but it sounded like an interesting problem, so&amp;hellip;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/larsks/nova/tree/feature/xmlfilter"&gt;https://github.com/larsks/nova/tree/feature/xmlfilter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a fork of Nova (Juno) that includes support for an extensible
filtering mechanism that is applied to the generated XML before it
gets passed to libvirt.&lt;/p&gt;</description></item><item><title>Docker vs. PrivateTmp</title><link>https://blog.oddbit.com/post/2015-01-18-docker-vs-privatetmp/</link><pubDate>Sun, 18 Jan 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-01-18-docker-vs-privatetmp/</guid><description>&lt;p&gt;While working with Docker &lt;a href="https://blog.oddbit.com/post/2015-01-17-running-novalibvirt-and-novado/"&gt;the other day&lt;/a&gt;, I ran into an
undesirable interaction between Docker and &lt;a href="http://www.freedesktop.org/wiki/Software/systemd/"&gt;systemd&lt;/a&gt; services that
utilize the &lt;code&gt;PrivateTmp&lt;/code&gt; directive.&lt;/p&gt;
&lt;p&gt;The &lt;a href="http://www.freedesktop.org/software/systemd/man/systemd.exec.html#PrivateTmp="&gt;PrivateTmp&lt;/a&gt; directive, if &lt;code&gt;true&lt;/code&gt;, &amp;ldquo;sets up a new file system
namespace for the executed processes and mounts private &lt;code&gt;/tmp&lt;/code&gt; and
&lt;code&gt;/var/tmp&lt;/code&gt; directories inside it that is not shared by processes outside
of the namespace&amp;rdquo;. This is a great idea from a &lt;a href="https://danwalsh.livejournal.com/51459.html"&gt;security
perspective&lt;/a&gt;, but can cause some unanticipated consequences.&lt;/p&gt;
&lt;h2 id="the-problem-in-a-nutshell"&gt;The problem in a nutshell&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Start a Docker container:&lt;/p&gt;</description></item><item><title>Running nova-libvirt and nova-docker on the same host</title><link>https://blog.oddbit.com/post/2015-01-17-running-novalibvirt-and-novado/</link><pubDate>Sat, 17 Jan 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-01-17-running-novalibvirt-and-novado/</guid><description>&lt;p&gt;I regularly use &lt;a href="http://www.openstack.org/"&gt;OpenStack&lt;/a&gt; on my laptop with &lt;a href="http://www.libvirt.org/"&gt;libvirt&lt;/a&gt; as my
hypervisor. I was interested in experimenting with recent versions of
the &lt;a href="https://github.com/stackforge/nova-docker"&gt;nova-docker&lt;/a&gt; driver, but I didn&amp;rsquo;t have a spare system available
on which to run the driver, and I use my regular &lt;code&gt;nova-compute&lt;/code&gt; service
often enough that I didn&amp;rsquo;t want to simply disable it temporarily in
favor of &lt;code&gt;nova-docker&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;NB&lt;/strong&gt; As pointed out by &lt;em&gt;gustavo&lt;/em&gt; in the comments, running two
&lt;code&gt;neutron-openvswitch-agents&lt;/code&gt; on the same host &amp;ndash; as suggested in this
article &amp;ndash; is going to lead to nothing but sadness and doom. So
kids, don&amp;rsquo;t try this at home. I&amp;rsquo;m leaving the article here because I
think it still has some interesting bits.&lt;/p&gt;</description></item><item><title>Building a minimal web server for testing Kubernetes</title><link>https://blog.oddbit.com/post/2015-01-04-building-a-minimal-web-server-/</link><pubDate>Sun, 04 Jan 2015 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2015-01-04-building-a-minimal-web-server-/</guid><description>&lt;p&gt;I have recently been doing some work with &lt;a href="https://github.com/googlecloudplatform/kubernetes"&gt;Kubernetes&lt;/a&gt;, and wanted
to put together a minimal image with which I could test service and
pod deployment. Size in this case was critical: I wanted something
that would download quickly when initially deployed, because I am
often setting up and tearing down Kubernetes as part of my testing
(and some of my test environments have poor external bandwidth).&lt;/p&gt;
&lt;h2 id="building-thttpd"&gt;Building thttpd&lt;/h2&gt;
&lt;p&gt;My go-to minimal webserver is &lt;a href="http://acme.com/software/thttpd/"&gt;thttpd&lt;/a&gt;. For the normal case,
building the software is a simple matter of &lt;code&gt;./configure&lt;/code&gt; followed by
&lt;code&gt;make&lt;/code&gt;. This gets you a dynamically linked binary; using &lt;code&gt;ldd&lt;/code&gt; you
could build a Docker image containing only the necessary shared
libraries:&lt;/p&gt;</description></item><item><title>Accessing the serial console of your Nova servers</title><link>https://blog.oddbit.com/post/2014-12-22-accessing-the-serial-console-o/</link><pubDate>Mon, 22 Dec 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-12-22-accessing-the-serial-console-o/</guid><description>&lt;p&gt;One of the new features available in the Juno release of OpenStack is
support for &lt;a href="https://blueprints.launchpad.net/nova/&amp;#43;spec/serial-ports"&gt;serial console access to your Nova
servers&lt;/a&gt;. This post looks into how to configure the
serial console feature and then how to access the serial consoles of
your Nova servers.&lt;/p&gt;
&lt;h2 id="configuring-serial-console-support"&gt;Configuring serial console support&lt;/h2&gt;
&lt;p&gt;In previous release of OpenStack, read-only access to the serial
console of your servers was available through the
&lt;code&gt;os-getConsoleOutput&lt;/code&gt; server action (exposed via &lt;code&gt;nova console-log&lt;/code&gt; on
the command line). Most cloud-specific Linux images are configured
with a command line that includes something like &lt;code&gt;console=tty0 console=ttyS0,115200n81&lt;/code&gt;, which ensures that kernel output and other
messages are available on the serial console. This is a useful
mechanism for diagnosing problems in the event that you do not have
network access to a server.&lt;/p&gt;</description></item><item><title>Cloud-init and the case of the changing hostname</title><link>https://blog.oddbit.com/post/2014-12-10-cloudinit-and-the-case-of-the-/</link><pubDate>Wed, 10 Dec 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-12-10-cloudinit-and-the-case-of-the-/</guid><description>&lt;h2 id="setting-the-stage"&gt;Setting the stage&lt;/h2&gt;
&lt;p&gt;I ran into a problem earlier this week deploying RDO Icehouse under
RHEL 6. My target systems were a set of libvirt guests deployed from
the RHEL 6 KVM guest image, which includes &lt;a href="https://cloudinit.readthedocs.org/en/latest/"&gt;cloud-init&lt;/a&gt; in order to
support automatic configuration in cloud environments. I take
advantage of this when using &lt;code&gt;libvirt&lt;/code&gt; by attaching a configuration
drive so that I can pass in ssh keys and a &lt;code&gt;user-data&lt;/code&gt; script.&lt;/p&gt;</description></item><item><title>Starting systemd services without blocking</title><link>https://blog.oddbit.com/post/2014-12-02-starting-systemd-services-with/</link><pubDate>Tue, 02 Dec 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-12-02-starting-systemd-services-with/</guid><description>&lt;p&gt;Recently, I&amp;rsquo;ve been playing around with &lt;a href="https://blog.oddbit.com/post/2014-11-24-fedora-atomic-openstack-and-ku/"&gt;Fedora Atomic and
Kubernetes&lt;/a&gt;. I ran into a frustrating problem in which I
would attempt to start a service from within a script launched by
&lt;a href="http://cloudinit.readthedocs.org/"&gt;cloud-init&lt;/a&gt;, only to have have &lt;code&gt;systemctl&lt;/code&gt; block indefinitely
because the service I was attempting to start was dependent on
&lt;code&gt;cloud-init&lt;/code&gt; finishing first.&lt;/p&gt;
&lt;p&gt;It turns out that &lt;code&gt;systemctl&lt;/code&gt; has a flag meant exactly for this
situation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; --no-block
 Do not synchronously wait for the requested operation to finish. If
 this is not specified, the job will be verified, enqueued and
 systemctl will wait until it is completed. By passing this
 argument, it is only verified and enqueued.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replacing &lt;code&gt;systemctl start &amp;lt;service&amp;gt;&lt;/code&gt; with &lt;code&gt;systemctl start --no-block &amp;lt;service&amp;gt;&lt;/code&gt; has solved that particular problem.&lt;/p&gt;</description></item><item><title>Fedora Atomic, OpenStack, and Kubernetes (oh my)</title><link>https://blog.oddbit.com/post/2014-11-24-fedora-atomic-openstack-and-ku/</link><pubDate>Mon, 24 Nov 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-11-24-fedora-atomic-openstack-and-ku/</guid><description>&lt;p&gt;While experimenting with &lt;a href="http://www.projectatomic.io/"&gt;Fedora Atomic&lt;/a&gt;, I was looking for an
elegant way to automatically deploy Atomic into an &lt;a href="http://openstack.org/"&gt;OpenStack&lt;/a&gt;
environment and then automatically schedule some &lt;a href="http://docker.com/"&gt;Docker&lt;/a&gt; containers
on the Atomic host. This post describes my solution.&lt;/p&gt;
&lt;p&gt;Like many other cloud-targeted distributions, Fedora Atomic runs
&lt;a href="http://cloudinit.readthedocs.org/"&gt;cloud-init&lt;/a&gt; when the system boots. We can take advantage of this
to configure the system at first boot by providing a &lt;code&gt;user-data&lt;/code&gt; blob
to Nova when we boot the instance. A &lt;code&gt;user-data&lt;/code&gt; blob can be as
simple as a shell script, and while we could arguably mash everything
into a single script it wouldn&amp;rsquo;t be particularly maintainable or
flexible in the face of different pod/service/etc descriptions.&lt;/p&gt;</description></item><item><title>Creating a Windows image for OpenStack</title><link>https://blog.oddbit.com/post/2014-11-15-creating-a-windows-image-for-o/</link><pubDate>Sat, 15 Nov 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-11-15-creating-a-windows-image-for-o/</guid><description>&lt;p&gt;If you want to build a Windows image for use in your OpenStack
environment, you can follow &lt;a href="http://docs.openstack.org/image-guide/content/windows-image.html"&gt;the example in the official
documentation&lt;/a&gt;, or you can grab a Windows 2012r2
evaluation &lt;a href="http://www.cloudbase.it/ws2012r2/"&gt;pre-built image&lt;/a&gt; from the nice folks at &lt;a href="http://www.cloudbase.it/"&gt;CloudBase&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The CloudBase-provided image is built using a set of scripts and
configuration files that CloudBase has &lt;a href="https://github.com/cloudbase/windows-openstack-imaging-tools/"&gt;made available on
GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The CloudBase repository is an excellent source of information, but I
wanted to understand the process myself. This post describes the
process I went through to establish an automated process for
generating a Windows image suitable for use with OpenStack.&lt;/p&gt;</description></item><item><title>Building Docker images with Puppet</title><link>https://blog.oddbit.com/post/2014-10-22-building-docker-images-with-pu/</link><pubDate>Wed, 22 Oct 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-10-22-building-docker-images-with-pu/</guid><description>&lt;p&gt;I like &lt;a href="http://docker.com/"&gt;Docker&lt;/a&gt;, but I&amp;rsquo;m not a huge fan of using shell scripts for
complex system configuration&amp;hellip;and Dockerfiles are basically giant
shell scripts.&lt;/p&gt;
&lt;p&gt;I was curious whether or not it would be possible to use Puppet during
the &lt;code&gt;docker build&lt;/code&gt; process. As a test case, I used the
&lt;a href="https://github.com/saz/puppet-ssh"&gt;ssh&lt;/a&gt; module included in the openstack-puppet-modules package.&lt;/p&gt;
&lt;p&gt;I started with a manifest like this (in &lt;code&gt;puppet/node.pp&lt;/code&gt;):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class { 'ssh': }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And a Dockerfile like this:&lt;/p&gt;</description></item><item><title>Docker networking with dedicated network containers</title><link>https://blog.oddbit.com/post/2014-10-06-docker-networking-with-dedicat/</link><pubDate>Mon, 06 Oct 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-10-06-docker-networking-with-dedicat/</guid><description>&lt;p&gt;The current version of Docker has a very limited set of networking
options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;bridge&lt;/code&gt; &amp;ndash; connect a container to the Docker bridge&lt;/li&gt;
&lt;li&gt;&lt;code&gt;host&lt;/code&gt; &amp;ndash; run the container in the global network namespace&lt;/li&gt;
&lt;li&gt;&lt;code&gt;container:xxx&lt;/code&gt; &amp;ndash; connect a container to the network namespace of
another container&lt;/li&gt;
&lt;li&gt;&lt;code&gt;none&lt;/code&gt; &amp;ndash; do not configure any networking&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you need something more than that, you can use a tool like
&lt;a href="https://github.com/jpetazzo/pipework"&gt;pipework&lt;/a&gt; to provision additional network interfaces inside the
container, but this leads to a synchronization problem: &lt;code&gt;pipework&lt;/code&gt; can
only be used after your container is running. This means that when
starting your container, you must have logic that will wait until the
necessary networking is available before starting your service.&lt;/p&gt;</description></item><item><title>Integrating custom code with Nova using hooks</title><link>https://blog.oddbit.com/post/2014-09-27-integrating-custom-code-with-n/</link><pubDate>Sat, 27 Sep 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-09-27-integrating-custom-code-with-n/</guid><description>&lt;p&gt;Would you like to run some custom Python code when Nova creates and
destroys virtual instances on your compute hosts? This is possible
using Nova&amp;rsquo;s support for &lt;a href="http://docs.openstack.org/developer/nova/devref/hooks.html"&gt;hooks&lt;/a&gt;, but the existing documentation is
somewhat short on examples, so I&amp;rsquo;ve spent some time trying to get
things working.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://github.com/larsks/demo_nova_hooks"&gt;demo_nova_hooks&lt;/a&gt; repository contains a working example of the
techniques discussed in this article.&lt;/p&gt;
&lt;h2 id="whats-a-hook"&gt;What&amp;rsquo;s a hook?&lt;/h2&gt;
&lt;p&gt;A Nova &amp;ldquo;hook&amp;rdquo; is a mechanism that allows you to attach a class of your
own design to a particular function or method call in Nova. Your
class should define a &lt;code&gt;pre&lt;/code&gt; method (that will be called before the
method is called) and &lt;code&gt;post&lt;/code&gt; function (that will be called after the
method is called):&lt;/p&gt;</description></item><item><title>Stupid command line tricks: Quickly share screen captures</title><link>https://blog.oddbit.com/post/2014-09-23-stupid-cli-quickly-share-scree/</link><pubDate>Tue, 23 Sep 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-09-23-stupid-cli-quickly-share-scree/</guid><description>&lt;p&gt;Sometimes you want to quickly share a screenshot with someone. Here&amp;rsquo;s
my favorite mechanism, which assumes you have installed both &lt;code&gt;curl&lt;/code&gt;
and the &lt;a href="http://www.imagemagick.org/"&gt;ImageMagick&lt;/a&gt; suite.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ import png:- | curl -T- -s chunk.io
http://chunk.io/f/76ea98ea081748e19de4507fde3c2c65 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you run this command, you cursor will change into crosshairs.
Click on a window, and this will grab a png image of that window and
send it to &lt;a href="http://chunk.io/"&gt;chunk.io&lt;/a&gt; using curl.&lt;/p&gt;
&lt;p&gt;You&amp;rsquo;ll get back a URL that you can use to share the image with people.&lt;/p&gt;</description></item><item><title>Heat Hangout</title><link>https://blog.oddbit.com/post/2014-09-05-heat-hangout/</link><pubDate>Fri, 05 Sep 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-09-05-heat-hangout/</guid><description>&lt;p&gt;I ran a Google Hangout this morning on &lt;a href="https://plus.google.com/events/c9u4sjn7ksb8jrmma7vd25aok94"&gt;Deploying with Heat&lt;/a&gt;. You
can find the slides for the presentation on line &lt;a href="http://oddbit.com/rdo-hangout-heat-intro/#/"&gt;here&lt;/a&gt;, and the
Heat templates (as well as slide sources) are available &lt;a href="https://github.com/larsks/rdo-hangout-heat-intro/"&gt;on
github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have any questions about the presentation, please feel free to
ping me on irc (&lt;code&gt;larsks&lt;/code&gt;).&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/qH-qYE1Kmpg?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;</description></item><item><title>Visualizing Heat stacks</title><link>https://blog.oddbit.com/post/2014-09-02-visualizing-heat-stacks/</link><pubDate>Tue, 02 Sep 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-09-02-visualizing-heat-stacks/</guid><description>&lt;p&gt;I spent some time today learning about Heat &lt;a href="https://wiki.openstack.org/wiki/Heat/AutoScaling"&gt;autoscaling groups&lt;/a&gt;,
which are incredibly nifty but a little opaque from the Heat command
line, since commands such as &lt;code&gt;heat resource-list&lt;/code&gt; don&amp;rsquo;t recurse into
nested stacks. It is possible to introspect these resources (you can
pass the physical resource id of a nested stack to &lt;code&gt;heat resource-list&lt;/code&gt;, for example)&amp;hellip;&lt;/p&gt;
&lt;p&gt;&amp;hellip;but I really like visualizing things, so I wrote a quick hack
called &lt;a href="http://github.com/larsks/dotstack"&gt;dotstack&lt;/a&gt; that will generate &lt;a href="http://en.wikipedia.org/wiki/DOT_%28graph_description_language%29"&gt;dot&lt;/a&gt; language output from a
Heat stack. You can process this with &lt;a href="http://www.graphviz.org/"&gt;Graphviz&lt;/a&gt; to produce output
like this, in which graph nodes are automatically colorized by
resource type:&lt;/p&gt;</description></item><item><title>Docker plugin bugs</title><link>https://blog.oddbit.com/post/2014-09-01-docker-plugin-bugs/</link><pubDate>Mon, 01 Sep 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-09-01-docker-plugin-bugs/</guid><description>&lt;p&gt;This is a companion to my &lt;a href="https://blog.oddbit.com/post/2014-08-30-docker-plugin-for-openstack-he/"&gt;article on the Docker plugin for Heat&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;While writing that article, I encountered a number of bugs in the
Docker plugin and elsewhere. I&amp;rsquo;ve submitted patches for most of the
issues I encountered:&lt;/p&gt;
&lt;h2 id="bugs-in-the-heat-plugin"&gt;Bugs in the Heat plugin&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://bugs.launchpad.net/heat/&amp;#43;bug/1364017"&gt;https://bugs.launchpad.net/heat/+bug/1364017&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker plugin fails to delete a container resource in
&lt;code&gt;CREATE_FAILED&lt;/code&gt; state.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://bugs.launchpad.net/heat/&amp;#43;bug/1364041"&gt;https://bugs.launchpad.net/heat/+bug/1364041&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker plugin &lt;code&gt;volumes_from&lt;/code&gt; parameter should be a list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://bugs.launchpad.net/heat/&amp;#43;bug/1364039"&gt;https://bugs.launchpad.net/heat/+bug/1364039&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;docker plugin &lt;code&gt;volumes_from&lt;/code&gt; parameter results in an error&lt;/p&gt;</description></item><item><title>Annotated documentation for DockerInc::Docker::Container</title><link>https://blog.oddbit.com/post/2014-08-30-docker-contain-doc/</link><pubDate>Sat, 30 Aug 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-08-30-docker-contain-doc/</guid><description>&lt;p&gt;This is a companion to my &lt;a href="https://blog.oddbit.com/post/2014-08-30-docker-plugin-for-openstack-he/"&gt;article on the Docker plugin for Heat&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="dockerincdockercontainer"&gt;DockerInc::Docker::Container&lt;/h2&gt;
&lt;h3 id="properties"&gt;Properties&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;cmd&lt;/code&gt; : List&lt;/p&gt;
&lt;p&gt;Command to run after spawning the container.&lt;/p&gt;
&lt;p&gt;Optional property.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; cmd: [ 'thttpd', '-C', '/etc/thttpd.conf', '-D', '-c', '*.cgi']
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;dns&lt;/code&gt; : List&lt;/p&gt;
&lt;p&gt;Set custom DNS servers.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; dns:
 - 8.8.8.8
 - 8.8.4.4
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;docker_endopint&lt;/code&gt; : String&lt;/p&gt;
&lt;p&gt;Docker daemon endpoint. By default the local Docker daemon will
be used.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; docker_endpoint: tcp://192.168.1.100:2375
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;env&lt;/code&gt; : String&lt;/p&gt;</description></item><item><title>Docker plugin for OpenStack Heat</title><link>https://blog.oddbit.com/post/2014-08-30-docker-plugin-for-openstack-he/</link><pubDate>Sat, 30 Aug 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-08-30-docker-plugin-for-openstack-he/</guid><description>&lt;p&gt;I have been looking at both Docker and OpenStack recently. In my &lt;a href="https://blog.oddbit.com/post/2014-08-28-novadocker-and-environment-var/"&gt;last
post&lt;/a&gt; I talked a little about the &lt;a href="https://github.com/stackforge/nova-docker"&gt;Docker driver for Nova&lt;/a&gt;; in
this post I&amp;rsquo;ll be taking an in-depth look at the Docker plugin for
Heat, which has been available &lt;a href="https://blog.docker.com/2014/03/docker-will-be-in-openstack-icehouse/"&gt;since the Icehouse release&lt;/a&gt; but is
surprisingly under-documented.&lt;/p&gt;
&lt;p&gt;The &lt;a href="https://blog.docker.com/2014/03/docker-will-be-in-openstack-icehouse/"&gt;release announcement&lt;/a&gt; on the Docker blog includes an
example Heat template, but it is unfortunately grossly inaccurate and
has led many people astray. In particular:&lt;/p&gt;</description></item><item><title>Using wait conditions with Heat</title><link>https://blog.oddbit.com/post/2014-08-30-using-wait-conditions-with-hea/</link><pubDate>Sat, 30 Aug 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-08-30-using-wait-conditions-with-hea/</guid><description>&lt;p&gt;This post accompanies my &lt;a href="https://blog.oddbit.com/post/2014-08-30-docker-plugin-for-openstack-he/"&gt;article on the Docker plugin for
Heat&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In order for &lt;code&gt;WaitCondition&lt;/code&gt; resources to operate correctly in Heat, you
will need to make sure that that you have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Created the necessary Heat domain and administrative user in
Keystone,&lt;/li&gt;
&lt;li&gt;Configured appropriate values in &lt;code&gt;heat.conf&lt;/code&gt; for
&lt;code&gt;stack_user_domain&lt;/code&gt;, &lt;code&gt;stack_domain_admin&lt;/code&gt;, and
&lt;code&gt;stack_domain_admin_password&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Configured an appropriate value in &lt;code&gt;heat.conf&lt;/code&gt; for
&lt;code&gt;heat_waitcondition_server_url&lt;/code&gt;. On a single-system install this
will often be pointed by default at &lt;code&gt;127.0.0.1&lt;/code&gt;, which, hopefully for
obvious reasons, won&amp;rsquo;t be of any use to your Nova servers.&lt;/li&gt;
&lt;li&gt;Enabled the &lt;code&gt;heat-api-cfn&lt;/code&gt; service,&lt;/li&gt;
&lt;li&gt;Configured your firewall to permit access to the CFN service (which
runs on port 8000).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Steve Hardy has a blog post on &lt;a href="http://hardysteven.blogspot.co.uk/2014/04/heat-auth-model-updates-part-2-stack.html"&gt;stack domain users&lt;/a&gt; that goes into
detail on configuring authentication for Heat and Keystone.&lt;/p&gt;</description></item><item><title>nova-docker and environment variables</title><link>https://blog.oddbit.com/post/2014-08-28-novadocker-and-environment-var/</link><pubDate>Thu, 28 Aug 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-08-28-novadocker-and-environment-var/</guid><description>&lt;p&gt;I&amp;rsquo;ve been playing with &lt;a href="https://docker.com/"&gt;Docker&lt;/a&gt; a bit recently, and decided to take
a look at the &lt;a href="https://github.com/stackforge/nova-docker"&gt;nova-docker&lt;/a&gt; driver for &lt;a href="http://openstack.org/"&gt;OpenStack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;nova-docker&lt;/code&gt; driver lets Nova, the OpenStack Compute service,
spawn Docker containers instead of hypervisor-based servers. For
certain workloads, this leads to better resource utilization than you
would get with a hypervisor-based solution, while at the same time
givin you better support for multi-tenancy and flexible networking
than you get with Docker by itself.&lt;/p&gt;</description></item><item><title>lvcache: a tool for managing LVM caches</title><link>https://blog.oddbit.com/post/2014-08-16-lvcache-a-tool-for-managing-lv/</link><pubDate>Sat, 16 Aug 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-08-16-lvcache-a-tool-for-managing-lv/</guid><description>&lt;p&gt;Until recently I had a &lt;a href="http://bcache.evilpiepirate.org/"&gt;bcache&lt;/a&gt; based setup on my laptop, but when
forced by circumstance to reinstall everything I spent some time
looking for alternatives that were less disruptive to configure on an
existing system.&lt;/p&gt;
&lt;p&gt;I came across &lt;a href="http://rwmj.wordpress.com/2014/05/22/using-lvms-new-cache-feature/"&gt;Richard Jones&amp;rsquo; article&lt;/a&gt; discussing the recent work to
integrate &lt;a href="https://en.wikipedia.org/wiki/Dm-cache"&gt;dm-cache&lt;/a&gt; into &lt;a href="http://en.wikipedia.org/wiki/Logical_Volume_Manager_%28Linux%29"&gt;LVM&lt;/a&gt;. Unlike &lt;em&gt;bcache&lt;/em&gt; and unlike using
&lt;em&gt;dm-cache&lt;/em&gt; directly, the integration with LVM makes it easy to
associate devices with an existing logical volume.&lt;/p&gt;
&lt;p&gt;I have put together a small tool called &lt;a href="https://github.com/larsks/lvcache"&gt;lvcache&lt;/a&gt; that simplies the
process of:&lt;/p&gt;</description></item><item><title>Four ways to connect a docker container to a local network</title><link>https://blog.oddbit.com/post/2014-08-11-four-ways-to-connect-a-docker/</link><pubDate>Mon, 11 Aug 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-08-11-four-ways-to-connect-a-docker/</guid><description>&lt;p&gt;&lt;strong&gt;Update (2018-03-22)&lt;/strong&gt; Since I wrote this document back in 2014,
Docker has developed the &lt;a href="https://docs.docker.com/network/macvlan/"&gt;macvlan network
driver&lt;/a&gt;. That gives you a
&lt;em&gt;supported&lt;/em&gt; mechanism for direct connectivity to a local layer 2
network. I&amp;rsquo;ve &lt;a href="https://blog.oddbit.com/2018/03/12/using-docker-macvlan-networks/"&gt;written an article about working with the macvlan
driver&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;This article discusses four ways to make a Docker container appear on
a local network. These are not suggested as practical solutions, but
are meant to illustrate some of the underlying network technology
available in Linux.&lt;/p&gt;</description></item><item><title>gpio-watch: Run scripts in response to GPIO signals</title><link>https://blog.oddbit.com/post/2014-07-26-gpiowatch-run-scripts-in-respo/</link><pubDate>Sat, 26 Jul 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-07-26-gpiowatch-run-scripts-in-respo/</guid><description>&lt;p&gt;For a small project I&amp;rsquo;m working on I needed to attach a few buttons to
a &lt;a href="http://raspberrypi.org/"&gt;Raspberry Pi&lt;/a&gt; and have some code execute in response to the
button presses.&lt;/p&gt;
&lt;p&gt;Normally I would reach for &lt;a href="http://python.org/"&gt;Python&lt;/a&gt; for a simple project like this,
but constraints of the project made it necessary to implement
something in C with minimal dependencies. I didn&amp;rsquo;t want to write
something that was tied closely to my project&amp;hellip;&lt;/p&gt;
&lt;figure&gt;&lt;a href="https://xkcd.com/974/"&gt;&lt;img src="http://imgs.xkcd.com/comics/the_general_problem.png"&gt;&lt;/a&gt;
&lt;/figure&gt;

&lt;p&gt;&amp;hellip;so I ended up writing &lt;a href="https://github.com/larsks/gpio-watch"&gt;gpio-watch&lt;/a&gt;, a simple tool for connecting
shell scripts (or any other executable) to GPIO events. There are a
few ways to interact with GPIO on the Raspberry Pi. For the fastest
possible performance, you will need to interact directly with the
underlying hardware using, e.g., something like &lt;a href="http://hertaville.com/2014/07/07/rpimmapgpio/"&gt;direct register
access&lt;/a&gt;. Since I was only responding to button presses I opted
to take advantage of the &lt;a href="https://www.kernel.org/doc/Documentation/gpio/sysfs.txt"&gt;GPIO sysfs interface&lt;/a&gt;, which exposes
the GPIO pins via the filesystem.&lt;/p&gt;</description></item><item><title>Tracking down a kernel bug with git bisect</title><link>https://blog.oddbit.com/post/2014-07-21-tracking-down-a-kernel-bug-wit/</link><pubDate>Mon, 21 Jul 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-07-21-tracking-down-a-kernel-bug-wit/</guid><description>&lt;p&gt;After a recent upgrade of my Fedora 20 system to kernel 3.15.mumble, I
started running into a problem (&lt;a href="https://bugzilla.redhat.com/show_bug.cgi?id=1121345"&gt;BZ 1121345&lt;/a&gt;) with my &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;
containers. Operations such as &lt;code&gt;su&lt;/code&gt; or &lt;code&gt;runuser&lt;/code&gt; would fail with the
singularly unhelpful &lt;code&gt;System error&lt;/code&gt; message:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker run -ti fedora /bin/bash
bash-4.2# su -c 'uptime'
su: System error
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hooking up something (like, say, &lt;code&gt;socat unix-listen:/dev/log -&lt;/code&gt;) to
&lt;code&gt;/dev/log&lt;/code&gt; revealed that the system was logging:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Jul 19 14:31:18 su: PAM audit_log_acct_message() failed: Operation not permitted
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Downgrading the kernel to 3.14 immediately resolved the problem,
suggesting that this was at least partly a kernel issue. This seemed
like a great opportunity to play with the &lt;a href="http://git-scm.com/docs/git-bisect"&gt;git bisect&lt;/a&gt; command,
which uses a binary search to find which commit introduced a
particular problem.&lt;/p&gt;</description></item><item><title>Booting an instance with multiple fixed addresses</title><link>https://blog.oddbit.com/post/2014-05-28-booting-an-instance-with-multi/</link><pubDate>Wed, 28 May 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-05-28-booting-an-instance-with-multi/</guid><description>&lt;p&gt;This article expands on my answer to &lt;a href="https://ask.openstack.org/en/question/30690/add-multiple-specific-ips-to-instance/"&gt;Add multiple specific IPs to
instance&lt;/a&gt;, a question posted to &lt;a href="https://ask.openstack.org/"&gt;ask.openstack.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In order to serve out SSL services from an OpenStack instance, you
will generally want one local ip address for each SSL virtual host you
support. It is possible to create an instance with multiple fixed
addresses, but there are a few complications to watch out for.&lt;/p&gt;
&lt;h1 id="assumptions"&gt;Assumptions&lt;/h1&gt;
&lt;p&gt;This article assumes that the following resources exist:&lt;/p&gt;</description></item><item><title>Multiple external networks with a single L3 agent</title><link>https://blog.oddbit.com/post/2014-05-28-multiple-external-networks-wit/</link><pubDate>Wed, 28 May 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-05-28-multiple-external-networks-wit/</guid><description>&lt;p&gt;In the old days (so, like, last year), Neutron supported a single
external network per L3 agent. You would run something like this&amp;hellip;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ neutron net-create external --router:external=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;hellip;and neutron would map this to the bridge defined in
&lt;code&gt;external_network_bridge&lt;/code&gt; in &lt;code&gt;/etc/neutron/l3_agent.ini&lt;/code&gt;. If you
wanted to support more than a single external network, you would need
to run multiple L3 agents, each with a unique value for
&lt;code&gt;external_network_bridge&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;There is now a better option available.&lt;/p&gt;</description></item><item><title>Video: Configuring OpenStack's external bridge on a single-interface system</title><link>https://blog.oddbit.com/post/2014-05-27-configuring-openstacks-externa/</link><pubDate>Tue, 27 May 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-05-27-configuring-openstacks-externa/</guid><description>&lt;p&gt;I&amp;rsquo;ve just put a video on Youtube that looks at the steps required to
set up the external bridge (&lt;code&gt;br-ex&lt;/code&gt;) on a single-interface system:&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/8zFQG5mKwPk?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;</description></item><item><title>Open vSwitch and persistent MAC addresses</title><link>https://blog.oddbit.com/post/2014-05-23-open-vswitch-and-persistent-ma/</link><pubDate>Fri, 23 May 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-05-23-open-vswitch-and-persistent-ma/</guid><description>&lt;p&gt;Normally I like to post solutions, but today&amp;rsquo;s post is about a
vexing problem to which I have not been able to find a solution.&lt;/p&gt;
&lt;p&gt;This started as a simple attempt to set up external connectivity on
an all-in-one Icehouse install deployed on an OpenStack instance. I
wanted to add &lt;code&gt;eth0&lt;/code&gt; to &lt;code&gt;br-ex&lt;/code&gt; in order to model a typical method for
providing external connectivity, but I ran into a very odd problem:
the system would boot and work fine for a few seconds, but would then
promptly lose network connectivity.&lt;/p&gt;</description></item><item><title>Solved: Open vSwitch and persistent MAC addresses</title><link>https://blog.oddbit.com/post/2014-05-23-solved-open-vswitch-and-persis/</link><pubDate>Fri, 23 May 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-05-23-solved-open-vswitch-and-persis/</guid><description>&lt;p&gt;In my &lt;a href="https://blog.oddbit.com/2014/05/23/open-vswitch-and-persistent-ma/"&gt;previous post&lt;/a&gt; I discussed a problem I was having setting a
persistent MAC address on an OVS bridge device. It looks like the
short answer is, &amp;ldquo;don&amp;rsquo;t use &lt;code&gt;ip link set ...&lt;/code&gt;&amp;rdquo; for this purpose.&lt;/p&gt;
&lt;p&gt;You can set the bridge MAC address via &lt;code&gt;ovs-vsctl&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ovs-vsctl set bridge br-ex other-config:hwaddr=$MACADDR
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So I&amp;rsquo;ve updated my &lt;code&gt;ifconfig-br-ex&lt;/code&gt; to look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DEVICE=br-ex
DEVICETYPE=ovs
TYPE=OVSBridge
ONBOOT=yes
OVSBOOTPROTO=dhcp
OVSDHCPINTERFACES=eth0
MACADDR=fa:16:3e:ef:91:ec
OVS_EXTRA=&amp;quot;set bridge br-ex other-config:hwaddr=$MACADDR&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;OVS_EXTRA&lt;/code&gt; parameter gets passed to the &lt;code&gt;add-br&lt;/code&gt; call like this:&lt;/p&gt;</description></item><item><title>Sharing a terminal session with termshare</title><link>https://blog.oddbit.com/post/2014-05-21-sharing-a-terminal-session-wit/</link><pubDate>Wed, 21 May 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-05-21-sharing-a-terminal-session-wit/</guid><description>&lt;p&gt;&lt;a href="https://github.com/progrium/termshare"&gt;Termshare&lt;/a&gt; is a tool for sharing your terminal in a browser
session. It supports both read-only and read-write sessions, and
unlike many other tools it does not require any software installation
on the remote side. This makes it tremendously handy for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Streaming terminal demonstrations to a diverse audience, or&lt;/li&gt;
&lt;li&gt;Sharing a terminal session with someone without needing to much
about with ssh, tmux, screen, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;rsquo;ve successfully used &lt;a href="https://github.com/progrium/termshare"&gt;Termshare&lt;/a&gt; under both Fedora (19 and 20) and
CentOS. To get started on these platforms, you&amp;rsquo;ll need to install the
&lt;a href="http://golang.org/"&gt;Go&lt;/a&gt; language, &lt;a href="http://git-scm.org/"&gt;git&lt;/a&gt; for cloning the termshare repository, and
&lt;a href="http://mercurial.selenic.com/"&gt;mercurial&lt;/a&gt; to support installation of some Go libraries:&lt;/p&gt;</description></item><item><title>Fedora and OVS Bridge Interfaces</title><link>https://blog.oddbit.com/post/2014-05-20-fedora-and-ovs-bridge-interfac/</link><pubDate>Tue, 20 May 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-05-20-fedora-and-ovs-bridge-interfac/</guid><description>&lt;p&gt;I run OpenStack on my laptop, and I&amp;rsquo;ve been chasing down a pernicious
problem with OVS bridge interfaces under both F19 and F20. My
OpenStack environment relies on an OVS bridge device named &lt;code&gt;br-ex&lt;/code&gt; for
external connectivity and for making services available to OpenStack
instances, but after rebooting, &lt;code&gt;br-ex&lt;/code&gt; was consistently unconfigured,
which caused a variety of problems.&lt;/p&gt;
&lt;p&gt;This is the network configuration file for &lt;code&gt;br-ex&lt;/code&gt; on my system:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DEVICE=br-ex
DEVICETYPE=ovs
TYPE=OVSBridge
BOOTPROT=static
IPADDR=192.168.200.1
NETMASK=255.255.255.0
ONBOOT=yes
NM_CONTROLLED=no
ZONE=openstack
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Running &lt;code&gt;ifup br-ex&lt;/code&gt; would also fail to configure the interface, but
running &lt;code&gt;ifdown br-ex; ifup br-ex&lt;/code&gt; would configure things
appropriately.&lt;/p&gt;</description></item><item><title>Firewalld, NetworkManager, and OpenStack</title><link>https://blog.oddbit.com/post/2014-05-20-firewalld-and-openstack/</link><pubDate>Tue, 20 May 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-05-20-firewalld-and-openstack/</guid><description>&lt;p&gt;These are my notes on making OpenStack play well with &lt;a href="https://fedoraproject.org/wiki/FirewallD"&gt;firewalld&lt;/a&gt;
and &lt;a href="https://wiki.gnome.org/Projects/NetworkManager"&gt;NetworkManager&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="networkmanager"&gt;NetworkManager&lt;/h2&gt;
&lt;p&gt;By default, NetworkManager attempts to start a DHCP client on every
new available interface. Since booting a single instance in OpenStack
can result in the creation of several virtual interfaces, this results
in a lot of:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;May 19 11:58:24 pk115wp-lkellogg NetworkManager[1357]: &amp;lt;info&amp;gt;
 Activation (qvb512640bd-ee) starting connection 'Wired connection 2'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can disable this behavior by adding the following to
&lt;code&gt;/etc/NetworkManager/NetworkManager.conf&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Flat networks with ML2 and OpenVSwitch</title><link>https://blog.oddbit.com/post/2014-05-19-flat-networks-with-ml-and-open/</link><pubDate>Mon, 19 May 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-05-19-flat-networks-with-ml-and-open/</guid><description>&lt;p&gt;Due to an unfortunate incident involving sleep mode and an overheated
backpack I had the &amp;ldquo;opportunity&amp;rdquo; to rebuild my laptop. Since this meant
reinstalling OpenStack I used this as an excuse to finally move to the ML2
network plugin for Neutron.&lt;/p&gt;
&lt;p&gt;I was attempting to add an external network using the normal incantation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;neutron net-create external -- --router:external=true \
 --provider:network_type=flat \
 --provider:physical_network=physnet1
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this command completed successfully, I was left without any
connectivity between &lt;code&gt;br-int&lt;/code&gt; and &lt;code&gt;br-ex&lt;/code&gt;, despite having in my
&lt;code&gt;/etc/neutron/plugins/ml2/ml2_conf.ini&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Extending Puppet</title><link>https://blog.oddbit.com/post/2014-04-16-article-on-extending-puppet/</link><pubDate>Wed, 16 Apr 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-04-16-article-on-extending-puppet/</guid><description>&lt;p&gt;I wanted to learn about writing custom Puppet types and providers.
The official documentation is a little sparse, but I finally stumbled
upon the following series of articles by &lt;a href="http://garylarizza.com/"&gt;Gary Larizza&lt;/a&gt; that provide
a great deal of insight into the process and a bunch of example code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://garylarizza.com/blog/2013/11/25/fun-with-providers/"&gt;Fun With Puppet Providers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://garylarizza.com/blog/2013/11/26/fun-with-providers-part-2/"&gt;Who Abstracted My Ruby?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://garylarizza.com/blog/2013/12/15/seriously-what-is-this-provider-doing/"&gt;Seriously, What Is This Provider Doing?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>Multinode OpenStack with Packstack</title><link>https://blog.oddbit.com/post/2014-02-27-multinode-packstack/</link><pubDate>Thu, 27 Feb 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-02-27-multinode-packstack/</guid><description>&lt;p&gt;I was the presenter for this morning&amp;rsquo;s &lt;a href="http://openstack.redhat.com/"&gt;RDO&lt;/a&gt; hangout, where I ran
through a simple demonstration of setting up a multinode OpenStack
deployment using &lt;a href="https://wiki.openstack.org/wiki/Packstack"&gt;packstack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The slides are online &lt;a href="http://goo.gl/Yvmd0P"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the video (also available on the &lt;a href="https://plus.google.com/events/cm9ff549vmsim737lj7hopk4gao"&gt;event page&lt;/a&gt;):&lt;/p&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/DGf-ny25OAw?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;</description></item><item><title>Show OVS external-ids</title><link>https://blog.oddbit.com/post/2014-01-19-show-ovs-externalids/</link><pubDate>Sun, 19 Jan 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-01-19-show-ovs-externalids/</guid><description>&lt;p&gt;This is just here as a reminder for me:&lt;/p&gt;
&lt;p&gt;An OVS interface has a variety of attributes associated with it, including an
&lt;code&gt;external-id&lt;/code&gt; field that can be used to associate resources outside of
OpenVSwitch with the interface. You can view this field with the following
command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ovs-vsctl --columns=name,external-ids list Interface
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which on my system, with a single virtual instance, looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# ovs-vsctl --columns=name,external-ids list Interface
.
.
.
name : &amp;quot;qvo519d7cc4-75&amp;quot;
external_ids : {attached-mac=&amp;quot;fa:16:3e:f7:75:b0&amp;quot;, iface-id=&amp;quot;519d7cc4-7593-4944-af7b-4056436f2d66&amp;quot;, iface-status=active, vm-uuid=&amp;quot;0330b084-03db-4d42-a231-2cd6ad89515b&amp;quot;}
.
.
.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the information contained here:&lt;/p&gt;</description></item><item><title>Stupid OpenStack Tricks</title><link>https://blog.oddbit.com/post/2014-01-16-stupid-openstack-tricks/</link><pubDate>Thu, 16 Jan 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-01-16-stupid-openstack-tricks/</guid><description>&lt;p&gt;I work with several different OpenStack installations. I usually work
on the command line, sourcing in an appropriate &lt;code&gt;stackrc&lt;/code&gt; with
credentials as necessary, but occasionally I want to use the dashboard
for something.&lt;/p&gt;
&lt;p&gt;For all of the deployments with which I work, the keystone endpoint is
on the same host as the dashboard. So rather than trying to remember
which dashboard url I want for the environment I&amp;rsquo;m currently using on
the command line, I put together this shell script:&lt;/p&gt;</description></item><item><title>Direct access to Nova metadata</title><link>https://blog.oddbit.com/post/2014-01-14-direct-access-to-nova-metadata/</link><pubDate>Tue, 14 Jan 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-01-14-direct-access-to-nova-metadata/</guid><description>&lt;p&gt;When you boot a virtual instance under &lt;a href="http://www.openstack.org/"&gt;OpenStack&lt;/a&gt;, your instance
has access to certain &lt;a href="http://docs.openstack.org/admin-guide-cloud/content//section_metadata-service.html"&gt;instance metadata&lt;/a&gt; via the Nova metadata service,
which is canonically available at &lt;a href="http://169.254.169.254/"&gt;http://169.254.169.254/&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In an environment running &lt;a href="https://wiki.openstack.org/wiki/Neutron"&gt;Neutron&lt;/a&gt;, a request from your instance
must traverse a number of steps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From the instance to a router,&lt;/li&gt;
&lt;li&gt;Through a NAT rule in the router namespace,&lt;/li&gt;
&lt;li&gt;To an instance of the neutron-ns-metadata-proxy,&lt;/li&gt;
&lt;li&gt;To the actual Nova metadata service&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When there are problem accessing the metadata, it can be helpful to
verify that the metadata service itself is configured correctly and
returning meaningful information.&lt;/p&gt;</description></item><item><title>RDO Bug Triage</title><link>https://blog.oddbit.com/post/2014-01-13-rdo-bug-triage/</link><pubDate>Mon, 13 Jan 2014 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2014-01-13-rdo-bug-triage/</guid><description>&lt;p&gt;This Wednesday, January 15, at 14:00 UTC (that&amp;rsquo;s 9AM US/Eastern, or
&lt;code&gt;date -d &amp;quot;14:00 UTC&amp;quot;&lt;/code&gt; in your local timezone) I will be helping out
with the
&lt;a href="http://openstack.redhat.com/"&gt;RDO&lt;/a&gt; &lt;a href="http://openstack.redhat.com/RDO-BugTriage"&gt;bug triage day&lt;/a&gt;. We&amp;rsquo;ll be trying to validate all the
&lt;a href="http://goo.gl/NqW2LN"&gt;untriaged bugs&lt;/a&gt; opened against RDO.&lt;/p&gt;
&lt;p&gt;Feel free to drop by on &lt;code&gt;#rdo&lt;/code&gt; and help out or ask questions.&lt;/p&gt;</description></item><item><title>Visualizing Neutron Networking with GraphViz</title><link>https://blog.oddbit.com/post/2013-12-23-visualizing-network-with-graph/</link><pubDate>Mon, 23 Dec 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-12-23-visualizing-network-with-graph/</guid><description>&lt;p&gt;I&amp;rsquo;ve put together a few tools to help gather information about your
Neutron and network configuration and visualize it in different ways.
All of these tools are available as part of my &lt;a href="http://github.com/larsks/neutron-diag/"&gt;neutron-diag&lt;/a&gt;
repository on GitHub.&lt;/p&gt;
&lt;p&gt;In this post I&amp;rsquo;m going to look at a tool that will help you visualize
the connectivity of network devices on your system.&lt;/p&gt;
&lt;h2 id="mk-network-dot"&gt;mk-network-dot&lt;/h2&gt;
&lt;p&gt;There are a lot of devices involved in your Neutron network
configuration. Information originating in one of your instances has
two traverse &lt;em&gt;at least&lt;/em&gt; seven network devices before seeing the light
of day. Understanding how everything connects is critical if you&amp;rsquo;re
trying to debug problems in your envionment.&lt;/p&gt;</description></item><item><title>An introduction to OpenStack Heat</title><link>https://blog.oddbit.com/post/2013-12-06-an-introduction-to-openstack-h/</link><pubDate>Fri, 06 Dec 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-12-06-an-introduction-to-openstack-h/</guid><description>&lt;p&gt;&lt;a href="https://wiki.openstack.org/wiki/Heat"&gt;Heat&lt;/a&gt; is a template-based orchestration mechanism for use with
OpenStack. With Heat, you can deploy collections of resources &amp;ndash;
networks, servers, storage, and more &amp;ndash; all from a single,
parameterized template.&lt;/p&gt;
&lt;p&gt;In this article I will introduce Heat templates and the &lt;code&gt;heat&lt;/code&gt; command
line client.&lt;/p&gt;
&lt;h2 id="writing-templates"&gt;Writing templates&lt;/h2&gt;
&lt;p&gt;Because Heat began life as an analog of AWS &lt;a href="http://aws.amazon.com/cloudformation/"&gt;CloudFormation&lt;/a&gt;, it
supports the template formats used by the CloudFormation (CFN) tools.
It also supports its own native template format, called HOT (&amp;ldquo;Heat
Orchestration Templates&amp;rdquo;). In this article I will be using the HOT
template syntax, which is fully specified on &lt;a href="http://docs.openstack.org/developer/heat/template_guide/hot_spec.html"&gt;the OpenStack
website&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>A Python interface to signalfd() using FFI</title><link>https://blog.oddbit.com/post/2013-11-28-a-python-interface-to-signalfd/</link><pubDate>Thu, 28 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-28-a-python-interface-to-signalfd/</guid><description>&lt;p&gt;I just recently learned about the &lt;code&gt;signalfd(2)&lt;/code&gt; system call, which was
introduced to the Linux kernel &lt;a href="http://lwn.net/Articles/225714/"&gt;back in 2007&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;signalfd() creates a file descriptor that can be used to accept
signals targeted at the caller. This provides an alternative to
the use of a signal handler or sigwaitinfo(2), and has the
advantage that the file descriptor may be monitored by select(2),
poll(2), and epoll(7).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The traditional asynchronous delivery mechanism can be tricky to get
right, whereas this provides a convenient fd interface that integrates
nicely with your existing event-based code.&lt;/p&gt;</description></item><item><title>Long polling with Javascript and Python</title><link>https://blog.oddbit.com/post/2013-11-23-long-polling-with-ja/</link><pubDate>Sat, 23 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-23-long-polling-with-ja/</guid><description>&lt;p&gt;In this post I&amp;rsquo;m going to step through an example web chat system
implemented in Python (with &lt;a href="http://bottlepy.org/docs/"&gt;Bottle&lt;/a&gt; and &lt;a href="http://www.gevent.org/"&gt;gevent&lt;/a&gt;) that uses long
polling to implement a simple publish/subscribe mechanism for
efficiently updating connected clients.&lt;/p&gt;
&lt;p&gt;My &lt;a href="http://github.com/larsks/pusub_example/"&gt;pubsub_example&lt;/a&gt; repository on &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt; has a complete
project that implements the ideas discussed in this article. This
project can be deployed directly on &lt;a href="http://openshift.com/"&gt;OpenShift&lt;/a&gt; if you want to try
things out on your own. You can also try it out online at
&lt;a href="http://pubsub.example.oddbit.com/"&gt;http://pubsub.example.oddbit.com/&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Sockets on OpenShift</title><link>https://blog.oddbit.com/post/2013-11-23-openshift-socket-pro/</link><pubDate>Sat, 23 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-23-openshift-socket-pro/</guid><description>&lt;p&gt;In this article, a followup to my &lt;a href="https://blog.oddbit.com/post/2013-11-23-long-polling-with-ja/"&gt;previous post&lt;/a&gt; regarding
long-poll servers and Python, we investigate the code changes that
were necessary to make the code work when deployed on OpenShift.&lt;/p&gt;
&lt;p&gt;In the previous post, we implemented IO polling to watch for client
disconnects at the same time we were waiting for messages on a message
bus:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;poll = zmq.Poller()
poll.register(subsock, zmq.POLLIN)
poll.register(rfile, zmq.POLLIN)

events = dict(poll.poll())

.
.
.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you were to try this at home, you would find that everything worked
as described&amp;hellip;but if you were to deploy the same code to OpenShift,
you would find that the problem we were trying to solve (the server
holding file descriptors open after a client disconnected) would still
exist.&lt;/p&gt;</description></item><item><title>A unified CLI for OpenStack</title><link>https://blog.oddbit.com/post/2013-11-22-a-unified-cli-for-op/</link><pubDate>Fri, 22 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-22-a-unified-cli-for-op/</guid><description>&lt;p&gt;The &lt;a href="https://github.com/openstack/python-openstackclient"&gt;python-openstackclient&lt;/a&gt; project, by &lt;a href="https://github.com/dtroyer"&gt;Dean Troyer&lt;/a&gt; and
others, is a new command line tool to replace the existing command
line clients (including commands such as &lt;code&gt;nova&lt;/code&gt;, &lt;code&gt;keystone&lt;/code&gt;, &lt;code&gt;cinder&lt;/code&gt;,
etc).&lt;/p&gt;
&lt;p&gt;This tool solves two problems I&amp;rsquo;ve encountered in the past:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Command line options between different command line clients are
sometimes inconsistent.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The output from the legacy command line tools is not designed to be
machine parse-able (and yet people &lt;a href="https://github.com/openstack/python-openstackclient"&gt;do it anyway&lt;/a&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The new &lt;code&gt;openstack&lt;/code&gt; CLI framework is implement using the &lt;a href="https://github.com/dreamhost/cliff"&gt;cliff&lt;/a&gt;
module for Python, which will help enforce a consistent interface to
the various subcommands (because common options can be shared, and
just having everything in the same codebase will help tremendously).
Cliff also provides flexible table formatters. It includes a number
of useful formatters out of the box, and can be extended via
setuptools entry points.&lt;/p&gt;</description></item><item><title>Automatic maintenance of tag feeds</title><link>https://blog.oddbit.com/post/2013-11-22-automatic-maintenanc/</link><pubDate>Fri, 22 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-22-automatic-maintenanc/</guid><description>&lt;p&gt;I recently added some scripts to automatically generate tag feeds for
my blog when pushing new content. I&amp;rsquo;m using GitHub Pages to publish
everything, so it seemed easiest to make tag generation part of a
&lt;code&gt;pre-push&lt;/code&gt; hook (new in Git 1.8.2). This hook is run automatically as
part of the &lt;code&gt;git push&lt;/code&gt; operation, so it&amp;rsquo;s the perfect place to insert
generated content that must be kept in sync with posts on the blog.&lt;/p&gt;</description></item><item><title>Enabled blog comments</title><link>https://blog.oddbit.com/post/2013-11-18-enabled-comments/</link><pubDate>Mon, 18 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-18-enabled-comments/</guid><description>&lt;p&gt;I&amp;rsquo;ve enabled blog comments using &lt;a href="http://disqus.com/"&gt;Disqus&lt;/a&gt;. This is something of an
experiment, since (a) I&amp;rsquo;m not really happy with how Disqus is handling
user registration these days and (b) I don&amp;rsquo;t know that I have the time
to moderate anything. But we&amp;rsquo;ll see.&lt;/p&gt;</description></item><item><title>json-tools: cli for generating and filtering json</title><link>https://blog.oddbit.com/post/2013-11-17-json-tools/</link><pubDate>Sun, 17 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-17-json-tools/</guid><description>&lt;p&gt;Interacting with JSON-based APIs from the command line can be
difficult, and OpenStack is filled with REST APIs that consume or
produce JSON. I&amp;rsquo;ve just put pair of tools for generating and
filtering JSON on the command line, called collectively
&lt;a href="http://github.com/larsks/json-tools/"&gt;json-tools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Both make use of the Python &lt;a href="https://github.com/akesterson/dpath-python"&gt;dpath&lt;/a&gt; module to populate or filter
JSON objects.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;jsong&lt;/code&gt; command generates JSON on &lt;code&gt;stdout&lt;/code&gt;. You provide &lt;code&gt;/&lt;/code&gt;-delimited paths
on the command line to represent the JSON structure. For example, if
you run:&lt;/p&gt;</description></item><item><title>Quantum in Too Much Detail</title><link>https://blog.oddbit.com/post/2013-11-14-quantum-in-too-much-detail/</link><pubDate>Thu, 14 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-14-quantum-in-too-much-detail/</guid><description>&lt;blockquote&gt;
&lt;p&gt;I originally posted this article on
the &lt;a href="http://openstack.redhat.com/Networking_in_too_much_detail"&gt;RDO&lt;/a&gt;
website.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id="the-players"&gt;The players&lt;/h1&gt;
&lt;p&gt;This document describes the architecture that results from a
particular OpenStack configuration, specifically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quantum networking using GRE tunnels;&lt;/li&gt;
&lt;li&gt;A dedicated network controller;&lt;/li&gt;
&lt;li&gt;A single instance running on a compute host&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Much of the document will be relevant to other configurations, but
details will vary based on your choice of layer 2 connectivity, number
of running instances, and so forth.&lt;/p&gt;
&lt;p&gt;The examples in this document were generated on a system with Quantum
networking but will generally match what you see under Neutron as
well, if you replace &lt;code&gt;quantum&lt;/code&gt; by &lt;code&gt;neutron&lt;/code&gt; in names. The OVS flow
rules under Neutron are somewhat more complex and I will cover those
in another post.&lt;/p&gt;</description></item><item><title>Moving to GitHub</title><link>https://blog.oddbit.com/post/2013-11-13-moving-to-github/</link><pubDate>Wed, 13 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-13-moving-to-github/</guid><description>&lt;p&gt;This blog has been hosted on &lt;a href="http://scriptogr.am/"&gt;scriptogram&lt;/a&gt; for the past year or so.
Unfortunately, while I like the publish-via-Dropbox mechanism, there
have been enough problems recently that I&amp;rsquo;ve finally switched over to
using &lt;a href="http://pages.github.com/"&gt;GitHub Pages&lt;/a&gt; for hosting. I&amp;rsquo;ve been thinking about doing
this for a while, but the things that finally pushed me to make the
change were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sync problems that would prevent new posts from appearing (and that
at least once caused posts to disappear).&lt;/li&gt;
&lt;li&gt;Lack of any response to bug reports by the site maintainers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A benefit of the publish-via-Dropbox mechanism is, of course, that I
already had all the data and didn&amp;rsquo;t need to go through any sort of
export process.&lt;/p&gt;</description></item><item><title>A random collection of OpenStack Tools</title><link>https://blog.oddbit.com/post/2013-11-12-a-random-collection/</link><pubDate>Tue, 12 Nov 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-11-12-a-random-collection/</guid><description>&lt;p&gt;I&amp;rsquo;ve been working with &lt;a href="http://openstack.org/"&gt;OpenStack&lt;/a&gt; a lot recently, and I&amp;rsquo;ve ended up with a small collection of utilities that make my life easier. On the odd chance that they&amp;rsquo;ll make your life easier, too, I thought I&amp;rsquo;d hilight them here.&lt;/p&gt;
&lt;h2 id="crux"&gt;Crux&lt;/h2&gt;
&lt;p&gt;&lt;a href="http://github.com/larsks/crux"&gt;Crux&lt;/a&gt; is a tool for provisioning tenants, users, and roles in keystone. Instead of a sequence of keystone command, you can provision new tenants, users, and roles with a single comand.&lt;/p&gt;</description></item><item><title>Why does the Neutron documentation recommend three interfaces?</title><link>https://blog.oddbit.com/post/2013-10-28-why-does-the-neutron/</link><pubDate>Mon, 28 Oct 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-10-28-why-does-the-neutron/</guid><description>&lt;p&gt;The &lt;a href="http://docs.openstack.org/havana/install-guide/install/yum/content/neutron-install.dedicated-network-node.html"&gt;documentation for configuring Neutron&lt;/a&gt; recommends
that a network controller has three physical interfaces:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Before you start, set up a machine to be a dedicated network node.
Dedicated network nodes should have the following NICs: the
management NIC (called MGMT_INTERFACE), the data NIC (called
DATA_INTERFACE), and the external NIC (called EXTERNAL_INTERFACE).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;People occasionally ask, &amp;ldquo;why three interfaces? What if I only have
two?&amp;rdquo;, so I wanted to provide an extended answer that might help
people understand what the interfaces are for and what trade-offs are
involved in using fewer interfaces.&lt;/p&gt;</description></item><item><title>Automatic hostname entries for libvirt domains</title><link>https://blog.oddbit.com/post/2013-10-04-automatic-dns-entrie/</link><pubDate>Fri, 04 Oct 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-10-04-automatic-dns-entrie/</guid><description>&lt;p&gt;Have you ever wished that you could use &lt;code&gt;libvirt&lt;/code&gt; domain names as
hostnames? So that you could do something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ virt-install -n anewhost ...
$ ssh clouduser@anewhost
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since this is something that would certainly make my life convenient,
I put together a small script called &lt;a href="https://raw.github.com/larsks/virt-utils/master/virt-hosts"&gt;virt-hosts&lt;/a&gt; that makes this
possible. You can find &lt;a href="https://raw.github.com/larsks/virt-utils/master/virt-hosts"&gt;virt-hosts&lt;/a&gt; in my &lt;a href="https://raw.github.com/larsks/virt-utils/"&gt;virt-utils&lt;/a&gt; GitHub
repository:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://raw.github.com/larsks/virt-utils/master/virt-hosts"&gt;https://raw.github.com/larsks/virt-utils/master/virt-hosts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Run by itself, with no options, &lt;code&gt;virt-hosts&lt;/code&gt; will scan through your
running domains for interfaces on the libvirt &lt;code&gt;default&lt;/code&gt; network, look
up those MAC addresses up in the corresponding &lt;code&gt;default.leases&lt;/code&gt; file,
and then generate a hosts file on &lt;code&gt;stdout&lt;/code&gt; like this:&lt;/p&gt;</description></item><item><title>Interrupts on the PiFace</title><link>https://blog.oddbit.com/post/2013-08-05-interrupts-on-the-pi/</link><pubDate>Mon, 05 Aug 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-08-05-interrupts-on-the-pi/</guid><description>&lt;p&gt;I recently acquired both a &lt;a href="http://www.raspberrypi.org/"&gt;Raspberry Pi&lt;/a&gt; and a &lt;a href="http://www.element14.com/community/docs/DOC-52857/l/piface-digital-for-raspberry-pi"&gt;PiFace&lt;/a&gt; IO board.
I had a rough time finding examples of how to read the input ports via
interrupts (rather than periodically polling for values), especially
for the &lt;a href="https://github.com/piface"&gt;newer versions&lt;/a&gt; of the PiFace python libraries.&lt;/p&gt;
&lt;p&gt;After a little research, &lt;a href="https://gist.github.com/larsks/6161684"&gt;here&amp;rsquo;s&lt;/a&gt; some simple code that
will print out pin names as you press the input buttons. Button 3
will cause the code to exit:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/usr/bin/python

import pifacecommon.core
import pifacecommon.interrupts
import os
import time

quit = False

def print_flag(event):
 print 'You pressed button', event.pin_num, '.'

def stop_listening(event):
 global quit
 quit = True

pifacecommon.core.init()

# GPIOB is the input ports, including the four buttons.
port = pifacecommon.core.GPIOB

listener = pifacecommon.interrupts.PortEventListener(port)

# set up listeners for all buttons
listener.register(0, pifacecommon.interrupts.IODIR_ON, print_flag)
listener.register(1, pifacecommon.interrupts.IODIR_ON, print_flag)
listener.register(2, pifacecommon.interrupts.IODIR_ON, print_flag)
listener.register(3, pifacecommon.interrupts.IODIR_ON, stop_listening)

# Start listening for events. This spawns a new thread.
listener.activate()

# Hang around until someone presses button 3.
while not quit:
 time.sleep(1)

print 'you pressed button 3 (quitting)'
listener.deactivate()
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Generating a memberOf attribute for posixGroups</title><link>https://blog.oddbit.com/post/2013-07-22-generating-a-membero/</link><pubDate>Mon, 22 Jul 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-07-22-generating-a-membero/</guid><description>&lt;p&gt;This showed up on &lt;a href="https://wiki.openstack.org/wiki/IRC"&gt;#openstack&lt;/a&gt; earlier today:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2013-07-22T13:56:10 &amp;lt;m0zes&amp;gt; hello, all. I am looking to
setup keystone with an ldap backend. I need to filter
users based on group membership, in this case a
non-rfc2307 posixGroup. This means that memberOf doesn't
show up, and that the memberUid in the group is not a
dn. any thoughts on how to accomplish this?
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It turns out that this is a not uncommon question, so I spent some
time today working out a solution using the &lt;a href="http://www.openldap.org/faq/data/cache/1209.html"&gt;dynlist&lt;/a&gt; overlay for
&lt;a href="http://www.openldap.org/"&gt;OpenLDAP&lt;/a&gt;.&lt;/p&gt;</description></item><item><title>Split concatenated certificates with awk</title><link>https://blog.oddbit.com/post/2013-07-16-split-concatenated-c/</link><pubDate>Tue, 16 Jul 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-07-16-split-concatenated-c/</guid><description>&lt;p&gt;&lt;a href="https://gist.github.com/larsks/6008833"&gt;This&lt;/a&gt; is a short script that takes a list of concatenated
certificates as input (such as a collection of CA certificates) and
produces a collection of numbered files, each containing a single
certificate.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#!/bin/awk -f
 
# This script expects a list of concatenated certificates on input and
# produces a collection of individual numbered files each containing
# a single certificate.
 
BEGIN {incert=0}
 
/-----BEGIN( TRUSTED)? CERTIFICATE-----/ {
certno++
certfile=sprintf(&amp;quot;cert-%d.crt&amp;quot;, certno)
incert=1
}
 
/-----END( TRUSTED)? CERTIFICATE-----/ {
print &amp;gt;&amp;gt; certfile
incert=0
}
 
incert==1 { print &amp;gt;&amp;gt; certfile }
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Did Arch Linux eat your KVM?</title><link>https://blog.oddbit.com/post/2013-04-08-did-archlinux-eat-yo/</link><pubDate>Mon, 08 Apr 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-04-08-did-archlinux-eat-yo/</guid><description>&lt;p&gt;A recent update to &lt;a href="https://www.archlinux.org/"&gt;Arch Linux&lt;/a&gt; replaced the &lt;code&gt;qemu-kvm&lt;/code&gt; package with
an updated version of &lt;code&gt;qemu&lt;/code&gt;. A side effect of this change is that
the &lt;code&gt;qemu-kvm&lt;/code&gt; binary is no longer available, and any &lt;code&gt;libvirt&lt;/code&gt; guests
on your system utilizing that binary will no longer operate. As is
typical with Arch, there is no announcement about this incompatible
change, and queries to &lt;code&gt;#archlinux&lt;/code&gt; will be met with the knowledge,
grace and decorum you would expect of that channel:&lt;/p&gt;</description></item><item><title>I2C on the Raspberry Pi</title><link>https://blog.oddbit.com/post/2013-03-12-i2c-on-the-raspberry/</link><pubDate>Tue, 12 Mar 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-03-12-i2c-on-the-raspberry/</guid><description>&lt;p&gt;I&amp;rsquo;ve set up my &lt;a href="http://www.raspberrypi.org/"&gt;Raspberry Pi&lt;/a&gt; to communicate with my &lt;a href="http://www.arduino.cc/"&gt;Arduino&lt;/a&gt; via
&lt;a href="http://en.wikipedia.org/wiki/I%C2%B2C"&gt;I2C&lt;/a&gt;. The Raspberry Pi is a 3.3v device and the Arduino is a 5v
device. While in general this means that you need to use a level
converter when connecting the two devices, &lt;strong&gt;you don&amp;rsquo;t need to use a
level converter when connecting the Arduino to the Raspberry Pi via
I2C.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The design of the I2C bus is such that the only device driving a
voltage on the bus is the master (in this case, the Raspberry Pi), via
pull-up resistors. So when &amp;ldquo;idle&amp;rdquo;, the bus is pulled to 3.3v volts by
the Pi, which is perfectly safe for the Arduino (and compatible with
it&amp;rsquo;s 5v signaling). To transmit data on the bus, a device brings the
bus low by connecting it to ground. In other words, slave devices
&lt;em&gt;never&lt;/em&gt; drive the bus high. This means that the Raspberry Pi will
never see a 5v signal from the Arduino&amp;hellip;unless, of course, you make a
mistake and accidentally &lt;code&gt;digitalWrite&lt;/code&gt; a &lt;code&gt;HIGH&lt;/code&gt; value on one of the
Arduino&amp;rsquo;s &lt;code&gt;I2C&lt;/code&gt; pins. So don&amp;rsquo;t do that.&lt;/p&gt;</description></item><item><title>Interrupt driven GPIO with Python</title><link>https://blog.oddbit.com/post/2013-03-08-interrupt-driven-gpi/</link><pubDate>Fri, 08 Mar 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-03-08-interrupt-driven-gpi/</guid><description>&lt;p&gt;There are several Python libraries out there for interacting with the
&lt;a href="https://en.wikipedia.org/wiki/General_Purpose_Input/Output"&gt;GPIO&lt;/a&gt; pins on a Raspberry Pi:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://pypi.python.org/pypi/RPi.GPIO"&gt;RPi.GPIO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/WiringPi/WiringPi-Python"&gt;WiringPi&lt;/a&gt; bindings for Python, and&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://github.com/quick2wire/quick2wire-python-api"&gt;Quick2Wire&lt;/a&gt; Python API (which depends on Python 3)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of them are reasonably easy to use, but the Quick2Wire API
provides a uniquely useful feature: &lt;code&gt;epoll&lt;/code&gt;-enabled GPIO interrupts.
This makes it trivial to write code that efficiently waits for and
responds to things like button presses.&lt;/p&gt;
&lt;p&gt;The following simple example waits for a button press attached to
&lt;code&gt;GPIO1&lt;/code&gt; (but refer to the chart in &lt;a href="https://projects.drogon.net/raspberry-pi/wiringpi/pins/"&gt;this document&lt;/a&gt; to see
exactly what that means; this is pin 12 on a Raspberry Pi v2 board)
and lights an LED attached to &lt;code&gt;GPIO0&lt;/code&gt; when the button is pressed:&lt;/p&gt;</description></item><item><title>Controlling a servo with your Arduino</title><link>https://blog.oddbit.com/post/2013-03-07-controlling-a-servo/</link><pubDate>Thu, 07 Mar 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-03-07-controlling-a-servo/</guid><description>&lt;p&gt;I&amp;rsquo;ve recently started playing with an &lt;a href="http://arduino.cc/"&gt;Arduino&lt;/a&gt; kit I purchased a year
ago (and only just now got around to unboxing). I purchased the kit
from &lt;a href="https://www.sparkfun.com/"&gt;SparkFun&lt;/a&gt;, and it includes a motley collection of resistors,
LEDs, a motor, a servo, and more.&lt;/p&gt;
&lt;p&gt;I was fiddling around with &lt;a href="http://oomlout.com/a/products/ardx/circ-04/"&gt;this exercise&lt;/a&gt;, which uses the
&lt;code&gt;SoftwareServo&lt;/code&gt; library to control a servo. Using this library,
you just pass it an angle and the library takes care of everything
else, e.g. to rotate to 90 degrees you would do this:&lt;/p&gt;</description></item><item><title>A quote about XMLRPC</title><link>https://blog.oddbit.com/post/2013-02-25-puppet-xmlrpc-quote/</link><pubDate>Mon, 25 Feb 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-02-25-puppet-xmlrpc-quote/</guid><description>&lt;p&gt;I&amp;rsquo;ve been reading up on Puppet 3 lately, and came across the
following:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;XMLRPC was the new hotness when development on Puppet started. Now,
XMLRPC is that horrible thing with the XML and the angle brackets and
the pain and sad.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(from &lt;a href="http://somethingsinistral.net/blog/the-angry-guide-to-puppet-3/"&gt;http://somethingsinistral.net/blog/the-angry-guide-to-puppet-3/&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&amp;hellip;which also accurately sums up my feelings when I come across yet
another piece of software where someone has decided that XML (or even
JSON) is a good user-facing configuration syntax.&lt;/p&gt;</description></item><item><title>A systemd unit for ucarp</title><link>https://blog.oddbit.com/post/2013-02-21-ucarp-unit-for-systemd/</link><pubDate>Thu, 21 Feb 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-02-21-ucarp-unit-for-systemd/</guid><description>&lt;p&gt;In Fedora 17 there are still a number of services that either have not
been ported over to &lt;code&gt;systemd&lt;/code&gt; or that do not take full advantage of
&lt;code&gt;systemd&lt;/code&gt;. I&amp;rsquo;ve been investigating some IP failover solutions
recently, including &lt;a href="http://www.pureftpd.org/project/ucarp"&gt;ucarp&lt;/a&gt;, which includes only a System-V style
init script.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve created a &lt;a href="http://0pointer.de/blog/projects/instances.html"&gt;template service&lt;/a&gt; for ucarp that will let
you start a specific virtual ip like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;systemctl start ucarp@001
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will start ucarp using settings from &lt;code&gt;/etc/ucarp/vip-001.conf&lt;/code&gt;.
The unit file is &lt;a href="https://gist.github.com/larsks/5009872"&gt;on github&lt;/a&gt; and embedded here for your
reading pleasure:&lt;/p&gt;</description></item><item><title>Running dhcpcd under LXC</title><link>https://blog.oddbit.com/post/2013-02-01-dhcpcd-under-lxc/</link><pubDate>Fri, 01 Feb 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-02-01-dhcpcd-under-lxc/</guid><description>&lt;p&gt;I&amp;rsquo;ve been working with &lt;a href="http://www.archlinux.org/"&gt;Arch Linux&lt;/a&gt; recently, which uses &lt;a href="http://roy.marples.name/projects/dhcpcd/"&gt;dhcpcd&lt;/a&gt;
as its default DHCP agent. If you try booting Arch inside an &lt;a href="http://lxc.sourceforge.net/"&gt;LXC&lt;/a&gt;
container, you will find that &lt;code&gt;dhcpcd&lt;/code&gt; is unable to configure your
network interfaces. Running it by hand you will first see the
following error:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# dhcpcd eth0
dhcpcd[492]: version 5.6.4 starting
dhcpcd[492]: eth0: if_init: Read-only file system
dhcpcd[492]: eth0: interface not found or invalid
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This happens because &lt;code&gt;dhcpcd&lt;/code&gt; is trying to modify a sysctl value.
Running &lt;code&gt;dhcpcd&lt;/code&gt; under &lt;code&gt;strace&lt;/code&gt; we see:&lt;/p&gt;</description></item><item><title>Cleaning up LXC cgroups</title><link>https://blog.oddbit.com/post/2013-01-28-lxc-cant-remove-cgroup/</link><pubDate>Mon, 28 Jan 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-01-28-lxc-cant-remove-cgroup/</guid><description>&lt;p&gt;I spent some time today looking at systemd (44) under Fedora (17).
When stopping an LXC container using &lt;code&gt;lxc-stop&lt;/code&gt;, I would always
encounter this problem:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# lxc-stop -n node0
lxc-start: Device or resource busy - failed to remove cgroup '/sys/fs/cgroup/systemd/node0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This prevents one from starting a new container with the same name:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# lxc-start -n node0 
lxc-start: Device or resource busy - failed to remove previous cgroup '/sys/fs/cgroup/systemd/node0'
lxc-start: failed to spawn 'node0'
lxc-start: Device or resource busy - failed to remove cgroup '/sys/fs/cgroup/systemd/node0'
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can correct the problem manually by removing all the child cgroups
underneath &lt;code&gt;/sys/fs/cgroup/systemd/&amp;lt;container&amp;gt;&lt;/code&gt;, like this:&lt;/p&gt;</description></item><item><title>How do I LXC console?</title><link>https://blog.oddbit.com/post/2013-01-28-how-do-i-lxc-console/</link><pubDate>Mon, 28 Jan 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-01-28-how-do-i-lxc-console/</guid><description>&lt;p&gt;It took me an unreasonably long time to boot an LXC container with
working console access. For the record:&lt;/p&gt;
&lt;p&gt;When you boot an LXC container, the console appears to be attached to
a &lt;code&gt;pts&lt;/code&gt; device. For example, when booting with the console attached to
your current terminal:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# lxc-start -n node0
...
node0 login: root
Last login: Mon Jan 28 16:35:19 on tty1
[root@node0 ~]# tty
/dev/console
[root@node0 ~]# ls -l /dev/console
crw------- 1 root tty 136, 12 Jan 28 16:36 /dev/console
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is also true when you attach to a container using &lt;code&gt;lxc-console&lt;/code&gt;:&lt;/p&gt;</description></item><item><title>Systemd and the case of the missing network</title><link>https://blog.oddbit.com/post/2013-01-28-net-with-no-net/</link><pubDate>Mon, 28 Jan 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-01-28-net-with-no-net/</guid><description>&lt;p&gt;I was intrigued by &lt;a href="http://0pointer.de/blog/projects/socket-activated-containers.html"&gt;this post&lt;/a&gt; on socket activated containers with &lt;code&gt;systemd&lt;/code&gt;. The basic premise is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;systemd&lt;/code&gt; opens a socket on the host and listens for connections.&lt;/li&gt;
&lt;li&gt;When a client connections, &lt;code&gt;systemd&lt;/code&gt; spawns a new container.&lt;/li&gt;
&lt;li&gt;The host &lt;code&gt;systemd&lt;/code&gt; passes the connected socket to the container
&lt;code&gt;systemd&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Services in the container receive these sockets from the container
&lt;code&gt;systemd&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a very neat idea, since it delegates all the socket listening
to the host and only spins up container and service resources when
necessary.&lt;/p&gt;</description></item><item><title>A second look at Arch Linux</title><link>https://blog.oddbit.com/post/2013-01-25-archlinux-second-look/</link><pubDate>Fri, 25 Jan 2013 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2013-01-25-archlinux-second-look/</guid><description>&lt;p&gt;This is a followup to an &lt;a href="https://blog.oddbit.com/post/a-first-look-at-arch-linux"&gt;earlier post about Arch Linux&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ve since spent a little more time working with Arch, and these are
the things I like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The base system is very small and has a very short boot time. I
replaced Ubuntu on my old &lt;a href="https://en.wikipedia.org/wiki/Asus_Eee_PC#Eee_900_series"&gt;Eee PC&lt;/a&gt; with Arch and suddenly the boot
time is reasonable (&amp;lt; 10 seconds to a text prompt, &amp;lt; 30 seconds to a
full GUI login).&lt;/p&gt;</description></item><item><title>Parsing Libvirt XML with xmllint</title><link>https://blog.oddbit.com/post/2012-12-21-parsing-libvirt-xml/</link><pubDate>Fri, 21 Dec 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-12-21-parsing-libvirt-xml/</guid><description>&lt;p&gt;I&amp;rsquo;ve been playing around with the &lt;a href="http://lxc.sourceforge.net/"&gt;LXC&lt;/a&gt; support in libvirt recently,
and I&amp;rsquo;m trying to use a model where each LXC instance is backed by a
dedicated LVM volume. This means that the process of starting an
instance is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mount the instance root filesystem if necessary&lt;/li&gt;
&lt;li&gt;start the instance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It&amp;rsquo;s annoying to have to do this by hand. I could simply add all the
LXC filesystems to &lt;code&gt;/etc/fstab&lt;/code&gt;, but this would mean and extra step
when creating and deleting each instance.&lt;/p&gt;</description></item><item><title>Getting the IP address of a libvirt domain</title><link>https://blog.oddbit.com/post/2012-12-15-get-vm-ip/</link><pubDate>Sat, 15 Dec 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-12-15-get-vm-ip/</guid><description>&lt;p&gt;If you are starting virtual machines via &lt;code&gt;libvirt&lt;/code&gt;, and you have
attached them to the &lt;code&gt;default&lt;/code&gt; network, there is a very simple method
you can use to determine the address assigned to your running
instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Libvirt runs &lt;code&gt;dnsmasq&lt;/code&gt; for the &lt;code&gt;default&lt;/code&gt; network, and saves leases
in a local file (&lt;code&gt;/var/lib/libvirt/dnsmasq/default.leases&lt;/code&gt; under
RHEL).&lt;/li&gt;
&lt;li&gt;You can get the MAC address assigned to a virtual machine by
querying the domain XML description.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Putting this together gets us something along the lines of:&lt;/p&gt;</description></item><item><title>A first look at Arch Linux</title><link>https://blog.oddbit.com/post/2012-12-10-archlinux/</link><pubDate>Mon, 10 Dec 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-12-10-archlinux/</guid><description>&lt;p&gt;I decided to take a look at &lt;a href="https://www.archlinux.org/"&gt;Arch Linux&lt;/a&gt; this evening. It&amp;rsquo;s an
interesting idea, but has a long way to go:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The installer configured the wrong &lt;code&gt;root=&lt;/code&gt; command line into my
&lt;code&gt;syslinux&lt;/code&gt; configuration, resulting in a system that wouldn&amp;rsquo;t boot.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: As far as I can tell, the &lt;code&gt;syslinux-install_update&lt;/code&gt;
command doesn&amp;rsquo;t actually make any attempt to configure
&lt;code&gt;syslinux.cfg&lt;/code&gt; at all.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I tried to install &lt;code&gt;libvirt&lt;/code&gt; and &lt;code&gt;lxc&lt;/code&gt;, but there are unresolved
library dependencies&amp;hellip;the &lt;code&gt;virsh&lt;/code&gt; command apparently requires
&lt;code&gt;libX11.so.6&lt;/code&gt;, but the package is missing the appropriate
dependencies to pull in the necessary packages automatically.&lt;/p&gt;</description></item><item><title>Service discovery in the cloud using Avahi</title><link>https://blog.oddbit.com/post/2012-11-27-avahi-service-discovery/</link><pubDate>Tue, 27 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-27-avahi-service-discovery/</guid><description>&lt;p&gt;I&amp;rsquo;m been writing &lt;a href="http://github.com/larsks/drifter"&gt;a provisioning tool&lt;/a&gt; for OpenStack
recently, and I&amp;rsquo;ve put together a demo configuration that installs a
simple cluster consisting of three backend nodes and a front-end http
proxy. I needed a way for the backend servers to discover the ip
address of the frontend server. Since in my target environment
everything would be on the same layer-2 network segment, service
discovery with multicast DNS (mDNS) seemed like the way to go.&lt;/p&gt;</description></item><item><title>Using Oracle JDK under CentOS</title><link>https://blog.oddbit.com/post/2012-11-26-using-oracle-jdk/</link><pubDate>Mon, 26 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-26-using-oracle-jdk/</guid><description>&lt;p&gt;I needed to replace the native OpenJDK based Java VM with the Oracle
Java distribution on one of our CentOS servers. In order to do it
cleanly I wanted to set up the &lt;code&gt;alternatives&lt;/code&gt; system to handle it, but
it took a while to figure out the exact syntax.&lt;/p&gt;
&lt;p&gt;For the record (and because I will probably forget):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;alternatives --install /usr/bin/java java /usr/java/latest/bin/java 2000 \
 --slave /usr/bin/keytool keytool /usr/java/latest/bin/keytool \
 --slave /usr/bin/rmiregistry rmiregistry /usr/java/latest/bin/rmiregistry
&lt;/code&gt;&lt;/pre&gt;</description></item><item><title>Document classification with POPFile</title><link>https://blog.oddbit.com/post/2012-11-08-popfile-document-classificatio/</link><pubDate>Thu, 08 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-08-popfile-document-classificatio/</guid><description>&lt;p&gt;I recently embarked upon a quest to categorize a year&amp;rsquo;s worth of
trouble tickets (around 15000 documents total). We wanted to see what
sort of things are generating the most work for our helpdesk staff so
that we can identify areas in which improvements would have the
biggest impact. One of my colleagues took a first pass at the data by
manually categorizing the tickets based on their subject. This
resulted in some useful data, but in the end just over 40% of the
tickets are still uncategorized.&lt;/p&gt;</description></item><item><title>Converting HTML to Markdown</title><link>https://blog.oddbit.com/post/2012-11-06-convert-html-to-markdown/</link><pubDate>Tue, 06 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-06-convert-html-to-markdown/</guid><description>&lt;p&gt;In order to import posts from &lt;a href="http://blogger.com/"&gt;Blogger&lt;/a&gt; into &lt;a href="http://scriptogr.am/"&gt;Scriptogr.am&lt;/a&gt; I needed to convert all the HTML formatting into Markdown. Thankfully there are a number of tools out there that can help with this task.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="http://markdownrules.com/"&gt;MarkdownRules&lt;/a&gt;. This is an online service build around
&lt;a href="http://milianw.de/projects/markdownify/"&gt;Markdownify&lt;/a&gt;. It&amp;rsquo;s a slick site with a nice API, but the backend
wasn&amp;rsquo;t able to correctly render &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; blocks. Since I&amp;rsquo;m often
writing about code, my posts are filled with things like embedded
XML and &lt;code&gt;#include &amp;lt;stdio.h&amp;gt;&lt;/code&gt;, so this was a problem.&lt;/p&gt;</description></item><item><title>Relocating from Blogger</title><link>https://blog.oddbit.com/post/2012-11-06-moving-from-blogger/</link><pubDate>Tue, 06 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-06-moving-from-blogger/</guid><description>&lt;p&gt;I&amp;rsquo;m in the process of porting over content from Blogger. This may
lead to odd formatting or broken links here and there. If you spot
something, please &lt;a href="http://blog.oddbit.com/about"&gt;let me know&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you came here from Google and found a broken link, try starting at
the &lt;a href="http://blog.oddbit.com/archive"&gt;archive&lt;/a&gt; and see if you can spot what you were looking for.&lt;/p&gt;</description></item><item><title>Posting to Scriptogr.am using the API</title><link>https://blog.oddbit.com/post/2012-11-05-posting-via-api/</link><pubDate>Mon, 05 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-05-posting-via-api/</guid><description>&lt;p&gt;Scriptogr.am has a &lt;a href="http://scriptogr.am/dashboard/#api_documentation"&gt;very simple api&lt;/a&gt; that allows one to &lt;code&gt;POST&lt;/code&gt; and
&lt;code&gt;DELETE&lt;/code&gt; articles. &lt;code&gt;POST&lt;/code&gt;ing an article will place it in the
appropriate Dropbox directory and make it available on your blog all
in one step.&lt;/p&gt;
&lt;p&gt;Here is how you could use this API via Curl:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;curl \
 -d app_key=$APP_KEY \
 -d user_id=$USER_ID \
 -d name=&amp;quot;${title:-$1}&amp;quot; \
 --data-urlencode text@$tmpfile \
 \
 http://scriptogr.am/api/article/post/
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This assumes that you&amp;rsquo;ve registered for an application key and that
you have configured the value into &lt;code&gt;$APP_KEY&lt;/code&gt; and your Scriptogr.am
user id into &lt;code&gt;$USER_ID&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>Private /tmp directories in Fedora</title><link>https://blog.oddbit.com/post/2012-11-05-fedora-private-tmp/</link><pubDate>Mon, 05 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-05-fedora-private-tmp/</guid><description>&lt;p&gt;I ran into an odd problem the other day: I was testing out some
configuration changes for a web application by dropping files into
&lt;code&gt;/tmp&lt;/code&gt; and pointing the application configuration at the appropriate
directory. Everything worked out great when testing it by hand&amp;hellip;but
when starting up the &lt;code&gt;httpd&lt;/code&gt; service, the application behaved as if it
was unable to find any of the files in &lt;code&gt;/tmp&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;My first assumption was that had simply missed something obvious like
file permissions or that I had a typo in my configuration, but after
repeated checks and lots of testing it was obvious that something else
was going on.&lt;/p&gt;</description></item><item><title>Automatic configuration of Windows instances in OpenStack, part 1</title><link>https://blog.oddbit.com/post/2012-11-04-openstack-windows-config-part1/</link><pubDate>Sun, 04 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-04-openstack-windows-config-part1/</guid><description>&lt;p&gt;This is the first of two articles in which I discuss my work in
getting some Windows instances up and running in our &lt;a href="http://www.openstack.org/"&gt;OpenStack&lt;/a&gt;
environment. This article is primarily about problems I encountered
along the way.&lt;/p&gt;
&lt;h2 id="motivations"&gt;Motivations&lt;/h2&gt;
&lt;p&gt;Like many organizations, we have a mix of Linux and Windows in our
environment. Some folks in my group felt that it would be nice to let
our Windows admins take advantage of OpenStack for prototyping and
sandboxing in the same ways our Linux admins can use it.&lt;/p&gt;</description></item><item><title>Generating random passwords in PowerShell</title><link>https://blog.oddbit.com/post/2012-11-04-powershell-random-passwords/</link><pubDate>Sun, 04 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-04-powershell-random-passwords/</guid><description>&lt;p&gt;I was looking for PowerShell solutions for generating a random password (in
order to set the Administrator password on a Windows instance provisioned in
&lt;a href="http://www.openstack.org/"&gt;OpenStack&lt;/a&gt;), and found several solutions using the GeneratePassword method
of &lt;code&gt;System.Web.Security.Membership&lt;/code&gt; (documentation &lt;a href="http://msdn.microsoft.com/en-us/library/system.web.security.membership.generatepassword.aspx"&gt;here&lt;/a&gt;),
along the lines of &lt;a href="https://gist.github.com/4011878"&gt;this&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Function New-RandomComplexPassword ($length=8)
{
 $Assembly = Add-Type -AssemblyName System.Web
 $password = [System.Web.Security.Membership]::GeneratePassword($length,2)
 return $password
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;While this works, I was unhappy with the generated passwords: they
were difficult to type or transcribe because they make heavy use of
punctuation. For example:&lt;/p&gt;</description></item><item><title>Waiting for networking using PowerShell</title><link>https://blog.oddbit.com/post/2012-11-04-powershell-wait-for-networking/</link><pubDate>Sun, 04 Nov 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-11-04-powershell-wait-for-networking/</guid><description>&lt;p&gt;I&amp;rsquo;ve recently been exploring the world of Windows scripting, and I ran
into a small problem: I was running a script at system startup, and
the script was running before the network interface (which was using
DHCP) was configured.&lt;/p&gt;
&lt;p&gt;There are a number of common solutions proposed to this problem:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Just wait for some period of time.&lt;/p&gt;
&lt;p&gt;This can work but it&amp;rsquo;s ugly, and because it doesn&amp;rsquo;t actually
verify the network state it can result in things breaking if some
problem prevents Windows from pulling a valid DHCP lease.&lt;/p&gt;</description></item><item><title>Growing a filesystem on a virtual disk</title><link>https://blog.oddbit.com/post/2012-10-24-resizing-virtual-disk/</link><pubDate>Wed, 24 Oct 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-10-24-resizing-virtual-disk/</guid><description>&lt;p&gt;Occasionally we will deploy a virtual instance into our KVM
infrastructure and realize after the fact that we need more local disk
space available. This is the process we use to expand the disk image.
This process assumes the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You&amp;rsquo;re using legacy disk partitions. The process for LVM is similar
and I will describe that in another post (it&amp;rsquo;s generally identical
except for an additional &lt;code&gt;pvresize&lt;/code&gt; thrown in and &lt;code&gt;lvextend&lt;/code&gt; in
place of &lt;code&gt;resize2fs&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The partition you need to resize is the last partition on the disk.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This process will work with either a &lt;code&gt;qcow2&lt;/code&gt; or &lt;code&gt;raw&lt;/code&gt; disk image. For
&lt;code&gt;raw&lt;/code&gt; images you can also run &lt;code&gt;fdisk&lt;/code&gt; on the host, potentially saving
yourself a reboot, but that&amp;rsquo;s less convenient for &lt;code&gt;qcow2&lt;/code&gt; format
images.&lt;/p&gt;</description></item><item><title>Parsing XML with Awk</title><link>https://blog.oddbit.com/post/2012-09-10-awk-parsing-xml/</link><pubDate>Mon, 10 Sep 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-09-10-awk-parsing-xml/</guid><description>&lt;p&gt;Recently, changes from the &lt;a href="http://gawkextlib.sourceforge.net/"&gt;xmlgawk&lt;/a&gt; project have been integrated into
&lt;a href="https://www.gnu.org/software/gawk/"&gt;GNU awk&lt;/a&gt;, and xmlgawk has been renamed to &lt;a href="http://gawkextlib.sourceforge.net/"&gt;gawkextlib&lt;/a&gt;. With both a
recent (post-4.0.70) gawk and gawkextlib built and installed
correctly, you can write simple XML parsing scripts using gawk.&lt;/p&gt;
&lt;p&gt;For example, let&amp;rsquo;s say you would like to generate a list of disk image
files associated with a KVM virtual instance. You can use the &lt;code&gt;virsh dumpxml&lt;/code&gt; command to get output like the following:&lt;/p&gt;</description></item><item><title>Markdown in your Email</title><link>https://blog.oddbit.com/post/2012-08-09-markdown-email/</link><pubDate>Thu, 09 Aug 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-08-09-markdown-email/</guid><description>&lt;p&gt;I really like &lt;a href="http://daringfireball.net/projects/markdown/"&gt;Markdown&lt;/a&gt;, a minimal markup language designed to be readable as plain text that can be rendered into structurally valid HTML. Markdown is already used on sites such as &lt;a href="http://github.com/"&gt;GitHub&lt;/a&gt; and all the &lt;a href="http://stackexchange.com/sites"&gt;StackExchange&lt;/a&gt; sites.&lt;/p&gt;
&lt;p&gt;I use Markdown often enough that it&amp;rsquo;s become ingrained in my fingers, to the point that I&amp;rsquo;ve started unconsciously using Markdown syntax in my email. This isn&amp;rsquo;t particularly useful by itself, although it means that I can take a message and render it to something pretty if I decide it needs to go somewhere other than my sent mail folder.&lt;/p&gt;</description></item><item><title>Chasing OpenStack idle connection timeouts</title><link>https://blog.oddbit.com/post/2012-07-30-openstack-idle-connection-time/</link><pubDate>Mon, 30 Jul 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-07-30-openstack-idle-connection-time/</guid><description>&lt;h2 id="the-original-problem"&gt;The original problem&lt;/h2&gt;
&lt;p&gt;I&amp;rsquo;ve recently spent some time working on an OpenStack deployment. I ran into a
problem in which the &lt;a href="http://docs.openstack.org/trunk/openstack-compute/starter/content/Compute_Worker_nova-compute_-d1e232.html"&gt;compute service&lt;/a&gt; would frequently stop communicating
with the &lt;a href="http://www.amqp.org/"&gt;AMQP&lt;/a&gt; message broker (&lt;code&gt;qpidd&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In order to gather some data on the problem, I ran the following simple test:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Wait &lt;code&gt;n&lt;/code&gt; minutes&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;nova boot ...&lt;/code&gt; to create an instance&lt;/li&gt;
&lt;li&gt;Wait a minute and see if the new instance becomes &lt;code&gt;ACTIVE&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If it works, delete the instance, set &lt;code&gt;n&lt;/code&gt; = &lt;code&gt;2n&lt;/code&gt; and repeat&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This demonstrated that communication was failing after about an hour, which
correlates rather nicely with the idle connection timeout on the firewall.&lt;/p&gt;</description></item><item><title>Git fetch, tags, remotes, and more</title><link>https://blog.oddbit.com/post/2012-07-27-git-fetch-tags-et-al/</link><pubDate>Fri, 27 Jul 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-07-27-git-fetch-tags-et-al/</guid><description>&lt;p&gt;I’ve been playing around with Git, Puppet, and GPG verification of our
Puppet configuration repository, and these are some random facts about
Git that have come to light as part of the process.&lt;/p&gt;
&lt;p&gt;If you want to pull both changes &lt;em&gt;and&lt;/em&gt; new tags from a remote
repository, you can do this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git fetch
$ git fetch --tags
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or you can do this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ git fetch --tags
$ git fetch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;What’s the difference? &lt;code&gt;git fetch&lt;/code&gt; will leave &lt;code&gt;FETCH_HEAD&lt;/code&gt; pointing at
the remote &lt;code&gt;HEAD&lt;/code&gt;, whereas &lt;code&gt;git fetch --tags&lt;/code&gt; will leave &lt;code&gt;FETCH_HEAD&lt;/code&gt;
pointing at the most recent tag.&lt;/p&gt;</description></item><item><title>Capturing Envoy Data</title><link>https://blog.oddbit.com/post/2012-02-22-capturing-envoy-data/</link><pubDate>Wed, 22 Feb 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-02-22-capturing-envoy-data/</guid><description>&lt;p&gt;Pursuant to my &lt;a href="http://blog.oddbit.com/2012/02/13/enphase-envoy-xml-data-format/"&gt;last post&lt;/a&gt;, I&amp;rsquo;ve written a simple man-in-the-middle proxy to intercept communication between the Envoy and the Enphase servers. The code is available &lt;a href="https://github.com/larsks/envoy-tools"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="what-it-does"&gt;What it does&lt;/h2&gt;
&lt;p&gt;As I detailed in my previous post, the Envoy sends data to Enphase via http &lt;code&gt;POST&lt;/code&gt; requests. The proxy intercepts these requests, extracts the XML data from the request, and writes it to a local file (by default in &lt;code&gt;/var/spool/envoy&lt;/code&gt;). It then forwards the request on to Enphase, and returns the reply to your Envoy.&lt;/p&gt;</description></item><item><title>Enphase Envoy XML Data Format</title><link>https://blog.oddbit.com/post/2012-02-13-enphase-envoy-xml-data-format/</link><pubDate>Mon, 13 Feb 2012 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2012-02-13-enphase-envoy-xml-data-format/</guid><description>&lt;p&gt;We recently installed a (photovoltaic) solar array on our house. The system uses &lt;a href="http://enphase.com/"&gt;Enphase&lt;/a&gt; microinverters, and includes a monitoring device called the &amp;ldquo;&lt;a href="http://enphase.com/products/envoy/"&gt;Envoy&lt;/a&gt;&amp;rdquo;. The Envoy collects data from the microinverters and sends it back to Enphase. Enphase performs monitoring services for the array and also provides access to the data collected by the Envoy product.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m interested in getting direct access to the data provided by the Envoy. In pursuit of that goal, I set up a man-in-the-middle proxy server on my home network to intercept the communication from the Envoy to the Enphase servers. I&amp;rsquo;m documenting the results of my exploration here in case somebody else finds the information useful.&lt;/p&gt;</description></item><item><title>Rate limiting made simple</title><link>https://blog.oddbit.com/post/2011-12-26-simple-rate-limiting/</link><pubDate>Mon, 26 Dec 2011 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2011-12-26-simple-rate-limiting/</guid><description>&lt;p&gt;I use &lt;a href="http://www.crashplan.com/"&gt;CrashPlan&lt;/a&gt; as a backup service. It works and is very simple to set
up, but has limited options for controlling bandwidth. In fact, if you&amp;rsquo;re
running it on a headless system (e.g., a fileserver of some sort), your options
are effectively &amp;ldquo;too slow&amp;rdquo; and &amp;ldquo;CONSUME EVERYTHING&amp;rdquo;. There is an &lt;a href="https://crashplan.zendesk.com/entries/446273-throttle-bandwidth-by-hours?page=1#post_20799486"&gt;open
request&lt;/a&gt; to add time-based limitations to the application itself, but for
now I&amp;rsquo;ve solved this using a very simple traffic shaping configuration.
Because the learning curve for &amp;ldquo;tc&amp;rdquo; and friends is surprisingly high, I&amp;rsquo;m
putting &lt;a href="https://gist.github.com/larsks/4014881"&gt;my script&lt;/a&gt; here in the hopes
that other people might find it useful, and so that I can find it when I need
to do this again someday.&lt;/p&gt;</description></item><item><title>Puppet, scope, and inheritance</title><link>https://blog.oddbit.com/post/2011-08-16-puppet-scope-and-inheritance/</link><pubDate>Tue, 16 Aug 2011 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2011-08-16-puppet-scope-and-inheritance/</guid><description>&lt;p&gt;I note this here because it wasn&amp;rsquo;t apparent to me from the Puppet documentation.&lt;/p&gt;
&lt;p&gt;If you have a Puppet class like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class foo {
 File { ensure =&amp;gt; file,
 mode =&amp;gt; 600,
 }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And you use it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class bar {
 include foo

 file { '/tmp/myfile': }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then /tmp/myfile will not be created. But if instead you do this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class bar inherits foo {
 file { '/tmp/myfile': }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It will be created with mode 0600. In other words, if you use inherits then definitions in the parent class are available in the scope of your subclass. If you include, then definitions in he included class are &amp;ldquo;below&amp;rdquo; the scope of the including class.&lt;/p&gt;</description></item><item><title>Fixing RPM with evil magic</title><link>https://blog.oddbit.com/post/2011-07-26-fixing-rpm-with-evil-magic/</link><pubDate>Tue, 26 Jul 2011 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2011-07-26-fixing-rpm-with-evil-magic/</guid><description>&lt;h1 id="fixing-rpmsign-with-evil-magic"&gt;Fixing rpmsign with evil magic&lt;/h1&gt;
&lt;p&gt;At my office we are developing a deployment mechanism for RPM packages. The
general workflow looks like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You build a source rpm on your own machine.&lt;/li&gt;
&lt;li&gt;You sign the rpm with your GPG key.&lt;/li&gt;
&lt;li&gt;You submit the source RPM to our buildserver.&lt;/li&gt;
&lt;li&gt;The buildserver validates your signature and then builds the package.&lt;/li&gt;
&lt;li&gt;The buildserver signs the package using a master signing key.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last step in that sequence represents a problem, because the &lt;code&gt;rpmsign&lt;/code&gt;
command will always, always prompt for a password and read the response from
&lt;code&gt;/dev/tty&lt;/code&gt;. This means that (a) you can&amp;rsquo;t easily provide the password on stdin,
and (b) you can&amp;rsquo;t fix the problem using a passwordless key.&lt;/p&gt;</description></item><item><title>Installing CrashPlan under FreeBSD 8</title><link>https://blog.oddbit.com/post/2011-05-22-installing-crashplan-under-fre/</link><pubDate>Sun, 22 May 2011 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2011-05-22-installing-crashplan-under-fre/</guid><description>&lt;p&gt;This articles describes how I got &lt;a href="http://crashplan.com/"&gt;CrashPlan&lt;/a&gt; running on my FreeBSD 8(-STABLE) system. &lt;a href="http://kim.scarborough.chicago.il.us/do/nerd/tips/crashplan"&gt;These instructions&lt;/a&gt; by Kim Scarborough were my starting point, but as these were for FreeBSD 7 there were some additional steps necessary to get things working.&lt;/p&gt;
&lt;h1 id="install-java"&gt;Install Java&lt;/h1&gt;
&lt;p&gt;I had originally thought that it might be possible to run the CrashPlan client &amp;ldquo;natively&amp;rdquo; under FreeBSD. CrashPlan is a Java application, so this seemed like a possible solution. Unfortunately, Java under FreeBSD 8 seems to be a lost cause. I finally gave up and just installed Java under Linux.&lt;/p&gt;</description></item><item><title>Signing data with ssh-agent</title><link>https://blog.oddbit.com/post/2011-05-09-signing-data-with-ssh-agent/</link><pubDate>Mon, 09 May 2011 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2011-05-09-signing-data-with-ssh-agent/</guid><description>&lt;p&gt;This is follow-up to my previous post, &lt;a href="http://blog.oddbit.com/2011/05/08/converting-openssh-public-keys/"&gt;Converting OpenSSH public keys&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;OpenSSH allows one to use an &lt;em&gt;agent&lt;/em&gt; that acts as a proxy to your private key. When using an agent &amp;ndash; particularly with agent forwarding enabled &amp;ndash; this allows you to authenticate to a remote host without having to (a) repeatedly type in your password or (b) expose an unencrypted private key to remote systems.&lt;/p&gt;
&lt;p&gt;If one is temtped to use SSH keys as authentication credentials outside of ssh, one would ideally be able to take advantage of the ssh agent for these same reasons.&lt;/p&gt;</description></item><item><title>Converting OpenSSH public keys</title><link>https://blog.oddbit.com/post/2011-05-08-converting-openssh-public-keys/</link><pubDate>Sun, 08 May 2011 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2011-05-08-converting-openssh-public-keys/</guid><description>&lt;blockquote&gt;
&lt;p&gt;I&amp;rsquo;ve posted a &lt;a href="http://blog.oddbit.com/2011/05/09/signing-data-with-ssh-agent/"&gt;followup&lt;/a&gt; to this article that discusses ssh-agent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For reasons best left to another post, I wanted to convert an SSH public key into a PKCS#1 PEM-encoded public key. That is, I wanted to go from this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD7EZn/BzP26AWk/Ts2ymjpTXuXRiEWIWn
HFTilOTcuJ/P1HfOwiy4RHC1rv59Yh/E6jbTx623+OGySJWh1IS3dAEaHhcGKnJaikrBn3c
cdoNVkAAuL/YD7FMG1Z0SjtcZS6MoO8Lb9pkq6R+Ok6JQjwCEsB+OaVwP9RnVA+HSYeyCVE
0KakLCbBJcD1U2aHP4+IH4OaXhZacpb9Ueja6NNfGrv558xTgfZ+fLdJ7cpg6wU8UZnVM1B
JiUW5KFasc+2IuZR0+g/oJXaYwvW2T6XsMgipetCEtQoMAJ4zmugzHSQuFRYHw/7S6PUI2U
03glFmULvEV+qIxsVFT1ng3pj lars@tiamat.house
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA+xGZ/wcz9ugFpP07Nspo6U17l0YhFiFpxxU4pTk3Lifz9R3zsIsu
ERwta7+fWIfxOo208ett/jhskiVodSEt3QBGh4XBipyWopKwZ93HHaDVZAALi/2A
+xTBtWdEo7XGUujKDvC2/aZKukfjpOiUI8AhLAfjmlcD/UZ1QPh0mHsglRNCmpCw
mwSXA9VNmhz+PiB+Dml4WWnKW/VHo2ujTXxq7+efMU4H2fny3Se3KYOsFPFGZ1TN
QSYlFuShWrHPtiLmUdPoP6CV2mML1tk+l7DIIqXrQhLUKDACeM5roMx0kLhUWB8P
+0uj1CNlNN4JRZlC7xFfqiMbFRU9Z4N6YwIDAQAB
-----END RSA PUBLIC KEY-----
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have a recent version of OpenSSH (where recent means 5.6 or later), you can just do this:&lt;/p&gt;</description></item><item><title>Python ctypes module</title><link>https://blog.oddbit.com/post/2010-08-10-python-ctypes-module/</link><pubDate>Tue, 10 Aug 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-08-10-python-ctypes-module/</guid><description>&lt;p&gt;I just learned about the Python &lt;code&gt;ctypes&lt;/code&gt; module, which is a Python module for interfacing with C code. Among other things, &lt;code&gt;ctypes&lt;/code&gt; lets you call arbitrary functions in shared libraries. This is, from my perspective, some very cool magic. I thought I would provide a short example here, since it took me a little time to get everything working smoothly.&lt;/p&gt;
&lt;p&gt;For this example, we&amp;rsquo;ll write a wrapper for the standard &lt;code&gt;statvfs(2)&lt;/code&gt; function:&lt;/p&gt;</description></item><item><title>Importing vCard contacts into an LG 420G</title><link>https://blog.oddbit.com/post/2010-08-06-importing-vcard-contacts-into-/</link><pubDate>Fri, 06 Aug 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-08-06-importing-vcard-contacts-into-/</guid><description>&lt;p&gt;Alix recently acquired an LG 420G from &lt;a href="http://www.tracfone.com/"&gt;TracFone&lt;/a&gt;. She was interested in getting all of her contacts onto the phone, which at first seemed like a simple task &amp;ndash; transfer a vCard (.vcf) file to the phone via Bluetooth, and the phone would import all the contacts. This turned out to be a great idea in theory, but in practice there was a fatal flaw &amp;ndash; while the phone did indeed import the contacts, it only imported names and the occasional note or email address. There were no phone numbers.&lt;/p&gt;</description></item><item><title>Patch to gPXE dhcp command</title><link>https://blog.oddbit.com/post/2010-07-22-patch-to-gpxe-dhcp-command/</link><pubDate>Thu, 22 Jul 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-07-22-patch-to-gpxe-dhcp-command/</guid><description>&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: This patch has been &lt;a href="http://git.etherboot.org/?p=gpxe.git;a=commit;h=fa91c2c3269554df855107a24afec9a1149fee8f"&gt;accepted&lt;/a&gt; into gPXE.&lt;/p&gt;
&lt;p&gt;I just released a &lt;a href="http://gist.github.com/486907"&gt;patch&lt;/a&gt; to &lt;a href="http://etherboot.org/wiki/index.php"&gt;gPXE&lt;/a&gt; that modifies the dhcp command so that it can iterate over multiple interfaces. The stock dhcp command only accepts a single interface as an argument, which can be a problem if you are trying to boot on a machine with multiple interfaces. The builtin autoboot commands attempts to resolve this, but is only useful if you expect to receive appropriate boot parameters from your dhcp server.&lt;/p&gt;</description></item><item><title>Kerberos authenticated queries to Active Directory</title><link>https://blog.oddbit.com/post/2010-06-29-linux-kerberos-ad/</link><pubDate>Tue, 29 Jun 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-06-29-linux-kerberos-ad/</guid><description>&lt;p&gt;There are many guides out there to help you configure your Linux system as an LDAP and Kerberos client to an Active Directory server. Most of these guides solve the problem of authentication by embedding a username and password into a configuration file somewhere on your system. While this works, it presents some problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you use a common account for authentication from all of your Linux systems, a compromise on one system means updating the configuration of all of your systems.&lt;/li&gt;
&lt;li&gt;If you don&amp;rsquo;t want to use a common account, you need to provision a new account for each computer&amp;hellip;&lt;/li&gt;
&lt;li&gt;&amp;hellip;which is silly, because if you join the system to Active Directory there is already a computer object associated with the system that can be used for authentication.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This document describes how to configure a Linux system such that queries
generated by &lt;a href="http://www.padl.com/OSS/nss_ldap.html"&gt;nss_ldap&lt;/a&gt; will use either the current user&amp;rsquo;s Kerberos
credentials, or, for the root user, credentials stored in a Kerberos
credentials cache.&lt;/p&gt;</description></item><item><title>Pushing a Git repository to Subversion</title><link>https://blog.oddbit.com/post/2010-05-11-pushing-git-repository-to-subv/</link><pubDate>Tue, 11 May 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-05-11-pushing-git-repository-to-subv/</guid><description>&lt;p&gt;I recently set up a git repository server (using &lt;a href="http://scie.nti.st/2007/11/14/hosting-git-repositories-the-easy-and-secure-way"&gt;gitosis&lt;/a&gt; and &lt;a href="https://git.wiki.kernel.org/index.php/Gitweb"&gt;gitweb&lt;/a&gt;). Among the required features of the system was the ability to publish the git repository to a read-only Subversion repository. This sounds simple in principle but in practice proved to be a bit tricky.&lt;/p&gt;
&lt;p&gt;Git makes an excellent Subversion client. You can use the git svn &amp;hellip; series of commands to pull a remote Subversion repository into a local git working tree and then have all the local advantages of git forcing the central code repository to change version control software. An important aspect of this model is that:&lt;/p&gt;</description></item><item><title>LDAP redundancy through proxy servers</title><link>https://blog.oddbit.com/post/2010-02-24-ldap-redundancy-through-proxy-/</link><pubDate>Wed, 24 Feb 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-02-24-ldap-redundancy-through-proxy-/</guid><description>&lt;h1 id="problem-1-failover"&gt;Problem 1: Failover&lt;/h1&gt;
&lt;h2 id="the-problem"&gt;The problem&lt;/h2&gt;
&lt;p&gt;Many applications only allow you to configure a single LDAP server. This can lead to unnecessary service outages if your directory service infrastructure is highly available (e.g., you are running Active Directory) and your application cannot take advantage of this fact.&lt;/p&gt;
&lt;h2 id="a-solution"&gt;A solution&lt;/h2&gt;
&lt;p&gt;We can provide a level of redundancy by passing the LDAP connections through a load balancing proxy. While this makes the proxy a single point of failure, it is (a) a very simple tool and thus less prone to complex failure modes, (b) running on the same host as the web application, and (c) is completely under our control.&lt;/p&gt;</description></item><item><title>Apache virtual host statistics</title><link>https://blog.oddbit.com/post/2010-02-19-apache-virtual-host-statistics/</link><pubDate>Fri, 19 Feb 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-02-19-apache-virtual-host-statistics/</guid><description>&lt;p&gt;As part of a project I&amp;rsquo;m working on I wanted to get a rough idea of the activity of the Apache virtual hosts on the system. I wasn&amp;rsquo;t able to find exactly what I wanted, so I refreshed my memory of curses to bring you &lt;em&gt;vhoststats&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This tools reads an Apache log file (with support for arbitrary formats) and generates a dynamic bar chart showing the activity (in number of requests and bytes transferred) of hosts on the system. The output might look something like this (but with colors):&lt;/p&gt;</description></item><item><title>Merging directories with OpenLDAP's Meta backend</title><link>https://blog.oddbit.com/post/2010-02-16-merging-directories-with-openl/</link><pubDate>Tue, 16 Feb 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-02-16-merging-directories-with-openl/</guid><description>&lt;p&gt;This document provides an example of using OpenLDAP&amp;rsquo;s meta backend to provide a unified view of two distinct LDAP directory trees. I was frustrated by the lack of simple examples available when I went looking for information on this topic, so this is my attempt to make life easier for the next person looking to do the same thing.&lt;/p&gt;
&lt;p&gt;The particular use case that motiviated my interest in this topic was the need to configure web applications to (a) authenticate against an existing Active Directory server while (b) also allowing new accounts to be provisioned quickly and without granting any access in the AD environment. A complicating factor is that the group managing the AD server(s) was not the group implementing the web applications.&lt;/p&gt;</description></item><item><title>Filtering Blogger feeds</title><link>https://blog.oddbit.com/post/2010-02-10-filtering-blogger-feeds/</link><pubDate>Wed, 10 Feb 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-02-10-filtering-blogger-feeds/</guid><description>&lt;p&gt;After encountering a number of problems trying to filter Blogger feeds by tag (using services like &lt;a href="http://feedrinse.com/"&gt;Feedrinse&lt;/a&gt; and Yahoo &lt;a href="http://pipes.yahoo.com/"&gt;Pipes&lt;/a&gt;), I&amp;rsquo;ve finally put together a solution that works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Shadow the feed with &lt;a href="http://feedburner.com/"&gt;Feedburner&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Enable the &lt;em&gt;Convert Format Burner&lt;/em&gt;, and convert your feed to RSS 2.0.&lt;/li&gt;
&lt;li&gt;Use Yahoo &lt;a href="http://pipes.yahoo.com/"&gt;Pipes&lt;/a&gt; to filter the feed (because Feedrinse seems to be broken).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This let me create a feed that excluded all my posts containing the &lt;em&gt;fbpost&lt;/em&gt; tag, thus allowing me to avoid yet another postgasm in Facebook when adding new import URL to notes.&lt;/p&gt;</description></item><item><title>Funny usage message</title><link>https://blog.oddbit.com/post/2010-02-08-funny-usage-message/</link><pubDate>Mon, 08 Feb 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-02-08-funny-usage-message/</guid><description>&lt;p&gt;I was poking around in a command shell on my Droid to see what was available. While it&amp;rsquo;s a pretty restricted environment, there&amp;rsquo;s a number of commands available in /system/bin, including dexopt.&lt;/p&gt;
&lt;p&gt;Apparently dexopt isn&amp;rsquo;t something I&amp;rsquo;m supposed to poke at:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ dexopt
Usage: don't use this
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hah.&lt;/p&gt;</description></item><item><title>MBTA realtime XML feed</title><link>https://blog.oddbit.com/post/2010-02-07-mbta-realtime-xml-feed/</link><pubDate>Sun, 07 Feb 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-02-07-mbta-realtime-xml-feed/</guid><description>&lt;p&gt;The &lt;a href="http://mbta.com/"&gt;MBTA&lt;/a&gt; has a trial web service interface that provides access to realtime location information for select MBTA buses, as well as access to route information, arrival prediction, and other features. More information can be found here:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href="http://www.eot.state.ma.us/developers/realtime/"&gt;http://www.eot.state.ma.us/developers/realtime/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The service is provided by &lt;a href="http://www.nextbus.com/"&gt;NextBus&lt;/a&gt;, which specializes in real-time location information for public transit organizations. The &lt;a href="http://www.eot.state.ma.us/developers/downloads/MBTA_XML_Feed_Trial_Docs_13Nov09.pdf"&gt;API&lt;/a&gt; (sorry, PDF) is very simple and does not require any sort of advance registration.&lt;/p&gt;
&lt;p&gt;At the moment, the service only provides coverage for a small number of routes (39, 111, 114, 116, 117). I hope they expand the coverage of this service in the near future!&lt;/p&gt;</description></item><item><title>Blocking VNC with iptables</title><link>https://blog.oddbit.com/post/2010-02-04-vnc-blockingrst/</link><pubDate>Thu, 04 Feb 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-02-04-vnc-blockingrst/</guid><description>&lt;p&gt;VNC clients use the &lt;a href="http://www.realvnc.com/docs/rfbproto.pdf"&gt;RFB protocol&lt;/a&gt; to provide virtual display capabilities. The RFB protocol, as implemented by most clients, provides very poor authentication options. While passwords are not actually sent &amp;ldquo;in the clear&amp;rdquo;, it is possible to brute force them based on information available on the wire. The RFB 3.x protocol limits passwords to a maximum of eight characters, so the potential key space is relatively small.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s possible to securely connect to a remote VNC server by tunneling your connection using ssh port forwarding (or setting up some sort of SSL proxy). However, while this ameliorates the password problem, it still leaves a VNC server running that, depending on the local system configuration, may accept connections from all over the world. This leaves open the possibility that someone could brute force the password and gain access to the systsem. The problem is exacerbated if a user is running a passwordless VNC session.&lt;/p&gt;</description></item><item><title>NFS and the 16-group limit</title><link>https://blog.oddbit.com/post/2010-02-02-nfs-and-16-group-limit/</link><pubDate>Tue, 02 Feb 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-02-02-nfs-and-16-group-limit/</guid><description>&lt;p&gt;I learned something new today: it appears that the underlying authorization mechanism used by NFS limits your group membership to 16 groups. From &lt;a href="http://bit.ly/cBhU8N"&gt;http://bit.ly/cBhU8N&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;NFS is built on ONC RPC (Sun RPC). NFS depends on RPC for authentication and identification of users. Most NFS deployments use an RPC authentication flavor called AUTH_SYS (originally called AUTH_UNIX, but renamed to AUTH_SYS).&lt;/p&gt;
&lt;p&gt;AUTH_SYS sends 3 important things:&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;A 32 bit numeric user identifier (what you&amp;rsquo;d see in the UNIX /etc/passwd file)&lt;/li&gt;
&lt;li&gt;A 32 bit primary numeric group identifier (ditto)&lt;/li&gt;
&lt;li&gt;A variable length list of up to 16 32-bit numeric supplemental group identifiers (what&amp;rsquo;d you see in the /etc/group file)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;We ran into this today while diagnosing a weird permissions issue. Who knew?&lt;/p&gt;</description></item><item><title>Cleaning up Subversion with Git</title><link>https://blog.oddbit.com/post/2010-01-29-cleaning-up-subversion-with-gi/</link><pubDate>Fri, 29 Jan 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-01-29-cleaning-up-subversion-with-gi/</guid><description>&lt;h1 id="overview"&gt;Overview&lt;/h1&gt;
&lt;p&gt;At my office, we have a crufty &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; repository (dating back to early 2006) that contains a jumble of unrelated projects. We would like to split this single repository up into a number of smaller repositories, each following the recommended trunk/tags/branches repository organization.&lt;/p&gt;
&lt;p&gt;What we want to do is move a project from a path that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.../projects/some-project-name
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To a new repository using the recommended Subversion repository layout, like this:&lt;/p&gt;</description></item><item><title>Linux UPnP Gateway</title><link>https://blog.oddbit.com/post/2010-01-29-linux-upnp-gateway/</link><pubDate>Fri, 29 Jan 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-01-29-linux-upnp-gateway/</guid><description>&lt;p&gt;Like many other folks out there, I have several computers in my house connected to the outside world via a Linux box acting as a NAT gateway. I often want to use application such as BitTorrent and Freenet, which require that a number of ports be forwarded from my external connection to the particular computer on which I happen to be working. It turns out there&amp;rsquo;s a protocol for this, called &lt;a href="http://en.wikipedia.org/wiki/Universal_Plug_and_Play"&gt;UPnP&lt;/a&gt;. From Wikipedia:&lt;/p&gt;</description></item><item><title>Retrieving Blogger posts by post id</title><link>https://blog.oddbit.com/post/2010-01-29-retrieving-blogger-posts-by-po/</link><pubDate>Fri, 29 Jan 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-01-29-retrieving-blogger-posts-by-po/</guid><description>&lt;p&gt;I spent some time recently trying to figure out, using Google&amp;rsquo;s &lt;a href="http://code.google.com/apis/gdata/docs/2.0/basics.html"&gt;gdata&lt;/a&gt; API, how to retrieve a post from a &lt;a href="http://www.blogger.com/"&gt;Blogger&lt;/a&gt; blog if I know corresponding post id. As far as I can tell there is no obvious way of doing this, at least not using the gdata.blogger.client api, but after much nashing of teeth I came up with the following solution.&lt;/p&gt;
&lt;p&gt;Given client, a &lt;a href="http://gdata-python-client.googlecode.com/svn/trunk/pydocs/gdata.blogger.client.html"&gt;gdata.blogger.client&lt;/a&gt; instance, and blog, a &lt;a href="http://gdata-python-client.googlecode.com/svn/trunk/pydocs/gdata.blogger.data.html"&gt;gdata.blogger.data.Blog&lt;/a&gt; instance, the following code will return a &lt;a href="http://gdata-python-client.googlecode.com/svn/trunk/pydocs/gdata.blogger.data.html"&gt;gdata.blogger.data.BlogPost&lt;/a&gt; instance:&lt;/p&gt;</description></item><item><title>Fring: How not to handle registration</title><link>https://blog.oddbit.com/post/2010-01-24-fring-how-not-to-handle-regist/</link><pubDate>Sun, 24 Jan 2010 00:00:00 +0000</pubDate><guid>https://blog.oddbit.com/post/2010-01-24-fring-how-not-to-handle-regist/</guid><description>&lt;p&gt;I thought I&amp;rsquo;d give Fring a try after seeing some favorable reviews on other sites. If you haven&amp;rsquo;t previously heard of Fring, the following blurb from their website might be helpful:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Using your handset&amp;rsquo;s internet connection, you can interact with friends on all your favourite social networks including Skype, MSN Messenger, Google Talk, ICQ, SIP, Twitter, Yahoo! and AIM. You can listen to music with your Last.fm friends, check out what each other are up to on Facebook, receive alerts of new Google Mail and tailor make your very own fring by adding more cool experiences from fringAdd-ons&lt;/p&gt;</description></item></channel></rss>