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