2 # Copyright (C) The Arvados Authors. All rights reserved.
4 # SPDX-License-Identifier: AGPL-3.0
7 # Prior to April 2015, Arvados Gitolite integration stored repositories by
8 # name. To improve user repository management, we switched to storing
9 # repositories by UUID, and aliasing them to names. This makes it easy to
10 # have rich name hierarchies, and allow users to rename repositories.
12 # This script will migrate a name-based Gitolite configuration to a UUID-based
15 # 1. Change the value of REPOS_DIR below, if needed.
16 # 2. Install this script in the same directory as `update-gitolite.rb`.
17 # 3. Ensure that no *other* users can access Gitolite: edit gitolite's
18 # authorized_keys file so it only contains the arvados_git_user key,
19 # and disable the update-gitolite cron job.
20 # 4. Run this script: `ruby migrate-gitolite-to-uuid-storage.rb production`.
29 REPOS_DIR = "/var/lib/gitolite/repositories"
31 # Default is development
32 production = ARGV[0] == "production"
34 ENV["RAILS_ENV"] = "development"
35 ENV["RAILS_ENV"] = "production" if production
39 # load and merge in the environment-specific application config info
40 # if present, overriding base config parameters as specified
41 path = File.dirname(__FILE__) + '/config/arvados-clients.yml'
42 if File.exist?(path) then
43 cp_config = YAML.load_file(path)[ENV['RAILS_ENV']]
45 puts "Please create a\n " + File.dirname(__FILE__) + "/config/arvados-clients.yml\n file"
49 gitolite_url = cp_config['gitolite_url']
50 gitolite_arvados_git_user_key = cp_config['gitolite_arvados_git_user_key']
52 gitolite_tmpdir = File.join(File.absolute_path(File.dirname(__FILE__)),
53 cp_config['gitolite_tmp'])
54 gitolite_admin = File.join(gitolite_tmpdir, 'gitolite-admin')
55 gitolite_keydir = File.join(gitolite_admin, 'keydir', 'arvados')
57 ENV['ARVADOS_API_HOST'] = cp_config['arvados_api_host']
58 ENV['ARVADOS_API_TOKEN'] = cp_config['arvados_api_token']
59 if cp_config['arvados_api_host_insecure']
60 ENV['ARVADOS_API_HOST_INSECURE'] = 'true'
62 ENV.delete('ARVADOS_API_HOST_INSECURE')
65 def ensure_directory(path, mode)
72 def replace_file(path, contents)
74 dirname, basename = File.split(path)
75 new_file = Tempfile.new([basename, ".tmp"], dirname)
77 new_file.write(contents)
79 File.rename(new_file, path)
82 new_file.close(unlink_now)
86 def file_has_contents?(path, contents)
88 IO.read(path) == contents
94 module TrackCommitState
96 # Note that all classes that include TrackCommitState will have
97 # @@need_commit = true if any of them set it. Since this flag reports
98 # a boolean state of the underlying git repository, that's OK in the
99 # current implementation.
100 @@need_commit = false
106 def ensure_in_git(path, contents)
107 unless file_has_contents?(path, contents)
108 replace_file(path, contents)
109 system("git", "add", path)
115 def ensure_in_git(path, contents)
116 self.class.ensure_in_git(path, contents)
119 def self.included(base)
120 base.extend(ClassMethods)
125 include TrackCommitState
129 def initialize(arv_repo)
133 def self.ensure_system_config(conf_root)
134 ensure_in_git(File.join(conf_root, "arvadosaliases.pl"), alias_config)
137 def self.rename_repos(repos_root)
138 @@aliases.each_pair do |uuid, name|
140 File.rename(File.join(repos_root, "#{name}.git/"),
141 File.join(repos_root, "#{uuid}.git"))
145 Dir.chdir(repos_root) { File.symlink("#{uuid}.git/", "arvados.git") }
150 def ensure_config(conf_root)
152 @@aliases[uuid] = name
153 name_conf_path = auto_conf_path(conf_root, name)
154 return unless File.exist?(name_conf_path)
155 conf_file = IO.read(name_conf_path)
156 conf_file.gsub!(/^repo #{Regexp.escape(name)}$/m, "repo #{uuid}")
157 ensure_in_git(auto_conf_path(conf_root, uuid), conf_file)
158 File.unlink(name_conf_path)
159 system("git", "rm", "--quiet", name_conf_path)
164 def auto_conf_path(conf_root, basename)
165 File.join(conf_root, "conf", "auto", "#{basename}.conf")
173 if @arv_repo[:name].nil?
177 @arv_repo[:name].sub(/^[^A-Za-z]+/, "").gsub(/[^\w\.\/]/, "")
181 def self.alias_config
183 @@aliases.sort.each do |(repo_name, repo_uuid)|
184 conf_s += "\t'#{repo_name}' \t=> '#{repo_uuid}',\n"
192 # Get our local gitolite-admin repo up to snuff
193 if not File.exist?(gitolite_admin) then
194 ensure_directory(gitolite_tmpdir, 0700)
195 Dir.chdir(gitolite_tmpdir)
196 `git clone #{gitolite_url}`
197 Dir.chdir(gitolite_admin)
199 Dir.chdir(gitolite_admin)
204 permissions = arv.repository.get_all_permissions
206 permissions[:repositories].each do |repo_record|
207 repo = Repository.new(repo_record)
208 repo.ensure_config(gitolite_admin)
210 Repository.ensure_system_config(gitolite_admin)
212 message = "#{Time.now().to_s}: migrate to storing repositories by UUID"
213 Dir.chdir(gitolite_admin)
215 `git commit -m '#{message}'`
216 Repository.rename_repos(REPOS_DIR)
220 puts "Error: " + bang.to_s
221 puts bang.backtrace.join("\n")