diff options
author | John Cai <jcai@gitlab.com> | 2020-04-14 08:31:59 +0300 |
---|---|---|
committer | John Cai <jcai@gitlab.com> | 2020-04-14 09:01:13 +0300 |
commit | 1c5e0a2f9a93cb90bfe59e67504909427b842cce (patch) | |
tree | 5ff7076b19cea186c7c5afeaa142f9e51e860550 | |
parent | 88859ee2bf2e20846f54cecde36376bc471a2aa9 (diff) |
Add gitlabshell config values to gitaly tomljc-add-gitlabshell-config-to-gitaly-config
-rw-r--r-- | cmd/gitaly-hooks/hooks.go | 7 | ||||
-rw-r--r-- | cmd/gitaly-hooks/hooks_test.go | 5 | ||||
-rw-r--r-- | internal/config/config.go | 20 | ||||
-rw-r--r-- | internal/git/receivepack.go | 6 | ||||
-rw-r--r-- | internal/gitlabshell/env.go | 41 | ||||
-rw-r--r-- | internal/gitlabshell/env_test.go | 21 | ||||
-rw-r--r-- | internal/rubyserver/rubyserver.go | 8 | ||||
-rw-r--r-- | internal/service/hooks/post_receive.go | 7 | ||||
-rw-r--r-- | internal/service/hooks/pre_receive.go | 16 | ||||
-rw-r--r-- | internal/service/hooks/update.go | 7 | ||||
-rw-r--r-- | internal/testhelper/testserver.go | 8 | ||||
-rw-r--r-- | ruby/gitlab-shell/lib/gitlab_config.rb | 48 | ||||
-rw-r--r-- | ruby/gitlab-shell/lib/http_helper.rb | 5 | ||||
-rw-r--r-- | ruby/gitlab-shell/spec/gitlab_config_spec.rb | 8 |
14 files changed, 162 insertions, 45 deletions
diff --git a/cmd/gitaly-hooks/hooks.go b/cmd/gitaly-hooks/hooks.go index 552b9a663..3877148ac 100644 --- a/cmd/gitaly-hooks/hooks.go +++ b/cmd/gitaly-hooks/hooks.go @@ -256,7 +256,12 @@ func check(configPath string) (int, error) { cmd := exec.Command(filepath.Join(c.GitlabShell.Dir, "bin", "check")) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr - cmd.Env = append(os.Environ(), gitlabshell.EnvFromConfig(c)...) + + gitlabshellEnv, err := gitlabshell.EnvFromConfig(c) + if err != nil { + return 1, err + } + cmd.Env = append(os.Environ(), gitlabshellEnv...) if err = cmd.Run(); err != nil { if status, ok := command.ExitStatus(err); ok { diff --git a/cmd/gitaly-hooks/hooks_test.go b/cmd/gitaly-hooks/hooks_test.go index 152da93fd..96f60dad0 100644 --- a/cmd/gitaly-hooks/hooks_test.go +++ b/cmd/gitaly-hooks/hooks_test.go @@ -426,7 +426,7 @@ func TestCheckOK(t *testing.T) { testhelper.WriteShellSecretFile(t, gitlabShellDir, "the secret") testhelper.WriteTemporaryGitlabShellConfigFile(t, gitlabShellDir, testhelper.GitlabShellConfig{GitlabURL: ts.URL, HTTPSettings: testhelper.HTTPSettings{User: user, Password: password}}) - configPath, cleanup := testhelper.WriteTemporaryGitalyConfigFile(t, tempDir) + configPath, cleanup := testhelper.WriteTemporaryGitalyConfigFile(t, tempDir, ts.URL, user, password) defer cleanup() cmd := exec.Command(fmt.Sprintf("%s/gitaly-hooks", config.Config.BinDir), "check", configPath) @@ -436,6 +436,7 @@ func TestCheckOK(t *testing.T) { cmd.Stdout = &stdout require.NoError(t, cmd.Run()) + require.Empty(t, stderr.String()) expectedCheckOutput := "Check GitLab API access: OK\nRedis available via internal API: OK\n" require.Equal(t, expectedCheckOutput, stdout.String()) @@ -474,7 +475,7 @@ func TestCheckBadCreds(t *testing.T) { testhelper.WriteTemporaryGitlabShellConfigFile(t, gitlabShellDir, testhelper.GitlabShellConfig{GitlabURL: ts.URL, HTTPSettings: testhelper.HTTPSettings{User: user + "wrong", Password: password}}) testhelper.WriteShellSecretFile(t, gitlabShellDir, "the secret") - configPath, cleanup := testhelper.WriteTemporaryGitalyConfigFile(t, tempDir) + configPath, cleanup := testhelper.WriteTemporaryGitalyConfigFile(t, tempDir, ts.URL, user+"wrong", password) defer cleanup() cmd := exec.Command(fmt.Sprintf("%s/gitaly-hooks", config.Config.BinDir), "check", configPath) diff --git a/internal/config/config.go b/internal/config/config.go index 0f041f2a9..a528fee70 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -58,14 +58,26 @@ type TLS struct { // GitlabShell contains the settings required for executing `gitlab-shell` type GitlabShell struct { - Dir string `toml:"dir"` + CustomHooksDir string `toml:"custom_hooks_dir"` + Dir string `toml:"dir"` + GitlabURL string `toml:"gitlab_url"` + HTTPSettings HTTPSettings `toml:"http-settings"` + SecretFile string `toml:"secret_file"` +} + +type HTTPSettings struct { + ReadTimeout int `toml:"read_timeout" json:"read_timeout"` + User string `toml:"user" json:"user"` + Password string `toml:"password" json:"password"` + CAFile string `toml:"ca_file" json:"ca_file"` + CAPath string `toml:"ca_path" json:"ca_path"` + SelfSigned bool `toml:"self_signed_cert" json:"self_signed_cert"` } // Git contains the settings for the Git executable type Git struct { - BinPath string `toml:"bin_path"` - - CatfileCacheSize int `toml:"catfile_cache_size"` + BinPath string `toml:"bin_path"` + CatfileCacheSize int `toml:"catfile_cache_size"` } // Storage contains a single storage-shard diff --git a/internal/git/receivepack.go b/internal/git/receivepack.go index b321a83b1..b8bf83582 100644 --- a/internal/git/receivepack.go +++ b/internal/git/receivepack.go @@ -29,13 +29,17 @@ func HookEnv(req ReceivePackRequest) ([]string, error) { return nil, err } + gitlabshellEnv, err := gitlabshell.Env() + if err != nil { + return nil, err + } return append([]string{ fmt.Sprintf("GL_ID=%s", req.GetGlId()), fmt.Sprintf("GL_USERNAME=%s", req.GetGlUsername()), fmt.Sprintf("GL_REPOSITORY=%s", req.GetGlRepository()), fmt.Sprintf("GITALY_SOCKET=" + config.GitalyInternalSocketPath()), fmt.Sprintf("GITALY_REPO=%s", repo), - }, gitlabshell.Env()...), nil + }, gitlabshellEnv...), nil } // ReceivePackConfig contains config options we want to enforce when diff --git a/internal/gitlabshell/env.go b/internal/gitlabshell/env.go index 4db3c4fd0..f3919e343 100644 --- a/internal/gitlabshell/env.go +++ b/internal/gitlabshell/env.go @@ -1,25 +1,52 @@ package gitlabshell import ( + "encoding/json" + "fmt" + "gitlab.com/gitlab-org/gitaly/internal/config" ) // Env is a helper that returns a slice with environment variables used by gitlab shell -func Env() []string { +func Env() ([]string, error) { cfg := config.Config return EnvFromConfig(cfg) } // EnvFromConfig returns a set of environment variables from a config struct relevant to gitlab shell -func EnvFromConfig(cfg config.Cfg) []string { +func EnvFromConfig(cfg config.Cfg) ([]string, error) { + gitlabShellConfig := Config{ + CustomHooksDir: cfg.GitlabShell.CustomHooksDir, + GitlabURL: cfg.GitlabShell.GitlabURL, + HTTPSettings: cfg.GitlabShell.HTTPSettings, + LogFormat: cfg.Logging.Format, + LogLevel: cfg.Logging.Level, + LogPath: cfg.Logging.Dir, + RootPath: cfg.GitlabShell.Dir, //GITLAB_SHELL_DIR has been deprecated + SecretFile: cfg.GitlabShell.SecretFile, + } + + gitlabShellConfigString, err := json.Marshal(&gitlabShellConfig) + if err != nil { + return nil, err + } + return []string{ "GITALY_GITLAB_SHELL_DIR=" + cfg.GitlabShell.Dir, - "GITALY_LOG_DIR=" + cfg.Logging.Dir, - "GITALY_LOG_FORMAT=" + cfg.Logging.Format, - "GITALY_LOG_LEVEL=" + cfg.Logging.Level, - "GITLAB_SHELL_DIR=" + cfg.GitlabShell.Dir, //GITLAB_SHELL_DIR has been deprecated "GITALY_BIN_DIR=" + cfg.BinDir, "GITALY_RUBY_DIR=" + cfg.Ruby.Dir, - } + fmt.Sprintf("GITALY_GITLAB_SHELL_CONFIG=%s", gitlabShellConfigString), + }, nil +} + +type Config struct { + CustomHooksDir string `json:"custom_hooks_dir"` + GitlabURL string `json:"gitlab_url"` + HTTPSettings config.HTTPSettings `json:"http_settings"` + LogFormat string `json:"log_format"` + LogLevel string `json:"log_level"` + LogPath string `json:"log_path"` + RootPath string `json:"root_path"` + SecretFile string `json:"secret_file"` } diff --git a/internal/gitlabshell/env_test.go b/internal/gitlabshell/env_test.go index 809a436c2..aad9699ce 100644 --- a/internal/gitlabshell/env_test.go +++ b/internal/gitlabshell/env_test.go @@ -30,13 +30,18 @@ func TestGitHooksConfig(t *testing.T) { config.Config.Logging.Level = "fatal" config.Config.Logging.Format = "my-custom-format" config.Config.GitlabShell.Dir = "../../ruby/gitlab-shell" + config.Config.GitlabShell.SecretFile = "secret_file.very_secret" + config.Config.GitlabShell.CustomHooksDir = "custom_hooks_directory/is/here" + config.Config.GitlabShell.GitlabURL = "http://localhost:1234" dumpConfigPath := filepath.Join(config.Config.Ruby.Dir, "gitlab-shell", "bin", "dump-config") var stdout bytes.Buffer cmd := exec.Command(dumpConfigPath) - cmd.Env = append(os.Environ(), gitlabshell.Env()...) + gitlabshellEnv, err := gitlabshell.Env() + require.NoError(t, err) + cmd.Env = append(os.Environ(), gitlabshellEnv...) cmd.Stdout = &stdout require.NoError(t, cmd.Run()) @@ -46,6 +51,20 @@ func TestGitHooksConfig(t *testing.T) { require.NoError(t, json.NewDecoder(&stdout).Decode(&rubyConfigMap)) require.Equal(t, config.Config.Logging.Level, rubyConfigMap["log_level"]) require.Equal(t, config.Config.Logging.Format, rubyConfigMap["log_format"]) + require.Equal(t, config.Config.GitlabShell.SecretFile, rubyConfigMap["secret_file"]) + require.Equal(t, config.Config.GitlabShell.CustomHooksDir, rubyConfigMap["custom_hooks_dir"]) + require.Equal(t, config.Config.GitlabShell.GitlabURL, rubyConfigMap["gitlab_url"]) + require.Equal(t, config.Config.GitlabShell.SecretFile, rubyConfigMap["secret_file"]) + + // HTTP Settings + httpSettings, ok := rubyConfigMap["http_settings"].(map[string]interface{}) + require.True(t, ok) + require.Equal(t, float64(config.Config.GitlabShell.HTTPSettings.ReadTimeout), httpSettings["read_timeout"]) + require.Equal(t, config.Config.GitlabShell.HTTPSettings.User, httpSettings["user"]) + require.Equal(t, config.Config.GitlabShell.HTTPSettings.Password, httpSettings["password"]) + require.Equal(t, config.Config.GitlabShell.HTTPSettings.CAFile, httpSettings["ca_file"]) + require.Equal(t, config.Config.GitlabShell.HTTPSettings.CAPath, httpSettings["ca_path"]) + require.Equal(t, config.Config.GitlabShell.HTTPSettings.SelfSigned, httpSettings["self_signed_cert"]) dir := filepath.Dir(rubyConfigMap["log_file"].(string)) require.Equal(t, config.Config.Logging.Dir, dir) diff --git a/internal/rubyserver/rubyserver.go b/internal/rubyserver/rubyserver.go index d3e8863f8..967d8a19f 100644 --- a/internal/rubyserver/rubyserver.go +++ b/internal/rubyserver/rubyserver.go @@ -87,6 +87,12 @@ func (s *Server) start() error { } cfg := config.Config + + gitlabshellEnv, err := gitlabshell.Env() + if err != nil { + return err + } + env := append( os.Environ(), "GITALY_RUBY_GIT_BIN_PATH="+command.GitPath(), @@ -97,7 +103,7 @@ func (s *Server) start() error { "GITALY_VERSION="+version.GetVersion(), "GITALY_GIT_HOOKS_DIR="+hooks.Path(), "GITALY_RUGGED_GIT_CONFIG_SEARCH_PATH="+cfg.Ruby.RuggedGitConfigSearchPath) - env = append(env, gitlabshell.Env()...) + env = append(env, gitlabshellEnv...) env = append(env, command.GitEnv...) diff --git a/internal/service/hooks/post_receive.go b/internal/service/hooks/post_receive.go index f4e312d08..9385df70d 100644 --- a/internal/service/hooks/post_receive.go +++ b/internal/service/hooks/post_receive.go @@ -20,7 +20,10 @@ func (s *server) PostReceiveHook(stream gitalypb.HookService_PostReceiveHookServ return helper.ErrInvalidArgument(err) } - hookEnv := append(hookRequestEnv(firstRequest), hooks.GitPushOptions(firstRequest.GetGitPushOptions())...) + hookEnv, err := hookRequestEnv(firstRequest) + if err != nil { + return helper.ErrInternal(err) + } stdin := streamio.NewReader(func() ([]byte, error) { req, err := stream.Recv() @@ -42,7 +45,7 @@ func (s *server) PostReceiveHook(stream gitalypb.HookService_PostReceiveHookServ stdin, stdout, stderr, c, - hookEnv, + append(hookEnv, hooks.GitPushOptions(firstRequest.GetGitPushOptions())...), ) if err != nil { diff --git a/internal/service/hooks/pre_receive.go b/internal/service/hooks/pre_receive.go index 0564bb71c..a8261115f 100644 --- a/internal/service/hooks/pre_receive.go +++ b/internal/service/hooks/pre_receive.go @@ -18,8 +18,12 @@ type hookRequest interface { GetRepository() *gitalypb.Repository } -func hookRequestEnv(req hookRequest) []string { - return append(gitlabshell.Env(), req.GetEnvironmentVariables()...) +func hookRequestEnv(req hookRequest) ([]string, error) { + gitlabshellEnv, err := gitlabshell.Env() + if err != nil { + return nil, err + } + return append(gitlabshellEnv, req.GetEnvironmentVariables()...), nil } func preReceiveEnv(req hookRequest) ([]string, error) { @@ -27,7 +31,13 @@ func preReceiveEnv(req hookRequest) ([]string, error) { if err != nil { return nil, err } - return append(hookRequestEnv(req), env...), nil + + hookEnv, err := hookRequestEnv(req) + if err != nil { + return nil, err + } + + return append(hookEnv, env...), nil } func gitlabShellHook(hookName string) string { diff --git a/internal/service/hooks/update.go b/internal/service/hooks/update.go index c980dd92f..626f02ec9 100644 --- a/internal/service/hooks/update.go +++ b/internal/service/hooks/update.go @@ -25,12 +25,17 @@ func (s *server) UpdateHook(in *gitalypb.UpdateHookRequest, stream gitalypb.Hook c := exec.Command(gitlabShellHook("update"), string(in.GetRef()), in.GetOldValue(), in.GetNewValue()) c.Dir = repoPath + updateEnv, err := hookRequestEnv(in) + if err != nil { + return helper.ErrInternal(err) + } + status, err := streamCommandResponse( stream.Context(), nil, stdout, stderr, c, - hookRequestEnv(in), + updateEnv, ) if err != nil { diff --git a/internal/testhelper/testserver.go b/internal/testhelper/testserver.go index 11ca87255..128a82bb0 100644 --- a/internal/testhelper/testserver.go +++ b/internal/testhelper/testserver.go @@ -446,12 +446,16 @@ func WriteTemporaryGitlabShellConfigFile(t TB, dir string, config GitlabShellCon // WriteTemporaryGitalyConfigFile writes a gitaly toml file into a temporary directory. It returns the path to // the file as well as a cleanup function -func WriteTemporaryGitalyConfigFile(t TB, tempDir string) (string, func()) { +func WriteTemporaryGitalyConfigFile(t TB, tempDir, gitlabURL, user, password string) (string, func()) { path := filepath.Join(tempDir, "config.toml") contents := fmt.Sprintf(` [gitlab-shell] dir = "%s/gitlab-shell" -`, tempDir) + gitlab_url = "%s" + [gitlab-shell.http-settings] + user = "%s" + password = "%s" +`, tempDir, gitlabURL, user, password) require.NoError(t, ioutil.WriteFile(path, []byte(contents), 0644)) return path, func() { diff --git a/ruby/gitlab-shell/lib/gitlab_config.rb b/ruby/gitlab-shell/lib/gitlab_config.rb index 19f03c346..0d4963c7c 100644 --- a/ruby/gitlab-shell/lib/gitlab_config.rb +++ b/ruby/gitlab-shell/lib/gitlab_config.rb @@ -1,45 +1,50 @@ require 'yaml' +require 'json' class GitlabConfig def secret_file - fetch_from_legacy_config('secret_file',File.join(ROOT_PATH, '.gitlab_shell_secret')) + fetch_from_config('secret_file', fetch_from_legacy_config('secret_file', File.join(ROOT_PATH, '.gitlab_shell_secret'))) end # Pass a default value because this is called from a repo's context; in which # case, the repo's hooks directory should be the default. # def custom_hooks_dir(default: nil) - fetch_from_legacy_config('custom_hooks_dir', File.join(ROOT_PATH, 'hooks')) + fetch_from_config('custom_hooks_dir', fetch_from_legacy_config('custom_hooks_dir', File.join(ROOT_PATH, 'hooks'))) end def gitlab_url - fetch_from_legacy_config('gitlab_url',"http://localhost:8080").sub(%r{/*$}, '') + fetch_from_config('gitlab_url', fetch_from_legacy_config('gitlab_url',"http://localhost:8080").sub(%r{/*$}, '')) end def http_settings - fetch_from_legacy_config('http_settings', {}) + fetch_from_config('http_settings', fetch_from_legacy_config('http_settings', {})) end def log_file - return File.join(LOG_PATH, 'gitlab-shell.log') unless LOG_PATH.empty? + log_path = fetch_from_config('log_path', LOG_PATH) - fetch_from_legacy_config('log_file', File.join(ROOT_PATH, 'gitlab-shell.log')) + return File.join(log_path, 'gitlab-shell.log') unless log_path.empty? + + File.join(ROOT_PATH, 'gitlab-shell.log') end def log_level - return LOG_LEVEL unless LOG_LEVEL.empty? + log_level = fetch_from_config('log_level', LOG_LEVEL) + + log_level = LOG_LEVEL if log_level.empty? + + return log_level unless log_level.empty? - fetch_from_legacy_config('log_level', 'INFO') + 'INFO' end def log_format - return LOG_FORMAT unless LOG_FORMAT.empty? + log_format = fetch_from_config('log_format', LOG_FORMAT) - fetch_from_legacy_config('log_format', 'text') - end + return log_format unless log_format.empty? - def metrics_log_file - fetch_from_legacy_config('metrics_log_file', File.join(ROOT_PATH, 'gitlab-shell-metrics.log')) + 'text' end def to_json @@ -51,7 +56,6 @@ class GitlabConfig log_file: log_file, log_level: log_level, log_format: log_format, - metrics_log_file: metrics_log_file }.to_json end @@ -61,8 +65,22 @@ class GitlabConfig private + def fetch_from_config(key, default='') + value = config[key] + return value unless value.nil? || value.empty? + + default + end + + def config + @config ||= JSON.parse(ENV.fetch('GITALY_GITLAB_SHELL_CONFIG', '{}')) + end + def legacy_config # TODO: deprecate @legacy_config that is parsing the gitlab-shell config.yml - @legacy_config ||= YAML.load_file(File.join(ROOT_PATH, 'config.yml')) + legacy_file = File.join(ROOT_PATH, 'config.yml') + return {} unless File.exist?(legacy_file) + + @legacy_config ||= YAML.load_file(legacy_file) end end diff --git a/ruby/gitlab-shell/lib/http_helper.rb b/ruby/gitlab-shell/lib/http_helper.rb index c6a4bb845..5cadb6196 100644 --- a/ruby/gitlab-shell/lib/http_helper.rb +++ b/ruby/gitlab-shell/lib/http_helper.rb @@ -120,6 +120,9 @@ module HTTPHelper end def read_timeout - config.http_settings['read_timeout'] || READ_TIMEOUT + read_timeout = config.http_settings['read_timeout'] + return read_timeout unless read_timeout == 0 + + READ_TIMEOUT end end diff --git a/ruby/gitlab-shell/spec/gitlab_config_spec.rb b/ruby/gitlab-shell/spec/gitlab_config_spec.rb index 6de0cd08e..6114bda31 100644 --- a/ruby/gitlab-shell/spec/gitlab_config_spec.rb +++ b/ruby/gitlab-shell/spec/gitlab_config_spec.rb @@ -24,11 +24,11 @@ describe GitlabConfig do end end - describe '#log_format' do - subject { config.log_format } + describe '#secret_file' do + subject { config.secret_file } - it 'returns "text" by default' do - is_expected.to eq('text') + it 'returns ".gitlab_shell_secret" by default' do + is_expected.to eq(File.join(File.expand_path('..', __dir__),'.gitlab_shell_secret')) end end |