Merge branch '1977-geo-postgres-tracking-database' into 'master'

Geo PostgreSQL tracking database

Closes #1977

See merge request !1346
This commit is contained in:
Marin Jankovski 2017-03-08 13:18:43 +00:00
commit f1077d1049
33 changed files with 1054 additions and 429 deletions

View File

@ -89,6 +89,7 @@ dependency 'gitlab-shell'
dependency 'gitlab-workhorse'
dependency 'gitlab-ctl'
dependency 'gitlab-psql'
dependency 'gitlab-geo-psql' if ee
dependency 'gitlab-healthcheck'
dependency 'gitlab-cookbooks'
dependency 'gitlab-selinux'

View File

@ -0,0 +1,63 @@
#
# Copyright:: Copyright (c) 2016 GitLab Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
require 'digest'
name 'gitlab-geo-psql'
license 'Apache-2.0'
license_file File.expand_path('LICENSE', Omnibus::Config.project_root)
# This 'software' is self-contained in this file. Use the file contents
# to generate a version string.
default_version Digest::MD5.file(__FILE__).hexdigest
build do
block do
open("#{install_dir}/bin/gitlab-geo-psql", 'w') do |file|
file.print <<-EOH
#!/bin/sh
error_echo()
{
echo "$1" 2>& 1
}
gitlab_geo_psql_rc='/opt/gitlab/etc/gitlab-geo-psql-rc'
if ! [ -f ${gitlab_geo_psql_rc} ] ; then
error_echo "$0 error: could not load ${gitlab_geo_psql_rc}"
error_echo "Either you are not allowed to read the file, or it does not exist yet."
error_echo "You can generate it with: sudo gitlab-ctl reconfigure"
exit 1
fi
. ${gitlab_geo_psql_rc}
if [ "$(id -n -u)" = "${psql_user}" ] ; then
privilege_drop=''
else
privilege_drop="-u ${psql_user}"
fi
exec /opt/gitlab/embedded/bin/chpst ${privilege_drop} -U ${psql_user} /opt/gitlab/embedded/bin/psql -p ${psql_port} -h ${psql_host} "$@"
EOH
end
end
command "chmod 755 #{install_dir}/bin/gitlab-geo-psql"
end

View File

@ -17,10 +17,11 @@ by default:
| Unicorn | Yes | Socket | Port (8080) | X |
| GitLab Workhorse | Yes | Socket | Port (8181) | X |
| Nginx status | Yes | Port | X | 8060 |
| Node exporter | No | Port | X | 9100 |
| Prometheus | No | Port | X | 9090 |
| Redis exporter | No | Port | X | 9121 |
| Postgres exporter | No | Port | X | 9187 |
| Geo PostgreSQL | No | Socket | Port (5431) | X |
| Node exporter | No | Port | X | 9100 |
| Prometheus | No | Port | X | 9090 |
| Redis exporter | No | Port | X | 9121 |
| Postgres exporter| No | Port | X | 9187 |
| Gitlab monitor | No | Port | X | 9168 |
| Redis Sentinel | No | Port | X | 26379 |
| Incoming email | No | Port | X | 143 |

View File

@ -34,3 +34,73 @@ default['gitlab']['sidekiq-cluster']['ha'] = false
default['gitlab']['sidekiq-cluster']['log_directory'] = "/var/log/gitlab/sidekiq-cluster"
default['gitlab']['sidekiq-cluster']['interval'] = nil
default['gitlab']['sidekiq-cluster']['queue_groups'] = []
###
# Geo: PostgreSQL (Tracking database)
###
default['gitlab']['geo-postgresql']['enable'] = false
default['gitlab']['geo-postgresql']['ha'] = false
default['gitlab']['geo-postgresql']['dir'] = '/var/opt/gitlab/geo-postgresql'
default['gitlab']['geo-postgresql']['data_dir'] = '/var/opt/gitlab/geo-postgresql/data'
default['gitlab']['geo-postgresql']['log_directory'] = '/var/log/gitlab/geo-postgresql'
default['gitlab']['geo-postgresql']['unix_socket_directory'] = '/var/opt/gitlab/geo-postgresql'
# Postgres User's Environment Path
# defaults to /opt/gitlab/embedded/bin:/opt/gitlab/bin/$PATH. The install-dir path is set at build time
default['gitlab']['geo-postgresql']['sql_user'] = 'gitlab_geo'
default['gitlab']['geo-postgresql']['port'] = 5431
# Postgres allow multi listen_address, comma-separated values.
# If used, first address from the list will be use for connection
default['gitlab']['geo-postgresql']['listen_address'] = nil
default['gitlab']['geo-postgresql']['max_connections'] = 200
default['gitlab']['geo-postgresql']['md5_auth_cidr_addresses'] = []
default['gitlab']['geo-postgresql']['trust_auth_cidr_addresses'] = []
# Mininum of 1/8 of total memory and Maximum of 1024MB as sane defaults
default['gitlab']['geo-postgresql']['shared_buffers'] = "#{[(node['memory']['total'].to_i / 8) / (1024), 1024].max}MB"
default['gitlab']['geo-postgresql']['work_mem'] = '8MB'
default['gitlab']['geo-postgresql']['maintenance_work_mem'] = '16MB'
default['gitlab']['geo-postgresql']['effective_cache_size'] = "#{[(node['memory']['total'].to_i / 8) / (1024), 2048].max}MB" # double of shared_buffers estimation
default['gitlab']['geo-postgresql']['log_min_duration_statement'] = -1 # Disable slow query logging by default
default['gitlab']['geo-postgresql']['checkpoint_segments'] = 10
default['gitlab']['geo-postgresql']['min_wal_size'] = '80MB'
default['gitlab']['geo-postgresql']['max_wal_size'] = '1GB'
default['gitlab']['geo-postgresql']['checkpoint_timeout'] = '5min'
default['gitlab']['geo-postgresql']['checkpoint_completion_target'] = 0.9
default['gitlab']['geo-postgresql']['checkpoint_warning'] = '30s'
default['gitlab']['geo-postgresql']['wal_buffers'] = '-1'
default['gitlab']['geo-postgresql']['autovacuum'] = 'on'
default['gitlab']['geo-postgresql']['log_autovacuum_min_duration'] = '-1'
default['gitlab']['geo-postgresql']['autovacuum_max_workers'] = '3'
default['gitlab']['geo-postgresql']['autovacuum_naptime'] = '1min'
default['gitlab']['geo-postgresql']['autovacuum_vacuum_threshold'] = '50'
default['gitlab']['geo-postgresql']['autovacuum_analyze_threshold'] = '50'
default['gitlab']['geo-postgresql']['autovacuum_vacuum_scale_factor'] = '0.02' # 10x lower than PG defaults
default['gitlab']['geo-postgresql']['autovacuum_analyze_scale_factor'] = '0.01' # 10x lower than PG defaults
default['gitlab']['geo-postgresql']['autovacuum_freeze_max_age'] = '200000000'
default['gitlab']['geo-postgresql']['autovacuum_vacuum_cost_delay'] = '20ms'
default['gitlab']['geo-postgresql']['autovacuum_vacuum_cost_limit'] = '-1'
default['gitlab']['geo-postgresql']['statement_timeout'] = '0'
default['gitlab']['geo-postgresql']['log_line_prefix'] = nil
default['gitlab']['geo-postgresql']['track_activity_query_size'] = '1024'
default['gitlab']['geo-postgresql']['shared_preload_libraries'] = nil
# Replication settings
default['gitlab']['geo-postgresql']['wal_level'] = 'minimal'
default['gitlab']['geo-postgresql']['max_wal_senders'] = 0
default['gitlab']['geo-postgresql']['wal_keep_segments'] = 10
default['gitlab']['geo-postgresql']['hot_standby'] = 'off'
default['gitlab']['geo-postgresql']['max_standby_archive_delay'] = '30s'
default['gitlab']['geo-postgresql']['max_standby_streaming_delay'] = '30s'
default['gitlab']['geo-postgresql']['max_replication_slots'] = 0
default['gitlab']['geo-postgresql']['synchronous_commit'] = 'on'
default['gitlab']['geo-postgresql']['synchronous_standby_names'] = ''
# Backup/Archive settings
default['gitlab']['geo-postgresql']['archive_mode'] = 'off'
default['gitlab']['geo-postgresql']['archive_command'] = nil
default['gitlab']['geo-postgresql']['archive_timeout'] = '60'
# Trackin database settings
default['gitlab']['geo-secondary']['db_database'] = 'gitlabhq_geo_production'

View File

@ -1,6 +1,6 @@
class SentinelHelper
MYID_PATTERN = /^[0-9a-f]{40}$/
JSON_FILE = '/etc/gitlab/gitlab-sentinel.json'.freeze
MYID_PATTERN ||= /^[0-9a-f]{40}$/
JSON_FILE ||= '/etc/gitlab/gitlab-sentinel.json'.freeze
def initialize(node)
@node = node

View File

@ -19,8 +19,9 @@ include_recipe 'gitlab::default'
include_recipe 'gitlab-ee::config'
[
"sentinel",
"sidekiq-cluster"
'sentinel',
'sidekiq-cluster',
'geo-postgresql',
].each do |service|
if node["gitlab"][service]["enable"]
include_recipe "gitlab-ee::#{service}"

View File

@ -0,0 +1,150 @@
#
# Copyright:: Copyright (c) 2012 Opscode, Inc.
# Copyright:: Copyright (c) 2017 GitLab Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
account_helper = AccountHelper.new(node)
omnibus_helper = OmnibusHelper.new(node)
postgresql_dir = node['gitlab']['geo-postgresql']['dir']
postgresql_data_dir = node['gitlab']['geo-postgresql']['data_dir']
postgresql_data_dir_symlink = File.join(postgresql_dir, 'data')
postgresql_log_dir = node['gitlab']['geo-postgresql']['log_directory']
postgresql_socket_dir = node['gitlab']['geo-postgresql']['unix_socket_directory']
postgresql_user = account_helper.postgresql_user
pg_helper = GeoPgHelper.new(node)
directory postgresql_dir do
owner postgresql_user
mode '0755'
recursive true
end
[
postgresql_data_dir,
postgresql_log_dir
].each do |dir|
directory dir do
owner postgresql_user
mode '0700'
recursive true
end
end
link postgresql_data_dir_symlink do
to postgresql_data_dir
not_if { postgresql_data_dir == postgresql_data_dir_symlink }
end
runit_service 'geo-postgresql' do
down node['gitlab']['geo-postgresql']['ha']
control(['t'])
options({
:log_directory => postgresql_log_dir
}.merge(params))
log_options node['gitlab']['logging'].to_hash.merge(node['gitlab']['geo-postgresql'].to_hash)
end
execute "/opt/gitlab/embedded/bin/initdb -D #{postgresql_data_dir} -E UTF8" do
user postgresql_user
not_if { File.exists?(File.join(postgresql_data_dir, 'PG_VERSION')) }
notifies :run, 'execute[start geo-postgresql]', :immediately
end
postgresql_config = File.join(postgresql_data_dir, 'postgresql.conf')
should_notify = omnibus_helper.should_notify?('geo-postgresql')
template postgresql_config do
source 'postgresql.conf.erb'
owner postgresql_user
mode '0644'
helper(:pg_helper) { pg_helper }
variables(node['gitlab']['geo-postgresql'].to_hash)
cookbook 'gitlab'
notifies :restart, 'service[geo-postgresql]', :immediately if should_notify
end
pg_hba_config = File.join(postgresql_data_dir, 'pg_hba.conf')
template pg_hba_config do
source 'pg_hba.conf.erb'
owner postgresql_user
mode '0644'
variables(node['gitlab']['geo-postgresql'].to_hash)
cookbook 'gitlab'
notifies :restart, 'service[geo-postgresql]', :immediately if should_notify
end
template File.join(postgresql_data_dir, 'pg_ident.conf') do
owner postgresql_user
mode '0644'
variables(node['gitlab']['geo-postgresql'].to_hash)
cookbook 'gitlab'
notifies :restart, 'service[geo-postgresql]', :immediately if should_notify
end
# This recipe must be ran BEFORE any calls to the binaries are made
# and AFTER the service has been defined
# to ensure the correct running version of PostgreSQL
# Only exception to this rule is "initdb" call few lines up because this should
# run only on new installation at which point we expect to have correct binaries.
include_recipe 'gitlab::postgresql-bin'
execute 'start geo-postgresql' do
command '/opt/gitlab/bin/gitlab-ctl start geo-postgresql'
retries 20
action :nothing
end
###
# Create the database, migrate it, and create the users we need, and grant them
# privileges.
###
# This template is needed to make the gitlab-geo-psql script and GeoPgHelper work
template '/opt/gitlab/etc/gitlab-geo-psql-rc' do
owner 'root'
group 'root'
end
pg_port = node['gitlab']['geo-postgresql']['port']
gitlab_sql_user = node['gitlab']['geo-postgresql']['sql_user']
database_name = node['gitlab']['geo-secondary']['db_database']
if node['gitlab']['geo-postgresql']['enable']
execute "create #{gitlab_sql_user} database user" do
command "/opt/gitlab/bin/gitlab-geo-psql -d template1 -c \"CREATE USER #{gitlab_sql_user}\""
user postgresql_user
# Added retries to give the service time to start on slower systems
retries 20
not_if { !pg_helper.is_running? || pg_helper.user_exists?(gitlab_sql_user) }
end
execute "create #{database_name} database" do
command "/opt/gitlab/embedded/bin/createdb --port #{pg_port} -h #{postgresql_socket_dir} -O #{gitlab_sql_user} #{database_name}"
user postgresql_user
retries 30
not_if { !pg_helper.is_running? || pg_helper.database_exists?(database_name) }
end
execute 'enable pg_trgm extension on geo-postgresql' do
command "/opt/gitlab/bin/gitlab-geo-psql -d #{database_name} -c \"CREATE EXTENSION IF NOT EXISTS pg_trgm;\""
user postgresql_user
retries 20
action :nothing
not_if { !pg_helper.is_running? || pg_helper.is_slave? || pg_helper.extension_enabled?('pg_trgm', database_name) }
end
end

View File

@ -0,0 +1,21 @@
#
# Copyright:: Copyright (c) 2012 Opscode, Inc.
# Copyright:: Copyright (c) 2017 GitLab Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
runit_service 'geo_postgresql' do
action :disable
end

View File

@ -0,0 +1,3 @@
psql_user='<%= node['gitlab']['postgresql']['username'] %>'
psql_host='<%= node['gitlab']['geo-postgresql']['unix_socket_directory'] %>'
psql_port='<%= node['gitlab']['geo-postgresql']['port'] %>'

View File

@ -0,0 +1,6 @@
<% [node['gitlab']['high-availability']['mountpoint']].flatten.compact.each do |mountpoint| %>
if ! mountpoint -q '<%= mountpoint %>' ; then
echo 'Refusing to start because <%= mountpoint %> is not a mountpoint.'
exit 1
fi
<% end %>

View File

@ -0,0 +1,3 @@
#!/bin/sh
echo "received TERM from runit, sending INT instead to force quit connections"
/opt/gitlab/embedded/bin/sv interrupt geo-postgresql

View File

@ -0,0 +1,6 @@
<%= "s#@svlogd_size" if @svlogd_size %>
<%= "n#@svlogd_num" if @svlogd_num %>
<%= "t#@svlogd_timeout" if @svlogd_timeout %>
<%= "!#@svlogd_filter" if @svlogd_filter %>
<%= "u#@svlogd_udp" if @svlogd_udp %>
<%= "p#@svlogd_prefix" if @svlogd_prefix %>

View File

@ -0,0 +1,2 @@
#!/bin/sh
exec svlogd -tt <%= @options[:log_directory] %>

View File

@ -0,0 +1,4 @@
#!/bin/sh
exec 2>&1
<%= render('mount_point_check.erb') %>
exec chpst -P -U <%= node['gitlab']['postgresql']['username'] %> -u <%= node['gitlab']['postgresql']['username'] %> /opt/gitlab/embedded/bin/postgres -D <%= File.join(node['gitlab']['geo-postgresql']['dir'], 'data') %>

View File

@ -89,6 +89,7 @@ module Gitlab
registry_external_url nil
git_data_dirs Mash.new
gitaly Mash.new
geo_postgresql Mash.new
# roles
redis_sentinel_role Mash.new
@ -191,7 +192,8 @@ module Gitlab
"redis_exporter",
"postgres_exporter",
"gitlab_monitor",
"sentinel"
"sentinel",
"geo_postgresql",
].each do |key|
rkey = key.gsub('_', '-')
results['gitlab'][rkey] = Gitlab[key]

View File

@ -16,332 +16,12 @@
# limitations under the License.
#
require 'mixlib/shellout'
require 'uri'
require 'digest'
require 'openssl'
module ShellOutHelper
def do_shell_out(cmd, user = nil, cwd = nil)
o = Mixlib::ShellOut.new(cmd, user: user, cwd: cwd)
o.run_command
o
rescue Errno::EACCES
Chef::Log.info("Cannot execute #{cmd}.")
o
rescue Errno::ENOENT
Chef::Log.info("#{cmd} does not exist.")
o
end
def success?(cmd)
o = do_shell_out(cmd)
o.exitstatus == 0
end
def failure?(cmd)
o = do_shell_out(cmd)
o.exitstatus != 0
end
end
class PgHelper
include ShellOutHelper
attr_reader :node
def initialize(node)
@node = node
end
def is_running?
OmnibusHelper.new(node).service_up?("postgresql")
end
def database_exists?(db_name)
psql_cmd(["-d 'template1'",
"-c 'select datname from pg_database' -A",
"| grep -x #{db_name}"])
end
def user_exists?(db_user)
psql_cmd(["-d 'template1'",
"-c 'select usename from pg_user' -A",
"|grep -x #{db_user}"])
end
def is_slave?
psql_cmd(["-d 'template1'",
"-c 'select pg_is_in_recovery()' -A",
"|grep -x t"])
end
def psql_cmd(cmd_list)
cmd = ["/opt/gitlab/bin/gitlab-psql", cmd_list.join(" ")].join(" ")
success?(cmd)
end
def version
VersionHelper.version('/opt/gitlab/embedded/bin/psql --version').split.last
end
def database_version
version_file = "#{@node['gitlab']['postgresql']['data_dir']}/PG_VERSION"
if File.exist?(version_file)
File.read(version_file).chomp
else
nil
end
end
end
module AuthorizeHelper
def query_gitlab_rails(uri, name)
warn("Connecting to GitLab to generate new app_id and app_secret for #{name}.")
runner_cmd = create_or_find_authorization(uri, name)
cmd = execute_rails_runner(runner_cmd)
do_shell_out(cmd)
end
def create_or_find_authorization(uri, name)
args = %Q(redirect_uri: "#{uri}", name: "#{name}")
app = %Q(app = Doorkeeper::Application.where(#{args}).first_or_create;)
output = %Q(puts app.uid.concat(" ").concat(app.secret);)
%W(
#{app}
#{output}
).join
end
def execute_rails_runner(cmd)
%W(
/opt/gitlab/bin/gitlab-rails
runner
-e production
'#{cmd}'
).join(" ")
end
def warn(msg)
Chef::Log.warn(msg)
end
def info(msg)
Chef::Log.info(msg)
end
end
class MattermostHelper
extend ShellOutHelper
extend AuthorizeHelper
def self.authorize_with_gitlab(gitlab_external_url)
redirect_uri = "#{Gitlab['mattermost_external_url']}/signup/gitlab/complete\r\n#{Gitlab['mattermost_external_url']}/login/gitlab/complete"
app_name = "GitLab Mattermost"
o = query_gitlab_rails(redirect_uri, app_name)
app_id, app_secret = nil
if o.exitstatus == 0
app_id, app_secret = o.stdout.chomp.split(" ")
Gitlab['mattermost']['gitlab_enable'] = true
Gitlab['mattermost']['gitlab_secret'] = app_secret
Gitlab['mattermost']['gitlab_id'] = app_id
Gitlab['mattermost']['gitlab_scope'] = ""
SecretsHelper.write_to_gitlab_secrets
info("Updated the gitlab-secrets.json file.")
else
warn("Something went wrong while trying to update gitlab-secrets.json. Check the file permissions and try reconfiguring again.")
end
end
end
class SecretsHelper
def self.generate_hex(chars)
SecureRandom.hex(chars)
end
def self.generate_rsa(bits)
OpenSSL::PKey::RSA.new(bits)
end
def self.read_gitlab_secrets
existing_secrets ||= Hash.new
if File.exists?("/etc/gitlab/gitlab-secrets.json")
existing_secrets = Chef::JSONCompat.from_json(File.read("/etc/gitlab/gitlab-secrets.json"))
end
existing_secrets.each do |k, v|
if Gitlab[k]
v.each do |pk, p|
# Note: Specifiying a secret in gitlab.rb will take precendence over "gitlab-secrets.json"
Gitlab[k][pk] ||= p
end
else
warn("Ignoring section #{k} in /etc/gitlab/giltab-secrets.json, does not exist in gitlab.rb")
end
end
end
def self.write_to_gitlab_secrets
secret_tokens = {
'gitlab_workhorse' => {
'secret_token' => Gitlab['gitlab_workhorse']['secret_token'],
},
'gitlab_shell' => {
'secret_token' => Gitlab['gitlab_shell']['secret_token'],
},
'gitlab_rails' => {
'secret_key_base' => Gitlab['gitlab_rails']['secret_key_base'],
'db_key_base' => Gitlab['gitlab_rails']['db_key_base'],
'otp_key_base' => Gitlab['gitlab_rails']['otp_key_base'],
'jws_private_key' => Gitlab['gitlab_rails']['jws_private_key']
},
'registry' => {
'http_secret' => Gitlab['registry']['http_secret'],
'internal_certificate' => Gitlab['registry']['internal_certificate'],
'internal_key' => Gitlab['registry']['internal_key']
},
'mattermost' => {
'email_invite_salt' => Gitlab['mattermost']['email_invite_salt'],
'file_public_link_salt' => Gitlab['mattermost']['file_public_link_salt'],
'email_password_reset_salt' => Gitlab['mattermost']['email_password_reset_salt'],
'sql_at_rest_encrypt_key' => Gitlab['mattermost']['sql_at_rest_encrypt_key']
}
}
if Gitlab['mattermost']['gitlab_enable']
gitlab_oauth = {
'gitlab_enable' => Gitlab['mattermost']['gitlab_enable'],
'gitlab_secret' => Gitlab['mattermost']['gitlab_secret'],
'gitlab_id' => Gitlab['mattermost']['gitlab_id'],
'gitlab_scope' => Gitlab['mattermost']['gitlab_scope'],
'gitlab_auth_endpoint' => Gitlab['mattermost']['gitlab_auth_endpoint'],
'gitlab_token_endpoint' => Gitlab['mattermost']['gitlab_token_endpoint'],
'gitlab_user_api_endpoint' => Gitlab['mattermost']['gitlab_user_api_endpoint']
}
secret_tokens['mattermost'].merge!(gitlab_oauth)
end
if File.directory?('/etc/gitlab')
File.open('/etc/gitlab/gitlab-secrets.json', 'w', 0600) do |f|
f.puts(Chef::JSONCompat.to_json_pretty(secret_tokens))
f.chmod(0600)
end
end
end
end
module SingleQuoteHelper
def single_quote(string)
"'#{string}'" unless string.nil?
end
end
class RedhatHelper
def self.system_is_rhel7?
platform_family == "rhel" && platform_version =~ /7\./
end
def self.platform_family
case platform
when /oracle/, /centos/, /redhat/, /scientific/, /enterpriseenterprise/, /amazon/, /xenserver/, /cloudlinux/, /ibm_powerkvm/, /parallels/
"rhel"
else
"not redhat"
end
end
def self.platform
contents = read_release_file
get_redhatish_platform(contents)
end
def self.platform_version
contents = read_release_file
get_redhatish_version(contents)
end
def self.read_release_file
if File.exists?("/etc/redhat-release")
contents = File.read("/etc/redhat-release").chomp
else
"not redhat"
end
end
# Taken from Ohai
# https://github.com/chef/ohai/blob/31f6415c853f3070b0399ac2eb09094eb81939d2/lib/ohai/plugins/linux/platform.rb#L23
def self.get_redhatish_platform(contents)
contents[/^Red Hat/i] ? "redhat" : contents[/(\w+)/i, 1].downcase
end
# Taken from Ohai
# https://github.com/chef/ohai/blob/31f6415c853f3070b0399ac2eb09094eb81939d2/lib/ohai/plugins/linux/platform.rb#L27
def self.get_redhatish_version(contents)
contents[/Rawhide/i] ? contents[/((\d+) \(Rawhide\))/i, 1].downcase : contents[/release ([\d\.]+)/, 1]
end
end
class VersionHelper
extend ShellOutHelper
def self.version(cmd)
result = do_shell_out(cmd)
if result.exitstatus == 0
result.stdout
else
nil
end
end
end
class MattermostHelper
extend ShellOutHelper
def initialize(node, mattermost_user, mattermost_home)
@node = node
@mattermost_user = mattermost_user
@mattermost_home = mattermost_home
@config_file_path = File.join(@mattermost_home, 'config.json')
@status = {}
end
def version
return @status[:version] if @status.key?(:version)
cmd = self.class.version_cmd(@config_file_path)
result = self.class.do_shell_out(cmd, @mattermost_user, "/opt/gitlab/embedded/service/mattermost")
if result.exitstatus == 0
@status[:version] = result.stdout
else
@status[:version] = nil
end
end
def self.version_cmd(path)
"/opt/gitlab/embedded/bin/mattermost -config='#{path}' -version"
end
def self.upgrade_db_30(path, user, team_name)
cmd = upgrade_db_30_cmd(path, team_name)
result = do_shell_out(cmd, user, "/opt/gitlab/embedded/service/mattermost")
result.exitstatus
end
def self.upgrade_db_30_cmd(path, team_name)
"/opt/gitlab/embedded/bin/mattermost -config='#{path}' -upgrade_db_30 -confirm_backup='YES' -team_name='#{team_name}'"
end
end
require_relative 'helpers/pg_helper'
require_relative 'helpers/geo_pg_helper'
require_relative 'helpers/mattermost_helper'
require_relative 'helpers/redhat_helper'
require_relative 'helpers/secrets_helper'
require_relative 'helpers/version_helper'
require_relative 'helpers/single_quote_helper'

View File

@ -0,0 +1,38 @@
module AuthorizeHelper
def query_gitlab_rails(uri, name)
warn("Connecting to GitLab to generate new app_id and app_secret for #{name}.")
runner_cmd = create_or_find_authorization(uri, name)
cmd = execute_rails_runner(runner_cmd)
do_shell_out(cmd)
end
def create_or_find_authorization(uri, name)
args = %Q(redirect_uri: "#{uri}", name: "#{name}")
app = %Q(app = Doorkeeper::Application.where(#{args}).first_or_create;)
output = %Q(puts app.uid.concat(" ").concat(app.secret);)
%W(
#{app}
#{output}
).join
end
def execute_rails_runner(cmd)
%W(
/opt/gitlab/bin/gitlab-rails
runner
-e production
'#{cmd}'
).join(" ")
end
def warn(msg)
Chef::Log.warn(msg)
end
def info(msg)
Chef::Log.info(msg)
end
end

View File

@ -0,0 +1,73 @@
require_relative 'shell_out_helper'
# This is a base class to be inherited by PG Helpers
class BasePgHelper
include ShellOutHelper
attr_reader :node
def initialize(node)
@node = node
end
def is_running?
OmnibusHelper.new(node).service_up?(service_name)
end
def database_exists?(db_name)
psql_cmd(["-d 'template1'",
"-c 'select datname from pg_database' -A",
"| grep -x #{db_name}"])
end
def extension_exists?(extension_name)
psql_cmd(["-d 'template1'",
"-c 'select name from pg_available_extensions' -A",
"| grep -x #{extension_name}"])
end
def extension_enabled?(extension_name, db_name)
psql_cmd(["-d '#{db_name}'",
"-c 'select extname from pg_extension' -A",
"| grep -x #{extension_name}"])
end
def user_exists?(db_user)
psql_cmd(["-d 'template1'",
"-c 'select usename from pg_user' -A",
"|grep -x #{db_user}"])
end
def is_slave?
psql_cmd(["-d 'template1'",
"-c 'select pg_is_in_recovery()' -A",
"|grep -x t"])
end
def psql_cmd(cmd_list)
cmd = ["/opt/gitlab/bin/#{service_cmd}", cmd_list.join(' ')].join(' ')
success?(cmd)
end
def version
VersionHelper.version('/opt/gitlab/embedded/bin/psql --version').split.last
end
def database_version
version_file = "#{@node['gitlab'][service_name]['data_dir']}/PG_VERSION"
if File.exist?(version_file)
File.read(version_file).chomp
else
nil
end
end
protected
def service_name
raise NotImplementedError
end
def service_cmd
raise NotImplementedError
end
end

View File

@ -0,0 +1,16 @@
require_relative 'base_pg_helper'
# Helper class to interact with bundled Geo PostgreSQL instance
class GeoPgHelper < BasePgHelper
protected
# internal name for the service (node['gitlab'][service_name])
def service_name
'geo-postgresql'
end
# command wrapper name
def service_cmd
'gitlab-geo-psql'
end
end

View File

@ -0,0 +1,64 @@
require_relative 'shell_out_helper'
require_relative 'authorizer_helper'
class MattermostHelper
extend ShellOutHelper
extend AuthorizeHelper
def initialize(node, mattermost_user, mattermost_home)
@node = node
@mattermost_user = mattermost_user
@mattermost_home = mattermost_home
@config_file_path = File.join(@mattermost_home, 'config.json')
@status = {}
end
def version
return @status[:version] if @status.key?(:version)
cmd = self.class.version_cmd(@config_file_path)
result = self.class.do_shell_out(cmd, @mattermost_user, "/opt/gitlab/embedded/service/mattermost")
if result.exitstatus == 0
@status[:version] = result.stdout
else
@status[:version] = nil
end
end
def self.authorize_with_gitlab(gitlab_external_url)
redirect_uri = "#{Gitlab['mattermost_external_url']}/signup/gitlab/complete\r\n#{Gitlab['mattermost_external_url']}/login/gitlab/complete"
app_name = 'GitLab Mattermost'
o = query_gitlab_rails(redirect_uri, app_name)
app_id, app_secret = nil
if o.exitstatus == 0
app_id, app_secret = o.stdout.chomp.split(" ")
Gitlab['mattermost']['gitlab_enable'] = true
Gitlab['mattermost']['gitlab_secret'] = app_secret
Gitlab['mattermost']['gitlab_id'] = app_id
Gitlab['mattermost']['gitlab_scope'] = ""
SecretsHelper.write_to_gitlab_secrets
info('Updated the gitlab-secrets.json file.')
else
warn('Something went wrong while trying to update gitlab-secrets.json. Check the file permissions and try reconfiguring again.')
end
end
def self.version_cmd(path)
"/opt/gitlab/embedded/bin/mattermost -config='#{path}' -version"
end
def self.upgrade_db_30(path, user, team_name)
cmd = upgrade_db_30_cmd(path, team_name)
result = do_shell_out(cmd, user, '/opt/gitlab/embedded/service/mattermost')
result.exitstatus
end
def self.upgrade_db_30_cmd(path, team_name)
"/opt/gitlab/embedded/bin/mattermost -config='#{path}' -upgrade_db_30 -confirm_backup='YES' -team_name='#{team_name}'"
end
end

View File

@ -0,0 +1,16 @@
require_relative 'base_pg_helper'
# Helper class to interact with bundled PostgreSQL instance
class PgHelper < BasePgHelper
protected
# internal name for the service (node['gitlab'][service_name])
def service_name
'postgresql'
end
# command wrapper name
def service_cmd
'gitlab-psql'
end
end

View File

@ -0,0 +1,44 @@
class RedhatHelper
def self.system_is_rhel7?
platform_family == 'rhel' && platform_version =~ /7\./
end
def self.platform_family
case platform
when /oracle/, /centos/, /redhat/, /scientific/, /enterpriseenterprise/, /amazon/, /xenserver/, /cloudlinux/, /ibm_powerkvm/, /parallels/
'rhel'
else
'not redhat'
end
end
def self.platform
contents = read_release_file
get_redhatish_platform(contents)
end
def self.platform_version
contents = read_release_file
get_redhatish_version(contents)
end
def self.read_release_file
if File.exists?('/etc/redhat-release')
contents = File.read('/etc/redhat-release').chomp
else
'not redhat'
end
end
# Taken from Ohai
# https://github.com/chef/ohai/blob/31f6415c853f3070b0399ac2eb09094eb81939d2/lib/ohai/plugins/linux/platform.rb#L23
def self.get_redhatish_platform(contents)
contents[/^Red Hat/i] ? 'redhat' : contents[/(\w+)/i, 1].downcase
end
# Taken from Ohai
# https://github.com/chef/ohai/blob/31f6415c853f3070b0399ac2eb09094eb81939d2/lib/ohai/plugins/linux/platform.rb#L27
def self.get_redhatish_version(contents)
contents[/Rawhide/i] ? contents[/((\d+) \(Rawhide\))/i, 1].downcase : contents[/release ([\d\.]+)/, 1]
end
end

View File

@ -0,0 +1,79 @@
require 'openssl'
class SecretsHelper
def self.generate_hex(chars)
SecureRandom.hex(chars)
end
def self.generate_rsa(bits)
OpenSSL::PKey::RSA.new(bits)
end
def self.read_gitlab_secrets
existing_secrets ||= Hash.new
if File.exists?("/etc/gitlab/gitlab-secrets.json")
existing_secrets = Chef::JSONCompat.from_json(File.read("/etc/gitlab/gitlab-secrets.json"))
end
existing_secrets.each do |k, v|
if Gitlab[k]
v.each do |pk, p|
# Note: Specifiying a secret in gitlab.rb will take precendence over "gitlab-secrets.json"
Gitlab[k][pk] ||= p
end
else
warn("Ignoring section #{k} in /etc/gitlab/giltab-secrets.json, does not exist in gitlab.rb")
end
end
end
def self.write_to_gitlab_secrets
secret_tokens = {
'gitlab_workhorse' => {
'secret_token' => Gitlab['gitlab_workhorse']['secret_token'],
},
'gitlab_shell' => {
'secret_token' => Gitlab['gitlab_shell']['secret_token'],
},
'gitlab_rails' => {
'secret_key_base' => Gitlab['gitlab_rails']['secret_key_base'],
'db_key_base' => Gitlab['gitlab_rails']['db_key_base'],
'otp_key_base' => Gitlab['gitlab_rails']['otp_key_base'],
'jws_private_key' => Gitlab['gitlab_rails']['jws_private_key']
},
'registry' => {
'http_secret' => Gitlab['registry']['http_secret'],
'internal_certificate' => Gitlab['registry']['internal_certificate'],
'internal_key' => Gitlab['registry']['internal_key']
},
'mattermost' => {
'email_invite_salt' => Gitlab['mattermost']['email_invite_salt'],
'file_public_link_salt' => Gitlab['mattermost']['file_public_link_salt'],
'email_password_reset_salt' => Gitlab['mattermost']['email_password_reset_salt'],
'sql_at_rest_encrypt_key' => Gitlab['mattermost']['sql_at_rest_encrypt_key']
}
}
if Gitlab['mattermost']['gitlab_enable']
gitlab_oauth = {
'gitlab_enable' => Gitlab['mattermost']['gitlab_enable'],
'gitlab_secret' => Gitlab['mattermost']['gitlab_secret'],
'gitlab_id' => Gitlab['mattermost']['gitlab_id'],
'gitlab_scope' => Gitlab['mattermost']['gitlab_scope'],
'gitlab_auth_endpoint' => Gitlab['mattermost']['gitlab_auth_endpoint'],
'gitlab_token_endpoint' => Gitlab['mattermost']['gitlab_token_endpoint'],
'gitlab_user_api_endpoint' => Gitlab['mattermost']['gitlab_user_api_endpoint']
}
secret_tokens['mattermost'].merge!(gitlab_oauth)
end
if File.directory?('/etc/gitlab')
File.open('/etc/gitlab/gitlab-secrets.json', 'w', 0600) do |f|
f.puts(Chef::JSONCompat.to_json_pretty(secret_tokens))
f.chmod(0600)
end
end
end
end

View File

@ -0,0 +1,25 @@
require 'mixlib/shellout'
module ShellOutHelper
def do_shell_out(cmd, user = nil, cwd = nil)
o = Mixlib::ShellOut.new(cmd, user: user, cwd: cwd)
o.run_command
o
rescue Errno::EACCES
Chef::Log.info("Cannot execute #{cmd}.")
o
rescue Errno::ENOENT
Chef::Log.info("#{cmd} does not exist.")
o
end
def success?(cmd)
o = do_shell_out(cmd)
o.exitstatus == 0
end
def failure?(cmd)
o = do_shell_out(cmd)
o.exitstatus != 0
end
end

View File

@ -0,0 +1,5 @@
module SingleQuoteHelper
def single_quote(string)
"'#{string}'" unless string.nil?
end
end

View File

@ -0,0 +1,14 @@
require_relative 'shell_out_helper'
class VersionHelper
extend ShellOutHelper
def self.version(cmd)
result = do_shell_out(cmd)
if result.exitstatus == 0
result.stdout
else
nil
end
end
end

View File

@ -93,9 +93,9 @@ postgresql_config = File.join(postgresql_data_dir, "postgresql.conf")
should_notify = omnibus_helper.should_notify?("postgresql")
template postgresql_config do
source "postgresql.conf.erb"
source 'postgresql.conf.erb'
owner postgresql_user
mode "0644"
mode '0644'
helper(:pg_helper) { pg_helper }
variables(node['gitlab']['postgresql'].to_hash)
notifies :restart, 'service[postgresql]', :immediately if should_notify
@ -104,14 +104,14 @@ end
pg_hba_config = File.join(postgresql_data_dir, "pg_hba.conf")
template pg_hba_config do
source "pg_hba.conf.erb"
source 'pg_hba.conf.erb'
owner postgresql_user
mode "0644"
variables(node['gitlab']['postgresql'].to_hash)
notifies :restart, 'service[postgresql]', :immediately if should_notify
end
template File.join(postgresql_data_dir, "pg_ident.conf") do
template File.join(postgresql_data_dir, 'pg_ident.conf') do
owner postgresql_user
mode "0644"
variables(node['gitlab']['postgresql'].to_hash)
@ -187,5 +187,5 @@ execute "enable pg_trgm extension" do
user postgresql_user
retries 20
action :nothing
not_if { !pg_helper.is_running? || pg_helper.is_slave? }
not_if { !pg_helper.is_running? || pg_helper.is_slave? || pg_helper.extension_enabled?('pg_trgm', database_name) }
end

View File

@ -69,12 +69,14 @@
# "local" is for Unix domain socket connections only
local all all peer map=gitlab
<% node['gitlab']['postgresql']['trust_auth_cidr_addresses'].each do |cidr| %>
<% @trust_auth_cidr_addresses.each do |cidr| %>
host all all <%= cidr %> trust
<% end %>
<% node['gitlab']['postgresql']['md5_auth_cidr_addresses'].each do |cidr| %>
<% @md5_auth_cidr_addresses.each do |cidr| %>
host all all <%= cidr %> md5
host replication <%= node['gitlab']['postgresql']['sql_replication_user'] %> <%= cidr %> md5
<% if @sql_replication_user %>
host replication <%= @sql_replication_user %> <%= cidr %> md5
<% end %>
<% end %>

View File

@ -40,7 +40,9 @@
# ----------------------------------
# MAPNAME SYSTEM-USERNAME PG-USERNAME
gitlab <%= node['gitlab']['user']['username'] %> <%= node['gitlab']['postgresql']['sql_user'] %>
gitlab <%= node['gitlab']['mattermost']['username'] %> <%= node['gitlab']['postgresql']['sql_mattermost_user'] %>
gitlab <%= node['gitlab']['user']['username'] %> <%= @sql_user %>
<% if @sql_mattermost_user %>
gitlab <%= node['gitlab']['mattermost']['username'] %> <%= @sql_mattermost_user %>
<% end %>
# Default to a 1-1 mapping between system usernames and Postgres usernames
gitlab /^(.*)$ \1

View File

@ -60,19 +60,19 @@
# - Connection Settings -
listen_addresses = '<%= node['gitlab']['postgresql']['listen_address'] %>' # what IP address(es) to listen on;
listen_addresses = '<%= @listen_address %>' # what IP address(es) to listen on;
# comma-separated list of addresses;
# defaults to 'localhost', '*' = all
# (change requires restart)
port = <%= node['gitlab']['postgresql']['port'] %> # (change requires restart)
max_connections = <%= node['gitlab']['postgresql']['max_connections'] %> # (change requires restart)
port = <%= @port %> # (change requires restart)
max_connections = <%= @max_connections %> # (change requires restart)
# Note: Increasing max_connections costs ~400 bytes of shared memory per
# connection slot, plus lock space (see max_locks_per_transaction).
#superuser_reserved_connections = 3 # (change requires restart)
<% if pg_helper.database_version == "9.2" %>
unix_socket_directory = '<%= node['gitlab']['postgresql']['unix_socket_directory'] %>' # (change requires restart)
unix_socket_directory = '<%= @unix_socket_directory %>' # (change requires restart)
<% else %>
unix_socket_directories = '<%= node['gitlab']['postgresql']['unix_socket_directory'] %>' # (change requires restart)
unix_socket_directories = '<%= @unix_socket_directory %>' # (change requires restart)
<% end %>
#unix_socket_group = '' # (change requires restart)
#unix_socket_permissions = 0777 # begin with 0 to use octal notation
@ -114,7 +114,7 @@ unix_socket_directories = '<%= node['gitlab']['postgresql']['unix_socket_directo
# - Memory -
shared_buffers = <%= node['gitlab']['postgresql']['shared_buffers'] %> # min 128kB
shared_buffers = <%= @shared_buffers %> # min 128kB
# (change requires restart)
#temp_buffers = 8MB # min 800kB
#max_prepared_transactions = 0 # zero disables the feature
@ -123,15 +123,15 @@ shared_buffers = <%= node['gitlab']['postgresql']['shared_buffers'] %> # min 128
# per transaction slot, plus lock space (see max_locks_per_transaction).
# It is not advisable to set max_prepared_transactions nonzero unless you
# actively intend to use prepared transactions.
work_mem = <%= node['gitlab']['postgresql']['work_mem'] %> # min 64kB
maintenance_work_mem = <%= node['gitlab']['postgresql']['maintenance_work_mem'] %> # 16MB # min 1MB
work_mem = <%= @work_mem %> # min 64kB
maintenance_work_mem = <%= @maintenance_work_mem %> # 16MB # min 1MB
#max_stack_depth = 2MB # min 100kB
# - Kernel Resource Usage -
#max_files_per_process = 1000 # min 25
# (change requires restart)
shared_preload_libraries = '<%= node['gitlab']['postgresql']['shared_preload_libraries'] %>' # (change requires restart)
shared_preload_libraries = '<%= @shared_preload_libraries %>' # (change requires restart)
# - Cost-Based Vacuum Delay -
@ -158,11 +158,11 @@ shared_preload_libraries = '<%= node['gitlab']['postgresql']['shared_preload_lib
# - Settings -
wal_level = <%= node['gitlab']['postgresql']['wal_level'] %>
wal_level = <%= @wal_level %>
# (change requires restart)
#fsync = on # turns forced synchronization on or off
synchronous_commit = <%= node['gitlab']['postgresql']['synchronous_commit'] %> # synchronization level; on, off, or local
synchronous_standby_names = '<%= node['gitlab']['postgresql']['synchronous_standby_names'] %>'
synchronous_commit = <%= @synchronous_commit %> # synchronization level; on, off, or local
synchronous_standby_names = '<%= @synchronous_standby_names %>'
#wal_sync_method = fsync # the default is the first option
# supported by the operating system:
# open_datasync
@ -171,7 +171,7 @@ synchronous_standby_names = '<%= node['gitlab']['postgresql']['synchronous_stand
# fsync_writethrough
# open_sync
#full_page_writes = on # recover from partial page writes
wal_buffers = <%= node['gitlab']['postgresql']['wal_buffers'] %> # -1 # min 32kB, -1 sets based on shared_buffers
wal_buffers = <%= @wal_buffers %> # -1 # min 32kB, -1 sets based on shared_buffers
# (change requires restart)
#wal_writer_delay = 200ms # 1-10000 milliseconds
@ -180,24 +180,24 @@ wal_buffers = <%= node['gitlab']['postgresql']['wal_buffers'] %> # -1 # min
# - Checkpoints -
<% if pg_helper.database_version == "9.2" %>
checkpoint_segments = <%= node['gitlab']['postgresql']['checkpoint_segments'] %> # in logfile segments, min 1, 16MB each, default 3
checkpoint_segments = <%= @checkpoint_segments %> # in logfile segments, min 1, 16MB each, default 3
<% else %>
min_wal_size = <%= node['gitlab']['postgresql']['min_wal_size'] %>
max_wal_size = <%= node['gitlab']['postgresql']['max_wal_size'] %>
min_wal_size = <%= @min_wal_size %>
max_wal_size = <%= @max_wal_size %>
# The number of replication slots to reserve.
max_replication_slots = <%= node['gitlab']['postgresql']['max_replication_slots'] %>
max_replication_slots = <%= @max_replication_slots %>
<% end %>
checkpoint_timeout = <%= node['gitlab']['postgresql']['checkpoint_timeout'] %> # range 30s-1h, default 5min
checkpoint_completion_target = <%= node['gitlab']['postgresql']['checkpoint_completion_target'] %> # checkpoint target duration, 0.0 - 1.0, default 0.5
checkpoint_warning = <%= node['gitlab']['postgresql']['checkpoint_warning'] %> # 0 disables, default 30s
checkpoint_timeout = <%= @checkpoint_timeout %> # range 30s-1h, default 5min
checkpoint_completion_target = <%= @checkpoint_completion_target %> # checkpoint target duration, 0.0 - 1.0, default 0.5
checkpoint_warning = <%= @checkpoint_warning %> # 0 disables, default 30s
# - Archiving -
archive_mode = <%= node['gitlab']['postgresql']['archive_mode'] %> # allows archiving to be done
archive_mode = <%= @archive_mode %> # allows archiving to be done
# (change requires restart, also requires 'wal_level' of 'hot_standby' OR 'replica')
archive_command = '<%= node['gitlab']['postgresql']['archive_command'] %>' # command to use to archive a logfile segment
archive_timeout = <%= node['gitlab']['postgresql']['archive_timeout'] %> # force a logfile segment switch after this
archive_command = '<%= @archive_command %>' # command to use to archive a logfile segment
archive_timeout = <%= @archive_timeout %> # force a logfile segment switch after this
# number of seconds; 0 disables
@ -209,10 +209,10 @@ archive_timeout = <%= node['gitlab']['postgresql']['archive_timeout'] %> # fo
# These settings are ignored on a standby server
max_wal_senders = <%= node['gitlab']['postgresql']['max_wal_senders'] %>
max_wal_senders = <%= @max_wal_senders %>
# (change requires restart)
#wal_sender_delay = 1s # walsender cycle time, 1-10000 milliseconds
wal_keep_segments = <%= node['gitlab']['postgresql']['wal_keep_segments'] %>
wal_keep_segments = <%= @wal_keep_segments %>
#vacuum_defer_cleanup_age = 0 # number of xacts by which cleanup is delayed
#replication_timeout = 60s # in milliseconds; 0 disables
#synchronous_standby_names = '' # standby servers that provide sync rep
@ -223,12 +223,12 @@ wal_keep_segments = <%= node['gitlab']['postgresql']['wal_keep_segments'] %>
# These settings are ignored on a master server
hot_standby = <%= node['gitlab']['postgresql']['hot_standby'] %>
hot_standby = <%= @hot_standby %>
# (change requires restart)
max_standby_archive_delay = <%= node['gitlab']['postgresql']['max_standby_archive_delay'] %> # max delay before canceling queries
max_standby_archive_delay = <%= @max_standby_archive_delay %> # max delay before canceling queries
# when reading WAL from archive;
# -1 allows indefinite delay
max_standby_streaming_delay = <%= node['gitlab']['postgresql']['max_standby_streaming_delay'] %> # max delay before canceling queries
max_standby_streaming_delay = <%= @max_standby_streaming_delay %> # max delay before canceling queries
# when reading streaming WAL;
# -1 allows indefinite delay
#wal_receiver_status_interval = 10s # send replies at least this often
@ -261,7 +261,7 @@ max_standby_streaming_delay = <%= node['gitlab']['postgresql']['max_standby_stre
#cpu_tuple_cost = 0.01 # same scale as above
#cpu_index_tuple_cost = 0.005 # same scale as above
#cpu_operator_cost = 0.0025 # same scale as above
effective_cache_size = <%= node['gitlab']['postgresql']['effective_cache_size'] %> # Default 128MB
effective_cache_size = <%= @effective_cache_size %> # Default 128MB
# - Genetic Query Optimizer -
@ -390,7 +390,7 @@ log_min_duration_statement = <%= @log_min_duration_statement %> # -1 is disable
#log_duration = off
#log_error_verbosity = default # terse, default, or verbose messages
#log_hostname = off
log_line_prefix = '<%= node['gitlab']['postgresql']['log_line_prefix'] %>' # default '', special values:
log_line_prefix = '<%= @log_line_prefix %>' # default '', special values:
# %a = application name
# %u = user name
# %d = database name
@ -426,7 +426,7 @@ log_line_prefix = '<%= node['gitlab']['postgresql']['log_line_prefix'] %>' # def
#track_activities = on
#track_counts = on
#track_functions = none # none, pl, all
track_activity_query_size = <%= node['gitlab']['postgresql']['track_activity_query_size'] %> # (change requires restart)
track_activity_query_size = <%= @track_activity_query_size %> # (change requires restart)
#update_process_title = on
#stats_temp_directory = 'pg_stat_tmp'
@ -443,27 +443,27 @@ track_activity_query_size = <%= node['gitlab']['postgresql']['track_activity_que
# AUTOVACUUM PARAMETERS
#------------------------------------------------------------------------------
autovacuum = <%= node['gitlab']['postgresql']['autovacuum'] %> # Enable autovacuum subprocess? 'on'
autovacuum = <%= @autovacuum %> # Enable autovacuum subprocess? 'on'
# requires track_counts to also be on.
log_autovacuum_min_duration = <%= node['gitlab']['postgresql']['log_autovacuum_min_duration'] %> # -1 disables, 0 logs all actions and
log_autovacuum_min_duration = <%= @log_autovacuum_min_duration %> # -1 disables, 0 logs all actions and
# their durations, > 0 logs only
# actions running at least this number
# of milliseconds.
autovacuum_max_workers = <%= node['gitlab']['postgresql']['autovacuum_max_workers'] %> # max number of autovacuum subprocesses
autovacuum_max_workers = <%= @autovacuum_max_workers %> # max number of autovacuum subprocesses
# (change requires restart)
autovacuum_naptime = <%= node['gitlab']['postgresql']['autovacuum_naptime'] %> # time between autovacuum runs
autovacuum_vacuum_threshold = <%= node['gitlab']['postgresql']['autovacuum_vacuum_threshold'] %> # min number of row updates before
autovacuum_naptime = <%= @autovacuum_naptime %> # time between autovacuum runs
autovacuum_vacuum_threshold = <%= @autovacuum_vacuum_threshold %> # min number of row updates before
# vacuum
autovacuum_analyze_threshold = <%= node['gitlab']['postgresql']['autovacuum_analyze_threshold'] %> # min number of row updates before
autovacuum_analyze_threshold = <%= @autovacuum_analyze_threshold %> # min number of row updates before
# analyze
autovacuum_vacuum_scale_factor = <%= node['gitlab']['postgresql']['autovacuum_vacuum_scale_factor'] %> # fraction of table size before vacuum
autovacuum_analyze_scale_factor = <%= node['gitlab']['postgresql']['autovacuum_analyze_scale_factor'] %> # fraction of table size before analyze
autovacuum_freeze_max_age = <%= node['gitlab']['postgresql']['autovacuum_freeze_max_age'] %> # maximum XID age before forced vacuum
autovacuum_vacuum_scale_factor = <%= @autovacuum_vacuum_scale_factor %> # fraction of table size before vacuum
autovacuum_analyze_scale_factor = <%= @autovacuum_analyze_scale_factor %> # fraction of table size before analyze
autovacuum_freeze_max_age = <%= @autovacuum_freeze_max_age %> # maximum XID age before forced vacuum
# (change requires restart)
autovacuum_vacuum_cost_delay = <%= node['gitlab']['postgresql']['autovacuum_vacuum_cost_delay'] %> # default vacuum cost delay for
autovacuum_vacuum_cost_delay = <%= @autovacuum_vacuum_cost_delay %> # default vacuum cost delay for
# autovacuum, in milliseconds;
# -1 means use vacuum_cost_delay
autovacuum_vacuum_cost_limit = <%= node['gitlab']['postgresql']['autovacuum_vacuum_cost_limit'] %> # default vacuum cost limit for
autovacuum_vacuum_cost_limit = <%= @autovacuum_vacuum_cost_limit %> # default vacuum cost limit for
# autovacuum, -1 means use
# vacuum_cost_limit
@ -483,7 +483,7 @@ autovacuum_vacuum_cost_limit = <%= node['gitlab']['postgresql']['autovacuum_vacu
#default_transaction_read_only = off
#default_transaction_deferrable = off
#session_replication_role = 'origin'
statement_timeout = <%= node['gitlab']['postgresql']['statement_timeout'] %>
statement_timeout = <%= @statement_timeout %>
#vacuum_freeze_min_age = 50000000
#vacuum_freeze_table_age = 150000000
#bytea_output = 'hex' # hex, escape

View File

@ -0,0 +1,198 @@
require 'chef_helper'
describe 'geo postgresql 9.2' do
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab::config', 'gitlab-ee::default') }
before do
allow(Gitlab).to receive(:[]).and_call_original
allow_any_instance_of(GeoPgHelper).to receive(:version).and_return('9.2.18')
allow_any_instance_of(GeoPgHelper).to receive(:database_version).and_return('9.2')
stub_gitlab_rb(geo_postgresql: {
enable: true
})
end
it 'includes the postgresql-bin recipe' do
expect(chef_run).to include_recipe('gitlab::postgresql-bin')
end
context 'with default settings' do
it 'correctly sets the shared_preload_libraries default setting' do
expect(chef_run.node['gitlab']['geo-postgresql']['shared_preload_libraries']).to be_nil
expect(chef_run).to render_file('/var/opt/gitlab/geo-postgresql/data/postgresql.conf')
.with_content(/shared_preload_libraries = ''/)
end
it 'correctly sets the log_line_prefix default setting' do
expect(chef_run.node['gitlab']['geo-postgresql']['log_line_prefix']).to be_nil
expect(chef_run).to render_file('/var/opt/gitlab/geo-postgresql/data/postgresql.conf')
.with_content(/log_line_prefix = ''/)
end
it 'sets max_standby settings' do
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/max_standby_archive_delay = 30s/)
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/max_standby_streaming_delay = 30s/)
end
it 'sets archive settings' do
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/archive_mode = off/)
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/archive_command = ''/)
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/archive_timeout = 60/)
end
end
context 'when user settings are set' do
before do
stub_gitlab_rb(geo_postgresql: {
enable: true,
shared_preload_libraries: 'pg_stat_statements',
log_line_prefix: '%a',
max_standby_archive_delay: '60s',
max_standby_streaming_delay: '120s',
archive_mode: 'on',
archive_command: 'command',
archive_timeout: '120',
})
end
it 'correctly sets the shared_preload_libraries setting' do
expect(chef_run.node['gitlab']['geo-postgresql']['shared_preload_libraries']).to eql('pg_stat_statements')
expect(chef_run).to render_file('/var/opt/gitlab/geo-postgresql/data/postgresql.conf')
.with_content(/shared_preload_libraries = 'pg_stat_statements'/)
end
it 'correctly sets the log_line_prefix setting' do
expect(chef_run.node['gitlab']['geo-postgresql']['log_line_prefix']).to eql('%a')
expect(chef_run).to render_file('/var/opt/gitlab/geo-postgresql/data/postgresql.conf')
.with_content(/log_line_prefix = '%a'/)
end
it 'sets max_standby settings' do
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/max_standby_archive_delay = 60s/)
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/max_standby_streaming_delay = 120s/)
end
it 'sets archive settings' do
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/archive_mode = on/)
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/archive_command = 'command'/)
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/archive_timeout = 120/)
end
end
context 'version specific settings' do
it 'sets unix_socket_directory' do
expect(chef_run.node['gitlab']['geo-postgresql']['unix_socket_directory']).to eq('/var/opt/gitlab/geo-postgresql')
expect(chef_run.node['gitlab']['geo-postgresql']['unix_socket_directories']).to eq(nil)
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content { |content|
expect(content).to match(
/unix_socket_directory = '\/var\/opt\/gitlab\/geo-postgresql'/
)
expect(content).not_to match(
/unix_socket_directories = '\/var\/opt\/gitlab\/geo-postgresql'/
)
}
end
it 'sets checkpoint_segments' do
expect(chef_run.node['gitlab']['geo-postgresql']['checkpoint_segments']).to eq(10)
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/checkpoint_segments = 10/)
end
it 'does not set the max_replication_slots setting' do
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content { |content|
expect(content).to_not match(/max_replication_slots = /)
}
end
end
end
describe 'geo postgresql 9.6' do
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab::config', 'gitlab-ee::default') }
before do
allow(Gitlab).to receive(:[]).and_call_original
allow_any_instance_of(GeoPgHelper).to receive(:version).and_return('9.6.1')
allow_any_instance_of(GeoPgHelper).to receive(:database_version).and_return('9.6')
stub_gitlab_rb(geo_postgresql: {
enable: true
})
end
context 'version specific settings' do
it 'sets unix_socket_directories' do
expect(chef_run.node['gitlab']['geo-postgresql']['unix_socket_directory']).to eq('/var/opt/gitlab/geo-postgresql')
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content { |content|
expect(content).to match(
/unix_socket_directories = '\/var\/opt\/gitlab\/geo-postgresql'/
)
expect(content).not_to match(
/unix_socket_directory = '\/var\/opt\/gitlab\/geo-postgresql'/
)
}
end
it 'does not set checkpoint_segments' do
expect(chef_run).not_to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/checkpoint_segments = 10/)
end
it 'sets the max_replication_slots setting' do
expect(chef_run.node['gitlab']['geo-postgresql']['max_replication_slots']).to eq(0)
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/max_replication_slots = 0/)
end
it 'sets the synchronous_commit setting' do
expect(chef_run.node['gitlab']['geo-postgresql']['synchronous_commit']).to eq('on')
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/synchronous_commit = on/)
end
it 'sets the synchronous_commit setting' do
expect(chef_run.node['gitlab']['geo-postgresql']['synchronous_standby_names']).to eq('')
expect(chef_run).to render_file(
'/var/opt/gitlab/geo-postgresql/data/postgresql.conf'
).with_content(/synchronous_standby_names = ''/)
end
end
end

View File

@ -30,14 +30,6 @@ describe 'postgresql 9.2' do
.with_content(/log_line_prefix = ''/)
end
it 'sets checkpoint_segments' do
expect(chef_run.node['gitlab']['postgresql']['checkpoint_segments'])
.to eq(10)
expect(chef_run).to render_file(
'/var/opt/gitlab/postgresql/data/postgresql.conf'
).with_content(/checkpoint_segments = 10/)
end
it 'sets max_standby settings' do
expect(chef_run).to render_file(
'/var/opt/gitlab/postgresql/data/postgresql.conf'
@ -58,14 +50,6 @@ describe 'postgresql 9.2' do
'/var/opt/gitlab/postgresql/data/postgresql.conf'
).with_content(/archive_timeout = 60/)
end
it 'does not set the max_replication_slots setting' do
expect(chef_run).to render_file(
'/var/opt/gitlab/postgresql/data/postgresql.conf'
).with_content { |content|
expect(content).to_not match(/max_replication_slots = /)
}
end
end
context 'when user settings are set' do
@ -137,6 +121,22 @@ describe 'postgresql 9.2' do
}
end
it 'sets checkpoint_segments' do
expect(chef_run.node['gitlab']['postgresql']['checkpoint_segments'])
.to eq(10)
expect(chef_run).to render_file(
'/var/opt/gitlab/postgresql/data/postgresql.conf'
).with_content(/checkpoint_segments = 10/)
end
it 'does not set the max_replication_slots setting' do
expect(chef_run).to render_file(
'/var/opt/gitlab/postgresql/data/postgresql.conf'
).with_content { |content|
expect(content).to_not match(/max_replication_slots = /)
}
end
context 'running version differs from data version' do
before do
allow_any_instance_of(PgHelper).to receive(:version).and_return('9.6.1')

View File

@ -1,41 +1,77 @@
require 'chef_helper'
describe PgHelper do
shared_examples 'Postgres helpers' do |service_name, service_cmd|
let(:chef_run) do
ChefSpec::SoloRunner.new do |node|
node.set['gitlab']['postgresql']['data_dir'] = '/fakedir'
node.set['gitlab'][service_name]['data_dir'] = '/fakedir'
node.set['package']['install-dir'] = '/fake/install/dir'
end.converge('gitlab::default')
end.converge('gitlab::config')
end
let(:node) { chef_run.node }
let!(:helper) do
described_class.new(node)
end
before do
allow(VersionHelper).to receive(:version).with(
'/opt/gitlab/embedded/bin/psql --version'
).and_return('YYYYYYYY XXXXXXX')
@helper = PgHelper.new(node)
allow(VersionHelper).to receive(:version).with('/opt/gitlab/embedded/bin/psql --version') { 'YYYYYYYY XXXXXXX' }
end
it 'returns a valid version' do
expect(@helper.version).to eq('XXXXXXX')
it 'is associated with a valid service' do
# this is a validation to make sure we are passing a valid/existing service_name to the shared example
expect(node['gitlab'][service_name].to_h).not_to be_empty
end
it 'returns a valid database_version' do
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?).with(
'/fakedir/PG_VERSION'
).and_return(true)
allow(File).to receive(:read).and_call_original
allow(File).to receive(:read).with(
'/fakedir/PG_VERSION'
).and_return('111.222')
allow(Dir).to receive(:glob).with(
'/fake/install/dir/embedded/postgresql/*'
).and_return(['111.222.18', '222.333.11'])
# We mock this in chef_helper.rb. Overide the mock to call the original
allow_any_instance_of(PgHelper).to receive(:database_version).and_call_original
expect(@helper.database_version).to eq('111.222')
describe '#version' do
it 'returns a valid version' do
expect(helper.version).to eq('XXXXXXX')
end
end
describe '#database_version' do
it 'returns a valid database_version' do
allow(File).to receive(:exist?).and_call_original
allow(File).to receive(:exist?).with('/fakedir/PG_VERSION') { true }
allow(File).to receive(:read).and_call_original
allow(File).to receive(:read).with('/fakedir/PG_VERSION') { '111.222' }
allow(Dir).to receive(:glob).with('/fake/install/dir/embedded/postgresql/*') { %w(111.222.18 222.333.11) }
# We mock this in chef_helper.rb. Override the mock to call the original
allow_any_instance_of(described_class).to receive(:database_version).and_call_original
expect(helper.database_version).to eq('111.222')
end
end
describe '#extension_exists?' do
it 'returns whether an extension exists' do
expect(helper).to receive(:success?).with("/opt/gitlab/bin/#{service_cmd} -d 'template1' -c 'select name from pg_available_extensions' -A | grep -x myextension")
helper.extension_exists?('myextension')
end
end
describe '#extension_enabled?' do
it 'returns whether an extension exists' do
expect(helper).to receive(:success?).with("/opt/gitlab/bin/#{service_cmd} -d 'mydatabase' -c 'select extname from pg_extension' -A | grep -x myextension")
helper.extension_enabled?('myextension', 'mydatabase')
end
end
describe '#database_exists?' do
it 'returns whether a database exists' do
expect(helper).to receive(:success?).with("/opt/gitlab/bin/#{service_cmd} -d 'template1' -c 'select datname from pg_database' -A | grep -x mydatabase")
helper.database_exists?('mydatabase')
end
end
end
describe PgHelper do
include_examples 'Postgres helpers', 'postgresql', 'gitlab-psql'
end
describe GeoPgHelper do
include_examples 'Postgres helpers', 'geo-postgresql', 'gitlab-geo-psql'
end
describe OmnibusHelper do