<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

<title>Eric Radman : A Journal</title>
<link href="http://eradman.com/atom.xml" rel="self"/>
<link href="http://eradman.com/" />
<updated>2026-09-05T00:00:00Z</updated>
<author>
  <name>Eric Radman</name>
  <email>ericshane@eradman.com</email>
</author>
<id>http://eradman.com/</id>



<entry>
  <title>iSCSI Volume Claims</title>
  <link href="http://eradman.com/posts/iscsi-pvc.html" />
  <id>http://eradman.com/posts/iscsi-pvc.html</id>
  <updated>2026-03-31T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
<a href='https://kubernetes.io/docs/concepts/storage/persistent-volumes/'>Persistent Volumes</a>
provide a means of connecting a service with storage.  Local SSDs
will, of course be uncontested in terms of latency, but iSCSI allows a
container to be scheduled on any compute node.
</p>
<table>
<tr>
<th></th>
<th style='width: 6em;'>Local Disk</th>
<th style='width: 6em;'>iSCSI</th>
<th style='width: 6em;'>NFSv3</th>
</tr>
<tr>
<td>Volume Claim Required</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
</tr>
<tr>
<td>Authenticated</td>
<td>&ndash;</td>
<td>yes</td>
<td>no</td>
</tr>
<tr>
<td>Schedule on any Node</td>
<td>no</td>
<td>yes</td>
<td>yes</td>
</tr>
<tr>
<td>Concurrent Access</td>
<td>yes</td>
<td>no</td>
<td>yes</td>
</tr>
<tr>
<td>Native Linux File System</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
</tr>
<tr>
<td>Uses Buffer Cache</td>
<td>yes</td>
<td>yes</td>
<td>no</td>
</tr>
</table>

  ]]>
  </summary>
</entry>


<entry>
  <title>EFI/PXE Debugging</title>
  <link href="http://eradman.com/posts/openbsd-efi-loader.html" />
  <id>http://eradman.com/posts/openbsd-efi-loader.html</id>
  <updated>2026-01-30T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
These are the steps to diagnosing a problem booting OpenBSD using EFI and PXE.
</p>
<pre>
probing: pc0 com0 mem[636K 1887M 16M 84K 88K 752K 16K 4M 584K 7M 6M 6148M]
disk: hd0* hd1* hd2* hd3* hd4
&gt;&gt; OpenBSD/amd64 BOOTX64 3.69
boot&gt;
cannot open tftp:/etc/random.seed: No such file or directory
booting tftp:/bsd: open tftp:/bsd: No such file or directory
 failed(2). will try /bsd
</pre>

  ]]>
  </summary>
</entry>


<entry>
  <title>QEMU on Mac and Linux</title>
  <link href="http://eradman.com/posts/qemu-mac-linux.html" />
  <id>http://eradman.com/posts/qemu-mac-linux.html</id>
  <updated>2025-12-29T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
QEMU is perhaps best known for the ability to emulate various architectures,
but it also has wide support for the native Linux and Mac hypervisors.
In this way it is similar to using
<a hef='bhyve-ipxe.html'>Bhyve</a>.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>FFS Backup</title>
  <link href="http://eradman.com/posts/ffs-backup.html" />
  <id>http://eradman.com/posts/ffs-backup.html</id>
  <updated>2025-12-12T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
For large data sets, home directories, or backups,
<a href='zfs-quickstart.html'>ZFS</a>
has a wide range of supurb features.  But if an advanced file system is not
available, as FFS on OpenBSD or EXT2/3/4 on Linux can also be used.  For
backups the goal will be to maintain three copies that guard against hardware
failure
<em>and</em>
human error.
</p>
<ol>
<li>Home directory</li>
<li>Primary backup</li>
<li>Secondary backup</li>
</ol>

  ]]>
  </summary>
</entry>


<entry>
  <title>WireGuard and NFS</title>
  <link href="http://eradman.com/posts/wireguard-nfs.html" />
  <id>http://eradman.com/posts/wireguard-nfs.html</id>
  <updated>2025-10-24T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
Among the brilliant features of WireGuard is the ability to classify traffic
based on peer
<em>public keys</em>.
This means that packets can be filtered by interface or require that each peer
use a specific tunnel address.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Running a Local Registry</title>
  <link href="http://eradman.com/posts/local-registry.html" />
  <id>http://eradman.com/posts/local-registry.html</id>
  <updated>2025-03-06T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
If a local network is secure, we can easily configure a local registry without
having to manage TLS certificates
</p>
<pre>
$ kubectl get svc -o wide registry
NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE     SELECTOR
registry   ClusterIP   None         &lt;none&gt;        5000/TCP   5d20h   app=registry
</pre>

  ]]>
  </summary>
</entry>


<entry>
  <title>OSPF and DNS NodePort</title>
  <link href="http://eradman.com/posts/ospf-dns-nodeport.html" />
  <id>http://eradman.com/posts/ospf-dns-nodeport.html</id>
  <updated>2025-02-28T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
After bootstrapping up a basic
<a href='https://scriptedconfiguration.org/formulas/kubernetes-lab.html'>Kubernetes Lab</a>,
a dynamic routing protocol provides effective routing at all layers because
each router and switch understands how to route traffic effectively
</p>
<pre>
# ospfctl show rib
Destination          Nexthop           Path Type    Type      Cost    Uptime
192.168.0.4          192.168.2.4       Intra-Area   Router    20      04:47:00
192.168.2.0/24       192.168.2.3     C Intra-Area   Network   20      05:06:25
10.244.1.0/24        192.168.2.65      Type 2 ext   Network   20      04:16:00
10.244.2.0/24        192.168.2.66      Type 2 ext   Network   20      04:16:00
10.244.3.0/24        192.168.2.67      Type 2 ext   Network   20      04:16:00
</pre>
<p>
To make name resolution work, we will configure a stub zone and port
forwarding for DNS
</p>
<pre>
$ traceroute -n registry.default.svc.mykube.lan
traceroute to registry.default.svc.mykube.lan (10.244.3.62), 64 hops max, 40 byte packets
1  192.168.0.7  11.875 ms  10.928 ms  11.47 ms
2  192.168.2.67  0.749 ms  0.483 ms  0.349 ms
3  10.244.3.62  0.459 ms  0.328 ms  0.383 ms
</pre>

  ]]>
  </summary>
</entry>


<entry>
  <title>Crosstab Views</title>
  <link href="http://eradman.com/posts/crosstab-views.html" />
  <id>http://eradman.com/posts/crosstab-views.html</id>
  <updated>2025-01-18T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
Also known as
<q>pivot tables</q>,
distributing categories across colums is a very intuative way
to display query results. Some built-in methods exist in PostgreSQL
</p>
<ul>
<li>
The
<a href='https://www.postgresql.org/docs/current/app-psql.html'>psql</a>
<code>\crosstab</code>
command provides a quick way to reformat the output of an interactive query,
but is of no use for applications.
</li>
<li>
The
<a href='https://www.postgresql.org/docs/current/tablefunc.html'>crosstab functions</a>
from the
<code>contrib</code>
module are awkward to use since they take a
<em>query</em>
as input, and has limited means of customization.
</li>
</ul>
<p>
But we can assemble these using aggregate functions or CTEs.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>A Strategy for IPv6</title>
  <link href="http://eradman.com/posts/ipv6-strategy.html" />
  <id>http://eradman.com/posts/ipv6-strategy.html</id>
  <updated>2024-11-22T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
I first configured IPv6 Internet access at my home in 2003. More than 20 years
later IPv6 is widely available, but remains a challenge to implement on a
local area network.
</p>
<p>
Perhaps the most interesting question is not how to implement IPv6 networking,
but determining
<em>why anyone would need it.</em>
The 128-bit address space is divided into a strict hierarchy, and it may be
that this allows the protocol to operate with less cooperation between
geographic regions. If this is true, then maybe IPv6 is an alternative plan to
keep the Internet up if individual countries sabotage IPv4 routing.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>AWK Programming</title>
  <link href="http://eradman.com/posts/awk-programming.html" />
  <id>http://eradman.com/posts/awk-programming.html</id>
  <updated>2024-02-22T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
<a href='https://man.openbsd.org/awk.1'>awk</a>
is a processing language with a man page that can be printed on eight sheets
of paper. Most importantly, it is a standard part of any Unix-like
environment, so it can be used in contexts where the features of a target
installation are unknown.
</p>
<p>
Program structure has three sections, all of which are optional
</p>
<pre>
<span class="Special">BEGIN</span> { ... }
<span class="Constant">/patternN/</span> { ... }
<span class="Special">END</span> { ... }
</pre>

  ]]>
  </summary>
</entry>


<entry>
  <title>Late Binding Views</title>
  <link href="http://eradman.com/posts/late-binding-views.html" />
  <id>http://eradman.com/posts/late-binding-views.html</id>
  <updated>2023-08-24T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
In my view, the most significant feature missing from PostgreSQL is the
ability to create views without hard dependencies.
Views reference objects by
<code>oid</code>
not by
<code>name</code>,
hence creating a view always has the potential to break automated schema
updates.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>ZFS Quickstart</title>
  <link href="http://eradman.com/posts/zfs-quickstart.html" />
  <id>http://eradman.com/posts/zfs-quickstart.html</id>
  <updated>2023-08-10T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
ZFS has a truly unique combination of features
</p>
<ol>
<li>
ZFS is able to distribute data across multiple devices, and this format is
portable.  Unlike traditional RAID, only dataset records are copied, making
recovery very efficient.  ZFS does away with the need for a volume manager,
so there are no platform-specific layers such as BSD disklabels, or LVM.
(<a href='https://docs.kernel.org/filesystems/btrfs.html'>BTRFS</a>
also has these capabilities, but is Linux-only.)
</li>
<li>
Native encryption, which allows send/receive of datasets even without
unlocking and mounting a volume.
</li>
<li>
By setting
<a href='https://openzfs.github.io/openzfs-docs/man/v2.4/7/zfsprops.7.html#volmode'>volmode</a>
raw block devices can be provisioned for
<a href='bhyve-ipxe.html'>virtual machines</a>,
or across the network by way of
<a href='iscsi-pvc.html'>iSCSI</a>.
</li>
</ol>

  ]]>
  </summary>
</entry>


<entry>
  <title>JSON Processing in SQL</title>
  <link href="http://eradman.com/posts/json-in-sql.html" />
  <id>http://eradman.com/posts/json-in-sql.html</id>
  <updated>2023-07-11T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
For many reasons it is useful to store arbitrary nested key-value and array
data in JSON.  Among the deficiencies of JSON is limited data types, but
the great benefit is that it is universal can be queried.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Rendering Pages with Puppeteer</title>
  <link href="http://eradman.com/posts/puppeteer-snapshot.html" />
  <id>http://eradman.com/posts/puppeteer-snapshot.html</id>
  <updated>2023-06-28T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
<a href='https://pptr.dev/'>Puppeteer</a>
is a Node.js library which provides an API to control Chromium using the
<em>DevTools Protocol.</em>
</p>
<p>
JavaScript may be executed in the context of the headless browser, so any kind
of change may be made to the page before taking a snapshot (PNG) or saving as
a PDF.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Partition Pruning</title>
  <link href="http://eradman.com/posts/partition-pruning.html" />
  <id>http://eradman.com/posts/partition-pruning.html</id>
  <updated>2023-06-15T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
Declarative partitioning in enables the PostgreSQL query planner to optimize
queries in several ways, most notably by
<q>pruning</q>
partitions that are irrelevant for the query.  This results in tremendous
performance gains, but only works for values known during the
<em>planning stage</em>.
</p>
<p>
If the partition key is also a natural key, such as a date, pruning may appear
to work in all cases, but if an intermediate lookup is required
(<em>name &rarr; id</em>),
queries will resort to scan all partitions.
</p>
<!--
See also
src/backend/partitioning/partprune.c:match_clause_to_partition_key()
-->

  ]]>
  </summary>
</entry>


<entry>
  <title>Automated FreeBSD Installation</title>
  <link href="http://eradman.com/posts/automated-freebsd-install.html" />
  <id>http://eradman.com/posts/automated-freebsd-install.html</id>
  <updated>2023-05-19T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
For FreeBSD, the ability to PXE boot BIOS and UEFI systems is not new, but
documentation frequently assumes an NFS mounted root file system.  In my view
NFS is unworkable since file access is not logged, and a hung mount is
difficult to diagnose.
</p>
<p>
By using TFTP to pivot to a minroot, then switching to HTTP the entire process
can be audited and tailored for individual hosts.  This methodology aims to
borrow techniques used by an automated install for
<a href='autoinstall-openbsd.html'>OpenBSD</a>
and
<a href='automated-rhel-fedora-install.html'>Red Hat Linux</a>.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Sphynx Development Notes</title>
  <link href="http://eradman.com/posts/sphynx-dev-notes.html" />
  <id>http://eradman.com/posts/sphynx-dev-notes.html</id>
  <updated>2023-03-23T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
One of the most useful skills a Systems Engineer employees is a method of
keeping personal notes.  This serves as a form of documentation that is
constantly revised that captures current knowledge of a system and the tricks
to accomplishing specialized tasks effectively.
</p>
<p>
Note taking also services to keep long-term goals moving.  On a daily basis
write-ahead logging can provide short-term focus.  By keeping a personal
record of experiments is a reserve to draw on when the rest of the team will
be most receptive to a change.
</p>
<p>
The organization for note-taking can a directory with plain text files, but a
framework such as
<a href='https://www.sphinx-doc.org/en/master/'>Sphynx</a>
provides a way to create personal notes that can be easily shared with a team.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Bhyve and iPXE</title>
  <link href="http://eradman.com/posts/bhyve-ipxe.html" />
  <id>http://eradman.com/posts/bhyve-ipxe.html</id>
  <updated>2022-10-13T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
In software or systems engineering, the ability to spin up virtual machines is
a valuable capability.  Virtual machines provide a means of testing software
or configuration in on multiple platforms, and in multiple configurations.
</p>
<p>
In production, a high-performance and reliable hypervisor allows services to
be provisioned and updated one at a time.  This capability avoids the added
risk and complexity of
<q>fork-lift</q>
upgrades.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>PostgreSQL Administrative Queries</title>
  <link href="http://eradman.com/posts/pg-admin-queries.html" />
  <id>http://eradman.com/posts/pg-admin-queries.html</id>
  <updated>2022-10-05T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
These are operations that I commonly use to aid supporting PostgreSQL
databases.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Automated Ubuntu Installation</title>
  <link href="http://eradman.com/posts/automated-ubuntu-install.html" />
  <id>http://eradman.com/posts/automated-ubuntu-install.html</id>
  <updated>2022-09-02T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
Ubuntu supports major version upgrades using the
<code>do-release-upgrade</code>
utility, but in my experience this is not a reliable means of updating the
operating system.  Automating installation facilitates testing and iterative
design of systems configuration.
</p>
<p>
Although Ubuntu is a derivative of Debian, it doesn't follow the same
conventions for an automated install.
</p>
<p>
x86_64 hardware and hypervisors usually don't provide a means of picking a
one-time boot device.  To force a reinstall wipe the first part of the disk.
</p>
<pre>
<span class="Comment"># reinstall</span>
<span class="Comment"># use with caution!</span>
dd <span class="Identifier">if</span>=/dev/zero <span class="Identifier">of</span>=/dev/sda <span class="Identifier">bs</span>=1M <span class="Identifier">count</span>=<span class="Constant">100</span>
reboot
</pre>

  ]]>
  </summary>
</entry>


<entry>
  <title>Automated RHEL/Fedora Installation</title>
  <link href="http://eradman.com/posts/automated-rhel-fedora-install.html" />
  <id>http://eradman.com/posts/automated-rhel-fedora-install.html</id>
  <updated>2022-08-23T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
Any time a task needs to be repeated it is a good candidate for automation.
Any time a task needs to be reproducible automation is required.  For running
frequent experiments on my home lab, and the ability to quickly rebuild a
machine is of immense benefit.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>The Sidecomment Web Stack</title>
  <link href="http://eradman.com/posts/sidecomment-web-stack.html" />
  <id>http://eradman.com/posts/sidecomment-web-stack.html</id>
  <updated>2022-06-21T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
<a href='http://sidecomment.io'>sidecomment.io</a>
is a service that allows readers to select text and create a ticket with
suggestions or corrections that the
<em>site owner</em>
can respond to.  Like a commenting platform such as
<a href='https://talk.hyvor.com/'>Hyvor Talk</a>,
JavaScript is included from an external CDN, and is authorized by a
<em>site code</em>.
</p>
<p>
This concept developed after I noticed how many people were willing to take
the time to write an email to point out typos, broken links or errors on this
online journal and other project pages.
</p>
<!--
Anonymity is a key concept.  Contributors need a valid email address to
validate their user code, but a only information they add to their profile is
visible.
-->

  ]]>
  </summary>
</entry>


<entry>
  <title>Open Workstation Notes</title>
  <link href="http://eradman.com/posts/openbsd-workstation.html" />
  <id>http://eradman.com/posts/openbsd-workstation.html</id>
  <updated>2022-06-13T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
I first posted my notes on using OpenBSD as my workstation in of 2013, but I
probably switched from Arch Linux in 2005.  This is a collection of
customizations I have used for over the years, as well as some hints for using
some more modern features.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Practical JWT</title>
  <link href="http://eradman.com/posts/practical-jwt.html" />
  <id>http://eradman.com/posts/practical-jwt.html</id>
  <updated>2022-01-04T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
<em>JSON Web Tokens</em>
(JWT) provide a standardized representation of
<q>claims to be transferred between two parties</q>.
This payload may contain any JSON data, but for
web services this is most commonly applied to stashing some bit of data that
identifies a user that has passed a prior authorization step.
</p>
<p>
Keeping the length of the encoded string short is important to minimizing
overhead, especially for cookies which are added to the header in every HTTP
request.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Cross-Origin Requests</title>
  <link href="http://eradman.com/posts/cross-origin-requests.html" />
  <id>http://eradman.com/posts/cross-origin-requests.html</id>
  <updated>2021-12-28T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
Modern web browsers all allow REST interfaces to external services
depends on using a request-response standard called
<em>Cross-Origin Resource Sharing.</em>
</p>
<p>
This mode is available by setting the
<a href='https://developer.mozilla.org/en-US/docs/Web/API/Request/mode'>mode</a>
attribute of a JavaScript
<code>Request</code>
object. The following is
an example using the
<a href='https://javascript.info/fetch-api'>Fetch API</a>
</p>
<pre>
<span class="Statement">async</span> <span class="Identifier">function</span> sct_postData(url, data=<span class="Identifier">{}</span>) <span class="Identifier">{</span>
  <span class="Statement">const</span> response = <span class="Statement">await</span> fetch(url, <span class="Identifier">{</span>
    method: <span class="Constant">'POST'</span>,
    headers: <span class="Identifier">{</span>
      <span class="Constant">'Content-Type'</span>: <span class="Constant">'application/json'</span>
    <span class="Identifier">}</span>,
    mode: <span class="Constant">'cors'</span>,
    body: JSON.stringify(data)
  <span class="Identifier">}</span>);
  <span class="Statement">return</span> response.json();
<span class="Identifier">}</span>
</pre>
<p>
Specifying
<code>'no-cors'</code>
does not mean relax the protocol, it means
<em>don't follow the protocol which might allow external resource.</em>
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>OpenBSD VPS Installation</title>
  <link href="http://eradman.com/posts/openbsd-vps-installation.html" />
  <id>http://eradman.com/posts/openbsd-vps-installation.html</id>
  <updated>2021-10-29T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
Some virtual private server providers support OpenBSD as an install target.
This is a wonderful start, but only a start because the image applied and
resided will probably not a useful partition scheme and mount options that
makes sense for a given security and operational strategy.
</p>
<p>
Fortunately, a hosting provider such as
<a href='https://www.vultr.com/?ref=8964824-8H'>
Vultr
</a>
can deliver an OpenBSD instance that can reinstall itself using and
autoinstall answers file and disklabel fetched over HTTP.
</p>
<pre>
<span class="Comment"># /etc/fstab</span>
/dev/sd0a / <span class="Type">ffs</span> <span class="Type">rw</span> <span class="Constant">1</span> <span class="Constant">1</span>
/dev/sd0b <span class="Statement">none</span> <span class="Type">swap</span> <span class="Type">sw</span>
/dev/sd0d /usr <span class="Type">ffs</span> <span class="Type">rw</span><span class="Statement">,</span><span class="Type">nodev</span> <span class="Constant">1</span> <span class="Constant">2</span>
/dev/sd0e /usr/local <span class="Type">ffs</span> <span class="Type">rw</span><span class="Statement">,</span><span class="Statement">wxallowed</span><span class="Statement">,</span><span class="Type">nodev</span> <span class="Constant">1</span> <span class="Constant">2</span>
/dev/sd0f /tmp <span class="Type">ffs</span> <span class="Type">rw</span><span class="Statement">,</span><span class="Type">nodev</span><span class="Statement">,</span><span class="Type">nosuid</span> <span class="Constant">1</span> <span class="Constant">2</span>
/dev/sd0g /home <span class="Type">ffs</span> <span class="Type">rw</span><span class="Statement">,</span><span class="Type">nodev</span><span class="Statement">,</span><span class="Type">nosuid</span> <span class="Constant">1</span> <span class="Constant">2</span>
/dev/sd0h /var <span class="Type">ffs</span> <span class="Type">rw</span><span class="Statement">,</span><span class="Type">nodev</span><span class="Statement">,</span><span class="Type">nosuid</span> <span class="Constant">1</span> <span class="Constant">2</span>
</pre>
<p>
Using a pre-built cloud image as a trampoline also provides the opportunity to
exclude some base filesets or include other capabilities using
<code>siteXX.tgz</code>.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Modeling Unix Group Membership</title>
  <link href="http://eradman.com/posts/unix-group-membership.html" />
  <id>http://eradman.com/posts/unix-group-membership.html</id>
  <updated>2021-09-28T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
There are two reasons I have found it advantageous to synchronize local user
accounts to an SQL lookup table:
</p>
<ol>
<li>
Databases frequently keep records based on the user who ran a task; a users
table allows you to write queries that include or exclude certain groups
</li>
<li>
Applications need to filter records using access controls that are
consistent with file system permissions
</li>
</ol>
<p>
Arrays provide a very natural means of associating group membership in a
database.  Since arrays are ordered, we can assign special meaning to the
first member
</p>
<pre>
<span class="Statement">CREATE</span> <span class="Special">TABLE</span> users (
  username <span class="Type">varchar</span>(<span class="Constant">32</span>) PRIMARY KEY,
  unix_groups <span class="Type">varchar</span>(<span class="Constant">32</span>)[]  <span class="Comment">-- first element is the primary group</span>
);
</pre>

  ]]>
  </summary>
</entry>


<entry>
  <title>PostgreSQL Native Logical Replication</title>
  <link href="http://eradman.com/posts/postgresql-native-logical.html" />
  <id>http://eradman.com/posts/postgresql-native-logical.html</id>
  <updated>2020-04-03T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
SQL databases provide a critical service by giving the application globally
consistent access to data, but logical replication makes it possible to trade
in the guarantee that a query always reads the most recent write for other
features.
Instead of global behavior, logical replication allows a relational database
to target particular features for distributed processing.
</p>
<p>
I may be mistaken, but I believe the ability to replicate a subset of data
between databases that are otherwise unrelated has become a unique feature of
relational databases.
Unlike statement-based replication, logical replication is PostgreSQL is based
on the WAL, and enables strict guarantees.
It's also a modular architecture, but the built-in plugin
(<code>pgoutput</code>)
can usually be assumed.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Sorting out Autocommit</title>
  <link href="http://eradman.com/posts/autocommit.html" />
  <id>http://eradman.com/posts/autocommit.html</id>
  <updated>2019-05-08T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<!-- https://dev.mysql.com/doc/refman/5.6/en/innodb-autocommit-commit-rollback.html -->
<!-- https://docs.python.org/2/library/sqlite3.html#sqlite3-controlling-transactions -->
<p>
The PostgreSQL server does not have a feature called "autocomit", but the most
popular database library for Python, psycopg2
<a href='http://initd.org/psycopg/docs/connection.html#connection.autocommit'>has it enabled by default</a>.
I say "enabled", but to disable this behavior we have to turn something on
</p>
<pre>
conn.autocommit = <span class="Identifier">True</span>
</pre>
<p>
The psycopg2 documentation has a warning about the default behavior
</p>
<blockquote>
Warning:
By default, any query execution, including a simple SELECT will start a
transaction
</blockquote>

  ]]>
  </summary>
</entry>


<entry>
  <title>Programming Documents with Haml</title>
  <link href="http://eradman.com/posts/haml-programming.html" />
  <id>http://eradman.com/posts/haml-programming.html</id>
  <updated>2018-10-18T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
<a href='http://haml.info/'>Haml</a>
is an templating language for writing HTML. Over the past twenty years the
capabilities of HTML+CSS have become good enough for nearly any kind of
document to be rendred in a Web browser. I use Haml for all of my writing.
</p>
<p>
Haml combines a set of valuable features:
</p>
<ol>
<li>A notation that mirrors HTML</li>
<li>Inline scripting and control flow</li>
<li>Blocks of text can be interpreted using custom filters</li>
</ol>
<p class='warning'>
Haml 6+ introduced many breaking changes in the library and command line.
Critically, there is no means of passing arguments or locals to the
<code>haml render</code>
command.
To work around this use
<code>gem install -v 5.2.2</code>.
</p>

  ]]>
  </summary>
</entry>


<entry>
  <title>Automated OpenBSD Installation</title>
  <link href="http://eradman.com/posts/autoinstall-openbsd.html" />
  <id>http://eradman.com/posts/autoinstall-openbsd.html</id>
  <updated>2016-05-18T00:00:00Z</updated>
  <summary type="html">
  <![CDATA[
  
<p>
OpenBSD has a very good story for automated installations, which includes
features such as:
</p>
<ul>
<li>Boot parameters set on boot (example: switch to serial port)</li>
<li>Configuration of network interfaces</li>
<li>Partitioning &amp; adaptive disklabels</li>
<li>Selection and installation of base sets</li>
<li>Custom site package that can contain arbitrary content</li>
<li>Installation of non-root user with SSH public key</li>
<li>Applying patches on first boot</li>
</ul>

  ]]>
  </summary>
</entry>


</feed>
