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