<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>dan&#x27;s tech blog</title>
    <subtitle>direct from the mysterious land of the sysadmin</subtitle>
    <link rel="self" type="application/atom+xml" href="https://blog.dark.ca/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://blog.dark.ca"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-07-31T00:00:00+00:00</updated>
    <id>https://blog.dark.ca/atom.xml</id>
    <entry xml:lang="en">
        <title>16 Years of DevOpsDays: A Look at the Numbers</title>
        <published>2026-07-31T00:00:00+00:00</published>
        <updated>2026-07-31T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/16-years-of-devopsdays/"/>
        <id>https://blog.dark.ca/posts/16-years-of-devopsdays/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/16-years-of-devopsdays/">&lt;p&gt;Since the first DevOpsDays in Ghent in 2009, the community has organised well over 700 events across every populated continent. Here&#x27;s what the shape of that history looks like.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-long-arc-2009-2026&quot;&gt;The long arc, 2009–2026&lt;&#x2F;h2&gt;
&lt;p&gt;Events grew steadily from a handful in the early years to a peak of &lt;strong&gt;81 in 2020&lt;&#x2F;strong&gt; (yes, the pandemic year). The virtual format lowered the barrier to entry: no venue costs, no travel logistics, no border controls. 2020 briefly turned every organiser&#x27;s &quot;we could totally run one&quot; into an actual event.&lt;&#x2F;p&gt;
&lt;p&gt;2021 was the hangover. Numbers dropped nearly in half (42), reflecting both organiser burnout and the awkward middle period between virtual and in-person. From there, in-person events rebuilt: 56 in 2022, 64 in 2023, 68 in 2024.&lt;&#x2F;p&gt;
&lt;p&gt;The most recent years show a mild decline: 60 in 2025 and 53 confirmed for 2026 so far. To me, it looks less like a slump and more like a return to a stable, sustainable equilibrium.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-devopsdays-happen&quot;&gt;Where DevOpsDays happen&lt;&#x2F;h2&gt;
&lt;p&gt;The all-time regional picture:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Region&lt;&#x2F;th&gt;&lt;th&gt;Events&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;USA&lt;&#x2F;td&gt;&lt;td&gt;261&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Europe&lt;&#x2F;td&gt;&lt;td&gt;192&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Brazil&lt;&#x2F;td&gt;&lt;td&gt;106&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;East Asia&lt;&#x2F;td&gt;&lt;td&gt;32&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Latin America (excl. Brazil)&lt;&#x2F;td&gt;&lt;td&gt;32&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Canada&lt;&#x2F;td&gt;&lt;td&gt;29&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;South &amp;amp; Southeast Asia&lt;&#x2F;td&gt;&lt;td&gt;26&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Africa&lt;&#x2F;td&gt;&lt;td&gt;18&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Oceania&lt;&#x2F;td&gt;&lt;td&gt;18&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Central Asia&lt;&#x2F;td&gt;&lt;td&gt;14&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Middle East&lt;&#x2F;td&gt;&lt;td&gt;13&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;USA and Europe together account for roughly 61% of all events ever held. That&#x27;s the headline, but it undersells one thing: &lt;strong&gt;Brazil&lt;&#x2F;strong&gt;. 106 events makes it the single most active country after the USA (by a comfortable margin).&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-post-covid-picture&quot;&gt;The post-COVID picture&lt;&#x2F;h2&gt;
&lt;p&gt;Restrict the lens to 2022 and later, and the picture shifts:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Region&lt;&#x2F;th&gt;&lt;th&gt;2022–2026&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;USA&lt;&#x2F;td&gt;&lt;td&gt;89&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Europe&lt;&#x2F;td&gt;&lt;td&gt;80&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Brazil&lt;&#x2F;td&gt;&lt;td&gt;61&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Latin America (excl. Brazil)&lt;&#x2F;td&gt;&lt;td&gt;17&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;East Asia&lt;&#x2F;td&gt;&lt;td&gt;12&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Central Asia&lt;&#x2F;td&gt;&lt;td&gt;10&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;South &amp;amp; SE Asia&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Canada&lt;&#x2F;td&gt;&lt;td&gt;8&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Africa&lt;&#x2F;td&gt;&lt;td&gt;6&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Oceania&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;Middle East&lt;&#x2F;td&gt;&lt;td&gt;4&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;A few things stand out:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Brazil is on the come-up.&lt;&#x2F;strong&gt; From 5 events in 2022 to 18 in 2025. At current rate it will outpace Europe within a year or two.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;The USA is slowing down.&lt;&#x2F;strong&gt; From 22 events in 2022 to 11 (so far) in 2026; a real decline, which speaks to shifting business priorities.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Europe is remarkably steady.&lt;&#x2F;strong&gt; Bouncing between 14 and 18 events a year through the whole post-COVID period.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Central Asia has quietly arrived.&lt;&#x2F;strong&gt; No events at all before 2018; now a consistent presence in double digits.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;ok-so-now-what&quot;&gt;OK, so now what?&lt;&#x2F;h2&gt;
&lt;p&gt;DevOpsDays is smaller than it was at its 2019–2020 peak, but I think we&#x27;re healthier for it. More distributed, less dependent on any single region, and drawing organisers in places (Baku, Almaty, Tashkent, Kazan) that would have been unthinkable a decade ago. The centre of gravity is still transatlantic, but it&#x27;s drifting south and east, one event at a time.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Building a (mostly) reliable research assistant</title>
        <published>2026-04-24T00:00:00+00:00</published>
        <updated>2026-04-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/building-a-mostly-reliable-ai-research-assistant/"/>
        <id>https://blog.dark.ca/posts/building-a-mostly-reliable-ai-research-assistant/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/building-a-mostly-reliable-ai-research-assistant/">&lt;p&gt;If you install software from a public package registry (npm, PyPI, Crates, etc.), every security decision that registry makes sits inside your trust boundary. You don&#x27;t run the infrastructure, you don&#x27;t set the publisher policies, you don&#x27;t decide what &quot;verified&quot; means, and whatever the registry (fails to) enforce travels straight into your build.&lt;&#x2F;p&gt;
&lt;p&gt;This is a well-studied surface. Sonatype tracked more than 700 thousand malicious open-source packages between 2019 and the end of 2024, with over half a million new ones in the last year of that window alone! That&#x27;s a 156 percent year-over-year growth rate.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#sonatype&quot;&gt;1&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; There are some existing concepts that can help: SLSA gives us a vocabulary for provenance&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#slsa&quot;&gt;2&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;, for example, and Sigstore gives us signing and transparency logs.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#sigstore&quot;&gt;3&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Both are real, serious, and widely adopted. But provenance and signing don&#x27;t themselves answer the question I keep bumping into, which is &lt;em&gt;what is the actual security posture of package registries?&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;So I decided to try to answer that question. I started where all good plans start: a list. I call it the Software Supply Chain Security Scorecard (SSCSS). It&#x27;s a set of 52 binary questions across eight sections, each probing one concrete security control a registry either enforces or doesn&#x27;t: &lt;em&gt;Does the source enforce multi-factor authentication for publishers? Does it require identity federation for organisational accounts? Does it display a verified publisher identity to consumers? Does it have a published vulnerability disclosure policy?&lt;&#x2F;em&gt; Yes, no, or unknown. The questions are binary, but the work of answering them is anything but.&lt;&#x2F;p&gt;
&lt;p&gt;A quick note: This is not to be confused with the OpenSSF &lt;em&gt;Security Scorecard&lt;&#x2F;em&gt; project&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#openssfurl&quot;&gt;4&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;. This is an unrelated tool that scores the security hygiene of open-source &lt;em&gt;source-code repositories&lt;&#x2F;em&gt; (branch protection, signed releases, SAST configuration, and so on) rather than registries. Similar name but a different scope. (I didn&#x27;t actually know it existed when I named mine.)&lt;&#x2F;p&gt;
&lt;p&gt;A good human assessment (i.e. me) takes upwards of a day and a half. It takes that long because &lt;em&gt;enforced&lt;&#x2F;em&gt; is not the same as &lt;em&gt;supported&lt;&#x2F;em&gt;; because documentation and behaviour don&#x27;t always agree; because the useful evidence is usually scattered across docs, RFC repositories, governance pages, changelogs, and the occasional blog post from 2022; and because the honest answer to a surprising number of questions is still &quot;yeah, I dunno&quot; after hours of careful reading. Multiply that by the long tail of registries in general, and it rapidly becomes clear that if you want to cover this ecosystem with any breadth you need either a bigger team or a different approach.&lt;&#x2F;p&gt;
&lt;p&gt;Well I&#x27;m just one person, so I tried the different approach. I built an AI research agent that could work through the scorecard on its own. So this post is about what that took, which turned out to be much more than &quot;wire up an LLM and let it go.&quot; The title&#x27;s hedge is load-bearing: the agent I ended up with is &lt;em&gt;mostly&lt;&#x2F;em&gt; reliable, and the &lt;em&gt;mostly&lt;&#x2F;em&gt; is where the interesting lessons live (I think).&lt;&#x2F;p&gt;
&lt;p&gt;p.s. When I say that I built an agent, that makes it seems like it was a success from day one. It &lt;em&gt;really&lt;&#x2F;em&gt; was not. I&#x27;ll walk through four attempts, and spoiler alert: the first three were failures.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;attempt-one-straight-at-the-wall&quot;&gt;Attempt one: straight at the wall&lt;&#x2F;h2&gt;
&lt;p&gt;The first version was made before I had thought carefully about anything. I fired up Claude Code and gave it a single prompt that said, roughly, &lt;em&gt;here is a list of 52 questions and the name of a target registry&lt;&#x2F;em&gt;, then I let it rip. You can imagine how that went. Context limits, rate limits, truncated output, the whole thing keeling over somewhere around question fifteen. I sat with the broken output for a while and felt stupid.&lt;&#x2F;p&gt;
&lt;p&gt;In retrospect, this was the best possible outcome. It failed immediately, unambiguously, and cheaply. No half-working demo to mistake for progress, no partial results to rationalise. It was the kind of failure that makes you stop typing and start thinking. The thing I was thinking about, initially, was the shape of the input: maybe the prompt was too long, maybe the questions were too varied, maybe I needed to batch. What I should have been thinking about (and wasn&#x27;t yet) was the &lt;em&gt;shape of the problem&lt;&#x2F;em&gt;. I&#x27;d get there eventually, but I had to go the long way around first.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;attempt-two-the-orchestration-era&quot;&gt;Attempt two: the orchestration era&lt;&#x2F;h2&gt;
&lt;p&gt;The second version was much more considered and approximately just as useless. Its architecture was the one you&#x27;d draw on a whiteboard if someone gave you the task for the first time: a lightweight orchestrator on Haiku, spawning a Sonnet researcher agent per scorecard section, each writing its results back to a shared JSON file. Eight parallel researchers, a coordinator, and a shared state file. Very reasonable and, as it turned out, very error-prone. The problems came in two waves.&lt;&#x2F;p&gt;
&lt;p&gt;The first wave was mechanical. Researcher agents would occasionally hang indefinitely, producing nothing and blocking the run. Others would hit a transient error mid-research, write a blank result, and report success upstream to the orchestrator, which would dutifully record the blank result as an answered question. The shared-state file became a source of subtle corruption as different researchers arrived at slightly different interpretations of its structure under slightly different success and failure conditions. The orchestrator grew more defensive with every iteration. Its prompt climbed from a few hundred lines of markdown to nearly a thousand as I added more rules for validating results, more recovery paths for hanging agents, more invariants to protect the state file. More instructions did not produce more reliable behaviour—they produced more surface area for things to go sideways on. The system became harder to reason about with every attempted fix.&lt;&#x2F;p&gt;
&lt;p&gt;I should have paused and asked why a thousand-line prompt was making things &lt;em&gt;worse&lt;&#x2F;em&gt;. I did not. I kept going. Eventually the mechanical problems settled down to a grim steady state where the system would complete a run without actually crashing, and I was able to sit down and read the results.&lt;&#x2F;p&gt;
&lt;p&gt;Which is when the second wave hit: The &lt;em&gt;actual research wasn&#x27;t any good.&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I had confident &quot;yes&quot; answers backed by evidence that clearly said &quot;no&quot; if you read it. I had notes that bore no relation to the question they were attached to. I had URLs that did not exist. Bafflingly, I had answers where the &quot;evidence&quot; turned out, on inspection, to be the model narrating its own search process. Amazing. And when I ran the same assessment against the same registry three times, the results disagreed with each other—not only in their answers but in which questions they considered answerable at all. The inconsistencies were, themselves, inconsistent.&lt;&#x2F;p&gt;
&lt;p&gt;There is a name for this category of failure in the academic literature, and it is &lt;em&gt;not&lt;&#x2F;em&gt; hallucination, at least not in the useful sense of that word. Farquhar, Kossen, Kuhn, and Gal published a paper in &lt;em&gt;Nature&lt;&#x2F;em&gt; in 2024 that carves out a specific subtype they call &lt;em&gt;confabulation&lt;&#x2F;em&gt;: &quot;arbitrary and incorrect generations&quot; that vary between reruns of the same query.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#farquhar&quot;&gt;5&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Hallucination is the umbrella; confabulation is the subset where the wrongness isn&#x27;t stable. The distinction matters, because confabulations are exactly the errors you&#x27;ll catch if you run a query multiple times and compare (and exactly the ones you&#x27;ll miss if you don&#x27;t).&lt;&#x2F;p&gt;
&lt;p&gt;Why does this happen at all? An OpenAI paper from September 2025 makes a mechanistic argument I find persuasive: modern LLM training and evaluation procedures reward &lt;em&gt;guessing&lt;&#x2F;em&gt; over &lt;em&gt;acknowledging uncertainty&lt;&#x2F;em&gt;. &quot;Language models are optimized to be good test-takers,&quot; write Kalai, Nachum, Vempala, and Zhang, &quot;and guessing when uncertain improves test performance.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#kalai&quot;&gt;6&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; The structural incentive of the training pipeline is to produce a confident answer, not to produce &lt;em&gt;no&lt;&#x2F;em&gt; answer when no answer is warranted. Confident wrongness isn&#x27;t a bug; it&#x27;s the predictable output of the optimisation you&#x27;ve run.&lt;&#x2F;p&gt;
&lt;p&gt;You can zoom out further. In the bluntly-titled 2024 paper &lt;em&gt;ChatGPT is bullshit&lt;&#x2F;em&gt;, Hicks, Humphries, and Slater argue that &quot;hallucination&quot; is actually the wrong metaphor for what LLMs do when they produce false text. Hallucination implies a perceptual system misperceiving reality. But LLMs don&#x27;t perceive reality—they produce text without any epistemic stake in it at all. Their behaviour is better described, the authors argue, in the sense that Harry Frankfurt gave the word &lt;em&gt;bullshit&lt;&#x2F;em&gt; in 1986: &quot;speech or text produced without concern for its truth.&quot; The bullshitter &quot;does not care whether the things he says describe reality correctly. He just picks them out, or makes them up, to suit his purpose.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#hicks&quot;&gt;7&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#frankfurt&quot;&gt;8&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This was the frame I needed. The agent wasn&#x27;t &lt;em&gt;misperceiving&lt;&#x2F;em&gt; the documentation. It wasn&#x27;t &lt;em&gt;trying to mislead&lt;&#x2F;em&gt;, either. It was a confident pattern-completer optimised to produce a plausible answer, and plausible answers are easier to generate than correct ones. Once I really internalised that, I stopped trying to make the system more &lt;em&gt;sophisticated&lt;&#x2F;em&gt; and started trying to make it more &lt;em&gt;accountable&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;I didn&#x27;t get there yet, though. First I needed to take a detour through the land of milk and honey, also known as production-grade infrastructure.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;attempt-three-production-grade-reliability-theatre&quot;&gt;Attempt three: production-grade reliability theatre&lt;&#x2F;h2&gt;
&lt;p&gt;I was struggling enough with attempt two that I decided to change tools entirely. I switched to Codex and spent a couple of weeks building what I thought was going to be the serious version.&lt;&#x2F;p&gt;
&lt;p&gt;What I produced was several thousand lines of best-practice Python: a clean orchestration layer, JSON schema enforcement on every boundary, a test suite with fixtures for each question type, local MCP servers, and a sandboxed research environment with controlled network egress. It was the kind of codebase you would be quietly pleased to ship. It had docstrings. It had a linter config. The CI ran on every commit.&lt;&#x2F;p&gt;
&lt;p&gt;It made no difference.&lt;&#x2F;p&gt;
&lt;p&gt;Every time I encountered a new failure mode, more code got written to handle it. The infrastructure became genuinely robust! I could catch a hung researcher, retry a malformed search, validate a schema, roll back a corrupted state file. That was all lovely and made my nerd brain hum, but none of that touched the thing that was actually broken. The research quality didn&#x27;t move. The model still confabulated. The confident-yes-backed-by-evidence-that-says-no problem was exactly as prevalent as it had been in attempt two, now wrapped in a prettier wrapper.&lt;&#x2F;p&gt;
&lt;p&gt;This is the central engineering lesson I took from the project, and I&#x27;d like to state it as plainly as I can: &lt;strong&gt;You cannot code your way out of an LLM quality problem.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Mechanical failures and quality failures look similar from the outside. Both produce wrong answers. Both break user-visible behaviour. Both make you feel like you need to &lt;em&gt;fix&lt;&#x2F;em&gt; something. But they have entirely different causes.&lt;&#x2F;p&gt;
&lt;p&gt;A &lt;em&gt;mechanical failure&lt;&#x2F;em&gt; is a hung process, a schema violation, a corrupted file, a network timeout, etc. These are the kinds of things our field has spent fifty years learning to handle, and for which the standard defensive-engineering toolkit works well. A &lt;em&gt;quality failure&lt;&#x2F;em&gt; is the model confidently producing content that is wrong. No amount of retry logic, schema validation, sandboxing, or test coverage touches that, because none of those tools are in the loop where the wrongness actually gets introduced. They&#x27;re upstream and downstream of it, not inside it.&lt;&#x2F;p&gt;
&lt;p&gt;This is not a new observation. Chip Huyen made it in its more general ML form back in 2022: &quot;ML systems often fail silently … Users encounter painfully wrong outputs without realizing they&#x27;re wrong, making performance expectation violations harder to detect than operational failures.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#huyen&quot;&gt;9&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Hamel Husain and Shreya Shankar (who between them have written much of the current practitioner canon on evaluating LLM applications) make a sharper version of the point: the most important activity in evals is &lt;em&gt;error analysis&lt;&#x2F;em&gt;, not infrastructure. &quot;Start with error analysis, not infrastructure. Spend 30 minutes manually reviewing 20-50 LLM outputs whenever you make significant changes.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#husainshankar&quot;&gt;10&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Eugene Yan says it a third way: &quot;While building with AI can feel like magic, building AI products still takes elbow grease. If teams don&#x27;t apply the scientific method, practice eval-driven development, and monitor the system&#x27;s output, buying or building yet another evaluation tool won&#x27;t save the product.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#yan&quot;&gt;11&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This was the pivot. The problem was never the infrastructure. It was the method.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;factory-vs-lever&quot;&gt;Factory vs lever&lt;&#x2F;h3&gt;
&lt;p&gt;When I came back to Claude Code from Codex, I noticed something I hadn&#x27;t seen clearly before. Both are terminal REPLs over an LLM. Both do broadly similar things. But they have fundamentally different defaults.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Codex reaches for infrastructure.&lt;&#x2F;strong&gt; Given a problem, it wants to build a factory: structured code, generator modules, layered abstractions, a test harness. It is very good at that, and if the problem you have is &quot;produce a well-engineered software artefact,&quot; the factory instinct is the right one.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Claude Code reaches for the simplest mechanism that works.&lt;&#x2F;strong&gt; Given the same problem, it gravitates toward a single-file script, a direct invocation, the least amount of apparatus that can plausibly do the job. It will &lt;em&gt;build&lt;&#x2F;em&gt; infrastructure if you ask it to, but it won&#x27;t go looking for excuses to.&lt;&#x2F;p&gt;
&lt;p&gt;This isn&#x27;t a claim about the underlying models — Codex and Claude Code both run various members of the same family of frontier LLMs. It&#x27;s a claim about the &lt;em&gt;harness&lt;&#x2F;em&gt;. The HumanLayer team have an apt framing: &quot;The most well-known examples are Anthropic&#x27;s Claude, where the same Claude model powers different interfaces with radically different behavior due to the harness.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#harness&quot;&gt;12&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; What you think of as a model&#x27;s personality is very often a harness&#x27;s personality.&lt;&#x2F;p&gt;
&lt;p&gt;For a problem where the hard part was infrastructure, Codex&#x27;s defaults would have been the right ones. For a problem where the hard part was research &lt;em&gt;quality&lt;&#x2F;em&gt;, I needed a lever, not a factory. I had been fighting a tool&#x27;s instinct rather than matching it. Switching tools didn&#x27;t solve my problem — it just moved me from a harness whose defaults were working against me to one whose defaults were working with me.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;attempt-four-starting-from-constraints-not-architecture&quot;&gt;Attempt four: starting from constraints, not architecture&lt;&#x2F;h2&gt;
&lt;p&gt;For the fourth attempt I did something I should have done at the start and hadn&#x27;t: I stopped designing and wrote down the constraints.&lt;&#x2F;p&gt;
&lt;p&gt;Three pages of them. Not requirements in the usual sense — no &quot;the system shall&quot; language. Just a list of problems I had hit and things I needed any real solution to satisfy. &lt;em&gt;Answers must be grounded in verifiable quotes, not in inference. The same question run twice should produce the same answer, or at least tell me honestly that it doesn&#x27;t know. The agent should be able to resume if my laptop goes to sleep. I should be able to read the agent&#x27;s reasoning trail after the fact, in full.&lt;&#x2F;em&gt; And so on.&lt;&#x2F;p&gt;
&lt;p&gt;One constraint, once I wrote it down, changed everything: &lt;strong&gt;Time doesn&#x27;t matter.&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I was assessing six registries, with more on the roadmap. I was not in a hurry. A single agent that finished a run in forty minutes of patient, serial work was strictly better than a fleet of eight parallel agents that finished in four but disagreed with themselves half of the time.&lt;&#x2F;p&gt;
&lt;p&gt;This eliminated parallelism. Which eliminated the orchestrator. Which eliminated the shared-state file. Which eliminated most of the surface area where attempt two had gone wrong. I realised that &lt;em&gt;a single agent, working slowly and correctly, through all 52 questions in series.&lt;&#x2F;em&gt; was not a compromise; it was the right answer to the actual problem, which I had been talking myself out of by building from the start.&lt;&#x2F;p&gt;
&lt;p&gt;The design principle that crystallised out of this (and which is a Datadog maxim): &lt;strong&gt;simple, but not simplistic.&lt;&#x2F;strong&gt; Not a short prompt that glosses over the hard parts. Not a naïve architecture that ignores the failure modes. Just the minimum complexity the problem actually demands, applied precisely where it&#x27;s needed.&lt;&#x2F;p&gt;
&lt;p&gt;Anthropic&#x27;s engineering team published a post called &lt;em&gt;Building effective agents&lt;&#x2F;em&gt; in December 2024 that captures the same sentiment from the other direction. Schluntz and Zhang write: &quot;The most successful implementations weren&#x27;t using complex frameworks or specialized libraries. Instead, they were building with simple, composable patterns... Success in the LLM space isn&#x27;t about building the most sophisticated system. It&#x27;s about building the right system for your needs.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#anthropicagents&quot;&gt;13&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Simon Willison, after two years of refusing to use the word &quot;agent&quot; because nobody could agree on a definition, recently arrived at one that is about as tight as I&#x27;ve seen: &quot;An LLM agent runs tools in a loop to achieve a goal.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#willisondef&quot;&gt;14&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; That&#x27;s the whole abstraction. Everything else is implementation detail.&lt;&#x2F;p&gt;
&lt;p&gt;The system I ended up with has two skill&#x2F;agent pairs. In Claude Code terminology, a &lt;em&gt;skill&lt;&#x2F;em&gt; is a named entry point (i.e. something you invoke with &lt;code&gt;&#x2F;skill-name&lt;&#x2F;code&gt;) that loads context and sets a workflow in motion. An &lt;em&gt;agent&lt;&#x2F;em&gt; is a specialised subprocess with its own system prompt, model assignment, and tool permissions. Skills are the user-facing verb and agents are the thing doing the work.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;build-starter-kit &amp;lt;registry&amp;gt;  →  starter-kit-builder (Sonnet)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                        ↓&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                  internal&#x2F;starter-kits&#x2F;&amp;lt;registry&amp;gt;.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                        ↓&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&#x2F;assess &amp;lt;registry&amp;gt;             →  assessment (Opus)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                        ↓&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                  assessments&#x2F;&amp;lt;registry&amp;gt;&#x2F;runtime-&amp;lt;ts&amp;gt;.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                                  assessments&#x2F;&amp;lt;registry&amp;gt;&#x2F;scorecard-&amp;lt;ts&amp;gt;.json&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;start-at-the-start&quot;&gt;Start at the start&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&#x2F;build-starter-kit&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; runs first, once per registry. Its entire job is source configuration: &lt;em&gt;where should the assessment agent look?&lt;&#x2F;em&gt; It maps out the registry&#x27;s documentation structure, identifies the handful of hub URLs that matter (documentation root, blog root, security page, policy index), locates the RFC or proposal system if one exists, determines which URL patterns to block (package pages, user profiles, search results — anything that reflects user-generated content rather than registry policy), and captures a short interview&#x27;s worth of human-only knowledge: any questions you already know the answer to from private sources, any questions known to be permanently unanswerable. It writes a starter-kit JSON and stops.&lt;&#x2F;p&gt;
&lt;p&gt;The brief is explicit about what it is &lt;em&gt;not&lt;&#x2F;em&gt;: the starter-kit builder does not read policy content, does not try to answer scorecard questions, does not populate anything from its own research. If it finds itself going deep into the registry&#x27;s documentation to determine whether a security control exists, it has gone out of scope. The prompt says this three separate times in three slightly different ways because I found that the model, given the option, would drift toward helpful research every single time.&lt;&#x2F;p&gt;
&lt;p&gt;I run the starter kit on Sonnet. This is because Sonnet is extremely good at driving at the most obvious interpretation of a task by the most direct path; that tendency is a liability for the open-ended research job, but it is &lt;em&gt;exactly&lt;&#x2F;em&gt; the right instinct for source configuration, where the most obvious hub URLs usually are the right ones and you don&#x27;t want the model to get clever.&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s what a sample starter kit looks like, trimmed for length:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;schema_version&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;registry&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;rubygems&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;registry_url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;rubygems.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;notes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Operated by Ruby Central (nonprofit). Completed first external security audit by Trail of Bits in 2024. Trusted Publishing via OIDC launched December 2023. Mandatory MFA enforced for top-100 gem owners...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;sources&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;primary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;rubygems.org&#x2F;pages&#x2F;security&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,     &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Security disclosure policy and HackerOne details&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;rubygems.org&#x2F;policies&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,           &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Policies hub: acceptable use, copyright, privacy, ToS&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;guides.rubygems.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,             &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Documentation hub: security, trusted publishing, MFA&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;blog.rubygems.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,               &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Official blog: releases, security updates, features&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;secondary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rubygems&#x2F;rubygems.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;, &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;description&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Registry source code, issues, PRs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;blocked&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;pattern&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;rubygems.org&#x2F;gems&#x2F;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;reason&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Individual gem pages are user content, not policy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;pattern&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;rubygems.org&#x2F;profiles&#x2F;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;reason&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;User profile pages are user content, not policy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;rfcs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rubygems&#x2F;rfcs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;acceptance_criteria&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;RFC PR merged into the text&#x2F; directory. Merged RFCs become &amp;#39;active&amp;#39; after a 7-day FCP.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;notes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Concrete examples: text&#x2F;0007-mfa-rollout.md (MFA rollout), text&#x2F;0010-OIDC.md (trusted publishing).&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;pre_answered&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {},&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;evidence_gaps&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: {}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nothing exotic. A list of hubs, a list of blocked patterns, an RFC pointer with a concrete definition of what &quot;accepted&quot; means, and room for human-only knowledge. It takes about ten minutes to produce and it is the single most important piece of context the assessment agent will ever see.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;do-the-actual-thing&quot;&gt;Do the actual thing&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;&#x2F;assess&lt;&#x2F;code&gt;&lt;&#x2F;strong&gt; is where the real work happens. The assessment agent works through all 52 questions in section order. For each question it follows a source hierarchy: primary sources first (the hubs the starter kit identified), then RFCs if applicable, then secondary sources, and only as a last resort the open web. It is not permitted to answer a question from inference; every answer must be accompanied by a direct quote from a real URL. It produces two files: a &lt;code&gt;scorecard-*.json&lt;&#x2F;code&gt; with the final answers and their citations, and a &lt;code&gt;runtime-*.json&lt;&#x2F;code&gt; with the complete evidence trail — every query issued, every URL visited, every candidate quote, every decision point. Same timestamp for both. The runtime file is resumable: if the run is interrupted, I can pick it up on the same question where it stopped.&lt;&#x2F;p&gt;
&lt;p&gt;The assessment agent runs on Opus. Opus has a specific trait that Sonnet does not, which is that it likes to play with language. Left to its own devices, it will re-frame a question, re-phrase a search query, try a synonym, worry at a word. That is a liability when you need a direct path to an obvious answer. It is a &lt;em&gt;feature&lt;&#x2F;em&gt; when you need to interrogate a specific claim from different angles before you trust it. I&#x27;ll come back to that.&lt;&#x2F;p&gt;
&lt;p&gt;One piece of context that matters before the next section. Earlier I said that running the same assessment three times produced three different answers. That wasn&#x27;t a quirk of the attempt-two architecture; it&#x27;s a property of LLM inference in general, and it&#x27;s worth understanding why. Horace He and colleagues at Thinking Machines Lab published an essay in September 2025 called &lt;em&gt;Defeating Nondeterminism in LLM Inference&lt;&#x2F;em&gt; that pins the blame on a specific cause: &quot;The primary reason nearly all LLM inference endpoints are nondeterministic is that the load (and thus batch-size) nondeterministically varies.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#he&quot;&gt;15&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; The floating-point non-associativity story you hear in passing (different GPUs, different rounding) is the symptom; the underlying cause is that production inference systems batch requests together and the batch composition varies. Which means — and this is the useful bit — run-to-run variance is a &lt;em&gt;systems-design property&lt;&#x2F;em&gt;, not a property of the universe. It can be reduced, designed around, or embraced. You just have to pick.&lt;&#x2F;p&gt;
&lt;p&gt;Thus, my design does not try to eliminate variance. It logs it exhaustively and exploits it.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-the-answers-right-operational-versus-behavioural-prompting&quot;&gt;Getting the answers right: operational versus behavioural prompting&lt;&#x2F;h2&gt;
&lt;p&gt;The assessment agent&#x27;s system prompt is about two hundred and fifty lines of markdown. Every line is load-bearing because every line addresses a specific failure I observed in a previous run&#x27;s evidence trail. The prompt has grown, but grown in a different sense from the attempt-two orchestrator: not accumulating defensive handlers, but encoding lessons.&lt;&#x2F;p&gt;
&lt;p&gt;The prompt splits cleanly into two kinds of instructions, and the distinction between them is the single thing I most wish I&#x27;d understood much earlier in my journey of discovery: operational vs behavioural instructions.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Operational instructions&lt;&#x2F;strong&gt; tell the agent &lt;em&gt;what to do and in what order, using which tools&lt;&#x2F;em&gt;. They are procedural: &lt;em&gt;parse these arguments; load the starter kit file; initialise the runtime file with this schema; call &lt;code&gt;jq&lt;&#x2F;code&gt; to extract questions matching the filter; write the runtime file after each completed section&lt;&#x2F;em&gt;, etc. Operational instructions are the kind of thing you&#x27;d write for a shell script if a shell script could handle the task, and indeed wherever a piece of operational behaviour is genuinely deterministic the right move is to pull it out into an actual shell script and have the agent invoke that. A specific example is &lt;em&gt;&quot;Use &lt;code&gt;jq&lt;&#x2F;code&gt; to manipulate JSON. Do not parse or edit JSON as text.&quot;&lt;&#x2F;em&gt; because the model, left to its own devices, will happily reimplement JSON parsing and get it subtly wrong.&lt;&#x2F;p&gt;
&lt;p&gt;This generalises into a principle I&#x27;ve ended up putting at the top of most agent prompts I write now: &lt;strong&gt;tooling over LLM.&lt;&#x2F;strong&gt; The model should be the orchestrator and the reasoner of last resort. For deterministic sub-tasks—parsing, filtering, counting, scheduling, any operation where we have fifty years of reliable tooling already—use that tool. Don&#x27;t let the model confabulate its way through work that a deterministic two-line &lt;code&gt;jq&lt;&#x2F;code&gt; expression would get right every time.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Behavioural instructions&lt;&#x2F;strong&gt; tell the agent &lt;em&gt;how to think about the problem&lt;&#x2F;em&gt;. They are about judgement: what counts as evidence, when to keep searching, how to interpret ambiguous documentation, what &quot;enforce&quot; means in contrast to &quot;support.&quot; They cannot be replaced with a shell script, because the work they describe is exactly the work we are hiring the model for.&lt;&#x2F;p&gt;
&lt;p&gt;You can see the split most clearly in how I write new rules. Every time I review a runtime file and find a failure mode, I ask: &lt;em&gt;is this a thing the model got wrong because I told it to do the wrong procedure, or because it reasoned in a way I don&#x27;t want?&lt;&#x2F;em&gt; Procedural failures get operational rules: &lt;em&gt;&quot;When you cite evidence, record &lt;code&gt;url&lt;&#x2F;code&gt;, &lt;code&gt;quote&lt;&#x2F;code&gt;, and &lt;code&gt;source_type&lt;&#x2F;code&gt; in a single object, not as parallel lists.&quot;&lt;&#x2F;em&gt; Reasoning failures get behavioural rules: &lt;em&gt;&quot;A quote must be content from the source, not a description of your own search process.&quot;&lt;&#x2F;em&gt; Confusing the two produces prompts that are both longer and less effective.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-small-team-of-researchers-with-varying-expertise&quot;&gt;A small team of researchers with varying expertise&lt;&#x2F;h3&gt;
&lt;p&gt;I find it useful to think about agent prompts the way I&#x27;d think about briefing a team of contractors. You would not walk into a room of six analysts and deliver one monolithic paragraph of instructions. You would break the work into specified sub-tasks with clear handoffs; you would attach behavioural norms to each one: &lt;em&gt;&quot;be skeptical of vendor marketing,&quot; &quot;quote sources verbatim,&quot; &quot;keep searching when the evidence is ambiguous&quot;&lt;&#x2F;em&gt;, and so forth. Naturally, each member of the team has varying expertise, which means things that seem obvious might need to be spelled out (sometimes in excruciating detail).&lt;&#x2F;p&gt;
&lt;p&gt;The agent prompt is therefore that briefing document, written for an extremely fast but extremely literal contractor who has never worked with you before and forgets everything between engagements. Things like, &quot;please don&#x27;t make things up,&quot; &quot;don&#x27;t stop at the first promising result,&quot; &quot;here is what I mean by &#x27;enforce&#x27;&quot;. You have to say these things to the agent, because it will &lt;em&gt;assume&lt;&#x2F;em&gt; whatever you don&#x27;t specify, and those assumptions are probably wrong. The prompt length is important. If it&#x27;s too long the model will get confused; but if it&#x27;s too short, the assumptions creep in. Unfortunately there is no One True Way to get this right—you just have to tune it as you go.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;non-determinism-can-be-your-friend&quot;&gt;Non-determinism can be your friend&lt;&#x2F;h3&gt;
&lt;p&gt;The single most interesting thing in the behavioural half of the prompt is the way it treats non-determinism. I had spent attempts two and three trying to &lt;em&gt;suppress&lt;&#x2F;em&gt; the model&#x27;s variance, and it never worked. In attempt four, I flipped the polarity. Every question gets re-phrased in three different ways before any searching happens at all.&lt;&#x2F;p&gt;
&lt;p&gt;The instruction, verbatim from the prompt:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;**Step 1 — Generate queries**: produce 3 query variations from the question&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;text covering different angles:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Direct phrasing of the question&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Synonym-heavy rephrasing&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- A different aspect or implication of the question&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Three variations, three different search passes per source, all three run even when the first one returns a promising result. This is weaponised non-determinism. The model&#x27;s tendency to riff on language—the very thing that made Opus annoying for the starter-kit job—becomes the mechanism by which we can interrogate a claim from angles that I wouldn&#x27;t have thought of. If three different phrasings of &lt;em&gt;&quot;does this registry enforce MFA for publishers?&quot;&lt;&#x2F;em&gt; all return the same answer from the same source, I can believe the answer. If they don&#x27;t, I have contradictory evidence to work through, which is fine. Contradictory evidence is information. Missing evidence is not.&lt;&#x2F;p&gt;
&lt;p&gt;The underlying pattern has academic support. Gao and colleagues published a paper in 2022 called &lt;em&gt;Precise Zero-Shot Dense Retrieval without Relevance Labels&lt;&#x2F;em&gt; that introduces a technique called HyDE — the model generates &lt;em&gt;hypothetical answer documents&lt;&#x2F;em&gt; for a query, and those documents are then used as the retrieval key.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#hyde&quot;&gt;16&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; It&#x27;s a particular application of a general insight: one phrasing of a question is a sample, not a signal. Sample more.&lt;&#x2F;p&gt;
&lt;p&gt;And running all three variations &lt;em&gt;even after a promising first result&lt;&#x2F;em&gt; is a direct hedge against confirmation bias, which is a real and present threat with these models. The prompt is explicit about it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Run ALL 3 even after a promising result on query 1 — seek contradictions,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;not just confirmation.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is one of the patterns of what I think of as a &lt;strong&gt;rule ↔ failure-mode table&lt;&#x2F;strong&gt;: a handful of behavioural lines, each of which exists because the model, unsupervised, failed in that specific way often enough that I had to write the rule to make it stop.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Rule&lt;&#x2F;th&gt;&lt;th&gt;Failure mode it addresses&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&quot;Inference is not evidence. Every answer requires a direct quote from a source URL.&quot;&lt;&#x2F;td&gt;&lt;td&gt;Model confabulates plausible-sounding justifications in place of sourcing.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;Run all three query variations even after a promising first result.&quot;&lt;&#x2F;td&gt;&lt;td&gt;Confirmation bias — model stops searching the moment it finds a confirming sentence.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;A quote must be content from the source, not a description of your own search process.&quot;&lt;&#x2F;td&gt;&lt;td&gt;Model narrates its own activity and treats the narration as evidence.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;Ambiguous evidence means keep searching, not stop.&quot;&lt;&#x2F;td&gt;&lt;td&gt;Default inclination toward closure — model wants to finish a question, not leave it open.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;Corroborating evidence from a different URL is desirable; from the same URL it is noise.&quot;&lt;&#x2F;td&gt;&lt;td&gt;Model double-cites the same page to appear to have more evidence than it does.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&quot;When a page contains both historical&#x2F;transitional and current-state language, always prefer the current-state sentence.&quot;&lt;&#x2F;td&gt;&lt;td&gt;Model quotes an older announcement while ignoring the newer one on the same page.&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;Every one of these rules took at least one painful runtime-file review to discover, and most of them I got wrong the first time. &quot;A quote must be content from the source, not a description of your own search process&quot; in particular was a bizarre pathology to encounter: the model would, when it couldn&#x27;t find evidence, &lt;em&gt;write a sentence describing its own search&lt;&#x2F;em&gt; and put that in the evidence field. Things like: &lt;em&gt;&quot;Review of the security documentation did not reveal an enforcement policy for MFA.&quot;&lt;&#x2F;em&gt; That is not evidence, but it &lt;em&gt;looks&lt;&#x2F;em&gt; like evidence to the model, which is much worse.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s a deep result here that Shankar, Zamfirescu-Pereira, Hartmann, Parameswaran, and Arawjo named in a UIST 2024 paper called &lt;em&gt;Who Validates the Validators?&lt;&#x2F;em&gt;: they call it &lt;strong&gt;criteria drift&lt;&#x2F;strong&gt;. Users building LLM applications, they observed, &quot;need criteria to grade outputs, but grading outputs helps users define criteria.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#shankar&quot;&gt;17&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; You cannot write all of your evaluation rules in advance. You have to look at outputs, notice where they go wrong, and write a rule. Then you look at more outputs, notice that a rule you wrote has a loophole, and refine it. The rule ↔ failure-mode table above didn&#x27;t come from thinking carefully about the problem. It came from reading hundreds of runtime files and writing down what I saw.&lt;&#x2F;p&gt;
&lt;p&gt;This is a big part of what observability looks like for an LLM agent. Not a dashboard of request latencies (though that can be interesting, of course). Instead, what was useful to me was a full transcript of every decision the agent made, in a schema I can read, for questions I know the answer to, so I can compare what the agent did to what it should have done. Every entry in the runtime file is a sample in the distribution of the agent&#x27;s behaviour, and the prompt is the mechanism I have to &lt;em&gt;shape&lt;&#x2F;em&gt; that distribution.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;what-it-actually-looks-like&quot;&gt;What it actually looks like&lt;&#x2F;h3&gt;
&lt;p&gt;Here&#x27;s a slice of a real runtime file: the agent&#x27;s work on Q1.1 (&quot;Does the source enforce multi-factor authentication for publishers?&quot;) from a RubyGems assessment.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;json&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Q1.1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;question&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Does the source enforce multi-factor authentication (MFA) for publishers?&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;status&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;answered&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;answer&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;NO&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;searches&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;site:guides.rubygems.org MFA enforce multi-factor authentication required publishers&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url_scope&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;guides.rubygems.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;result_url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;guides.rubygems.org&#x2F;mfa-requirement-opt-in&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;site:blog.rubygems.org MFA enforce mandatory multi-factor authentication all users&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url_scope&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;blog.rubygems.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;result_url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;blog.rubygems.org&#x2F;2022&#x2F;08&#x2F;15&#x2F;requiring-mfa-on-popular-gems.html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;site:blog.rubygems.org mandatory MFA all gem owners require 2024 2025 2026&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url_scope&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;blog.rubygems.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;result_url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;blog.rubygems.org&#x2F;2023&#x2F;12&#x2F;14&#x2F;trusted-publishing.html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;rubygems.org mandatory MFA all users 2025 2026 enforce requirement&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url_scope&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;result_url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;rubycentral.org&#x2F;news&#x2F;securing-rubys-future...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;rubygems.org MFA enforcement expanded lowered threshold 2024 2025 all gem owners&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url_scope&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;result_url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;query&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;site:github.com&#x2F;rubygems&#x2F;rfcs MFA rollout mandatory all users&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url_scope&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;github.com&#x2F;rubygems&#x2F;rfcs&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;result_url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rubygems&#x2F;rfcs&#x2F;blob&#x2F;master&#x2F;text&#x2F;0007-mfa-rollout.md&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;evidence&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: [&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;blog.rubygems.org&#x2F;2022&#x2F;08&#x2F;15&#x2F;requiring-mfa-on-popular-gems.html&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;quote&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Today (August 15th, 2022), we will begin to enforce MFA on owners of gems with over 180 million total downloads.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;source_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;primary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;guides.rubygems.org&#x2F;mfa-requirement-opt-in&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;quote&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;You can opt-in a gem you are managing by releasing a version that has metadata.rubygems_mfa_required set to true.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;source_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;primary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    { &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;url&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;https:&#x2F;&#x2F;github.com&#x2F;rubygems&#x2F;rfcs&#x2F;blob&#x2F;master&#x2F;text&#x2F;0007-mfa-rollout.md&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;quote&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Once these policy changes are fully complete for maintainers of the most popular gems, we intend to increase coverage by extending the MFA requirement to more gems in future.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;      &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;source_type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;rfc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  ],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;  &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-type&quot;&gt;notes&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;: &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;RubyGems enforces MFA only for owners of gems exceeding 180 million cumulative downloads (roughly the top 100 gems), not for all publishers. For other gems, MFA enforcement is opt-in via the rubygems_mfa_required metadata flag set by individual gem maintainers. The accepted RFC (0007-mfa-rollout) describes phased expansion but defers broader enforcement to a future RFC that has not materialised. Ruby Central encourages MFA adoption but has not mandated it universally.&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Six searches across three domain-scoped sources, two open-web fallbacks, and an RFC. Three evidence items from three different URLs, each with a direct quote and a source-type tag. A notes field that a human reviewer can read and understand the answer from. The full trail is much more informative than a yes&#x2F;no bit on its own would be, because the reasoning trail is right there.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;trust-but-verify&quot;&gt;Trust, but verify&lt;&#x2F;h3&gt;
&lt;p&gt;One behaviour this example demonstrates that I want to call out specifically is the &lt;em&gt;theory-vs-reality gap&lt;&#x2F;em&gt;. This one is informal security folk knowledge and, as far as I can tell, isn&#x27;t systematised anywhere in the literature. The security community has rigorous frameworks for lots of things, but the gap between what a registry (or anything, really) &lt;em&gt;documents about itself&lt;&#x2F;em&gt; and what it &lt;em&gt;actually does&lt;&#x2F;em&gt; remains a largely informal concern.&lt;&#x2F;p&gt;
&lt;p&gt;The agent surfaces it every few registries. Q1.1 is a soft example: RubyGems documents a phased MFA policy that &lt;em&gt;sounds&lt;&#x2F;em&gt; mandatory at a quick read but turns out, on careful reading, to apply only to the top 100 gems by download count. Other questions have turned up harder examples. Treating documentation as a starting point for investigation rather than ground truth, and forcing the agent to quote the enforcement language itself rather than paraphrasing its flavour, is one of the main things that lifts the agent above a glorified documentation summariser.&lt;&#x2F;p&gt;
&lt;p&gt;There&#x27;s a closely related failure mode worth calling out because it&#x27;s specific to this kind of research and because an LLM handles it badly by default: &lt;em&gt;absence of evidence.&lt;&#x2F;em&gt; If the agent searches the documentation for &quot;vulnerability disclosure policy&quot; and finds nothing, a human researcher reads that as meaningful evidence that the policy probably doesn&#x27;t exist. The agent reads it as evidence that &lt;em&gt;it hasn&#x27;t found the answer yet&lt;&#x2F;em&gt;. It keeps searching, dutifully, and will eventually reach for the open web or mark the question unknown rather than drawing the conclusion a human would draw in thirty seconds. Altman and Bland&#x27;s famous note on this distinction — &lt;em&gt;Absence of evidence is not evidence of absence&lt;&#x2F;em&gt; — was written about clinical trials in the BMJ in 1995, but it applies here, too: a null result is not the same as a negative result, and how you handle the distinction is a design choice.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#altman&quot;&gt;18&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; I resolve it by instructing the agent to exhaust its sources before marking a question &lt;code&gt;unknown&lt;&#x2F;code&gt;, and by treating &lt;code&gt;unknown&lt;&#x2F;code&gt; as a first-class answer—not a failure mode, not something to avoid, but an honest reflection of what the public documentation does and doesn&#x27;t tell us.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-human-in-the-loop&quot;&gt;The human in the loop&lt;&#x2F;h2&gt;
&lt;p&gt;Even with all of the above, the agent gets some questions wrong. This is expected, because confabulation is a property of the underlying system, not a bug I can fix in a prompt. The question is what you &lt;em&gt;do&lt;&#x2F;em&gt; with the wrongness.&lt;&#x2F;p&gt;
&lt;p&gt;What I do is run each assessment multiple times. Typically three, sometimes more if I have the patience. Each run is cheap: I&#x27;m not in a hurry, the agent works in series, I can do something else while it runs. I do this because the runs tend to disagree with each other in a very specific way.&lt;&#x2F;p&gt;
&lt;p&gt;Most questions stabilise. Let&#x27;s say that 90% of them answer the same way every time, with the same evidence, and when I spot-check those against the documentation they&#x27;re right. A small group (typically three to five questions, depending on the target) flip between runs. Sometimes between YES and NO, sometimes between one of those and UNKNOWN, sometimes cycling through all three.&lt;&#x2F;p&gt;
&lt;p&gt;Those flips are precisely what Farquhar et al. call &lt;em&gt;confabulations&lt;&#x2F;em&gt;: rerun-variant arbitrary wrong answers. The flip rate is, in effect, a probabilistic quality signal that doesn&#x27;t require a ground-truth oracle. I don&#x27;t need an answer key. I only need to notice that the model hasn&#x27;t converged on an answer across multiple tries, and that by itself tells me the question is above the agent&#x27;s reliable resolution.&lt;&#x2F;p&gt;
&lt;p&gt;Those flipping questions are exactly where I spend my review effort. I go look at them myself, read the documentation carefully, follow the evidence the agent did and didn&#x27;t find, and produce an answer I&#x27;m willing to stand behind. Then I put that answer into the starter kit&#x27;s &lt;code&gt;pre_answered&lt;&#x2F;code&gt; block, with the URL and the quote I used to resolve it. The next run (and every run after it) starts by copying that pre-answered entry into the scorecard verbatim and moving on.&lt;&#x2F;p&gt;
&lt;p&gt;This is the part I like best about the design. Every assessment makes the next one &lt;em&gt;faster and more accurate&lt;&#x2F;em&gt;. The system accumulates a data asset over time; the starter kit starts out containing hubs and blocked patterns, and over the course of a few assessments, it gains a growing set of human-resolved answers to the specific questions the agent couldn&#x27;t handle. My human effort isn&#x27;t thrown away on each run: it&#x27;s captured in a durable input to the next one.&lt;&#x2F;p&gt;
&lt;p&gt;I hesitate to call this a ratchet because ratchet implies irreversibility, and human-resolved answers can be wrong or go stale. The starter kit&#x27;s pre-answered section is versioned with the registry&#x27;s policy as of a given date, and we&#x27;ll need to revisit it when things change. But within a normal cadence of review, the direction is one-way: the work the agent can do reliably, it does, at scale; the work it can&#x27;t, I do, once, and capture the result. Breadth from the agent, depth from me, and both compounding into a system that covers more surface area with every registry we touch.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-agent-itself-is-an-attack-surface&quot;&gt;The agent itself is an attack surface&lt;&#x2F;h2&gt;
&lt;p&gt;I wasn&#x27;t originally going to mention this, but it&#x27;s important—especially for an audience that thinks about security for a living. Automated agents that have access to the open web are &lt;em&gt;dangerous&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;An LLM agent that &lt;em&gt;browses the web&lt;&#x2F;em&gt; (i.e. reads arbitrary pages, follows links, extracts text it then feeds back into its own reasoning) sits inside a threat model that is fundamentally different from one that only operates on trusted local inputs. Simon Willison coined a phrase for it in June 2025 that I&#x27;ve found clarifying: the &lt;em&gt;lethal trifecta&lt;&#x2F;em&gt;. Three capabilities that, when present together, make an agent a serious security liability:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;Access to your private data&lt;&#x2F;li&gt;
&lt;li&gt;Exposure to untrusted content&lt;&#x2F;li&gt;
&lt;li&gt;The ability to externally communicate in a way that could be used to steal your data&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#willisontrifecta&quot;&gt;19&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;A registry-assessment agent has all three. It has private data: my local environment, whatever else is on my machine that Claude Code can see. It has exposure to untrusted content: every web page it fetches is attacker-controlled from the agent&#x27;s perspective. And it obviously has external communication: it can make outbound HTTP requests.&lt;&#x2F;p&gt;
&lt;p&gt;The specific threat this creates is &lt;em&gt;indirect prompt injection&lt;&#x2F;em&gt;. A hostile web page can contain instructions aimed at the agent rather than the human reader. Stuff hidden in HTML comments, like in text with CSS that sets it to &lt;code&gt;display: none&lt;&#x2F;code&gt;, in image alt text, or in JavaScript that modifies the rendered content. Those instructions get read by the agent as part of its retrieved context. Greshake and colleagues formalised this class of attack in a 2023 paper called &lt;em&gt;Not what you&#x27;ve signed up for&lt;&#x2F;em&gt;: &quot;LLM-Integrated Applications blur the line between data and instructions... Adversaries can remotely exploit LLM-integrated applications by strategically injecting prompts into data likely to be retrieved.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#greshake&quot;&gt;20&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt;&lt;&#x2F;p&gt;
&lt;p&gt;It is not a hypothetical concern. Brave Software&#x27;s security researchers published a technical write-up in August 2025 of an indirect-prompt-injection attack against Perplexity&#x27;s Comet agentic browser. The money line: &quot;When an AI assistant follows malicious instructions from untrusted webpage content, traditional protections such as same-origin policy (SOP) or cross-origin resource sharing (CORS) are all effectively useless.&quot;&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#comet&quot;&gt;21&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; The browser-level security model we&#x27;ve spent thirty years building does not apply at the level where an AI agent is making decisions, because the decisions are happening in LLM-land, not in browser-land.&lt;&#x2F;p&gt;
&lt;p&gt;My response to this is to run Claude Code, and therefore the assessment agent, inside a sandbox called Nono. Nono is a capability-based sandbox that uses kernel-level isolation (Landlock on Linux, Seatbelt (&lt;code&gt;sandbox-exec&lt;&#x2F;code&gt;) on macOS) to restrict a process to an explicit allow-list of filesystem paths and network endpoints.&lt;sup class=&quot;footnote-reference&quot;&gt;&lt;a href=&quot;#nono&quot;&gt;22&lt;&#x2F;a&gt;&lt;&#x2F;sup&gt; Once a profile is applied, the restrictions are irreversible and inherited by every child process. There&#x27;s no API to loosen them from inside, including for Nono itself. If the agent is instructed by a hostile page to exfiltrate my SSH keys, it can try, but the attempt is blocked at the kernel level before any connection is made. Nono is maintained by Luke Hinds, who also created Sigstore, so the provenance on the sandbox itself is reassuring.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t mention Nono as a product pitch. I mention it because the threat model is real, it is named, and I would rather run a browsing agent inside a kernel-enforced capability sandbox than trust the LLM to follow my instructions under adversarial conditions. The lethal trifecta is a concrete list of capabilities; if your agent has all three, it is worth taking a beat to think about what happens when the untrusted content in the middle position starts fighting back.&lt;&#x2F;p&gt;
&lt;p&gt;Anyway, back to the regularly scheduled programming.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ok-but-does-it-work&quot;&gt;OK, but does it work?&lt;&#x2F;h2&gt;
&lt;p&gt;I ran the same 52-question set through Gemini Deep Research as a sanity check before I started work on the fourth attempt. Gemini Deep Research is a reasonable state-of-the-art benchmark for AI-assisted research (it&#x27;s the product that Google points you at if you ask for &quot;do some research on topic X and produce a report.&quot;) I fed it the full 52 questions and the same registry context I was giving my own system, and compared the outputs.&lt;&#x2F;p&gt;
&lt;p&gt;The results were instructive. Gemini hallucinated questions that weren&#x27;t on the scorecard. It produced sections that were off-topic for the questions it did answer. Some answers were wrong in ways that were hard to miss; others were wrong in ways I only noticed because I happened to know the answer. And it disagreed with itself on reruns. Its run-to-run drift was roughly 20 percent, so about one question in five would change its answer between runs, or not get answered at all. This gave me a concrete target, and my 7 to 10% drift was a clear improvement on that benchmark.&lt;&#x2F;p&gt;
&lt;p&gt;But the drift rate isn&#x27;t really the headline. The headline is that I know &lt;em&gt;which&lt;&#x2F;em&gt; questions drift. The four-to-five-questions-per-run figure isn&#x27;t a diffuse uncertainty spread over the whole scorecard; it&#x27;s a concentrated uncertainty in a specific subset of questions, which is simple to enumerate. My review is targeted rather than distrustful. I get to trust most of questions and spend my time examining the handful that actually need it.&lt;&#x2F;p&gt;
&lt;p&gt;Concretely: what used to take a day and a half of careful reading now takes about an hour of agent time (plus the compute cost, which is genuinely negligible at this scale) and two to three hours of human review. That&#x27;s a 3× to 5× speedup on the part of the work that &lt;em&gt;can&lt;&#x2F;em&gt; be accelerated, and meaningful ecosystem coverage that would otherwise require headcount I don&#x27;t have.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;research-assistant-not-leader&quot;&gt;Research assistant, not leader&lt;&#x2F;h2&gt;
&lt;p&gt;I want to be honest about what this system is and isn&#x27;t.&lt;&#x2F;p&gt;
&lt;p&gt;It is a research &lt;em&gt;assistant&lt;&#x2F;em&gt;. It has meaningfully accelerated my ability to produce assessments across an ecosystem that would otherwise require either much more time or much more labour. It is &lt;em&gt;not a replacement for human judgement&lt;&#x2F;em&gt;, and given the current state of the art, I don&#x27;t believe it can be. The questions where sources contradict one another and someone has to decide which to trust; where you need to understand that a registry was acquired by a company with a different security culture and factor that into how you read their documentation; where a new threat has emerged that isn&#x27;t on the 52-question list yet… That all still requires a human who understands the domain, has read the security community&#x27;s work on similar registries, and can integrate signals that aren&#x27;t in any web-accessible document.&lt;&#x2F;p&gt;
&lt;p&gt;The split that actually works, after four attempts at getting it right, is this: the agent handles the grind, but the hard calls remain mine.&lt;&#x2F;p&gt;
&lt;p&gt;I think that&#x27;s fine. &quot;Research assistant, not leader&quot; is an honest description of what AI tooling can do well in a domain that requires nuanced judgement. The temptation to overclaim—to pretend the agent is doing the research rather than accelerating the parts of research that benefit from being done at scale—is real, and the corrective is a small dose of deflation. This thing doesn&#x27;t do my job. It makes me faster at the parts of my job that can be made faster, and it captures my slow-and-careful work in a form that speeds up the next round. That&#x27;s enough.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-what-generalises&quot;&gt;Closing: what generalises&lt;&#x2F;h2&gt;
&lt;p&gt;While the outcome is specific, the lessons aren&#x27;t. They are, I hope, useful if you are building any kind of research or evaluation agent—or more generally, any system where an LLM has to produce answers a human will rely on.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Mechanical failures and quality failures look similar from the outside but have entirely different causes.&lt;&#x2F;strong&gt; Separate them early, because the toolkits are different and the techniques don&#x27;t transfer. A hung process wants a retry; a confabulation wants a prompt rule. If you&#x27;re shipping more schema validation to fix confabulations, you are doing the wrong thing.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Tools have defaults.&lt;&#x2F;strong&gt; Choose them by their instincts, not by their spec sheets. The same model can behave very differently in different harnesses, and if your harness&#x27;s default instinct is fighting your problem you will spend most of your energy fighting the harness. Pick the one that matches your problem&#x27;s shape.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Operational and behavioural instructions are different jobs.&lt;&#x2F;strong&gt; Write them separately. Procedural rules want to be simple and unambiguous (&quot;use &lt;code&gt;jq&lt;&#x2F;code&gt;, don&#x27;t parse JSON yourself&quot;); behavioural rules want the kind of precision that comes from reviewing failures (&quot;a quote must be content from the source, not a description of your search process&quot;). If your prompt feels bloated, it may be because the two kinds of rule are tangled together and neither is doing its job well.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Observability is not optional for agents.&lt;&#x2F;strong&gt; A structured runtime file (every search, every URL, every candidate quote, every decision) is not paranoia and it is not for debugging after the fact. It is the raw material you use to understand what the model actually does, which is what turns prompt refinement from guesswork into iteration. If you can&#x27;t see what the agent did, you can&#x27;t tell it to do better.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Non-determinism is both antagonist and tool.&lt;&#x2F;strong&gt; Crush it where you need reproducibility: structured outputs, deterministic tools, runtime logs you can replay. Weaponise it where you need creativity: ask the same question three different ways, sample more phrasings than you think you need, let the model&#x27;s tendency to riff work for you. Both at once, applied to different layers of the same system.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;The best human-in-the-loop designs capture the human&#x27;s work as durable input to the next run.&lt;&#x2F;strong&gt; If your system relies on a human to resolve the cases the agent can&#x27;t handle, the cost of that human&#x27;s work should decrease over time as the system learns which kinds of cases it can&#x27;t handle and pre-routes them. A system that makes you re-resolve the same problem on every run is a worse system than one that gets out of your way as you teach it.&lt;&#x2F;p&gt;
&lt;p&gt;I came to this project expecting to build something clever and instead learnt several old engineering lessons by running straight into them. While few of the lessons were genuinely new, all of them were surprising, in context, because LLMs are new enough that we haven&#x27;t yet mapped our existing engineering intuitions onto them correctly. You cannot code your way out of a quality problem. You cannot make a non-deterministic system deterministic by putting schemas around it. Observability beats sophistication. Small sharp tools beat frameworks. Write a runtime log. Measure twice, cut once.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;h2 id=&quot;notes&quot;&gt;Notes&lt;&#x2F;h2&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;sonatype&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;1&lt;&#x2F;sup&gt;
&lt;p&gt;Sonatype, &lt;em&gt;10th Annual State of the Software Supply Chain Report&lt;&#x2F;em&gt;, 2024. https:&#x2F;&#x2F;www.sonatype.com&#x2F;state-of-the-software-supply-chain&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;slsa&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;2&lt;&#x2F;sup&gt;
&lt;p&gt;&lt;em&gt;Supply-chain Levels for Software Artifacts&lt;&#x2F;em&gt; (SLSA), v1.2. https:&#x2F;&#x2F;slsa.dev. &quot;SLSA is a set of incrementally adoptable guidelines for supply chain security, established by industry consensus.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;sigstore&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;3&lt;&#x2F;sup&gt;
&lt;p&gt;The Sigstore project. https:&#x2F;&#x2F;docs.sigstore.dev&#x2F;about&#x2F;overview&#x2F;. An OpenSSF-hosted project for signing and verifying software artefacts.&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;openssfurl&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;4&lt;&#x2F;sup&gt;
&lt;p&gt;OpenSSF Scorecard. https:&#x2F;&#x2F;github.com&#x2F;ossf&#x2F;scorecard&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;farquhar&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;5&lt;&#x2F;sup&gt;
&lt;p&gt;Sebastian Farquhar, Jannik Kossen, Lorenz Kuhn, and Yarin Gal, &quot;Detecting hallucinations in large language models using semantic entropy,&quot; &lt;em&gt;Nature&lt;&#x2F;em&gt; 630, 19 June 2024. https:&#x2F;&#x2F;www.nature.com&#x2F;articles&#x2F;s41586-024-07421-0. &quot;We develop entropy-based uncertainty estimators for LLMs to detect a subset of hallucinations — confabulations — which are arbitrary and incorrect generations.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;kalai&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;6&lt;&#x2F;sup&gt;
&lt;p&gt;Adam Tauman Kalai, Ofir Nachum, Santosh S. Vempala, and Edwin Zhang (OpenAI), &quot;Why Language Models Hallucinate,&quot; arXiv:2509.04664, 4 September 2025. https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;2509.04664&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;hicks&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;7&lt;&#x2F;sup&gt;
&lt;p&gt;Michael Townsen Hicks, James Humphries, and Joe Slater, &quot;ChatGPT is bullshit,&quot; &lt;em&gt;Ethics and Information Technology&lt;&#x2F;em&gt; 26:38, 8 June 2024. https:&#x2F;&#x2F;link.springer.com&#x2F;article&#x2F;10.1007&#x2F;s10676-024-09775-5. &quot;The falsehoods and overall activity of large language models is better understood as bullshit in the sense explored by Frankfurt... the models are in an important way indifferent to the truth of their outputs.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;frankfurt&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;8&lt;&#x2F;sup&gt;
&lt;p&gt;Harry G. Frankfurt, &lt;em&gt;On Bullshit&lt;&#x2F;em&gt; (Princeton University Press, 2005; originally a 1986 essay). &quot;He does not care whether the things he says describe reality correctly. He just picks them out, or makes them up, to suit his purpose.&quot;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;huyen&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;9&lt;&#x2F;sup&gt;
&lt;p&gt;Chip Huyen, &quot;Data Distribution Shifts and Monitoring,&quot; 7 February 2022. https:&#x2F;&#x2F;huyenchip.com&#x2F;2022&#x2F;02&#x2F;07&#x2F;data-distribution-shifts-and-monitoring.html&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;husainshankar&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;10&lt;&#x2F;sup&gt;
&lt;p&gt;Hamel Husain and Shreya Shankar, &quot;LLM Evals: Everything You Need to Know,&quot; January 2026. https:&#x2F;&#x2F;hamel.dev&#x2F;blog&#x2F;posts&#x2F;evals-faq&#x2F;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;yan&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;11&lt;&#x2F;sup&gt;
&lt;p&gt;Eugene Yan, &quot;An LLM-as-Judge Won&#x27;t Save The Product — Fixing Your Process Will,&quot; April 2025. https:&#x2F;&#x2F;eugeneyan.com&#x2F;writing&#x2F;eval-process&#x2F;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;harness&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;12&lt;&#x2F;sup&gt;
&lt;p&gt;HumanLayer, &quot;Skill Issue: Harness Engineering for Coding Agents,&quot; March 2026. https:&#x2F;&#x2F;www.humanlayer.dev&#x2F;blog&#x2F;skill-issue-harness-engineering-for-coding-agents&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;anthropicagents&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;13&lt;&#x2F;sup&gt;
&lt;p&gt;Erik Schluntz and Barry Zhang, &quot;Building effective agents,&quot; Anthropic Engineering, 19 December 2024. https:&#x2F;&#x2F;www.anthropic.com&#x2F;engineering&#x2F;building-effective-agents&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;willisondef&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;14&lt;&#x2F;sup&gt;
&lt;p&gt;Simon Willison, &quot;I think &#x27;agent&#x27; may finally have a widely enough agreed upon definition to be useful jargon now,&quot; 18 September 2025. https:&#x2F;&#x2F;simonw.substack.com&#x2F;p&#x2F;i-think-agent-may-finally-have-a&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;he&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;15&lt;&#x2F;sup&gt;
&lt;p&gt;Horace He et al. (Thinking Machines Lab), &quot;Defeating Nondeterminism in LLM Inference,&quot; 10 September 2025. https:&#x2F;&#x2F;thinkingmachines.ai&#x2F;blog&#x2F;defeating-nondeterminism-in-llm-inference&#x2F;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;hyde&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;16&lt;&#x2F;sup&gt;
&lt;p&gt;Luyu Gao, Xueguang Ma, Jimmy Lin, and Jamie Callan, &quot;Precise Zero-Shot Dense Retrieval without Relevance Labels&quot; (HyDE), arXiv:2212.10496, 2022. https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;2212.10496&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;shankar&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;17&lt;&#x2F;sup&gt;
&lt;p&gt;Shreya Shankar, J.D. Zamfirescu-Pereira, Björn Hartmann, Aditya G. Parameswaran, and Ian Arawjo, &quot;Who Validates the Validators? Aligning LLM-Assisted Evaluation of LLM Outputs with Human Preferences,&quot; UIST 2024 &#x2F; arXiv:2404.12272. https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;2404.12272&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;altman&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;18&lt;&#x2F;sup&gt;
&lt;p&gt;Douglas G. Altman and J. Martin Bland, &quot;Absence of evidence is not evidence of absence,&quot; &lt;em&gt;BMJ&lt;&#x2F;em&gt; 311:485, 19 August 1995. https:&#x2F;&#x2F;www.bmj.com&#x2F;content&#x2F;311&#x2F;7003&#x2F;485&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;willisontrifecta&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;19&lt;&#x2F;sup&gt;
&lt;p&gt;Simon Willison, &quot;The lethal trifecta for AI agents: private data, untrusted content, and external communication,&quot; 16 June 2025. https:&#x2F;&#x2F;simonwillison.net&#x2F;2025&#x2F;Jun&#x2F;16&#x2F;the-lethal-trifecta&#x2F;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;greshake&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;20&lt;&#x2F;sup&gt;
&lt;p&gt;Kai Greshake, Sahar Abdelnabi, Shailesh Mishra, Christoph Endres, Thorsten Holz, and Mario Fritz, &quot;Not what you&#x27;ve signed up for: Compromising Real-World LLM-Integrated Applications with Indirect Prompt Injection,&quot; arXiv:2302.12173, February 2023. https:&#x2F;&#x2F;arxiv.org&#x2F;abs&#x2F;2302.12173&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;comet&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;21&lt;&#x2F;sup&gt;
&lt;p&gt;Artem Chaikin and Shivan Kaul Sahib, &quot;Agentic Browser Security: Indirect Prompt Injection in Perplexity Comet,&quot; Brave Blog, 20 August 2025. https:&#x2F;&#x2F;brave.com&#x2F;blog&#x2F;comet-prompt-injection&#x2F;&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;footnote-definition&quot; id=&quot;nono&quot;&gt;&lt;sup class=&quot;footnote-definition-label&quot;&gt;22&lt;&#x2F;sup&gt;
&lt;p&gt;Nono sandbox. https:&#x2F;&#x2F;github.com&#x2F;always-further&#x2F;nono. Capability-based sandbox using Landlock (Linux) and Seatbelt (macOS).&lt;&#x2F;p&gt;
&lt;&#x2F;div&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Easily keep your local git repo up to date</title>
        <published>2024-07-12T00:00:00+00:00</published>
        <updated>2024-07-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/easily-keep-you-local-git-repo-up-to-date/"/>
        <id>https://blog.dark.ca/posts/easily-keep-you-local-git-repo-up-to-date/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/easily-keep-you-local-git-repo-up-to-date/">&lt;p&gt;&lt;em&gt;(This post originally appeared on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;dev.to&#x2F;phrawzty&#x2F;easily-keep-your-local-git-repo-up-to-date-l52&quot;&gt;dev.to&lt;&#x2F;a&gt;)&lt;&#x2F;em&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Here&#x27;s how to keep your clone of a Git repository current with upstream quickly and efficiently. Just pop this snippet into the &lt;code&gt;.git&#x2F;config&lt;&#x2F;code&gt; of your local checkout and you&#x27;re good to go (some assembly required).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;remote &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;upstream&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    url&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;http ur&lt;&#x2F;span&gt;&lt;span&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    fetch&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = +refs&#x2F;heads&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:refs&#x2F;remotes&#x2F;upstream&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;alias&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    refresh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;!git checkout main &amp;amp;&amp;amp; git fetch upstream &amp;amp;&amp;amp; git merge upstream&#x2F;main main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Run &lt;code&gt;git refresh&lt;&#x2F;code&gt; before you branch locally, and just like magic, you&#x27;ll avoid merge conflicts and other irritating side effects. It&#x27;s a bit dirty, but it&#x27;ll do the job in most cases. 😉&lt;&#x2F;p&gt;
&lt;p&gt;Want to know more about what&#x27;s going on here? Great!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;First: &lt;em&gt;why?&lt;&#x2F;em&gt; A few of the open source projects I work on have very active repositories, and since they all favour trunk-based development, that means &lt;code&gt;main&lt;&#x2F;code&gt; gets updated frequently. Furthermore, they all prefer pull requests to be proposed from clones, as humans don&#x27;t touch the primary repository directly.&lt;&#x2F;p&gt;
&lt;p&gt;This is a really common model, so nothing special; however I &lt;em&gt;always&lt;&#x2F;em&gt; forgot to rebase before branching, except when I didn&#x27;t forget to rebase, because I&#x27;d forgotten &lt;em&gt;how&lt;&#x2F;em&gt; to rebase. (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;jvns.ca&#x2F;blog&#x2F;2024&#x2F;01&#x2F;26&#x2F;inside-git&#x2F;&quot;&gt;Git is fun!&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;So instead of having to do a little dance every time, I figured: 💭 &lt;em&gt;let the computer do the work&lt;&#x2F;em&gt;. And while incantations are great, I&#x27;m cranky enough to want to know what it is the computer is doing on my behalf, so let&#x27;s break it down:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;remote &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;upstream&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    url&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;http ur&lt;&#x2F;span&gt;&lt;span&gt;l&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    fetch&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = +refs&#x2F;heads&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:refs&#x2F;remotes&#x2F;upstream&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;[remote]&lt;&#x2F;code&gt; block defines a &lt;em&gt;remote&lt;&#x2F;em&gt; repository, i.e. a repo that isn&#x27;t on your computer. Here I&#x27;ve given it an arbitrary name (&lt;code&gt;upstream&lt;&#x2F;code&gt;). Arbitrary because it&#x27;s only used in &lt;em&gt;this&lt;&#x2F;em&gt; configuration context, so go with your heart on this one.&lt;&#x2F;p&gt;
&lt;p&gt;Inside that block there&#x27;s &lt;code&gt;url = &amp;lt;http url&amp;gt;&lt;&#x2F;code&gt;, which—you guessed it—defines the URL where the remote repository lives. This could be a link to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&#x2F;&quot;&gt;Codeberg&lt;&#x2F;a&gt;, GitHub, GitLab, or whatever y&#x27;all got going on.&lt;&#x2F;p&gt;
&lt;p&gt;Next is &lt;code&gt;fetch&lt;&#x2F;code&gt;, which literally tells git how to &lt;em&gt;fetch&lt;&#x2F;em&gt; updates from that remote repository. That&#x27;s the easy part. What do those other bits mean?&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;+&lt;&#x2F;code&gt; tells git to &quot;force&quot; update the references. If you&#x27;re familiar with Git, this means forcing the references even if the result is a non-fast-forward update. Remember at the top of the post when I said &quot;It&#x27;s a bit dirty&quot;? This is what I&#x27;m talking about. But here&#x27;s the thing: it&#x27;s &lt;em&gt;probably&lt;&#x2F;em&gt; what you want anyway. 😇&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;refs&#x2F;heads&#x2F;*&lt;&#x2F;code&gt; part just tells git to get all the branches from the remote repo. Again: it&#x27;s &lt;em&gt;probably&lt;&#x2F;em&gt; what you want.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, &lt;code&gt;:refs&#x2F;remotes&#x2F;upstream&#x2F;*&lt;&#x2F;code&gt; specifies where those fetched branches are going to be stored locally. There&#x27;s a whole different blog post to be written about &lt;em&gt;just this&lt;&#x2F;em&gt;, but the tl;dr is we want to keep the upstream branches separate from the local branches, because things get crazy graph-theory style if we don&#x27;t. 😝&lt;&#x2F;p&gt;
&lt;p&gt;OK, now the part you&#x27;ve all been waiting for: the &lt;em&gt;actual command&lt;&#x2F;em&gt;!&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;alias&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    refresh&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;!git checkout main &amp;amp;&amp;amp; git fetch upstream &amp;amp;&amp;amp; git merge upstream&#x2F;main main&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;[alias]&lt;&#x2F;code&gt; block defines, well, an alias. It&#x27;s basically a shortcut that lets us run arbitrary commands or sequences (including, notably, shell commands) so that we don&#x27;t have to write them out by hand each time. In this case, the alias is &lt;code&gt;refresh&lt;&#x2F;code&gt;; the idea here being that we can type &lt;code&gt;git refresh&lt;&#x2F;code&gt; on the shell and it &lt;em&gt;runs the command sequence&lt;&#x2F;em&gt;, thus simplifying our lives somewhat. And some is better than none.&lt;&#x2F;p&gt;
&lt;p&gt;Also: remember at the top of the post when I said &quot;It&#x27;s a bit dirty&quot;? This shell command is &lt;em&gt;actually&lt;&#x2F;em&gt; what I&#x27;m talking about. 🥸 Let&#x27;s be legends…&lt;&#x2F;p&gt;
&lt;p&gt;The &lt;code&gt;!&lt;&#x2F;code&gt; right at the start of the sequence tells git to treat the whole thing as a shell command, so whatever comes next will just be executed like we typed it out.&lt;&#x2F;p&gt;
&lt;p&gt;First we make sure that we&#x27;re on the &lt;code&gt;main&lt;&#x2F;code&gt; branch in our local repo by running &lt;code&gt;git checkout main&lt;&#x2F;code&gt;. It&#x27;s possible that your repo uses a different name for trunk (&quot;master&quot; was popular for a long time), but &quot;main&quot; is common.&lt;&#x2F;p&gt;
&lt;p&gt;Then we &lt;code&gt;git fetch upstream&lt;&#x2F;code&gt; to nab that fresh upstream data from the remote repository. Remember &lt;code&gt;upstream&lt;&#x2F;code&gt;? It&#x27;s the remote repository we defined previously. Ah what fun we had.&lt;&#x2F;p&gt;
&lt;p&gt;Finally, we &lt;em&gt;merge&lt;&#x2F;em&gt; the changes from the &lt;code&gt;main&lt;&#x2F;code&gt; branch of &lt;code&gt;upstream&lt;&#x2F;code&gt; into the &lt;code&gt;main&lt;&#x2F;code&gt; branch of our local repository. That&#x27;s literally how to read &lt;code&gt;git merge upstream&#x2F;main main&lt;&#x2F;code&gt;. 🧠&lt;&#x2F;p&gt;
&lt;p&gt;And that&#x27;s it! A couple of lines gets us a quick, reusable, fairly reliable method of keeping our local repo up to date.&lt;&#x2F;p&gt;
&lt;p&gt;Hope that helps! Let me know!&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;BONUS: You might also be wondering what those &lt;code&gt;&amp;amp;&amp;amp;&lt;&#x2F;code&gt; are for in between each of the commands. The Very Correct Definition is that &lt;code&gt;&amp;amp;&amp;amp;&lt;&#x2F;code&gt; is a &quot;logical AND operator&quot;. What it&#x27;s used for in this case is a way to chain a series of shell commands into a sequence, whereby the &lt;em&gt;next&lt;&#x2F;em&gt; command will only be called if the &lt;em&gt;current&lt;&#x2F;em&gt; one was successful. This way, we don&#x27;t end up doing horrible things to our local repo &lt;del&gt;if&lt;&#x2F;del&gt; when things go wrong.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Presentations and videos</title>
        <published>2020-11-17T00:00:00+00:00</published>
        <updated>2020-11-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/presentations-and-videos/"/>
        <id>https://blog.dark.ca/posts/presentations-and-videos/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/presentations-and-videos/">&lt;p&gt;Hi there! I&#x27;m Dan. Over the past few years I&#x27;ve done a fair number of presentations, talks, panels, and other appearances at technical conferences and shows. You can check out the complete list of content—including videos, slide decks, and links to additional resources where available—at &lt;strong&gt;https:&#x2F;&#x2F;speaking.dark.ca&#x2F;&lt;&#x2F;strong&gt; .&lt;&#x2F;p&gt;
&lt;p&gt;Thanks, and as always, please enjoy responsibly!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Observability as code: dashboards</title>
        <published>2020-09-10T00:00:00+00:00</published>
        <updated>2020-09-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/observability-as-code-dashboards/"/>
        <id>https://blog.dark.ca/posts/observability-as-code-dashboards/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/observability-as-code-dashboards/">&lt;p&gt;I recently received a really great question from a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;datadoghq.com&quot;&gt;Datadog&lt;&#x2F;a&gt; customer that I&#x27;d like to share concerning Observability as Code—specifically managing dashboards via &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.terraform.io&#x2F;&quot;&gt;Terraform&lt;&#x2F;a&gt; in this case, but the question and answer apply more broadly.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;While we use Terraform for 100% of our Datadog monitors, we&#x27;ve found [that] developers are less likely to update dashboards when they see a mistake in the UI, because they need to open a branch, run a pipeline and merge it in. This is a lot of overhead for a quick dashboard fix. Do you have any thoughts on this?&lt;&#x2F;p&gt;
&lt;p&gt;SRE Team Lead&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;First, the standard disclaimer: There’s no one true way to do anything, and every recommendation or “best practice” out there needs to be weighed against the reality of the environment and organisation that you’re a part of. :)&lt;&#x2F;p&gt;
&lt;p&gt;That said, there are a few ways to look at this. If you’re part of a small shop with only a handful of resources, then it might be entirely reasonable to manage everything by hand—not just the dashboards. Scale, therefore, is a big part of the equation—and that notion extends to both computers and people. If you’re part of a small team that works either in isolation, or on things which are so specific as to be unusable to others, then here again, it’s entirely reasonable to manage those dashboards by hand. Still, even here one could make an argument for treating them as code: it’s self-documenting (for values of documentation), and it serves as a backup mechanism for when one of those manual edits inevitably goes awry.&lt;&#x2F;p&gt;
&lt;p&gt;As scale increases, so does the value of managing the dashboards as code. A prime example is repeatability. Many organisations end up deploying multiple iterations of very similar stacks. Creating the dashboards for these stacks by hand becomes tiresome very quickly. Furthermore, as the stack itself changes, having to go through each dashboard set to update them can be a nightmare (not to mention making sure that future stacks get the correct dashboard updates as well).&lt;&#x2F;p&gt;
&lt;p&gt;Some organisations may have more tightly controlled environments than others, and traceability for modifications is important. Even in environments that aren’t particularly controlled, there may be a healthy peer review culture that, far from being a burden, is a huge asset in ensuring that even small changes have more than one set of eyes in order to ensure completeness and suitability. In these cases, having tight feedback loops and rapid CI&#x2F;CD mechanisms is paramount—if engineers feel like they’re fighting heavyweight tooling for “small changes”, then that’s a problem that should be addressed beyond the issue of dashboards specifically.&lt;&#x2F;p&gt;
&lt;p&gt;If you want to learn more about Datadog, Hashicorp Terraform, and Observability as Code, I invite you to check out our &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.datadoghq.com&#x2F;partner&#x2F;hashicorpwebinaremea&#x2F;&quot;&gt;upcoming joint webinar&lt;&#x2F;a&gt; on the topic on 23 September at 12:00 UTC. Hope to see you there!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Devopsdays Berlin 2018; recap</title>
        <published>2018-09-18T00:00:00+00:00</published>
        <updated>2018-09-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/devopsdays-berlin-2018-recap/"/>
        <id>https://blog.dark.ca/posts/devopsdays-berlin-2018-recap/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/devopsdays-berlin-2018-recap/">&lt;p&gt;The sixth edition of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.devopsdays.org&#x2F;events&#x2F;2018-berlin&#x2F;welcome&#x2F;&quot;&gt;DevOpsDays Berlin&lt;&#x2F;a&gt; was held over the 12th and 13th of September 2018, and despite the fact that it&#x27;s one of the most consistent, longest-running Devopsdays events on the calendar, this year was my &lt;em&gt;first ever&lt;&#x2F;em&gt; opportunity to attend. The tl;dr is that this was a very fine event, and the local organising team clearly has their act together (though they are &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.devopsdays.org&#x2F;events&#x2F;2018-berlin&#x2F;contact&#x2F;&quot;&gt;actively recruiting&lt;&#x2F;a&gt; for new volunteers).
The talks were not recorded, so for the benefit of those who couldn&#x27;t make it, I&#x27;ve refined my notes from the talks on Day 2 (unfortunately I had to miss Day 1).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;dirk-on-trust&quot;&gt;Dirk, on trust&lt;&#x2F;h3&gt;
&lt;p&gt;The day started with a presentation from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;doergn&quot;&gt;Dirk Lehmann&lt;&#x2F;a&gt; of SAP entitled &quot;Trust as Foundation of DevOps&quot;. Dirk has been a DevOps practitioner and booster for years, and I&#x27;ve had the pleasure of seeing him speak a handful of times before - as usual, he didn&#x27;t disappoint. The central thesis of this talk is right there in the title: that trust, that fickle, difficult, human emotional thing, is the fundamental element of DevOps. He proposed a few ways to think about trust beyond a philosophical concept, and introduced a way of measuring the level of trust within an organisation: by measuring &lt;em&gt;speed&lt;&#x2F;em&gt;. Fast decision making, execution, and turnaround are hallmarks of a trust-based organisation. In terms of fostering a trusting environment, he proposed three key elements: managing team size, cultivating diversity, and embracing &quot;positive failure culture&quot;.
Regarding team size, he looked to the seminal Mythical Man Month, as well as the work of evolutionary psychologist Robin Dunbar (see: Dunbar&#x27;s Number). Dirk&#x27;s conclusion? 15 people is the largest a team can get before it it breaks - and often it should be smaller. Concerning diversity, the take-away was that teams should organise around projects, products, or goals, instead of the traditional &quot;business unit&quot; (or work-type silos) that have been commonplace for much of the post-industrial era. Finally, citing Google&#x27;s research that investing in psychological safety - more than anything else - was critical to making a team work, Dirk argued that embracing failure as a learning experience is paramount.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;yuwei-on-mentoring&quot;&gt;Yuwei, on mentoring&lt;&#x2F;h3&gt;
&lt;p&gt;The next talk was by &lt;a href=&quot;mailto:yuwei.ren@facebook.com&quot;&gt;Yuwei Ren&lt;&#x2F;a&gt;, a Production Engineer at Facebook, entitled &quot;Mentorship: From the receiving end&quot;. Despite the title, most of her talk was about mentorship from the perspective of the mentor, and it was chock full of good tips for anybody engaging in a mentoring relationship.
For example, as a mentor, how do you get off to a good start with your mentee? Start by establishing career goals, and then ask &quot;How can I help get you there?&quot;. Ensure that the expectations are set, and that outcomes are clearly defined by both parties. This is done by establishing a plan to achieve those goals, and setting up milestones along the way. During the process, schedule regular check-ins, and stick to them! Set the bar high, and along with those lofty expectations, make sure that both parties are accountable to each other. The mentor&#x2F;mentee relationship is a big responsibility, and it must be treated with respect and commitment.
Both parties must acknowledge that disagreements and misunderstanding are inevitable, so &lt;em&gt;empathy&lt;&#x2F;em&gt; is key. Assuming good intentions is important, but that&#x27;s only the first part of the equation - both parties need to actively listen and respect each other both professionally and as human beings. Finally, the mentee needs to take responsibility for their career, actively seeking and providing feedback, and acting on the advice of the mentor.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ken-on-devops-transformations&quot;&gt;Ken, on DevOps transformations&lt;&#x2F;h3&gt;
&lt;p&gt;Next up was &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;kmugrage&quot;&gt;Ken Mugrage&lt;&#x2F;a&gt; of Thoughtworks (and fellow member of the DevOpsDays global core) with a talk entitled &quot;Want to successfully adopt DevOps? Change Everything&quot;. His talk was &lt;em&gt;very dense&lt;&#x2F;em&gt;, and to be honest I didn&#x27;t quite capture all of it. His four key points to successful DevOps adoption were: redefine words, change your organisation, change your architecture, and use CD to &lt;em&gt;safely&lt;&#x2F;em&gt; deploy more often.
Within a team specifically, and an organisation in general, agreeing on specific definitions is critical. In terms of defining the word DevOps, Ken argued that DevOps should not define a toolset, nor a role, nor a team. Instead, DevOps is &lt;em&gt;verbs&lt;&#x2F;em&gt;: developING and operatING. If you need a noun, why not CAMS or CALMS (upon which much has &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;duckduckgo.com&#x2F;?q=cams+or+calms+in+devops&quot;&gt;been written&lt;&#x2F;a&gt; before). Ken then offered his interesting description of DevOps:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;A culture where people, regardless of title or background, work together to imagine, develop, deploy, and operate a system.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Words are important, but action is critical, and the best way to implement CA(L)MS is to change how your organisation is, well, organised. Ken invoked &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Conway%27s_law&quot;&gt;Conway&#x27;s Law&lt;&#x2F;a&gt; and by way of illustration, explained how just renaming the Ops Team to DevOps team isn&#x27;t going to help (nor is any other action that just leaves silos in place). Teams need to be organised differently, which means that the whole organisation might need to be organised differently as well. Furthermore, the success of those teams must be measured by how they deliver &lt;em&gt;business value&lt;&#x2F;em&gt; (not just whether their software functions or not).
Ken then moved into continuous delivery versus continuous deployment, and this is where things got fuzzy for me.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;sponsors&quot;&gt;Sponsors!&lt;&#x2F;h3&gt;
&lt;p&gt;Three sponsors had an opportunity to say a few words on stage: &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.chef.io&#x2F;&quot;&gt;Chef&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;cloud.google.com&#x2F;&quot;&gt;Google Cloud&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.quest.com&#x2F;&quot;&gt;Quest&lt;&#x2F;a&gt;. I mention this because it&#x27;s important to acknowledge the important role that sponsors play in the DevOpsDays series - without them, the events simply wouldn&#x27;t be able to happen. Thanks, sponsors!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;tiago-on-microsoft&quot;&gt;Tiago, on Microsoft&lt;&#x2F;h3&gt;
&lt;p&gt;The final full presentation of the day was from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;tipascoamsft&quot;&gt;Tiago Pascoal&lt;&#x2F;a&gt; from the Azure DevOps Customer Advisory Team, speaking about how a unit within the Microsoft empire experienced its own DevOps transformation. This one started slow, but once Tiago got going, it ended up being &lt;em&gt;very&lt;&#x2F;em&gt; interesting - so I&#x27;ll skip right to the good stuff.
Within the Azure DevOps unit, teams are assembled into 10 to 12 person groups, the composition of which is heterogeneous and organised around products (see: Dirk&#x27;s argument above). These teams are &lt;em&gt;self-forming&lt;&#x2F;em&gt;, so everybody decides which team and&#x2F;or manager they want to work with. Apparently, while 100% of the group gets a choice, typically less than 20% choose to change from their existing situation. (To me, this is &lt;em&gt;wild&lt;&#x2F;em&gt;, and I&#x27;d be very interested to try something like this out at some point in my career.)
Tiago invoked Daniel Pink&#x27;s popular book Drive, noting that need teams 3 things: autonomy, mastery, and purpose. He added another layer, which he referred to as &quot;Alignment vs Autonomy&quot;. Autonomy is everything related to planning and execution,  whereas alignment is the organisation, the team structure, and most importantly, the &lt;em&gt;cadence&lt;&#x2F;em&gt; of work. For example, they work in 3-week sprints, and at the end of the sprint, whatever is in the master branch gets deployed - so be ready.
At an organisational level they track metrics; but NOT the classics like burndown, velocity, original estimate, completed hours, team capacity, or number of bugs found. Individual teams can track those if they wish, but at a high level there&#x27;s only one metric that matters: impact. Are they delivering value? Speaking of measuring, in terms of code quality, Tiago explained the &quot;Bug Cap&quot;: &lt;code&gt;n * 5 = x&lt;&#x2F;code&gt; where &lt;code&gt;n&lt;&#x2F;code&gt; is # of engineers, and &lt;code&gt;x&lt;&#x2F;code&gt; is maximum bug limit. If the bug count exceeds the bug cap at any time, the team &lt;em&gt;stops&lt;&#x2F;em&gt; working on new features and moves immediately to stabilise. Neat!&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ignites&quot;&gt;Ignites&lt;&#x2F;h3&gt;
&lt;p&gt;After lunch, it was time for everybody&#x27;s favourite DevOpsDays tradition: the &lt;strong&gt;ignites&lt;&#x2F;strong&gt;! I was preparing for my own ignite so I missed the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.devopsdays.org&#x2F;events&#x2F;2018-berlin&#x2F;program&#x2F;suresh-chandra-bose&#x2F;&quot;&gt;first one&lt;&#x2F;a&gt; (sorry).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;daiany-on-relaxing-at-speed&quot;&gt;Daiany, on relaxing at speed&lt;&#x2F;h3&gt;
&lt;p&gt;This was an excellently-delivered lightning that told the (true?) story of two teams and their relative stress levels heading into the GDPR cut-off date. It was fun, light-hearted, and carried a strong message: when you&#x27;re doing the DevOps at high velocities, even massive EU legislation can&#x27;t stress you out! Well done, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;DaianyMargarita&quot;&gt;Daiany&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;daniel-on-serverless&quot;&gt;Daniel, on serverless&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;phrawzty&quot;&gt;I&lt;&#x2F;a&gt; did a lightning talk on serverless. It was fun. :)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;thanks&quot;&gt;Thanks!&lt;&#x2F;h3&gt;
&lt;p&gt;First off, thanks to the local DevOpsDays Berlin volunteer group. Also, thanks (again) to the sponsors. Finally, thank-you to my employer, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.datadoghq.com&#x2F;&quot;&gt;Datadog&lt;&#x2F;a&gt;, for sending me out there to speak. There are so many moving parts to make even a small conference happen.
I hope to make it out next year!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>So long, and thanks for all the fish.</title>
        <published>2016-11-15T00:00:00+00:00</published>
        <updated>2016-11-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/so-long-and-thanks-for-all-the-fish/"/>
        <id>https://blog.dark.ca/posts/so-long-and-thanks-for-all-the-fish/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/so-long-and-thanks-for-all-the-fish/">&lt;p&gt;I joined &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mozilla.org&#x2F;&quot;&gt;Mozilla&lt;&#x2F;a&gt; nearly five years ago, which was an interesting period culturally for the company - we were transitioning from being a scrappy, disorganised group of hackers into a proper corporation with a global reach.  One of my first bugs was to audit our load balancers - another was to help fix the tap in the office beer keg.  It was an interesting time, fraught with mistakes, but heady with the promise of opportunity.
For the first few years, I was part of the WebOps team, and as such, got to work with a wide range of projects and people around the world.  Every day was a trial by fire, and while it was often times difficult or frustrating, the lens of hindsight now allows me to understand how valuable it was as a learning experience.
From there, I moved into Services Engineering, and had the opportunity to work on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;crash-stats.mozilla.com&#x2F;&quot;&gt;Crash Stats&lt;&#x2F;a&gt; project - a humbling experience if ever there was.  I was exposed to some brilliant technologists and learned more about &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Zq5lx3bINZQ&quot;&gt;resilient systems design&lt;&#x2F;a&gt; than I ever dreamed possible.  I was also exposed to some great &lt;em&gt;managers&lt;&#x2F;em&gt;, and will remain eternally grateful for the mentorship I received both directly and indirectly.
Finally, I landed with the Cloud Services and Operations teams, and even though I&#x27;d been with the company for a long time, it was like my first days all over again: new and complex systems, new and complex people.
Speaking of people, I&#x27;d be remiss if I didn&#x27;t say this: Mozilla is &lt;em&gt;full&lt;&#x2F;em&gt; of some of the finest human beings I&#x27;ve ever had the honour and pleasure of working with.  The spirit, drive, and desire to &lt;em&gt;do good&lt;&#x2F;em&gt; is something that is more than rare in the Valley (or anywhere), and the importance of this aspect cannot be overstated.
Mozilla has treated me well.  I&#x27;ve travelled the world, honed my skills, and learned so much, both professionally and personally.  It&#x27;s been a wild, interesting, life-changing ride.&lt;&#x2F;p&gt;
&lt;p&gt;Today, more than ever, the Internet needs Mozilla.  Even though my personal journey is taking me in a different direction, the mission and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mozilla.org&#x2F;about&#x2F;manifesto&#x2F;&quot;&gt;manifesto&lt;&#x2F;a&gt; are more important than ever before.  The show &lt;em&gt;must&lt;&#x2F;em&gt; go on.&lt;&#x2F;p&gt;
&lt;p&gt;Much love to all, and thanks for everything.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Genesis: Terraforming a New Home for Firefox Crash Reporter</title>
        <published>2016-03-24T00:00:00+00:00</published>
        <updated>2016-03-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/genesis-terraforming-a-new-home/"/>
        <id>https://blog.dark.ca/posts/genesis-terraforming-a-new-home/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/genesis-terraforming-a-new-home/">&lt;p&gt;Last year, my esteemed colleague &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jdotp&quot;&gt;JP Schneider&lt;&#x2F;a&gt; and I were invited to keynote at a couple of conferences last year. We gave two variations on the same talk, entitled &quot;Genesis: Terraforming a New Home for Firefox Crash Reporter&quot;, at each of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=aNmWv3ZTJNg&quot;&gt;Hashiconf 2015&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=Zq5lx3bINZQ&quot;&gt;Velocity EU 2015&lt;&#x2F;a&gt; respectively.
The blurb for these talks is as follows:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Everyone loves talking about different stacks used in migrating applications to DevOps methodologies, but the most important and valuable change is not a technology stack; instead, it is the human stack.
In this keynote address, we will cover the intersection of technology and humans, and walk the audience through a real life example of the move of Firefox crash reporter. The three engineers tasked with this had to build the plane while it was in the air, all without landing or crashing.
As with many projects, hard deadlines and requirements made the team work through a lot of tough decisions and compromises while simultaneously training devs, product managers, managers, and other engineers in the new world of DevOps and Continuous Delivery.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;The talks were a lot of fun and were well received by both audiences.  We keep things light (including images and quotes from Shakespeare to Mobb Deep) and we keep them honest (both our successes &lt;em&gt;and failures&lt;&#x2F;em&gt;).
The Velocity talk, which at 25 minutes in length is the shorter of the two, is aimed at a more general audience; the Hashiconf talk is longer, and includes a lot more detail about the Hashicorp tools that we used to reach our goals. I hope you enjoy either or both of them. :)&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Handling extant resources in Terraform</title>
        <published>2015-01-27T00:00:00+00:00</published>
        <updated>2015-01-27T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/handling-extant-resources-in-terraform/"/>
        <id>https://blog.dark.ca/posts/handling-extant-resources-in-terraform/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/handling-extant-resources-in-terraform/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.terraform.io&#x2F;&quot;&gt;Terraform&lt;&#x2F;a&gt; is a Hashicorp tool which embraces the Infrastructure as Code model to manage a variety of platforms and services in today&#x27;s modern, cloud-based Internet.  It&#x27;s still in development, but it already provides a wealth of useful functionality, notably with regards to Amazon and Digital Ocean interactions.  The one thing it doesn&#x27;t do, however, is manage &lt;em&gt;pre-existing&lt;&#x2F;em&gt; infrastructure very well.  In this blog post we&#x27;ll explore a way to integrate extant infra into a basic Terraform instance.
Note that this post is current as of Terraform v&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;hashicorp&#x2F;terraform&#x2F;tree&#x2F;v0.3.6&quot;&gt;0.3.6&lt;&#x2F;a&gt;.  Hashicorp has hinted that future versions of Terraform will handle this problem in a more graceful way, so be sure to check those changelogs regularly. :)&lt;&#x2F;p&gt;
&lt;h1 id=&quot;summary&quot;&gt;summary&lt;&#x2F;h1&gt;
&lt;p&gt;A full example and walk-through will follow; however, for those familiar with Terraform and just looking for the tl;dr, I got you covered.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Declare a &lt;em&gt;new, temporary&lt;&#x2F;em&gt; resource in your Terraform plan that is &lt;em&gt;nearly identical&lt;&#x2F;em&gt; to the extant resource.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;Apply&lt;&#x2F;code&gt; the plan, thus instantiating the temporary &quot;twinned&quot; resource and building a state file.&lt;&#x2F;li&gt;
&lt;li&gt;Alter the appropriate &lt;code&gt;id&lt;&#x2F;code&gt; fields to be the &lt;em&gt;same&lt;&#x2F;em&gt; as the extant resource in both the state and config files.&lt;&#x2F;li&gt;
&lt;li&gt;Perform a &lt;code&gt;refresh&lt;&#x2F;code&gt; which will populate the state file with the correct data for the declared extant resource.&lt;&#x2F;li&gt;
&lt;li&gt;Remove the temporary resource from AWS manually.&lt;&#x2F;li&gt;
&lt;li&gt;Voilà.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;faster-and-more-dangerous-please&quot;&gt;faster and more dangerous, please.&lt;&#x2F;h2&gt;
&lt;p&gt;Walking through the process and meticulously checking every step? Ain&#x27;t nobody got time for that!&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Edit the state file and insert the resource directly - it&#x27;s just JSON, after all.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h1 id=&quot;examples&quot;&gt;examples&lt;&#x2F;h1&gt;
&lt;p&gt;In the examples below, the notation &lt;code&gt;[...]&lt;&#x2F;code&gt; is used to indicate truncated output or data.
Also note that the AWS cli tool is assumed to be configured and functional.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;s3&quot;&gt;S3&lt;&#x2F;h2&gt;
&lt;p&gt;The extant resource in this case is an S3 bucket called &lt;code&gt;phrawzty-tftest-1422290325&lt;&#x2F;code&gt;. This resource is &lt;em&gt;unknown&lt;&#x2F;em&gt; to Terraform.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; aws s3 ls&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; tftest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;2015-01-26&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 17:39:07 phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Declare the temporary twin in the Terraform config:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;aws_s3_bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest-1422353583&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Verify and prepare the plan:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; terraform plan -out=terratest.plan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    [&lt;&#x2F;span&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Path:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; terratest.plan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; aws_s3_bucket.phrawzty-tftest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    acl:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;private&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    bucket:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest-1422353583&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Apply the plan (this will create the twin):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; terraform apply .&#x2F;terratest.plan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    [&lt;&#x2F;span&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws_s3_bucket.phrawzty-tftest:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Creation complete&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Apply&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; complete! Resources:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; added,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; changed,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; destroyed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    [&lt;&#x2F;span&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;State&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; path: terraform.tfstate&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Verify that the both the extant and temporary resources exist:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; aws s3 ls&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; phrawzty-tftest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;2015-01-26&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 17:39:07 phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;2015-01-27&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 11:14:09 phrawzty-tftest-1422353583&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Verify that Terraform is aware of the temporary resource:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; terraform show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws_s3_bucket.phrawzty-tftest:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  id&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = phrawzty-tftest-1422353583&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  acl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = private&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = phrawzty-tftest-1422353583&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Alter the config file:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Insert the name of the extant resource in place of the temporary.&lt;&#x2F;li&gt;
&lt;li&gt;Strictly speaking this is not necessary, but it helps to keep things tidy.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;resource&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;aws_s3_bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Alter the state file:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Insert the name (&lt;code&gt;id&lt;&#x2F;code&gt;) of the extant resource in place of the temporary.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;            &amp;quot;resources&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                &amp;quot;aws_s3_bucket.phrawzty-tftest&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                    &amp;quot;type&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;aws_s3_bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                    &amp;quot;primary&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                        &amp;quot;id&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                        &amp;quot;attributes&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                            &amp;quot;acl&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;private&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                            &amp;quot;bucket&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                            &amp;quot;id&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Refresh the Terraform state (note the ID):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; terraform refresh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws_s3_bucket.phrawzty-tftest:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Refreshing state...&lt;&#x2F;span&gt;&lt;span&gt; (ID:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Verify that Terraform is satisfied with the state:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;terraform&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; plan&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Refreshing&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Terraform state prior to plan...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws_s3_bucket.phrawzty-tftest:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Refreshing state...&lt;&#x2F;span&gt;&lt;span&gt; (ID:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;No&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; changes. Infrastructure is up-to-date. This means that Terraform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;could&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; not detect any differences between your configuration and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;the&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; real physical resources that exist. As a result, Terraform&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;doesn&amp;#39;t need to do anything.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Remove the temporary resource:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; aws s3 rb s3:&#x2F;&#x2F;phrawzty-tftest-1422353583&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;remove_bucket:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; s3:&#x2F;&#x2F;phrawzty-tftest-1422353583&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;s3-faster&quot;&gt;S3, faster.&lt;&#x2F;h2&gt;
&lt;p&gt;For the sake of this example, the state file already contains an S3 resource called &lt;code&gt;phrawzty-tftest-blah&lt;&#x2F;code&gt;.
Add the &quot;extant&quot; resource directly to the state file.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;            &amp;quot;resources&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;                [&lt;&#x2F;span&gt;&lt;span&gt;...&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                },&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                &amp;quot;aws_s3_bucket.phrawzty-tftest&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                    &amp;quot;type&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;aws_s3_bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                    &amp;quot;primary&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                        &amp;quot;id&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                        &amp;quot;attributes&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                            &amp;quot;acl&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;private&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                            &amp;quot;bucket&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function z-support z-function&quot;&gt;                            &amp;quot;id&amp;quot;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                        }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Refresh:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; terraform refresh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws_s3_bucket.phrawzty-tftest:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Refreshing state...&lt;&#x2F;span&gt;&lt;span&gt; (ID:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws_s3_bucket.phrawzty-tftest-blah:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Refreshing state...&lt;&#x2F;span&gt;&lt;span&gt; (ID:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; phrawzty-tftest-blah&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Verify:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; terraform show&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws_s3_bucket.phrawzty-tftest:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  id&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  acl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = private&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = phrawzty-tftest-1422290325&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;aws_s3_bucket.phrawzty-tftest-blah:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  id&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = phrawzty-tftest-blah&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  acl&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = private&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  bucket&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = phrawzty-tftest-blah&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s that.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Sysadvent 2014: What Sysadmins can learn from Community Management</title>
        <published>2014-12-09T00:00:00+00:00</published>
        <updated>2014-12-09T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/sysadvent-2014-what-sysadmins-can-learn-from-community-management/"/>
        <id>https://blog.dark.ca/posts/sysadvent-2014-what-sysadmins-can-learn-from-community-management/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/sysadvent-2014-what-sysadmins-can-learn-from-community-management/">&lt;p&gt;The annual Sysadvent series of blog posts is well under-way and this year features, for the first time ever, an entry authored collaboratively by myself and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;jooooooon42&quot;&gt;Jonathan Clarke&lt;&#x2F;a&gt; entitled « &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;sysadvent.blogspot.fr&#x2F;2014&#x2F;12&#x2F;day-7-what-system-administrators-can.html&quot;&gt;What System Administrators Can Learn From Community Management&lt;&#x2F;a&gt; ».  This post was borne from notes collected over numerous Devops Paris meet-ups and other local community get-togethers, as well as from the personal experiences of both Jon and I in these respective domains.  While the article is certainly valuable, it is by no means definitive, and my feeling is that it represents the &lt;em&gt;beginning&lt;&#x2F;em&gt; of the discussion - not the end.  I&#x27;d love to hear from others who are involved in one or both of these areas, as there is so much more to explore concerning the interesting relationship and parallels between these interesting domains.  Feel free to comment here, or better yet, hit me up on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;phrawzty&quot;&gt;the Twitters&lt;&#x2F;a&gt;.
For the sake of posterity, I will re-post the article here.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;introduction&quot;&gt;Introduction&lt;&#x2F;h3&gt;
&lt;p&gt;At first blush it might not seem like there are any parallels between system administration and community management, but the two fields have much more overlap than you might think! Before we begin, let’s define community management briefly, and to do so, I’m going to lean on this &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;kommein.com&#x2F;10-things-community-management-isnt&#x2F;&quot;&gt;this excellent post&lt;&#x2F;a&gt; by Deb Ng. It’s not marketing, nor social media, nor tech support, though these things can be involved. A community manager is a strategist, a content creator, and above all, a communicator. In this article, we will explore a handful of key principles from the community management world and see how they apply to system administration.
It’s important to realise that both fields are concerned with systems, which is to say, “an assemblage or combination of things or parts forming a complex or unitary whole” (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;dictionary.reference.com&#x2F;browse&#x2F;system&quot;&gt;source&lt;&#x2F;a&gt;). In the case of sysadmins, one normally thinks of the relationship between nodes in a cluster, or clusters in a farm, or farms in a data centre, or - well, you get the idea. For community managers, one normally thinks of the relationship between members of a forum, or forums in a site, or sites in a community, or - well, here again, you get the idea. In both cases, the relationships between the individual elements of the whole can be complex, and often require specialised tools and years of experience to get a handle on.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;managing-groups-at-scale&quot;&gt;Managing groups at scale&lt;&#x2F;h3&gt;
&lt;p&gt;Scale is an important concept in community management. What works for managing a group of two people might not work for a group of 20 or 200 people. It’s generally easier to discuss a topic in a small group and achieve consensus when there are mutually-shared interests. Small groups can function directly together since the number of individual voices is low and the space needed for them to work is commensurate with their size. Logistically speaking, a small group can make use of pretty much any communication platform that happens to be convenient - a common list of people to CC when emailing and a Google document might well be enough.
Contrast that with managing a community of, say, 50 people - that’s a big list of people to keep tabs on every time you need to write an email (not to mention the amount of noise that might get generated with an errant reply- all), and as anybody who’s ever tried to play a fast-paced game of multiplayer text editing knows, that’s a lot of cooks in the kitchen when it comes to a shared document. Even at this modest scale, some sort of more purpose-built tooling is required, such as a proper mailing list or forum site. This necessity is borne from two important effects of larger groups which, for our purposes, we can refer to as quantity and quality.
Quantity is straightforward: more people means more conversations! A handful of emails per week is trivial for any one person to deal with, but multiply that by a factor of ten or 100, and the trickle becomes a raging torrent. The more information that’s being generated, the more difficult it becomes for any one member of the group to process it effectively.
Quality refers to the nature of those conversations, and in particular, their level of diversity. Each person in the community will bring their own particular histories, viewpoints, cultural perspectives, and so forth to the group. Good tooling can make all the difference when trying to manage such a heterogenous system. A straightforward example of this is mature forum software that has conversational threads, thematic areas, and a robust back- end for gathering statistics and metrics about usage.
From here it shouldn’t be difficult to make the mental leap to system administration. Two servers sitting on your desk are pretty straightforward to deal with - even if they’re totally different, there’s only two of them, so you probably don’t need any special infrastructure to manage them. Scale that up to a dozen servers, however, and the situation becomes much more complex. The dual effects of quantity and quality are instantly applicable. At even relatively small scales the importance of a coherent configuration management tool becomes evident: something that allows the different nodes in the system to be organised as operational or thematic groups, and with a robust back-end for gathering statistics and metrics about usage. Sound familiar?
We’re going to come back to scale later, but for now, let’s move on to something a little bit more esoteric.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;writing-a-mission-statement&quot;&gt;Writing a mission statement&lt;&#x2F;h3&gt;
&lt;p&gt;I know what you’re thinking: “mission statement? That’s just corporate-speak nonsense!” And yes, that can certainly be the case, but it doesn’t have to be. In fact, a good mission statement is essential for any community, and explicitly stating it can help to crystallise the community in powerful ways.
Most organic communities assemble around an initial idea or principle. While this shared element is enough to form the community, it’s rarely enough to maintain it, and almost certainly insufficient for real growth - the secret sustainability sauce is made up of the values that original germ represents. In other words, people come for the brilliant spark, but they stay for the ideas generated from the spark. A mission statement is a way to codify and present both.
Sound a little high level? Consider that at some point in your life you’ve probably come across an open source project that was little more than a few hundred lines of code and a README. But something about this project made it different from the others. The documentation, ersatz though it might have been, clearly elucidated the problem and how this project acted as a (potential) solution. This simple addition to the repository made all the difference in the world because it helped you to understand how the project could fit your particular situation. Even without a deeper analysis of the code in question, your interest was piqued and your desire to learn more was set into motion. What happened there? Believe it or not, what captured your attention was, fundamentally, a mission statement.
Most established companies have mission statements. These are organisation- wide screeds that may or may not have any direct relationship with the work that any one contributor effects within that organisation. Is it possible to bring the granularity level down a notch or two, and if so, what might the benefit be? Could it be useful to a system administration team?
Imagine you’re just starting on a new project: a simple but powerful collection of scripts to manage virtual machines that’s going to make everyone’s day-to-day work much easier. Right now, even before you’ve begun writing any code, is the perfect time to write a mission statement. Start with something simple like “I’m fed up of typing in a dozen long and complicated commands every time I need to migrate a VM in our infrastructure, especially in the middle of the night, when on call. I intend this to be a small wrapper tool that can do normal migrations for us by typing in just one command. This should reduce the amount of time we waste on manual migrations and help to eliminate typing errors”. This brief, simple statement encapsulates both the problem and the solution, clearly defines the scope of the project, and describes both the initial idea germ and - critically - the parameters for success.
There are numerous benefits to drafting your mission statement at the earliest possible stage. Crucially, by acting as a sort of combination compass and mold, it acts as a guide to keep the contributors focused (even if you’re the only one), which helps to nip things like feature creep in the bud straight away. Keep it short and don’t overthink it. Much like setting up some new test infrastructure, or working on a new program, the best thing is to start small and iterate over time as necessary. Finally, writing a mission statement should be easy; if you’re embarking on a project, then you know best what problem you’re trying to solve, and at those early stages is when you’ll have the most clarity about it. If for no one else, write the mission statement for your future self - a few weeks down the line you may have gone so deep you completely forgot the original problem you were trying to solve!
A good mission statement can also be used to generate excitement which, as we’ll see below, can be a powerful tool for getting things done.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;encouraging-involvement&quot;&gt;Encouraging involvement&lt;&#x2F;h3&gt;
&lt;p&gt;A key principle of community management is actively encouraging contribution and involvement from the community. A good community manager will generate excitement and foster enthusiasm. Cultivating a positive emotional connection to the community will make members more loyal and encourage them to participate even more - a virtuous cycle that in turn makes the community even stronger. That said, while a general feeling of excitement is, like that initial idea germ, enough to create a spark, it’s insufficient to maintain the community. The excitement needs to be backed up by concrete measures to encourage active involvement.
There is a fairly well-known philosophy in the open source world called “&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Release_early,_release_often&quot;&gt;Release early, release often&lt;&#x2F;a&gt;” that was popularised by Eric S. Raymond in the late 90’s. The essence of the philosophy is that sharing versions of a software project early and often will ultimately improve the overall quality of the software. This happens because beta-testers and early adopters can have fun playing with new features while contributors can learn the codebase by fixing obvious bugs - that early feedback will help influence development in useful ways. In fact, as long as they’re not fatal, it can be helpful to leave some bugs in there deliberately! Providing low hanging fruit can enable an enthusiastic contributor to jump into the project by giving them the chance to fix that bug themselves.
Looking at this from a systems perspective, this is basically a process with a feedback loop, and by releasing often the loop is accelerated. In other words, excitement is generated by rapid development, and the rapid development is encouraged by excitement - it’s almost too easy!
As a system administrator, while you may certainly be leading up a project for which the rapid release model is applicable, that won’t always be the case. That’s no reason not to adopt this principle, however; by actively encouraging your co-workers to get involved, you help to build a trust relationship that will pay dividends down the line. Consider the development vs. operations silo for example - how nice would it be if the two groups actually worked together on projects right from the start?
So how do you generate excitement? The easiest thing is to talk to your co- workers. Write a mission statement - or, better yet, draft one in collaboration with some potentially interested parties. Ask questions, discuss ideas, and continuously act on that feedback. Share design documents, proofs of concept, and initial implementations. Don’t be shy about unfinished releases or weird bugs, and don’t let perfection be the enemy of good - the important thing here is that both the features and the bugs are clearly explained.
Whatever the scope of your next project, try sharing the idea with your co- workers (or whomever) before you get started and see how they react. Chances are, you’ll get their support a lot more easily that by showing them hundreds of lines of script that don’t yet solve the whole problem - and they probably won’t nitpick about your chosen scripting language or variable naming while reading the mission statement either.
Of course for others to be able to fix bugs in your code, they need to know how to get that bug fix back into the code. Which brings us to our next topic&quot;¦&lt;&#x2F;p&gt;
&lt;h3 id=&quot;establishing-community-guidelines&quot;&gt;Establishing community guidelines&lt;&#x2F;h3&gt;
&lt;p&gt;A simple search with the term “community guidelines” will reveal hundreds of thousands of examples from across the web. They encompass, either implicitly or explicitly, communities of just about every conceivable size on more or less every topic there is. It’s difficult to find a legitimate site that doesn’t have one - but, what are they? Simply stated, they are the basic tenets that frame the social contract between all of the members of the community, and they serve as ground rules to help that community to interact well. For example, an increasingly popular type of guideline is the conference code-of-conduct, which most conferences have now to help ensure that respectful and inclusive behaviour prevails.
Responsible community management is, in many respects, predicated on the existence of community guidelines. It’s one of the most important tools that leaders can use to act decisively and consistently.
When technical folk collaborate, be it in writing code or in administrating a server, we all tend to do things slightly differently from one another. How so? A simple question: where do you put custom binaries on a server?
Right.
Now, chances are you’re thinking “I don’t need to write out guidelines - we’re a tiny group”. You may well be right - your group probably can function just fine, for now; however, consider when a new person is joining your team. They will need to understand “how to do stuff around here”. Thinking further, the future could include a larger expansion, perhaps open sourcing a tool you wrote, or your company being acquired or merging with a larger one. In these cases, having planned ahead and written down the key points on how to work together could be a life saver - for both yourself and the new arrivals.
As with everything, the key is to start simply: put a minimum viable set of guidelines together and then iterate as necessary. Some good starting points might include things like “all code must live in a given version control system.” That’s a simple, effective guideline that is both easy to follow and hard to misinterpret. Stipulate the conventions up front: paths on file systems, tabs vs. spaces for indentation, and so forth. That’s a great start.
Next, explain how to contribute; this could be by sending a pull request on GitHub, a patch by email, or whatever. The important thing is to set up a consistent framework. Elucidate expectations for responses to contributions, too - it’s better to say something like “I only review patches on Mondays, so please be patient” than to leave an enthusiastic first time contributor hanging for six days. Examples of such standards documents (that have open source licenses) include &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;code.google.com&#x2F;p&#x2F;google-styleguide&#x2F;&quot;&gt;Google’s style guide&lt;&#x2F;a&gt;, or for a more simple example, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.rudder-project.org&#x2F;foswiki&#x2F;Development&#x2F;GeneralGuidelines&quot;&gt;Rudder’s technical guidelines&lt;&#x2F;a&gt;.
These contribution guidelines obviously tie into lowering the barrier to entry to your project too (see previous section). The underlying goal is to facilitate collaboration by avoiding pointless debates about which indentation style to use, when the project could be accepting contributions and moving forwards. There are no hard and fast rules governing the content or structure here, but as a general rule the idea is to be concise - use clear, brief language that expresses the core principles accurately.
Similar guidelines can, and should, be drawn out for social interaction. Don’t fall into the trap of defining complex rules that are hard to follow and, most importantly, assume good intentions by default. Great relationships are built on trust, and the best way to get trust is to give it in the first place. There is really no one-size-fits-all set of rules and each community will grow around the shared values that have particular meaning to them; however, it is very important to point out what is not OK. Again, exact details here depend on who you are as a community but make sure that as a bare minimum you explicitly forbid any kind of discriminatory behaviour or harassment.
Last but not least, remember that as one of your community’s leaders - however big or small that community is - you should be setting the example through action. Respect your own conventions. Welcome newcomers. Communicate clearly, consistently, and often. Be mindful that your words carry weight, and choose them deliberately and carefully when you write every email, blog post, or README.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;resources&quot;&gt;Resources&lt;&#x2F;h3&gt;
&lt;p&gt;The web is full of resources about community management - if you’re curious to learn more, some good starting points (for system administrators) include the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;producingoss.com&#x2F;&quot;&gt;Producing Open Source Software&lt;&#x2F;a&gt; book, Eric S. Raymond’s &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;The_Cathedral_and_the_Bazaar&quot;&gt;The Cathedral and The Bazaar&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mozilla.org&#x2F;en-US&#x2F;about&#x2F;manifesto&#x2F;&quot;&gt;The Mozilla Manifesto&lt;&#x2F;a&gt;. &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;fastwonderblog.com&#x2F;tag&#x2F;community&#x2F;&quot;&gt;Dawn Foster’s blog&lt;&#x2F;a&gt; also has some great insight on managing a community from a sysadmin perspective.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Devopsdays Belgium 2014; recap</title>
        <published>2014-11-04T00:00:00+00:00</published>
        <updated>2014-11-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/devopsdays-belgium-2014-recap/"/>
        <id>https://blog.dark.ca/posts/devopsdays-belgium-2014-recap/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/devopsdays-belgium-2014-recap/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;devopsdays.org&#x2F;events&#x2F;2014-belgium&#x2F;&quot;&gt;Devopsdays Belgium 2014&lt;&#x2F;a&gt; was held over 27 and 28 October in the charming town of Ghent (or Gent, or Gand), Belgium.  This event marked the &lt;em&gt;five-year anniversary&lt;&#x2F;em&gt; of the Devopsdays series of conferences - and with such an important milestone in play, expectations were running high.  I&#x27;m happy to report that those expectations were met.
First off, the basic details:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The Devopsdays format is half-day presentations and half-day open spaces (the programme is &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;devopsdays.org&#x2F;events&#x2F;2014-belgium&#x2F;program&#x2F;&quot;&gt;available here&lt;&#x2F;a&gt;).&lt;&#x2F;li&gt;
&lt;li&gt;All of the presentations were recorded by &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;bmc.tv&quot;&gt;BMC&lt;&#x2F;a&gt; and are available on &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.ustream.tv&#x2F;channel&#x2F;devopsdays-belgium-2014&quot;&gt;Ustream&lt;&#x2F;a&gt; for your viewing pleasure.&lt;&#x2F;li&gt;
&lt;li&gt;Perusing &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;search?q=%23devopsdays&quot;&gt;#devopsdays on Twitter&lt;&#x2F;a&gt; is probably the fastest way to tap into the over-mind of the conference attendees, both in real-time and in retrospect.&lt;&#x2F;li&gt;
&lt;li&gt;The popular &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.hangops.com&#x2F;&quot;&gt;Hangops&lt;&#x2F;a&gt; show&#x2F;podcast did a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=J5pop-B6rtU&quot;&gt;recap of the event&lt;&#x2F;a&gt; featuring speakers, attendees, and even Patrick Debois himself (if briefly).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Looking at the programme, it&#x27;s interesting to note that there were no strictly-technical talks (the same was true, more or less, for the ignites as well).  Broadly speaking, the topics ranged from management skills, to brain chemistry, and as far as a post-modern analysis of the Devops movement itself.  Indeed, in terms of content, this was one of the most &lt;em&gt;human-centric&lt;&#x2F;em&gt; conferences I&#x27;ve ever attended.  Five years ago this wouldn&#x27;t have been the case and it is an indicator of just how far we&#x27;ve come as a community - in other words, huzzah, we&#x27;ve finally managed to stop talking about tools constantly.
Concerning the presentations specifically, much has already been written, and I don&#x27;t feel like I can add much more to the existing discourse.  While I would recommend watching the videos themselves, for those looking for an executive summary of the two mornings, you could do worse than Carlos Sanchez&#x27;s posts at InfoQ &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.infoq.com&#x2F;news&#x2F;2014&#x2F;10&#x2F;devops-days-belgium-1&quot;&gt;here&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.infoq.com&#x2F;news&#x2F;2014&#x2F;10&#x2F;devops-days-belgium-2&quot;&gt;here&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.infoq.com&#x2F;news&#x2F;2014&#x2F;10&#x2F;devops-days-automation-humans&quot;&gt;here&lt;&#x2F;a&gt;.
The best part of almost any conference, for me, is the so-called hallway track: those serendipitous encounters near the coffee machine or spontaneous introductions around a lunch table.  In many ways, the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;devopsdays.org&#x2F;pages&#x2F;open-space-format&#x2F;&quot;&gt;open space&lt;&#x2F;a&gt; format is a formalisation of the hallway track, and one that works for everybody (not just people who are comfortable approaching strangers).  In either case, when combined with the highly-local nature of Devopsdays, it made for a great opportunity to meet and speak with people whom I&#x27;d normally never encounter - the perfect environment for challenging discussions and generating fresh ideas.
A great example of this environment came courtesy of &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;bridgetkromhout.com&#x2F;blog&#x2F;2014&#x2F;11&#x2F;03&#x2F;the-first-rule-of-devops-club&#x2F;&quot;&gt;Bridget Kromhout&lt;&#x2F;a&gt;, who (bravely) challenged the conference at large to use more inclusive language, especially when referring to groups within our industry (i.e. say &quot;people&quot; instead of &quot;guys&quot;).  The subsequent conversation was civil, reasoned, thought-provoking, and - notably - itself inclusive, not only in terms of gender, but &lt;em&gt;culture&lt;&#x2F;em&gt; as well.  This was interesting since it reminded everybody that, hey, different languages have different ways of dealing with this, and that while the problem exists everywhere, specific characteristics can vary wildly from region to region.
I also had the pleasure of meeting &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;davemangot&quot;&gt;Dave Mangot&lt;&#x2F;a&gt; who turned me on to something called the &quot;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.salesforcefoundation.org&#x2F;about-us&#x2F;&quot;&gt;1-1-1 model&lt;&#x2F;a&gt;&quot; (as pioneered by Salesforce).  Basically the idea is to donate 1% of profits, product, and time (respectively) to charitable ends.  This got us thinking about how we could apply the model to Devopsdays, and by extension, tech conferences in general.  Put another way, is it possible to leverage our industry&#x27;s many social gatherings as a force for social good?  I would submit that the answer is a resounding &lt;em&gt;yes&lt;&#x2F;em&gt;.  For example, following the model, a given conference could:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Donate 1% (or more, there&#x27;s no upper limit!) of the profits to &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.doctorswithoutborders.org&quot;&gt;charity&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;Set aside a pool of tickets for people who otherwise wouldn&#x27;t be able to afford to attend - or better yet, put together a grant programme to help for the cost of transport, accommodation, etc.&lt;&#x2F;li&gt;
&lt;li&gt;Facilitate an open space where attendees can volunteer to assemble care packages, sort clothing or food donations, or other types of manual activities along those lines.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Personally, I&#x27;d love to see Devopsdays adopt a model such as this one.  Given the local, grassroots nature of the conference series, it seems like a perfect fit.  Perhaps even the upcoming Devopsdays Paris, scheduled for April of 2015?  Something to think about.
As always, if you want to chat, feel free to leave a comment, or hit me up on the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;phrawzty&quot;&gt;twitters&lt;&#x2F;a&gt;.  Salut!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>DevOpsDays Paris 2013, the event that was</title>
        <published>2013-04-23T00:00:00+00:00</published>
        <updated>2013-04-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/devopsdays-paris-2013-the-event-that-was/"/>
        <id>https://blog.dark.ca/posts/devopsdays-paris-2013-the-event-that-was/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/devopsdays-paris-2013-the-event-that-was/">&lt;p&gt;I recently helped organise the inaugural &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;devopsdays.org&#x2F;events&#x2F;2013-paris&#x2F;http:&#x2F;&#x2F;&quot;&gt;Paris edition&lt;&#x2F;a&gt; of the popular &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;search?q=%23devopsdays&quot;&gt;DevOpsDays&lt;&#x2F;a&gt; series of conferences.  It was a great event, and I&#x27;d like to share some of my thoughts and observations here.
The DevOpsDays series of events is, as the name implies, centred around the &quot;devops&quot; movement, and is intended as a way to introduce people to this style of IT workflow, project, and people management.  Since this is not related to a programming language, this conference falls outside of the normal sorts of events that Mozilla generally finds itself involved in.  I believe this to be a very good thing, and I am proud to have represented &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.mozilla.org&#x2F;&quot;&gt;Mozilla&lt;&#x2F;a&gt; both as a sponsor of the event, and as a European devops community member.
The audience was mostly French in composition with a not-insignificant number of attendees from both Francophone and non-Francophone European countries.  Said audience was a healthy mix of developers, IT operations, and managers across a wide spectrum of company sizes, types, and even industries; frankly, I was impressed at how broad the composition was, and it was refreshing to see interest in the devops movement from such a wide group.
Though the event was held in Paris, all of the talks (with the exception of some of the ignites) were done in English.  This was by design - a internally contentious decision that, in my opinion, ultimately proved itself to be the correct one.  The open spaces during the afternoon were in a mix of English and French in order to ensure that everybody could participate equally.  Concerning the open spaces, we weren&#x27;t sure if the format would work here in France, but they were a smash success!  Everybody seemed to really enjoy the format as a platform for discussion, debate, and idea-generation.  I&#x27;d wager that for many of the attendees, it was the first time they&#x27;d ever been exposed to such a thing, and my hope is that they can bring the format to others in the future.
Since devops is so new to France, the majority of the presentations themselves were entry-level, and thus not particularly interesting to me directly.  That said, there were two presentations that really stood out (and would have held their own even at a more &quot;advanced&quot; event): &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;speakerdeck.com&#x2F;alq&#x2F;customerops&quot;&gt;CustomerOps&lt;&#x2F;a&gt;&quot; by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;alq&quot;&gt;Alexis Lê-Quôc&lt;&#x2F;a&gt;, and &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;speakerdeck.com&#x2F;pyr&#x2F;map-and-territory-a-story-of-visibility&quot;&gt;Map &amp;amp; Territory&lt;&#x2F;a&gt;&quot; by &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;pyr&quot;&gt;Pierre-Yves Ritschard&lt;&#x2F;a&gt;.
Alexis&#x27; presentation on &quot;CustomerOps&quot; centred around the concept of providing customer support using engineering principles - and, indeed, delivered by engineers themselves.  This really hit home for me because in Mozilla IT&#x2F;Ops, we&#x27;re not only the people who build and provide technical infrastructure, but are also the people who provide direct support to the consumers of that infrastructure - a situation that is absolutely not a given in many other companies (i.e. the admins and the customer reps are not the same people).  Alexis illustrated the importance of communication, and how to measure success (read: customer satisfaction) in meaningful ways.
Pierre-Yves&#x27; presentation was based on a very interesting philosophical conjecture: that our mental &lt;em&gt;model&lt;&#x2F;em&gt; of the world is not the same as the &lt;em&gt;reality&lt;&#x2F;em&gt; said model attempts to describe.  Put another way, a map isn&#x27;t actually land, it&#x27;s a representation of the territory it describes (hence the title).  Therefore, the most valuable models are the ones that can describe reality in useful ways, and it&#x27;s in defining &quot;usefulness&quot; that the real effort must be made.  In a more applicable sense his thesis was simple: identify your &quot;key metrics&quot; - the numbers which literally describe the success or failure of your business - and make sure you are collecting, analysing, and modelling them above all.  Every other metric is either secondary or potentially uninteresting in the first place.
Personally, I spent a lot of time mingling with the attendees, talking about Mozilla, our projects, and our mission.  Generally speaking, the first question was, &quot;Can I have one of those Firefox stickers?&quot;, but the second question was, &quot;When can I get my hands on a &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.geeksphone.com&#x2F;&quot;&gt;FirefoxOS phone&lt;&#x2F;a&gt;?&quot;  As usual, everybody wanted to see one, and (unfortunately), as usual, I didn&#x27;t have one to show them.  The more events that I attend on behalf of Mozilla, the more I realise that continues to be a wasted opportunity to promote our most exciting new project.  I&#x27;ll have to work on this going forward.
Of course, since this was a devops-related event, people were also very curious about if and how Mozilla is implementing devops internally.  The overarching theme of devops is communication, so this event was an excellent opportunity to talk about &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;blog.mozilla.org&#x2F;it&#x2F;&quot;&gt;IT at Mozilla&lt;&#x2F;a&gt;, and to promote not only our successes, but dig into our failures as well.  This sort of interaction is vital in order to avoid stagnation.
In summary, it was a fine showing for our first Parisian event, and I am looking forward to the next edition.  Hopefully I&#x27;ll see you there!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>hangops, european edition</title>
        <published>2013-04-05T00:00:00+00:00</published>
        <updated>2013-04-05T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/hangops-eu/"/>
        <id>https://blog.dark.ca/posts/hangops-eu/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/hangops-eu/">&lt;p&gt;Today &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;roidrage&quot;&gt;roidrage&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; title=&quot;How to use Puppet like an Adult&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;phrawzty&quot;&gt;I&lt;&#x2F;a&gt; hosted the &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=QmMmjDnrfk8&quot;&gt;inaugural European edition&lt;&#x2F;a&gt; of the popular &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;hangops&quot;&gt;Hangops&lt;&#x2F;a&gt; podcast &#x2F; hangout sessions.  Hangops.eu (as we&#x27;ve taking to calling it) is functionally the same its North American counterpart - with the exception that &quot;our&quot; 11:00 is that of Western Europe, not California. ;)
If you&#x27;re not familiar with the Hangops, now&#x27;s the time for you to get with the programme.  The format is simple : get a group of talkative Ops people together on Google Hangouts, and see what happens !  Sometimes there are moderated talks, other times there are special guests, but the basic idea never changes - it&#x27;s fundamentally a chance for nerds to present ideas, debate topics, learn a little something, and have a good time.
The sessions are simulcast to Youtube, so if you don&#x27;t want to join the hangout itself, you&#x27;re invited to listen and participate in the IRC channel (freenode&#x2F;#hangops) at your leisure.
Hope to see you out next time!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>HAProxy Puppet module (phrawzty remix)</title>
        <published>2013-03-18T00:00:00+00:00</published>
        <updated>2013-03-18T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/haproxy-puppet-module-phrawzty-remix/"/>
        <id>https://blog.dark.ca/posts/haproxy-puppet-module-phrawzty-remix/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/haproxy-puppet-module-phrawzty-remix/">&lt;p&gt;As part of a big &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.logstash.net&#x2F;&quot;&gt;Logstash&lt;&#x2F;a&gt; project at Mozilla (more on that to come), I was looking for an &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;haproxy.1wt.eu&#x2F;&quot;&gt;HAProxy&lt;&#x2F;a&gt; module for Puppet, stumbling across the official &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;forge.puppetlabs.com&#x2F;puppetlabs&#x2F;haproxy&quot;&gt;Puppetlabs module&lt;&#x2F;a&gt; in the process.  I&#x27;m told that this module works fairly well, with the caveat that it sometimes outputs poorly-formatted configuration files (due to a manifestly buggy implementation of &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;ripienaar&#x2F;puppet-concat&quot;&gt;concat&lt;&#x2F;a&gt;).  Furthermore, the module more or less requires &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.google.fr&#x2F;search?q=puppet+storeconfigs&quot;&gt;storeconfigs&lt;&#x2F;a&gt;, which we do not use in our primary Puppet system.
Long story short, while I never ended up using HAProxy as part of the project, I did &lt;em&gt;remix&lt;&#x2F;em&gt; the official module to solve both of the aforementioned issues.  From the README :&lt;&#x2F;p&gt;
&lt;p&gt;This module is based on Puppetlabs&#x27; official HAProxy module; however, it has been &quot;remixed&quot; for use at Mozilla. There are two major areas where the original module has been changed :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Storeconfigs, while present, are no longer required.&lt;&#x2F;li&gt;
&lt;li&gt;The &quot;listen&quot; stanza format has been abandoned in favour of a frontend &#x2F; backend style configuration.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;A very simple configuration to proxy unrelated Redis nodes :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  class&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;haproxy&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;: }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  haproxy::frontend&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;in_redis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    ipaddress&lt;&#x2F;span&gt;&lt;span&gt;       =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; $&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;::ipaddress,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    ports&lt;&#x2F;span&gt;&lt;span&gt;           =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;6379&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    default_backend&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;out_redis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    options&lt;&#x2F;span&gt;&lt;span&gt;         =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;balance&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;roundrobin&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;  haproxy::backend&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; {&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;out_redis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    listening_service&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;redis&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    server_names&lt;&#x2F;span&gt;&lt;span&gt;      =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;node01&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;node02&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    ipaddresses&lt;&#x2F;span&gt;&lt;span&gt;       =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;node01.redis.server.foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;node02.redis.server.foo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;],&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    ports&lt;&#x2F;span&gt;&lt;span&gt;             =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;6379&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    options&lt;&#x2F;span&gt;&lt;span&gt;           =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;check&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;If that sounds interesting to you, the module is available on my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;phrawzty&#x2F;puppetlabs-haproxy&quot;&gt;puppetlabs-haproxy repo&lt;&#x2F;a&gt; on Github. Pull requests welcome !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>LCA, the event that was</title>
        <published>2013-03-11T00:00:00+00:00</published>
        <updated>2013-03-11T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/lca-the-event-that-was/"/>
        <id>https://blog.dark.ca/posts/lca-the-event-that-was/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/lca-the-event-that-was/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;lca2013.linux.org.au&#x2F;&quot;&gt;Linux Conf Australia 2013&lt;&#x2F;a&gt;, (alias linux.conf.au, alias LCA) was an amazing experience, and it&#x27;s difficult to summarise it succinctly, but there are definitely some highlights and important take-aways that I&#x27;d like to make special note of.
My fundamental reason for attending was that &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;bkero&quot;&gt;Ben Kero&lt;&#x2F;a&gt; and I were invited to do a &lt;a rel=&quot;external&quot; title=&quot;How to use Puppet like an Adult&quot; href=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;2013&#x2F;02&#x2F;15&#x2F;how-to-use-puppet-like-an-adult&#x2F;&quot;&gt;talk regarding Puppet&lt;&#x2F;a&gt; (an important infrastructural tool that we use at Mozilla).  The talk, like all of the presentations given by Mozillians at LCA this year (and there were more than a few), was very well-received, and delivered to a packed auditorium - in fact, people had to be turned away at the door beforehand !
Since our talk bumped up against the lunch period, we had occasion to stay in the space and launch an informal panel discussion that included other Mozillians as well as representatives from a number of other Open Source companies and organisation.  We engaged on a variety of topics, ranging from IT-centric to questions about the future of the web, and the importance of open standards and market competition.  It was only when the organisers forced us out that the auditorium was finally cleared.
Interestingly, from the moment I arrived in Australia, and through until the very last day, I found myself acting as an ambassador for Mozilla.
For example, a day before the conference even started, I was part of an informal debate concerning the future of mobile and the importance of FirefoxOS within it.  Other participants included a Ubuntu employee and a number of hardware hackers who - as it turned out - were already trying to port FirefoxOS to other types of phones.
Another example even occurred at a local cricket match.  I was wearing my Firefox T-shirt (which usually generates interest), and ended up doing a some impromptu demos of Firefox for Android to a couple of different groups - the highly satisfying result was that a handful of people downloaded and installed it on the spot !
These, and more, are all opportunities to engage people about Mozilla, and in many cases, to introduce our values and mission to entirely new audiences.  During this and other conferences, I&#x27;ve found that even long-time users of Firefox and Thunderbird (for example) are often not even aware of who and what Mozilla is, and what we&#x27;re about.  I try my best to be a good ambassador, and I&#x27;m proud to represent the organisation wherever, and whenever I can.
From a personal perspective, the conference had two major benefits: it was an excellent learning experience, and a fantastic opportunity to spend time in-person with a number of my co-workers in the IT&#x2F;Ops team.
Of note, I had the pleasure of attending a number of talks and presentations about technology that we use in our environment that have had a direct impact in my work-flow already.  Beyond the directly-applicable benefits, I was particularly inspired by a presentation about &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;mirror.linux.org.au&#x2F;pub&#x2F;linux.conf.au&#x2F;2013&#x2F;ogv&#x2F;Keynote_Andrew_Bunnie_Huang.ogv&quot;&gt;programming for embedded devices&lt;&#x2F;a&gt; (shout-out to &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;lca2013.linux.org.au&#x2F;media&#x2F;news&#x2F;76&quot;&gt;Bunnie Huang&lt;&#x2F;a&gt;) which, due to peculiar technical constraints, requires a very precise and measured approach to development.  These ideals could - and should - be carried through outside of the embedded world.
In summary, LCA 2013 was an excellent opportunity to learn, teach, and engage the public concerning technology in specific, Mozilla in particular, and open source in general.  I&#x27;m already looking forward to next year !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>How to use Puppet like an Adult</title>
        <published>2013-02-15T00:00:00+00:00</published>
        <updated>2013-02-15T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/how-to-use-puppet-like-an-adult/"/>
        <id>https://blog.dark.ca/posts/how-to-use-puppet-like-an-adult/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/how-to-use-puppet-like-an-adult/">&lt;p&gt;Hello friends,
Recently, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;bkero&quot;&gt;Ben Kero&lt;&#x2F;a&gt; (a fellow Mozillian) and I were invited to present a talk at &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;linux.conf.au&#x2F;&quot;&gt;Linux Conf Australia&lt;&#x2F;a&gt;.  To say that we were excited about presenting at one of the best Libre &#x2F; Open Source conferences in the world is an understatement.  We knew that we&#x27;d have to bring our A-game, and in all modesty, I like to think that we did.  If you were there in person, I&#x27;d like to personally thank you for coming out, and if you couldn&#x27;t make it, that&#x27;s ok - the organisers have made many videos from the 2013 LCA &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;mirror.linux.org.au&#x2F;linux.conf.au&#x2F;2013&#x2F;ogv&#x2F;&quot;&gt;available online&lt;&#x2F;a&gt;, including ours, entitled &quot;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;mirror.linux.org.au&#x2F;linux.conf.au&#x2F;2013&#x2F;ogv&#x2F;How_to_use_Puppet_like_an_Adult.ogv&quot;&gt;How to use Puppet like an Adult&lt;&#x2F;a&gt;&quot;.
We cover a variety of topics, including parametrisation, how to select good pre-built modules, and how you can build eco-systems around Puppet itself.  Please feel free to drop us a line, either on &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;phrawzty&quot;&gt;Twitter&lt;&#x2F;a&gt; or here on the blog.  Thanks !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Puppet at Mozilla, the podcast</title>
        <published>2012-09-20T00:00:00+00:00</published>
        <updated>2012-09-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/puppet-at-mozilla-the-podcast/"/>
        <id>https://blog.dark.ca/posts/puppet-at-mozilla-the-podcast/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/puppet-at-mozilla-the-podcast/">&lt;p&gt;Hello everybody !
If you&#x27;re interested in learning a little about Puppet at Mozilla, I highly recommend that you check out &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;puppetlabs.com&#x2F;puppet-labs-podcast&#x2F;7&#x2F;&quot;&gt;Puppet Podcast #7&lt;&#x2F;a&gt;, where Brandan Burton (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;solarce&quot;&gt;@solarce&lt;&#x2F;a&gt;) and I (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;phrawzty&quot;&gt;@phrawzty&lt;&#x2F;a&gt;) talk with Puppet Labs&#x27; Mike Stahnke (&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;twitter.com&#x2F;stahnma&quot;&gt;@stahnma&lt;&#x2F;a&gt;) about just that topic.  It was our first podcast together, and frankly, it was more difficult that I thought it&#x27;d be.  That said, it was a great experience, and I hope to do it again sometime.  Hope you enjoy it !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>quickly generate an encrypted password</title>
        <published>2012-02-12T00:00:00+00:00</published>
        <updated>2012-02-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/quickly-generate-an-encrypted-password/"/>
        <id>https://blog.dark.ca/posts/quickly-generate-an-encrypted-password/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/quickly-generate-an-encrypted-password/">&lt;p&gt;Hi everybody !  Here&#x27;s a quick method for generating encrypted passwords that are suitable for things like &lt;code&gt;&#x2F;etc&#x2F;passwd&lt;&#x2F;code&gt; .  I realise that this isn&#x27;t terribly complex, but honestly, I always forget how to do this until I actually need to do it - so here&#x27;s a reminder for all of us. :)&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;#!&#x2F;bin&#x2F;bash&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [ &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ==&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39; ]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator z-keyword&quot;&gt;; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;USAGE: &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &amp;#39;password&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Get an md5sum of the password string; this is used for the SHA seed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;md5&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;$(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; $1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; md5sum&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; )&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;extract&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;${&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;md5&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-variable&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Calculate the SHA hash of the password string using the extracted seed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mkpasswd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -m SHA-512&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$extract&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;exit&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; $?&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Elasticsearch backup strategies</title>
        <published>2011-11-22T00:00:00+00:00</published>
        <updated>2011-11-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/elasticsearch-backup-strategies/"/>
        <id>https://blog.dark.ca/posts/elasticsearch-backup-strategies/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/elasticsearch-backup-strategies/">&lt;p&gt;&lt;strong&gt;Update&lt;&#x2F;strong&gt;: This is an old blog post and is no longer relevant as of version 1.x of Elasticsearch. Now we can just use the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.elasticsearch.org&#x2F;guide&#x2F;en&#x2F;elasticsearch&#x2F;reference&#x2F;current&#x2F;modules-snapshots.html&quot;&gt;snapshot&lt;&#x2F;a&gt; feature.
Hello again! Today we&#x27;re going to talk about backup strategies for &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;elasticsearch.org&quot;&gt;Elasticsearch&lt;&#x2F;a&gt;. One popular way to make backups of ES requires the use of separate ES node, while another relies entirely on the underlying file system of a given set of ES nodes.
The ES-based approach:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Bring up an independent (receiving) ES node on a machine that has network access to the actual ES cluster.&lt;&#x2F;li&gt;
&lt;li&gt;Trigger a script to perform a full index import &lt;em&gt;from&lt;&#x2F;em&gt; the ES cluster &lt;em&gt;to&lt;&#x2F;em&gt; the receiving node.&lt;&#x2F;li&gt;
&lt;li&gt;Since the receiving node is unique, every shard will be represented on said node.&lt;&#x2F;li&gt;
&lt;li&gt;Shutdown the receiving node.&lt;&#x2F;li&gt;
&lt;li&gt;Preserve the &lt;code&gt;&#x2F;data&#x2F;&lt;&#x2F;code&gt; directory from the receiving node.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The file system-based approach:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Identify a &lt;em&gt;quorum&lt;&#x2F;em&gt; of nodes in the ES cluster.&lt;&#x2F;li&gt;
&lt;li&gt;Quorum is necessary in order to ensure that all of the shards are represented.&lt;&#x2F;li&gt;
&lt;li&gt;Trigger a script that will preserve the &lt;code&gt;&#x2F;data&#x2F;&lt;&#x2F;code&gt; directory of each selected node.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;At first glance the file system-based approach appears simpler - and it is - but it comes with some drawbacks, notably the fact that coherency is &lt;em&gt;impossible to guarantee&lt;&#x2F;em&gt; due to the amount of time required to preserve &lt;code&gt;&#x2F;data&#x2F;&lt;&#x2F;code&gt; on each node. In other words, if data changes on node between the start and end times of the preservation mechanism, those changes may or may not be backed up. Furthermore, from an operational perspective, restoring nodes from individual shards may be problematic.
The ES-based approach does not have the coherency problem; however, beyond the fact that it is more complex to implement and maintain, it is also more costly in terms of service delivery. The actual import process itself requires a large number of requests to be made to the cluster, and the resulting resource consumption on both the cluster nodes as well as the receiving node are non-trivial. On the other hand, having a single, coherent representation of every shard in one place may pay dividends during a restoration scenario.
As is often the case, there is no one solution that is going to work for everybody all of the time - different environments have different needs, which call for different answers.  That said, if your &lt;em&gt;primary&lt;&#x2F;em&gt; goal is a consistent, coherent, and complete backup that can be easily restored when necessary (and overhead be damned!), then the ES-based approach is clearly the superior of the two.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;import-it&quot;&gt;import it !&lt;&#x2F;h3&gt;
&lt;p&gt;Regarding the ES-based approach, it may be helpful to take a look at a simple import script as an example.  How about a quick and dirty Perl script (straight from &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;clintongormley&#x2F;ElasticSearch.pm&quot;&gt;the docs)&lt;&#x2F;a&gt; ?&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;use&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ElasticSearch&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;my&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $local&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = ElasticSearch&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    servers&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;localhost:9200&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;my&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $remote&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = ElasticSearch&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;new&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    servers   &lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;cluster_member:9200&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    no_refresh&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;my&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $source&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $remote-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;scrolled_search&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    index&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;content&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    search_type&lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;scan&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;,&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;    scroll     &lt;&#x2F;span&gt;&lt;span&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;5m&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$local&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;reindex&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;source&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;&amp;gt;$source)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You&#x27;ll want to replace the relevant elements with something sane for your environment, of course.
As for preserving the resulting &#x2F;data&#x2F; directory (in either method), I will leave that as an exercise to the reader, since there are simply too many equally relevant ways to go about it.  It&#x27;s worth noting that the import method doesn&#x27;t need to be complex &lt;em&gt;at all&lt;&#x2F;em&gt; - in fact, it really shouldn&#x27;t be, since complex backup schemes tend to have too many chances for failure than is necessary.
Happy indexing!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Send your logs to the cloud; Loggly vs. Papertrail</title>
        <published>2011-11-17T00:00:00+00:00</published>
        <updated>2011-11-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/send-your-logs-to-the-cloud-loggly-vs-papertrail/"/>
        <id>https://blog.dark.ca/posts/send-your-logs-to-the-cloud-loggly-vs-papertrail/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/send-your-logs-to-the-cloud-loggly-vs-papertrail/">&lt;p&gt;&lt;strong&gt;N.B.&lt;&#x2F;strong&gt; This post is from &lt;em&gt;2011&lt;&#x2F;em&gt; - the landscape has changed since then...
 
Centralised cloud-based logging.  It sounds tasty - and it is - but who should you go with?  Well, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;loggly.com&#x2F;&quot;&gt;Loggly&lt;&#x2F;a&gt; and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;papertrailapp.com&#x2F;&quot;&gt;Papertrail&lt;&#x2F;a&gt; are the only games in town when it comes to the aforementioned service; the only other competitor in this space is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.splunkstorm.com&#x2F;&quot;&gt;Splunk Storm&lt;&#x2F;a&gt;, but their offering - well-pedigreed though it may be - is strictly in private beta at this time, and therefore cannot really be considered a valid option.
The fact of the matter is that Loggly and Papertrail are, at a high level, functionally identical. They offer more or less the same bouquet of functionality, including alert triggers, aggregate visualisation, and even map reduce tools for data mining and reporting. Loggly has been around longer, and has a better track record for open-source involvement, meaning that the eco-system around their service is more mature; however, that doesn&#x27;t mean that they are necessarily superior to Papertrail in terms of the actual service.
My suggestion: If you&#x27;re in a hurry, flip a coin and go with one or the other. If you have the time, you should go ahead and try both out for a bit; Papertrail has a 7-day free trial programme, and Loggly is free (in perpetuity) for sufficiently small amounts of data and retention (which is no problem if you&#x27;re just poking around).
I&#x27;m &lt;em&gt;very&lt;&#x2F;em&gt; interested in hearing about actual user experiences with either or both, so please don&#x27;t hesitate to add a comment or drop me a line directly via the contact form.
&lt;strong&gt;Edit&lt;&#x2F;strong&gt;: From &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;spootnik.org&#x2F;&quot;&gt;@pyr&lt;&#x2F;a&gt; : « you  can also consider &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.datadoghq.com&quot;&gt;@datadoghq&lt;&#x2F;a&gt; which has a different take on the issue but might fit the bill. »
&lt;strong&gt;Edit 2&lt;&#x2F;strong&gt;: From the comments, there&#x27;s also &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;logentries.com&#x2F;&quot;&gt;Logentries&lt;&#x2F;a&gt;, which I don&#x27;t personally have any experience with, but which appears to offer a reasonably comprehensive offering as well.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Heavyweight tilt : GitHub vs. Bitbucket</title>
        <published>2011-11-08T00:00:00+00:00</published>
        <updated>2011-11-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/heavyweight-tilt-github-vs-bitbucket/"/>
        <id>https://blog.dark.ca/posts/heavyweight-tilt-github-vs-bitbucket/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/heavyweight-tilt-github-vs-bitbucket/">&lt;p&gt;When it comes to code hosting on The Internets today, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;&quot;&gt;GitHub&lt;&#x2F;a&gt; is absolutely the hottest, trendiest service going - but it&#x27;s not alone. Right now, the primary direct competitor to GitHub is &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bitbucket.org&#x2F;&quot;&gt;Bitbucket&lt;&#x2F;a&gt;, and choosing the best service for you or your company can be a less than obvious scenario - so let&#x27;s break it down, shall we?
GitHub is generally considered to be the most popular code hosting and collaboration site out there today. They have an excellent track record for innovation and evolution of their service, and they put their money where their mouth is, notably by promoting and releasing their own internal tools into the open source community.  Their site offers a buffet of ever-improving facilities for collaborative activity, notably including an integrated issue tracker and excellent code comparison tools, among others. To be fair, not every feature has had the same level of care and attention paid to it, and as a result, some elements feel quite a bit more mature than others; however, again, they never stop trying to make things better.
Bitbucket looks &lt;em&gt;a lot&lt;&#x2F;em&gt; like GitHub.  That&#x27;s a fact.  I don&#x27;t honestly know which one came first, but it&#x27;s clear that today they&#x27;re bouncing off of each other in terms of design, features, and functionality.  You can more or less transpose your user experience between the two sites without missing too much of a beat, so for a casual user looking to contribute here and there, you get two learning curves for the price of one (nice).  Bitbucket&#x27;s pace of evolution is (perhaps) less blistering, but they too are capable of rolling out new and improved toys over time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;let-s-get-down-to-brass-tacks&quot;&gt;let&#x27;s get down to brass tacks&lt;&#x2F;h3&gt;
&lt;p&gt;Both services offer the same basic functionality, which is the ability to create an account, and associate that account with any number of &lt;em&gt;publicly-accessible&lt;&#x2F;em&gt; repositories; however, if you want a &lt;em&gt;private&lt;&#x2F;em&gt; repository, GitHub will make you pay for it, whereas BitBucket offers it gratis.  There, as it is said, lies the rub.  More on this later.
One of the big differences between the two services lie in their respective origins: GitHub remains an independent start-up, whereas Bitbucket (although once independent) was acquired by - and is now strongly associated with - Atlassian (of JIRA fame). It is my opinion that this affects the cultural make-up of Bitbucket in subtle ways, leading to a more corporate take on development, deployment, and importantly, community relations and involvement.  Take a look at their respective blogs (go ahead, I&#x27;ll wait).
A quick scan of the past few months from each blog will reveal some important differences:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub&#x27;s release schedule is more aggressive, with improvements and new features coming more regularly, whereas Bitbucket places greater emphasis on their tight integration with JIRA, Jenkins, and other industry tools.&lt;&#x2F;li&gt;
&lt;li&gt;Bitbucket advertises paid services and software on their blog, whereas GitHub advertises open source projects.&lt;&#x2F;li&gt;
&lt;li&gt;Bitbucket&#x27;s blog has one recent author, whereas GitHub&#x27;s blog has many recent authors.&lt;&#x2F;li&gt;
&lt;li&gt;GitHub hosts more community events (notably drinkups, heh) over a greater geographic area than Bitbucket (and their posts have more community response overall).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Also, check out GitHub&#x27;s &quot;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;about&quot;&gt;about us&lt;&#x2F;a&gt;&quot; page - &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.quora.com&#x2F;Brogramming&#x2F;How-does-a-programmer-become-a-brogrammer&quot;&gt;brogrammers&lt;&#x2F;a&gt; abound!  I&#x27;d compare the group to Bitbucket, but as it so happens, they don&#x27;t have an analogous page.
Previously I mentioned that GitHub would like you to pay for private repositories.  This is obviously part of their revenue scheme (and who can blame them for wanting to get that cheese?), but it also has the side-effect of making people &lt;em&gt;choose&lt;&#x2F;em&gt; to willingly host their projects publicly.  This has ended up creating a (very) large community of active participants representing a variety of languages and interests, which in turn results in more projects, and so on and so forth.  This feedback loop is interesting since it auto-builds popularity: as more people use it, the more people will use it.
These observations are, in no way, objective statements of the superiority of one platform over the other - they &lt;em&gt;are&lt;&#x2F;em&gt;, however, indicative of cultural differences between the two companies.  This is (or, at least, should be) a non-trivial element when deciding which service is right for you or your organisation.  For example, I&#x27;m a beer-drinking open source veteran that works in start-ups and small companies, so culturally my preferences are different than those of a suit-wearing system architect, working for a thousand-person consulting firm.  One isn&#x27;t necessarily better than the other - they&#x27;re just not the same (and that&#x27;s OK).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;but-wait-there-s-more&quot;&gt;but wait, there&#x27;s more&lt;&#x2F;h3&gt;
&lt;p&gt;Alright, here comes the shocker: for paid services (i.e. private repositories), GitHub is &lt;em&gt;much more expensive&lt;&#x2F;em&gt; than Bitbucket.  As in nowhere near the same price.  At all.  How can this be?  Well, I&#x27;m not privy to the financials of either company (if I were, I doubt I&#x27;d have written this post), but hey, the money for all those great open source projects, drinkups, and (bluntly) &lt;em&gt;salaries&lt;&#x2F;em&gt; have to come from somewhere - and while Bitbucket has Atlassian&#x27;s pockets backing them, GitHub has to stand on their own successes, and live with their own failures.
The two services are not dissimilar technically speaking, so it&#x27;s really up to you to decide which culture is better suited for your project.  Do you just need a spot to put your private project, that you program alone, isolated from the greater Internet?  BitBucket.  Do you have a public project that you&#x27;d like other people to discover, hack on together, and build a community around?  GitHub.  As for paid services, well I suppose that comes down to whether you want to pay extra to support what GitHub is doing or not.
Now, let&#x27;s be fair, for a lot of companies, &quot;culture&quot; is an irrelevant factor in their purchasing department - cost is the only concern.  Fair enough.  But let&#x27;s say you&#x27;ve got a team of developers, all of whom already have their own projects on GitHub, are familiar with the tools and processes, and have a network of fellow hackers built-in and ready to go.  In that case, perhaps culture is worth something after all.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Improvements in Cassandra 1.0, briefly stated</title>
        <published>2011-11-03T00:00:00+00:00</published>
        <updated>2011-11-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/improvements-in-cassandra-1-0-briefly-stated/"/>
        <id>https://blog.dark.ca/posts/improvements-in-cassandra-1-0-briefly-stated/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/improvements-in-cassandra-1-0-briefly-stated/">&lt;p&gt;Datastax recently announced the availability of Cassandra 1.0 (stable), and along with that announcement, they made a series of blog posts (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.datastax.com&#x2F;dev&#x2F;blog&#x2F;whats-new-in-cassandra-1-0-compression&quot;&gt;1&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.datastax.com&#x2F;dev&#x2F;blog&#x2F;whats-new-in-cassandra-1-0-improved-memory-and-disk-space-management&quot;&gt;2&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.datastax.com&#x2F;dev&#x2F;blog&#x2F;leveled-compaction-in-apache-cassandra&quot;&gt;3&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.datastax.com&#x2F;dev&#x2F;blog&#x2F;whats-new-in-cassandra-1-0-performance&quot;&gt;4&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.datastax.com&#x2F;dev&#x2F;blog&#x2F;whats-new-in-cassandra-1-0-windows-service-new-cql-clients-and-more&quot;&gt;5&lt;&#x2F;a&gt;) about many of the great new features and improvements that the current version brings to the table.
For those of you looking for an executive summary of those posts, you&#x27;re in luck, cause I&#x27;ve got your back on this one.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;New multi-layer approach to compression that provides improvements to &lt;em&gt;both&lt;&#x2F;em&gt; write and (especially) read operations.&lt;&#x2F;li&gt;
&lt;li&gt;Said compression strategy also yields potentially significant disk space savings.&lt;&#x2F;li&gt;
&lt;li&gt;Leverages the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;jna.java.net&#x2F;&quot;&gt;JNA library&lt;&#x2F;a&gt; in order to provide in-memory caching; this procedure is optimised for garbage collection, resulting in a more efficient collection and a smaller overall footprint.&lt;&#x2F;li&gt;
&lt;li&gt;A much improved compaction strategy results in less costly compaction runs, improving overall performance on each node.&lt;&#x2F;li&gt;
&lt;li&gt;Fewer requests are made over the network, and said requests are smaller in size, improving overall performance across the cluster.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In short, 1.0 is a very significant, very important upgrade to 0.8 (et al.), and one which will likely bring it to the forefront of the hardcore big data &#x2F; nosql scene at large.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Nagios plugin to parse JSON from an HTTP response</title>
        <published>2011-03-04T00:00:00+00:00</published>
        <updated>2011-03-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/nagios-plugin-to-parse-json-from-an-http-response/"/>
        <id>https://blog.dark.ca/posts/nagios-plugin-to-parse-json-from-an-http-response/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/nagios-plugin-to-parse-json-from-an-http-response/">&lt;p&gt;&lt;strong&gt;&lt;em&gt;Update 2015-10-07&lt;&#x2F;em&gt;:&lt;&#x2F;strong&gt; This plugin has evolved - please check the latest &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;phrawzty&#x2F;check_http_json&#x2F;blob&#x2F;master&#x2F;README.md&quot;&gt;README&lt;&#x2F;a&gt; for up to date details.
 
Hello all !  I wrote a plugin for Nagios that will parse JSON from an HTTP response.  If that sounds interesting to you, feel free to check out my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;phrawzty&#x2F;check_http_json&quot;&gt;check_http_json repo&lt;&#x2F;a&gt; on Github.  The plugin has been tested with Ruby 1.8.7 and 1.9.3.  Pull requests welcome !&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Usage:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; .&#x2F;check_http_json.rb -u  -e  -w  -c&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-h,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --help                       Help info.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-v,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --verbose                    Additional human output.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-u,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --uri URI                    Target URI. Incompatible with -f.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    --user&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; USERNAME              HTTP basic authentication username.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;    --pass&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; PASSWORD              HTTP basic authentication password.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-f,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --file PATH                  Target file. Incompatible with -u.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-e,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --element ELEMENT            Desired element&lt;&#x2F;span&gt;&lt;span&gt; (ex.&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; foo&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;bar&lt;&#x2F;span&gt;&lt;span&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ish is foo.bar.ish&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-E,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --element_regex REGEX        Desired element expressed as regular expression.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-d,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --delimiter CHARACTER        Element delimiter&lt;&#x2F;span&gt;&lt;span&gt; (default&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; is period&lt;&#x2F;span&gt;&lt;span&gt;).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-w,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --warn VALUE                 Warning threshold&lt;&#x2F;span&gt;&lt;span&gt; (integer).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-c,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --crit VALUE                 Critical threshold&lt;&#x2F;span&gt;&lt;span&gt; (integer).&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-r,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --result STRING              Expected string result. No need for -w or -c.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-R,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --result_regex REGEX         Expected string result expressed as regular expression. No need for -w or -c.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-W,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --result_warn STRING         Warning if element is&lt;&#x2F;span&gt;&lt;span&gt; [string]. -C is required.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-C,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --result_crit STRING         Critical if element is&lt;&#x2F;span&gt;&lt;span&gt; [string]. -W is required.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-t,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --timeout SECONDS            Wait before HTTP timeout.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;code&gt;--warn&lt;&#x2F;code&gt; and &lt;code&gt;--crit&lt;&#x2F;code&gt; arguments conform to the Nagios &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;nagiosplug.sourceforge.net&#x2F;developer-guidelines.html&quot;&gt;threshold format guidelines&lt;&#x2F;a&gt;.
If a simple result of either string or regular expression (&lt;code&gt;-r&lt;&#x2F;code&gt; or &lt;code&gt;-R&lt;&#x2F;code&gt;) is specified :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A match is OK and anything else is CRIT.&lt;&#x2F;li&gt;
&lt;li&gt;The warn &#x2F; crit thresholds will be ignored.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;If the warn and crit results (&lt;code&gt;-W&lt;&#x2F;code&gt; and &lt;code&gt;-C&lt;&#x2F;code&gt;) are specified :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A match is WARN or CRIT and anything else is OK.&lt;&#x2F;li&gt;
&lt;li&gt;The warn &#x2F; crit thresholds will be ignored.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Note that (&lt;code&gt;-r&lt;&#x2F;code&gt; or &lt;code&gt;-R&lt;&#x2F;code&gt;) and (&lt;code&gt;-W&lt;&#x2F;code&gt; and &lt;code&gt;-C&lt;&#x2F;code&gt;) are mutually exclusive.
Note also that the response must be pure JSON. Bad things happen if this isn&#x27;t the case.
How you choose to implement the plugin is, of course, up to you.  Here&#x27;s one suggestion:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# check json from http&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;define&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; command{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; command_name   &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; check_http_json-string&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; command_line   &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;nagios3&#x2F;plugins&#x2F;check_http_json.rb -u&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;http:&#x2F;&#x2F;$HOSTNAME$:$ARG1$&#x2F;$ARG2$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$ARG3$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -r&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$ARG4$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;define&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; command{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; command_name   &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; check_http_json-int&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; command_line   &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;nagios3&#x2F;plugins&#x2F;check_http_json.rb -u&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;http:&#x2F;&#x2F;$HOSTNAME$:$ARG1$&#x2F;$ARG2$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$ARG3$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -w&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$ARG4$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -c&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;$ARG5$&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# make use of http json check&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;define&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; service{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; service_description    &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; elasticsearch-cluster-status&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; check_command          &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; check_http_json-string!9200!_cluster&#x2F;health!status!green&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;define&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; service{&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; service_description    &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; elasticsearch-cluster-nodes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; check_command          &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; check_http_json-int!9200!_cluster&#x2F;health!number_of_nodes!4:!3:&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>RabbitMQ plugin for Collectd</title>
        <published>2011-02-24T00:00:00+00:00</published>
        <updated>2011-02-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/rabbitmq-plugin-for-collectd/"/>
        <id>https://blog.dark.ca/posts/rabbitmq-plugin-for-collectd/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/rabbitmq-plugin-for-collectd/">&lt;p&gt;Hello all,
I wrote a rudimentary RabbitMQ plugin for Collectd.  If that sounds interesting to you, feel free to take a look at my &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;phrawzty&#x2F;rabbitmq-collectd-plugin&quot;&gt;GitHub&lt;&#x2F;a&gt;.  The plugin itself is written in Python and makes use of the Python plugin for Collectd.
It will accept four options from the Collectd plugin configuration :&lt;&#x2F;p&gt;
&lt;p&gt;Locations of binaries :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;RmqcBin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = &#x2F;usr&#x2F;sbin&#x2F;rabbitmqctl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;PmapBin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = &#x2F;usr&#x2F;bin&#x2F;pmap&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;PidofBin&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = &#x2F;bin&#x2F;pidof&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Logging :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Verbose&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; false&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It will attempt to gather the following information :&lt;&#x2F;p&gt;
&lt;p&gt;From « rabbitmqctl list_queues » :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;messages&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;memory&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;consumser&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From « pmap » of « beam.smp » :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;memory&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mapped&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;memory&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; writeable&#x2F;private&lt;&#x2F;span&gt;&lt;span&gt; (used)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;memory&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; shared&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Props to Garret Heaton for inspiration and conceptual guidance from his « &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;powdahound&#x2F;redis-collectd-plugin&quot;&gt;redis-collectd-plugin&lt;&#x2F;a&gt; ».&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>how to use the Distributed Numeric Assignment (DNA) plug-in in 389 Directory Server</title>
        <published>2010-04-20T00:00:00+00:00</published>
        <updated>2010-04-20T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/how-to-use-the-distributed-numeric-assignment-dna-plug-in-in-389-directory-server/"/>
        <id>https://blog.dark.ca/posts/how-to-use-the-distributed-numeric-assignment-dna-plug-in-in-389-directory-server/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/how-to-use-the-distributed-numeric-assignment-dna-plug-in-in-389-directory-server/">&lt;p&gt;Hello everybody !  Today&#x27;s post is about the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;directory.fedoraproject.org&#x2F;wiki&#x2F;DNA_Plugin&quot;&gt;Distributed Numeric Assignment&lt;&#x2F;a&gt; (or « DNA » ) plug-in for the 389 Directory Server (also known as the Fedora, Red Hat, and CentOS Directory Servers).  Although this plug-in has existed for quite some, there isn&#x27;t a whole lot of documentation about how to implement it in a real-world scenario.  I recently submitted some documentation to the maintainer of the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;directory.fedoraproject.org&#x2F;wiki&#x2F;Documentation&quot;&gt;389 wiki&lt;&#x2F;a&gt;, but since i&#x27;m not sure how, when, or in what form that documentation will come to exist on their site, i thought i&#x27;d expand on it here as well.  If you&#x27;ve made it this far, i&#x27;m going to assume that you&#x27;re already familiar with the basics of LDAP, and already have an instance of Directory Server up and running - if not, i suggest you take a look through the official &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.redhat.com&#x2F;docs&#x2F;manuals&#x2F;dir-server&#x2F;8.1&#x2F;install&#x2F;index.html&quot;&gt;Red Hat documentation&lt;&#x2F;a&gt; in order to get you started.
By way of some background, it is worth noting that my basic requirement was simply to have a centralised back-end for authenticating SSH logins to the various machines in our park.  The actual numerical values for the UID and GID fields did not need to be the same, they simply needed to be both extant and unique for each user, with the further caveat that they should not collide with any existing values that might be defined locally on the machines.  This is a very basic set of requirements, so it is an excellent starting point for our example.  The first step is to activate the DNA plug-in via the console :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;TAB&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; Servers and Applications&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Domain&lt;&#x2F;span&gt;&lt;span&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Server&lt;&#x2F;span&gt;&lt;span&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Server Group&lt;&#x2F;span&gt;&lt;span&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Directory Server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;SECTION&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; Configuration&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Server&lt;&#x2F;span&gt;&lt;span&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Plug-ins&lt;&#x2F;span&gt;&lt;span&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Distributed Numeric Assignment&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;X&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; Enable plug-in&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Save&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Directory Server needs to be restarted in order for the activation to take effect.  This can either be done via the console, or via the command-line as normal.  The next step is to define how DNA will interact with new user data ; this is different from configuring the plug-in itself, in that we will be setting up a layer in between the plug-in and the user data that will allow certain values to be generated automatically (which is, of course, the end goal of this exercise).  Consider the following two LDIF snippets :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# uids&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dn:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cn=UID numbers,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;objectClass:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; top&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;objectClass:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; extensibleObject&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cn:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; UID numbers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnatype:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; uidNumber&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnamagicregen:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 99999&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnafilter:&lt;&#x2F;span&gt;&lt;span&gt; (objectclass=posixAccount))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnascope:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dc=example,dc=com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnanextvalue:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# gids&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dn:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cn=GID numbers,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;objectClass:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; top&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;objectClass:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; extensibleObject&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cn:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; GID numbers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnatype:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gidNumber&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnamagicregen:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 99999&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnafilter:&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;objectclass&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;posixAccount&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;objectclass&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;posixGroup&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnascope:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dc=example,dc=com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dnanextvalue:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As you can see, they are nearly identical.  This configuration activates the DNA magic-number functionality for the UID and GID fields as shown in the Posix attributes section of the console, though the values used may require further explanation.  The only particular requirement for the magic number (specified by the « dnamagicregen » field) is that it be a value that cannot occur naturally, which is to say a value that would not be generated by the DNA plug-in, nor set manually at any time.  The default value is « 0 », but since this is clearly a number with meaning on the average Posix system, i would recommend a suitably large number that is unlikely to ever be used, such as « 99999 ».  Non-numerical values can technically be used too ; however, these will not be acceptable to the console, so unless you&#x27;re using a third-party interface (or doing everything from the commandline), a numerical value must be used.
The « dnanextvalue » field functionally indicates where the count will start from.  As noted previously, in order to avoid collisions with existing local entries on the various machines, i chose a start point of « 1000 », which was more than acceptable in my environment.  Once these two snippets are integrated via the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.ca&#x2F;search?q=ldapmodify&quot;&gt;commandline&lt;&#x2F;a&gt;, simply re-start the Directory Server (again), and you&#x27;re good to go  From now on, any time that a new user is created with the value « 99999 » entered into either (or both) of the UID and GID Posix fields, DNA will automagically generate real values as appropriate.
Hope that helps - enjoy !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>CPAN RPMs in RHEL &#x2F; CentOS : generation, conflict, and solutions</title>
        <published>2010-04-08T00:00:00+00:00</published>
        <updated>2010-04-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/cpan-rpms-in-rhel-centos/"/>
        <id>https://blog.dark.ca/posts/cpan-rpms-in-rhel-centos/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/cpan-rpms-in-rhel-centos/">&lt;p&gt;Hello all !  Today we&#x27;re going to take a look at a somewhat obscure problem that - once encountered - can cause nothing but headaches for a system administrator.  The problem relates to conflicts in CPAN RPM packages, and what can be done to work around the issue.  If you&#x27;ve made it this far, i&#x27;m going to assume a couple of things : you&#x27;re comfortable with RPMs and repositories, have worked with a .spec file before, and you know what Perl modules are.  Good ?  Ok, let&#x27;s go.
&lt;em&gt;Edit : About a week after i posted this article, the pastebin i uploaded the examples to disappeared.  Maybe it will come back - i don&#x27;t know - but if not, sorry for the broken links...&lt;&#x2F;em&gt;
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.cpan.org&#x2F;&quot;&gt;CPAN&lt;&#x2F;a&gt; is an enormous collection of Perl modules.  If you&#x27;ve ever written a Perl script, there&#x27;s a good chance you&#x27;ve used a module that - at one point or another - came from this archive.  One of the really neat features of CPAN is the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;search.cpan.org&#x2F;~jhi&#x2F;perl-5.8.0&#x2F;lib&#x2F;CPAN.pm#Interactive_Mode&quot;&gt;interactive manner&lt;&#x2F;a&gt; in which modules can be downloaded and installed from the archive using Perl right from the command line (frankly, if you&#x27;re reading this post, there&#x27;s a good chance you&#x27;ve used this feature, too).  This is a fairly common way to install new modules and add functionality to your system, especially if you&#x27;re coding for local use (i.e. on your personal box).
It&#x27;s useful, but it&#x27;s not perfect, and one of the key areas where it starts to fail is scalability : if you&#x27;ve got a bunch of machines, and you need to SSH into each one to interactively install a CPAN module or two, it&#x27;s going to be a hassle.  Likewise, CPAN doesn&#x27;t often find its way into the hearts and minds of enterprise Red Hat or CentOS environments, where the official policy is often to install software via RPM only (for support, administration, and sanity reasons, this is often the case).
Luckily, some of the most commonly used CPAN modules exist as RPMs in the default repositories.  Some, but not all (and not even « many ») - for this, there are other repositories available.  Some examples :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;fedoraproject.org&#x2F;wiki&#x2F;EPEL&quot;&gt;EPEL&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;dag.wieers.com&#x2F;rpm&#x2F;&quot;&gt;Dag&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;rpmrepo.org&#x2F;RPMforge&#x2F;&quot;&gt;RPMForge&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;rpm.mag-sol.com&#x2F;&quot;&gt;Magnum Solutions&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;That last one - Magnum - is particularly interesting given the subject of our post today.  From their info page :&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;At Magnum we have a firm rule that all CPAN modules on our machines are installed from RPMs. The Fedora and Centos projects build RPMs for many CPAN modules, but there are always ones missing and the ones that are available often lag behind the most up to date versions.  For that reason, we build a lot of RPMs of CPAN modules. And we don&#x27;t want to keep that work to ourselves, so on these pages we make them available for anyone to download.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Their RPMs are generated automagically using a great tool called « cpanspec », which does exactly what you think it does : given a CPAN tarball, it will generate a .spec file suitable for building an installable RPM.  It is available in the standard repositories, and can be installed easily via YUM as normal, so go ahead and do that now.  Ok, example time : say you needed HTML::Laundry, but after a quick peek through your repositories, it becomes readily apparent that an RPM is not available.  Thanks to cpanspec, all is not lost :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;build@host-119 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;$ wget http:&#x2F;&#x2F;search.cpan.org&#x2F;CPAN&#x2F;authors&#x2F;id&#x2F;S&#x2F;ST&#x2F;STEVECOOK&#x2F;HTML-Laundry-0.0103.tar.gz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;build@host-119 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;$ cpanspec --packager &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;build &amp;lt;build@domain.ext&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; HTML-Laundry-0.0103.tar.gz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We just downloaded the tarball right from the CPAN website, and ran cpanspec against it.  The « --packager » argument simple defines the person who&#x27;s generating the .spec, and doesn&#x27;t necessarily have to be anything accurate.  Go ahead and try it for yourself.  Now take a look at the resulting .spec file (or on the a pastebin &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;pastebin.ca&#x2F;1858756&quot;&gt;here&lt;&#x2F;a&gt;).  As you can see, it fills in all the fields, including the critical (and often tricky-to-determine) « BuildRequires » and « Requires » items.  Frankly, it&#x27;s solid gold, and it has made the lives of CentOS &#x2F; RHEL admins all over the world much easier.
That said, it&#x27;s not perfect, and there are times when you might run into problems.  Actually, you may run into two problems in particular.  The first is conflicts over ownership, which arises when multiple RPMs claim to be responsible for the same file (or files, or directories, or features, or whatever).  The second is more nefarious : an RPM that writes files to the system without declaring ownership for them - a condition often referred to as « clobbering ».  The former is irritating, but at least it&#x27;s not destructive, unlike the latter, which can cause all manner of headaches.  To illustrate these two problems, let&#x27;s take a look at another example (this one being decidedly more real-world than that of Laundry above) : &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;search.cpan.org&#x2F;dist&#x2F;CGI.pm&#x2F;lib&#x2F;CGI.pm&quot;&gt;CGI.pm&lt;&#x2F;a&gt;.
The &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;pastebin.ca&#x2F;1858885&quot;&gt;.spec file&lt;&#x2F;a&gt; that is generated from this tarball is functional and correct, and we can build an installable RPM out of it, so at first all appears well.  Again, go ahead and try for yourself - i&#x27;ll wait.  You may wish to capture the build output for review - otherwise, check the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;pastebin.ca&#x2F;1858890&quot;&gt;pastebin&lt;&#x2F;a&gt;.  I&#x27;d like to draw your attention to the « Installing » lines.  By trimming the « Installing &#x2F;var&#x2F;tmp&#x2F;perl-CGI.pm.3.49-1-root-root » element from each of those lines, we can see the actual paths and files that this RPM will install to.  Examples :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;lib&#x2F;perl5&#x2F;vendor_perl&#x2F;5.8.8&#x2F;CGI.pm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;lib&#x2F;perl5&#x2F;vendor_perl&#x2F;5.8.8&#x2F;CGI&#x2F;Cookie.pm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;lib&#x2F;perl5&#x2F;vendor_perl&#x2F;5.8.8&#x2F;CGI&#x2F;Util.pm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;share&#x2F;man&#x2F;man3&#x2F;CGI.3pm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;share&#x2F;man&#x2F;man3&#x2F;CGI::Pretty.3pm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;share&#x2F;man&#x2F;man3&#x2F;CGI::Cookie.3pm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At first glance this looks perfectly acceptable.  But look what happens when we try to install the resulting RPM (clipped for brevity) :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host-119 build&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# rpm -iv &#x2F;usr&#x2F;src&#x2F;redhat&#x2F;RPMS&#x2F;noarch&#x2F;perl-CGI.pm-3.49-1.noarch.rpm&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Preparing&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; packages for installation...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;file&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;usr&#x2F;share&#x2F;man&#x2F;man3&#x2F;CGI.3pm.gz from install of perl-CGI.pm-3.49-1.noarch conflicts with file from package perl-5.8.8-27.el5.x86_64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;file&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;usr&#x2F;share&#x2F;man&#x2F;man3&#x2F;CGI::Cookie.3pm.gz from install of perl-CGI.pm-3.49-1.noarch conflicts with file from package perl-5.8.8-27.el5.x86_64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;file&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;usr&#x2F;share&#x2F;man&#x2F;man3&#x2F;CGI::Pretty.3pm.gz from install of perl-CGI.pm-3.49-1.noarch conflicts with file from package perl-5.8.8-27.el5.x86_64&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As it turns out, the Perl package that comes with RHEL &#x2F; CentOS already contains CGI.pm.  This is normal, since it&#x27;s so popular, and is included as a convenience.  Thus, RPM - in an attempt to preserve the coherence of the package management system - refuses to install overtop of the existing owned files.  This is a fine illustration of the first of the two problems previously noted : conflicts over ownership.  As i mentioned above, it&#x27;s aggravating, but it&#x27;s not a bug - it&#x27;s a feature, and it&#x27;s doing exactly what it&#x27;s designed to do.  Irritating, but not ultimately dire.
If you look carefully, though, it&#x27;s also an illustration of the second problem.  Note the list of files that are conflicting.  Look back to the list of files that the package contains - notice anything missing from the conflicts list ?  That&#x27;s right - the actual module files (*.pm) are not showing conflicts, which means they&#x27;d get overwritten without complaint by RPM.  You might be thinking « who cares ? that&#x27;s what i want » right now, but trust me, it&#x27;s not what you want.  Imagine this CGI package, with this version of CGI.pm gets installed, and then later you upgrade the Perl package - your CGI.pm files will get overwritten by the Perl package, because as far as RPM is concerned, Perl owns those files.  All of a sudden, things break because you had scripts that relied on your particular version, but since you just upgraded Perl, you think (quite naturally) that the problem could be anywhere - where do you even start looking ?
Imagine the headache if there are multiple administrators, multiple servers, multiple data centres, and multiple clients paying multiple dollars.  No fun at all.
So how can we upgrade CGI.pm, using an RPM, without running into these problems ?  As is often the case, the answer is deceptively simple, but not immediately obvious.  Ultimately what we want to accomplish is twofold :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Avoid the man conflicts.&lt;&#x2F;li&gt;
&lt;li&gt;Ensure that the existing owned module files are not clobbered by our new package.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Concerning the man pages - and i&#x27;m going to be perfectly blunt here - the solution is to simply not install them, since, of course, they&#x27;re already there.  As for avoiding a clobbering condition, this requires a little bit of investigation into how Perl modules and libraries are stored on an RHEL &#x2F; CentOS machine.  Consider the following output :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host-119 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ls -d &#x2F;usr&#x2F;lib64&#x2F;perl5&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;lib64&#x2F;perl5&#x2F;5.8.8&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;usr&#x2F;lib64&#x2F;perl5&#x2F;site_perl  &#x2F;usr&#x2F;lib64&#x2F;perl5&#x2F;vendor_perl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What&#x27;s it all mean ?  Well, the « 5.8.8 » directory is the default directory as defined by the Perl architecture, and is system and platform-agnostic, which is to say that it&#x27;s (supposed to be) the same on every system.  The « vendor_perl » directory contains everything that specific to RHEL &#x2F; CentOS (the « vendor » of the distribution).  As you may recall from the rpmbuild output above, this is where the RPM wants to install the modules (thus creating the clobbering condition).
There&#x27;s a third directory there, promisingly named « site_perl » ; as the name implies, this is where site-specific files are stored, which is to say items that are neither part of the default Perl architecture, nor part of the RHEL &#x2F; CentOS distribution.  As you&#x27;ve no doubt guessed by now, site_perl is where we&#x27;re going to put our new modules.
Luckily for us, the only thing that needs to be changed is the .spec file - and we even get a headstart, since cpanspec does most of the heavy lifting for us.  Examining the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;pastebin.ca&#x2F;1858885&quot;&gt;.spec file&lt;&#x2F;a&gt; once more, we see the following lines of note (again, cut for brevity) :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;%build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{__perl} Makefile.PL INSTALLDIRS=vendor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;%files&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{perl_vendorlib}&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;These indicate that the target installation directory is that of the vendor, which is normally the case, and thus the default setting.  Since we want to install to the site directory, we make the following changes :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;%build&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{__perl} Makefile.PL INSTALLDIRS=site&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;%files&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;%&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{perl_sitelib}&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That solves our clobbering problem quite nicely, but what about the man files ?  As i mentioned above, the idea is to simply avoid installing them altogether, but since they&#x27;re generated automatically during the build process, how can we exclude them ?  What i&#x27;m about to present is a bit of a hack, but it&#x27;s absolutely effective, and ultimately quite clean : we delete them after they&#x27;ve been generated, and then don&#x27;t declare them in the file list.  Some items are already being potentially deleted by default, so let&#x27;s go ahead and add our own line into the mix :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;find&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $RPM_BUILD_ROOT&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -depth -type d -exec rmdir {}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; 2&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;dev&#x2F;null&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt; ;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# destroy manified man, man.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;find&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $RPM_BUILD_ROOT&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -type f -name&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;*.3pm&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -exec rm -f {}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt; ;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will look for all of the « manified » man files and just remove from the build tree.  All that&#x27;s left now is to remove them from the file list.  This is as simple as deleting (or commenting out) their sole declaration :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;#%{_mandir}&#x2F;man3&#x2F;*&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another option is to simply install use the « --excludedocs » argument when installing the RPM.  I opted to remove the docs altogether in order to ensure that the package can be installed without errors by anyone else without needed to know about the argument requirement ahead of time (and to facilitate automated rollouts).
What you&#x27;ll end up with is a .spec file that &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;pastebin.ca&#x2F;1858951&quot;&gt;looks like this&lt;&#x2F;a&gt;.  Go ahead and build your RPM - it&#x27;ll install without conflicts and without danger.  This is a technique that can be used for other CPAN packages as well, so go ahead and install everything you&#x27;ve always wanted.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>workaround for slow shared folders in Virtualbox 3.x</title>
        <published>2010-01-29T00:00:00+00:00</published>
        <updated>2010-01-29T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/workaround-for-slow-shared-folders-in-virtualbox-3-x/"/>
        <id>https://blog.dark.ca/posts/workaround-for-slow-shared-folders-in-virtualbox-3-x/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/workaround-for-slow-shared-folders-in-virtualbox-3-x/">&lt;p&gt;Happy 2010 fair readers !  I hope that all is well with you and yours.  Let&#x27;s get right to business : &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.virtualbox.org&#x2F;&quot;&gt;Virtualbox&lt;&#x2F;a&gt; has a feature that allows you to access the host OS&#x27;s file system from the guest OS (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.virtualbox.org&#x2F;manual&#x2F;UserManual.html#sharedfolders&quot;&gt;shared folders&lt;&#x2F;a&gt;), which is super useful, but not exactly perfectly implemented.  In particular, there are known, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.com&#x2F;search?q=virtualbox+shared+folder+slow&quot;&gt;documented performance issues&lt;&#x2F;a&gt; in certain scenarios, such as when accessing a Linux host via a Windows guest (which, as you might imagine, is a pretty regular sort of activity).
One common (?) workaround is to install and configure Samba on the Linux host, then access it from the Windows guest like one would access any network server.  The problem here is that it requires that Samba be installed and configured, which &lt;em&gt;can&lt;&#x2F;em&gt; be a pain in the, well, you know.  Furthermore, the connection will be treated like any other, and the traffic will travel up and down the network stack, which is fundamentally unnecessary since the data is, physically speaking, stored locally.
Instead, here&#x27;s another workaround, one that keeps things simple, &lt;em&gt;and&lt;&#x2F;em&gt; solves the performance problem : just map the shared folder to a local drive in the host OS.  It&#x27;s that easy.  For those of us who aren&#x27;t too familiar with the Windows explorer interface (me included, heh), there are tonnes of &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.com&#x2F;search?q=windows+map+shared+folder+to+local+drive&quot;&gt;step by step instructions&lt;&#x2F;a&gt; available.  For whatever reason (i suspect Netbios insanity), accessing the network share via a mapped drive manages to &lt;em&gt;avoid&lt;&#x2F;em&gt; whatever condition creates the lag problems, resulting in a rapid, efficient access to the underlying filesystem.
Hope that helps - enjoy !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>how to deal with broken time zones during a CentOS 5.3 kickstart</title>
        <published>2009-12-01T00:00:00+00:00</published>
        <updated>2009-12-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/how-to-deal-with-broken-time-zones-during-a-centos-5-3-kickstart/"/>
        <id>https://blog.dark.ca/posts/how-to-deal-with-broken-time-zones-during-a-centos-5-3-kickstart/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/how-to-deal-with-broken-time-zones-during-a-centos-5-3-kickstart/">&lt;p&gt;Hello again fair readers !  Today&#x27;s quick tip concerns the problem with missing time zones when deploying CentOS 5.3 (and some of the more recent Fedoras) in a kickstart environment.  It&#x27;s a &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;bugzilla.redhat.com&#x2F;show_bug.cgi?id=481617&quot;&gt;known problem&lt;&#x2F;a&gt;, and unfortunately, since the source of the problem (an incomplete time zone data file) lies deep in the heart of the kickstart environment, fixing it directly is a distinct pain in the buttock region.
There is, however, a workaround - and it&#x27;s not even that messy !  The first step is to use a region that &lt;em&gt;does&lt;&#x2F;em&gt; exist, such as « Europe&#x2F;Paris », which will satisfy the installer - then set the time zone to what you &lt;em&gt;actually&lt;&#x2F;em&gt; want after the fact in the « %post » section.  So, in the top section of the kickstart file, we&#x27;ll put :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# set temporarily to avoid time zone bug during install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;timezone&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --utc Europe&#x2F;Paris&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The « --utc » switch simply states that the &lt;em&gt;system&lt;&#x2F;em&gt; clock is in UTC, which is pretty standard these days, but ultimately optional.  Next, in the %post section towards the end, we&#x27;ll shoe horn our little hack fix into place :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# fix faulty time zone setting&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mv&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;sysconfig&#x2F;clock &#x2F;etc&#x2F;sysconfig&#x2F;clock.BAD&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;sed&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s@^ZONE=&amp;quot;Europe&#x2F;Paris&amp;quot;@ZONE=&amp;quot;Etc&#x2F;UTC&amp;quot;@&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;sysconfig&#x2F;clock.BAD&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;etc&#x2F;sysconfig&#x2F;clock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;sbin&#x2F;tzdata-update&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So, what&#x27;s going on there ?  Let&#x27;s break it down :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;In the first line, we&#x27;re just backing up the original configuration file, to use in the next line...&lt;&#x2F;li&gt;
&lt;li&gt;The second line is the important one - this is the actual manipulation which will fix the faulty time zone, setting it to whatever we want.  In this example « Etc&#x2F;UTC » is used, but you can pick whatever is appropriate.
&lt;ul&gt;
&lt;li&gt;The tool being used here is « sed », a non-interactive editor which dates back to the 1970&#x27;s, and which is still used by system administrators around the world every day.&lt;&#x2F;li&gt;
&lt;li&gt;The command we&#x27;re issuing to sed is between the single quotes - astute readers will notice that it&#x27;s a &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.com&#x2F;search?q=regular+expression+tutorial&quot;&gt;regular expression&lt;&#x2F;a&gt;, but with @&#x27;s instead of the more usual &#x2F;&#x27;s.  In it, we simply state that the instance of « ZONE=&quot;Europe&#x2F;Paris&quot; » is to be replaced with « ZONE=&quot;Etc&#x2F;UTC&quot; ».&lt;&#x2F;li&gt;
&lt;li&gt;This change is to be made against the backup file, and outputted to the actual config.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Finally, we run « tzdata-update » which, as you&#x27;ve no doubt guessed, updates the time zone data system-wide, based (in part) on the newly-corrected clock config.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And that, as they say, is that.  Happy kickstarting, friends, and i&#x27;ll see you next time !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>load balancing, or, « how i learned to love a piranha »</title>
        <published>2009-10-21T00:00:00+00:00</published>
        <updated>2009-10-21T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/load-balancing-or-how-i-learned-to-love-a-piranha/"/>
        <id>https://blog.dark.ca/posts/load-balancing-or-how-i-learned-to-love-a-piranha/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/load-balancing-or-how-i-learned-to-love-a-piranha/">&lt;p&gt;Hello again, everybody !  Today i thought that we&#x27;d take a look at a fun and useful topic of interest to many system administrators : load balancing &amp;amp; redundancy.  Now, i know, it doesn&#x27;t &lt;em&gt;sound&lt;&#x2F;em&gt; too exciting - but trust me, once you get your first mini-cluster set up, you&#x27;ll never look at service management quite the same way again.  It&#x27;s not even that tough to set up, and you can get a basic setup going in almost no time at all, thanks to some great open source software that can be found in more or less any modern repository.
First, as always, a little bit of theory.  The most basic web server setup (for example), looks something like figure 001, below :
[caption id=&quot;attachment_133&quot; align=&quot;alignnone&quot; width=&quot;243&quot; caption=&quot;Figure 001&quot;]&lt;img src=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;wordpress&#x2F;wp-content&#x2F;uploads&#x2F;2009&#x2F;09&#x2F;simple-web_server-no_lb.png&quot; alt=&quot;Figure 001&quot; title=&quot;simple-web_server-no_lb&quot; &#x2F;&gt;[&#x2F;caption]
As you can see, this is a functional setup, but it does have (at least) two major drawbacks :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;A critical failure on the web server means the &lt;em&gt;service&lt;&#x2F;em&gt; (i.e. the content being served) disappears along with it.&lt;&#x2F;li&gt;
&lt;li&gt;If the web server becomes overloaded, you may be forced to take the entire machine down to upgrade it (or just let your adoring public deal with a slow, unresponsive website, i suppose).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The solution to both of these problems forms the topic of this blog entry : &lt;em&gt;load balancing&lt;&#x2F;em&gt;.  The idea is straightforward enough : by adding more than one web server, we can ensure that our service continues to be available even when a machine fails, and we can also spread the love, er, load, across multiple machines, thus increasing our overall efficiency.  Nice !&lt;&#x2F;p&gt;
&lt;h3 id=&quot;batman-and-round-robin&quot;&gt;batman and round robin&lt;&#x2F;h3&gt;
&lt;p&gt;Now, there are a couple of ways to go about this, one of which is called « Round Robin DNS » (or RRDNS), which is both very simple and moderately useful.  &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Domain_Name_System&quot;&gt;DNS&lt;&#x2F;a&gt;, for those needing a refresher, is (in a nutshell) the way that human-readable hostnames get translated into machine-readable numbers.  Generally speaking, hostnames are tied to IP addresses in a &lt;em&gt;one-to-one&lt;&#x2F;em&gt; or &lt;em&gt;many-to-one&lt;&#x2F;em&gt; fashion, such that when you type in a hostname, you get a single number back.  For example :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; host www.dark.ca&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;www.dark.ca&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; has address&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 88.191.66.127&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In other words, when you type &lt;em&gt;www.dark.ca&lt;&#x2F;em&gt; into your browser, you get one particular machine on the Internet (as indicated by the address); however, it is also possible to set up a &lt;em&gt;one-to-many&lt;&#x2F;em&gt; relationship - this is the basis or RRDNS.  A very common example is Google :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; host www.google.com&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;www.google.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; is an alias for www.l.google.com.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;www.l.google.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; has address&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 74.125.39.99&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;www.l.google.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; has address&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 74.125.39.103&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;www.l.google.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; has address&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 74.125.39.104&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;www.l.google.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; has address&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 74.125.39.105&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;www.l.google.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; has address&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 74.125.39.106&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;www.l.google.com&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; has address&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 74.125.39.147&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;So what&#x27;s going on here ?  In essence, the Google administrators have created a situation whereby typing in &lt;em&gt;www.google.com&lt;&#x2F;em&gt; into your browser will get you one of a whole group of possibilities.  In this way, each time you request some content from them, one of any number of machines will be responsible for delivering that service.  (Now, to be fair, the &lt;em&gt;reality&lt;&#x2F;em&gt; of what&#x27;s going on at Google is likely far more complex, but the premise is identical.)  Your web browser will only get &lt;em&gt;one&lt;&#x2F;em&gt; answer back, which is more or less randomly provided by the DNS server, and that response is the machine you&#x27;ll interact with.  As you can see, this (sort of) satisfies our problem of resource usage, and it (sort of) addresses the problem resource failure.  For those of you who are more visually inclined, please see figure 002 below :
[caption id=&quot;attachment_137&quot; align=&quot;alignnone&quot; width=&quot;299&quot; caption=&quot;Figure 002&quot;]&lt;img src=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;wordpress&#x2F;wp-content&#x2F;uploads&#x2F;2009&#x2F;09&#x2F;rrdns.png&quot; alt=&quot;Figure 002&quot; title=&quot;rrdns&quot; &#x2F;&gt;[&#x2F;caption]
It&#x27;s not perfect, but it &lt;em&gt;is&lt;&#x2F;em&gt; workable, and most of all, it&#x27;s dead simple to set up - you just need to set your DNS configuration up and you&#x27;re good to go (an exercise i leave to you, fair reader, as RRDNS is not really the focus of our discussion today).  Thus, while RRDNS is a simple method for implementing a rudimentary load balancing infrastructure, it still has notable failings :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The load balancing isn&#x27;t systematic at all - by pure chance, one machine could end up getting hammered while others do very little, for example.&lt;&#x2F;li&gt;
&lt;li&gt;If a machine fails, there&#x27;s a chance that the DNS response will contain the address of the downed machine.  In other words, the chances of you getting the downed machine are 1 in X, where X is the number of possible responses to the DNS query.  The odds get better (or worse, depending on how you look at it) as more machines fail.&lt;&#x2F;li&gt;
&lt;li&gt;A slightly more obscure problem is that of response caching : as a method of optimisation, many DNS systems, as well as software that interacts with DNS, will &lt;em&gt;cache&lt;&#x2F;em&gt; (hold on to) hostname lookups for variable lengths of time.  This can invalidate the magic of RRDNS altogether...&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;another-attack-vector&quot;&gt;another attack vector&lt;&#x2F;h3&gt;
&lt;p&gt;Another approach to the problem, and the one we&#x27;ll be exploring in great depth in this article, is using a dedicated load balancing infrastructure, combining a handful of great open source tools and proven methodologies.  First, however, some more theory.
Our new approach to load balancing must propose both a solution to the original problems (critical failure &amp;amp; resource usage), as well as address and solve the drawbacks of RRDNS as noted above.  Really, what we want is an intelligent (or, at least, systematic) distribution of load across multiple machines, and a way to ensure that requests don&#x27;t get sent to downed machines by accident.  It&#x27;d be nice if these functions were automated too, since the last thing an administrator wants to do is baby-sit racks of servers.  What we&#x27;d like, in other words, could be represented by replacing the phrase « RRNDS » in figure 002 above, with the word « magic ».  For now, let&#x27;s imagine that this magic sits on a machine that we&#x27;ll call « Load Balancer » (or LB, for short), and that this LB machine would have a similar conceptual relationship to the web servers as RRDNS does.  Consider figure 003 :
[caption id=&quot;attachment_143&quot; align=&quot;alignnone&quot; width=&quot;299&quot; caption=&quot;Figure 003&quot;]&lt;img src=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;wordpress&#x2F;wp-content&#x2F;uploads&#x2F;2009&#x2F;09&#x2F;simple-web_server-lb.png&quot; alt=&quot;Figure 003&quot; title=&quot;simple-web_server-lb&quot; &#x2F;&gt;[&#x2F;caption]
This is a basic way of thinking about what&#x27;s going to happen.  It looks a lot like figure 002, but there is a very important difference : instead of relying on the somewhat nebulous concept of DNS for our load balancing, we can now give that responsibility to a proper machine running and dedicated to the purpose.  As you can imagine, this is already a huge improvement, since this opens the door to all sorts of additional features and possibilities that simply aren&#x27;t possible with straight DNS.  Another interesting aspect of this diagram is that, visually speaking, it would appear that the Internet cloud only « sees » one machine (the load balancer), even though there are a number of web servers behind it.  This concept of having a single point of entry lies at the very core of our strategy - both figuratively &lt;em&gt;and&lt;&#x2F;em&gt; &lt;em&gt;literally&lt;&#x2F;em&gt; - as we&#x27;ll soon discover
In the here and now, however, we&#x27;re still dealing with theory, and a solution based on « magic » is about as theoretical as it gets. Luckily for us though, magic is &lt;em&gt;exactly&lt;&#x2F;em&gt; what we&#x27;re about to unleash - in the form of « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.linuxvirtualserver.org&#x2F;&quot;&gt;Linux Virtual Server&lt;&#x2F;a&gt; », or « LVS » for short.  From their homepage :&lt;&#x2F;p&gt;
&lt;p&gt;The Linux Virtual Server is a highly scalable and highly available server built on a cluster of real servers, with the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;kb.linuxvirtualserver.org&#x2F;wiki&#x2F;Load_balancer&quot;&gt;load balancer&lt;&#x2F;a&gt; running on the Linux operating system. The architecture of the server cluster is fully transparent to end users, and the users interact as if it were a single high-performance virtual server. [...] The Linux Virtual Server as an advanced load balancing solution can be used to build highly scalable and highly available network services, such as scalable web, cache, mail, ftp, media and VoIP services.&lt;&#x2F;p&gt;
&lt;p&gt;The thing about LVS is that while it&#x27;s not inherently complex, it is highly malleable, and this means you really do need to have a solid handle on exactly &lt;em&gt;what&lt;&#x2F;em&gt; you want to do, and &lt;em&gt;how&lt;&#x2F;em&gt; you want to do it, before you start playing around.  Put another way, there are a myriad of ways to use LVS, but you&#x27;ll only use one of them at a time, and picking the right methodology is important.  The best way to do this is by building maps and really getting a solid feel for how the various components of the overall architecture relate to each other.  Once you&#x27;ve got a good mental idea of what things should look like, actually configuring LVS is about as straightforward as it gets (no, really!).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;let-s-complicate-the-issue-further-for-science&quot;&gt;let&#x27;s complicate the issue further, for science !&lt;&#x2F;h3&gt;
&lt;p&gt;Looking back to figure 003, we can see that our map includes the Internet, the Load Balancer, and some Web Servers.  This is a pretty typical sort of setup, and thus, we can approach it from a few different ways.  One of the decisions that needs to be made fairly early on, though, has more to do with topology and routing than LVS specifically : how, exactly, do the objects on the map relate to each other at a network level ?  As always, there can be lots of answers to this question - each with their advantages and disadvantages - but ultimately we must pick only one.  Since i value &lt;em&gt;simplicity&lt;&#x2F;em&gt; when it comes to technology, figure 004 describes a simple network topology :
[caption id=&quot;attachment_147&quot; align=&quot;alignnone&quot; width=&quot;358&quot; caption=&quot;figure 004&quot;]&lt;img src=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;wordpress&#x2F;wp-content&#x2F;uploads&#x2F;2009&#x2F;09&#x2F;dr-network_map.png&quot; alt=&quot;figure 004&quot; title=&quot;dr-network_map&quot; &#x2F;&gt;[&#x2F;caption]
Now, for those of you out there who may have some experience with LVS, you can see exactly where this is headed - for everybody else, this might not be what you were expecting at all.  Let&#x27;s take a look at some of the more obvious points :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;There are two load balancers.&lt;&#x2F;li&gt;
&lt;li&gt;The web servers are on the same network segment as the LBs.&lt;&#x2F;li&gt;
&lt;li&gt;Unlike the previous diagrams, the LBs do not appear to be « in between » the Internet and the web servers.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The first point is easy  : there are two LBs for reasons of redundancy, as a single LB represents a single point of failure.  In other words, if the LB stops working for whatever reason, all of your services behind it become functionally unavailable, thus, you really, &lt;em&gt;really&lt;&#x2F;em&gt; want to have another machine ready to go immediately following a failure.
A little bit more explanation is required to explain the second and third points - but the short answer is two words : « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;kb.linuxvirtualserver.org&#x2F;wiki&#x2F;LVS&#x2F;DR&quot;&gt;Direct Routing&lt;&#x2F;a&gt; » (or DR for short).  From the LVS wiki :&lt;&#x2F;p&gt;
&lt;p&gt;Direct Routing [is] an IP load balancing technology implemented in LVS. It directly routes packets to backend server through rewriting MAC address of data frame with the MAC address of the selected backend server. It has the best scalability among all other methods because the overhead of rewriting MAC address is pretty low, but it requires that the load balancer and the backend servers (real servers) are in a physical network.&lt;&#x2F;p&gt;
&lt;p&gt;If that sounds heavy, don&#x27;t worry - figure 005 explains it in easy visual form :
&lt;img src=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;wordpress&#x2F;wp-content&#x2F;uploads&#x2F;2009&#x2F;09&#x2F;dr-logic.png&quot; alt=&quot;figure 005&quot; title=&quot;dr-logic&quot; &#x2F;&gt;
In a nutshell, requests get sent to the LB, which then passes it to the Web Server, who in turn responds directly to the client.  It&#x27;s fast, efficient, scalable, and easy to set up, with the only caveat being that the LBs and the machines they&#x27;re balancing &lt;em&gt;must&lt;&#x2F;em&gt; be &lt;em&gt;on the same network&lt;&#x2F;em&gt;.  As long as you&#x27;re willing to accept that restriction, Direct Routing is an excellent choice - and it&#x27;s the one we&#x27;ll be exploring further today.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-little-less-conversation-a-little-more-action&quot;&gt;a little less conversation, a little more action&lt;&#x2F;h3&gt;
&lt;p&gt;So with that in mind, let&#x27;s get started.  I&#x27;m going to be describing four machines in the following scenario.  All four are identical off-the-shelf servers running CentOS 5.2 - nothing fancy here.  The naming and numbering conventions are simple as well :
&lt;strong&gt;[TABLE=2]&lt;&#x2F;strong&gt;
You probably noticed the fifth item in this list, labelled « Virtual Web Server ».  This represents our &lt;em&gt;virtual&lt;&#x2F;em&gt;, or &lt;em&gt;clustered&lt;&#x2F;em&gt; service, and is not a real machine.  This will be explained in further detail later on - for now, let&#x27;s go ahead and install the key software on &lt;strong&gt;both&lt;&#x2F;strong&gt; of the Load Balancer machines :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@A01 etc&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# yum install ipvsadm piranha httpd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;« ipvsadm » is, as you might have guessed, the administrative tool for « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.linuxvirtualserver.org&#x2F;software&#x2F;ipvs.html&quot;&gt;IPVS&lt;&#x2F;a&gt; », which is in turn an acronym for « Internet Protocol Virtual Server », which makes more sense when you say « IP-based Virtual Server » instead.  As the name implies, IPVS is implemented at the IP level (which is more generically known as Layer-3 of the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;OSI_model&quot;&gt;OSI model&lt;&#x2F;a&gt;), and is used to spread incoming connections to one IP address towards other IP addresses according to one of many pre-defined methods.  It&#x27;s the tool that allows us to control our new load balancing infrastructure, and is the key software component around which this entire exercise revolves.  It is powerful, but sort of a pain to use, which brings us to the second item in the list : piranha.
Piranha is a web-based tool (hence httpd, above) for administering LVS, and is effectively a front-end for ipvsadm.  As installed in CentOS, however, the Piranha package contains not only the PHP pages that make up the interface, but also a handful of other tools of particular interest and usefulness that we&#x27;ll take a look at as well.  For now, let&#x27;s continue with some basic setup and configuration.
A quick word of warning : &lt;em&gt;before&lt;&#x2F;em&gt; starting « piranha-gui » (one of the services supplied by Piranha) up for the first time, it&#x27;s important that both LBs have the &lt;em&gt;same time&lt;&#x2F;em&gt; set on them.  You&#x27;ve probably already got &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;NTP&quot;&gt;NTP&lt;&#x2F;a&gt; installed and functioning, but if not, here&#x27;s a hint :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@A01 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# yum -y install ntp &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; ntpdate&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pool.ntp.org&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; chkconfig&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ntpd on&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; service&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; start ntpd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Moving right along, the next step is to define a login for the Piranha web interface :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@A01 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# &#x2F;usr&#x2F;sbin&#x2F;piranha-passwd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You can define multiple logins if you like, but for now, one is certainly enough.  Now, unless you plan to run your load balanced infrastructure on a completely internal network, you&#x27;ll probably want to set up some basic restrictions on who can access the interface.  Since the interface is served via an instance of &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;httpd.apache.org&#x2F;&quot;&gt;Apache HTTPd&lt;&#x2F;a&gt;, all we have to do is set up a normal « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;httpd.apache.org&#x2F;docs&#x2F;2.0&#x2F;howto&#x2F;htaccess.html&quot;&gt;.htaccess&lt;&#x2F;a&gt; » file.  Now, a full breakdown of .htaccess (and, in particular, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;httpd.apache.org&#x2F;docs&#x2F;2.0&#x2F;mod&#x2F;mod_access.html&quot;&gt;mod_access&lt;&#x2F;a&gt;) is outside of the scope of this document, but the simple jist is as follows :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@A01 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cat &#x2F;etc&#x2F;sysconfig&#x2F;ha&#x2F;web&#x2F;secure&#x2F;.htaccess&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Order&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; deny,allow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Deny&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; from all&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;              # by default, deny from everybody&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Allow&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; from&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 192.168.0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;       # requests from this network are allowed&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With those items out of the way, we can now activate piranha-gui :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@A01 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# chkconfig piranha-gui on &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; service&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; piranha-gui start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Congratulations !  The interface is now running on port 3636, and can be accessed via your browser of choice - in the case of our example, it&#x27;d be « http:&#x2F;&#x2F;A01:3636&#x2F; ».  The username for the web login is « piranha », and the password is the one we set above.  Now that we&#x27;re logged in, let&#x27;s take a look at the interface in greater depth.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;look-out-piranhas&quot;&gt;look out - piranhas !&lt;&#x2F;h3&gt;
&lt;p&gt;The first screen - known as the « Control » page - is a summary of the current state of affairs.  Since nothing is configured or even active, there isn&#x27;t a lot to see right now.  Moving on to the « Global Settings » tab, we have our first opportunity to start putting some settings into place :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Primary server public IP : Put the IP address of the « primary » LB.  In this example, we&#x27;ll put the IP of A01.&lt;&#x2F;li&gt;
&lt;li&gt;Private server public IP : If we &lt;em&gt;weren&#x27;t&lt;&#x2F;em&gt; using direct routing, this field would need a value.  In our example, therefore, it should be empty.&lt;&#x2F;li&gt;
&lt;li&gt;Use network type : Direct Routing (of course!)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;On to the « Redundancy » tab :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Redundant server public IP : Put the IP address of the « secondary » LB.  In this example, we&#x27;ll put the IP of A02.&lt;&#x2F;li&gt;
&lt;li&gt;Syncdaemon : Optional and useful - but know that it requires additional configuration in order to make it work.
&lt;ul&gt;
&lt;li&gt;This feature (which is &lt;em&gt;relatively&lt;&#x2F;em&gt; new to LVS) ensures that the state information (i.e. connections, etc..) are shared with the secondary in the event that a failover occurs.  For more information, please see &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.austintek.com&#x2F;LVS&#x2F;LVS-HOWTO&#x2F;HOWTO&#x2F;LVS-HOWTO.server_state_sync_demon.html&quot;&gt;this page&lt;&#x2F;a&gt; from the LVS Howto.&lt;&#x2F;li&gt;
&lt;li&gt;It is &lt;em&gt;not&lt;&#x2F;em&gt; necessary, strictly speaking, so we can just leave it unchecked for now.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Under the « Virtual Servers » tab, let&#x27;s go ahead and click « Add », then select the new unconfigured entry and hit « Edit » :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Name : This is an arbitrary identifier for a given clustered service.  For our example, we&#x27;d put « WWW ».&lt;&#x2F;li&gt;
&lt;li&gt;Application Port : The port number for the service - HTTP runs on port 80, for example.&lt;&#x2F;li&gt;
&lt;li&gt;Protocol : TCP or UDP - this is normally TCP.&lt;&#x2F;li&gt;
&lt;li&gt;Virtual IP Address : This is the IP address of the &lt;em&gt;virtual&lt;&#x2F;em&gt; service (VIP), which you may recall from the table above.  This is the IP address that clients will send requests to, regardless of the &lt;em&gt;real&lt;&#x2F;em&gt; IP addresses (RIP) of the &lt;em&gt;real&lt;&#x2F;em&gt; servers which are responsible for the service.  In our example, we&#x27;d put 192.168.0.40 .
&lt;ul&gt;
&lt;li&gt;Each service that you wish to cluster needs a &lt;em&gt;unique&lt;&#x2F;em&gt; « address : port » pairing.  For example, 192.168.0.40:80 could be a web service, and 192.168.0.40:25 would likely be a mail service, but if you wanted to run &lt;em&gt;another, separate&lt;&#x2F;em&gt; web service, you&#x27;d need to assign a different virtual IP.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Virtual IP Network Mask : Normally this is 255.255.255.255, indicating a &lt;em&gt;single&lt;&#x2F;em&gt; IP address (the Virtual IP Address above).
&lt;ul&gt;
&lt;li&gt;You can actually cluster subnets, but this is outside of the scope of this tutorial.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Device : The Virtual IP address needs to be assigned to a « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.fr&#x2F;search?q=virtual+network+interface&quot;&gt;virtual network interface&lt;&#x2F;a&gt; », which can be named more or less anything, but generally follows the format « ethN:X », where N is the physical device, and X is an incremental numeric identifier.  For example, if your physical interface is « eth0 », and this is the &lt;em&gt;first&lt;&#x2F;em&gt; virtual interface, then it would be named « eth0:1 ».
&lt;ul&gt;
&lt;li&gt;If and when you set up multiple virtual interfaces, it is important to &lt;strong&gt;not&lt;&#x2F;strong&gt; mix these up.  Piranha has no facility for sanity checking these identifiers, so you may wish to track them yourself in a &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;docs.google.com&#x2F;&quot;&gt;Google document&lt;&#x2F;a&gt; or something.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Scheduling : There are a number of options here, and some are &lt;em&gt;very&lt;&#x2F;em&gt; different from one another.  For the purposes of this exercise, we&#x27;ll pick a simple, yet relatively effective scheduler called « Least-Connections ».
&lt;ul&gt;
&lt;li&gt;This does exactly what it sounds like : when a new request is made to the virtual service, the LB will check to see how many connections are open to each of the real servers in the cluster, and then route the connection to the machine with the &lt;em&gt;least&lt;&#x2F;em&gt; connections.  Congrats, you&#x27;ve now got load balancing !&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Finally, let&#x27;s add some real servers into the cluster.  From the « Edit » screen we&#x27;re already in, click on the « Real Server » sub-tab.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Name : This is the hostname of the real server.  In our example, we&#x27;d put B01.&lt;&#x2F;li&gt;
&lt;li&gt;Address : The IP address of the real server.  In our example, for B01, we&#x27;d put 192.168.0.38 .&lt;&#x2F;li&gt;
&lt;li&gt;Port : Generally speaking this can be left empty, as it will inherit the Port value defined in the virtual service (in this case, 80).
&lt;ul&gt;
&lt;li&gt;A value would be required here if your real server is running the service on a &lt;em&gt;different&lt;&#x2F;em&gt; port than that specified in the virtual service ; if your real server is running a web service on port 8080 instead of 80, for example.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Weight : Despite the name, this value is used in various different ways depending on which Scheduler you selected for the virtual service.  In our example, however, this field is irrelevant, and can be left empty.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;You can apply and add as many real servers as you like, one at a time, in this fashion.  Go ahead and set up B02 (or whatever your equivalent is) now.
If you&#x27;re wondering when the &lt;em&gt;secondary&lt;&#x2F;em&gt; LB is going to be configured, well, wonder no longer : the future is now.  Luckily, this step is very, very easy.  From the secondary :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@A02 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# scp root@A01:&#x2F;etc&#x2F;sysconfig&#x2F;ha&#x2F;lvs.conf &#x2F;etc&#x2F;sysconfig&#x2F;ha&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;now-is-a-good-time-to-grab-a-beer&quot;&gt;now is a good time to grab a beer&lt;&#x2F;h3&gt;
&lt;p&gt;Phew !  That was a lot of work.  After consuming a suitable refreshment, let&#x27;s move on to the final few steps.  Earlier i mentioned that there were some other items that we&#x27;d need to learn about besides the Piranha interface - « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.redhat.com&#x2F;support&#x2F;wpapers&#x2F;piranha&#x2F;x32.html&quot;&gt;Pulse&lt;&#x2F;a&gt; » is one such item.  Pulse, as a tool, is in the same family as some other tools you may have heard of, such as « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.linux-ha.org&#x2F;&quot;&gt;Heartbeat&lt;&#x2F;a&gt; », « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.keepalived.org&#x2F;&quot;&gt;Keepalived&lt;&#x2F;a&gt; », or « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.openais.org&#x2F;doku.php&quot;&gt;OpenAIS&lt;&#x2F;a&gt; ».
The basic idea of all of these tools is simple : to provide a « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Failover&quot;&gt;failover&lt;&#x2F;a&gt; » facility between a group of two or more machines.  In our example, our primary LB is the one that is normally active, but in the case that it fails for some reason, we&#x27;d like our secondary to click in and take over the responsibilities of the unavailable primary - this is what Pulse does.  Each of the load balancers runs an instance of « pulse » (the executable, not the package), which behaves in this fashion :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Each LB sends out a broadcast packet (a pulse, as it were) stating that they are alive.  As long as the active LB (commonly the primary) continues to announce itself, everybody is happy and nothing changes.&lt;&#x2F;li&gt;
&lt;li&gt;If, however, the inactive LB (commonly the secondary) server notices that it hasn&#x27;t seen any pulses from the active LB lately, it assumes that the active LB has failed.&lt;&#x2F;li&gt;
&lt;li&gt;The secondary, formerly inactive LB, then becomes active.  This state is maintained until such a time as the primary starts announcing itself again, at which point the secondary demotes itself back to inactivity.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The difference between the active and the inactive server is actually very simple : the active server is the one with the virtual addresses assigned to it (remember those, from the Virtual Servers tab in Piranha?).
Let&#x27;s go ahead of start it up (on the primary LB first, then on the secondary) :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@A01 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# chkconfig --add pulse&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@A01 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# service pulse start&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;an-internet-ballgame-drama-in-5-parts&quot;&gt;an internet ballgame drama - in 5 parts&lt;&#x2F;h3&gt;
&lt;p&gt;You may have noticed that we haven&#x27;t even touched the « real » servers (i.e. the web servers) yet.  Now is the time.  As it so happens, there&#x27;s only one major step that relates to the real servers, but it&#x27;s a very, very important one : defining VIPs, and then ensuring that the web servers are OK with the routing voodoo that we&#x27;re using to make this whole load balancing infrastructure work.  The solution is simple, but the &lt;em&gt;reason&lt;&#x2F;em&gt; for the solution may not be immediately obvious - for that, we need to take a look at the IP layer of each packet (neat!).  First, though, let&#x27;s run through a series of little stories :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Alice has a ball that she&#x27;d like to pass to Bob, so she tosses it his way.&lt;&#x2F;li&gt;
&lt;li&gt;Bob catches the ball, sees that it&#x27;s from Alice, and throws it back at her.  What great fun !&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Now imagine that Alice and Bob are hanging out with a few hundred million of their closest friends - but they still want to play ball.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Alice writes Bob&#x27;s name on the ball, who then passes it to somebody else, and so forth.&lt;&#x2F;li&gt;
&lt;li&gt;Eventually the ball gets passed to Bob.  Unfortunately for Bob, he has no idea where it came from, so he can&#x27;t send it back.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The solution is obvious :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Alice writes « From : Alice, To : Bob » on the ball, the passes it along.&lt;&#x2F;li&gt;
&lt;li&gt;Bob gets the ball, and switches the names around so that it says « From : Bob, To : Alice », and sends it back.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;OK, so, those were some nice stories, but how do they apply to our Load Balancing setup ?  As it turns out, all we need to do is throw in &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.fr&#x2F;search?q=the+internet+is+a+series+of+tubes&quot;&gt;some tubes&lt;&#x2F;a&gt;, and we&#x27;ve described one of the basic functions of the Internet Protocol - that the source and destination IP addresses of a given packet are part of the IP layer of said packet.  Let&#x27;s complicate it by one more level :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Alice prepares the ball as above, and send it flying.&lt;&#x2F;li&gt;
&lt;li&gt;Bob gets the ball, who&#x27;s been avoiding Alice since things got weird at the bar last week-end, passes it along to Charles.&lt;&#x2F;li&gt;
&lt;li&gt;Charles - who&#x27;s had a not-so-secret crush on Alice since high school - happily writes « From : Charles, To : Alice », and tosses it away.&lt;&#x2F;li&gt;
&lt;li&gt;Alice receives the ball, but much to her surprise, it&#x27;s from Charles, and not Bob as she expected. &lt;em&gt;Awkward !&lt;&#x2F;em&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;With that last story in mind, let&#x27;s take another look at figure 005 above (go ahead, i&#x27;ll wait).  Notice anything ?  That&#x27;s right - the original source sends their packet off, but then receives a response from a &lt;em&gt;different&lt;&#x2F;em&gt; machine than they expected.  This &lt;em&gt;does not work&lt;&#x2F;em&gt; - it violates some basic rules about how communications are supposed to function on the Internet.   For the thrilling conclusion - and a solution to the problem - let&#x27;s return to our drama :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;As it turns out, Bob is a player : he gets so many balls from so many women that he needs to keep track of them all in a little notebook.&lt;&#x2F;li&gt;
&lt;li&gt;When Bob gets Alice&#x27;s ball he passes it to Charles, then he records where it came from and who he gave it to in his notebook&lt;&#x2F;li&gt;
&lt;li&gt;Charles - in an attempt to get into Bob&#x27;s circle of friends - agrees to write « From : Bob, To : Alice » on the ball, then sends it back.&lt;&#x2F;li&gt;
&lt;li&gt;Alice - expecting a ball from Bob - is happy to receive her Bob-signed spheroid.&lt;&#x2F;li&gt;
&lt;li&gt;Bob then gets another ball from Denise, passes it to Edward, and records this relationship as well.&lt;&#x2F;li&gt;
&lt;li&gt;Edward - a sycophant if ever there was - prepares the ball in the same fashion as Charles, and fires it back.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Of course, the more balls Bob has to deal with, the more helpers he can use to spread the work around.  Now, as you&#x27;ve no doubt pieced together, Alice and Denise are any given sources on the Internet, Bob is our LB, and Charles &amp;amp; Edward are the web servers.  Now, instead of writing people&#x27;s names on balls, we should now make the mental leap to IP addresses in packets.  With our tables of hostnames and addresses in mind, let&#x27;s consider the following example :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The source sends a request for a web page.
&lt;ul&gt;
&lt;li&gt;The source IP is « 10.1.2.3 », and the destination IP is « 192.168.0.40 » (the VIP for WWW).&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The packet is sent to A01, which is currently active, and thus has the VIP for WWW assigned to it.&lt;&#x2F;li&gt;
&lt;li&gt;A01 then forwards the packet to B02 (by chance), which crafts a response packet.
&lt;ul&gt;
&lt;li&gt;The RIP for B02 is « 192.168.0.39 », but instead of using that, the source IP is set to « 192.168.0.40 », and the destination is « 10.1.2.3 ».&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The source, expecting a response from « .40 », indeed receives a packet that appears to be from WWW.  Done and done.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The theory is sound, but how can we implement this in practice ?  As i said - it&#x27;s simple !  We simply add a &lt;em&gt;dummy interface&lt;&#x2F;em&gt; to each of the web servers that has the same address as the VIP, which will allow the web servers to interact with packets properly.  This is best done by creating a simple sysconfig entry on each of the web servers for the required dummy interface, as follows :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@B01 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# vim &#x2F;etc&#x2F;sysconfig&#x2F;network-scripts&#x2F;ifcfg-lo:0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# for VIP&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;DEVICE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;lo:0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;IPADDR&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;192.168.0.40&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;NETMASK&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;255.255.255.255&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;BROADCAST&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;192.168.0.40&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;ONBOOT&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;yes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;NAME&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;vip0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;[root@B01 ~]# vim &#x2F;etc&#x2F;sysconfig&#x2F;network-scripts&#x2F;ifcfg-lo:0&lt;&#x2F;p&gt;
&lt;h1 id=&quot;for-vip&quot;&gt;for VIP&lt;&#x2F;h1&gt;
&lt;p&gt;DEVICE=lo:0&lt;&#x2F;p&gt;
&lt;p&gt;IPADDR=192.168.0.34&lt;&#x2F;p&gt;
&lt;p&gt;NETMASK=255.255.255.255&lt;&#x2F;p&gt;
&lt;p&gt;BROADCAST=192.168.0.34&lt;&#x2F;p&gt;
&lt;p&gt;ONBOOT=yes&lt;&#x2F;p&gt;
&lt;p&gt;NAM&lt;strong&gt;all together now&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The « lo » indicates that it&#x27;s a « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Loopback#Network_equipment&quot;&gt;Loopback address&lt;&#x2F;a&gt; », which is best described by Wikipedia :&lt;&#x2F;p&gt;
&lt;p&gt;Such an interface is assigned an address that can be accessed from management equipment over a network but is not assigned to any of the real interfaces on the device. This loopback address is also used for management datagrams, such as alarms, originating from the equipment. The property that makes this virtual interface special is that applications that use it will send or receive traffic using the address assigned to the virtual interface as opposed to the address on the physical interface through which the traffic passes.&lt;&#x2F;p&gt;
&lt;p&gt;In other words, it&#x27;s a fake IP that the machine can use to make packets anyways.  Now, there is a known scenario in which a machine with a given loopback address will, in this particular situation, cause confusion on the network about which interface actually « owns » a given address.  It has to do with ARP, and interested readers are encouraged to Google for « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.fr&#x2F;search?q=lvs+arp+problem&quot;&gt;LVS ARP problem&lt;&#x2F;a&gt; » for more technical details - for now, let&#x27;s just get right to the solution.  On each of the real servers, we&#x27;ll need to edit « sysctl.conf » :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@B01 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# vim &#x2F;etc&#x2F;sysctl.conf&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# this file already has stuff in it, so put this at the bottom&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;net.ipv4.conf.lo.arp_ignore&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;net.ipv4.conf.lo.arp_announce&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, restart &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Sysctl&quot;&gt;sysctl&lt;&#x2F;a&gt; :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@B01 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# sysctl -p&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s it - problem solved.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;all-together-now&quot;&gt;all together now !&lt;&#x2F;h3&gt;
&lt;p&gt;At this point we&#x27;ve now explored each key item that is necessary to make this whole front-end infrastructure work, but it is perhaps not quite clear how it all works together.  So, let&#x27;s take a step back for a moment and review :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;There are four servers : two are load balancers, and two are web servers.
&lt;ul&gt;
&lt;li&gt;Of the two load balancers, only one is active at any given time ; the other is a backup.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;Every DNS entry for the sites on the web servers points to &lt;em&gt;one&lt;&#x2F;em&gt; actual IP address.
&lt;ul&gt;
&lt;li&gt;This IP address is called the « Virtual IP ».&lt;&#x2F;li&gt;
&lt;li&gt;The VIP is claimed by the &lt;em&gt;active&lt;&#x2F;em&gt; load balancer, meaning that when a request is made for a given website, it goes to the active LB.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;The LB then re-directs the request to an actual web server.
&lt;ul&gt;
&lt;li&gt;The re-direction can be random, or based on varying levels of logical decision making.&lt;&#x2F;li&gt;
&lt;li&gt;The web server will respond &lt;em&gt;directly&lt;&#x2F;em&gt; - the LB is not a proxy.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Great !  Now, what software runs where, and why ?&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;The load balancers use LVS in order to manage the relationship between VIPs and RIPs.&lt;&#x2F;li&gt;
&lt;li&gt;Pulse is used between the LBs in order to determine who is alive, and which one is active.&lt;&#x2F;li&gt;
&lt;li&gt;An optional (but useful) web interface to both LVS and Pulse comes in the form of Piranha, which runs on a dedicated instance of Apache HTTPd on port 3636.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;And that, my friends, is that !  If you have any questions, feel free to comment below (remember to subscribe to the RSS feed for responses).  Happy balancing !&lt;&#x2F;p&gt;
&lt;h4 id=&quot;oh-p-s-one-last-thing&quot;&gt;oh, p.s., one last thing...&lt;&#x2F;h4&gt;
&lt;p&gt;In case you&#x27;re wondering how to keep your LVS configuration file synchronised across both of the load balancers, one way to do it would be with a network-aware filesystem - &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;2009&#x2F;06&#x2F;17&#x2F;pohmelfs-nfs-future&#x2F;&quot;&gt;POHMELFS&lt;&#x2F;a&gt;, for example. ;-)&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>it&#x27;s coming !</title>
        <published>2009-10-12T00:00:00+00:00</published>
        <updated>2009-10-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/its-coming/"/>
        <id>https://blog.dark.ca/posts/its-coming/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/its-coming/">&lt;p&gt;Hi all ! I&#x27;m currently working on a new Howto regarding Load Balancing. It&#x27;s gonna be a good one, complete with graphical charts and everything - so stay tuned !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>where to specify ethtool options in Fedora</title>
        <published>2009-08-25T00:00:00+00:00</published>
        <updated>2009-08-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/where-to-specify-ethtool-options-in-fedora/"/>
        <id>https://blog.dark.ca/posts/where-to-specify-ethtool-options-in-fedora/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/where-to-specify-ethtool-options-in-fedora/">&lt;p&gt;Hi everybody - here&#x27;s a super-quick update for you concerning « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;directory.fsf.org&#x2F;project&#x2F;ethtool&#x2F;&quot;&gt;ethtool&lt;&#x2F;a&gt; », and how to use it to set options in Fedora properly.  Ethtool is a great little tool that can be used to configure all manner of network interface related settings - notably the speed and duplex of a card - on the fly and in real time.  One of the most common situations where ethtool would be used is at boot time, especially for cards which are finnicky, or have buggy drivers, or poor software support, or.. well, you get the idea.
Times were that if you needed to use ethtool to configure a NIC setting at boot time, you&#x27;d just stick the given command line into « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.fr&#x2F;search?q=rc.local&quot;&gt;rc.local&lt;&#x2F;a&gt; », or perhaps another runlevel script, and forget about it.  The problem with this approach is (at least) twofold :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Frankly, it&#x27;s easy to forget about something like this, which makes future support &#x2F; debugging of network issues more of a pain.&lt;&#x2F;li&gt;
&lt;li&gt;Anything that automatically modifies the runlevel script (such as updates to the parent package) may destroy your local edits.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;In order to deal with these issues, and to standardise the implementation of the ethtool-at-boot technique, the Red Hat (and, thus, Fedora) maintainers introduced an option for defining ethtool parameters on a per-interface basis via the standard « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.comptechdoc.org&#x2F;os&#x2F;linux&#x2F;howlinuxworks&#x2F;linux_hlsysconfig.html&quot;&gt;sysconfig&lt;&#x2F;a&gt; » directory system.  Now, this actually happened a number of years ago, but the implementation was poorly announced (and poorly documented at the time), and thus, even today a lot of users &lt;em&gt;and administrators&lt;&#x2F;em&gt; don&#x27;t seem to know about it.
Now, there&#x27;s a very good chance that you already know this, but just to refresh your memory : in the sysconfig directory, there is another directory called « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.faqs.org&#x2F;docs&#x2F;securing&#x2F;chap9sec90.html&quot;&gt;network-scripts&lt;&#x2F;a&gt; », which in turn contains a series of files named « ifcfg-eth? », where « ? » is a device number.  Each network device has a configuration file associated with it ; for example, ifcfg-eth1 is the configuration file for the « eth1 » device.
In order to specify the ethtool options for a given network interface, simply edit the associated configuration file, and add a « ETHTOOL_OPTS » line.  For example :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;ETHTOOL_OPTS&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;autoneg off speed 100 duplex full&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, whenever the network service initialises that interface, ethtool will be run with the specified options.  Simple, easy, and best of all, &lt;em&gt;standardised&lt;&#x2F;em&gt;.  What could be better ?&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>(complex) partitioning in kickstart</title>
        <published>2009-08-03T00:00:00+00:00</published>
        <updated>2009-08-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/complex-partitioning-in-kickstart/"/>
        <id>https://blog.dark.ca/posts/complex-partitioning-in-kickstart/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/complex-partitioning-in-kickstart/">&lt;p&gt;UPDATE: This article was written back in 2009. According to &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.dark.ca&#x2F;2009&#x2F;08&#x2F;03&#x2F;complex-partitioning-in-kickstart&#x2F;#comment-200157&quot;&gt;a commenter below&lt;&#x2F;a&gt;, Busybox has been replaced by Bash in RHEL 6; perhaps Fedora as well?
Bonjour my geeky friends ! :)  As you are likely aware, it is now summer-time here in the northern hemisphere, and thus, i&#x27;ve been spending as much time &lt;em&gt;away&lt;&#x2F;em&gt; from the computer as possible.  That said, it&#x27;s been a long time, i shouldn&#x27;t have left you, without a strong beat to step to.
Now, if you&#x27;re not familiar with kickstarting, it&#x27;s basically just a way to automate the installation of an operating environment on a machine - think hands-free installation.  Anaconda is the OS installation tool used in Fedora, RedHat, and some other Linux OS&#x27;s, and it can be used in a kickstart capacity.  For those of you looking for an intro, i heavily suggest reading over the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;fedoraproject.org&#x2F;wiki&#x2F;Anaconda&#x2F;Kickstart&quot;&gt;excellent documentation&lt;&#x2F;a&gt; at the Fedora project website.  The kickstart configuration process could very easily be a couple of blog entries on its own (which i&#x27;ll no doubt get around to in the future), but for now i want to touch on one particular aspect of it : &lt;em&gt;complex partition schemes&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;how-it-is&quot;&gt;how it is&lt;&#x2F;h3&gt;
&lt;p&gt;The current method for declaring partitions is relatively powerful, in that all manner of basic partitions, LVM components, and even RAID devices can be specified - but where it fails is in the creating of the actual partitions on the disk itself.  The options that can be supplied to the partition keywords can make this clunky at best (and impossible at worst).
A basic example of a partitioning scheme that requires nothing outside of the available functions :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;DEVICE&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;                 MOUNTPOINT               SIZE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;dev&#x2F;sda&lt;&#x2F;span&gt;&lt;span&gt;               (total)                  500,000 MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;dev&#x2F;sda1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;              &#x2F;boot&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;                       128&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;dev&#x2F;sda2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;              &#x2F;                         20,000 MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;dev&#x2F;sda3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;              &#x2F;var&#x2F;log&#x2F;                 20,000 MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;dev&#x2F;sda5&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;              &#x2F;home&#x2F;                   400,000 MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;dev&#x2F;sda6&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;              &#x2F;opt&#x2F;                     51,680 MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;dev&#x2F;sda7&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;              swap                       8,192 MB&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Great, no problem - we can easily define that in the kickstart :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;boot     --asprimary  --size=128&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;         --asprimary  --size=20000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;var&#x2F;log  --asprimary  --size=20000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;home                  --size=400000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;opt                   --size=51680&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  swap                   --size=8192&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;But what happens if we want to use this same kickstart on another machine (or, indeed, &lt;em&gt;many&lt;&#x2F;em&gt; other machines) that &lt;em&gt;don&#x27;t&lt;&#x2F;em&gt; have the same disk size ?  One of the options that can be used with the « part » keyword is « --grow », which tells Anaconda to create as large a partition as possible.  This can be used along with « --maxsize= », which does exactly what you think it does.
Continuing with the example, we can modify the « &#x2F;home » partition to be of a variable size, which should do us nicely on disks which may be smaller or larger than our original 500GB unit.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;home  --size=1024  --grow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here we&#x27;ve stated that we&#x27;d like the partition to be &lt;em&gt;at least&lt;&#x2F;em&gt; a gig, but that it should otherwise be as large as possible given the constraints of both the other partitions, as well as the total space available on the device.  But what if you &lt;em&gt;also&lt;&#x2F;em&gt; want « &#x2F;opt » to be variable in size ?  One way would be to grow both of them :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;home  --size=1024  --grow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;opt   --size=1024  --grow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, what do you think that will do ? If you guessed « grow both of them to &lt;em&gt;half&lt;&#x2F;em&gt; the total available size each », you&#x27;d be correct.  Maybe this is what you wanted - but then again, maybe it wasn&#x27;t.  Of course, we could always specify a maximum ceiling on how far &#x2F;opt will grow :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;opt  --size=1024  --maxsize=200000  --grow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That works, but only at the &lt;em&gt;potential expense&lt;&#x2F;em&gt; of &#x2F;home.  Consider what would happen if this was run against a 250GB disk ; the other (static) partitions would eat up some 48GB, &#x2F;opt would grow to the maximum specified size of 200GB, and &#x2F;home would be left with the remaining 2GB of available space.
If we were to add more partitions into the mix, the whole thing would become an imprecise mess rather quickly.  Furthermore, we haven&#x27;t even begun to look at scenarios where there may (or may not) more than one disk, nor any fun tricks like automatically setting the swap size to be same as the actual amount of RAM (for example).  For these sorts of things we need a different approach.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-magic-of-pre-the-power-of-parted&quot;&gt;the magic of pre, the power of parted&lt;&#x2F;h3&gt;
&lt;p&gt;The kickstart configuration contains a section called « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;fedoraproject.org&#x2F;wiki&#x2F;Anaconda&#x2F;Kickstart#Chapter_4._Pre-installation_Script&quot;&gt;%pre&lt;&#x2F;a&gt; », which should be familiar to anybody who&#x27;s dealt with RPM packaging.  Basically, the pre section contains text which will be parsed by the shell during the installation process - in other words, you can write a shell script here.  Fairly be thee warned, however, as the shell spawned by Anaconda is « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;BusyBox&quot;&gt;BusyBox&lt;&#x2F;a&gt; », &lt;em&gt;not&lt;&#x2F;em&gt; « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Bash&quot;&gt;bash&lt;&#x2F;a&gt; », and it lacks some of the functionality that you might expect.  We can use the %pre section to our advantage in many ways - including partitioning.  Instead of using the built-in functions to set up the partitions, we can do it ourselves (in a manner of speaking) using « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;GNU_Parted&quot;&gt;parted&lt;&#x2F;a&gt; ».
Parted is, as you might expect, a tool for editing partition data.  Generally speaking it&#x27;s an interactive tool, but one of the nifty features is the « scripted mode », wherein partitioning commands can be passed to Parted on the command-line and executed immediately without further intervention.  This is &lt;em&gt;very&lt;&#x2F;em&gt; handy in any sort of automated scenario, including during a kickstart.
We can use Parted to lay the groundwork for the basic example above, wherein &#x2F;home is dynamically sized.  Initially this will appear inefficient, since we won&#x27;t be doing anything that can&#x27;t be accomplished by using the existing Kickstart functionality, but it provides an excellent base from which to do more interesting things.  What follows (until otherwise noted) are text blocks that can be inserted directly into the %pre section of the kickstart config :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# clear the MBR and partition table&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;dd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; if=&#x2F;dev&#x2F;zero of=&#x2F;dev&#x2F;sda bs=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;512&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; count=&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s &#x2F;dev&#x2F;sda mklabel msdos&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This ensures that the disk is clean, so that we don&#x27;t run into any existing partition data that might cause trouble.  The « dd » command overwrites the first bit of the disk, so that any basic partition information is destroyed, then Parted is used to create a new disk label.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;TOTAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s &#x2F;dev&#x2F;sda unit mb print free&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Free&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; awk&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;{print $3}&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cut&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -d&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;M&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -f1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;`&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That little line gives us the total size of the disk, and assigns to a variable named « TOTAL ».  There are other ways to obtain this value, but in keeping with the spirit of using Parted to solve our problems, this works.  In this instance, « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;AWK&quot;&gt;awk&lt;&#x2F;a&gt; » and « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;coreutils&#x2F;manual&#x2F;html_node&#x2F;cut-invocation.html&quot;&gt;cut&lt;&#x2F;a&gt; » are used to extract the string we&#x27;re interested in.  Continuing on...&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# calculate start points&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; SWAP_START=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$TOTAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-8192&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; OPT_START=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$SWAP_START&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-51680&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here we determine the &lt;em&gt;starting position&lt;&#x2F;em&gt; for the swap and &#x2F;opt partitions.  Since we know the total size, we can subtract 8GB from it, and that gives us where the swap partition &lt;em&gt;starts&lt;&#x2F;em&gt;.  Likewise, we can calculate the starting position of &#x2F;opt based on the start point of swap (and so forth, were there other partitions to calculate).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# partitions IN ORDER&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s &#x2F;dev&#x2F;sda mkpart primary ext3&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0 128&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s &#x2F;dev&#x2F;sda mkpart primary ext3&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 128 20128&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s &#x2F;dev&#x2F;sda mkpart primary ext3&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 20128 40256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s &#x2F;dev&#x2F;sda mkpart extended&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 40256&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $TOTAL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s &#x2F;dev&#x2F;sda mkpart logical ext3&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 40256&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $OPT_START&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s &#x2F;dev&#x2F;sda mkpart logical ext3&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $OPT_START $SWAP_START&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;parted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s &#x2F;dev&#x2F;sda mkpart logical&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $SWAP_START $TOTAL&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The variables we populated above are used here in order to create the partitions on the disk.  The syntax is very simple :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;« parted -s »  : run Parted in scripted (non-interactive) mode.&lt;&#x2F;li&gt;
&lt;li&gt;« &#x2F;dev&#x2F;sda » : the device (later, we&#x27;ll see how to determine this dynamically).&lt;&#x2F;li&gt;
&lt;li&gt;« mkpart » : the action to take (make partition).&lt;&#x2F;li&gt;
&lt;li&gt;« primary | extended | logical » : the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Disk_partitioning#PC_BIOS_partition_types&quot;&gt;type of partition&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;« ext3 » : the type of filesystem (there are a number of possible options, but ext3 is pretty standard).
&lt;ul&gt;
&lt;li&gt;Notice that the « extended » and « swap » definitions do not contain a filesystem type - it is not necessary.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;« start# end# » : the start and end points, expressed in MB.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Finally, we must still declare the partitions in the usual way.  Take note that this does &lt;em&gt;not&lt;&#x2F;em&gt; occur in the %pre section - this goes in the normal portion of the configuration for defining partitions :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;boot     --onpart=&#x2F;dev&#x2F;sda1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;         --onpart=&#x2F;dev&#x2F;sda2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;var&#x2F;log  --onpart=&#x2F;dev&#x2F;sda3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;home     --onpart=&#x2F;dev&#x2F;sda5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;opt      --onpart=&#x2F;dev&#x2F;sda6&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  swap      --onpart=&#x2F;dev&#x2F;sda7&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As i mentioned when we began this section, yes, this is (so far) a remarkably inefficient way to set this particular basic configuration up.  But, again to re-iterate, this exercise is about putting the groundwork in place for much more interesting applications of the technique.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;mo-drives-mo-better&quot;&gt;mo&#x27; drives, mo&#x27; better&lt;&#x2F;h3&gt;
&lt;p&gt;Perhaps some of your machines have more than one drive, and some don&#x27;t.  These sorts of things can be determined, and then reacted upon dynamically using the described technique.  Back to the %pre section :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# Determine number of drives (one or two in this case)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;set&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; $(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;list-harddrives&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; numd=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;$#&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;d1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;d2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;$3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case, we&#x27;re using a built-in function called « list-harddrives » to help us determine which drive or drives are present, and then assign their device identifiers to variables.  In other words, if you have an « sda » and an « sdb », those identifiers will be assigned to « $d1 » and « $d2 », and if you just have an sda, then $d2 will be empty.
This gives us some interesting new options ; for example, if we wanted to put &#x2F;home on to the second drive, we could write up some simple logic to make that happen :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# if $d2 has a value, it&amp;#39;s that of the second device.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ! -z&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $d2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  HOMEDEVICE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$d2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;else&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;  HOMEDEVICE&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$d1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# snip...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;part&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  &#x2F;home  --size=1024  --ondisk=&#x2F;dev&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$HOMEDEVICE&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  --grow&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That, of course, assumes that the other partitions are defined, and that &#x2F;home is the only entity which should be grown dynamically - but you get the idea.  There&#x27;s nothing stopping us from writing a normal shell script that could determine the number of drives, their total size, and where the partition start points should be based on that information.  In fact, let&#x27;s examine this idea a little further.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-size-she-is-dynamic&quot;&gt;the size, she is dynamic !&lt;&#x2F;h3&gt;
&lt;p&gt;Instead of trying to wrangle the partition sizes together with the default options, we can get as complex (or as simple) as we like with a few if statements, and some basic maths.  Thinking about our layout then, we can express something like the following quite easily :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;If there is one drive that is at least 500 GB in size, then &#x2F;opt should be 200 GB, and &#x2F;home should consume the rest.&lt;&#x2F;li&gt;
&lt;li&gt;If there is one drive is less than 500 GB, but more than 250 GB, then &#x2F;opt and &#x2F;home should each take half.&lt;&#x2F;li&gt;
&lt;li&gt;If there is one drive that is less than 250 GB, then &#x2F;home should take two-thirds, and &#x2F;opt gets the rest.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;# $TOTAL from above...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $TOTAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -ge&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 512000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; OPT_START=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$SWAP_START&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-204800&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;elif&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $TOTAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -lt&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 512000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ] &amp;amp;&amp;amp; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $TOTAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -ge&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment z-comment&quot;&gt;  # get the dynamic space total, which is between where &#x2F;var&#x2F;log ends, and swap begins&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; DYN_TOTAL=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$SWAP_START&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-40256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; OPT_START=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$DYN_TOTAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;elif&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt; $TOTAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -lt&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 256000&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; ]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; DYN_TOTAL=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$SWAP_START&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;-40256&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; OPT_START=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$DYN_TOTAL&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;  let&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; OPT_START=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$OPT_START&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;$OPT_START&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, instead of having to create three different kickstart files, each describing a different scenario, we&#x27;ve covered it with one - nice !&lt;&#x2F;p&gt;
&lt;h3 id=&quot;other-possibilities&quot;&gt;other possibilities&lt;&#x2F;h3&gt;
&lt;p&gt;At the end of the day, the possilibities are nearly endless, with the only restriction being that whatever you&#x27;d like to do has to be do-able in BusyBox - which, at this level, provides &lt;em&gt;a lot&lt;&#x2F;em&gt; great functionality.
Stay tuned for more entries related to kickstarting, PXE-based installations, and so forth, all to come here on dan&#x27;s linux blog.  Cheers !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>getting Dia to give you a pdf</title>
        <published>2009-07-16T00:00:00+00:00</published>
        <updated>2009-07-16T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/getting-dia-to-give-you-a-pdf/"/>
        <id>https://blog.dark.ca/posts/getting-dia-to-give-you-a-pdf/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/getting-dia-to-give-you-a-pdf/">&lt;p&gt;Hello again !  Today&#x27;s quick tip concerns a software package called &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Dia_(software)&quot;&gt;Dia&lt;&#x2F;a&gt;, which is an open source tool (available for both Windows and Linux, as it goes) used to make diagrams, flowcharts, network maps, and so forth.  It has its own file format (.dia), which is (obviously?) useful for saving the projects you&#x27;re working on, but less useful if you need to give the diagram to anybody else, either in print or electronic form.
Dia can export to a variety of formats including &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Scalable_Vector_Graphics&quot;&gt;SVG&lt;&#x2F;a&gt;, &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Portable_Network_Graphicshttp:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Portable_Network_Graphics&quot;&gt;PNG&lt;&#x2F;a&gt;, and &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Encapsulated_PostScript&quot;&gt;EPS&lt;&#x2F;a&gt;, but one export format that it lacks native support for is the venerable PDF, which has become a de facto standard for transmitting documents between diverse environments.  There are many advantages and interesting aspects of the PDF format, not the least of which being that what you see on your screen is what you get when it&#x27;s printed.  It is unfortunate, then, that Dia won&#x27;t spit out a PDF (even if you ask very nicely).
Of course, being that it&#x27;s so easy to print directly to PDF (via &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;CUPS&quot;&gt;CUPS&lt;&#x2F;a&gt;, for example) these days, having native support for PDF may not, at first, seem all that useful.  Well, as it turns out, printing directly to PDF might not give you quite what you were looking for.  In practice, you &lt;em&gt;do&lt;&#x2F;em&gt; get a PDF, but what appeared to be a modestly-sized diagram in Dia will turn out to be a multi-page monster in (virtually) printed form.  As a general rule, this is not what you want.
In order to get a usable PDF we need to use an intermediate step between Dia and the final file.  The idea, quite simply, is to export the diagram as one of the supported formats, then convert that file into a PDF.  There are a number of options here, but for our purposes we&#x27;ll save the diagram as an EPS file, then use a quick little command-line tool called « epstopdf » to perform the conversion.
There&#x27;s a good chance that you don&#x27;t have epstopdf on your machine.  If you&#x27;re using Ubuntu, you &lt;em&gt;used&lt;&#x2F;em&gt; to be able to install it easily via the APT packager, but these days the little conversion tool comes as part of a larger suite of tools called « texlive-extra-utils ».  This suite is dependant on a number of other packages, so go ahead and install them all :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sudo apt-get install texlive-extra-tools&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;EDIT : In Ubuntu 10.04, the package is named « texlive-font-utils ».
Among many, many little items of interest, our target application will be installed.  To use it, simply feed it the name of the EPS file as an argument :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; epstopdf somediagram.eps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It will automatically output a PDF file of the same name.  There you go - a nice, shiny PDF of your Dia diagram.
Enjoy !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>pohmelfs pt. 2, return of pohmelfs !</title>
        <published>2009-07-06T00:00:00+00:00</published>
        <updated>2009-07-06T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/pohmelfs-pt-2-return-of-pohmelfs/"/>
        <id>https://blog.dark.ca/posts/pohmelfs-pt-2-return-of-pohmelfs/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/pohmelfs-pt-2-return-of-pohmelfs/">&lt;p&gt;Hello again fair readers.  Today i&#x27;m going to re-visit POHMELFS, which i introduced in an &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;2009&#x2F;06&#x2F;17&#x2F;pohmelfs-nfs-future&#x2F;&quot;&gt;earlier blog post&lt;&#x2F;a&gt;.  I received a comment on that post which basically asked for more information on some of the more interesting (read : advanced) features of POHMELFS, such as distributed storage, and the like.  Well, today is the day !  If you need a refresher, be sure to skim over my previous post, as we&#x27;re going to dive in now right where i left off last time.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;patch-for-the-win&quot;&gt;patch for the win&lt;&#x2F;h3&gt;
&lt;p&gt;One of the reasons that there was a bit of a delay between my last POHMELFS post and this one was because i hit a bug.  Given that we&#x27;re working with staging-level code here, that&#x27;s to be expected - luckily, thanks to some quick work by &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.ioremap.net&#x2F;pipermail&#x2F;pohmelfs&#x2F;2009-June&#x2F;000087.html&quot;&gt;Evgeniy Polyakov on the POHMLEFS mailing list&lt;&#x2F;a&gt;, there is still hope - hope in the form of a tasty little patch.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;diff&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --git a&#x2F;drivers&#x2F;staging&#x2F;pohmelfs&#x2F;trans.c b&#x2F;drivers&#x2F;staging&#x2F;pohmelfs&#x2F;trans.c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; eab7868..bf7b09a&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 100644&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;---&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; a&#x2F;drivers&#x2F;staging&#x2F;pohmelfs&#x2F;trans.c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;+++&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; b&#x2F;drivers&#x2F;staging&#x2F;pohmelfs&#x2F;trans.c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;@@&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -467,7 +467,8 @@ int netfs_trans_finish_send&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;struct&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; netfs_trans&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;t, struct pohmelfs_sb&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;psb&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword z-punctuation z-terminator&quot;&gt; 				continue;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt; 		}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;		if&lt;&#x2F;span&gt;&lt;span&gt; (psb-&amp;gt;active_state &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;amp;&amp;amp; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;psb-&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;active_state-&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;state.ctl.prio&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;= st&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ctl.prio&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;+&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;		if&lt;&#x2F;span&gt;&lt;span&gt; (psb-&amp;gt;active_state &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-punctuation z-section&quot;&gt;&amp;amp;&amp;amp; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;psb-&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;active_state-&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;state.ctl.prio&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;= st&lt;&#x2F;span&gt;&lt;span&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ctl.prio&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section z-punctuation&quot;&gt;) &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;+&lt;&#x2F;span&gt;&lt;span&gt;				(t-&amp;gt;flags &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; NETFS_TRANS_SINGLE_DST&lt;&#x2F;span&gt;&lt;span&gt;))&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; 			st&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;psb-&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;active_state-&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;state&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; 		err&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = netfs_trans_push&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;t,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; st&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-terminator&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Basically, this patch fixes a minor, but ultimately crippling bug related to writing to multiple servers.  The details are not important - what&#x27;s important is that we apply the patch and keep the dream alive.  First, you&#x27;ll need to copy and paste that block of code into a text file on one of the systems (in « ~&#x2F;pohmel.diff, for example »).  Then, in order to apply the patch, we&#x27;ll need to use a standard tool called (appropriately) « patch » :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cd &#x2F;usr&#x2F;src&#x2F;linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# patch -p 1 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;lt; ~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;pohmel.diff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;patching&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; file drivers&#x2F;staging&#x2F;pohmelfs&#x2F;trans.c&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, just as we did last time, we must play the kernel and module compilation and installation game (fun!).  If you need a refresher on how to do this, just go back to my &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;2009&#x2F;06&#x2F;17&#x2F;pohmelfs-nfs-future&#x2F;&quot;&gt;previous post&lt;&#x2F;a&gt;.  Note that this time around, the whole process will be &lt;em&gt;much faster&lt;&#x2F;em&gt;, since only the POHMELFS components need to be recompiled - everything else will stay the same.  As a result, you can skip the part where you archive the entire kernel tree and copy it over - instead, just patch and recompile on each server and the client.  It&#x27;s your call.
Once that&#x27;s out of the way we&#x27;ll reboot, and then it&#x27;s off to the races.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;a-new-challenger-appears&quot;&gt;a new challenger appears !&lt;&#x2F;h3&gt;
&lt;p&gt;It&#x27;s now time to add a third machine into the mix (« host_147 » in this case).  Using this new box, we&#x27;ll create a simple sort of setup which is, in fact, quite representative of how things might work in the real world : two storage servers and a client.  As you no doubt recall, one of the neat features of POHMELFS is that it can be employed in a parallel fashion, meaning that a file which appears to the client to be in one place, is actaully located in more than one storage medium.  A general way of describing these ideas is by using the terms « logical » and « physical » ; the logical medium is the filesystem that the client sees, and the physical medium is the actual hard drive upon which the data is stored.
In this case, host_75 and host_166 will be the servers, each containing one copy of the data on their respective physical mediums (i.e. hard drives), and host_147 will be our client, which will access the data via the logical medium (i.e. the POHMELFS export).  The new machine was set up in the same way as host_166 was, so we&#x27;ll skip over that, and get right to the good stuff.
A new directory should be created on each of the machines : « &#x2F;opt&#x2F;pohtest ».  This will serve as the export directory on the servers, and the mount directory on the client - don&#x27;t put any data in it yet, though.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;server-config&quot;&gt;server config&lt;&#x2F;h3&gt;
&lt;p&gt;On the servers, we&#x27;ll initiate the server daemon.  Unlike our first test, where we just let the defaults ride, this time around we&#x27;ll configure things a bit more intelligently :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;and host_166&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# fserver -r &#x2F;opt&#x2F;pohtest -l &#x2F;var&#x2F;log&#x2F;pohmelfs.log -d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the above example, « -r » defines the directory to export, « -l » is where to output the logs to, and « -d » puts the process into the background, instead of on our console as before.  This is normally how things would work, so it&#x27;s good to get used to it now.  Now, we can follow the log files on each machine by using « tail » :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;and host_166&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; ~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# tail -f &#x2F;var&#x2F;log&#x2F;pohmelfs.log&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Server&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; is now listening at 0.0.0.0:1025.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;client-config&quot;&gt;client config&lt;&#x2F;h3&gt;
&lt;p&gt;With the servers up and ready to go, we can now turn our attention on the client.  Don&#x27;t forget to load the pohmelfs module first !&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# modprobe pohmelfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cfg -A add -a 192.168.0.75 -p 1025 -i 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we mount.  It&#x27;s important that we mount &lt;em&gt;before&lt;&#x2F;em&gt; we attempt to add the second server into the mix - trying to do it ahead of time will only result in terrible, crippling failure.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;# mount -t pohmel -o idx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; none&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;opt&#x2F;pohtest&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No output means it worked (as usual), so let&#x27;s verify :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# df &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; poh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;none                &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 154590376 &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10018492&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 144571884   7% &#x2F;opt&#x2F;pohtest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Great, now let&#x27;s add the other server :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 opt&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cfg -A add -a 192.168.0.166 -p 1025 -i 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we must wait &lt;em&gt;at least 5 seconds&lt;&#x2F;em&gt; for the synchronisation to occur.  In reality it&#x27;s shorter than that, but 5 seconds is an easy number to remember, and it&#x27;s safe.  So far this looks exactly the same as before, but there&#x27;s a bit of a conceptual twist - as you can see, both of those new add statements have the &lt;em&gt;same index&lt;&#x2F;em&gt; (as denoted by the -i).  This means that they&#x27;re grouped together as part of the same logical medium.  We can check on this by using the « show » action :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cfg -A show -i 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Config&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Index =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Family   &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Server IP                                            Port     &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;AF_INET  &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 192.168.0.75                                        &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1025&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;AF_INET  &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 192.168.0.166                                       &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1025&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Everything seems on the up and up so far, so we can go ahead and try our first mount.  A series of options will be passed to the mount line, notably « idx=1 », which means index 1 (as seen above) - this is &lt;em&gt;very&lt;&#x2F;em&gt; important to specify, as without it, POHMELFS won&#x27;t be able to determine which logical group you&#x27;re talking about.
And if we take a look at the log output on the servers, we&#x27;ll see that the client connection has been accepted.  Both of the logs should show the accepted line, but with different port numbers (the trailing digits at the end) :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Accepted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; client 192.168.0.147:48277.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are other diagnostics we can run to take a look at what we&#x27;ve got running.  At this stage they won&#x27;t tell us anything we don&#x27;t already know, but it will give us some practice with the tools and data, so that when the time comes to debug problems down the road, we&#x27;ll be ready.
For example, POHMELFS will write some handy information to « mountstats », which is exactly what it sounds like :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cat &#x2F;proc&#x2F;1&#x2F;mountstats&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;   ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;device&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; none mounted on &#x2F;opt&#x2F;pohtest with fstype pohmel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;idx&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; addr&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;:port&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-section&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; socket_type protocol active priority permissions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 192.168.0.75:1025&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1 6 1 0 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 192.168.0.166:1025&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1 6 1 0 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It&#x27;s not lined up very nicely, but the interesting column right now is « active », which lists « 1 » in both cases, meaning the connections are open.  The « permissions » column lists « 3 » for both nodes which, in this case, means that they&#x27;re both available for reading and writing (as opposed to being read or write-only, which are also valid options).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;but-will-it-blend&quot;&gt;but will it blend ?&lt;&#x2F;h3&gt;
&lt;p&gt;Accepting the connection is one thing - successfully reading and writing files is entirely another.  Let&#x27;s do some tests ; first we&#x27;ll use the client to create an empty file in mount :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cd &#x2F;opt&#x2F;pohtest&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 pohtest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# touch FILE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 pohtest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ls&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;FILE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Great, now let&#x27;s take a look at our servers :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 pohtest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ls -l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; root root&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-07-06 16:58 FILE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the other :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ls -l &#x2F;opt&#x2F;pohtest&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; root root&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-07-06 16:46 FILE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now, during my limited tests, i noticed a small lag time between my manipulations on the client, and when those actions were reflected on the servers.  At this stage of the game i&#x27;m not sure whether that&#x27;s normal or not, or exactly what&#x27;s causing it - so don&#x27;t be alarmed if you see a small lag as well.  I&#x27;ll be sure to post further updates on this point once i&#x27;ve got more information.
&lt;strong&gt;Update&lt;&#x2F;strong&gt; : As per Evgeniy on the mailing list :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;This&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; delay is not a bug, but feature - POHMELFS has local cache on&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;clients&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; and  data written on client is stored in that cache first and&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; flushed&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; to the server when client is under memory pressure or when&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;another&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; one requests updated but not yet flushed data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;To&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; force client to flush the data one can&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;sync&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; on client or use&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&amp;#39;flush&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; utility on the server. The latter will invalidate data on the&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;client&lt;&#x2F;span&gt;&lt;span&gt; (which&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; implies it to be flushed to the server first&lt;&#x2F;span&gt;&lt;span&gt;), so server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;update&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; will become visible next time client reads that data.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;how-not-to-do-it&quot;&gt;how not to do it&lt;&#x2F;h3&gt;
&lt;p&gt;Let&#x27;s do another little test.  On one of the servers, we&#x27;ll perform a manipulation in the POHMELFS export directory :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# touch &#x2F;opt&#x2F;pohtest&#x2F;host75file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ls -l &#x2F;opt&#x2F;pohtest&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; root root&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-07-06 16:46 FILE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; root root&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-07-06 16:57 host75file&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Great, but if we take a look at the other server :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ls -l &#x2F;opt&#x2F;pohtest&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; root root&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-07-06 16:59 FILE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And the client :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_147 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ls -l &#x2F;opt&#x2F;pohtest&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; root root&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-07-06 20:47 FILE&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;We notice that it&#x27;s not there.  Why ?  Unfortunately, like so much bureaucracy, we didn&#x27;t go through the proper channels.  Recall that our client has certain software running on it that allows it to speak to both servers, and that the mountpoint uses that software to ensure consistency between across the shared filesystem.  In the example above, we wrote directly to the underlying filesystem of the server - completely avoiding said software - and thus POHMELFS had no way of knowing that a manipulation had occured.
In short - if you want to keep things consistent, you &lt;em&gt;must&lt;&#x2F;em&gt; interact via a client.  But what if we want our servers to be able to interact with the data as well ?  Well, there&#x27;s nothing stopping us from setting up client processes on our servers, too.  This, however, will have to wait for the next instalment.
See you on the intertubes !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>setting the from address in GNU mail</title>
        <published>2009-07-03T00:00:00+00:00</published>
        <updated>2009-07-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/setting-the-from-address-in-mail/"/>
        <id>https://blog.dark.ca/posts/setting-the-from-address-in-mail/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/setting-the-from-address-in-mail/">&lt;p&gt;Today i&#x27;m going to address a question that comes up again and again on the various Linux help forums and mailing lists (in one form or another) :
« How do i set the From address when using mail ? »
Of course, « mail » in this case refers to that most basic of all Linux mail applications : GNU mail.  Commonly part of the default software on a Linux box, it&#x27;s not used very often in an interactive capacity, but it still gets a &lt;em&gt;lot&lt;&#x2F;em&gt; of play in the System Administration world as a way to quickly fire off automated emails from scripts.  For example :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;This is the message&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; mail&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;This is the subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; user@domain.tld&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This would result in a message that&#x27;s &lt;em&gt;from&lt;&#x2F;em&gt; whatever raw user@system that the local mailing software detects, such as « systemcheck@2.1.0.192.int.domain.tld » or some such thing.  Normally, whatever defaults (including the From address) that get used are good enough, but occasionally it can be handy to have a finer level of control ; for example, policy restrictions on your local mail relay, or just because the default From address looks bad and you want to make it more readable.
The solution, like so many others in the Linux world, is straightforward once you already know about it, but just obscure enough that it isn&#x27;t obvious at first.  The man page for « mail » on Ubuntu (and, likely, other distros as well) has this tasty little morsel of information listed as the &lt;em&gt;very first&lt;&#x2F;em&gt; option :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-a,&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --append=HEADER: VALUE Append given header to the message being sent&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;« Headers » form part of every email message, and are used to store all sorts of information about the email, from such pedestrian items as « From: » and « To: », to more esoteric things like Spam analysis breakdowns and binary encoding methods.  For now, the important thing to realise is that the From: address is contained within the From header, and using the argument noted above, we can set it quite easily :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; echo&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;The message&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; mail&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -s&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;The subject&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --append=FROM:sensible@domain.tld user@domain.tld&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This would send the same message as above, but with the From: address set to « sensible@domain.tld ».  In fact, &lt;em&gt;any&lt;&#x2F;em&gt; header can be altered in this fashion, not just the From header - so if you ever have the need to change other headers, now you know at least one way. :)&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>pohmelfs update</title>
        <published>2009-07-01T00:00:00+00:00</published>
        <updated>2009-07-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/pohmelfs-update/"/>
        <id>https://blog.dark.ca/posts/pohmelfs-update/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/pohmelfs-update/">&lt;p&gt;Hello again ! You may be wondering when the next update in the POHMELFS series is coming - well, rest assured that i&#x27;m working on it even as you read this, and that it will be worth the wait.
Remember that we&#x27;re working with Staging-level code, and that sometimes things don&#x27;t always go as well as one might hope - in this case, there are some discrepancies between the code that the POHMELFS devs are using, and that which was released in the 2.6.30 code (according to the devs, at least).
I&#x27;ve recently received a nice new patch from one of the devs, and once i&#x27;ve got that squared away, we&#x27;ll continue with our exercise.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>force disk geometry with sfdisk</title>
        <published>2009-06-22T00:00:00+00:00</published>
        <updated>2009-06-22T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/force-disk-geometry-with-sfdisk/"/>
        <id>https://blog.dark.ca/posts/force-disk-geometry-with-sfdisk/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/force-disk-geometry-with-sfdisk/">&lt;p&gt;Hello again !  This is a quick and dirty update which covers a handy little trick when dealing with writeable removable media - especially USB drives, compact flash cards, and the like.
I end up using a &lt;em&gt;lot&lt;&#x2F;em&gt; of USB keys in my environment for a variety of reasons, not the least of which is as handy portable Linux drives that can be stuck into any workstation and booted from directly.  They&#x27;re like LiveCDs, except since i can write to them, any changes that are made during a session don&#x27;t disappear when the machine reboots (nice).  As an aside, if that sounds interesting to you, i suggest checking out the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;fedoraproject.org&#x2F;wiki&#x2F;FedoraLiveCD&#x2F;USBHowTo&quot;&gt;Fedora LiveCD on USB Howto&lt;&#x2F;a&gt;.
USB keys are so ubiquitous now that we buy in bulk, meaning we&#x27;ll get a bunch of identical units at one time.  Once in a while (though more often than i&#x27;d like), one of the keys will end up having a detected geometry which is different from the others.  This isn&#x27;t normally a big deal, but it can cause slight variations in the apparent available space to create a partition.  This ends up being a problem if i&#x27;m looking to clone data from one key to another using a disk imaging tool such as « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Partimage&quot;&gt;Partimage&lt;&#x2F;a&gt; » (another tool that gets a lot of play around here).
The solution is fantastically simple, but perhaps not immediately obvious, as it requires the use of a tool that - for the most part - never gets touched by the average user (or admin !) : « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.fr&#x2F;search?q=sfdisk&quot;&gt;sfdisk&lt;&#x2F;a&gt; ».  Sfdisk is a partition table manipulator that allows us to do a number of advanced (read: &lt;em&gt;dangerous&lt;&#x2F;em&gt;) operations to disks.  Since the common day-to-day operations one might perform on a disk, such as creating or modifying partition assignments, are covered by the more common « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Fdisk&quot;&gt;fdisk&lt;&#x2F;a&gt; » (or even « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cfdisk&quot;&gt;cfdisk&lt;&#x2F;a&gt; »), sfdisk is rarely called upon outside of bizarre or extreme situations.
Altering geometry is one such situation.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;change-is-good&quot;&gt;change is good&lt;&#x2F;h3&gt;
&lt;p&gt;The first thing we need to do is determine what the &lt;em&gt;correct&lt;&#x2F;em&gt; geometry is.  This is obtained easily enough by running an fdisk report against a known-good key (sdc, in this case) :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# fdisk -l &#x2F;dev&#x2F;sdc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Disk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;dev&#x2F;sdc:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4001&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; MB,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4001366016&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;19&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; heads,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sectors&#x2F;track,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 21648&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cylinders&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Units&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; = cylinders of&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 361&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 512&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 184832&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; bytes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Disk&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; identifier:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0xf1bcd225&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; Device&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Boot      Start         End      Blocks   Id  System&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;dev&#x2F;sdc1  &lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;           1       21648     3907454+  83  Linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Alternatively, we could ask sfdisk :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# sfdisk -g &#x2F;dev&#x2F;sdc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;dev&#x2F;sdc:&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 21648&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cylinders,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; heads,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 19&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sectors&#x2F;track&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now that we have the correct geometry, we can get sfdisk to alter that of the naughty key (sdb, in this case).  As you can likely guess, -C is the cylinders, -H is the heads, and -S in the sectors (per track) :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# sfdisk -C 21648 -H 19 -S 19 &#x2F;dev&#x2F;sdb&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Depending on your particular version of sfdisk and distro, this may trigger an interactive process which will ask you to create the desired partitions on the key.  Assuming you just want one big Linux partition, you can hit « enter » and accept every default until it&#x27;s done.
And that&#x27;s that - one key brought rapidly in line with the others.
Cheers !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>pohmelfs - the network filesystem of the future !</title>
        <published>2009-06-17T00:00:00+00:00</published>
        <updated>2009-06-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/pohmelfs-nfs-future/"/>
        <id>https://blog.dark.ca/posts/pohmelfs-nfs-future/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/pohmelfs-nfs-future/">&lt;p&gt;Hello again fair readers !  Today we&#x27;re going to take a look at &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.ioremap.net&#x2F;projects&#x2F;pohmelfs&quot;&gt;POHMELFS&lt;&#x2F;a&gt;, which is a network file system that was just recently integrated into the Linux kernel.  This is an excellent exercise for three reasons : we&#x27;ll learn about some great new concepts related to network file systems, we get to compile and install our own kernel, and we get to play with a great new platform that could, eventually, become the new standard for network file systems in the *nix world.  Sound good ?  Let&#x27;s go !
A network file system is, according to &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Network_file_system&quot;&gt;Wikipedia&lt;&#x2F;a&gt;, « any computer file system that supports sharing of files, printers and other resources as persistent storage over a computer network. » It is important to note that there is also a specific protocol called « Network File System », which is exactly what it sounds like, and is highly popular in the *nix world.  For the purposes of this article, unless otherwise stated every time i use « network file system » or « nfs », i&#x27;m referring to the concept, not the protocol.
Building on the idea of an nfs, there are other types of network-aware file systems which fall into similar categories, such as « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Distributed_file_system&quot;&gt;distributed file systems&lt;&#x2F;a&gt; », « parallel file systems », « distributed parallel file systems », and so forth.  These terms are largely non-standard, and conventional wisdom tends to put all of these sub-categories into the one big nfs family.  POHMELFS, for example, is described by its creator as a « distributed parallel internet filesystem » - in fact, the name itself is an acronym for « Parallel Optimized Host Message Exchange Layered File System », which is, mercifully, pronounced simply as « poh-mel ».
The two interesting portions of the name are « parallel » and «optmized »...&lt;&#x2F;p&gt;
&lt;h3 id=&quot;parallel&quot;&gt;parallel&lt;&#x2F;h3&gt;
&lt;p&gt;One of the interesting aspects of POHMELFS is that a given chunk of data can (and in many cases, &lt;em&gt;should&lt;&#x2F;em&gt;) reside in more than one distinct storage unit (different physical servers, for example).  The client can be made aware of this, which means that accesses to the data can happen in a « parallel » fashion, which has two major advantages :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Seamless real-time replication of the data during write operations&lt;&#x2F;li&gt;
&lt;li&gt;Faster overall data accesses during read operations&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Imagine a scenario whereby you have two file servers : serverA and serverB, and any given number of clients (clientA, B, C, etc..).  In a classic non-parallel (and non-replicating) file system scenario, data would not be identical between the two file servers.  Clients would need to know which server had the data they wanted ahead of time, and if one of the servers went down, it would take all of its unique data with it.  Furthermore, if all of the clients wanted to read data from serverB at once, everybody would get bogged down overall, since there are a finite amount of resources available for everybody to use.
The same scenario with a parallel file system is much better indeed !  Firstly, data would be identical on the two file servers, meaning that if one were to go down, there would be no direct loss of data availability (already a &lt;em&gt;huge&lt;&#x2F;em&gt; improvement).  Secondly, and this is also huge, clients could spread their requests for data between the two servers, thus reducing the direct load on any one given server, and resulting in better overall resource usage (translation : better performance).&lt;&#x2F;p&gt;
&lt;h3 id=&quot;optimized&quot;&gt;optimized&lt;&#x2F;h3&gt;
&lt;p&gt;The author claims that POHMELFS is designed from the ground-up with performance in mind.  This design principle has resulted in some amazing benchmarks which, frankly stated, make more or less every other network file system &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.ioremap.net&#x2F;node&#x2F;153&quot;&gt;look slow&lt;&#x2F;a&gt; in &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.ioremap.net&#x2F;node&#x2F;134&quot;&gt;comparison&lt;&#x2F;a&gt; ; some types of data access processes are merely rapid, whereas others are revolutionary.  Of course, speed isn&#x27;t everything, and as you might expect, POHMELFS isn&#x27;t quite as feature rich (yet?) as many of the other nfs options on the market.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;take-it-for-a-test-drive&quot;&gt;take it for a test drive&lt;&#x2F;h2&gt;
&lt;p&gt;At the top of the article i mentioned that POHMELFS was recently introduced into the Linux kernel.  What i really meant was that as of kernel version 2.6.30, POHMELFS is located in the « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;kerneltrap.org&#x2F;Linux&#x2F;Introducing_the_Linux_Staging_Tree&quot;&gt;staging&lt;&#x2F;a&gt; » tree of the overall &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Source_tree&quot;&gt;source&lt;&#x2F;a&gt; collection.  This is already a little bit of a warning - code in the staging area is generally considered usable, but not ready to be merged into the kernel proper.  If this doesn&#x27;t sound like your bag, it&#x27;s time to bail out now, but for those of you in the mood for adventure, the staging tree is a great place to find interesting new features and functionalities.
In the test scenario we&#x27;re about to run through, there are two servers : « host_75 » and « host _166 ».  Both of these machines are &lt;em&gt;very&lt;&#x2F;em&gt; basic installations of Fedora 8, which from a server perspective is not very different from any other Fedora prior or since - therefore, unless otherwise noted, these operations should be identical on any other Fedora box.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;kernel-configuration&quot;&gt;kernel configuration&lt;&#x2F;h3&gt;
&lt;p&gt;Long ago, in a faraway land where dragons battled wizards for supremacy over ancient battlements, the process of properly configuring, compiling, and installing a new Linux kernel was arcane knowledge - the stuff of legends.  In our modern, enlightened age, installing a new kernel on your machine is (relatively) simple !  Heck, you even get a &lt;em&gt;menu&lt;&#x2F;em&gt; these days...
The first step in compiling a new kernel is to make sure that your system has the necessary tools with which to work.  On a standard Fedora system, the fastest way is simply to install all of the development tools as a single mass operation.  This is overkill, really, but it&#x27;s simple, and since we&#x27;re just testing things out anyways, fast and simple are our primary criteria :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# yum groupinstall &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Development Tools&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The kernel menu i mentioned a few moments ago is going to require an additional package which is not part of the development tools group : « ncurses-devel ».&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# yum install ncurses-devel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next up, we need to download and unpack the kernel source package.  Your best bet is from &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.kernel.org&#x2F;&quot;&gt;kernel.org&lt;&#x2F;a&gt;, which is reliable, rapid, and most importantly, secure :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cd &#x2F;usr&#x2F;src&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# wget http:&#x2F;&#x2F;eu.kernel.org&#x2F;pub&#x2F;linux&#x2F;kernel&#x2F;v2.6&#x2F;linux-2.6.30.tar.bz2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# tar -xvjf linux-2.6.30.tar.bz2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ln -s linux-2.6.30 linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, we can take a look at the configuration menu.  You&#x27;ll notice that we issue the command « make », which is a mechanism for compiling source code used across the *nix world.  We&#x27;ll see it again a little later on, but for now, understand that all we&#x27;re doing here is «making » the configuration menu, not the kernel itself.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cd linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 linux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# make menuconfig&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now there are a lot (&lt;em&gt;a LOT&lt;&#x2F;em&gt;) of possible options for configuring a kernel, and if you&#x27;ve got the time and the inclination, going through each one and reading the description can be very enlightening.  That said, what we&#x27;re interested in is POHMELFS, and in order to enable it, we&#x27;re going to have to explicitly tell the configuration that we&#x27;re interested in staging-level code.
First, &lt;em&gt;enable&lt;&#x2F;em&gt; « Staging Drivers » :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Device&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Drivers ---&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [*] Staging Drivers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then &lt;em&gt;disable&lt;&#x2F;em&gt; « Exclude Staging drivers from being built ».  It&#x27;s set up this way in order to prevent somebody from accidentally building anything from staging by accident :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Device&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Drivers ---&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Staging Drivers ---&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ] Exclude Staging drivers from being built&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, enable POHMELFS as a &lt;em&gt;module&lt;&#x2F;em&gt; (if you&#x27;d like a refresher on modules, just check out any post on this blog with the « modules » tag) :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Device&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Drivers ---&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Staging Drivers ---&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;M&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; POHMELFS filesystem support&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And, optionally, support for encryption :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Device&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Drivers ---&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Staging Drivers ---&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span&gt;M&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; POHMELFS filesystem support&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; [*] POHMELFS crypto support&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, you may wish to add a « local version string » - this is an identifier that you can customise to help you keep track of each kernel build.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;General&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Setup ---&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; (-pohmelfs_test) Local version&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Now we save and exit !&lt;&#x2F;p&gt;
&lt;h3 id=&quot;build-install-the-kernel&quot;&gt;build &amp;amp; install the kernel&lt;&#x2F;h3&gt;
&lt;p&gt;From here, all that&#x27;s left is to let it build - depending on your hardware, this can take a while.  Patience, grasshopper.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 linux&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# make &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; make&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; modules&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; make&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; modules_install&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; make&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There are four distinct commands which, assuming the previous one is successful, will execute consecutively - that&#x27;s what the double-ampersand (&amp;amp;&amp;amp;) does.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;make : Builds the actual kernel (this is the part that takes forever)&lt;&#x2F;li&gt;
&lt;li&gt;make modules : Builds the modules (everything enabled as &lt;M&gt;, such as POHMELFS)&lt;&#x2F;li&gt;
&lt;li&gt;make modules_install : Copies the modules to their proper positions&lt;&#x2F;li&gt;
&lt;li&gt;make install : Creates the initrd (which i discussed in a previous post), sets up the bootloader (which we&#x27;ll take a look at), and so forth&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Once the process is done, which is to say that all four items executed successfully, the last thing we need to check before we reboot is the bootloader - in this case, « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;GNU_GRUB&quot;&gt;GRUB&lt;&#x2F;a&gt; ».  The « make install » will add an entry for our new kernel into the GRUB configuration.  This is fairly automatic, but i like to check it, just to be safe.  The new entry should look something like this :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;title&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Fedora&lt;&#x2F;span&gt;&lt;span&gt; (2.6.30-pohmelfs_test)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; root&lt;&#x2F;span&gt;&lt;span&gt; (hd0,0)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; kernel&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;vmlinuz-2.6.30-pohmelfs_test ro root=&#x2F;dev&#x2F;sda1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; initrd&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;initrd-2.6.30-pohmelfs_test.img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From here, we reboot, and when the GRUB menu appears, select our new POHMELFS item instead of the default entry.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;userspace-tools&quot;&gt;userspace tools&lt;&#x2F;h3&gt;
&lt;p&gt;The actual POHMELFS executables - the « userspace tools », so called since they are used by the user, not by the system, are &lt;em&gt;not&lt;&#x2F;em&gt; included with the kernel.  This is normal.  Even though our kernel now supports POHMELFS, our system doesn&#x27;t actually have any of the software which will interface with the kernel module yet.  This has to be downloaded, configured, and compiled in the same fashion as the kernel ; however, whereas the kernel was easily downloaded via HTTP, the POHMELFS source is only available via « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Git_(software)&quot;&gt;GIT&lt;&#x2F;a&gt; ».
GIT, in a nutshell, is a platform for managing source code (like « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Concurrent_Versions_System&quot;&gt;CVS&lt;&#x2F;a&gt; », « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Subversion_(software)&quot;&gt;Subversion&lt;&#x2F;a&gt; », or « &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Visual_SourceSafe&quot;&gt;VSS&lt;&#x2F;a&gt; », just to name a few).  For our purposes today, we&#x27;re only going to use &lt;em&gt;one&lt;&#x2F;em&gt; of its many features : copying the source code from the official POHMELFS site so that we can compile it ourselves.  If you don&#x27;t already have GIT installed, now is the time !  Don&#x27;t delay, act today !&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# yum install git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Depending on your existing installation, this may cause a fairly large number of new packages to be downloaded and installed, so don&#x27;t worry if the list looks huge.  With that out of the way, we can download the source - this is known as « cloning » a « project » in GIT terminology :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# git clone http:&#x2F;&#x2F;www.ioremap.net&#x2F;git&#x2F;pohmelfs-server.git&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Preparation of the source and so forth for POHMELFS was, not too long ago, a bit of a pain in the yoohoo.  Now, the author has graciously included a tool which will take most of the pain out of the process - though there are still a few things to look out for :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cd pohmelfs-server&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# .&#x2F;autogen.sh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will take a little while, and will output a handful of lines as it goes along.  The next step is to is a standard « .&#x2F;configure », which, if you&#x27;ve never compiled anything before, is just about the most standard possible way to pre-configure source for compilation in the *nix world.  Normally, .&#x2F;configure accepts a variety of options (take a look at « .&#x2F;configure --help » for a taste), but for now, we&#x27;re only interested in one :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;# .&#x2F;configure --with-kdir-path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;usr&#x2F;src&#x2F;linux&#x2F;drivers&#x2F;staging&#x2F;pohmelfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The supplied option tells .&#x2F;configure where the POHMELFS kernel code is - in specific, where the « netfs.h » file is located.  This is important later on, so take note.  This process output tonnes of lines as it checks for the capabilities and desires of your environment, and customises the configuration as best it can for your machine.  Once it&#x27;s done, we can go ahead and « make » :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As of this writing, the above make may fail.  As it turns out, certain elements in the POHMELFS source, as they stand now, expect &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Openssl&quot;&gt;OpenSSL&lt;&#x2F;a&gt; to be installed on the system.  This is true even if you were clever and provided « --disable-openssl » to .&#x2F;configure above (good thinking, though !).  We&#x27;ve got two options here : either modify the POHMELFS source in order to remove the references to things which do not exist, or simply install OpenSSL and be done with it.  If you&#x27;ve already got OpenSSL on your system, then no worries, you probably didn&#x27;t even see this problem.
OpenSSL, briefly, is an open-source implementation of a series of encryption protocols and cryptographic algorithms which, among other things, allow for « secure » websites (i.e. via HTTP&lt;strong&gt;S&lt;&#x2F;strong&gt;), and other such things.  As such, it&#x27;s a pretty standard thing to have on a machine (especially a server), and since it&#x27;s so easy to install in our test scenario, we&#x27;ll just go ahead and do that now :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# yum install openssl openssl-devel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Back to POHMELFS, it&#x27;s time to reconfigure.  We&#x27;ll enable openssl now, since we&#x27;ve got it anyways...&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;# .&#x2F;configure --with-kdir-path&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;&#x2F;usr&#x2F;src&#x2F;linux&#x2F;drivers&#x2F;staging&#x2F;pohmelfs&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; --enable-openssl&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As of this writing, the above make &lt;em&gt;will&lt;&#x2F;em&gt; fail (again, possibly).  In this instance, a required file can&#x27;t be located : netfs.h .  Remember that one from above ?  Of course you do.  As it turns out, even though we explicitly specified the path to find this file, certain elements in the source (possibly auto-generated) expect it to be elsewhere.  As with OpenSSL, we have two options : alter the code ourselves, or just satisfy the requirement as painlessly as possible.  Well, you already know how we roll in these parts :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# mkdir &#x2F;usr&#x2F;src&#x2F;linux&#x2F;drivers&#x2F;staging&#x2F;pohmelfs&#x2F;fs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ln -s &#x2F;usr&#x2F;src&#x2F;linux&#x2F;drivers&#x2F;staging&#x2F;pohmelfs &#x2F;usr&#x2F;src&#x2F;linux&#x2F;drivers&#x2F;staging&#x2F;pohmelfs&#x2F;fs&#x2F;pohmelfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;What we&#x27;ve done here is create a link that points from where the source &lt;em&gt;wants&lt;&#x2F;em&gt; netfs.h to be, to where it actually is.  Hey, it&#x27;s staging-level code, remember ?  No worries - this was an easy one anyways.  With that out of the way, we can make away !&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# make&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;   ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# make install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The make install will put the necessary binaries in the appropriate places on the system.  In particular :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# which fserver cfg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;local&#x2F;bin&#x2F;fserver&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;usr&#x2F;local&#x2F;bin&#x2F;cfg&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;and-again&quot;&gt;and again !&lt;&#x2F;h3&gt;
&lt;p&gt;That&#x27;s one server down, one to go.  But, wait, that was a lot of work, and even more waiting, wasn&#x27;t it ?  Doing it again would suck ; luckily, there are some shortcuts we can take.
If the hardware of both machines is more or less the same, there&#x27;s a better-than-average chance that the same kernel you&#x27;ve already compiled will work on the other server - you can just port it over.  Now, there are very particular, very clean ways to go about this, and to those that like their test environments clean and tidy, i salute you ; we, however, know better.  Let&#x27;s just pack up the source, copy it over, and deploy it all at once :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; cd &#x2F;usr&#x2F;src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; tar -cvzf src.tar.gz linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;   ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; scp src.tar.gz root@host_166:&#x2F;usr&#x2F;src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-string&quot;&gt;   ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;From here on in you&#x27;ll want to keep an eye on the hostname being used - we&#x27;re dealing with two machines now...&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; cd &#x2F;usr&#x2F;src&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; tar -xvzf src.tar.gz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; cd linux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 src&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt; make modules_install &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;amp;&amp;amp;&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; make&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nice !  Reboot the second machine now, and &lt;em&gt;don&#x27;t forget&lt;&#x2F;em&gt; to choose the new kernel from the GRUB menu.
Likewise, we don&#x27;t need to install GIT on the second machine - we&#x27;ll just do like we did with the kernel :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;# tar -cvzf poh.tar.gz --exclude&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.git&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; pohmelfs-server&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# scp poh.tar.gz root@host_166:&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Notice the « --exclude » line in the tar command ?  This is to prevent the GIT-specific stuff (which is substantial) from being archived, as it is not useful where we&#x27;re going.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# tar -xvzf poh.tar.gz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;   ...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cd pohmelfs-server&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# make install&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;testing-time&quot;&gt;testing time&lt;&#x2F;h3&gt;
&lt;p&gt;The first thing we need to do is load the POHMELFS module, which was generated way back when we built the kernel :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# modprobe pohmelfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 pohmelfs-server&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# lsmod&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Module                 &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Size  Used by&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pohmelfs              &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 59284 &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;You will likely have a lot more items in this list - but one of them &lt;em&gt;must&lt;&#x2F;em&gt; be « pohmelfs ».  Before we start the server daemon, we&#x27;ll have to decide which directory we want to « export », which is to say which one we&#x27;d like to share on the network.  For now, let&#x27;s pick « &#x2F;tmp », since it&#x27;s simple (and it&#x27;s the daemon default).  Let&#x27;s put a file in there so that we can check to see if our share is properly working :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# touch &#x2F;tmp&#x2F;POHTEST.TXT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Next, we start the server daemon.  For our first test, we&#x27;ll just launch the binary without any options - by default, the daemon will launch in a local console, export &#x2F;tmp (as noted above), and bind the process to port 1025.  Eventually you may wish to change some or all of these defaults, but for now, we&#x27;ll keep it simple :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_75 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# fserver&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Server&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; is now listening at 0.0.0.0:1025.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The most basic test possible at this point is to telnet from the second machine to the first, just to see if we can connect on the port :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# telnet host_75 1025&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Trying&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 192.168.0.75...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Connected&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; to 192.168.0.75.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Escape&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; character is&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;^]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;^]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;telnet&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; quit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Connection&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; closed.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This will create some output on the server console :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Accepted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; client 192.168.0.166:49744.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;fserver_recv_data:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; size: 40, err: -104: Success&lt;&#x2F;span&gt;&lt;span&gt; [0].&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Dropped&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; thread&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; for client 192.168.0.166:49744.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Disconnected&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; client 192.168.0.166:49744, operations served: 0.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Dropping&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; worker: 3086465936.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Looks good !  Let&#x27;s try a proper connection with the POHMELFS userspace tool : « cfg ».  The options we&#x27;ll pass to it are the most basic possible set :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;« -A add » : Action is to add a new connection&lt;&#x2F;li&gt;
&lt;li&gt;« -a &lt;address&gt; » : Connect to this server&lt;&#x2F;li&gt;
&lt;li&gt;« -p &lt;port&gt; » : Connect on this port&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cfg -A add -a 192.168.0.75 -p 1025&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Timed&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; out polling for ack&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;main:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; err: -1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Uh oh !  What happened ?  The error message tells us that the client « timed out » (or waited too long) to receive an acknowledgement of the connection from the server.  But why ?  The answer, though simple, is not immediately obvious : we forgot to load the POHMELFS module on the second machine.  No worries, go ahead and do that now, and we&#x27;ll try again :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# modprobe pohmelfs&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cfg -A add -a 192.168.0.75 -p 1025&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In a stroke of user-friendliness to last the ages, a successful cfg execution will produce &lt;em&gt;no&lt;&#x2F;em&gt; output.  No news is good news, i suppose...
Alright, now that we&#x27;ve got the server up, and we&#x27;ve prepared the client for a connection, we&#x27;ll need to pick a spot to « mount » the remote share, then initiate the mount itself :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# mkdir pohtest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;# mount -t pohmel -o idx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; none&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pohtest&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;mount:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; unknown filesystem type&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;pohmel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Curses, foiled again !  Well, &lt;em&gt;i&lt;&#x2F;em&gt; was, at least - your mileage may vary on this one.  If you get this error instead of a successful mount, the problem is very likely that the « pohmel » file system type isn&#x27;t declared in all the proper places.  Check « proc » and the « filesystems » etc config :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cat &#x2F;proc&#x2F;filesystems &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; poh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;nodev  &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  pohmel&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cat &#x2F;etc&#x2F;filesystems &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; poh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;#&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ah ha !  Let&#x27;s rectify that little oversight and try again :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# echo &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nodev pohmel&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; &#x2F;etc&#x2F;filesystems&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other&quot;&gt;# mount -t pohmel -o idx&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; none&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pohtest&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;No output ?  Great success !  Let&#x27;s verify :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# df &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;|&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; grep&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; poh&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;none                &lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 154590376 &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10007348&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 144583028   7% &#x2F;root&#x2F;pohtest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The server console also confirms the connection :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;fserver_root_capabilities:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; avail: 148053020672, used: 10247524352, export: 0, inodes: 39911424, flags: 2.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Accepted&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; client 192.168.0.166:37617.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And, finally, we can see our test file :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# cd pohtest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 pohtest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# ls -l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; root root&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-16 15:39 POHTEST.TXT&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Closing the connection cleanly is as simple as umounting :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;[&lt;&#x2F;span&gt;&lt;span&gt;root@host_166 &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;~&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;]&lt;&#x2F;span&gt;&lt;span&gt;# umount pohtest&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This is confirmed on the server console :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Dropped&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; thread&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; for client 192.168.0.166:58955.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Disconnected&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; client 192.168.0.166:58955, operations served: 1.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;Dropping&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; worker: 3086400400.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h3 id=&quot;that-s-a-wrap-for-now&quot;&gt;that&#x27;s a wrap, for now&lt;&#x2F;h3&gt;
&lt;p&gt;Now i know what you&#x27;re thinking : where&#x27;s the parallel storage ?  Where&#x27;s the real-time mirroring and all that fun stuff ?  It&#x27;s coming.  For now, we&#x27;re just getting our feet wet with technology.  As time and testing permits, i&#x27;ll post more about POHMELFS - so stay tuned !
&lt;strong&gt;UPDATE&lt;&#x2F;strong&gt; : Check out the next instalment in the series ! &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.dark.ca&#x2F;2009&#x2F;07&#x2F;06&#x2F;pohmelfs-pt-2-return-of-pohmelfs&#x2F;&quot;&gt;http:&#x2F;&#x2F;www.dark.ca&#x2F;2009&#x2F;07&#x2F;06&#x2F;pohmelfs-pt-2-return-of-pohmelfs&#x2F;&lt;&#x2F;a&gt;
Last but not least, be sure to check out « fserver -h » for such useful features as « fork to background » and « logfile » - both of which, i guaruntee, you&#x27;ll want to look into if you intend to play around anymore with POHMELFS.
Finally, remember that while the code is very mature for &lt;em&gt;staging&lt;&#x2F;em&gt;, it&#x27;s still considered highly experimental.  Good luck, and happy hacking !&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>how to be properly lazy, with perl !</title>
        <published>2009-06-12T00:00:00+00:00</published>
        <updated>2009-06-12T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/how-to-be-perl-lazy/"/>
        <id>https://blog.dark.ca/posts/how-to-be-perl-lazy/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/how-to-be-perl-lazy/">&lt;p&gt;One of the wonderful things about Perl is that it enables the busy System Administrator to be lazy - and that&#x27;s a good thing ! Of course, i don&#x27;t mean lazy as in unmotivated, or possesed of a poor work ethic, i mean it in the sense that Perl lets us do as little work as possible in a wide variety of situations. Let&#x27;s examine this idea, shall we ?
In the computer world, one often finds themselves doing the same sorts of things over and over again, such as adding a new user to the network, or verifying that the backups executed properly. Usually, these are relatively simple processes which are less about problem solving, and more about following the same set of steps over and over until the desired goal is attained. It is in these situations that the (properly) lazy admin identifies a way to automate as much as possible these processes, so that he or she can get back to more brain-intensive work (this has the net effect of improving overall efficiency and value - see how laziness pays off in the end ? :) )
There are, of course, as many scripting and programming languages as there are grains of sand on a beach, but despite the many competitors and alternatives out there, Perl remains the language of choice for many Linux admins around the world. This is in no small part due to Perl&#x27;s ability to manipulate data in a rapid, logical, and easily deployable manner - the most obvious example of this being the vaunted « Perl One-Liner ».&lt;&#x2F;p&gt;
&lt;h3 id=&quot;example&quot;&gt;example !&lt;&#x2F;h3&gt;
&lt;p&gt;There comes a time in every admin&#x27;s life when they must take a bunch of text files, and systematically swap some of the text within with new data - commonly known as searching and replacing.  You could certainly do this by hand using an editor or by using a relatively straightforward C program if you were so inclined.  But there is another way - a better, smarter, &lt;em&gt;lazier&lt;&#x2F;em&gt; way : the Perl search &amp;amp; replace one-liner !  Let&#x27;s take a look at the code, then break down each component.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; perl -p -i -e&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;s&#x2F;oldandbusted&#x2F;newhotness&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That&#x27;s it, you&#x27;re done - take a lap and hit the showers.  So, what exactly just happened there ?  We employed a classic and very common usage method in command-line Perl which can easily be remembered as « pie » :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;« -p » : In a nutshell, this tells Perl to loop through each line of input, then perform the desired action (in this case, the search &amp;amp; replace) against each of those lines.&lt;&#x2F;li&gt;
&lt;li&gt;« -i » : This instructs Perl to actually edit the input files directly (or « in place »), instead of just displaying the changes on the screen.&lt;&#x2F;li&gt;
&lt;li&gt;« -e » : This describes exactly one line of code - in this case, the search and replace regular expression...&lt;&#x2F;li&gt;
&lt;li&gt;« &#x27;s&#x2F;old&#x2F;new&#x2F;&#x27; » : This is the regular expression (or « regex ») which Perl will use to perform the search &amp;amp; replace.  (What&#x27;s a regex ?  &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Regular_expression&quot;&gt;Wikipedia has the answers you seek&lt;&#x2F;a&gt; !)&lt;&#x2F;li&gt;
&lt;li&gt;« *.txt » : The target filename - in this case, a simple glob.  (What&#x27;s a glob ?  &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Glob_(programming)&quot;&gt;Wikipedia has the answer&lt;&#x2F;a&gt; !)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The key to this whole operation was the fourth bullet point - the regex.  Don&#x27;t worry if your regex-fu is not yet strong - this is just an example, and it could have been anything - the point is that Perl can be used to rapidly execute regular expressions on data in simple, easy to execute ways, such as the search &amp;amp; replace one-liner above.  This sort of thing comes in handy on a &lt;em&gt;daily basis&lt;&#x2F;em&gt;, and thus, the perl one-liner is a powerful tool in the System Administrator&#x27;s toolbox.
For more one-liners, use the Google : &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.google.fr&#x2F;search?q=perl+one-liners&quot;&gt;http:&#x2F;&#x2F;www.google.fr&#x2F;search?q=perl+one-liners&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>initrd, modules, and tools</title>
        <published>2009-06-10T00:00:00+00:00</published>
        <updated>2009-06-10T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Dan Maher
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.dark.ca/posts/initrd-modules-and-tools/"/>
        <id>https://blog.dark.ca/posts/initrd-modules-and-tools/</id>
        
        <content type="html" xml:base="https://blog.dark.ca/posts/initrd-modules-and-tools/">&lt;p&gt;Today i thought i&#x27;d discuss initrd, how modules live within it, and an give a generic example of how it can be modified on a Fedora-based system.  Along the way, i&#x27;ll provide supplementary information about gzip, tar, and cpio.  Let&#x27;s begin !&lt;&#x2F;p&gt;
&lt;h3 id=&quot;initrd&quot;&gt;initrd&lt;&#x2F;h3&gt;
&lt;p&gt;The term « initrd » is short for « initial ramdisk ».  It refers to a file of the same name used by Linux systems during the boot process in order to load certain modules (drivers, and the like) prior to the full system being brought online.  An example usage of initrd would be to load a module for a RAID card, so that the actual filesystem - and all of the delicious data contained within - can be accessed properly.  As with most everything, the related &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Initrd&quot;&gt;Wikipedia entry&lt;&#x2F;a&gt; has more general information on the subject.&lt;&#x2F;p&gt;
&lt;p&gt;There are (perhaps unfortunately) a number of ways in which initrds can be constructed and implemented.  Generally speaking, the actual file is a compressed archive, which may contain further archives, filesystems, configuration files, and so forth.  Over the years, different distributions have handled the initrd in different ways, such that one distro&#x27;s method of constructing an initrd may be totally incompatible with that of another.  In fact, even within a single distribution, different releases may alter the internals of the initrd - Fedora being a recent popular example of this.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;fedora&quot;&gt;Fedora&lt;&#x2F;h3&gt;
&lt;p&gt;In the earlier days of Fedora, the initrd was a compressed gzip archive that contained a « squashfs » file, which was itself a compressed filesystem.  If you wanted to modify the contents of the initrd, all you had to do was un-gzip the initial file, then mount the squashed filesystem within. If some or all of these terms are fuzzy for you, don&#x27;t despair - i&#x27;ll explain everything as we go along.  The important thing you need to know now is that in Fedora 8, the nature of the initrd changed significantly.&lt;&#x2F;p&gt;
&lt;p&gt;In order to work with the current Fedora initrd, you need to be familiar with a few terms, their related technologies, and their usage...&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ramdisk&quot;&gt;ramdisk&lt;&#x2F;h3&gt;
&lt;p&gt;A « ramdisk » is, as the name implies, a sort of filesystem which has been loaded into RAM.  Although it does not physically exist, it appears for all intents and purposes to be a normal disk, which has the advantage of being seamless to the user (and to the system).  Ramdisks are handy because, compared to physical disks, they are &lt;em&gt;fast&lt;&#x2F;em&gt;.  Within the context of the initrd, however, speed isn&#x27;t a concern - it&#x27;s the &lt;em&gt;versatility&lt;&#x2F;em&gt; of the ramdisk that is key.  As in the module example i mentioned initially, the various bits and peices of hardware in a given computer often require special drivers to make them function properly.  These drivers can be built directly into the kernel, but often, for reasons of ease of use and cross-compatibility, it&#x27;s easier to put them into the initrd, and then load them via the &lt;em&gt;initial ramdisk&lt;&#x2F;em&gt; that gets built when the machine boots.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;modules-in-general&quot;&gt;modules, in general&lt;&#x2F;h3&gt;
&lt;p&gt;The basic idea behind a « loadable kernel module » (or just module for short) is, again, to add support for hardware, special filesystems, and the like, which the kernel doesn&#x27;t natively understand.  Modules can be loaded at any time, but for the most part, they are initialised at boot time, so that the kernel can interact with things like RAID, audio, or video cards, non-Linux filesystems (NTFS, for example), or even more esoteric items like robotic controllers and (the dreaded) software modems.&lt;&#x2F;p&gt;
&lt;p&gt;As a general rule, modules themselves are single files which are referenced via one or more configuration files.  We&#x27;ll take a closer look at these ideas below.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;gzip-and-tar-too&quot;&gt;gzip (and tar, too !)&lt;&#x2F;h3&gt;
&lt;p&gt;Gzip is, along with « tar », arguably the most ubiquitous archival format pairing in the Linux world.  Generally speaking, a gzip archive is a &lt;em&gt;single file&lt;&#x2F;em&gt; which has been compressed using the gzip binary.  Commonly, gzip is used to compress a « tar » archive, which normally does not use compression, but which can contain &lt;em&gt;any number&lt;&#x2F;em&gt; of files in a single archive.  Together, they are used to create « .tar.gz » or « .tgz » files, which are more or less the standard way to create compressed archives in Linux ; together, they&#x27;re like « zip » or « rar » (or « arj », or « boo ») in the Windows world.  (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Gzip&quot;&gt;Wikipedia&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;Within the context of the Fedora initrd, however, tar is not used - from the pair, only gzip is important.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;cpio&quot;&gt;cpio&lt;&#x2F;h3&gt;
&lt;p&gt;It is a rare and glorious thing when ancient technology is updated and used constantly from day one.  Take the lightbulb, for example.  Or fire.  Or « cpio » .  It&#x27;s basically like tar (mentioned above), in that it can be used to take any number of given files, and create a single archival file containing said files.  Like tar, compression isn&#x27;t part of the deal, and gzip can be used to compress a cpio archive as normal.&lt;&#x2F;p&gt;
&lt;p&gt;While cpio has a long and storied history (it was first specified way back in &lt;em&gt;1977),&lt;&#x2F;em&gt; over the years, it has increasingly replaced by tar in many implementations.  Some time ago, Red Hat decided to use cpio (instead of tar) for their ultra-popular packaging format « RPM ».  This sparked a renewed interest in cpio in many communities, including, as you may have already guessed, the Fedora team - it&#x27;s now employed regularly in the initrd (among other things).  (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Cpio&quot;&gt;Wikipedia&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ok-lets-go&quot;&gt;Ok, lets go !&lt;&#x2F;h2&gt;
&lt;p&gt;The first thing we&#x27;ll need to do is copy the initrd to somewhere handy, like « &#x2F;tmp », so that we can play with a copy .  &lt;em&gt;Never&lt;&#x2F;em&gt; play with the original - it should be preserved somewhere in case our modifications cause the file to become unusable.  The initrd will be named « initrd.img » - but what is it, exactly ?  Let&#x27;s find out :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cp&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;original_initrd.im&lt;&#x2F;span&gt;&lt;span&gt;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cd &#x2F;tmp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; file initrd.img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;initrd.img:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gzip compressed data, from Unix, last modified: Fri Nov&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;  2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 15:54:12 2007, max compression&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ah, it&#x27;s our old friend, gzip.  Since we know that gzip is a file compression tool, we know that initrd.img contains a file - let&#x27;s extract it :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gzip -d initrd.img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;gzip:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; initrd.img: unknown suffix -- ignored&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Uh oh ! By default, gzip doesn&#x27;t handle files with suffixes it doesn&#x27;t understand (i.e. « .gz » ).  The easiest way to deal with this is simply to add the appropriate suffix, then try again :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mv initrd.img initrd.img.gz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gzip -d initrd.img.gz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This gives us a single file (as we expected) : initrd.img .  Though it has the same name as the file we started with, it&#x27;s not the same data at all.  This initrd.img is larger than the original, and most importantly, it&#x27;s a different &lt;em&gt;type&lt;&#x2F;em&gt; of file :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; file initrd.img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;initrd.img:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ASCII cpio archive&lt;&#x2F;span&gt;&lt;span&gt; (SVR4&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; with no CRC&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Ah ha ! It&#x27;s a cpio archive - the first of two we&#x27;ll encounter during this process.  Note the trailing information, that it&#x27;s an « SVR4 » archive, as this is important for the next step : unarchiving.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;unpacking-the-initial-cpio-archive&quot;&gt;Unpacking the initial cpio archive&lt;&#x2F;h3&gt;
&lt;p&gt;As i mentioned above, cpio has a long and storied history, which is reflected in the myriad of arguments and options that can be provided during normal usage.  The command we&#x27;ll be using at this stage will be :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cpio -i -d -H newc -F&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;fil&lt;&#x2F;span&gt;&lt;span&gt;e&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; --no-absolute-filenames&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The arguments are, in order :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;-i : « copy-in » is more or less like saying « extract » in the parlance of cpio.&lt;&#x2F;li&gt;
&lt;li&gt;-d : « make directories » allows cpio to re-create the directory structure in the archive, instead of just unpacking everything to the same place.&lt;&#x2F;li&gt;
&lt;li&gt;-H newc : « format type » defines the particular format used by this cpio archive.  Over the course of cpio&#x27;s history, numerous formats have been used for various reasons : « newc » is an SVR4-based format that allows for large files and filesystems.  Remember the archive type from above ?  This is why we needed to make note of it.&lt;&#x2F;li&gt;
&lt;li&gt;-F &lt;file&gt; : « file filename » simply indicates the file we want to work with.&lt;&#x2F;li&gt;
&lt;li&gt;--no-absolute-filenames : as the name suggests, this forces cpio to unpack the contents relative to where we executed the command.  Basically speaking, it prevents the possibility of cpio trying to write to our root filesystem, which could have disastrous results.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;For more information about cpio, simply consult the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.gnu.org&#x2F;software&#x2F;cpio&#x2F;manual&#x2F;html_mono&#x2F;cpio.html&quot;&gt;GNU cpio manual&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;First we must make a directory in which to unpack the archive, then we can proceed :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mkdir &#x2F;tmp&#x2F;initrd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cd &#x2F;tmp&#x2F;initrd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cpio -i -d -H newc -F ..&#x2F;initrd.img --no-absolute-filenames&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;16442&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; blocks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The number of « blocks » refers to the amount of data that was unpacked - it is a measurement, like bytes.  This value may be different for you, as not all initrd&#x27;s are created equal.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-goods&quot;&gt;the goods&lt;&#x2F;h3&gt;
&lt;p&gt;A simple « ls » reveals the contents of the initrd.  Astute readers will notice that it looks very familiar - this is not a coincidence - it looks like the root of a normal filesystem :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ls -l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 36&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;lrwxrwxrwx&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;    4&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 bin&lt;&#x2F;span&gt;&lt;span&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; sbin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;drwxrwxr-x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4096&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 dev&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;drwxrwxr-x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 3&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4096&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 etc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;lrwxrwxrwx&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;   10&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 init&lt;&#x2F;span&gt;&lt;span&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;sbin&#x2F;init&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;drwxrwxr-x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4096&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 modules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;drwxrwxr-x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4096&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 proc&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;drwxrwxr-x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4096&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 sbin&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;drwxrwxr-x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4096&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 selinux&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;drwxrwxr-x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4096&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 sys&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;drwxrwxr-x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4096&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 tmp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;drwxrwxr-x&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 6&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4096&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 var&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The directory we&#x27;re interested in is « modules » :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cd modules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ls -l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5128&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;   12904&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 module-info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;  137235&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 modules.alias&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4971479&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 modules.cgz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;   37966&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 modules.dep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;   60204&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 pci.ids&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Aah, delicious modules, at last ! But wait - what&#x27;s that « .cgz » file ?&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; file modules.cgz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;modules.cgz:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gzip compressed data, from Unix, last modified: Fri Nov &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 15:54:07 2007, max compression&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Another gzip - but the suffix gives us another hint.  Just as a .tgz is a gzip&#x27;d tar archive, a .cgz indicates a gzip&#x27;d cpio archive.  Of course, as before, we&#x27;ll need to rename this file in order to work with it :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cp modules.cgz &#x2F;tmp&#x2F;modules.gz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cd &#x2F;tmp&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gzip -d modules.gz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; file modules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;modules:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ASCII cpio archive&lt;&#x2F;span&gt;&lt;span&gt; (SVR4&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; with CRC&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;As before, we must create a working directory into which we&#x27;ll unpack the cpio archive.  Be sure to take note of the cpio arguments - there&#x27;s been a change :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; mkdir &#x2F;tmp&#x2F;work&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cd &#x2F;tmp&#x2F;work&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cpio -i -d -H crc -F ..&#x2F;modules --no-absolute-filenames&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;25396&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; blocks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;How did i know to use a different format ? Look again at the file output for modules above, then compare it to the first cpio archive we dealt with.  The difference is subtle, but critical - the cpio manual (linked above) lists them all, just in case.  Ok, let&#x27;s take a look at what we&#x27;ve got.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; tree -d&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;`&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2.6.23.1-42.fc8&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;    `&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; i586&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Here, the string « 2.6.23.1-42.fc8 » refers to the kernel version that the initrd is built for, and the « i586 » refers to the architecture.  Yours may be different (i randomly selected one that was hanging around on my test system), and that&#x27;s OK, because the principles are still the same.  For now, you&#x27;ll note that the i586 directory is full of « .ko » files - these are the module files themselves.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;adding-the-new-module&quot;&gt;adding the new module&lt;&#x2F;h3&gt;
&lt;p&gt;The module that you want to add will be a .ko file as well.  You may have been supplied with this file directly, or perhaps you compiled it from source (which is outside of the scope of this document for today).  Regardless, as you may have guessed, you&#x27;ll want to put it along with all the other modules :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cp &#x2F;tmp&#x2F;new_module&#x2F;network_card.ko &#x2F;tmp&#x2F;work&#x2F;2.6.23.1-42.fc8&#x2F;i586&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With that in place, we&#x27;ll re-pack cpio archive, so that it can be inserted back into the initrd.  Through the magic of re-direction, we&#x27;ll accomplish this all in one swift command :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cd &#x2F;tmp&#x2F;work&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; find 2.6.23.1-42.fc8&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cpio&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -o -H crc&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; gzip&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;modules.cgz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;25590&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; blocks&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Whoah ! Let&#x27;s break that down :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;« find » was used to create a list of all the files with their relative directories.  Run « find &lt;dir&gt; » by itself to get a better idea of what this means.&lt;&#x2F;li&gt;
&lt;li&gt;That list was then piped to cpio, where « -o » indicated that a new archive should be created (« copy-out » in the cpio parlance).&lt;&#x2F;li&gt;
&lt;li&gt;That was then directly passed to gzip, which ultimately outputted the gzip&#x27;d cpio file « modules.cgz » .  Simple !&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Now we can copy this shiny new modules.cgz into the initrd tree :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cp &#x2F;tmp&#x2F;modules.cgz &#x2F;tmp&#x2F;initrd&#x2F;modules&#x2F;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;cp:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; overwrite&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; `&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;tmp&#x2F;initrd&#x2F;modules&#x2F;modules.cgz&amp;#39;? y&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;At this point, there&#x27;s a very good chance that you&#x27;ll need to modify a handful more items related to modules - in particular, the &lt;em&gt;other&lt;&#x2F;em&gt; files in the modules directory :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cd &#x2F;tmp&#x2F;initrd&#x2F;modules&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; ls -l&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;total&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5228&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;   12904&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 module-info&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;  137235&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 modules.alias&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5074769&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 17:35 modules.cgz&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;   37966&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 modules.dep&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;-rw-r--r--&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; dan dan&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;   60204&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 2009-06-10 16:37 pci.ids&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There&#x27;s our new modules.cgz, as you can see from the timestamp difference, along with the other items from before.  Those other items are all text files which contain various bits and pieces of information related to the modules contained in modules.cgz .  As this is a generic sort of post, i can&#x27;t go into specifics about how each of these files would be modified for any &lt;em&gt;actual&lt;&#x2F;em&gt; module ; that said, a general overview of each of these items is most certainly in order :&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;« module-info » : This file contains a an alphabetical list of each of the modules, with two lines per module that describe the type of device the module affects, and a verbose (i.e. human-readable) description of the module.  It is the most simplistic of the four, and the one most easily read by a human.  Example :&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;e1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;        eth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;        &amp;quot;Intel(R) PRO&#x2F;1000 Network Driver&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In this case, the module is named « e1000» , it affects Ethernet ( « eth » ) devices, and is an Intel gigabit NIC driver.&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;« modules.alias » : Under normal usage, hardware will expose certain information to the kernel that helps the kernel to properly identify and assign said hardware.  This is done via a sort of identification string, which contains (in machine-readable format) such things as the bus used by the hardware, the vendor and device id&#x27;s, and other such sundry items.  Normally, the system takes care of populating this file on its own, but in the case of the initrd, this doesn&#x27;t happen.  As a result, it is highly likely that you&#x27;ll need to insert the identification string for your hardware manually ; hopefully, your module came with some documentation to help with this.
&lt;ul&gt;
&lt;li&gt;If your module didn&#x27;t come with the appropriate documentation, you could always try putting the hardware into an already-installed system, and then poking around for it manually.  More information is available from the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;wiki.archlinux.org&#x2F;index.php&#x2F;ModaliasPrimer&quot;&gt;ArchLinux wiki&lt;&#x2F;a&gt;.&lt;&#x2F;li&gt;
&lt;li&gt;This file, since it&#x27;s normally generated automatically, and used behind the scenes, is the most daunting of the four.  Once you get a handle on how the string is built, however, it stops being scary, and starts being merely irritating.  I&#x27;m not going to lie - this file is tough.  Google is your friend on this one !&lt;&#x2F;li&gt;
&lt;li&gt;Example :&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-support z-function&quot;&gt;alias&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; pci:v00008086d0000108Bsv&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;sd&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;bc&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;sc&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;i&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-language&quot;&gt;*&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; e1000&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;« modules.dep » : This lists the « dependencies » for each module - effectively, it&#x27;s a list of what modules the &lt;em&gt;other&lt;&#x2F;em&gt; modules depend on.  Sometimes modules are designed to operate completely independently (such as the above-noted e1000 module), while other times they build on each other, with each module providing certain functionalities used by the next.  This file builds those relationships.  Example :&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;msdos:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; fat&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;ul&gt;
&lt;li&gt;« pci.ids » : Finally, can you guess what&#x27;s listed in this file ?  If you guessed « PCI IDs », you&#x27;re right !  This file is in the same genre as modules.alias, in that it contains a list of hardware identifiers that are used by the kernel in order to properly assign drivers and so forth.  Again, as with modules.alias, this data is not necessarily obvious, and your hardware documentation should list the appropriate identifiers.
&lt;ul&gt;
&lt;li&gt;In the event that your documentation doesn&#x27;t have this information, there are two excellent sites that contain information on known PCI IDs : the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;pciids.sourceforge.net&#x2F;&quot;&gt;PCI ID Repository&lt;&#x2F;a&gt;, and the &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.pcidatabase.com&#x2F;index.php&quot;&gt;PCI Vendor and Device List&lt;&#x2F;a&gt;.  Not exactly bedtime reading, i know, but they&#x27;re both life-savers !&lt;&#x2F;li&gt;
&lt;li&gt;Example :&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;101e&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  American Megatrends Inc.&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;        1960&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  MegaRAID&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;        9010&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  MegaRAID&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 428&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Ultra RAID Controller&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;        9060&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;  MegaRAID&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 434&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; Ultra GT RAID Controller&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Once these files have been properly updated, the only step that remains is re-packaging everything into a proper initrd.img !&lt;&#x2F;p&gt;
&lt;h3 id=&quot;new-initrd-img&quot;&gt;new initrd.img&lt;&#x2F;h3&gt;
&lt;p&gt;Here in the final step we&#x27;ll leverage the power of re-direction and create our initrd.img in one fell swoop :&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; cd &#x2F;tmp&#x2F;initrd&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; find .&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; cpio&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; -o -H newc&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; |&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; gzip&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; &#x2F;tmp&#x2F;initrd.img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;$&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; file &#x2F;tmp&#x2F;initrd.img&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;&#x2F;tmp&#x2F;initrd.img:&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; gzip compressed data, from Unix, last modified: Wed Jun&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 10&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt; 19:39:51&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2009&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;And there you have it, a shiny new initrd.img, ready for use in your PXE bootstrap, disk image, or wherever else such things are needed.
Aren&#x27;t sure what a PXE bootstrap is ?  Not sure why you&#x27;d want to use a disk image ?  Stay tuned, fair reader, all will be revealed as we delve deeping into the mysterious land of the Linux System Administrator...&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
