# HG changeset patch # User Balasankar 'Balu' C <balasankar@gitlab.com> # Date 1711996371 0 # Mon Apr 01 18:32:51 2024 +0000 # Node ID 148acfeedb99ad38e676d489071e783cd890583e # Parent a03e6c9b33d970ba1e2f06c7e268492b7545ed3c Move Redis server information to NewRedisHelper - Continue conversion to the new style redis helper with refactors against the redis server functionality methods Signed-off-by: Balasankar 'Balu' C <balasankar@gitlab.com> diff --git a/files/gitlab-cookbooks/gitlab/libraries/redis_helper.rb b/files/gitlab-cookbooks/gitlab/libraries/redis_helper.rb --- a/files/gitlab-cookbooks/gitlab/libraries/redis_helper.rb +++ b/files/gitlab-cookbooks/gitlab/libraries/redis_helper.rb @@ -116,90 +116,6 @@ end end - def running_version - return unless OmnibusHelper.new(@node).service_up?('redis') - - commands = ['/opt/gitlab/embedded/bin/redis-cli'] - commands << redis_cli_connect_options - commands << "INFO" - command = commands.join(" ") - - command_output = VersionHelper.version(command) - raise "Execution of the command `#{command}` failed" unless command_output - - version_match = command_output.match(/redis_version:(?<redis_version>\d*\.\d*\.\d*)/) - raise "Execution of the command `#{command}` generated unexpected output `#{command_output.strip}`" unless version_match - - version_match['redis_version'] - end - - def installed_version - return unless OmnibusHelper.new(@node).service_up?('redis') - - command = '/opt/gitlab/embedded/bin/redis-server --version' - - command_output = VersionHelper.version(command) - raise "Execution of the command `#{command}` failed" unless command_output - - version_match = command_output.match(/Redis server v=(?<redis_version>\d*\.\d*\.\d*)/) - raise "Execution of the command `#{command}` generated unexpected output `#{command_output.strip}`" unless version_match - - version_match['redis_version'] - end - - def redis_cli_connect_options - args = [] - if RedisHelper::Checks.is_redis_tcp? - args = redis_cli_tcp_connect_options(args) - else - args << "-s #{redis['unixsocket']}" - end - - args << "-a '#{Gitlab['redis']['password']}'" if Gitlab['redis']['password'] - - args - end - - def redis_cli_tcp_connect_options(args) - args << ["-h #{redis['bind']}"] - port = redis['port'].to_i - - if port.zero? - args = redis_cli_tls_options(args) - else - args << "-p #{port}" - end - - args - end - - def redis_cli_tls_options(args) - tls_port = redis['tls_port'].to_i - - args << "--tls" - args << "-p #{tls_port}" - args << "--cacert '#{redis['tls_ca_cert_file']}'" if redis['tls_ca_cert_file'] - args << "--cacertdir '#{redis['tls_ca_cert_dir']}'" if redis['tls_ca_cert_dir'] - - return args unless client_certs_required? - - raise "Redis TLS client authentication requires redis['tls_cert_file'] and redis['tls_key_file'] options" unless client_cert_and_key_available? - - args << "--cert '#{redis['tls_cert_file']}'" - args << "--key '#{redis['tls_key_file']}'" - - args - end - - def client_certs_required? - redis['tls_auth_clients'] == 'yes' - end - - def client_cert_and_key_available? - redis['tls_cert_file'] && !redis['tls_cert_file'].empty? && - redis['tls_key_file'] && !redis['tls_key_file'].empty? - end - class Checks class << self def is_redis_tcp? diff --git a/files/gitlab-cookbooks/package/libraries/helpers/new_redis_helper/server.rb b/files/gitlab-cookbooks/package/libraries/helpers/new_redis_helper/server.rb new file mode 100644 --- /dev/null +++ b/files/gitlab-cookbooks/package/libraries/helpers/new_redis_helper/server.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +require_relative '../version_helper' + +module NewRedisHelper + class Server < NewRedisHelper::Base + def installed_version + return unless OmnibusHelper.new(@node).service_up?('redis') + + command = '/opt/gitlab/embedded/bin/redis-server --version' + + command_output = VersionHelper.version(command) + raise "Execution of the command `#{command}` failed" unless command_output + + version_match = command_output.match(/Redis server v=(?<redis_version>\d*\.\d*\.\d*)/) + raise "Execution of the command `#{command}` generated unexpected output `#{command_output.strip}`" unless version_match + + version_match['redis_version'] + end + + def running_version + return unless OmnibusHelper.new(@node).service_up?('redis') + + commands = ['/opt/gitlab/embedded/bin/redis-cli'] + commands << redis_cli_connect_options + commands << "INFO" + command = commands.join(" ") + + command_output = VersionHelper.version(command) + raise "Execution of the command `#{command}` failed" unless command_output + + version_match = command_output.match(/redis_version:(?<redis_version>\d*\.\d*\.\d*)/) + raise "Execution of the command `#{command}` generated unexpected output `#{command_output.strip}`" unless version_match + + version_match['redis_version'] + end + + private + + def redis_cli_connect_options + args = [] + if redis_server_over_tcp? + args = redis_cli_tcp_connect_options(args) + else + args << "-s #{redis['unixsocket']}" + end + + args << "-a '#{redis['password']}'" if redis['password'] + + args + end + + def redis_cli_tcp_connect_options(args) + args << ["-h #{redis['bind']}"] + port = redis['port'].to_i + + if port.zero? + args = redis_cli_tls_options(args) + else + args << "-p #{port}" + end + + args + end + + def redis_cli_tls_options(args) + tls_port = redis['tls_port'].to_i + + args << "--tls" + args << "-p #{tls_port}" + args << "--cacert '#{redis['tls_ca_cert_file']}'" if redis['tls_ca_cert_file'] + args << "--cacertdir '#{redis['tls_ca_cert_dir']}'" if redis['tls_ca_cert_dir'] + + return args unless client_certs_required? + + raise "Redis TLS client authentication requires redis['tls_cert_file'] and redis['tls_key_file'] options" unless client_cert_and_key_available? + + args << "--cert '#{redis['tls_cert_file']}'" + args << "--key '#{redis['tls_key_file']}'" + + args + end + + def client_certs_required? + redis['tls_auth_clients'] == 'yes' + end + + def client_cert_and_key_available? + redis['tls_cert_file'] && !redis['tls_cert_file'].empty? && + redis['tls_key_file'] && !redis['tls_key_file'].empty? + end + end +end diff --git a/files/gitlab-cookbooks/redis/resources/service.rb b/files/gitlab-cookbooks/redis/resources/service.rb --- a/files/gitlab-cookbooks/redis/resources/service.rb +++ b/files/gitlab-cookbooks/redis/resources/service.rb @@ -4,7 +4,7 @@ property :dir, String, default: lazy { node['redis']['dir'] } property :account_helper, default: lazy { AccountHelper.new(node) }, sensitive: true property :omnibus_helper, default: lazy { OmnibusHelper.new(node) }, sensitive: true -property :redis_helper, default: lazy { RedisHelper.new(node) }, sensitive: true +property :redis_helper, default: lazy { NewRedisHelper::Server.new(node) }, sensitive: true property :runit_sv_timeout, [Integer, nil], default: lazy { node['redis']['runit_sv_timeout'] } property :logfiles_helper, default: lazy { LogfilesHelper.new(node) }, sensitive: true diff --git a/spec/chef/cookbooks/gitlab/libraries/redis_helper_spec.rb b/spec/chef/cookbooks/gitlab/libraries/redis_helper_spec.rb --- a/spec/chef/cookbooks/gitlab/libraries/redis_helper_spec.rb +++ b/spec/chef/cookbooks/gitlab/libraries/redis_helper_spec.rb @@ -233,139 +233,6 @@ end end - describe '#running_version' do - let(:redis_cli_output) do - <<~MSG - # Server - redis_version:3.2.12 - redis_git_sha1:00000000 - redis_git_dirty:0 - redis_build_id:e16da30f4a0a7845 - redis_mode:standalone - os:Linux 4.15.0-58-generic x86_64 - MSG - end - - before do - # Un-doing the stub added in chef_helper - allow_any_instance_of(described_class).to receive(:running_version).and_call_original - allow(Gitlab).to receive(:[]).and_call_original - allow(VersionHelper).to receive(:version).with(/redis-cli.*INFO/).and_return(redis_cli_output) - end - - context 'when redis is not running' do - it 'returns nil' do - allow_any_instance_of(OmnibusHelper).to receive(:service_up?).with('redis').and_return(false) - - expect(subject.running_version).to be_nil - end - end - - context 'when redis is running' do - before do - allow_any_instance_of(OmnibusHelper).to receive(:service_up?).with('redis').and_return(true) - end - context 'over socket' do - it 'calls VersionHelper.version with correct arguments' do - expect(VersionHelper).to receive(:version).with('/opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/redis.socket INFO') - - subject.running_version - end - end - - context 'over TCP' do - context 'on non-TLS port' do - before do - stub_gitlab_rb( - redis: { - bind: '0.0.0.0', - port: 6379 - } - ) - end - - it 'calls VersionHelper.version with correct arguments' do - expect(VersionHelper).to receive(:version).with('/opt/gitlab/embedded/bin/redis-cli -h 0.0.0.0 -p 6379 INFO') - - subject.running_version - end - end - - context 'on TLS port' do - before do - stub_gitlab_rb( - redis: { - bind: '0.0.0.0', - tls_port: 6380, - tls_cert_file: '/tmp/self_signed.crt', - tls_key_file: '/tmp/self_signed.key', - tls_auth_clients: 'yes' - } - ) - end - - it 'calls VersionHelper.version with correct arguments' do - expected_args = "-h 0.0.0.0 --tls -p 6380 --cacert '/opt/gitlab/embedded/ssl/certs/cacert.pem' --cacertdir '/opt/gitlab/embedded/ssl/certs/' --cert '/tmp/self_signed.crt' --key '/tmp/self_signed.key'" - expect(VersionHelper).to receive(:version).with("/opt/gitlab/embedded/bin/redis-cli #{expected_args} INFO") - - subject.running_version - end - end - end - - context 'with a Redis password specified' do - before do - stub_gitlab_rb( - redis: { - bind: '0.0.0.0', - port: 6379, - password: 'toomanysecrets' - } - ) - end - - it 'it passes password to the command' do - expect(VersionHelper).to receive(:version).with("/opt/gitlab/embedded/bin/redis-cli -h 0.0.0.0 -p 6379 -a 'toomanysecrets' INFO") - - subject.running_version - end - end - - it 'parses version from redis-cli output properly' do - expect(subject.running_version).to eq('3.2.12') - end - end - end - - describe '#installed_version' do - let(:redis_server_output) { 'Redis server v=3.2.12 sha=00000000:0 malloc=jemalloc-4.0.3 bits=64 build=e16da30f4a0a7845' } - - before do - # Un-doing the stub added in chef_helper - allow_any_instance_of(described_class).to receive(:installed_version).and_call_original - allow(Gitlab).to receive(:[]).and_call_original - allow(VersionHelper).to receive(:version).with(/redis-server --version/).and_return(redis_server_output) - end - - context 'when redis is not running' do - it 'returns nil' do - allow_any_instance_of(OmnibusHelper).to receive(:service_up?).with('redis').and_return(false) - - expect(subject.installed_version).to be_nil - end - end - - context 'when redis is running' do - before do - allow_any_instance_of(OmnibusHelper).to receive(:service_up?).with('redis').and_return(true) - end - - it 'parses redis-server output properly' do - expect(subject.installed_version).to eq('3.2.12') - end - end - end - describe '#validate_instance_shard_config' do before { allow(Gitlab).to receive(:[]).and_call_original } diff --git a/spec/chef/cookbooks/package/libraries/new_redis_helper/server_spec.rb b/spec/chef/cookbooks/package/libraries/new_redis_helper/server_spec.rb new file mode 100644 --- /dev/null +++ b/spec/chef/cookbooks/package/libraries/new_redis_helper/server_spec.rb @@ -0,0 +1,142 @@ +require 'chef_helper' + +RSpec.describe NewRedisHelper::Server do + let(:chef_run) { ChefSpec::SoloRunner.new(step_into: %w(templatesymlink)).converge('gitlab::default') } + + subject { described_class.new(chef_run.node) } + + describe '#running_version' do + let(:redis_cli_output) do + <<~MSG + # Server + redis_version:3.2.12 + redis_git_sha1:00000000 + redis_git_dirty:0 + redis_build_id:e16da30f4a0a7845 + redis_mode:standalone + os:Linux 4.15.0-58-generic x86_64 + MSG + end + + before do + # Un-doing the stub added in chef_helper + allow_any_instance_of(described_class).to receive(:running_version).and_call_original + allow(Gitlab).to receive(:[]).and_call_original + allow(VersionHelper).to receive(:version).with(/redis-cli.*INFO/).and_return(redis_cli_output) + allow_any_instance_of(OmnibusHelper).to receive(:service_up?).and_call_original + end + + context 'when redis is not running' do + it 'returns nil' do + allow_any_instance_of(OmnibusHelper).to receive(:service_up?).with('redis').and_return(false) + + expect(subject.running_version).to be_nil + end + end + + context 'when redis is running' do + before do + allow_any_instance_of(OmnibusHelper).to receive(:service_up?).with('redis').and_return(true) + end + context 'over socket' do + it 'calls VersionHelper.version with correct arguments' do + expect(VersionHelper).to receive(:version).with('/opt/gitlab/embedded/bin/redis-cli -s /var/opt/gitlab/redis/redis.socket INFO') + + subject.running_version + end + end + + context 'over TCP' do + context 'on non-TLS port' do + before do + stub_gitlab_rb( + redis: { + bind: '0.0.0.0', + port: 6379 + } + ) + end + + it 'calls VersionHelper.version with correct arguments' do + expect(VersionHelper).to receive(:version).with('/opt/gitlab/embedded/bin/redis-cli -h 0.0.0.0 -p 6379 INFO') + + subject.running_version + end + end + + context 'on TLS port' do + before do + stub_gitlab_rb( + redis: { + bind: '0.0.0.0', + tls_port: 6380, + tls_cert_file: '/tmp/self_signed.crt', + tls_key_file: '/tmp/self_signed.key', + tls_auth_clients: 'yes' + } + ) + end + + it 'calls VersionHelper.version with correct arguments' do + expected_args = "-h 0.0.0.0 --tls -p 6380 --cacert '/opt/gitlab/embedded/ssl/certs/cacert.pem' --cacertdir '/opt/gitlab/embedded/ssl/certs/' --cert '/tmp/self_signed.crt' --key '/tmp/self_signed.key'" + expect(VersionHelper).to receive(:version).with("/opt/gitlab/embedded/bin/redis-cli #{expected_args} INFO") + + subject.running_version + end + end + end + + context 'with a Redis password specified' do + before do + stub_gitlab_rb( + redis: { + bind: '0.0.0.0', + port: 6379, + password: 'toomanysecrets' + } + ) + end + + it 'it passes password to the command' do + expect(VersionHelper).to receive(:version).with("/opt/gitlab/embedded/bin/redis-cli -h 0.0.0.0 -p 6379 -a 'toomanysecrets' INFO") + + subject.running_version + end + end + + it 'parses version from redis-cli output properly' do + expect(subject.running_version).to eq('3.2.12') + end + end + end + + describe '#installed_version' do + let(:redis_server_output) { 'Redis server v=3.2.12 sha=00000000:0 malloc=jemalloc-4.0.3 bits=64 build=e16da30f4a0a7845' } + + before do + # Un-doing the stub added in chef_helper + allow_any_instance_of(described_class).to receive(:installed_version).and_call_original + allow(Gitlab).to receive(:[]).and_call_original + allow(VersionHelper).to receive(:version).with(/redis-server --version/).and_return(redis_server_output) + allow_any_instance_of(OmnibusHelper).to receive(:service_up?).and_call_original + end + + context 'when redis is not running' do + it 'returns nil' do + allow_any_instance_of(OmnibusHelper).to receive(:service_up?).with('redis').and_return(false) + + expect(subject.installed_version).to be_nil + end + end + + context 'when redis is running' do + before do + allow_any_instance_of(OmnibusHelper).to receive(:service_up?).with('redis').and_return(true) + end + + it 'parses redis-server output properly' do + expect(subject.installed_version).to eq('3.2.12') + end + end + end +end diff --git a/spec/chef/cookbooks/redis/recipes/redis_spec.rb b/spec/chef/cookbooks/redis/recipes/redis_spec.rb --- a/spec/chef/cookbooks/redis/recipes/redis_spec.rb +++ b/spec/chef/cookbooks/redis/recipes/redis_spec.rb @@ -74,8 +74,8 @@ describe 'pending restart check' do context 'when running version is same as installed version' do before do - allow_any_instance_of(RedisHelper).to receive(:running_version).and_return('3.2.12') - allow_any_instance_of(RedisHelper).to receive(:installed_version).and_return('3.2.12') + allow_any_instance_of(NewRedisHelper::Server).to receive(:running_version).and_return('3.2.12') + allow_any_instance_of(NewRedisHelper::Server).to receive(:installed_version).and_return('3.2.12') end it 'does not raise a warning' do @@ -85,8 +85,8 @@ context 'when running version is different than installed version' do before do - allow_any_instance_of(RedisHelper).to receive(:running_version).and_return('3.2.12') - allow_any_instance_of(RedisHelper).to receive(:installed_version).and_return('5.0.9') + allow_any_instance_of(NewRedisHelper::Server).to receive(:running_version).and_return('3.2.12') + allow_any_instance_of(NewRedisHelper::Server).to receive(:installed_version).and_return('5.0.9') end it 'raises a warning' do diff --git a/spec/chef_helper.rb b/spec/chef_helper.rb --- a/spec/chef_helper.rb +++ b/spec/chef_helper.rb @@ -70,8 +70,8 @@ allow(VersionHelper).to receive(:version).with('/opt/gitlab/embedded/bin/psql --version').and_return('fake_psql_version') allow(VersionHelper).to receive(:version).with('cat /opt/gitlab/embedded/service/mattermost/VERSION').and_return('foobar') allow(VersionHelper).to receive(:version).with(/-[-]?version/).and_return('foobar') - allow_any_instance_of(RedisHelper).to receive(:installed_version).and_return('3.2.12') - allow_any_instance_of(RedisHelper).to receive(:running_version).and_return('3.2.12') + allow_any_instance_of(NewRedisHelper::Server).to receive(:installed_version).and_return('3.2.12') + allow_any_instance_of(NewRedisHelper::Server).to receive(:running_version).and_return('3.2.12') allow_any_instance_of(ConsulHelper).to receive(:installed_version).and_return('1.9.6') allow_any_instance_of(ConsulHelper).to receive(:running_version).and_return('1.9.6') stub_command('/sbin/init --version | grep upstart')