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