Thursday, July 30, 2026

Two Thousand Times One

This year I re-read G.K. Chesterton's The Man Who Was Thursday. I think I have a new favorite line:

"… there are no words to express the abyss between isolation and having one ally. It may be conceded to the mathematicians that four is twice two. But two is not twice one; two is two thousand times one."

I'm holding onto this a lot this year. Friends are so important to me.

Saturday, July 26, 2025

This door was nearly always locked

Listened to The Silver Chair again this week.

"If only the door was open again!" said Scrubb as they went on, and Jill nodded. For at the top of the shrubbery was a high stone wall and in that wall a door by which you could get out onto open moor. This door was nearly always locked. But there had been times when people had found it open; or perhaps there had been only one time. But you may imagine how the memory of even one time kept people hoping, and trying the door; for if it should happen to be unlocked it would be a splendid way of getting outside the school grounds without being seen. 

I love this picture of the nature of desperation and hope. It resonated with me this week in my life.

Jill and Eustace, now both very hot and very grubby from going
along bent almost double under the laurels, panted up to the wall. And
there was the door, shut as usual.
"It's sure to be no good," said Eustace with his hand on the handle; and then, "O-o-oh. By Gum!!" For the handle turned and the door opened. 

Before we even get to Narnia, Lewis is already setting the stage for the themes of defeat and eucatastrophe - themes that echo through each chapter and crescendo in the climax.

Wednesday, January 22, 2025

returning to Red Hat

Last week I accepted an offer to work at Red Hat in the InstructLab engineering team. I can't wait to join this company again.


Tuesday, July 09, 2024

fail faster: better Python SSH timeouts

I use Python's Paramiko to automate many things at work. Recently I wrote a SFTP client library. It it has a helper method like this:

 def connect(username):
     password = getpass.getpass()
     transport = paramiko.Transport((HOST, PORT))
     transport.connect(username=username, password=password)
     return paramiko.SFTPClient.from_transport(transport)


Callers can do "sftp = connect('kdreyer@example.com')", then do SFTP operations like uploading files, listing directories, etc.

Recently I hit a problem where the SSH server ("HOST") was not available over the network. A firewall was silently dropping TCP packets without rejecting them (RST). As a result, when we called this connect() method in a CI job, we had to wait a long time for this code to time out.

As in all good networking stories, this did not happen every time, only sometimes, and especially at important times when we really needed the connection to work. This CI job was already large and long, the perfect opportunity for losing a human operator's focus and costing even more time when it dies slowly like this.

I began researching how to make Paramiko time out faster.

To begin, I set up another network environment that drops SSH packets in a similar way so that I can reproduce it on my laptop. I found Python was hanging in socket.connect().

It turns out that I can initialize Paramiko's Transport() class two ways. The first way is to pass in my own socket object. This is powerful but too advanced for most Paramiko users, so Paramiko also allows me to initialize with a hostname + port tuple (as I've done above). Transport operates on sockets, so the constructor will create the socket and call socket.connect() for me. Critically, it calls connect() with no timeout. There is no way to pass in a timeout to the Transport() constructor.

At this point I began looking at the broader Paramiko API. It turns out there is a much better way to initialize an SFTP client. Instead of creating my own paramiko.Transport, I can start with paramiko.SSHClient(). This method has several important features (like pre-selecting allowed authentication mechanisms), but the most important is the "timeout" argument! Paramiko sets this timeout on the socket object so we get TimeoutError sooner. I wrote a patch and the new method connect() method looks like this:

 def connect(username):
     password = getpass.getpass()
     client = paramiko.SSHClient()
     client.load_system_host_keys()
     client.connect(HOST, PORT, username, password, timeout=3.0,
                    allow_agent=False, look_for_keys=False)
     return client.open_sftp()


In terms of solving the bigger issue, usually I'd reach for the excellent backoff module in cases where infrastructure is unreliable, but this particular network failure is not one where we can simply catch Paramiko's TimeoutError and retry - unfortunately today it requires human involvement to fix. Eventually I will move the client to a more stable network, but that will require some broader architecture work. This Paramiko fix incrementally improves our operations in the meantime.

Wednesday, December 22, 2021

Intro to Koji video

(Cross-posting here from koji-devel)

This week I created an Introduction to Koji video. Koji is the build system we use for the Fedora Project and Red Hat products.

This video answers the following questions:

  • What is Koji, and how does it work?
  • What is the history of Koji in Fedora?
  • What are the unique design features of Koji?

 


 Direct link here: https://youtu.be/B0xfsJ1G4v0

Wednesday, October 07, 2020

How to succeed at Red Hat

I met someone recently who just graduated college and was on the job search.  I linked him to my favorite podcast episode on this topic. After listening to the episode, this person then asked me:

"What kind of person would succeed as a company such as Red Hat?"

I love this question. I asked around, and one colleague gave the following answer:

"I'd say someone that is passionate about enterprise technology and loves to learn in a fast moving environment."

I love this answer, and I'm going to break it into pieces to explain why this applies.

"Passionate"


This means that you understand more than just code. It means you understand the business (who our customers are, and how do we make customers happy, and why would people pay us money). It also means that you care about your work: you understand who your users are, and you think about how to improve the experience of those users consuming the work that you produce.

"Enterprise technology"


What's Enterprise technology? It's technology that is stable, secure, and used in a wide variety of places. You will be a good fit if:

  • You care about making things work "out of the box" so users can get going quickly without stumbling blocks or a lot of other busy work.
  • You like writing clear documentation to help people who are not complete experts or Linux ninjas
  • You care about making things stable and well-tested (understanding things like "backwards compatibility" and the different types of testing).
  • You care about security (understanding why things like authentication, encryption and signing are important)

"Learning in a fast-paced environment"


In Enterprise software, there is a natural pull to move slowly and stagnate. However, open-source is gigantic and moves incredibly fast. (In fact, the core of Red Hat's value proposition is that Red Hat drives innovation in "upstream" projects and then distills that down into stable products that customers can trust.)

I've been at Red Hat for six years, and the product and technology landscape has changed a lot. During that time, Red Hat acquired Ansible and we've integrated so many things with that now. Ceph used to just integrate with OpenStack, and now we've integrated Ceph with NFS, iSCSI and OpenShift as well. Every year I work on different things and find new ways to integrate new and different projects together.

When I joined Red Hat in 2014, I did not know Python or C++. One of the best things about accepting the job was that I knew I would be surrounding myself with people who knew these languages incredibly well. I picked up so much by osmosis, working alongside some senior developers on the team who could patiently explain things to me.

Technology aside, a few years ago I found the Manager Tools podcast and learned so much about how to communicate effectively (really important at Red Hat were so much work is remote work). I also found a coach and learned how to get really clear on what I want, how to set boundaries effectively, how to finish projects on time, and how to handle personal challenges at work.

"Being a passionate learner" does not mean the often-ridiculed caricature of the programmer who spends every spare night and weekend away from family slaving away on open-source for free. It means someone who spends their time effectively, someone who knows how to balance the critical fire-fighting of the moment with the time to make long-term investments (whether that's technical research or organizational relationship-building). In fact, one of the things I'm passionate about is quitting work on time (or even early) and encouraging folks on my teams to do the same. Quitting on time is how we keep coming back tomorrow.

Saturday, May 02, 2020

in defense of code coverage

"How much do I care about code coverage?"


"100%!" (Kidding.)

SQLite's article on testing is helpful in this discussion. SQLite famously has 100% code coverage, but developers still find and fix bugs in SQLite. Why? Because code coverage is just one part of a testing strategy.

When I find a software project that publishes code coverage metrics, it tells me some things:

  • The developers know what a unit test is, and they care about writing tests. This increases my confidence in the stability of the project and my respect for the developers.
  • If I contribute to this project, I will need to learn enough to contribute a test for my feature as well.
Yes, it's helpful to know the percentage of code coverage for a project. "100%" doesn't mean the project is bug-free. It means that the developers care about shipping quality software, and they have an (imperfect) metric to help achieve that outcome.

Who are my expected users?


This question informs how much effort I put into code coverage.

A) I'm writing a library or API that will be used in many different ways by different teams that do not communicate with me or each other: code coverage tools are very important.

B) I'm writing a specialized tool that will only be used in one well-understood case by my immediate team of developers: coverage is nice to have, but I don't prioritize this as much.

C) I'm writing a one-off script that I will only be the sole user: This depends on a lot of factors of course, but normally I'm not going to put much effort into writing tests.

Of course the answer to "who are my expected users on this project?" can change.  One time I wrote a project for myself that ended up drawing a lot of unexpected users. It's important to periodically reevaluate the nature of a project's user base. Example: "Given the last 12 months, have my users' expectations for stability and quality changed?"

How are my users changing?


On one project I wrote, my first user base was very small. It consisted of developers and hackers who were very involved with feedback, design, and testing. Those original users moved on to other responsibilities, and new users have replaced them who are unfamiliar with the code. They have very different expectations and want your project to "just work".


This is an entirely different scenario. Documentation and regression testing are critical to sustaining the growth of the project. The new user base does not share the initial users' tolerance for breaking changes.

Bug reports will continue to come in. On one recent bug report, once I identified the root-cause and the exact function that is buggy, the next question I ask is "Do the unit tests cover this method?" Code coverage tools can quickly answer this question. This makes it easier for me to confidently modify the method because I know that I'm not introducing regressions.

Summary


Unit tests and code coverage are important, and the question is "how important?".

The best way to evaluate the importance of unit tests and code coverage is asking the question "What is today's cost of introducing and fixing a regression"? On a personal project, it's very low. On a popular core library with many users, the cost is very high. To answer that question accurately, you must understand your users.