Merge branch 'master' into 2221-complete-docker
[arvados.git] / docker / build.rb
1 #! /usr/bin/env ruby
2
3 require 'tempfile'
4 require 'yaml'
5
6 def sudo(*cmd)
7   # user can pass a single list in as an argument
8   # to allow usage like: sudo %w(apt-get install foo)
9   if cmd.length == 1 and cmd[0].class == Array
10     cmd = cmd[0]
11   end
12   system '/usr/bin/sudo', *cmd
13 end
14
15 def is_valid_email? str
16   str.match /^\S+@\S+\.\S+$/
17 end
18
19 def generate_api_hostname
20   rand(2**256).to_s(36)[0...5]
21 end
22
23 # ip_forwarding_enabled?
24 #   Returns 'true' if IP forwarding is enabled in the kernel
25 #
26 def ip_forwarding_enabled?
27   %x(/sbin/sysctl -n net.ipv4.ip_forward) == "1\n"
28 end
29
30 def debootstrap_ok?
31   return system '/usr/sbin/debootstrap --version > /dev/null 2>&1'
32 end
33
34 def docker_ok?
35   return system 'docker images > /dev/null 2>&1'
36 end
37
38 def find_ssh_key key_name
39   # If the user already has a key loaded in their agent, use one of those
40   agent_keys = `ssh-add -l`
41   if agent_keys.empty?
42     # Use a key named arvados_{key_name}_id_rsa, generating
43     # a passphraseless key if necessary.
44     ssh_key_file = "#{ENV['HOME']}/.ssh/arvados_#{key_name}_id_rsa"
45     unless File.exists? ssh_key_file
46       system 'ssh_keygen', '-f', ssh_key_file, '-P', ''
47     end
48   else
49     # choose an agent key at random
50     ssh_key_file = agent_keys.split("\n").first.split[2]
51   end
52
53   return File.exists?("#{ssh_key_file}.pub") ? "#{ssh_key_file}.pub" : nil
54 end
55
56 if not ip_forwarding_enabled?
57   warn "NOTE: IP forwarding must be enabled in the kernel."
58   warn "Turning IP forwarding on. You may be asked to enter your password."
59   sudo %w(/sbin/sysctl net.ipv4.ip_forward=1)
60 end
61
62 # Check that:
63 #   * Docker is installed and can be found in the user's path
64 #   * Docker can be run as a non-root user
65 #      - TODO: put the user is in the docker group if necessary
66 #      - TODO: mount cgroup automatically
67 #      - TODO: start the docker service if not started
68
69 docker_path = %x(which docker).chomp
70 if docker_path.empty?
71   warn "Docker not found."
72   warn ""
73   warn "Please make sure that Docker has been installed and"
74   warn "can be found in your PATH."
75   warn ""
76   warn "Installation instructions for a variety of platforms can be found at"
77   warn "http://docs.docker.io/en/latest/installation/"
78   exit
79 elsif not docker_ok?
80   warn "WARNING: docker could not be run."
81   warn "Please make sure that:"
82   warn "  * You have permission to read and write /var/run/docker.sock"
83   warn "  * a 'cgroup' volume is mounted on your machine"
84   warn "  * the docker daemon is running"
85   exit
86 end
87
88 # Check that debootstrap is installed.
89 if not debootstrap_ok?
90   warn "Installing debootstrap."
91   sudo '/usr/bin/apt-get', 'install', 'debootstrap'
92 end
93
94 # Generate a config.yml if it does not exist
95 if not File.exists? 'config.yml'
96   print "Generating config.yml.\n"
97   print "Arvados needs to know the email address of the administrative user,\n"
98   print "so that when that user logs in they are automatically made an admin.\n"
99   print "This should be the email address you use to log in to Google.\n"
100   print "\n"
101   admin_email_address = ""
102   until is_valid_email? admin_email_address
103     print "Enter your Google ID email address here: "
104     admin_email_address = gets.strip
105     if not is_valid_email? admin_email_address
106       print "That doesn't look like a valid email address. Please try again.\n"
107     end
108   end
109
110   File.open 'config.yml', 'w' do |config_out|
111     config = YAML.load_file 'config.yml.example'
112     config['API_AUTO_ADMIN_USER'] = admin_email_address
113     config['API_HOSTNAME'] = generate_api_hostname
114     config['PUBLIC_KEY_PATH'] = find_ssh_key(config['API_HOSTNAME'])
115     config.each_key do |var|
116       if var.end_with?('_PW') or var.end_with?('_SECRET')
117         config[var] = rand(2**256).to_s(36)
118       end
119       config_out.write "#{var}: #{config[var]}\n"
120     end
121   end
122 end
123
124 # If all prerequisites are met, go ahead and build.
125 if ip_forwarding_enabled? and
126     docker_ok? and
127     debootstrap_ok? and
128     File.exists? 'config.yml'
129   warn "Building Arvados."
130   system '/usr/bin/make', *ARGV
131 end
132
133 # install_docker
134 #   Determine which Docker package is suitable for this Linux distro
135 #   and install, resolving any dependencies.
136 #   NOTE: not in use yet.
137
138 def install_docker
139   linux_distro = %x(lsb_release --id).split.last
140   linux_release = %x(lsb_release --release).split.last
141   linux_version = linux_distro + " " + linux_release
142   kernel_release = `uname -r`
143   
144   case linux_distro
145   when 'Ubuntu'
146     if not linux_release.match '^1[234]\.'
147       warn "Arvados requires at least Ubuntu 12.04 (Precise Pangolin)."
148       warn "Your system is Ubuntu #{linux_release}."
149       exit
150     end
151     if linux_release.match '^12' and kernel_release.start_with? '3.2'
152       # Ubuntu Precise ships with a 3.2 kernel and must be upgraded.
153       warn "Your kernel #{kernel_release} must be upgraded to run Docker."
154       warn "To do this:"
155       warn "  sudo apt-get update"
156       warn "  sudo apt-get install linux-image-generic-lts-raring linux-headers-generic-lts-raring"
157       warn "  sudo reboot"
158       exit
159     else
160       # install AUFS
161       sudo 'apt-get', 'update'
162       sudo 'apt-get', 'install', "linux-image-extra-#{kernel_release}"
163     end
164
165     # add Docker repository
166     sudo %w(/usr/bin/apt-key adv
167               --keyserver keyserver.ubuntu.com
168               --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9)
169     source_file = Tempfile.new('arv')
170     source_file.write("deb http://get.docker.io/ubuntu docker main\n")
171     source_file.close
172     sudo '/bin/mv', source_file.path, '/etc/apt/sources.list.d/docker.list'
173     sudo %w(/usr/bin/apt-get update)
174     sudo %w(/usr/bin/apt-get install lxc-docker)
175
176     # Set up for non-root access
177     sudo %w(/usr/sbin/groupadd docker)
178     sudo '/usr/bin/gpasswd', '-a', ENV['USER'], 'docker'
179     sudo %w(/usr/sbin/service docker restart)
180   when 'Debian'
181   else
182     warn "Must be running a Debian or Ubuntu release in order to run Docker."
183     exit
184   end
185 end
186