I just got a new laptop with Secure Boot and was having trouble getting Windows and Fedora installed in a dual boot configuration.  I read a few posts on how to do it by changing the bios to Legacy mode but that didn't seem like much fun.  Fedora 30 installed to secure with no problem, so I knew it was possible.

I started by paritioning the disk with a GPT partition table and the following partitions:

p1 /boot ext4
p2 /boot/efi vfat
p3 lvm
p4 Microsoft basic data

Initially I didn't partition p4 at all, and got the windows installer to create that partition later.

I installed Fedora 30 from USB with secure boot and EFI enabled. My Lenovo laptop features a Novo button that has to be used to access the boot menu. Everything worked but I had no boot menu. I entered the bios boot menu and booted the Windows USB. After installing Windows I could only switch between Windows and Fedora by pressing the Novo button. This is inconvenient on my laptop as the Novo button is recessed and requires a pin to press.

To install Grub2 in the EFI with a boot menu, I booted from the Fedora installation media and then mounted /boot and /boot/efi overtop of the live filesystem:

# mount /dev/nvme0n1p1 /boot
# mount /dev/nvme0n1p2 /boot/efi

I then installed the grub2-efi-x64-modules rpm and the efibootmgr rpm.

After installing the rpms, I ran grub2-mkconfig to generate a new grub.cfg

# grub2-mkconfig -o /boot/efi/EFI/fedora/grub.cfg

As noted on the Fedora Project Wiki I did not run grub2-install, I used efibootmgr to create an entry for grub.

# efibootmgr -c -L GRUB2 -d /dev/nvme0n1 -p 2 -l "\EFI\fedora\grubx64.efi"

I was then able to verify the entry with efibootmgr -v:

BootCurrent: 0003
Timeout: 0 seconds
BootOrder: 0005,0003,0000,0001,0006,0004,0002,2001,2002,2003
Boot0000* GRUB2 HD(2,GPT,2a3dbf30-521f-44aa-8f89-2dc2a4cd022d,0xef000,0xee800)/File(\EFI\fedora\grubx64.efi)
Boot0001* Linux HD(2,GPT,2a3dbf30-521f-44aa-8f89-2dc2a4cd022d,0xef000,0xee800)/File(\EFI\fedora\shimx64.efi)
Boot0002* Fedora HD(2,GPT,2a3dbf30-521f-44aa-8f89-2dc2a4cd022d,0xef000,0xee800)/File(\EFI\fedora\shim.efi)RC
Boot0003* Fedora HD(2,GPT,2a3dbf30-521f-44aa-8f89-2dc2a4cd022d,0xef000,0xee800)/File(\EFI\fedora\shimx64.efi)
Boot0004* Linpus lite HD(2,GPT,2a3dbf30-521f-44aa-8f89-2dc2a4cd022d,0xef000,0xee800)/File(\EFI\Boot\grubx64.efi)RC
Boot0006* Windows Boot Manager HD(2,GPT,2a3dbf30-521f-44aa-8f89-2dc2a4cd022d,0xef000,0xee800)/File(\EFI\Microsoft\Boot\bootmgfw.efi)WINDOWS.........x...B.C.D.O.B.J.E.C.T.=.{.9.d.e.a.8.6.2.c.-.5.c.d.d.-.4.e.7.0.-.a.c.c.1.-.f.3.2.b.3.4.4.d.}...a................
Boot2001* EFI USB Device RC
Boot2003* EFI Network RC

Once you are satisfied with your boot options, you can delete entries with "-B -b xxxx" where xxxx is the number you wish to delete.

# efibootmgr -B -b 0005

On the first reboot you will need to install the keys for grub into the MUK, this is outlined on this page. In my case I had to use the "hash" option and then import the keys for the \EFI\fedora\grubx64.efi and \EFI\BOOT\BOOTX64.efi. Once the keys are imported, grub should fire right up.

Now when I reboot, Grub2 is displayed before Fedora Boots, I can also select Windows from the Grub2 menu.

This stack exchange link was also helpful in figuring this out: https://superuser.com/questions/376470/how-to-reinstall-grub2-efi

For reasons I'm running vagrant with VirtualBox inside a docker container.  Most of the time this goes great and no problems, but when it fails it's difficult to see what's happening on the machine.  I've tried and failed to get VNC going on the vm running inside the container. I should note that my problem is with Windows VMs, with Linux VMs it's never a problem to get console. My workaround for Windows is to use screenshots and send keystrokes to the vm via vboxmanage.

First step is to get the uuid or name of the vm

List vms

$ vboxmanage list vms
"foo" {34bcbbef-ffff-4d2d-8546-031d7b597332}
"bar" {06e5696c-ffff-4c44-908e-e38aac1152fd}
"rhel76" {312f38c2-ffff-4e46-af79-6c951eeef63d}
"win2012" {4230645c-ffff-4c38-a933-a78787521ea6}
"win2019" {92d7e563-ffff-444d-afd4-242a9e24d219}

You can use either the name or the uuid to then controlvm:


$ vboxmanage controlvm win2019 screenshotpng win2019.png

You can then view that PNG to see what's on the screen right now. Next, you can send keyboard input to the VM using keyboardputscancode

Control-Alt-Delete on the VM

$ vboxmanage controlvm foo keyboardputscancode 1D 38 53 D3 B8 9D

Using this scancodes page to figure out what keystrokes you wish to type on the VM. The above corresponds to Keypress Ctrl, Keypress Alt, Keypress Del, Release Del, Release Alt, Release Ctl. You can use printf to print the Release codes, the release codes are the Keypress codes + 0x80, so for 1d:
$ printf '%#X\n' "$((0x80+0x1d))"

Using the same trick we can fake a Windows Logo key press and release with "E0 5B E0 DB", so to do a "Run Command" with the Windows Logo Key:

$ vboxmanage controlvm foo keyboardputscancode E0 5B 13 E0 DB 93
$ vboxmanage controlvm foo keyboardputstring "CMD"
$ vboxmanage controlvm foo keyboardputscancode 1C 9C

This types a Windows Key + R, then releases both. I then type "CMD" and then 1C 9C is an Enter. You can also cheat above using a Ctl-J in the string, if you type CMD then Ctrl-V Ctl-J, you'll get a literal carriage return in your keyboardputstring which will be sent to the remote host.

Using this method you can "view" the screen on your vm and "type" without having a real console.

It's worth noting that VRDP should work here, but I've had no success getting that working remotely. I only have SSH access to the vsphere host running docker/vagrant. VRDP will not work without the EXTPACK installed in virtualbox as well, you need to install the EXTPACK before trying VRDP.

Getting nokogiri to install was failing for me. I'm using bundler and needed nokogiri. Gem is trying to compile it and failing on libxml2.

At first I tried using the libxml from brew, that that didn't work, so specified where to find XCode's version of libxml in my bundle config.

BUNDLE_BUILD__NOKOGIRI: "--use-system-libraries=true --with-xml2-include=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/libxml2"

You might need to tweak the MacOSX10.14.sdk part, that's for Mojave, I've been using this line for a while, and just updated from 10.12->10.13->10.14.

I also like to install the gems in my home directory, so I add the following to my bundle config:
BUNDLE_PATH: "/Users/thomas/.gem"

We build our Jenkins from a docker container, setting up that with code requires setting up the plugin from groovy. I didn't want to figure out how to translate our config for the plain mailer plugin to the email-ext plugin. I started using the plain mailer plugin but decided I'd like to send the email in HTML format. Once again, Jenkins docs were terrible, but reading the code, it looked like mimetype was supported.

I came up with the following code to send an HTML email from the Jenkinsfile

  mail to: env.REQUESTOR,
    subject: "Pipeline: ${currentBuild.fullDisplayName} ${currentBuild.result}",
    mimeType: "text/html",
    body: """
<h1>Pipeline: ${currentBuild.fullDisplayName}</h1>
<h2><a href="${env.RUN_DISPLAY_URL}">Build ${currentBuild.id} Results</a></h2>
<h2><a href="${env.JOB_DISPLAY_URL}">${currentBuild.projectName}</a></h2>

This results in an email that is correctly displayed by Outlook and Gmail.

Just in case someone wants to see the config for the plain mailer...

import hudson.tasks.Mailer
def m = Mailer.descriptor()

I needed to checkout some code from another repository into my project, but I only wanted a specific directory within the other repository.

As usual with Jenkins, the docs are lacking, but reading the source for a bit I came up with the following:

dir('otherrepo') {
          checkout([$class: 'GitSCM',
            branches: [[name: '*/master']],
            doGenerateSubmoduleConfigurations: false,
            extensions: [
                $class: 'SparseCheckoutPaths',
                sparseCheckoutPaths: [
                  [ $class: 'SparseCheckoutPath', path: 'goodthing/' ]]
            submoduleCfg: [],
            userRemoteConfigs: [[credentialsId: 'ACTIVE_DIRECTORY',
            url: 'https://github.com/uphillian/otherrepo.git']]

According to the code, you should also be able to remove paths with `!` in the path, but I had trouble with this. I believe if the badpath is nested under the good path, it doesn't work.

dir('otherrepo') {
          checkout([$class: 'GitSCM',
            branches: [[name: '*/master']],
            doGenerateSubmoduleConfigurations: false,
            extensions: [
                $class: 'SparseCheckoutPaths',
                sparseCheckoutPaths: [
                  [ $class: 'SparseCheckoutPath', path: '!goodthing/badthing/*', path: 'scripts/' ],
            submoduleCfg: [],
            userRemoteConfigs: [[credentialsId: 'ACTIVE_DIRECTORY',
            url: 'https://github.com/uphillian/otherrepo.git']]

Doing this I only get the goodthing directory in the otherrepo directory in the workspace.

Talk I gave at #LISA2018. I've given this talk as a half day tutorial, at LISA2018 I gave it in 90minutes. The bulk of the talk is laying a solid foundation on how Linux works.


My iPad got updated to 11.3 and I lost the ability to use my usb-midi interface reliably. I had an M-Audio Uno which worked great on 10.3.3. On 11.3 it keeps stopping and a dialog is displayed stating that the "accessory is unsupported".

I think this is related to the M-Audio using more than 100mA. My lightning adapter couldn't inject voltage, so I looked at getting a Bluetooth MIDI adapter.

I ordered an MD-BT01 and of course the iPad could not see the adapter. I was able to see the device on my Android Phone and other Bluetooth devices. I found that you can install the MD-BT01 utility from the App Store, you have to search for MD-BT01, then select Filters and change from iPad only to iPhone only.

After installing that, you can see the adapter but still not use it. I had to install "Yamaha Synth Book" (you also need to filter for iPhone only to install this) and follow the instructions on yamaha's website

After that the adapter works. I haven't received any disconnect messages from the piano after that.

I made a data_hash backend for hiera that uses the puppet certificate certname to connect to a remote http service and retrieve hieradata for a node. The http backend is up to you, in my implementation I also verified the certificate was signed by the Puppet CA.

This backend uses data_hash, so that it only looks up hiera once per catalog compilation. If it finds hieradata for a node, it updates the hiera cache.

The github repo is located here https://github.com/uphillian/http_data_hash

I wanted to export my playlists with Plex, I installed Export Tools and ended up with CSV files.

I looked around and couldn't find something to convert those to m3u. I did get a m3u8 file but it didn't work with my devices...

I made a quick python script to convert the csv to m3u...it's possibly useful to someone else...maybe.

#!/usr/bin/env python

import csv
import getopt
import sys

options,remainder = getopt.getopt(sys.argv[1:], 'f:r:', ['filename=','root='])

for opt,arg in options:
if opt in ('-f', '--filename'):
filename = arg
elif opt in ('-r', '--root'):
root = arg

# convert time to seconds
def get_s(t):
return sum(int(x) * 60 ** i for i,x in enumerate(reversed(t.split(":"))))
return 0

with open(filename,'r') as csvfile:
# skip header
playlist = csv.reader(csvfile)
print "#EXTM3U"
for song in playlist:
print "#EXTINF: %s,%s - %s" % (get_s(song[9]),song[3],song[5])
print song[-1][len(root):]
print "Error opening CSV file"

https://t.co/AGeihMALAv configuring grub2 with EFI Fri Sep 13 05:20:01 +0000 2019

I published a Thing on @thingiverse! https://t.co/IYpRyEb7Hz #thingalert Tue Jul 23 19:27:57 +0000 2019

Nokogiri install on MacOSX https://t.co/v3An0miW9L Fri Jul 12 15:06:49 +0000 2019

HTML email with plain mailer plugin on Jenkins https://t.co/Z6FSDMDjy8 Thu Jul 11 21:07:25 +0000 2019

git sparse checkout within Jenkinsfile https://t.co/tcL7V8mzFK Thu Jul 11 20:40:53 +0000 2019