X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/e51a22dc5b9da795b68c87cb9d0a45e4732ed2f6..da5858d5f794c14cf00b830166bb34b1bcd79ba5:/services/api/script/arvados-git-sync.rb diff --git a/services/api/script/arvados-git-sync.rb b/services/api/script/arvados-git-sync.rb deleted file mode 100755 index 3a8ed2724f..0000000000 --- a/services/api/script/arvados-git-sync.rb +++ /dev/null @@ -1,266 +0,0 @@ -#!/usr/bin/env ruby - -require 'rubygems' -require 'pp' -require 'arvados' -require 'tempfile' -require 'yaml' -require 'fileutils' - -# This script does the actual gitolite config management on disk. -# -# Ward Vandewege - -# Default is development -production = ARGV[0] == "production" - -ENV["RAILS_ENV"] = "development" -ENV["RAILS_ENV"] = "production" if production - -DEBUG = 1 - -# load and merge in the environment-specific application config info -# if present, overriding base config parameters as specified -path = File.absolute_path('../../config/arvados-clients.yml', __FILE__) -if File.exists?(path) then - cp_config = YAML.load_file(path)[ENV['RAILS_ENV']] -else - puts "Please create a\n #{path}\n file" - exit 1 -end - -gitolite_url = cp_config['gitolite_url'] -gitolite_arvados_git_user_key = cp_config['gitolite_arvados_git_user_key'] - -gitolite_tmpdir = cp_config['gitolite_tmp'] -gitolite_admin = File.join(gitolite_tmpdir, 'gitolite-admin') -gitolite_admin_keydir = File.join(gitolite_admin, 'keydir') -gitolite_keydir = File.join(gitolite_admin, 'keydir', 'arvados') - -ENV['ARVADOS_API_HOST'] = cp_config['arvados_api_host'] -ENV['ARVADOS_API_TOKEN'] = cp_config['arvados_api_token'] -if cp_config['arvados_api_host_insecure'] - ENV['ARVADOS_API_HOST_INSECURE'] = 'true' -else - ENV.delete('ARVADOS_API_HOST_INSECURE') -end - -def ensure_directory(path, mode) - begin - Dir.mkdir(path, mode) - rescue Errno::EEXIST - end -end - -def replace_file(path, contents) - unlink_now = true - dirname, basename = File.split(path) - FileUtils.mkpath(dirname) - new_file = Tempfile.new([basename, ".tmp"], dirname) - begin - new_file.write(contents) - new_file.flush - File.rename(new_file, path) - unlink_now = false - ensure - new_file.close(unlink_now) - end -end - -def file_has_contents?(path, contents) - begin - IO.read(path) == contents - rescue Errno::ENOENT - false - end -end - -module TrackCommitState - module ClassMethods - # Note that all classes that include TrackCommitState will have - # @@need_commit = true if any of them set it. Since this flag reports - # a boolean state of the underlying git repository, that's OK in the - # current implementation. - @@need_commit = false - - def changed? - @@need_commit - end - - def ensure_in_git(path, contents) - unless file_has_contents?(path, contents) - replace_file(path, contents) - system("git", "add", path) - @@need_commit = true - end - end - end - - def ensure_in_git(path, contents) - self.class.ensure_in_git(path, contents) - end - - def self.included(base) - base.extend(ClassMethods) - end -end - -class UserSSHKeys - include TrackCommitState - - def initialize(user_keys_map, key_dir) - @user_keys_map = user_keys_map - @key_dir = key_dir - @installed = {} - end - - def install(filename, pubkey) - unless pubkey.nil? - key_path = File.join(@key_dir, filename) - ensure_in_git(key_path, pubkey) - end - @installed[filename] = true - end - - def ensure_keys_for_user(user_uuid) - return unless key_list = @user_keys_map.delete(user_uuid) - key_list.map { |k| k[:public_key] }.compact.each_with_index do |pubkey, ii| - # Handle putty-style ssh public keys - pubkey.sub!(/^(Comment: "r[^\n]*\n)(.*)$/m,'ssh-rsa \2 \1') - pubkey.sub!(/^(Comment: "d[^\n]*\n)(.*)$/m,'ssh-dss \2 \1') - pubkey.gsub!(/\n/,'') - pubkey.strip! - install("#{user_uuid}@#{ii}.pub", pubkey) - end - end - - def installed?(filename) - @installed[filename] - end -end - -class Repository - include TrackCommitState - - @@aliases = {} - - def initialize(arv_repo, user_keys) - @arv_repo = arv_repo - @user_keys = user_keys - end - - def self.ensure_system_config(conf_root) - ensure_in_git(File.join(conf_root, "conf", "gitolite.conf"), - %Q{include "auto/*.conf"\ninclude "admin/*.conf"\n}) - ensure_in_git(File.join(conf_root, "arvadosaliases.pl"), alias_config) - - conf_path = File.join(conf_root, "conf", "admin", "arvados.conf") - conf_file = %Q{ -@arvados_git_user = arvados_git_user - -repo gitolite-admin - RW = @arvados_git_user - -} - ensure_directory(File.dirname(conf_path), 0755) - ensure_in_git(conf_path, conf_file) - end - - def ensure_config(conf_root) - if name and (File.exist?(auto_conf_path(conf_root, name))) - # This gitolite installation knows the repository by name, rather than - # UUID. Leave it configured that way until a separate migration is run. - basename = name - else - basename = uuid - @@aliases[name] = uuid unless name.nil? - end - conf_file = "\nrepo #{basename}\n" - @arv_repo[:user_permissions].sort.each do |user_uuid, perm| - conf_file += "\t#{perm[:gitolite_permissions]}\t= #{user_uuid}\n" - @user_keys.ensure_keys_for_user(user_uuid) - end - ensure_in_git(auto_conf_path(conf_root, basename), conf_file) - end - - private - - def auto_conf_path(conf_root, basename) - File.join(conf_root, "conf", "auto", "#{basename}.conf") - end - - def uuid - @arv_repo[:uuid] - end - - def name - if @arv_repo[:name].nil? - nil - else - @clean_name ||= - @arv_repo[:name].sub(/^[^A-Za-z]+/, "").gsub(/[^\w\.\/]/, "") - end - end - - def self.alias_config - conf_s = "{\n" - @@aliases.sort.each do |(repo_name, repo_uuid)| - conf_s += "\t'#{repo_name}' \t=> '#{repo_uuid}',\n" - end - conf_s += "};\n" - conf_s - end -end - -begin - # Get our local gitolite-admin repo up to snuff - if not File.exists?(gitolite_admin) then - ensure_directory(gitolite_tmpdir, 0700) - Dir.chdir(gitolite_tmpdir) - `git clone #{gitolite_url}` - Dir.chdir(gitolite_admin) - else - Dir.chdir(gitolite_admin) - `git pull` - end - - arv = Arvados.new - permissions = arv.repository.get_all_permissions - - ensure_directory(gitolite_keydir, 0700) - admin_user_ssh_keys = UserSSHKeys.new(permissions[:user_keys], gitolite_admin_keydir) - # Make sure the arvados_git_user key is installed; put it in gitolite_admin_keydir - # because that is where gitolite will try to put it if we do not. - admin_user_ssh_keys.install('arvados_git_user.pub', gitolite_arvados_git_user_key) - - user_ssh_keys = UserSSHKeys.new(permissions[:user_keys], gitolite_keydir) - permissions[:repositories].each do |repo_record| - repo = Repository.new(repo_record, user_ssh_keys) - repo.ensure_config(gitolite_admin) - end - Repository.ensure_system_config(gitolite_admin) - - # Clean up public key files that should not be present - Dir.chdir(gitolite_keydir) - stale_keys = Dir.glob('*.pub').reject do |key_file| - user_ssh_keys.installed?(key_file) - end - if stale_keys.any? - stale_keys.each { |key_file| puts "Extra file #{key_file}" } - system("git", "rm", "--quiet", *stale_keys) - end - - if UserSSHKeys.changed? or Repository.changed? or stale_keys.any? - message = "#{Time.now().to_s}: update from API" - Dir.chdir(gitolite_admin) - `git add --all` - `git commit -m '#{message}'` - `git push` - end - -rescue => bang - puts "Error: " + bang.to_s - puts bang.backtrace.join("\n") - exit 1 -end -