Mounting a folder from the host inside an LXC container

sharing folder with host on LXC

1. Create profile (makes life easier)

Take this script (a slightly modified version from here), save it and make it executable and save it.

#!/bin/bash 
set -eu 
_UID=$(id -u) 
GID=$(id -g) 
 
# give lxd permission to map your user/group id through 
grep root:$_UID:1 /etc/subuid -qs || sudo usermod --add-subuids ${_UID}-${_UID} --add-subgids ${GID}-${GID} root 
 
# set up a separate key to make sure we can log in automatically via ssh 
# with $HOME mounted 
KEY=$HOME/.ssh/id_lxd_$USER 
PUBKEY=$KEY.pub 
AUTHORIZED_KEYS=$HOME/.ssh/authorized_keys 
[ -f $PUBKEY ] || ssh-keygen -f $KEY -N '' -C "key for local lxds" 
grep "$(cat $PUBKEY)" $AUTHORIZED_KEYS -qs || cat $PUBKEY >> $AUTHORIZED_KEYS 
 
# create a profile to control this, name it after $USER 
lxc profile create $USER &> /dev/null || true 
 
# configure profile 
# this will rewrite the whole profile 
cat << EOF | lxc profile edit $USER 
name: $USER 
description: allow home dir mounting for $USER 
config: 
  # this part maps uid/gid on the host to the same on the container 
  raw.idmap: | 
    uid $_UID 1000 
    gid $GID 1000 
  # note: user.user-data is still available 
  user.vendor-data: | 
    #cloud-config 
    users: 
      - name: $USER 
        groups: sudo 
        shell: $SHELL 
        sudo: ['ALL=(ALL) NOPASSWD:ALL'] 
    # ensure users shell is installed 
    packages: 
      - $(dpkg -S $(readlink -m $SHELL) | cut -d: -f1) 
EOF

So – this will take care of mapping your UIDs GIDs so you can edit the files in your mount point to your newly added user

2. Create your container

lxc launch ubuntu:18.04 <YOUR-CONTAINER> -p $USER -p default

3. Add you shared folder as a device and mount it

lxc config device add YOUR-CONTAINER YOUR-DEVICE-NAME disk source=/home/<user>/<projects-folder> path=/home/<user>/<projects-folder>

Congratulations – you now have a shiny Ubuntu 18.04 container to do your dev work in.

You  might want to jump in and install some important stuff

lxc exec YOUR-CONTAINER /bin/bash
$ apt install build-essential ....

Writing to the Android Log

So I just figured out how to get my log messages from a system Golang program into the android log without the need for logwrapper.

It is a side effect of importing the “app” mobile package. so…

import (
	_ "golang.org/x/mobile/app"
)

The downside is that *everything* written via stdout will go to the system log – even flag.Usage()

If you want to go a little more serious, here is a nice chunk of code

package main

/*
#cgo LDFLAGS: -llog
#include 
#include 
*/
import "C"
import "unsafe"

func writeAndroidLogInfo(tag, message string) {
	ctag := C.CString(tag)
	cstr := C.CString(message)
	C.__android_log_write(C.ANDROID_LOG_INFO, ctag, cstr)
	C.free(unsafe.Pointer(ctag))
	C.free(unsafe.Pointer(cstr))
}

You can use it like so

writeAndroidLogInfo("MyIdentifier", "My Message")

and the output in logcat will be

I/MyIdentifier( 4444): My Message

How To: Cross compile Golang for Android

To build for the android platform (GOOS=android) you need to do the following:

I placed all the downloads into ~/dev

  1. Get a copy of Golang >= version 1.4 from https://golang.org/dl/
    • Unpack it into ~/dev
  2. Grab the latest copy of the Android NDK from https://developer.android.com/tools/sdk/ndk/index.html
    • Make it executable and run it (it unpacks into the current folder, so ~/dev)
  3. Time to get a copy of our platform NDK.
    export NDK_ROOT=~/dev/ndk-toolchain
    ./android-ndk-r10c/build/tools/make-standalone-toolchain.sh --platform=android-16 --install-dir=$NDK_ROOT
        
  4. Now we need to build the Golang toolchain, cd into ~/dev/go/src
    export NDK_CC=~/dev/ndk-toolchain/bin/arm-linux-androideabi-gcc
    CC_FOR_TARGET=$NDK_CC GOOS=android GOARCH=arm GOARM=7 ./make.bash
        
  5. Now we can cross compile
    • You can put the following into a build.sh file
    • export NDK_TOOLCHAIN=~/dev/ndk-toolchain
      export CC=$NDK_TOOLCHAIN/bin/arm-linux-androideabi-gcc
      export GOROOT=~/dev/go
      export GOPATH=`pwd`
      export GOOS=android
      export GOARCH=arm
      export GOARM=7
      export CGO_ENABLED=1
      
      GO="$GOROOT/bin/go"
      
      $GO build -x main.go
      
    • Once you have made it executable (chmod +x build.sh) you can ./build.sh to build your app.

Cross Compile Golang on Ubuntu 14.04

So today I needed to cross compile a basic Golang app from linux/amd64 to linux/arm (for android) on my Ubuntu 14.04 box.

It is actually kinda easy

sudo apt-get install golang-go-linux-arm

because I am running the latest 1.3 golang i needed to run an extra step:

cd /usr/local/go/src/
sudo GOARCH=arm ./make.bash

Once you have that setup, it is as simple as:

you@host:~/golang/src/yourrepohost/yourrepos/repo$ GOARCH=arm go build

Golang – struct, make and the case of the missing variable

I made a rookie mistake last night. I forgot an asterisk in my code and it caused me a an hour of confusion!

TL;DR – methods on structs in golang need their stuct passed as a pointer if you want to modify it!

This works

func (f *Foo)SomeFunc() {}

This does not!

func (f Foo)SomeFunc() {}

rails generate Could not find <gem> in any of the sources

So with my latest project I am using Rails 4.1 – this is all well and good, but here is a gotcha. there is a thing called spring that is supposed to make things faster – except when it gets in the way!

tl;dr – killall spring

So – here are the symptoms

$ rails g
Could not find bcrypt-3.1.7 in any of the sources
Run `bundle install` to install missing gems.

Now bcrypt is the only thing having the issue (other gems worked) i think this is because it has a compiled binary component to it.

The fix? Kill all the springs!

$ ps aux | grep spring
jason     8361  0.0  0.2 426464 21380 ?        Sl   Apr22   0:01 spring server | wholesale | started 22 hours ago                                                                
jason    11730  1.0  0.2 225632 22276 ?        Ssl  11:46   0:00 spring app    | wholesale | started 55 secs ago | development mode

$ kill 8361

… and now rails generate plays nicely again!

Rails, CanCan and Best In Place editing

So here is a little gotcha and solution when using CanCan and Best In Place. With the default setup, if CanCan auth fails on a best in place edit you get a redirect to your default “Auth Failed” path and that page then tries to render as javascript.

that does not work all that well!

So here is my simple solution, if we get an auth denied on a XHR request, just return a generic error!

class ApplicationController < ActionController::Base
	protect_from_forgery
	check_authorization

	rescue_from CanCan::AccessDenied do |exception|
		if request.xhr?
			render :json => ['You are not authorised to do that.'], :status => :unprocessable_entity
		else
			redirect_to '/', :alert => exception.message
		end
	end
...
end

has_many :through and the case of the missing include

tl;dr – you need to specify the “inverse_of” option on your has_many/belongs_to relationship to get your children fully populated

So I came across an interesting situation the other day, where my includes() statement was preloading data, but then when accessing it I would see another SQL query.

require 'active_record'

class Parent < ActiveRecord::Base
attr_accessible :name
has_many :parent_children, inverse_of: :children
has_many :children, through: :parent_children

default_scope includes(:parent_children)
end

class ParentChildren < ActiveRecord::Base
attr_accessible :parent_id, :child_id
belongs_to :parents, inverse_of: :parent_children
belongs_to :children

default_scope includes(:children)
end

class Child < ActiveRecord::Base
attr_accessible :name
has_many :parent_children
has_many :parents, through: :parent_children
end

Parent.all.each {|p| p.children.each {|c| puts c.name}}

Without the :inverse_of here, each call to write the childs name will result in a new SQL query to get the data, even though this data has already been prefetched (eager loaded).

Hacking a Cisco/Linksys NSS6000

So I was given a Cisco/Linksys NSS6000 to upgrade and root.  Luckily I have was also provisioned with the instructions to root this machine.

Thanks to some hacker types that had already been and done this the process was relatively straight forward.

  1. Create User
  2. Insert USB Key
  3. Backup Configuration onto USB Key
  4. Unmount USB Key
  5. Dive into the tar ball (which is simply /etc) and:
    1. Change the root password in etc/password – I just copied my new users password!
    2. Added the following line to etc/cron.d/root
      */5 * * * * /usr/sbin/dropbear_start.sh
  6. Tar the extracted files
  7. Put the tarball back on the USB drive
  8. Mount it in the NAS and Restore from backup
  9. Profit, Right!?

Well,  nearly. I had a couple of issues:

Incorrect tarball Permissions

So, my first derp was when I tar’d the etc folder back up and well… instead of root owning everything, you get the picture.

What happens is that you get an error like this:

Warning: touch(): Unable to create file /etc/nas/ran_wizard because Permission denied in /www/html/index.php on line 48

And you end up getting into a loop with dialog boxes and never ending redirects to the same page.

The down side of this is that you cannot get to any other pages in the administration to even consider doing a factory reset. Luckily you *can* post to it still

curl --data "p=admin&s=maintenance&restore_all=Restore+ALL+Settings+to+Factory+Defaults" http://admin:admin@192.168.0.2/index.php

This command will reset the device to factory defaults – you should change the IP address and user/pass to what you need it to be. It obviously uses cURL so you will need that too 🙂

We also tried to overwrite the start of the one disk we had (using dd if=/dev/zero…) in the machine to see if that would work – but alas it did not. We were able to go through the setup wizard again, but ended back at the loop we had before.

SSH Connection Closed

The second problem I had was ssh’ing to the box. We discovered that if we used an older version of openSSH we could connect to it, but newer versions of openSSH would just not connect.

Pro Tip: Putty connects fine 🙂

To be able to connect to older dropbear’s with newer openSSH clients – try this in your ssh_config file

jason@workstation:~$ cat ~/.ssh/config 
host 192.168.0.2
	Ciphers aes128-cbc,3des-cbc,blowfish-cbc,cast128-cbc,arcfour,aes192-cbc,aes256-cbc

I hope this information saves someone a few hours of frustrations.

sprintf, floats and rounding

So I had some fun figuring out why my Spec tests were failing today.

tl;dr – do not use floats for currency (BigDecimal will sort you out in Ruby)

I was starting to question my highschool math today as I was seeing things like this:

php > echo sprintf("%0.2f\n", 1.045);
1.04

and

irb(main):003:0> '%0.2f' % 1.045
=> "1.04"

now for those playing at home, this needs to be 1.05 – and since both Ruby and PHP where doing the same, it pointed to an underlying library problem.

A Quick Google later and I found what I needed. 1.045 would be stored in floating point form as 1.04999999999999 – therefore – rounding would be busted.

In Ruby I am using BigDecimal to solve my problem and therefore make my spec tests pass!