oswitch 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/README.mkd +295 -0
- data/bin/oswitch +45 -0
- data/lib/oswitch.rb +293 -0
- data/oswitch.gemspec +27 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f17f0c2bd70cf5a969f60d6a000ebacaba1940dc
|
4
|
+
data.tar.gz: 4fc93cdb2580315e7a49032c2ff32797566144a1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 08362f1f00b5d02531c2df28c59ccb9107f13e9ffcce5efef32cf2378e922f83c8db512dd098af6c081237b6db7920bf64c1d258c0f916762de5bd5a3eb0e883
|
7
|
+
data.tar.gz: 73b363b026815f51c84b110dd59a857a168fc9c8e9aaee6b22b14cb96341b4d83c7eba06b02a92d9fd18ef2cbb4d4f2fd91307cf1ba52f27aa4b6909da0f8e3e
|
data/Gemfile
ADDED
data/README.mkd
ADDED
@@ -0,0 +1,295 @@
|
|
1
|
+
# OSwitch
|
2
|
+
|
3
|
+
One-line access to other operating systems.
|
4
|
+
|
5
|
+
* [Usage](#example-usage)
|
6
|
+
* [Installation](#installation)
|
7
|
+
* [FAQ](#faq)
|
8
|
+
* [Roadmap](#roadmap)
|
9
|
+
* [Contributors & Funding](#contributors-&-funding)
|
10
|
+
|
11
|
+
## Background
|
12
|
+
|
13
|
+
Genomic analyses require using many bioinformatics tools starting from assessing
|
14
|
+
the quality of sequenced data and assembly, to annotation, comparison and
|
15
|
+
analysis. The data types are young, thus the tools are too and many
|
16
|
+
genomicists lack computational training. Thus tools are frequently
|
17
|
+
updated yet often challenging to install. Furthermore, software updates often
|
18
|
+
involve changes in algorithms or input/output formats, making analyses
|
19
|
+
difficult to reproduce. To make matters worse, genomicists often lack
|
20
|
+
the skills necessary to setup complex bioinformatics software, and
|
21
|
+
systems administrators can be overwhelmed by large numbers of software
|
22
|
+
installation requests & the challenges of managing multiple versions.
|
23
|
+
|
24
|
+
## Aim & Features
|
25
|
+
|
26
|
+
We are developing `oswitch` to enable **seamless switching
|
27
|
+
from one operating system to another** - providing access to diverse
|
28
|
+
ranges of tools. This project grew from our own need to rapidly access
|
29
|
+
software distributed as part of
|
30
|
+
[BioLinux](http://environmentalomics.org/bio-linux/) on our MacBooks
|
31
|
+
and our university HPC system.
|
32
|
+
|
33
|
+
For this we take advantage of the [docker](http://docker.io/)
|
34
|
+
technology. Docker works by creating "to the specification" image from
|
35
|
+
a Dockerfile, which is then run in an isolated
|
36
|
+
"container". Dockerfiles or the resulting images can persist forever,
|
37
|
+
are easily [shared or published](https://hub.docker.com/), and make
|
38
|
+
it possible for anybody to recreate the exact same setup at
|
39
|
+
any point of time in the future. This is similar to using virtual
|
40
|
+
machine images - but much more
|
41
|
+
[flexible and light-weight](http://stackoverflow.com/questions/16047306/how-is-docker-io-different-from-a-normal-virtual-machine).
|
42
|
+
|
43
|
+
`oswitch` is thus a wrapper facilitating access to docker images (without the
|
44
|
+
need for ssh-ing). Importantly, when switching operating systems inside a
|
45
|
+
shell, most things remain unchanged:
|
46
|
+
|
47
|
+
* Current working directory is maintained
|
48
|
+
* User name, uid and gid are maintained
|
49
|
+
* Login shell (bash/zsh/fish) is maintained
|
50
|
+
* Home directory is maintained (thus all .dotfiles and config files
|
51
|
+
are maintained).
|
52
|
+
* read/write permissions are maintained
|
53
|
+
* Paths are maintained whenever possible. Thus volumes (external drives,
|
54
|
+
NAS) mounted on the host are available in the container at the same
|
55
|
+
path.
|
56
|
+
|
57
|
+
## Example Usage
|
58
|
+
|
59
|
+
There are two broad usage scenarios: interactive use & non-interactive
|
60
|
+
use.
|
61
|
+
|
62
|
+
##### Use a package interactively in a normal command-line
|
63
|
+
|
64
|
+
Minimalist example:
|
65
|
+
|
66
|
+
```shell
|
67
|
+
Yannick@n56-169 ~/g/oswitch> uname -a
|
68
|
+
Darwin n56-169.sbcs.qmul.ac.uk 14.0.0 Darwin Kernel Version 14.0.0: Fri Sep 19 00:26:44 PDT 2014; root:xnu-2782.1.97~2/RELEASE_X86_64 x86_64
|
69
|
+
Yannick@n56-169 ~/g/oswitch> oswitch yeban/biolinux:8
|
70
|
+
### You are now running: biolinux_8, in container: biolinux_8-27182. ###
|
71
|
+
Yannick@biolinux_8-27182 ~/g/oswitch> uname -a
|
72
|
+
Linux biolinux_8-27182 3.16.4-tinycore64 #1 SMP Thu Oct 23 16:14:24 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
|
73
|
+
```
|
74
|
+
|
75
|
+
Biologically relevant example:
|
76
|
+
|
77
|
+
```shell
|
78
|
+
# Trying to run blast.
|
79
|
+
pixel:~/test/ $ ls
|
80
|
+
mygene.fasta
|
81
|
+
pixel:~/test/ $ cat mygene.fa
|
82
|
+
>myfavoritegene isthisone
|
83
|
+
MNTLWLSLWDYPGKLPLNFMVFDTKDDLQAAYWRDPYSIPLAVIFEDPQPISQRLIYEIR
|
84
|
+
TNPSYTLPPPPTKLYSAPISCRKNKTGHWMDDILSIKTGESCPVNNYLHSGFLALQMITD
|
85
|
+
ITKIKLENSDVTIPDIKLIMFPKEPYTADWMLAFRVVIPLYMVLALSQFITYLLILIVGE
|
86
|
+
KENKIKEGMKMMGLNDSVF
|
87
|
+
pixel:~/test/ $ blastp -query mygene.fa -remote -db nr -outfmt 7 > mygene_blastp_nr.tab
|
88
|
+
zsh: command not found: blastp
|
89
|
+
# Indeed... blastp is not installed on my MacBook.
|
90
|
+
|
91
|
+
# Switch to BioLinux and run blastp.
|
92
|
+
pixel:~/test/ $ oswitch biolinux
|
93
|
+
###### You are now running: biolinux in container biolinux-7187. ######
|
94
|
+
biolinux-7187:~/test/ $ blastp -query mygene.fa -remote -db nr -outfmt 7 > mygene_blastp_nr.tab
|
95
|
+
# BioLinux includes blastp, thus the command ran smoothly.
|
96
|
+
|
97
|
+
# View the result.
|
98
|
+
biolinux-7187:~/test/ $ head mygene_blastp_nr.tab
|
99
|
+
# BLASTP 2.2.28+
|
100
|
+
# Query: myfavoritegene isthisone
|
101
|
+
# RID: BJAHAHU9015
|
102
|
+
# Database: nr
|
103
|
+
# Fields: query id, subject id, % identity, alignment length, mismatches, gap opens, q. start, q. end, s. start, s. end, evalue, bit score
|
104
|
+
# 501 hits found
|
105
|
+
myfavoritegene gi|322796550|gb|EFZ19024.1| 100.00 199 0 0 1 199 1 199 2e-142 407
|
106
|
+
myfavoritegene gi|307183032|gb|EFN69988.1| 86.07 201 25 2 1 199 80 279 6e-115 361
|
107
|
+
myfavoritegene gi|572260155|ref|XP_006608402.1| 80.60 201 36 2 1 199 95 294 4e-108 350
|
108
|
+
myfavoritegene gi|328778864|ref|XP_397465.4| 80.60 201 36 2 1 199 95 294 5e-108 350
|
109
|
+
|
110
|
+
|
111
|
+
# [... potentially run other analyses that require biolinux things...]
|
112
|
+
|
113
|
+
# Return to normal operating system
|
114
|
+
biolinux-7187:~/test/ $ exit
|
115
|
+
pixel:~/test/ $ ls
|
116
|
+
mygene.fasta mygene_blastp_nr.txt
|
117
|
+
```
|
118
|
+
|
119
|
+
##### Use a package non-interactively
|
120
|
+
|
121
|
+
Alternatively, single commands can be run directly in a container
|
122
|
+
(e.g. BioLinux) without entering it interactively. This can
|
123
|
+
be useful to test new tools, or to run a single piece of
|
124
|
+
not-locally-installed software as part of a single command. The
|
125
|
+
container terminates automatically once the command has been
|
126
|
+
executed, output is printed to the terminal and can be redirected, and
|
127
|
+
the exit status of the command run within container is returned.
|
128
|
+
|
129
|
+
```shell
|
130
|
+
# Run command directly in BioLinux and view results if success.
|
131
|
+
pixel:~/test/ $ oswitch biolinux blastp -remote -query mygene.fa -db nr > mygene_blastp_nr.txt
|
132
|
+
```
|
133
|
+
|
134
|
+
##### Listing available operating system containers
|
135
|
+
|
136
|
+
OSwitch can pull any image from docker hub. You can see the images you pulled
|
137
|
+
from docker hub using oswitch as:
|
138
|
+
|
139
|
+
```shell
|
140
|
+
pixel:~ $ oswitch -l
|
141
|
+
yeban/biolinux:8
|
142
|
+
ubuntu:14.04
|
143
|
+
```
|
144
|
+
|
145
|
+
##### Availability
|
146
|
+
|
147
|
+
OSwitch has been tested on:
|
148
|
+
|
149
|
+
* Mac OS X Yosemite
|
150
|
+
* Ubuntu 14.04.1
|
151
|
+
* CentOS 7
|
152
|
+
|
153
|
+
##### Caveats
|
154
|
+
|
155
|
+
* Works only for Debian, Ubuntu, CentOS based docker images.
|
156
|
+
* Host directories/volumes with paths conflicting with container paths are
|
157
|
+
skipped.
|
158
|
+
* SELinux must be disabled on CentOS for mounting volumes to work.
|
159
|
+
|
160
|
+
## Installation
|
161
|
+
|
162
|
+
OSwitch first requires a working docker install.
|
163
|
+
|
164
|
+
#### Install and setup docker
|
165
|
+
|
166
|
+
##### Mac OS X
|
167
|
+
|
168
|
+
Installing docker - https://docs.docker.com/installation/mac/
|
169
|
+
|
170
|
+
##### Ubuntu
|
171
|
+
|
172
|
+
Installing docker - https://docs.docker.com/installation/ubuntulinux/
|
173
|
+
|
174
|
+
Add yourself to docker group so you can run docker client without sudo:
|
175
|
+
|
176
|
+
```shell
|
177
|
+
$ sudo usermod -aG docker `whoami`
|
178
|
+
|
179
|
+
# then logout and login again for the above command to take effect
|
180
|
+
```
|
181
|
+
|
182
|
+
##### CentOS
|
183
|
+
|
184
|
+
Installing docker - https://docs.docker.com/installation/centos/
|
185
|
+
|
186
|
+
Add yourself to docker group so you can run docker client without sudo:
|
187
|
+
|
188
|
+
```shell
|
189
|
+
$ sudo usermod -aG docker `whoami`
|
190
|
+
|
191
|
+
# then logout and login again for the above command to take effect
|
192
|
+
```
|
193
|
+
|
194
|
+
Disable SELinux as it gets in the way of mounting volumes within the container:
|
195
|
+
|
196
|
+
```shell
|
197
|
+
$ sed -i .bak 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
|
198
|
+
|
199
|
+
# then reboot your system
|
200
|
+
```
|
201
|
+
|
202
|
+
The above command backs up the original file to `/etc/selinux/config.bak`. If
|
203
|
+
you are concerned about disabling SELinux, do note that we are trying to work
|
204
|
+
out a better solution.
|
205
|
+
|
206
|
+
#### Test that docker is correctly installed
|
207
|
+
|
208
|
+
The following should give an encouraging message:
|
209
|
+
|
210
|
+
$ docker run hello-world
|
211
|
+
|
212
|
+
#### Install oswitch
|
213
|
+
|
214
|
+
Requirements: Ruby 2.0 or higher.
|
215
|
+
|
216
|
+
$ gem install oswitch
|
217
|
+
|
218
|
+
#### Testing oswitch
|
219
|
+
|
220
|
+
$ oswitch ubuntu:14.04
|
221
|
+
|
222
|
+
## FAQ
|
223
|
+
|
224
|
+
##### Q. Directories mounted within container on Mac host are empty.
|
225
|
+
The problem is, on Mac `boot2docker` is the _real_ host, not OS X. `oswitch`
|
226
|
+
can mount only what's available to it from `boot2docker`. For example,
|
227
|
+
`/Applications`.
|
228
|
+
|
229
|
+
Run `boot2docker ssh ls /Applications` and you will find it empty as well.
|
230
|
+
|
231
|
+
The workaround is to correctly mount the directories you want in `boot2docker`
|
232
|
+
first.
|
233
|
+
|
234
|
+
```
|
235
|
+
boot2docker down
|
236
|
+
VBoxManage sharedfolder remove boot2docker-vm --name Applications
|
237
|
+
VBoxManage sharedfolder add boot2docker-vm --name Applications --hostpath /Applications
|
238
|
+
boot2docker up
|
239
|
+
boot2docker ssh "sudo mkdir -p /Applications && sudo mount -t vboxsf -o uid=1000,gid=50 Applications /Applications"
|
240
|
+
```
|
241
|
+
|
242
|
+
##### Q. cwd is empty in the container
|
243
|
+
This means the said directory was not mounted by oswitch, or was incorrectly
|
244
|
+
mounted. On Linux host, directories that can conflict with paths within
|
245
|
+
container are not mounted. On Mac, `boot2docker` can get in the way.
|
246
|
+
|
247
|
+
Please [report](https://github.com/yeban/oswitch/issues/new) this on our [issue
|
248
|
+
tracker](https://github.com/yeban/oswitch/issues). To help us debug, please
|
249
|
+
include:
|
250
|
+
|
251
|
+
1. the directory in question
|
252
|
+
2. the operating system you are running
|
253
|
+
|
254
|
+
##### Q. oswitch does not work with my docker image
|
255
|
+
Please [report](https://github.com/yeban/oswitch/issues/new) this on our [issue
|
256
|
+
tracker](https://github.com/yeban/oswitch/issues) with oswitch's output. If the
|
257
|
+
image you are using is not available via docker hub or another public
|
258
|
+
repository, please include the Dockerfile as well.
|
259
|
+
|
260
|
+
## Roadmap
|
261
|
+
|
262
|
+
1. ~~make it possible to use docker containers without inheriting our
|
263
|
+
current baseimage~~
|
264
|
+
2. ~~gem distribution for easier installation~~
|
265
|
+
3. brew recipe for Mac
|
266
|
+
4. test on QMUL's compute cluster
|
267
|
+
5. create an SELinux policy to run oswitch on CentOS without having to disable
|
268
|
+
SELinux entirely
|
269
|
+
6. rpm and deb packages
|
270
|
+
7. make available images for common bioinformatics software
|
271
|
+
8. deploy at [RAL/JASMIN](http://www.jasmin.ac.uk)
|
272
|
+
|
273
|
+
## Contribute
|
274
|
+
|
275
|
+
$ git clone https://github.com/yeban/oswitch
|
276
|
+
$ cd oswitch
|
277
|
+
$ gem install bundler && bundle
|
278
|
+
$ bundle exec bin/oswitch biolinux
|
279
|
+
|
280
|
+
## Contributors & Funding
|
281
|
+
|
282
|
+
* Anurag Priyam - [a.priyam@qmul.ac.uk](mailto:a.priyam@qmul.ac.uk) | [@yeban](//twitter.com/yeban)
|
283
|
+
* [Bruno Vieira](https://github.com/bmpvieira) ([@bmpvieira](//twitter.com/bmpvieira))
|
284
|
+
* [Saurabh Kumar](https://github.com/sa1)
|
285
|
+
* Richard Nichols - [http://www.sbcs.qmul.ac.uk/staff/richardnichols.html](http://www.sbcs.qmul.ac.uk/staff/richardnichols.html) | [@qmwugbt112](//twitter.com/qmwugbt112)
|
286
|
+
* Yannick Wurm - [http://wurmlab.github.io](http://wurmlab.github.io) |
|
287
|
+
[@yannick__](//twitter.com/yannick__)
|
288
|
+
|
289
|
+
---
|
290
|
+
|
291
|
+
<p align="center">
|
292
|
+
Development funded as part of NERC EOS Cloud at
|
293
|
+
<a href="http://wurmlab.github.io/">Wurm Lab</a>,
|
294
|
+
<a href="http://sbcs.mul.ac.uk/">Queen Mary University of London</a>.
|
295
|
+
</p>
|
data/bin/oswitch
ADDED
@@ -0,0 +1,45 @@
|
|
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] <package> [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
|
+
exit
|
41
|
+
end
|
42
|
+
|
43
|
+
package = ARGV[0]
|
44
|
+
command = ARGV[1..-1]
|
45
|
+
OSwitch.to(package, command)
|
data/lib/oswitch.rb
ADDED
@@ -0,0 +1,293 @@
|
|
1
|
+
require 'timeout'
|
2
|
+
require 'colorize'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'shellwords'
|
5
|
+
|
6
|
+
# OSwitch leverages docker to provide access to complex Bioinformatics software
|
7
|
+
# (even Biolinux!) in just one command.
|
8
|
+
#
|
9
|
+
# Images are built on the user's system on demand and executed in a container.
|
10
|
+
# Containers are removed after execution.
|
11
|
+
#
|
12
|
+
# Volumes from host OS are mounted in the container just the same, including
|
13
|
+
# home directory. USER, HOME, SHELL, and PWD are preserved.
|
14
|
+
class OSwitch
|
15
|
+
|
16
|
+
class ENOPKG < StandardError
|
17
|
+
|
18
|
+
def initialize(name)
|
19
|
+
@name = name
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
"Recipe to run #@name not available."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class ENODKR < StandardError
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
"***** Docker not installed / correctly setup / running.
|
31
|
+
Are you able to run 'docker info'?"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
include Timeout
|
36
|
+
|
37
|
+
# Captures a docker image's metadata.
|
38
|
+
Image = Struct.new :repository, :tag, :id, :created, :size
|
39
|
+
|
40
|
+
class Image
|
41
|
+
|
42
|
+
# Model Image's eigenclass as a collection of Image objects.
|
43
|
+
class << self
|
44
|
+
|
45
|
+
include Enumerable
|
46
|
+
|
47
|
+
def all
|
48
|
+
`docker images`.split("\n").drop(1).
|
49
|
+
map{|l| Image.new(*l.split(/\s{2,}/))}
|
50
|
+
end
|
51
|
+
|
52
|
+
def each(&block)
|
53
|
+
all.each(&block)
|
54
|
+
end
|
55
|
+
|
56
|
+
def get(imgname)
|
57
|
+
repository, tag = imgname.split(':')
|
58
|
+
return if not repository or repository.empty?
|
59
|
+
tag = 'latest' if not tag or tag.empty?
|
60
|
+
find {|img| img.repository == repository and img.tag == tag}
|
61
|
+
end
|
62
|
+
|
63
|
+
def exists?(imgname)
|
64
|
+
!!get(imgname)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Linux specific code.
|
70
|
+
module Linux
|
71
|
+
|
72
|
+
def uid
|
73
|
+
Process.uid
|
74
|
+
end
|
75
|
+
|
76
|
+
def gid
|
77
|
+
Process.gid
|
78
|
+
end
|
79
|
+
|
80
|
+
# Parse /proc/mounts for mountpoints.
|
81
|
+
def mountpoints
|
82
|
+
mtab = IO.readlines '/proc/mounts'
|
83
|
+
mountpoints = mtab.map{ |line| line.split(/\s+/)[1]}
|
84
|
+
mountpoints.map!{ |mount| unescape(mount) }
|
85
|
+
# Ignore common system mountpoints.
|
86
|
+
mountpoints.reject!{ |mount| mount =~ /^\/$/ }
|
87
|
+
mountpoints.reject!{ |mount| mount =~ /^\/(proc|sys|usr|boot|tmp|dev|var|bin|etc|lib).*/ }
|
88
|
+
# Mount /run/media/* but ignore other /run/ mountpoints.
|
89
|
+
mountpoints.reject!{ |mount| mount =~ /^\/run.*/ unless mount =~ /^\/run\/(media.*)/ }
|
90
|
+
|
91
|
+
# Add home dir.
|
92
|
+
mountpoints << home
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def unescape(mount)
|
98
|
+
mount.gsub(/\\040/, " ").gsub(/\\012/, "\n").gsub(/\\134/, "\\").gsub(/\\011/, "\t")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# Mac OS X specific code.
|
103
|
+
module Darwin
|
104
|
+
|
105
|
+
BLACKLIST =
|
106
|
+
%r{
|
107
|
+
^/$|
|
108
|
+
^/(bin|cores|dev|etc|home|Incompatible\ Software|
|
109
|
+
installer\.failurerequests|lost\+found|net|
|
110
|
+
Network|opt|private|sbin|System|Users|tmp|
|
111
|
+
usr|var|Volumes$)
|
112
|
+
}x
|
113
|
+
|
114
|
+
def uid
|
115
|
+
`boot2docker ssh id -u`.chomp
|
116
|
+
end
|
117
|
+
|
118
|
+
def gid
|
119
|
+
`boot2docker ssh id -g`.chomp
|
120
|
+
end
|
121
|
+
|
122
|
+
def mountpoints
|
123
|
+
volumes = Dir['/Volumes/*'].map {|v| File.symlink?(v) ? File.readlink(v) : v}
|
124
|
+
volumes = volumes | Dir['/*']
|
125
|
+
volumes.reject! { |mount| mount =~ BLACKLIST }
|
126
|
+
volumes << home
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# NOTE:
|
131
|
+
# This won't work on JRuby, as it sets RUBY_PLATFORM to 'java'.
|
132
|
+
case RUBY_PLATFORM
|
133
|
+
when /linux/
|
134
|
+
include Linux
|
135
|
+
when /darwin/
|
136
|
+
include Darwin
|
137
|
+
end
|
138
|
+
|
139
|
+
DOTDIR = File.expand_path('~/.oswitch')
|
140
|
+
|
141
|
+
class << self
|
142
|
+
# Invoke as `OSwitch.to` instead of `OSwitch.new`.
|
143
|
+
alias_method :to, :new
|
144
|
+
private :new
|
145
|
+
|
146
|
+
def packages
|
147
|
+
Dir["#{DOTDIR}/*"].
|
148
|
+
select {|entry| File.directory? entry}.
|
149
|
+
map {|pkg|
|
150
|
+
pkg.gsub("#{DOTDIR}/", '')
|
151
|
+
}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def initialize(package, command = [])
|
156
|
+
@package = package.strip
|
157
|
+
@command = command.join(' ')
|
158
|
+
@imgname = "oswitch_#{@package}"
|
159
|
+
@cntname = "#{@package.gsub(%r{/|:}, '_')}-#{Process.pid}"
|
160
|
+
exec
|
161
|
+
end
|
162
|
+
|
163
|
+
attr_reader :package, :command, :imgname, :cntname
|
164
|
+
|
165
|
+
def exec
|
166
|
+
ping and build and switch
|
167
|
+
rescue ENODKR, ENOPKG => e
|
168
|
+
puts e
|
169
|
+
exit
|
170
|
+
end
|
171
|
+
|
172
|
+
private
|
173
|
+
|
174
|
+
def switch
|
175
|
+
cmdline = "docker run --name #{cntname} --hostname #{cntname} -it --rm" \
|
176
|
+
" -w #{cwd} #{mountargs} #{imgname} "
|
177
|
+
if command.empty?
|
178
|
+
# Display motd and run interactive shell.
|
179
|
+
cmdline << "#{shell} -c \"echo #{motd}; #{shell} -i\""
|
180
|
+
else
|
181
|
+
cmdline << "#{shell} -c \"#{command}\""
|
182
|
+
end
|
183
|
+
Kernel.exec cmdline
|
184
|
+
end
|
185
|
+
|
186
|
+
def build
|
187
|
+
return true if Image.exists? imgname
|
188
|
+
write_context && system("docker build -t #{imgname} #{context_dir}")
|
189
|
+
end
|
190
|
+
|
191
|
+
# Ping docker daemon. Raise error if no response within 10s.
|
192
|
+
def ping
|
193
|
+
pong = timeout 5, ENODKR do
|
194
|
+
system 'docker info > /dev/null 2>&1'
|
195
|
+
end
|
196
|
+
pong or raise ENODKR
|
197
|
+
end
|
198
|
+
|
199
|
+
## Code to generate context dir that will be built into a docker image. ##
|
200
|
+
|
201
|
+
# Write data to context dir.
|
202
|
+
def write_context
|
203
|
+
create_context_dir
|
204
|
+
write_dockerfile
|
205
|
+
end
|
206
|
+
|
207
|
+
# Create context dir.
|
208
|
+
def create_context_dir
|
209
|
+
FileUtils.mkdir_p context_dir
|
210
|
+
FileUtils.cp_r(template_files, context_dir)
|
211
|
+
end
|
212
|
+
|
213
|
+
# Write Dockerfile.
|
214
|
+
def write_dockerfile
|
215
|
+
dockerfile = File.join(context_dir, 'Dockerfile')
|
216
|
+
File.write(dockerfile, dockerfile_data)
|
217
|
+
end
|
218
|
+
|
219
|
+
# Generate String that get written to Dockerfile.
|
220
|
+
def dockerfile_data
|
221
|
+
data = ["FROM #{package}"]
|
222
|
+
data << 'COPY _switch /'
|
223
|
+
data << 'COPY wheel /etc/sudoers.d/'
|
224
|
+
data << "RUN /_switch #{userargs} 2>&1 | tee /tmp/oswitch.log"
|
225
|
+
data << 'ENV LC_ALL en_US.UTF-8'
|
226
|
+
data << "USER #{username}"
|
227
|
+
data << "ENTRYPOINT [\"#{shell}\", \"-c\"]"
|
228
|
+
data.join("\n")
|
229
|
+
end
|
230
|
+
|
231
|
+
# Location of context dir.
|
232
|
+
def context_dir
|
233
|
+
File.join(DOTDIR, package)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Location of template dir.
|
237
|
+
def template_dir
|
238
|
+
File.expand_path('../context/', File.dirname(__FILE__))
|
239
|
+
end
|
240
|
+
|
241
|
+
# Template files.
|
242
|
+
def template_files
|
243
|
+
Dir[File.join(template_dir, '*')]
|
244
|
+
end
|
245
|
+
|
246
|
+
|
247
|
+
## Data required to switchify a container. ##
|
248
|
+
def username
|
249
|
+
ENV['USER']
|
250
|
+
end
|
251
|
+
|
252
|
+
def home
|
253
|
+
ENV['HOME']
|
254
|
+
end
|
255
|
+
|
256
|
+
def shell
|
257
|
+
File.basename ENV['SHELL']
|
258
|
+
end
|
259
|
+
|
260
|
+
def cwd
|
261
|
+
Dir.pwd
|
262
|
+
end
|
263
|
+
|
264
|
+
def motd
|
265
|
+
str =<<MOTD
|
266
|
+
################################################################################
|
267
|
+
You are now running: #{package}, in container: #{cntname}.
|
268
|
+
|
269
|
+
Container is distinct from the shell your launched this container from. Changes
|
270
|
+
you make here will be lost unless it's made to one of the directories below:
|
271
|
+
|
272
|
+
- #{mountpoints.join("\n - ")}
|
273
|
+
|
274
|
+
It's possible you may not be able to write to one or more directories above,
|
275
|
+
but it should be possible to read data from all. Home directory is often the
|
276
|
+
safest to write to.
|
277
|
+
|
278
|
+
Press Ctrl-D or type 'exit' to go back.
|
279
|
+
################################################################################
|
280
|
+
MOTD
|
281
|
+
str.blue.shellescape
|
282
|
+
end
|
283
|
+
|
284
|
+
def mountargs
|
285
|
+
mountpoints.map do |mountpoint|
|
286
|
+
"-v '#{mountpoint}':'#{mountpoint}'"
|
287
|
+
end.join(' ')
|
288
|
+
end
|
289
|
+
|
290
|
+
def userargs
|
291
|
+
[uid, gid, username, home, shell].join(' ')
|
292
|
+
end
|
293
|
+
end
|
data/oswitch.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
# meta
|
3
|
+
s.name = 'oswitch'
|
4
|
+
s.version = '0.1.0'
|
5
|
+
s.authors = ['Anurag Priyam']
|
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 = <<DESC
|
13
|
+
Use any docker image as the host operating system's user (same user name, same
|
14
|
+
uid, same gid, and even the same shell!) and access to host operating system's
|
15
|
+
filesystem.
|
16
|
+
DESC
|
17
|
+
|
18
|
+
# dependencies
|
19
|
+
s.add_dependency('colorize', '~> 0.7.5')
|
20
|
+
|
21
|
+
# gem
|
22
|
+
s.files = Dir['lib/**/*'] + Dir['Dockerfiles/**/*']
|
23
|
+
s.files = s.files + ['Gemfile', 'oswitch.gemspec']
|
24
|
+
s.files = s.files + ['README.mkd']
|
25
|
+
s.require_paths = ['lib']
|
26
|
+
s.executables = ['oswitch']
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: oswitch
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Anurag Priyam
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: colorize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.7.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.7.5
|
27
|
+
description: |
|
28
|
+
Use any docker image as the host operating system's user (same user name, same
|
29
|
+
uid, same gid, and even the same shell!) and access to host operating system's
|
30
|
+
filesystem.
|
31
|
+
email:
|
32
|
+
- anurag08priyam@gmail.com
|
33
|
+
executables:
|
34
|
+
- oswitch
|
35
|
+
extensions: []
|
36
|
+
extra_rdoc_files: []
|
37
|
+
files:
|
38
|
+
- Gemfile
|
39
|
+
- README.mkd
|
40
|
+
- bin/oswitch
|
41
|
+
- lib/oswitch.rb
|
42
|
+
- oswitch.gemspec
|
43
|
+
homepage: https://github.com/yeban/oswitch
|
44
|
+
licenses:
|
45
|
+
- MIT
|
46
|
+
metadata: {}
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 2.4.2
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: Use docker image as the host operating system's user and access host operating
|
67
|
+
system's filesystem.
|
68
|
+
test_files: []
|