├── debian ├── compat ├── source │ └── format ├── oswitch.docs ├── pkg.rb ├── install ├── watch ├── changelog ├── rules ├── control └── copyright ├── .gitignore ├── Gemfile ├── share └── oswitch │ └── context │ ├── wheel │ └── _switch ├── lib ├── oswitch │ ├── pkg.rb │ ├── exceptions.rb │ ├── image.rb │ ├── os │ │ ├── linux.rb │ │ └── darwin.rb │ └── os.rb └── oswitch.rb ├── oswitch.gemspec ├── bin └── oswitch ├── Rakefile ├── metadata.yml ├── contrib └── docker_setup_ubuntu.sh └── README.mkd /debian/compat: -------------------------------------------------------------------------------- 1 | 9 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | debian/oswitch 2 | -------------------------------------------------------------------------------- /debian/source/format: -------------------------------------------------------------------------------- 1 | 3.0 (quilt) 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | gemspec 4 | -------------------------------------------------------------------------------- /debian/oswitch.docs: -------------------------------------------------------------------------------- 1 | # FIXME: READMEs found 2 | # README.mkd 3 | -------------------------------------------------------------------------------- /share/oswitch/context/wheel: -------------------------------------------------------------------------------- 1 | %wheel ALL = (ALL) NOPASSWD: ALL -------------------------------------------------------------------------------- /debian/pkg.rb: -------------------------------------------------------------------------------- 1 | class OSwitch 2 | PREFIX = File.expand_path '/usr' 3 | end 4 | -------------------------------------------------------------------------------- /debian/install: -------------------------------------------------------------------------------- 1 | share usr 2 | debian/pkg.rb usr/lib/ruby/vendor_ruby/oswitch 3 | -------------------------------------------------------------------------------- /lib/oswitch/pkg.rb: -------------------------------------------------------------------------------- 1 | class OSwitch 2 | PREFIX = File.expand_path('../..', File.dirname(__FILE__)) 3 | end 4 | -------------------------------------------------------------------------------- /debian/watch: -------------------------------------------------------------------------------- 1 | version=3 2 | http://pkg-ruby-extras.alioth.debian.org/cgi-bin/gemwatch/oswitch .*/oswitch-(.*).tar.gz 3 | -------------------------------------------------------------------------------- /lib/oswitch/exceptions.rb: -------------------------------------------------------------------------------- 1 | class OSwitch 2 | class ENODKR < StandardError 3 | def to_s 4 | "***** Docker not installed / correctly setup / running. 5 | Are you able to run 'docker info'?" 6 | end 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | oswitch (0.2.6) trusty; urgency=medium 2 | 3 | * Upstream 0.2.6 4 | 5 | -- Anurag Priyam Tue, 15 Sep 2015 15:38:43 +0100 6 | 7 | oswitch (0.2.5-1) trusty; urgency=medium 8 | 9 | * Upstream 0.2.5 10 | 11 | -- Anurag Priyam Fri, 27 Mar 2015 06:10:20 +0000 12 | 13 | oswitch (0.2.3-1) UNRELEASED; urgency=medium 14 | 15 | * Setup things for deb packaging. 16 | 17 | -- Anurag Priyam Tue, 17 Mar 2015 07:41:55 +0000 18 | -------------------------------------------------------------------------------- /debian/rules: -------------------------------------------------------------------------------- 1 | #!/usr/bin/make -f 2 | 3 | DH_RUBY_VERSION := $(shell dh_ruby --version | cut -b 17-) 4 | 5 | %: 6 | dh $@ --buildsystem=ruby --with ruby 7 | 8 | override_dh_auto_install: 9 | dh_auto_install 10 | # Rewrite shebang line to `#!/usr/bin/ruby` instead of `#!/usr/bin/env ruby`. 11 | # This ensures the package always will always use system Ruby regardless of 12 | # the Ruby loaded in the env by rvm, rbenv, chruby, etc. This is the default 13 | # behaviour in Jessie and Vivid, so the fix is meant only for Trusty. 14 | if dpkg --compare-versions $(DH_RUBY_VERSION) lt 0.7.0; then \ 15 | sed -i '1s,.*,#!/usr/bin/ruby,' debian/oswitch/usr/bin/oswitch; \ 16 | fi 17 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Source: oswitch 2 | Section: ruby 3 | Priority: optional 4 | Maintainer: Debian Ruby Extras Maintainers 5 | Uploaders: Anurag Priyam 6 | Build-Depends: debhelper (>= 7.0.50~), gem2deb (>= 0.6.1~) 7 | Standards-Version: 3.9.5 8 | Homepage: https://github.com/yeban/oswitch 9 | XS-Ruby-Versions: all 10 | 11 | Package: oswitch 12 | Architecture: all 13 | XB-Ruby-Versions: ${ruby:Versions} 14 | Depends: ${shlibs:Depends}, ${misc:Depends}, ruby | ruby-interpreter, ruby-colorize (>= 0.7.5) 15 | Description: Use docker image as the host operating system's user and access 16 | host operating system's filesystem. Use any docker image as the host operating 17 | system's user (same user name, same uid, same gid, and even the same shell!) 18 | and access to host operating system's filesystem. 19 | -------------------------------------------------------------------------------- /lib/oswitch/image.rb: -------------------------------------------------------------------------------- 1 | class OSwitch 2 | # Captures a docker image's metadata. 3 | Image = Struct.new :repository, :tag, :id, :created, :size 4 | 5 | class Image 6 | 7 | # Model Image's eigenclass as a collection of Image objects. 8 | class << self 9 | 10 | include Enumerable 11 | 12 | def all 13 | `docker images`.split("\n").drop(1). 14 | map{|l| Image.new(*l.split(/\s{2,}/))} 15 | end 16 | 17 | def each(&block) 18 | all.each(&block) 19 | end 20 | 21 | def get(imgname) 22 | repository, tag = imgname.split(':') 23 | return if not repository or repository.empty? 24 | tag = 'latest' if not tag or tag.empty? 25 | find {|img| img.repository == repository and img.tag == tag} 26 | end 27 | 28 | def exists?(imgname) 29 | !!get(imgname) 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /oswitch.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | # meta 3 | s.name = 'oswitch' 4 | s.version = '0.2.7' 5 | s.authors = ['Anurag Priyam', 'Bruno Vieira', 'Yannick Wurm'] 6 | s.email = ['anurag08priyam@gmail.com'] 7 | s.homepage = 'https://github.com/yeban/oswitch' 8 | s.license = 'MIT' 9 | 10 | s.summary = "Use docker image as the host operating system's user and \ 11 | access host operating system's filesystem." 12 | s.description = < 0.7.5') 20 | s.required_ruby_version = '>= 2.0' 21 | 22 | # gem 23 | s.files = Dir['lib/**/*'] + Dir['share/**/*'] 24 | s.files = s.files + ['Gemfile', 'oswitch.gemspec'] 25 | s.files = s.files + ['README.mkd'] 26 | s.require_paths = ['lib'] 27 | s.executables = ['oswitch'] 28 | 29 | end 30 | -------------------------------------------------------------------------------- /lib/oswitch/os/linux.rb: -------------------------------------------------------------------------------- 1 | class OSwitch 2 | module OS 3 | # Linux specific code. 4 | module Linux 5 | BLACKLIST = 6 | %r{ 7 | ^/$| 8 | ^/(bin|boot|dev|etc|home|lib|lib64|lost\+found|opt|proc| 9 | run(?!/media)|sbin|srv|sys|tmp|usr|var| 10 | initrd.img|initrd.img.old|vmlinuz|vmlinuz.old) 11 | }x 12 | 13 | def uid 14 | Process.uid 15 | end 16 | 17 | def gid 18 | Process.gid 19 | end 20 | 21 | def mountpoints 22 | volumes = IO.readlines('/proc/mounts') 23 | .map { |line| line.split(/\s+/)[1] } 24 | .map { |path| unescape(path) } 25 | volumes = volumes | Dir['/*'] 26 | 27 | volumes.reject! do |path| 28 | (path =~ BLACKLIST) || !File.readable?(path) || !File.directory?(path) 29 | end 30 | 31 | volumes << home 32 | end 33 | 34 | private 35 | 36 | def unescape(mount) 37 | mount 38 | .gsub(/\\040/, " ") 39 | .gsub(/\\012/, "\n") 40 | .gsub(/\\134/, "\\") 41 | .gsub(/\\011/, "\t") 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/oswitch/os/darwin.rb: -------------------------------------------------------------------------------- 1 | class OSwitch 2 | module OS 3 | # OS X specific code. 4 | module Darwin 5 | BLACKLIST = 6 | %r{ 7 | ^/$| 8 | ^/(bin|cores|dev|etc|home|Incompatible\ Software| 9 | installer\.failurerequests|lost\+found|net| 10 | Network|opt|private|sbin|System|Users|tmp| 11 | usr|var|Volumes$) 12 | }x 13 | 14 | def mountpoints 15 | volumes = Dir['/Volumes/*'].map {|v| File.symlink?(v) ? File.readlink(v) : v} 16 | volumes = volumes | Dir['/*'] 17 | volumes.reject! { |mount| mount =~ BLACKLIST } 18 | volumes << home 19 | end 20 | 21 | if OS.command?('docker-machine') 22 | def uid 23 | OS.outputof('docker-machine ssh default id -u') 24 | end 25 | 26 | def gid 27 | OS.outputof('docker-machine ssh default id -g') 28 | end 29 | else 30 | def uid 31 | puts < /dev/null 2>&1") 13 | end 14 | 15 | def self.outputof(command) 16 | output = `#{command} 2> /dev/null`.chomp 17 | raise unless $CHILD_STATUS.success? 18 | output 19 | end 20 | 21 | def username 22 | ENV['USER'] 23 | end 24 | 25 | def home 26 | ENV['HOME'] 27 | end 28 | 29 | def shell 30 | File.basename ENV['SHELL'] 31 | end 32 | 33 | def cwd 34 | Dir.pwd 35 | end 36 | 37 | # Detect Linux or Darwin and load OS specific code. Following 38 | # methods are added: 39 | # 40 | # uid, gid, mountpoints 41 | # 42 | # NOTE: 43 | # This won't work on JRuby as it sets RUBY_PLATFORM to 'java'. 44 | case RUBY_PLATFORM 45 | when /linux/ 46 | require_relative 'os/linux' 47 | include Linux 48 | when /darwin/ 49 | require_relative 'os/darwin' 50 | include Darwin 51 | end 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /debian/copyright: -------------------------------------------------------------------------------- 1 | Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: oswitch 3 | Source: FIXME 4 | 5 | Files: * 6 | Copyright: 7 | 8 | License: GPL-2+ (FIXME) 9 | 10 | Files: debian/* 11 | Copyright: 2015 <> 12 | License: GPL-2+ (FIXME) 13 | Comment: the Debian packaging is licensed under the same terms as the original package. 14 | 15 | License: GPL-2+ (FIXME) 16 | This program is free software; you can redistribute it 17 | and/or modify it under the terms of the GNU General Public 18 | License as published by the Free Software Foundation; either 19 | version 2 of the License, or (at your option) any later 20 | version. 21 | . 22 | This program is distributed in the hope that it will be 23 | useful, but WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 25 | PURPOSE. See the GNU General Public License for more 26 | details. 27 | . 28 | You should have received a copy of the GNU General Public 29 | License along with this package; if not, write to the Free 30 | Software Foundation, Inc., 51 Franklin St, Fifth Floor, 31 | Boston, MA 02110-1301 USA 32 | . 33 | On Debian systems, the full text of the GNU General Public 34 | License version 2 can be found in the file 35 | `/usr/share/common-licenses/GPL-2'. 36 | -------------------------------------------------------------------------------- /bin/oswitch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'oswitch' 4 | require 'optparse' 5 | 6 | options = {} 7 | collect = lambda do |key| 8 | lambda do |value| 9 | options[key] = value 10 | end 11 | end 12 | 13 | optspec = OptionParser.new do |opts| 14 | opts.banner = "Usage: oswitch [options] [cmd]" 15 | 16 | opts.on '-l', '--list', 17 | 'List packages.', 18 | &collect[:list] 19 | 20 | opts.on '-h', '--help', 21 | 'Print help.', 22 | &collect[:help] 23 | end 24 | 25 | begin 26 | optspec.order! 27 | rescue OptionParser::InvalidOption, 28 | OptionParser::MissingArgument => e 29 | puts e 30 | exit 31 | end 32 | 33 | if options[:help] || (options.empty? && ARGV.empty?) 34 | puts optspec 35 | exit 36 | end 37 | 38 | if options[:list] 39 | puts OSwitch.packages 40 | if OSwitch.packages.empty? 41 | puts "Nothing installed. Use anything from http://registry.hub.docker.com\n" + 42 | "Some examples: oswitch ubuntu\n" + 43 | " oswitch yeban/biolinux:8\n" + 44 | " oswitch centos\n" + 45 | " oswitch nucleotides/sga" 46 | end 47 | exit 48 | end 49 | 50 | pattern = ARGV[0].strip 51 | command = ARGV[1..-1].join(' ') 52 | matches = OSwitch.packages.grep(/#{pattern}/) 53 | 54 | if matches.length > 1 55 | puts "Which one of the following did you mean?" 56 | puts matches.join(', ') 57 | else 58 | OSwitch.to(matches.first || pattern, command) 59 | end 60 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | GEMSPEC = eval File.read 'oswitch.gemspec' 2 | PLATFORMS = %w|linux-x86 linux-x86_64 osx| 3 | TRAVELING_RUBY_VERSION = '20150715-2.2.2' 4 | 5 | PLATFORMS.each do |platform| 6 | file "traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{platform}.tar.gz" do 7 | sh "wget -N " + 8 | "http://d6r77u77i8pq3.cloudfront.net" + 9 | "/releases/traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{platform}.tar.gz" 10 | end 11 | end 12 | 13 | desc "Create standalone SequenceServer packages" 14 | task :package do 15 | cd '..' do 16 | task('package:build' => ['package:linux-x86', 'package:linux-x86_64', 'package:osx']).invoke 17 | end 18 | end 19 | 20 | namespace :package do 21 | PLATFORMS.each do |platform| 22 | task platform => "traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{platform}.tar.gz" do 23 | package_dir = "#{GEMSPEC.name}-#{GEMSPEC.version}-#{platform}" 24 | 25 | rm_rf package_dir 26 | mkdir package_dir 27 | 28 | cp_r "#{Rake.original_dir}/.", package_dir 29 | 30 | cd package_dir do 31 | mkdir 'vendor' 32 | sh "tar xzf ../traveling-ruby-#{TRAVELING_RUBY_VERSION}-#{platform}.tar.gz -C vendor" 33 | sh "chruby-exec 2.2.2 -- bundle install --deployment" 34 | File.write(GEMSPEC.name, <" 20 | - !ruby/object:Gem::Version 21 | version: 0.7.5 22 | type: :runtime 23 | prerelease: false 24 | version_requirements: !ruby/object:Gem::Requirement 25 | requirements: 26 | - - "~>" 27 | - !ruby/object:Gem::Version 28 | version: 0.7.5 29 | description: | 30 | Use any docker image as the host operating system's user (same user name, same 31 | uid, same gid, and even the same shell!) and access to host operating system's 32 | filesystem. 33 | email: 34 | - anurag08priyam@gmail.com 35 | executables: 36 | - oswitch 37 | extensions: [] 38 | extra_rdoc_files: [] 39 | files: 40 | - Gemfile 41 | - README.mkd 42 | - bin/oswitch 43 | - context/_switch 44 | - context/wheel 45 | - lib/oswitch.rb 46 | - oswitch.gemspec 47 | homepage: https://github.com/yeban/oswitch 48 | licenses: 49 | - MIT 50 | metadata: {} 51 | post_install_message: 52 | rdoc_options: [] 53 | require_paths: 54 | - lib 55 | required_ruby_version: !ruby/object:Gem::Requirement 56 | requirements: 57 | - - ">=" 58 | - !ruby/object:Gem::Version 59 | version: '2.0' 60 | required_rubygems_version: !ruby/object:Gem::Requirement 61 | requirements: 62 | - - ">=" 63 | - !ruby/object:Gem::Version 64 | version: '0' 65 | requirements: [] 66 | rubyforge_project: 67 | rubygems_version: 2.4.2 68 | signing_key: 69 | specification_version: 4 70 | summary: Use docker image as the host operating system's user and access host operating 71 | system's filesystem. 72 | test_files: [] 73 | -------------------------------------------------------------------------------- /share/oswitch/context/_switch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | if [ $# -lt 5 ]; then 4 | echo "Usage: ... " 5 | exit 6 | fi 7 | 8 | uid=$1 9 | gid=$2 10 | user=$3; 11 | home=$4; 12 | shell=$5; 13 | shift 5 14 | 15 | echo 16 | echo "Switch-ifying ..." 17 | 18 | ## Debian ## 19 | if command -v apt-get >/dev/null; then 20 | 21 | export DEBIAN_FRONTEND=noninteractive 22 | 23 | echo 24 | echo 'Assuming Ubuntu.' 25 | echo 'Attempting to activate universe and multiverse repositories.' 26 | apt-get install -y software-properties-common 27 | apt-add-repository universe 28 | apt-add-repository multiverse 29 | 30 | if [ $? -ne 0 ]; then 31 | echo 32 | echo 'Oops ... it is Debian. Continuing.' 33 | fi 34 | 35 | echo 36 | echo 'Updating list of packages.' 37 | apt-get update 38 | 39 | echo 40 | echo 'Installing utilities.' 41 | apt-get install -y sudo less 42 | 43 | echo 44 | echo 'Setting up locale.' 45 | apt-get install -y locales 46 | echo 'en_US.UTF-8 UTF-8' >> /etc/locale.gen 47 | locale-gen en_US.UTF-8 48 | 49 | echo 50 | echo "Installing $shell as requested." 51 | apt-get install -y $shell 52 | 53 | ## Red Hat ## 54 | elif command -v yum >/dev/null; then 55 | 56 | echo 'Red Hat based image detected.' 57 | 58 | echo 59 | echo 'Installing utilities.' 60 | yum install -y sudo passwd 61 | 62 | echo 63 | echo "Installing $shell as requested." 64 | yum install -y $shell 65 | 66 | ## Arch ## 67 | # elif command -v pacman >/dev/null; then 68 | # 69 | # echo 'Arch based image detected.' 70 | # 71 | # echo 72 | # echo 'Updating list of packages.' 73 | # pacman --noconfirm -Sy 74 | # 75 | # echo 76 | # echo "Installing $shell as requested." 77 | # pacman --noconfirm -S $shell 78 | else 79 | echo 80 | echo "Can't infer base image." 81 | fi 82 | 83 | # Will create group 'wheel' to give passwordless sudo access to users. Will 84 | # create the user, without password, keeping the same uid as the host. Will 85 | # set newly created user as the current user in container. 86 | 87 | echo 88 | echo "Creating user $user with uid $uid ..." 89 | groupadd -f wheel 90 | groupadd -f $user -g $gid 91 | useradd -M -N -g $gid -G wheel -d $home -u $uid $user 92 | passwd -d $user &> /dev/null 93 | 94 | echo 'Done.' 95 | echo "Your home directory is $homedir." 96 | echo 'You can use sudo.' 97 | -------------------------------------------------------------------------------- /contrib/docker_setup_ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | set -u 5 | 6 | # This script was contributed to oswitch by Tim Booth, as part of the Bio-Linux project. 7 | # It was designed for Bio-Linux but should help you to install the latest Docker on any 8 | # Ubuntu system. 9 | 10 | # Are we really on Ubuntu? 11 | if ! [ "`lsb_release -si`" = Ubuntu ] ; then 12 | echo "According to lsb_release this is not an Ubuntu system. Installation will not proceed." 13 | exit 1 14 | fi 15 | 16 | if ! [ `id -u` = 0 ] ; then 17 | echo "Please re-run this script with sudo to install Docker" 18 | exit 1 19 | fi 20 | 21 | echo "Docker will be installed from https://get.docker.com" 22 | 23 | # Utility functions 24 | anykey() { read -p "Press any key to continue..." -n1 ; echo ; echo ; } 25 | 26 | yesnocancel() { 27 | read -p "$1 (Yes/No/Cancel): " -n1 a 28 | if [[ "$a" == y || "$a" = Y ]] ; then 29 | echo ; return 0 30 | elif [[ "$a" == n || "$a" = N ]] ; then 31 | echo ; return 1 32 | elif 33 | [[ "$a" == c || "$a" = C ]] ; then 34 | echo ' 'Aborting ; exit 1 35 | fi 36 | yesnocancel "$@" 37 | } 38 | 39 | ALLUSERS=0 40 | if yesnocancel "Would you like all users to be given permission to use Docker?" ; then 41 | ALLUSERS=1 42 | fi 43 | 44 | # We need this before adding the docker repo 45 | # Note docker does need apparmor even though it does not declare the dependency. 46 | # I'm installing all the depends/recommends from the docker.io package here 47 | echo "Installing pre-requisite packages" 48 | apt-get update 49 | apt-get install apt-transport-https software-properties-common \ 50 | ca-certificates apparmor cgroup-lite git git-man \ 51 | liberror-perl aufs-tools bind9-host 52 | add-apt-repository universe 53 | 54 | # Now we can add the repo 55 | cat >/etc/apt/sources.list.d/docker.list <<. 56 | deb https://get.docker.com/ubuntu docker main 57 | . 58 | apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys A88D21E9 59 | 60 | echo "Installing Docker itself" 61 | apt-get update && apt-get install lxc-docker 62 | 63 | if [ "$ALLUSERS" = 1 ] ; then 64 | echo "Allowing all new users to be able to run Docker by default..." 65 | if ! grep -q '^EXTRA_GROUPS=".* docker.*"' /etc/adduser.conf ; then 66 | echo " Fixing EXTRA_GROUPS" 67 | sed -i 's/^[# ]*\(EXTRA_GROUPS="[^"]*\)"/\1 docker"/' /etc/adduser.conf 68 | fi 69 | 70 | if ! grep -q '^ADD_EXTRA_GROUPS=1' /etc/adduser.conf ; then 71 | echo " Fixing ADD_EXTRA_GROUPS" 72 | sed -i 's/^[ #]*\(ADD_EXTRA_GROUPS\)=.*/\1=1/' /etc/adduser.conf 73 | fi 74 | 75 | # Add all regular users. This is a very dirty way to get a list of login users 76 | # but it should be adequate for our purposes. 77 | for user in `stat -c "%U" /home/* | sort -u` ; do 78 | [ "$user" = root ] && continue 79 | echo "Adding user $user to the docker group" 80 | usermod -aG docker "$user" 81 | done 82 | 83 | echo "You will need to log out and back in again to use oswitch and Docker" 84 | 85 | else 86 | echo "Before you can use Docker, you must run:" 87 | echo " sudo usermod -aG docker your_user_name" 88 | echo "And you will need to log out then back in again for this to take effect," 89 | echo "or else you will just get a cryptic error message about 'docker.sock' and a" 90 | echo "'TLS-enabled daemon'." 91 | fi 92 | 93 | echo 94 | echo "All done. Docker package updates will now be managed by the regular update manager." 95 | # done 96 | -------------------------------------------------------------------------------- /lib/oswitch.rb: -------------------------------------------------------------------------------- 1 | require 'timeout' 2 | require 'colorize' 3 | require 'fileutils' 4 | require 'shellwords' 5 | 6 | require 'oswitch/exceptions' 7 | require 'oswitch/image' 8 | require 'oswitch/pkg' 9 | require 'oswitch/os' 10 | 11 | # OSwitch leverages docker to provide access to complex Bioinformatics software 12 | # (even Biolinux!) in just one command. 13 | # 14 | # Images are built on the user's system on demand and executed in a container. 15 | # Containers are removed after execution. 16 | # 17 | # Volumes from host OS are mounted in the container just the same, including 18 | # home directory. USER, HOME, SHELL, and PWD are preserved. 19 | class OSwitch 20 | include OS, Timeout 21 | 22 | DOTDIR = File.expand_path('~/.oswitch') 23 | 24 | class << self 25 | # Invoke as `OSwitch.to` instead of `OSwitch.new`. 26 | alias_method :to, :new 27 | private :new 28 | 29 | def packages 30 | Dir["#{DOTDIR}/*"].map do |rep| 31 | pkgs = Dir["#{rep}/*"].select {|pkg| File.directory?(pkg)} 32 | pkgs = [rep] if pkgs.empty? 33 | pkgs 34 | end. 35 | flatten. 36 | map {|pkg| 37 | pkg.gsub("#{DOTDIR}/", '') 38 | } 39 | end 40 | end 41 | 42 | def initialize(package, command = []) 43 | @package = package 44 | @command = command 45 | @imgname = "oswitch_#{@package}" 46 | @cntname = "#{@package.gsub(%r{/|:}, '_')}-#{Process.pid}" 47 | exec 48 | end 49 | 50 | attr_reader :package, :command, :imgname, :cntname 51 | 52 | def exec 53 | ping and build and switch 54 | rescue ENODKR => e 55 | puts e 56 | exit 57 | rescue => e 58 | puts < /dev/null 2>&1' 93 | end 94 | pong or raise ENODKR 95 | end 96 | 97 | ## Code to generate context dir that will be built into a docker image. ## 98 | 99 | # Create context dir. 100 | def create_context_dir 101 | FileUtils.mkdir_p context_dir 102 | FileUtils.cp_r(template_files, context_dir) 103 | write_dockerfile 104 | end 105 | 106 | # Remove context dir. 107 | def remove_context_dir 108 | FileUtils.rm_r(context_dir) 109 | end 110 | 111 | # Write Dockerfile. 112 | def write_dockerfile 113 | dockerfile = File.join(context_dir, 'Dockerfile') 114 | File.write(dockerfile, dockerfile_data) 115 | end 116 | 117 | # Generate String that get written to Dockerfile. 118 | def dockerfile_data 119 | data = ["FROM #{package}"] 120 | data << 'COPY _switch /' 121 | data << 'COPY wheel /etc/sudoers.d/' 122 | data << "RUN /_switch #{userargs} 2>&1" 123 | data << 'ENV LC_ALL en_US.UTF-8' 124 | data << "USER #{username}" 125 | data << "ENTRYPOINT [\"#{shell}\", \"-c\"]" 126 | data.join("\n") 127 | end 128 | 129 | # Location of context dir. 130 | def context_dir 131 | File.join(DOTDIR, package) 132 | end 133 | 134 | # Location of template dir. 135 | def template_dir 136 | File.join(PREFIX, 'share', 'oswitch', 'context') 137 | end 138 | 139 | # Template files. 140 | def template_files 141 | Dir[File.join(template_dir, '*')] 142 | end 143 | 144 | def motd 145 | str =< abyss-pe k=25 reads.fastq.gz 20 | zsh: command not found: abyss-pe 21 | 22 | # List available images. 23 | mymacbook:~/2015-02-01-myproject> oswitch -l 24 | yeban/biolinux:8 25 | ubuntu:14.04 26 | ontouchstart/texlive-full 27 | ipython/ipython 28 | hlapp/rpopgen 29 | bioconductor/release_sequencing 30 | 31 | # Enter the continaer and run commands interactively. 32 | mymacbook:~/2015-02-01-myproject> oswitch biolinux 33 | ###### You are now running: biolinux in container biolinux-7187. ###### 34 | biolinux-7187:~/2015-02-01-myproject> abyss-pe k=25 reads.fastq.gz 35 | [... just works on your files where they are...] 36 | biolinux-7187:~/2015-02-01-myproject> exit 37 | mymacbook:~/2015-02-01-myproject> 38 | [... output is where you expect it to be ...] 39 | 40 | 41 | # Use a container non-interactively. 42 | pixel:~/test/ $ oswitch yeban/biolinux blastp -remote -query mygene.fa -db nr > mygene_blastp_nr.txt 43 | ``` 44 | 45 | ### Installation 46 | 47 | oswitch first requires a [working docker installation](https://github.com/wurmlab/Dockerfiles). 48 | 49 | #### Download and run oswitch 50 | * [Download for Linux (64-bit)](https://github.com/wurmlab/oswitch/releases/download/v0.2.7/oswitch-0.2.7-linux-x86_64.tar.gz) 51 | * [Download for Linux (32-bit)](https://github.com/wurmlab/oswitch/releases/download/v0.2.7/oswitch-0.2.7-linux-x86.tar.gz) 52 | * [Download for macOS](https://github.com/wurmlab/oswitch/releases/download/v0.2.7/oswitch-0.2.7-osx.tar.gz) 53 | 54 | #### Install oswitch using RubyGems 55 | If you have Ruby 2.0 or higher (available by default on Mac and through package 56 | managers on Linux), you can install oswitch systemwide by running the command 57 | below: 58 | 59 | $ sudo gem install oswitch 60 | 61 | #### Install oswitch using [homebrew](http://brew.sh/) 62 | If you are on Mac, you can also install oswitch using [homebrew](http://brew.sh/): 63 | 64 | brew tap homebrew/science 65 | brew install oswitch 66 | 67 | This will install oswitch systemwide or only for your user depending on how 68 | homebrew is setup. 69 | 70 | Currently this installs version 0.2.6 of oswitch. 71 | 72 | #### On Ubuntu 73 | A `deb` package of `oswitch` is available in BioLinux repository for Trusty, 74 | Vivid and Jessie. 75 | 76 | $ sudo add-apt-repository ppa:nebc/bio-linux 77 | $ sudo apt-get update 78 | $ sudo apt-get install oswitch 79 | 80 | This will install oswitch systemwide. Please note that the package may not 81 | be up to date as the first two options. 82 | 83 | Currently this installs version 0.2.6 of oswitch. 84 | 85 | ### Usage note 86 | 87 | * [Volume mounting on Mac OS hosts is imperfect](#q-directories-mounted-within-container-on-mac-host-are-empty). 88 | * SELinux must be disabled on CentOS hosts for mounting volumes to work (check 89 | the SELinux documentation to see the implications of doing this). 90 | * We have tested oswitch on Debian, Ubuntu, CentOS based docker images on the 91 | following hosts: 92 | * Mac OS X Yosemite, El Captain 93 | * Ubuntu 14.04.1 94 | * CentOS 7 95 | 96 | ### FAQ 97 | 98 | ##### Q. Directories mounted within container on Mac host are empty. 99 | The problem is, on Mac `docker-machine` is the _real_ host, not OS X. `oswitch` can mount only what's available to it from `docker-machine`. Consider `/Applications` directory as an example. Run `docker-machine ssh default ls /Applications` and you will find it empty as well. The workaround is to correctly mount the directories you want inside `docker-machine` first: 100 | 101 | ``` 102 | docker-machine stop default 103 | VBoxManage sharedfolder remove default --name Applications 104 | VBoxManage sharedfolder add default --name Applications --hostpath /Applications --automount 105 | docker-machine start default 106 | docker-machine ssh default "sudo mkdir -p /Applications && sudo mount -t vboxsf -o uid=1000,gid=50 Applications /Applications" 107 | ``` 108 | 109 | ##### Q. cwd is empty in the container 110 | This means the said directory was not mounted by oswitch, or was incorrectly 111 | mounted. On Linux host, directories that can conflict with paths within 112 | container are not mounted. On Mac, `docker-machine` can get in the way. 113 | 114 | Please [report](https://github.com/yeban/oswitch/issues/new) this on our [issue 115 | tracker](https://github.com/yeban/oswitch/issues). To help us debug, please 116 | include: 117 | 118 | 1. the directory in question 119 | 2. the operating system you are running 120 | 121 | ##### Q. oswitch does not work with my docker image 122 | Please [report](https://github.com/yeban/oswitch/issues/new) this on our [issue 123 | tracker](https://github.com/yeban/oswitch/issues) with oswitch's output. If the 124 | image you are using is not available via docker hub or another public 125 | repository, please include the Dockerfile as well. 126 | 127 | ##### Q. How does all this work? 128 | We create a new image on the fly that inherits from the given image. While creating 129 | the new image we execute a shell script that installs packages required for 130 | oswitch to work and creates a user in the image (almost) identical to that on the host. 131 | 132 | ##### Q. How can I connect to an existing container? 133 | In another shell, use `docker ps` to see which containers are already running. Copy the identifier from the `CONTAINER ID` (column this looks something like `37e4e6ada6a4`), and use it to run `docker attach 37e4e6ada6a4` (replace with your container's id). This will create a new ssh connection to your existing container. 134 | 135 | ### Contribute 136 | 137 | $ git clone https://github.com/yeban/oswitch 138 | $ cd oswitch 139 | $ gem install bundler && bundle 140 | $ bundle exec bin/oswitch biolinux 141 | 142 | ### Contributors & Funding 143 | 144 | * Anurag Priyam - [a.priyam@qmul.ac.uk](mailto:a.priyam@qmul.ac.uk) | [@yeban](//twitter.com/yeban) 145 | * [Bruno Vieira](https://github.com/bmpvieira) ([@bmpvieira](//twitter.com/bmpvieira)) 146 | * [Saurabh Kumar](https://github.com/sa1) 147 | * Richard Nichols - [http://www.sbcs.qmul.ac.uk/staff/richardnichols.html](http://www.sbcs.qmul.ac.uk/staff/richardnichols.html) | [@qmwugbt112](//twitter.com/qmwugbt112) 148 | * Yannick Wurm - [http://wurmlab.github.io](http://wurmlab.github.io) | [@yannick__](//twitter.com/yannick__) 149 | 150 | --- 151 | 152 |

153 | Development funded as part of 154 | NERC Environmental Omics (EOS) Cloud at
155 | Wurm Lab, 156 | Queen Mary University of London. 157 |

158 | --------------------------------------------------------------------------------