Troubleshooting Vagrant Libvirt Simulations

There are a lot of moving parts in a vagrant-libvirt simulation. Vagrant calls the vagrant-libvirt plugin which controls libvirt and libvirt in turn, is used to control QEMU.

Vagrant  → libvirt → qemu

Our troubleshooting is going to focus on the libvirt component. Our solution to vagrant issues is to correct permissions and basically remove all of the files that vagrant uses to keep state. We’ll use a series of virsh commands to manually correct issues with libvirt.

Suggestions to keep yourself out of hot water when working with libvirt simulations:

  • vagrant activities are unique per user so perform all actions from a single non-root user account, do not mix and match

Common Troubleshooting Path:

1). Make sure your user is added to the libvirtd group with the “id” command.

$ id
uid=1000(eric) gid=1000(eric) groups=1000(eric),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare),131(vboxusers),132(libvirtd)

NOTE: to append this group to your user id use this command

sudo usermod -a -G libvirtd userName

log out and log back in for group change to happen

2). Change ownership of everything in that user’s .vagrant.d directory back to the user in question.

$ sudo chown [user] -Rv ~/.vagrant.d/

3). List all Domains (VMs) and their storage volumes (Hard Drives)

$ virsh list --all
$ virsh vol-list default

Images are stored in /var/lib/libvirt/images/

4). Stop each VM, undefine it, and remove the virtual hard drive

$ virsh destroy vagrant_asdfasdf
$ virsh undefine vagrant_asdfasdf
$ virsh vol-delete --pool default vagrant_asdfasdf.img


VM list should be empty now and volume list should not have any of the volumes that correspond to VM names in your simulation.

$ virsh list --all
$ virsh vol-list default


5). Remove the hidden .vagrant directory in simulation folder

$ rm -rfv ./.vagrant/


6). Try your Vagrant up now.

$ vagrant status
$ vagrant up --provider=libvirt


Have VMs that you’ve already removed, stuck in output from “vagrant global-status”?

Remove the machine-index file as follows:

rm ~/.vagrant.d/data/machine-index/index

Use Less Power on Your NAS

Inspired by my read of this article I wanted to do some experimentation on my own NAS server.

The biggest power users (aside from the CPU) are the hard drives. In my NAS I have (5) 3TB WD Red Drives, and (1) 2TB WD Red Drive as well as a pair of Samsung 850 based SSDs. Of course the spinning disks consume the most power. I’m able to determine this based on the UPS which I have connected to the NAS. It has a nice little power meter built-in which I’m sure isn’t extremely accurate but is good enough for my needs.

After much experimentation with the options provided in the article above I found the only things to make a noticeable difference on my NAS were the spindowns of the mechanical harddrives.

Using the following script I was able to cut down my idle power draw from ~72 watts –> ~54 watts for an 18 watt savings or 25% which isn’t too bad!


echo "Setting Power down to 60 seconds."
hdparm -S 12 /dev/sda
hdparm -S 12 /dev/sdb
hdparm -S 12 /dev/sdc
hdparm -S 12 /dev/sde
hdparm -S 12 /dev/sdf

hdparm -S 12 /dev/sdd

echo "Powering Down Hard drives immediately."
hdparm -y /dev/sda
hdparm -y /dev/sdb
hdparm -y /dev/sdc
hdparm -y /dev/sde
hdparm -y /dev/sdf

hdparm -y /dev/sdd




Controlling Docker from Within A Docker Container

I’ve been tinkering with a project to interact with the Docker-Engine api using docker-py. The catch is that the program is running inside a docker container.

Modify /lib/systemd/system/docker.service to fix the Docker daemon to a TCP port.

First create a loopback IP address

sudo ip addr add dev lo

By default the Unix socket used by Docker is inaccessible from inside the container for this reason we need to use TCP.

Modify the ExecStart line to remove the unix socket and instead replace it with the address of your loopback and a port of your choosing. I used 2376 because that is what Docker uses on Windows where the unix sockets are not available.

Description=Docker Application Container Engine
Documentation= docker.socket firewalld.service

# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H
ExecReload=/bin/kill -s HUP $MAINPID
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
ExecReload=/bin/kill -s HUP $MAINPID
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
# set delegate yes so that systemd does not reset the cgroups of docker containers
# kill only the docker process, not all processes in the cgroup


Reload systemd daemons to pull in the new changes to the unit file.

sudo systemctl daemon-reload

Start Docker with the new settings.

sudo systemctl stop docker.service
sudo systemctl start docker.service

Modify your environment variables so you don’t have to use the -H argument everytime you call a docker cli command.

echo "export DOCKER_HOST=" >> ~/.bashrc

Run a new docker image in the new environment.

docker run -itd --name=test ubuntu /bin/bash
docker exec -itd ubuntu /usr/bin/apt-get update -y 
docker exec -itd ubuntu /usr/bin/apt-get install python python-pip -y
docker exec -itd ubuntu /usr/local/bin/pip install docker

Create a Test Script to Try In the Container

import docker
import pprint

# PrettyPrint Setup
pp = pprint.PrettyPrinter(indent=4)

#client = docker.from_env()
#  Custom SETUP
client = docker.DockerClient(base_url='tcp://')

for container in container_list:

Run The Test Script

chmod +x ./
docker cp ./ test:/root/
docker exec -it test /root/

Security: Don’t forget to secure your newly exposed port with IPtables rules!

sudo iptables -t filter -A INPUT -i eth0 -p tcp -m tcp --dport 2376 -j DROP

Migrating From Machine to Machine with Smokeping (and Armbian)

After having purchased an Orange Pi I have been looking for services that it can host on my network. One of the first services that come to mind for me is Smokeping. I love Smokeping it does one thing, and it does it well a true embodiment of the Unix Philosophy.

Enough glorification of Smokeping how do we get it running.

In this case I wasn’t starting from scratch. I already have an installation running on a Raspberry Pi elsewhere in my network. My first attempt had me copying all the files in the /etc/smokeping directory over to the Orange Pi directly. However this did not work. What I came to find is that the RRD files are architecture-specific, as it turns out, while both the Raspberry Pi and Orange Pi are ARM-based, they are not the same version of ARM and hence the RRD files are not directly compatible.

Starting fresh is no good here because I have years of Smokeping data in my existing install that I don’t want to lose; so how to migrate that data.

Scouring some obscure Smokeping mailing lists I was able to put together this procedure.

NOTE: I’m assuming preshared keys have already been setup between the root account of the old and new machines.

# On the New Machine
sudo su
# Install Smokeping
apt-get install smokeping rrdtool sendmail -y
systemctl stop smokeping
# On the Old Machine
sudo su

echo <<EOT >/tmp/


cd /var/lib/smokeping
echo "Stoping SMOKEPING"
service smokeping stop

rm -v ./*/*.xml
for f in ./*/*.rrd; do echo ${f}; rrdtool dump ${f} > ${f}.xml; done

scp -rv ./* root@$NEWMACHINE:/var/lib/smokeping/
scp -v /etc/smokeping/config.d/General root@$NEWMACHINE:/etc/smokeping/config.d/General
scp -v /etc/smokeping/config.d/Targets root@$NEWMACHINE:/etc/smokeping/config.d/Targets
scp -v /etc/smokeping/config.d/Probes root@$NEWMACHINE:/etc/smokeping/config.d/Probes

rm -v ./*/*.xml
service smokeping start

echo "DONE!"

chmod +x /tmp/
# On the New Machine
sudo su
cat <<EOT > /tmp/ 

# convert XML to RRD
cd /var/lib/smokeping

systemctl stop smokeping

rm -v ./*/*.rrd

for f in ./*/*.xml; do echo ${f}; rrdtool restore $f `echo $f |sed s/.xml//g`; done

echo "REMOVING Interim XML FILES..."
rm -v ./*/*.xml
sleep 1

chown -v smokeping:www-data /var/lib/smokeping/*/*.rrd
chmod 755 -Rv /var/lib/smokeping

systemctl restart apache2
systemctl start smokeping

echo "DONE!"

chmod +x /tmp/

This can convert the RRD files to an intermediary XML format that can then be converted back to RRD on the migration target, on Armbian, even with Smokeping installed, rrdtool itself was not installed. After installing rrdtool I operated on the subdirectories full of RRD files in the /var/lib/smokeping/ directory. Once converted to XML I moved the XML files in place on the new machine and converted them back to RRD.

These scripts were used on my machines, hopefully they can help you too!


Fixing LLDPd Default PortID Configuration

LLDPd is a great program written by Vincent Bernat which implements 802.1ab for unix based OSes.

Debian and Ubuntu offer this lovely utility right in their default software repositories meaning that is only an apt-get install away. One caveat is that the default configuration provides the MAC address of the interface instead of the interface name which is unusual compared to the implementation of LLDP in use on most network OS vendors like Cumulus, Cisco, Juniper, Arista etc…

Here is what is sent by default as seen by the far side of the link:

LLDP neighbors:
Interface: swp4, via: LLDP, RID: 2, Time: 0 day, 00:00:12
 ChassisID: mac 52:54:00:b9:e3:98
 SysName: server1
 SysDescr: Ubuntu 16.04 LTS Linux 4.4.0-22-generic #40-Ubuntu SMP Thu May 12 22:03:46 UTC 2016 x86_64
 TTL: 120
 MgmtIP: fe80::5054:ff:feb9:e398
 Capability: Bridge, off
 Capability: Router, off
 Capability: Wlan, off
 Capability: Station, on
 PortID: mac 44:38:39:00:00:06
 PortDescr: eth1
 PMD autoneg: supported: yes, enabled: yes
 Adv: 10Base-T, HD: yes, FD: yes
 Adv: 100Base-TX, HD: yes, FD: yes
 Adv: 1000Base-T, HD: no, FD: yes
 MAU oper type: 1000BaseTFD - Four-pair Category 5 UTP, full duplex mode

Luckily there are knobs to change that behavior. The configuration below will set LLDPd to provide a more similar configuration like a network device might expect.

sudo apt-get install lldpd
sudo bash -c "echo 'configure lldp portidsubtype ifname' > /etc/lldpd.d/port_info.conf"
sudo systemctl restart lldpd.service


Here is the net result of the changed configuration:

Interface: swp4, via: LLDP, RID: 2, Time: 0 day, 00:00:21
 ChassisID: mac 52:54:00:b9:e3:98
 SysName: server1
 SysDescr: Ubuntu 16.04 LTS Linux 4.4.0-22-generic #40-Ubuntu SMP Thu May 12 22:03:46 UTC 2016 x86_64
 TTL: 120
 MgmtIP: fe80::5054:ff:feb9:e398
 Capability: Bridge, off
 Capability: Router, off
 Capability: Wlan, off
 Capability: Station, on
 PortID: ifname eth1
 PortDescr: eth1
 PMD autoneg: supported: yes, enabled: yes
 Adv: 10Base-T, HD: yes, FD: yes
 Adv: 100Base-TX, HD: yes, FD: yes
 Adv: 1000Base-T, HD: no, FD: yes
 MAU oper type: 1000BaseTFD - Four-pair Category 5 UTP, full duplex mode

Securely Wiping a Hard Drive

When getting rid of a hard drive, I, like everyone else like to be secure about it. After collecting my data I usually like to overwrite the drive with garbage. In the past I used to just use the basic DD approach to zero the drive out.

dd if=/dev/zero of=/dev/sd<DRIVE>

This works fine but I started hearing rumors of being able to recover data from a zeroed out drive. Indeed this is partially true. Zeroing out is probably sufficient in most cases.

Ideally, I would write data out from /dev/random or /dev/urandom (whatever your system has) but the amount of entropy that is harnessed here is not enough to saturate the write speed of the drive meaning that it will take forever a very long time. Never the less I was curious to find out about another option to wipe a drive.

This approach uses OpenSSL with seed data from /dev/urandom. Supposedly it is possible to generate about 1.5gbps of garbage data with this technique… I’ll never know though because the write speed of my drive is nowhere near that.


Use the following command to randomize the drive/partition using a randomly-seeded AES cipher from OpenSSL (displaying the optional progress meter with pv):

# openssl enc -aes-256-ctr -pass pass:"$(dd if=/dev/urandom bs=128 count=1 2>/dev/null | base64)" -nosalt </dev/zero \
    | pv -bartpes <DISK_SIZE> | dd bs=64K of=/dev/sd"X"

where the (optional) total disk size in bytes (DISK_SIZE) may be obtained via:

# blockdev --getsize64 /dev/sd"X"

Sidenote: I love the use of PV here, this is an underloved utility that is truly awesome; I’ve only ever used it in one other place. TARing a remote file over SSH for delivery on my local machine (shown below).

ssh –c blowfish user@host  "tar cjpf - /home/user/file" | pv | cat > ./file.tar.bz2

Should I Leave The Window Open?

As the days start to get cooler again in North Carolina I’m always left with this conundrum… should I leave the window open or not?

On one hand I could feel a pleasant draft that cools me and my wife down all evening without having to pay for air conditioning, on the other hand I could end up waking up to a soaked wall as it’s rained in the middle of the night or the air conditioning has kicked on and I’m pumping lovely cool air that I’ve just paid for directly out the open window.

#firstworldproblems…. I know but it is never the less something I think about. So what can be done here? I’ve got a Nest thermostat and am a reasonably competent scripter.

Here is what I put together, a quick webpage that you can hit from any device on the home network and displays the following info…


Turns out there are a few libraries that help us get off to a useful start.

  • weather-cli — this one allows us to pull real time hourly weather info for the next 24 hours based on precise location.
  • flask — flask can be used to quickly serve up a webpage in python
  • python-nest — this is used to get/set data with Nest thermostats.

Interestingly, python-nest and the nest-API  provides some hourly weather info back in a pretty useful form. However it is missing one pivotal piece of data… which is the actual weather conditions for those individual hours, is it raining? is it sunny? that very important datapoint is not present and pretty much the primary reason I’m using weather-cli here.

There’s not a ton of documentation on weather-cli but for the few things that I wanted to know that weren’t documented, there’s always the source-code, and the code was helpful here.

Installing Software

sudo apt-get install python-pip
sudo pip install pip --upgrade
sudo pip install setuptools --upgrade
sudo pip install  weather-cli flask python-nest

Setting Up Weather-CLI

To use weather-cli, you’re going to need a API key, register here to obtain one. With the basic free plan, you have 999 API calls per day for free, enough to check the weather a couple hundred times per day which is more than enough for me.

To get weather-cli set up we need to use the setup argument.

pi@underhousepi ~/scripts/weather_predictor $ sudo weather-cli --setup

Enter your api key (required):xxxxxxxxxxxxxxxxx
The script will try to geolocate your IP.
If you fill the latitude and longitude, you avoid the IP geolocation.
Use it if you want a more acurated result, use a different location,
or just avoid the IP geolocation.
Check your latitude and longitude from

Enter the latitude (optional): 36.982917
Enter the longitude (optional): -75.402301
generating config file...
setup complete

Once setup is complete we can simply call weather-cli and it will return data for us based on the location we used for initial setup.

The rest is writing a quick flask app. Here is the code for that in the gist below. You’ll notice the flask app calls a template. I’ve placed that index.html template in a templates directory as shown below.

Note that I’m also calling the nest api to query the target temperature of the nest device and using that as a basis for whether or not the window open. You could hard-code that value alternatively if you don’t have a nest or for testing purposes. I also have more than one nest in my home so in line 29 I’m calling devices[1] to get to query the second nest in my environment. You may want to change this to devices[0] or another value based on your output from the python-nest api’s documentation page.

user@raspi4 ~/scripts/window_open $ tree
├── templates
│   └── index.html

Here is the code for the template too.

Hope this might save you a few minutes in your search for cool air at an affordable price.