Lightweight VMs With Docker

If you wanted to use Docker for very lightweight VMs for e.g. testing different Linux or BSD distributions, I will describe here one method of doing so. I'm very new to Docker myself.

First step is to install Docker, this is pretty straightforward, it is available for Linux, Windows and Mac.

Don't forget to go into the preferences and set the amount of RAM and number of CPUs you want available to your containers. If you are going to be e.g. compiling things, this is especially important.

Since the base images are very lightweight and don't run services or a GUI, you can get away with using less RAM then you would with a traditional VM.

Create the Image

Let's use Debian as an example, first pull the version you want, the format <dist>:<release>, so we are going to get Debian Jessie:

docker pull debian:jessie

Now we need to set it up, open a root shell with:

docker run -h debian-vm --detach-keys="ctrl-@" -it debian:jessie bash

This runs the image in a container with the hostname set to debian-vm, and the detach key set to ctrl-shift-2, and opens an interactive session with bash as the command.

Instead of debian:jessie you can use e.g. ubuntu:trusty or just about anything, look on Docker Hub for available images.

From here you want to use adduser to create your user, install some essential packages like sudo, vim, tmux, etc., and set up your home directory, etc. When you are done exit the shell, and we are going to save the image.

Run this command:

docker ps -a --filter="status=exited" | head

We are interested in the first line, the output will look something like this:

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                         PORTS               NAMES
eade5e91d060        debian:jessie       "bash"              3 minutes ago       Exited (0) 17 seconds ago                          serene_booth

Note the CONTAINER ID, we will use this to save the image, like so:

docker commit eade5e91d060 rkitover/debian:jessie

Here rkitover is my user name and Docker ID on Docker Hub and rkitover/debian:jessie will be the full name of the image.

Launching the Container

Now let's make a handy bash function to launch the container and automatically commit our work when done. Put something like this in your ~/.bashrc:

debian-vm() {
    docker run -h debian-vm --detach-keys="ctrl-@" -it -u rkitover rkitover/debian:jessie bash -l
    docker commit $(docker ps -a --filter="status=exited" | head -2 | tail -1 | awk '{ print $1 " " $2 }')
}

Here the user I created in the image is rkitover and it will launch bash as that user as a login shell. When the shell exits, it will commit changes in the filesystem back to the image.

If you use ctrl-shift-2 to detach from the container, you can reattach back to your terminal session with docker attach CONTAINER_ID, and as you've seen you can get the CONTAINER ID from docker ps -a.

NOTE: the above function doesn't handle detaching and reattaching to containers, if you do that, you will need to commit it to your image manually.

If you want to make a "snapshot", just commit the CONTAINER ID to another image name.

Configuration Notes

For the user in your container, my ~/.profile looks something like this:

cd $HOME
export SHELL=/bin/bash
. "$HOME/.bashrc"

And since the base images are bare and universal, you'll want to set your time zone and locale information at the top of ~/.bashrc, e.g.:

export LANG=en_US.UTF-8
export TZ=PST8PDT

Setting locale is important so you don't have issues with your terminal being screwy, although I found that the terminal can still have some issues.

Cleanup Cron Job

It's a good idea to have something to clean up unused containers and dangling images, I have a nightly cron job the script for which looks like this:

#!/bin/sh
  

docker inspect -f '{{if not .State.Running}}{{.Id}} {{ end }}' $(docker ps -aq) | grep -Ev '^$' | \
    xargs docker rm >/dev/null 2>&1
  

docker images -qf dangling=true | xargs docker rmi >/dev/null 2>&1
  

exit 0

That's all I have, as I said, I'm very new to Docker myself, and this is just one way of using it that isn't even primarily what it's meant to be used for.

Read more...

Last modified: 2017-1-30 (月) at 6:24 am

Charter 6rd IPV6 Tunnel on DD-WRT

I have a Linksys EA6500v1 at this house with Charter internet. This particular router doesn't have a good version of Tomato or OpenWRT available for it, so I was stuck with DD-WRT. And Charter does not have native IPV6 support, only a 6rd tunnel.

I will describe here how to configure DD-WRT for a 6rd tunnel such as the one Charter has.

Setup -> IPV6

Set IPV6 to Enabled, choose "Native IPV6 from ISP" (even though this is a lie) and add Google's IPV6 DNS servers for Static DNS 1 and 2, which are:

2001:4860:4860::8888
2001:4860:4860::8844

Leave everything else disabled.

Services -> Services

Under DNSMasq options, in "Additional DNSMasq Options", paste this block:

server=2001:4860:4860::8888 
server=2001:4860:4860::8844 
server=8.8.8.8 
server=8.8.4.4 

enable-ra 
dhcp-range=::1, ::400, constructor:br0, ra-stateless, ra-names, 12h 
dhcp-option=option6:dns-server,[::] 
dhcp-option=vendor:MSFT,2,1i 

This uses Google's public DNS for both IPV6 and IPV4. Local DNS will work (make sure you have that enabled.)

Administration -> Commands

In the "Commands" box, paste this script:

HOST6RD=6rd.charter.com
PREFIX=2602:100
ROUTER_LAN_IP=192.168.1.1
  

insmod /lib/modules/`uname -r`/ipv6.ko 2>/dev/null
insmod /lib/modules/`uname -r`/kernel/net/ipv6/sit.ko 2>/dev/null
  

WANIP="$(ifconfig vlan2 | sed -n '/inet /{s/.*addr://;s/ .*//;p}')"
IP6RD=$(nslookup $HOST6RD 2>/dev/null | grep "Address" | awk '{ print $3 }'|\
        grep -v $ROUTER_LAN_IP)
  

if [ -n "$WANIP" ]; then
  V6PREFIX=$(printf $PREFIX':%02x%02x:%02x%02x' $(echo $WANIP | tr . ' '))
  ip tunnel add tun6rd mode sit local $WANIP ttl 255
  ip tunnel 6rd dev tun6rd 6rd-prefix $PREFIX::/32
  ip addr add $V6PREFIX::1/32 dev tun6rd
  ip addr add $V6PREFIX::1/64 dev br0
  ip link set tun6rd mtu 1476
  ip link set tun6rd up
  ip route add ::/0 via ::$IP6RD dev tun6rd
  

  kill -HUP $(cat /var/run/radvd.pid) 2>/dev/null
fi

Edit the three variables at the top for your 6rd tunnel configuration and router LAN IP.

Now click "Save Startup".

Now paste this script in the "Commands" box:

ip6tables -F FORWARD
ip6tables -F OUTPUT

And click "Save Firewall".

Administration -> Management -> Reboot Router

Reboot the router and IPV6 should now work on all clients.

Go to http://test-ipv6.com/ to check, your score should be 10/10.

References

https://www.dd-wrt.com/wiki/index.php/IPv6#6rd

I started with the script here, which no longer works, and uses radvd.

http://kdwink.blogspot.com/2013/05/ipv6-with-charter-communications.html

Got charter specific info like the tunnel host and prefix from here.

http://www.litech.org/6rd/

Modified the script using this guide and got it to work, still using radvd which doesn't support DNS for Windows hosts.

https://www.dd-wrt.com/phpBB2/viewtopic.php?t=290486&postdays=0&postorder=asc&start=0

Used the discussion here to replace radvd with dnsmasq, which supports windows hosts correctly.

Read more...

Last modified: 2017-1-10 (火) at 8:07 am

Controlling Hue Bulbs With WeMo Light Switch

Previously I wrote about controlling Philips Hue bulbs with a Harmony remote here:

http://blog.cachemiss.com/articles/Controlling%20Hue%20Bulbs%20With%20Harmony%20on%20a%20Mac.pod

I finally got around to installing a WeMo light switch to have a switch type device to control these lights.

It has to be wired as described here:

http://community.wemothat.com/t5/WEMO-Application/Phillips-Hue-WeMo-LIght-Switch-and-IFTTT/m-p/6888/highlight/true#M1988

That is, you need to have power to the switch but not have the switch actually control the light fixture, the light fixture must have continuous power.

Once this is done, configure your new WeMo light switch in the WeMo smartphone app and give it a name.

I have a much nicer set of code than described here in a github repository here:

http://github.com/rkitover/wemohue

Now we can use a little daemon to detect switch activation, let's call it wemo_switch_daemon and put it in ~/bin.

#!/usr/bin/env python
  

import subprocess
from ouimeaux.environment import Environment
from ouimeaux.signals     import statechange, receiver
  

env = Environment();
env.start()
env.discover(5)

switch = env.get_switch('rafael_living_wemo')

@receiver(statechange, sender=switch)
def switch_toggle(*args, **kwargs):
    if kwargs['state'] == 1:
        subprocess.call(['~/bin/toggle_hue.py', 'on'],  shell=True)
    else:
        subprocess.call(['~/bin/toggle_hue.py', 'off'], shell=True)
  

env.wait()

You'll need to install the Python library with:

pip install --upgrade ouimeaux

Make sure the daemon runs with no error, then add a crontab entry to launch it on startup, with e.g. crontab -e:

@reboot             exec ~/bin/wemo_switch_daemon >/dev/null 2>&1 &

On Mac you can use "LaunchD Task Scheduler" and making a job to run at "load and login." On Windows you'd use Task Scheduler.

If you are not using the system python, either change the shebang or prepend the full path to your python.

Here is the toggle_hue script:

#!/usr/bin/env python
  

import socket, os.path, sys
from phue import Bridge
  

bridge = Bridge('rafael_living_hue')

arg = sys.argv[1].lower() if len(sys.argv) > 1 else 'toggle'

try:
    on_state = { 'on': True, 'off': False, 'toggle': not bridge.get_group(1, 'on') }[arg]
except KeyError:
    raise ValueError("command must be 'on', 'off' or 'toggle'")
  

bridge.set_group(1, { 'hue': 33862, 'sat': 50, 'bri': 254, 'on': on_state }, transitiontime=0)

You need phue for this script, install it with:

pip install --upgrade phue

UPDATE: I made some improvements to this post and made the toggle_hue script much faster, with some help from the phue author. Also a link to my new github repo with better code has been added.

Read more...

Last modified: 2017-1-8 (日) at 1:14 pm

Fixing the Microphone and Skype on a Linux Laptop

Many sound chipsets in laptops have a problem with linux where they will only work if only the left channel is enabled, and not the right channel. And this of course matters for Skype. I ran into this situation recently and it drove me utterly bonkers, because I could not find a permanent solution, but I finally did and will share it with you.

Installing Skype

I'm assuming you are using an Ubuntu or Ubuntu-like such as Mint, if not follow along and change the steps as appropriate for your own distro. The first step is to install the skype package, this is usually as simple as:

sudo apt-get install skype

If you do not have a skype package available in your repository, install the package off the website.

Skype is a 32 bit app, so the next step is to install the 32 bit pulseaudio library:

sudo apt-get install libpulse0:i386

Now you'll want to add an entry to your startup programs for your Desktop Environment to launch Skype on startup.

IMPORTANT: you must add a delay to your Skype launcher, or the icon will not appear in your notification area. Use a command such as the following:

sh -c 'sleep 3; skype'

In the skype login window, mark the checkbox in the lower right to 'login when Skype starts' so that you are logged in on startup.

Testing Skype

Once you are logged in to skype, go into preferences -> sound devices. The sound devices listed should be something like "Pulseaudio server" and not "virtual device". If it says "virtual device" you need to make sure you installed the 32 bit pulseaudio libs as described earlier.

Click "make a test sound", you should hear a sound. Check the "video devices" section to make sure your webcam works and you can see yourself.

Go back to the "sound devices" section and make a test call. When prompted, say something and wait to hear it repeated. If you heard your own voice, then you can stop here and there is nothing else you need to do, If you did not, then read on.

Open pavucontrol and go to the input sources section. Find your internal microphone, click the 'set as fallback device' button and the 'unlock channels' button. Slide the right channel to zero and the left channel to around 70%. You may hear an audible pop when you do this.

Now, without closing pavucontrol go back to Skype and make another test call. You should hear your own voice now.

Unfortunately this fix is not permanent, as soon as you close pavucontrol it will stop working again, I will describe how to make this fix permanent.

Reconfiguring Pulseaudio

We will reconfigure pulseaudio to pass everything straight to alsa and not do anything to the sound chip.

Edit the file /etc/pulse/default.pa, find the load-module alsa-sink etc. lines and change them to the following, removing the hash mark at the beginning to uncomment them, they should look like this:

load-module module-alsa-sink device=dmix
load-module module-alsa-source device=dsnoop

Find the lines that look like this:

### Automatically load driver modules depending on the hardware available
.ifexists module-udev-detect.so
load-module module-udev-detect
.else
### Use the static hardware detection module (for systems that lack udev
support)
load-module module-detect
.endif

And comment them out, by placing a hash mark at the beginning of each line to look like this:

#### Automatically load driver modules depending on the hardware available
#.ifexists module-udev-detect.so
#load-module module-udev-detect
#.else
#### Use the static hardware detection module (for systems that lack udev
#support)
#load-module module-detect
#.endif

Save the file. Make sure that when you upgrade your system the file is not overwritten or the changes will be lost.

Installing the Nightly ALSA PPA

Some laptops need a newer ALSA for the sound to work properly, run these commands:

sudo apt-add-repository ppa:ubuntu-audio-dev/alsa-daily
sudo apt-get update
sudo apt-get install oem-audio-hda-daily-dkms

And then reboot.

NOTE: if you have a custom kernel that is newer than that of your ubuntu base, you will need to tweak dkms module a bit as follows:

First edit /etc/apt/sources.list.d/ubuntu-audio-dev-alsa-daily-trusty.list and change the dist name from "trusty" to something newer like "utopic", then run:

sudo apt-get update
sudo apt-get install oem-audio-hda-daily-dkms

If the module builds and installs, you are good to go, if it says your kernel version does not match, then do the following:

Edit /usr/src/oem-audio-hda-daily-0.201503121632~ubuntu14.04.1/dkms.conf, the version string on the directory may be different but the directory is in /usr/src. Remove the following line:

BUILD_EXCLUSIVE_KERNEL="^3.13.*"

Then run:

sudo dkms install -m oem-audio-hda-daily/0.201503121632~ubuntu14.04.1

The version will probably be different, you can find it in the directory name under /usr/src .

Now reboot.

Reconfiguring the ALSA Mixer

Log out of your X session, switch to a virtual console with ctrl+alt+F1 and stop your display manager. Using a command such as:

invoke-rc.d mdm stop

The service may be gdm, kdm, lightdm, etc. Whichever your display manager is. When you press alt+f8 or alt+f7 there should not be an X session.

Make sure you are in the 'audio' group. As root, edit /etc/group and make sure the audio line looks something like this:

audio:x:29:pulse,your_user

Once this is done, exit and log back in on the virtual console.

Now, launch alsamixer. You may need to run it with sudo if you did not add yourself to the audio group. Set the master volume to a reasonable amount, such as 70% with the up and down keys. Fix the "Internal Mic" section, make sure it's unmuted, if it's muted press M to unmute it. Likewise, unmite the 'Mic Boost' section.

Go back to the "Internal Mic" section. The Q key raises the left channel and the Z key lowers it. The E key raises the right channel, and the C key lowers it. Use these keys to set the left channel to around 70% and the right channel to zero. Do the same thing for the "Mic Boost" section. Then press Escape to exit alsamixer.

Run this command to make your settings permanent:

sudo alsactl store

Now we're going to test the microphone. Run this command to record a sample sound:

arecord foo.wav

Say something and press Ctrl+C to exit the recording. Play back the recording with:

aplay foo.wav

If you can hear yourself, the alsa mixer is configured correctly.

Final Test

Reboot the laptop with:

sudo reboot

Once you are back in your Desktop Environment, make sure sound works and open skype from the icon in the notification area and try another test call. You should hear your own voice now.

Read more...

Last modified: 2017-1-8 (日) at 1:14 pm

Controlling Hue Bulbs With Harmony on a Mac

I wanted to be able to press a button on my harmony smart control to turn on my Hue bulbs.

I'll briefly describe how I did this.

Harmony Configuration

First, you need to configure your harmony to work in Plex mode with your Mac activity and install Remote Buddy on your mac.

The Remote Buddy configuration I used is described here, and is very time consuming.

https://forums.plex.tv/index.php/topic/33959-help-me-understand-mapping/

NOTE: you will need to choose the second type of apple remote when setting up the hardware remotes, it defaults to the first type which has fewer buttons and will not work. The black one, not the white one.

Hue Control Script

Next we are going to write a little Python program to turn the Hue lights on and off, here is mine:

#!/usr/bin/env python
  

import socket, os.path, sys
from phue import Bridge
  

bridge = Bridge('rafael_living_hue')

arg = sys.argv[1].lower() if len(sys.argv) > 1 else 'toggle'

try:
    on_state = { 'on': True, 'off': False, 'toggle': not bridge.get_group(1, 'on') }[arg]
except KeyError:
    raise ValueError("command must be 'on', 'off' or 'toggle'")
  

bridge.set_group(1, { 'hue': 33862, 'sat': 50, 'bri': 254, 'on': on_state }, transitiontime=0)

You will need to install phue, as described here:

https://github.com/studioimaginaire/phue

NOTE: I use the Homerew Python, I recommend you do the same.

The Bridge call takes a Hue bridge IP address, I recommend assigning a static DHCP lease on your router and rebooting the bridge to use it. This will give you a nice hostname like the one I'm using here.

This script will set the Concentration theme. If you want another theme, set it first using another app on your phone or whatever, then use get_light to read the hue, sat and bri values you need from one of the lights.

Someone mapped the values for the default themes here:

http://www.everyhue.com/vanilla/discussion/413/could-you-publish-the-offical-temperature-values-for-energize-concentrate-relax-and-reading

NOTE: you will need to test the script before we map it in Remote Buddy, and the first time you run it you will need to press the link button on your bridge first.

Put the script somewhere like:

~/bin/toggle_hue

Make sure to chmod +x it so it is executable.

Remote Buddy Mapping

- - - From the Remote Buddy menu, choose Behaviour Construction Kit and make a new action in the Action Factory pane. I called mine "Toggle HUE" in group "HUE".

Under implementation add Applescript, and for the code add the following:

do shell script "/Users/your-user/bin/toggle_hue"

replace the path with the actual path of the executable script. If the script is not executable, prepend the path with "python " to run it with python.

Next, in the Metadata pane choose "Action globally available".

Close the Behaviour Construction Kit and open Preferences, go to the Mapping pane.

Go to the very top entry, Global Mappings. Find the button according to the Plex mapping described in the first section, I use the Yellow button, which is Remote 159 Select. For the action, go to "Miscellaneous" and your new global action should be there, choose it.

Now you can test the button on your harmony and it should toggle your lights on and off.

UPDATE: I added vastly better Python code for the hue toggle script.

Read more...

Last modified: 2017-1-8 (日) at 1:14 pm