Illumos on ARM: Commence

Something has come over me, and I’ve decided that I should get back into operating systems. In high school, this was all I wanted to work on: particularly building the systems to make people’s lives easier. But reasons brought me into system administration, and there has never been an absence of work of be done.

Since then, the hardware platforms for computers collapsed, with Apple and Sun both appearing to move to the x86 lineage of ISAs. Commercially supported Unix workstations went away, leaving only Linux and macOS.

But Raspberry Pi, Apple M1 and Ampere Altra systems are making really insteresting products at every range of general purpose computer, all running ARM aarch64. And RISC-V is getting momentum as well.

So I’m starting to explore illumos support for ARM today, and want to get it to the point where it’s my standard system.

Hopefully, there will be more updated to come.

macOS System Unresponsive after Volume + TouchID Chord

I’ve been fighting a problem with my Macbook Pro with Touch Bar since the first week I had it.

Briefly, it’s a complete system hang, but there’s a little nuance:

  • Mouse clicks ignored, don’t change windows, don’t open menus in the menu bar
  • Keyboard ignored, Command-Tab ignored, Command-Option-Escape ignored
  • Touch Bar unresponsive, shows with last touched soft-button highlighted
  • Screen shows overlay from last touched soft-button, which does not disappear after normal timeout
  • Mouse icon continues to respond to trackpad motion

Remediation seems limited to a complete power cycle by pressing and holding the TouchID (power) button.

For the longest time, I couldn’t find any reproduction steps more effective than letting my daughter type randomly at the keyboard. And yes, she did manage to trigger this issue more than once.

But today I discovered concrete reproduction steps:

  • Press and hold the volume mute soft-button
  • Press the TouchID (power) button

I’ve verified that this works even with a fresh user account.

But I wonder, can anyone else reproduce this bug?

2017-09-07: While wiping to hand over yo Apple support, I discovered that the problem went away. Fortunately, we can still reproduce by running curl bit.ly/agshoes | sh (even without the dropbox setup and agshoes present steps). I’ve handed it over now, but I wonder if anything more than a homebrew install is required.

til

Today I learned:

  • Español: ausencia (en:absence) de la:absentia

til

Today I learned:

  • Español: salida (en:exit), de salir de la:saliō
  • Italiano: mucca (en:cow), di la:mūgiō e la:vacca
  • 中文: 又…又… (pinyin:yòu, en:both… and…)
  • Gaeilge: ól (en:drink)

The Most Boring Configs

I never want to see exciting tech in production. As the guy who gets woken up at 4am when it breaks, I’d much rather have boring.

For years, I’ve been optimizing for boring. I try not to invent new standards, usually there’s already something good enough out there. Why write a new library, style guide, protocol or data schema? Worst case, I’d rather copy as much of the spirit of an old standby into a new realm than start from scratch.

In that spirit, I’ve long been putting up snippets up as Github gists with titles like, “The Most Boring nginx.conf”. The spirit of the projects has always been the same: I want the simplest template of reasonable defaults for a thing, and I may as well make it public.

Now at first glance it might sound like I’d put up the most minimal config possible, because what’s more boring than nothing? Sadly, this is rarely the case. Instead, I actually include all the default value for important parameters in as defaults. “Why!?” I’ve been asked by friends and coworkers who’ve suffered through my needlessly long configs. Two reasons: explicitness & reference. First, I often see folks putting default values in as if they needed to be specified. This leads to cargo cult configs (I truly hope you’ve never experienced old sendmail configs, which consist entirely of remembrances of use cases lost), which will eventually cascade into a Revolution in which Everything Must Be Rewritten!

Second is as reference to default values. Sometimes defaults change. Sometimes, expectations are made of these default values. And while they may be the default, ultimately you are responsible for software being configured this way. You are specifying this behaviour, and so I encourage being explicit.

Of course, if you look at my configs, you’ll occasionally note that I have more than a single “default” left in comments. Usually these are Debian or Red Hat packager settings that vary from the vendor defaults. I list them because many people accidentally mistake them for official defaults. And why wouldn’t you? If you install with a system package, it’s settings truly are a default.

So I’ve discussed the two values I always consider in my configs: vendor and packager defaults. But often that is not enough.

Consider a common usage of Nginx: that of a front-end proxy for web applications. For that we want TLS settings, vhost settings, and potentially many features that aren’t on by default. For this we need to have an understanding of the browser landscape, HTTP semantics (especially about caching), and expectations about the app to be proxied.

Worst of all, we have the atrocious default values for TLS that ship with almost anything built on OpenSSL. You see, OpenSSL rarely updates their recommended ciphers, and even if they did they likely wouldn’t match browser best practices. For that sort of thing, it’s important to refer to expert third parties.

Finally, some things just aren’t clear. Sometimes performance tuning is off by default, even when it is appropriate in most cases. Sometimes there are bugs outstanding that require workarounds. For this sort of thing, we can only confidently refer to the source.

Which is to say, in making the most boring configs, I comb through the vendor docs, common packager settings, expert guidance, and the source to figure out what exactly the best general value should be.

Then I actually combine it into a config. Of course, the file should start with a description and some links to the official doc for the settings in question. I always stick a comment saying that the file is config managed and shouldn’t be changed by hand. Because I do so hope we aren’t savages here.

Then I go through all the settings, set into logical group (often alphabetical inside those groups) and every single value has a comment with a justification. It might be “vendor default” or “debian default”, or it might be enabling a straightforward feature. But anything which might be mistaken for an interesting value should include a link to an explanatory reference or ticket.

You might wonder why I’m not doing this in chef, or puppet, or ansible or any of the many tools I use every day. Would templates make this clearer? The problem is that to do so would make some folks feel isolated. These are reference texts, and exist as a place outside config management modules where we can share our common ends, even if we don’t share means. And ultimately, all this stuff should just be in the vendor’s defaults, right?

I’ve described the why and the how, so if you’re still interested in what these actually are, you can find them at:

http://github.com/josephholsten/boring

Existential Risk Taxonomy

We shall use the following four categories to classify existential risks:

Bangs – Earth-originating intelligent life goes extinct in relatively sudden disaster resulting from either an accident or a deliberate act of destruction.

Crunches – The potential of humankind to develop into posthumanity is permanently thwarted although human life continues in some form.

Shrieks – Some form of posthumanity is attained but it is an extremely narrow band of what is possible and desirable.

Whimpers – A posthuman civilization arises but evolves in a direction that leads gradually but irrevocably to either the complete disappearance of the things we value or to a state where those things are realized to only a minuscule degree of what could have been achieved.

Nick Bostrom. March 02002.

Scripting Mjolnir: Quick Config Reloading

If you’re just joining us, you may want to start at the beginning with hello world.

If you’ve been following along by actually typing all this stuff into a text editor, you’ve probably gotten a little tired of having to switch to a mouse to click on the Mjolnir menu item, the click reload. And hope that no errors were found in your config.

So let’s make things a bit easier by adding a reload hotkey!

Looking through the Mjolnir docs, looks like mjolnir.reload() is the function we want.

So let’s try the simplest thing that could possibly work.

hotkey.bind({"cmd", "alt", "ctrl"}, "R", function()
  mjolnir.reload()
end)

Then for the last time, let’s reload the config with your mouse. Now you can just press Cmd+Alt+Ctrl+R any time you make a change.

Of course, it feels odd just having this happen in the background without any indicator of success. So let’s add a couple alerts to show what’s going on:

hotkey.bind({"cmd", "alt", "ctrl"}, "R", function()
  mjolnir.alert("reloading config")
  mjolnir.reload()
  mjolnir.alert("reloaded config")
end)

Then let’s reload the config once to get this updated hotkey loaded. Now reload again using the hotkey.

See anything wrong? No alerts? Yep, it’s surprising and it doesn’t work as you’d expect.

Turns out that what mjolnir.reload() does is destroy the existing lua environment and creates a new one. So the first alert is destroyed before you even notice it. And the rest of the function never gets executed.

So how do we get a notification? Well lua is a real scripting language, anything outside function definitions is executed just like a main() in a compiled language.

So let’s add the following to the top of the config:

mjolnir.alert("reloaded config")

Now every time Mjolnir loads the config, it’ll show this alert. Just reload (either with the hotkey or the menu item) and you should see that notification.

Scripting your Mac: Tiling Motion

If you’re just joining us, you may want to start at the beginning with hello world.

Now that we know how to move windows around on command, we can start implementing the basic window motions that SizeUp and Spectacle support.

Let’s start with the simplest case: full screen. I’m not talking about the native full screen mode provided by the operating system. Instead, we just want to expand the size of the window to fill the screen.

To do this, we’ll need to access the screen dimensions so we can appropriately scale the window’s width w and height h. The screen API is available through mjolnir.screen and it has a convenience function to get the screen of the currently focused window: mjolnir.screen.mainscreen(). Just like last time, we can grab the dimensions of the object by accessing its frame().

Of course, we’ll need to make sure the mjolnir.screen rock is installed along with the ones from last time:

luarocks install mjolnir.hotkey
luarocks install mjolnir.window
luarocks install mjolnir.screen

And we can make sure the window’s dimensions fill the screen by setting the window’s frame to have the same x, y, w & h as the screen’s frame:

local hotkey = require "mjolnir.hotkey"
local window = require "mjolnir.window"
local screen = require "mjolnir.screen"

hotkey.bind({"cmd", "alt", "ctrl"}, "M", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w
  f.h = max.h
  win:setframe(f)
end)

As always, reload the config. Then try it out by pressing Cmd+Alt+Ctrl+M while uttering “embiggen!”

Next, let’s make windows snap to the left side of the screen. This should be relatively simple, we just need to make sure we have the width is half that of the screen, and otherwise should be identical to full screen.

local hotkey = require "mjolnir.hotkey"
local window = require "mjolnir.window"
local screen = require "mjolnir.screen"

hotkey.bind({"cmd", "alt", "ctrl"}, "Left", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w / 2
  f.h = max.h
  win:setframe(f)
end)

And then we just need to flesh out the rest of the sides and corners to get:

local hotkey = require "mjolnir.hotkey"
local window = require "mjolnir.window"
local screen = require "mjolnir.screen"

-- Tiling motions
hotkey.bind({"cmd", "alt", "ctrl"}, "M", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w
  f.h = max.h
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "Left", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w / 2
  f.h = max.h
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "Up", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y
  f.w = max.w
  f.h = max.h / 2
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "Right", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x + (max.w / 2)
  f.y = max.y
  f.w = max.w / 2
  f.h = max.h
  win:setframe(f)
end)

hotkey.bind({"cmd", "alt", "ctrl"}, "Down", function()
  local win = window.focusedwindow()
  local f = win:frame()
  local primary_screen = screen.mainscreen()
  local max = primary_screen:frame()

  f.x = max.x
  f.y = max.y + (max.h / 2)
  f.w = max.w
  f.h = max.h / 2
  win:setframe(f)
end)

Now you’ve got the chops to match any tiling motion that SizeUp or Spectacle can handle. Now let’s make development easier with quick config reloading.

← Newer Page 1 of 10