Add 'apps/arv-web/' from commit 'f9732ad8460d013c2f28363655d0d1b91894dca5'
[arvados.git] / docker / api / update-gitolite.rb
1 #!/usr/bin/env ruby
2
3 require 'rubygems'
4 require 'pp'
5 require 'arvados'
6 require 'active_support/all'
7 require 'yaml'
8
9 # This script does the actual gitolite config management on disk.
10 #
11 # Ward Vandewege <ward@curoverse.com>
12
13 # Default is development
14 production = ARGV[0] == "production"
15
16 ENV["RAILS_ENV"] = "development"
17 ENV["RAILS_ENV"] = "production" if production
18
19 DEBUG = 1
20
21 # load and merge in the environment-specific application config info
22 # if present, overriding base config parameters as specified
23 path = File.dirname(__FILE__) + '/config/arvados-clients.yml'
24 if File.exists?(path) then
25   cp_config = YAML.load_file(path)[ENV['RAILS_ENV']]
26 else
27   puts "Please create a\n " + File.dirname(__FILE__) + "/config/arvados-clients.yml\n file"
28   exit 1
29 end
30
31 gitolite_url = cp_config['gitolite_url']
32 gitolite_tmp = cp_config['gitolite_tmp']
33
34 gitolite_admin = File.join(File.expand_path(File.dirname(__FILE__)) + '/' + gitolite_tmp + '/gitolite-admin')
35
36 ENV['ARVADOS_API_HOST'] = cp_config['arvados_api_host']
37 ENV['ARVADOS_API_TOKEN'] = cp_config['arvados_api_token']
38 if cp_config['arvados_api_host_insecure']
39   ENV['ARVADOS_API_HOST_INSECURE'] = 'true'
40 else
41   ENV.delete('ARVADOS_API_HOST_INSECURE')
42 end
43
44 keys = ''
45
46 seen = Hash.new
47
48 def ensure_repo(name,permissions,user_keys,gitolite_admin)
49   tmp = ''
50   # Just in case...
51   name.gsub!(/[^a-z0-9]/i,'')
52
53   keys = Hash.new()
54
55   user_keys.each do |uuid,p|
56     p.each do |k|
57       next if k[:public_key].nil?
58       keys[uuid] = Array.new() if not keys.key?(uuid)
59
60       key = k[:public_key]
61       # Handle putty-style ssh public keys
62       key.sub!(/^(Comment: "r[^\n]*\n)(.*)$/m,'ssh-rsa \2 \1')
63       key.sub!(/^(Comment: "d[^\n]*\n)(.*)$/m,'ssh-dss \2 \1')
64       key.gsub!(/\n/,'')
65       key.strip
66
67       keys[uuid].push(key)
68     end
69   end
70
71   cf = gitolite_admin + '/conf/auto/' + name + '.conf'
72
73   conf = "\nrepo #{name}\n"
74
75   commit = false
76
77   seen = {}
78   permissions.sort.each do |uuid,v|
79     conf += "\t#{v[:gitolite_permissions]}\t= #{uuid.to_s}\n"
80
81     count = 0
82     keys.include?(uuid) and keys[uuid].each do |v|
83       kf = gitolite_admin + '/keydir/arvados/' + uuid.to_s + "@#{count}.pub"
84       seen[kf] = true
85       if !File.exists?(kf) or IO::read(kf) != v then
86         commit = true
87         f = File.new(kf + ".tmp",'w')
88         f.write(v)
89         f.close()
90         # File.rename will overwrite the destination file if it exists
91         File.rename(kf + ".tmp",kf);
92       end
93       count += 1
94     end
95   end
96
97   if !File.exists?(cf) or IO::read(cf) != conf then
98     commit = true
99     f = File.new(cf + ".tmp",'w')
100     f.write(conf)
101     f.close()
102     # this is about as atomic as we can make the replacement of the file...
103     File.unlink(cf) if File.exists?(cf)
104     File.rename(cf + ".tmp",cf);
105   end
106
107   return commit,seen
108 end
109
110 begin
111
112   pwd = Dir.pwd
113   # Get our local gitolite-admin repo up to snuff
114   if not File.exists?(File.dirname(__FILE__) + '/' + gitolite_tmp) then
115     Dir.mkdir(File.join(File.dirname(__FILE__) + '/' + gitolite_tmp), 0700)
116   end
117   if not File.exists?(gitolite_admin) then
118     Dir.chdir(File.join(File.dirname(__FILE__) + '/' + gitolite_tmp))
119     `git clone #{gitolite_url}`
120   else
121     Dir.chdir(gitolite_admin)
122     `git pull`
123   end
124   Dir.chdir(pwd)
125
126   arv = Arvados.new( { :suppress_ssl_warnings => false } )
127
128   permissions = arv.repository.get_all_permissions
129
130   repos = permissions[:repositories]
131   user_keys = permissions[:user_keys]
132
133   @commit = false
134
135   @seen = {}
136
137   repos.each do |r|
138     next if r[:name].nil?
139     (@c,@s) = ensure_repo(r[:name],r[:user_permissions],user_keys,gitolite_admin)
140     @seen.merge!(@s)
141     @commit = true if @c
142   end
143
144   # Clean up public key files that should not be present
145   Dir.glob(gitolite_admin + '/keydir/arvados/*.pub') do |key_file|
146     next if key_file =~ /arvados_git_user.pub$/
147     next if @seen.has_key?(key_file)
148     puts "Extra file #{key_file}"
149     @commit = true
150     Dir.chdir(gitolite_admin)
151     key_file.gsub!(/^#{gitolite_admin}\//,'')
152     `git rm #{key_file}`
153   end
154
155   if @commit then
156     message = "#{Time.now().to_s}: update from API"
157     Dir.chdir(gitolite_admin)
158     `git add --all`
159     `git commit -m '#{message}'`
160     `git push`
161   end
162
163 rescue Exception => bang
164   puts "Error: " + bang.to_s
165   puts bang.backtrace.join("\n")
166   exit 1
167 end
168