diff options
author | Ash McKenzie <amckenzie@gitlab.com> | 2018-07-25 14:15:07 +1000 |
---|---|---|
committer | Ash McKenzie <amckenzie@gitlab.com> | 2018-07-25 14:34:21 +1000 |
commit | e7a4f669e54bc097ab0ba5bcb9032a9c30978514 (patch) | |
tree | a40b531e737d0c91dbe7a60d30db8c7161e558c9 | |
parent | 634a519a38784372f729b51e006f260f7143531d (diff) | |
download | gitlab-shell-e7a4f669e54bc097ab0ba5bcb9032a9c30978514.tar.gz |
New Action module and Action::Gitaly class
-rw-r--r-- | lib/action.rb | 5 | ||||
-rw-r--r-- | lib/action/base.rb | 21 | ||||
-rw-r--r-- | lib/action/gitaly.rb | 129 |
3 files changed, 155 insertions, 0 deletions
diff --git a/lib/action.rb b/lib/action.rb new file mode 100644 index 0000000..cb76372 --- /dev/null +++ b/lib/action.rb @@ -0,0 +1,5 @@ +require_relative 'action/base' +require_relative 'action/gitaly' + +module Action +end diff --git a/lib/action/base.rb b/lib/action/base.rb new file mode 100644 index 0000000..5e5a2b2 --- /dev/null +++ b/lib/action/base.rb @@ -0,0 +1,21 @@ +require 'json' +require_relative '../gitlab_config' +require_relative '../current_user_helper' + +module Action + class Base + include CurrentUserHelper + + def self.create_from_json(_) + raise NotImplementedError + end + + def config + @config ||= GitlabConfig.new + end + + private + + attr_reader :key_id + end +end diff --git a/lib/action/gitaly.rb b/lib/action/gitaly.rb new file mode 100644 index 0000000..a87583b --- /dev/null +++ b/lib/action/gitaly.rb @@ -0,0 +1,129 @@ +require_relative 'base' +require_relative '../gitlab_logger' +require_relative '../gitlab_net' +require_relative '../log_helper' + +module Action + class Gitaly < Base + include LogHelper + + MIGRATED_COMMANDS = { + 'git-upload-pack' => File.join(ROOT_PATH, 'bin', 'gitaly-upload-pack'), + 'git-upload-archive' => File.join(ROOT_PATH, 'bin', 'gitaly-upload-archive'), + 'git-receive-pack' => File.join(ROOT_PATH, 'bin', 'gitaly-receive-pack') + }.freeze + + def initialize(key_id, gl_repository, gl_username, repository_path, gitaly) + @key_id = key_id + @gl_repository = gl_repository + @gl_username = gl_username + @repository_path = repository_path + @gitaly = gitaly + + self.repo_path = repository_path # FIXME: WTF IS THIS? + end + + def self.create_from_json(key_id, json) + values = JSON.parse(json) + new(key_id, + values["gl_repository"], + values["gl_username"], + values["repository_path"], + values["gitaly"]) + end + + def execute(command, args) + process(command, args) + end + + private + + attr_reader :gl_repository, :gl_username, :repository_path, :gitaly, :repo_path + + # FIXME: WTF IS THIS? + def repo_path=(repo_path) + raise ArgumentError, "Repository path not provided. Please make sure you're using GitLab v8.10 or later." unless repo_path + raise InvalidRepositoryPathError if File.absolute_path(repo_path) != repo_path + + @repo_path = repo_path + end + + def process(command, args) + executable = command + args = [repo_path] + + if MIGRATED_COMMANDS.key?(executable) && gitaly + executable = MIGRATED_COMMANDS[executable] + gitaly_address = gitaly['address'] + + # The entire gitaly_request hash should be built in gitlab-ce and passed + # on as-is. For now we build a fake one on the spot. + gitaly_request = { + 'repository' => gitaly['repository'], + 'gl_repository' => gl_repository, + 'gl_id' => key_id, + 'gl_username' => gl_username + } + + args = [gitaly_address, JSON.dump(gitaly_request)] + end + + args_string = [File.basename(executable), *args].join(' ') + $logger.info('executing git command', command: args_string, user: log_username) + + exec_cmd(executable, *args) + end + + def exec_cmd(*args) + # If you want to call a command without arguments, use + # exec_cmd(['my_command', 'my_command']) . Otherwise use + # exec_cmd('my_command', 'my_argument', ...). + if args.count == 1 && !args.first.is_a?(Array) + raise GitlabShell::DisallowedCommandError + end + + env = { + 'HOME' => ENV['HOME'], + 'PATH' => ENV['PATH'], + 'LD_LIBRARY_PATH' => ENV['LD_LIBRARY_PATH'], + 'LANG' => ENV['LANG'], + 'GL_ID' => key_id, + 'GL_PROTOCOL' => GitlabNet::GL_PROTOCOL, + 'GL_REPOSITORY' => gl_repository, + 'GL_USERNAME' => gl_username + } + + if gitaly && gitaly.include?('token') + env['GITALY_TOKEN'] = gitaly['token'] + end + + if git_trace_available? + env.merge!( + 'GIT_TRACE' => config.git_trace_log_file, + 'GIT_TRACE_PACKET' => config.git_trace_log_file, + 'GIT_TRACE_PERFORMANCE' => config.git_trace_log_file + ) + end + + # We use 'chdir: ROOT_PATH' to let the next executable know where config.yml is. + Kernel.exec(env, *args, unsetenv_others: true, chdir: ROOT_PATH) + end + + def git_trace_available? + return false unless config.git_trace_log_file + + if Pathname(config.git_trace_log_file).relative? + $logger.warn('git trace log path must be absolute, ignoring', git_trace_log_file: config.git_trace_log_file) + return false + end + + begin + File.open(config.git_trace_log_file, 'a') { nil } + return true + rescue => ex + $logger.warn('Failed to open git trace log file', git_trace_log_file: config.git_trace_log_file, error: ex.to_s) + return false + end + end + end +end |