Verified Commit 4b88e899 authored by Douglas Barbosa Alexandre's avatar Douglas Barbosa Alexandre
Browse files

Migrate Geo Tracking database configuration into database.yml

Put geo_secondary['db_*'] settings into database.yml under the
geo key instead of geo_database.yml.

Changelog: changed
parent b1a0ba14
......@@ -2687,6 +2687,7 @@ external_url 'GENERATED_EXTERNAL_URL'
# geo_secondary['db_sslrootcert'] = nil
# geo_secondary['db_sslca'] = nil
# geo_secondary['db_prepared_statements'] = false
# geo_secondary['db_database_tasks'] = true
################################################################################
## GitLab Geo Secondary Tracking Database (EE only)
......
......@@ -73,6 +73,7 @@ default['gitlab']['geo-secondary']['db_sslcompression'] = 0
default['gitlab']['geo-secondary']['db_sslrootcert'] = nil
default['gitlab']['geo-secondary']['db_sslca'] = nil
default['gitlab']['geo-secondary']['db_prepared_statements'] = false
default['gitlab']['geo-secondary']['db_database_tasks'] = true
###
# Geo: PostgreSQL (Tracking database)
......
module GeoSecondary
GEO_DB_MIGRATIONS_PATH = 'ee/db/geo/migrate'.freeze
GEO_SCHEMA_MIGRATIONS_PATH = 'ee/db/geo/schema_migrations'.freeze
class << self
def parse_variables
parse_database
end
def node
Gitlab[:node]
end
private
def parse_database
# If user hasn't specified a geo database, for now, we will use the
# geo_secondary[`db_*`] keys to populate one. In the future, we can
# deprecate geo_secondary[`db_*`] keys and ask users to explicitly
# set `gitlab_rails['databases']['geo']['db_*']` settings instead.
Gitlab['gitlab_rails']['databases'] ||= {}
Gitlab['gitlab_rails']['databases']['geo'] ||= { 'enable' => true }
if geo_secondary_enabled? && geo_database_enabled?
# Set default value for attributes of geo database based on
# geo_secondary[`db_*`] settings.
geo_database_attributes.each do |attribute|
Gitlab['gitlab_rails']['databases']['geo'][attribute] ||= Gitlab['geo_secondary'][attribute] || node['gitlab']['geo-secondary'][attribute]
end
# Set db_migrations_path since Geo migration lives in a non-default place
Gitlab['gitlab_rails']['databases']['geo']['db_migrations_paths'] = GEO_DB_MIGRATIONS_PATH
Gitlab['gitlab_rails']['databases']['geo']['db_schema_migrations_path'] = GEO_SCHEMA_MIGRATIONS_PATH
else
# Weed out the geo database settings if both Geo and database is not enabled
Gitlab['gitlab_rails']['databases'].delete('geo')
end
end
def geo_secondary_enabled?
Gitlab['geo_secondary_role']['enable'] || Gitlab['geo_secondary']['enable']
end
def geo_database_attributes
node['gitlab']['geo-secondary'].to_h.keys.select { |k| k.start_with?('db_') }
end
def geo_database_enabled?
Gitlab['gitlab_rails']['databases']['geo']['enable'] == true
end
end
end
......@@ -6,9 +6,4 @@ class GitlabGeoHelper < RailsMigrationHelper
@status_file_prefix = 'geo-db-migrate'
@attributes_node = node['gitlab']['geo-secondary']
end
def geo_database_configured?
database_geo_yml = ::File.join(node['gitlab']['gitlab-rails']['dir'], 'etc', 'database_geo.yml')
::File.exist?(database_geo_yml)
end
end
......@@ -25,19 +25,27 @@ postgresql_group = account_helper.postgresql_group
gitlab_rails_source_dir = '/opt/gitlab/embedded/service/gitlab-rails'
gitlab_rails_dir = node['gitlab']['gitlab-rails']['dir']
gitlab_rails_etc_dir = File.join(gitlab_rails_dir, "etc")
gitlab_rails_etc_dir = File.join(gitlab_rails_dir, 'etc')
dependent_services = %w(puma geo-logcursor sidekiq)
templatesymlink 'Create a database_geo.yml and create a symlink to Rails root' do
# TODO: To be removed in 15.0. See https://gitlab.com/gitlab-org/gitlab/-/issues/351946
templatesymlink 'Remove the deprecated database_geo.yml symlink' do
link_from File.join(gitlab_rails_source_dir, 'config/database_geo.yml')
link_to File.join(gitlab_rails_etc_dir, 'database_geo.yml')
source 'database_geo.yml.erb'
action :delete
end
templatesymlink 'Add the geo database settings to database.yml and create a symlink to Rails root' do
link_from File.join(gitlab_rails_source_dir, 'config/database.yml')
link_to File.join(gitlab_rails_etc_dir, 'database.yml')
source 'database.yml.erb'
cookbook 'gitlab'
owner 'root'
group account_helper.gitlab_group
mode '0640'
variables node['gitlab']['geo-secondary'].to_hash
variables node['gitlab']['gitlab-rails'].to_hash
notifies :run, 'ruby_block[Restart geo-secondary dependent services]'
end
......@@ -50,7 +58,7 @@ ruby_block 'Restart geo-secondary dependent services' do
action :nothing
end
# Make structure.sql writable for when we run `rake geo:db:migrate`
# Make structure.sql writable for when we run `rake db:migrate:geo`
file '/opt/gitlab/embedded/service/gitlab-rails/ee/db/geo/structure.sql' do
owner gitlab_user
end
......
......@@ -14,6 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
account_helper = AccountHelper.new(node)
omnibus_helper = OmnibusHelper.new(node)
gitlab_rails_source_dir = '/opt/gitlab/embedded/service/gitlab-rails'
......@@ -22,12 +23,24 @@ gitlab_rails_etc_dir = File.join(gitlab_rails_dir, "etc")
dependent_services = %w(puma sidekiq)
templatesymlink 'Removes database_geo.yml symlink' do
# TODO: To be removed in 15.0. See https://gitlab.com/gitlab-org/gitlab/-/issues/351946
templatesymlink 'Remove the deprecated database_geo.yml symlink' do
link_from File.join(gitlab_rails_source_dir, 'config/database_geo.yml')
link_to File.join(gitlab_rails_etc_dir, 'database_geo.yml')
action :delete
end
templatesymlink 'Removes the geo database settings from database.yml and create a symlink to Rails root' do
link_from File.join(gitlab_rails_source_dir, 'config/database.yml')
link_to File.join(gitlab_rails_etc_dir, 'database.yml')
source 'database.yml.erb'
cookbook 'gitlab'
owner 'root'
group account_helper.gitlab_group
mode '0640'
variables node['gitlab']['gitlab-rails'].to_hash
dependent_services.each do |svc|
notifies :restart, omnibus_helper.restart_service_resource(svc) if omnibus_helper.should_notify?(svc)
end
action :delete
end
......@@ -23,7 +23,7 @@ dependent_services << "runit_service[puma]" if omnibus_helper.should_notify?("pu
dependent_services << "sidekiq_service[sidekiq]" if omnibus_helper.should_notify?("sidekiq")
rails_migration "gitlab-geo tracking" do
rake_task 'geo:db:migrate'
rake_task 'db:migrate:geo'
logfile_prefix 'gitlab-geo-db-migrate'
helper migration_helper
......
......@@ -18,7 +18,8 @@ require_relative 'nginx.rb'
require_relative '../../gitaly/libraries/gitaly.rb'
module GitlabRails
ALLOWED_DATABASES = %w[main ci].freeze
ALLOWED_DATABASES = %w[main ci geo].freeze
MAIN_DATABASES = %w[main geo].freeze
SHARED_DATABASE_ATTRIBUTES = %w[db_host db_port db_database].freeze
class << self
......@@ -208,9 +209,9 @@ module GitlabRails
# settings
generate_main_database
# Weed out the databases that are either not allowed or not enabled explicitly (except for main)
# Weed out the databases that are either not allowed or not enabled explicitly (except for main and geo)
Gitlab['gitlab_rails']['databases'].to_h.each do |database, settings|
if database != 'main' && settings['enable'] != true
if !MAIN_DATABASES.include?(database) && settings['enable'] != true
Gitlab['gitlab_rails']['databases'].delete(database)
next
end
......@@ -221,10 +222,9 @@ module GitlabRails
end
end
# Set default value of settings for other databases based on values used
# in `main` database.
# Set default value of settings for other databases based on values used in `main` database.
Gitlab['gitlab_rails']['databases'].each_key do |database|
next if database == 'main'
next if MAIN_DATABASES.include?(database)
database_attributes.each do |attribute|
next unless Gitlab['gitlab_rails']['databases'][database][attribute].nil?
......
......@@ -10,6 +10,12 @@ production:
encoding: <%= attributes['db_encoding'] %>
collation: <%= attributes['db_collation'] %>
database: <%= attributes['db_database'] %>
<% if attributes.key?('db_migrations_paths') %>
migrations_paths: <%= quote(attributes['db_migrations_paths']) %>
<% end %>
<% if attributes.key?('db_schema_migrations_path') %>
schema_migrations_path: <%= quote(attributes['db_schema_migrations_path']) %>
<% end %>
username: <%= quote(attributes['db_username']) %>
password: <%= quote(attributes['db_password']) %>
host: <%= quote(attributes['db_host']) %>
......
# This file is managed by gitlab-ctl. Manual changes will be
# erased! To change the contents below, edit /etc/gitlab/gitlab.rb
# and run `sudo gitlab-ctl reconfigure`.
production:
adapter: <%= @db_adapter %>
encoding: <%= @db_encoding %>
collation: <%= @db_collation %>
database: <%= @db_database %>
username: <%= quote(@db_username) %>
password: <%= quote(@db_password) %>
host: <%= quote(@db_host) %>
port: <%= @db_port %>
socket: <%= quote(@db_socket) %>
sslmode: <%= quote(@db_sslmode) %>
sslcompression: <%= @db_sslcompression %>
sslrootcert: <%= quote(@db_sslrootcert) || quote(@db_sslca) %>
sslca: <%= quote(@db_sslca) || quote(@db_sslrootcert) %>
<% if !@db_sslcert.nil? && !@db_sslkey.nil? %>
sslcert: <%= quote(@db_sslcert) %>
sslkey: <%= quote(@db_sslkey) %>
<% end %>
load_balancing: <%= @db_load_balancing.to_json %>
prepared_statements: <%= @db_prepared_statements %>
statement_limit: <%= @db_statements_limit %>
connect_timeout: <%= @db_connect_timeout %>
keepalives: <%= @db_keepalives %>
keepalives_idle: <%= @db_keepalives_idle %>
keepalives_interval: <%= @db_keepalives_interval %>
keepalives_count: <%= @db_keepalives_count %>
tcp_user_timeout: <%= @db_tcp_user_timeout %>
application_name: <%= quote(@db_application_name) %>
variables:
statement_timeout: <%= @db_statement_timeout %>
......@@ -83,7 +83,7 @@ module Gitlab
attribute_block 'gitlab' do
# EE attributes
ee_attribute('geo_postgresql', priority: 20).use { GeoPostgresql }
ee_attribute('geo_secondary')
ee_attribute('geo_secondary', priority: 20).use { GeoSecondary }
ee_attribute('geo_logcursor')
ee_attribute('sentinel').use { Sentinel }
......
require 'chef_helper'
RSpec.describe 'gitlab-ee::geo-secondary_disable' do
let(:chef_run) { ChefSpec::SoloRunner.new(step_into: %w(templatesymlink)).converge('gitlab-ee::default') }
let(:database_yml_template) { chef_run.template('/var/opt/gitlab/gitlab-rails/etc/database.yml') }
let(:database_yml_file_content) { ChefSpec::Renderer.new(chef_run, database_yml_template).content }
let(:database_yml) { YAML.safe_load(database_yml_file_content, [], [], true, symbolize_names: true) }
before do
allow(Gitlab).to receive(:[]).and_call_original
end
describe 'when geo_secondary_role is disabled' do
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab-ee::default') }
before do
stub_gitlab_rb(geo_secondary_role: { enable: false })
end
context 'database_geo.yml' do
it 'removes the database_geo.yml symlink' do
expect(chef_run).to delete_templatesymlink('Remove the deprecated database_geo.yml symlink')
.with(link_to: '/var/opt/gitlab/gitlab-rails/etc/database_geo.yml',
link_from: '/opt/gitlab/embedded/service/gitlab-rails/config/database_geo.yml')
end
end
context 'database.yml' do
it 'renders database.yml without geo database' do
expect(database_yml[:production].keys).not_to include(:geo)
end
before { stub_gitlab_rb(geo_secondary_role: { enable: false }) }
context 'with geo database specified' do
before do
stub_gitlab_rb(
gitlab_rails: {
databases: {
geo: {
enable: true,
db_connect_timeout: 50
}
}
}
)
end
it 'removes database_geo.yml symlink' do
expect(chef_run).to delete_templatesymlink('Removes database_geo.yml symlink')
.with(link_to: '/var/opt/gitlab/gitlab-rails/etc/database_geo.yml',
link_from: '/opt/gitlab/embedded/service/gitlab-rails/config/database_geo.yml')
it 'renders database.yml without geo database' do
expect(database_yml[:production].keys).not_to include(:geo)
end
end
end
end
end
......@@ -2,37 +2,230 @@ require 'chef_helper'
RSpec.describe 'gitlab-ee::geo-secondary' do
let(:chef_run) { ChefSpec::SoloRunner.new(step_into: %w(templatesymlink)).converge('gitlab-ee::default') }
let(:database_geo_yml) { chef_run.template('/var/opt/gitlab/gitlab-rails/etc/database_geo.yml') }
let(:database_geo_yml_content) { ChefSpec::Renderer.new(chef_run, database_geo_yml).content }
let(:generated_yml_content) { YAML.safe_load(database_geo_yml_content, [], [], true, symbolize_names: true) }
let(:database_yml_template) { chef_run.template('/var/opt/gitlab/gitlab-rails/etc/database.yml') }
let(:database_yml_file_content) { ChefSpec::Renderer.new(chef_run, database_yml_template).content }
let(:database_yml) { YAML.safe_load(database_yml_file_content, [], [], true, symbolize_names: true) }
let(:default_content) do
{
main: {
adapter: 'postgresql',
application_name: nil,
collation: nil,
connect_timeout: nil,
database: "gitlabhq_production",
database_tasks: true,
encoding: "unicode",
host: "/var/opt/gitlab/postgresql",
keepalives: nil,
keepalives_count: nil,
keepalives_idle: nil,
keepalives_interval: nil,
load_balancing: {
hosts: []
},
password: nil,
port: 5432,
prepared_statements: false,
socket: nil,
sslca: nil,
sslcompression: 0,
sslmode: nil,
sslrootcert: nil,
statement_limit: 1000,
tcp_user_timeout: nil,
username: "gitlab",
variables: {
statement_timeout: nil
}
}
}
end
let(:default_geo_content) do
{
geo: {
adapter: 'postgresql',
application_name: nil,
collation: nil,
connect_timeout: nil,
database: "gitlabhq_geo_production",
database_tasks: true,
migrations_paths: "ee/db/geo/migrate",
schema_migrations_path: "ee/db/geo/schema_migrations",
encoding: "unicode",
host: "/var/opt/gitlab/geo-postgresql",
keepalives: nil,
keepalives_count: nil,
keepalives_idle: nil,
keepalives_interval: nil,
load_balancing: {
hosts: []
},
password: nil,
port: 5431,
prepared_statements: false,
socket: nil,
sslca: nil,
sslcompression: 0,
sslmode: nil,
sslrootcert: nil,
statement_limit: nil,
tcp_user_timeout: nil,
username: "gitlab_geo",
variables: {
statement_timeout: nil
}
}
}
end
before do
allow(Gitlab).to receive(:[]).and_call_original
end
describe 'when geo_secondary_role is disabled' do
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab-ee::default') }
shared_examples 'renders database.yml without geo database' do
context 'database_geo.yml' do
it 'removes the database_geo.yml symlink' do
expect(chef_run).to delete_templatesymlink('Remove the deprecated database_geo.yml symlink')
.with(link_to: '/var/opt/gitlab/gitlab-rails/etc/database_geo.yml',
link_from: '/opt/gitlab/embedded/service/gitlab-rails/config/database_geo.yml')
end
end
before { stub_gitlab_rb(geo_secondary_role: { enable: false }) }
context 'database.yml' do
it 'renders database.yml without geo database' do
expect(database_yml[:production].keys).not_to include(:geo)
end
it 'does not render the geo-secondary files' do
expect(chef_run).not_to render_file('/opt/gitlab/embedded/service/gitlab-rails/config/database_geo.yml')
expect(chef_run).not_to render_file('/var/opt/gitlab/gitlab-rails/etc/database_geo.yml')
context 'with geo database specified' do
before do
stub_gitlab_rb(
gitlab_rails: {
databases: {
geo: {
enable: true,
db_connect_timeout: 50
}
}
}
)
end
it 'renders database.yml without geo database' do
expect(database_yml[:production].keys).not_to include(:geo)
end
end
end
end
describe 'when geo_secondary_role is disabled but geo-postgresql enabled' do
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab-ee::default') }
shared_examples 'renders database.yml with both main and geo databases' do
context 'database_geo.yml' do
it 'removes the database_geo.yml symlink' do
expect(chef_run).to delete_templatesymlink('Remove the deprecated database_geo.yml symlink')
.with(link_to: '/var/opt/gitlab/gitlab-rails/etc/database_geo.yml',
link_from: '/opt/gitlab/embedded/service/gitlab-rails/config/database_geo.yml')
end
end
context 'database.yml' do
context 'with default settings' do
it 'renders database.yml with main stanza first' do
expect(database_yml_file_content).to match("production:\n main:")
end
it 'renders database.yml with both main and geo databases using default values' do
expected_output = default_content.merge(default_geo_content)
expect(database_yml[:production]).to eq(expected_output)
end
end
context 'with user provided settings' do
context "via top level geo_secondary['db_*'] keys" do
before do
stub_gitlab_rb(
geo_secondary: {
db_database: 'foo',
db_sslcompression: 1
}
)
end
it 'renders database.yml with user specified values for geo database' do
expect(database_yml[:production][:geo][:database]).to eq('foo')
expect(database_yml[:production][:geo][:sslcompression]).to eq(1)
end
end
context "via gitlab_rails['databases']['geo'] settings" do
before do
stub_gitlab_rb(
gitlab_rails: {
databases: {
geo: {
enable: true,
db_database: 'bar',
db_sslcompression: 1
}
}
}
)
end
it 'renders database.yml with user specified values for geo database' do
expect(database_yml[:production][:geo][:database]).to eq('bar')
expect(database_yml[:production][:geo][:sslcompression]).to eq(1)
end
end
end
context 'with geo database specified but not enabled' do
before do
stub_gitlab_rb(
gitlab_rails: {
databases: {
main: {
db_connect_timeout: 30
},
geo: {
db_connect_timeout: 50
}
}
}
)
end
it 'renders database.yml without geo database' do
expect(database_yml[:production].keys).not_to include(:geo)
end
end
context 'dependent services' do
let(:templatesymlink) { chef_run.templatesymlink('Add the geo database settings to database.yml and create a symlink to Rails root') }
it 'triggers dependent services notifications' do
expect(templatesymlink).to notify('ruby_block[Restart geo-secondary dependent services]').to(:run).delayed
end
end
end
end
describe 'when geo_secondary_role is disabled' do
before do
stub_gitlab_rb(geo_secondary_role: { enable: false })
end
it_behaves_like 'renders database.yml without geo database'
end
describe 'when geo_secondary_role is disabled but geo-postgresql enabled' do
before do
stub_gitlab_rb(geo_secondary_role: { enable: false },
geo_postgresql: { enable: true })
end
it 'does not render the geo-secondary files' do
expect(chef_run).not_to render_file('/opt/gitlab/embedded/service/gitlab-rails/config/database_geo.yml')
expect(chef_run).not_to render_file('/var/opt/gitlab/gitlab-rails/etc/database_geo.yml')
end
it_behaves_like 'renders database.yml without geo database'
end
describe 'when gitlab_rails is disabled, but geo_secondary_role is enabled' do
......@@ -44,7 +237,7 @@ RSpec.describe 'gitlab-ee::geo-secondary' do
end
it 'does not render the geo-secondary files' do
expect(chef_run).not_to create_templatesymlink('Create a database_geo.yml and create a symlink to Rails root')
expect(chef_run).not_to create_templatesymlink('Add the geo database settings to database.yml and create a symlink to Rails root')
end
end
......@@ -109,15 +302,10 @@ RSpec.describe 'gitlab-ee::geo-secondary' do
context 'when geo_secondary_role is enabled but geo-postgresql is disabled' do
before do
stub_gitlab_rb(geo_secondary_role: { enable: true },
geo_postgresql: { enable: false },
geo_secondary: {
db_host: '1.1.1.1',
db_password: 'password',
db_port: '5431'