Merge branch 'brodock/sentinel_daemon' into 'master'

Redis Sentinel daemon

Related to #1565 !996 

Updated documentation: 
* CE: gitlab-org/gitlab-ce!6471
* EE: ~~gitlab-org/gitlab-ee!786~~ (see: https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/1000#note_17084207)

Checklist
------------

- [x] Create a template for `sentinel.conf`
  - [x] `port` is configurable
  - [x] `working-directory` is configurable
  - [x] `auth-pass` is configurable
  - [x] `monitor` master instance is configurable
  - [x] `down-after-milliseconds` is configurable
  - [x] `failover-timeout` is configurable
  - [x] `myid` is configurable or will fallback to generated and  stored in `.json` file after first `reconfigure`
- [x] Create a service definition for sentinel daemon (definitions/sentinel_service.rb)
- [x] Sentinel code is EE package only (`gitlab-ee` recipe)
- [x] Add sentinel to runit init system
- [x] Sentinel should be enabled only when specific `enabled` flag is present
- [x] Sentinel-disable recipe
- [x] Generate specific `redis://` URL pointing to `master-name` when sentinels are present

Testplan
-----------

- Clean install:
  - [x] Works with default / unmodified configuration parameters
  - [x] Can enable managed sentinel
  - [x] Can disable managed sentinel (stop service and remove from runit)
  - [x] Can point to external (managed/unmanaged) sentinel service
  - [x] Works with multiple sentinel instances.
- Existing previous version
  - [x] Can upgrade with default / unmodified configuration parameters
  - [x] Can enable managed sentinel
  - [x] Can disable managed sentinel (stop service and remove from runit)

See merge request !1000
This commit is contained in:
Marin Jankovski 2016-11-09 09:53:36 +00:00
commit 457c47649e
32 changed files with 1159 additions and 109 deletions

View File

@ -21,16 +21,32 @@ name "gitlab-cookbooks"
license "Apache-2.0"
license_file File.expand_path("LICENSE", Omnibus::Config.project_root)
source :path => File.expand_path("files/gitlab-cookbooks", Omnibus::Config.project_root)
EE = system("#{Omnibus::Config.project_root}/support/is_gitlab_ee.sh")
source path: File.expand_path("files/gitlab-cookbooks", Omnibus::Config.project_root)
build do
cookbook_name = 'gitlab'
command "mkdir -p #{install_dir}/embedded/cookbooks"
sync "./", "#{install_dir}/embedded/cookbooks/"
# If EE package, use a different master cookbook
if EE
cookbook_name = 'gitlab-ee'
else
delete "#{install_dir}/embedded/cookbooks/gitlab-ee"
end
# Create a package cookbook.
command "mkdir -p #{install_dir}/embedded/cookbooks/package/attributes"
erb :dest => "#{install_dir}/embedded/cookbooks/package/attributes/default.rb",
:source => "cookbook_packages_default.erb",
:mode => 0755,
:vars => { :install_dir => project.install_dir }
erb :dest => "#{install_dir}/embedded/cookbooks/dna.json",
:source => "dna.json.erb",
:mode => 0644,
:vars => { :master_cookbook => cookbook_name }
end

View File

@ -0,0 +1,3 @@
{
"run_list": [ "recipe[<%= master_cookbook %>]" ]
}

View File

@ -549,6 +549,14 @@ external_url 'GENERATED_EXTERNAL_URL'
# redis['uid'] = nil
# redis['gid'] = nil
## To enable only redis service in this machine, uncomment
## one of the lines below (choose master or slave instance types).
##
## For more details please see:
## https://docs.gitlab.com/ce/administration/high_availability/redis.html
# redis_master_role['enable'] = true
# redis_slave_role['enable'] = true
## Redis Sentinel support
## You need a master slave redis replication to be able to do failover
## Please read the documentation before enabling it to understand the
@ -557,15 +565,79 @@ external_url 'GENERATED_EXTERNAL_URL'
## Redis TCP support (will disable UNIX socket transport)
# redis['bind'] = '0.0.0.0' # or specify an IP to bind to a single one
# redis['port'] = 6379
# redis['password'] = 'redis-password-goes-here'
## Master redis instance (if this will act as a master instance uncomment and fill below)
# redis['password'] = '<huge password string here>' # Only define this in the master instance
##
## Replication support
##
## Slave redis instance (if this will act as a slave / standby redis instance uncomment and fill below)
## Slave redis instance
# redis['master'] = false # by default this is true
## Slave and Sentinel shared configuration
## Both need to point to the master redis instance to get replication and heartbeat monitoring
# redis['master_name'] = 'gitlab-redis'
# redis['master_ip'] = nil
# redis['master_port'] = nil
# redis['master_password'] = nil
# redis['master_port'] = 6379
## Master password should have the same value defined in redis['password']
## to enable the instance to transition to/from master/slave in a failover event.
# redis['master_password'] = 'redis-password-goes-here'
########################
# GitLab Sentinel (EE) #
########################
## Make sure you configured all redis['master_*'] keys above before continuing.
## To enable sentinel and disable all other services in this machine,
## uncomment the line below (if you've enabled Redis role, it will keep it).
##
## For more details please see:
## https://docs.gitlab.com/ce/administration/high_availability/redis.html
# redis_sentinel_role['enable'] = true
# sentinel['enable'] = true
# sentinel['bind'] = '0.0.0.0' # bind to all interfaces, uncomment to specify an IP and bind to a single one
# sentinel['port'] = 26379 # uncomment to change default port
## Quorum must reflect the amount of voting sentinels it take to start a failover.
## Value must NOT be greater then the ammount of sentinels.
##
## The quorum can be used to tune Sentinel in two ways:
## 1. If a the quorum is set to a value smaller than the majority of Sentinels
## we deploy, we are basically making Sentinel more sensible to master failures,
## triggering a failover as soon as even just a minority of Sentinels is no longer
## able to talk with the master.
## 1. If a quorum is set to a value greater than the majority of Sentinels, we are
## making Sentinel able to failover only when there are a very large number (larger
## than majority) of well connected Sentinels which agree about the master being down.s
# sentinel['quorum'] = 1
## Consider unresponsive server down after x amount of ms.
# sentinel['down_after_milliseconds'] = 10000
## Specifies the failover timeout in milliseconds. It is used in many ways:
##
## - The time needed to re-start a failover after a previous failover was
## already tried against the same master by a given Sentinel, is two
## times the failover timeout.
##
## - The time needed for a slave replicating to a wrong master according
## to a Sentinel current configuration, to be forced to replicate
## with the right master, is exactly the failover timeout (counting since
## the moment a Sentinel detected the misconfiguration).
##
## - The time needed to cancel a failover that is already in progress but
## did not produced any configuration change (SLAVEOF NO ONE yet not
## acknowledged by the promoted slave).
##
## - The maximum time a failover in progress waits for all the slaves to be
## reconfigured as slaves of the new master. However even after this time
## the slaves will be reconfigured by the Sentinels anyway, but not with
## the exact parallel-syncs progression as specified.
# sentinel['failover_timeout'] = 60000
#####################
# GitLab Web server #

View File

@ -1,3 +0,0 @@
{
"run_list": [ "recipe[gitlab]" ]
}

View File

@ -0,0 +1,27 @@
#
# 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.
#
default['gitlab']['sentinel']['enable'] = false
default['gitlab']['sentinel']['bind'] = '0.0.0.0'
default['gitlab']['sentinel']['dir'] = '/var/opt/gitlab/sentinel'
default['gitlab']['sentinel']['log_directory'] = '/var/log/gitlab/sentinel'
default['gitlab']['sentinel']['ha'] = false
default['gitlab']['sentinel']['port'] = 26379
default['gitlab']['sentinel']['quorum'] = 1
default['gitlab']['sentinel']['down_after_milliseconds'] = 10000
default['gitlab']['sentinel']['failover_timeout'] = 60000
default['gitlab']['sentinel']['myid'] = nil

View File

@ -0,0 +1,95 @@
#
# 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.
#
define :sentinel_service, config_path: nil, redis_configuration: {}, sentinel_configuration: {}, logging_configuration: {}, action: :enable do
redis = params[:redis_configuration]
sentinel = params[:sentinel_configuration]
logging = params[:logging_configuration]
config_path = params[:config_path]
sentinel_service_name = 'sentinel'
sentinel_dir = sentinel['dir']
sentinel_log_dir = sentinel['log_directory']
redis_user = AccountHelper.new(node).redis_user
account 'user and group for sentinel' do
username redis_user
uid node['gitlab']['redis']['uid']
ugid redis_user
groupname redis_user
gid node['gitlab']['redis']['gid']
shell node['gitlab']['redis']['shell']
home node['gitlab']['redis']['home']
manage node['gitlab']['manage-accounts']['enable']
end
case params[:action]
when :enable
directory sentinel_dir do
owner redis['username']
group redis['group']
mode '0750'
end
directory sentinel_log_dir do
owner redis['username']
mode '0700'
end
runit_service sentinel_service_name do
down redis['ha']
template_name sentinel_service_name
options(
{
user: redis['username'],
config_path: config_path,
log_directory: sentinel_log_dir
}.merge(params)
)
log_options redis.to_hash.merge(logging.to_hash)
end
template config_path do
source 'sentinel.conf.erb'
owner redis['username']
mode '0644'
variables(
{
redis: redis.to_hash,
sentinel: sentinel.to_hash
}
)
notifies :restart, 'service[sentinel]', :immediately if OmnibusHelper.should_notify?('redis')
only_if { config_path }
end
when :disable
runit_service sentinel_service_name do
action :disable
end
file config_path do
action :delete
end
directory sentinel['dir'] do
action :delete
end
end
end

View File

@ -0,0 +1,65 @@
class SentinelHelper
MYID_PATTERN = /^[0-9a-f]{40}$/
JSON_FILE = '/etc/gitlab/gitlab-sentinel.json'.freeze
def initialize(node)
@node = node
end
def myid
if sentinel['myid']
restore_from_node
else
restore_or_generate_from_file
end
end
private
# Restore from node definition (gitlab.rb)
def restore_from_node
unless MYID_PATTERN =~ sentinel['myid']
fail 'Sentinel myid must be exactly 40 hex-characters lowercase'
end
sentinel['myid']
end
# Restore from local JSON file or create a new myid
def restore_or_generate_from_file
existing_data = load_from_file
if existing_data && existing_data['myid']
existing_data['myid']
else
myid = generate_myid
save_to_file({ 'myid' => myid })
myid
end
end
def sentinel
@node['gitlab']['sentinel']
end
# Load from local JSON file
def load_from_file
if File.exists?(JSON_FILE)
Chef::JSONCompat.from_json(File.read(JSON_FILE))
end
end
# Save to local JSON file
def save_to_file(data)
if File.directory?('/etc/gitlab')
File.open(JSON_FILE, 'w', 0600) do |f|
f.puts(Chef::JSONCompat.to_json_pretty(data))
f.chmod(0600) # update existing file
end
end
end
def generate_myid
SecureRandom::hex(20) # size will be n*2 -> 40 characters
end
end

View File

@ -0,0 +1,15 @@
name "gitlab-ee"
maintainer "GitLab Inc"
maintainer_email "support@gitlab.com"
license "Apache 2.0"
description "Install and configure GitLab EE from Omnibus"
long_description "Install and configure GitLab EE from Omnibus"
version "0.0.1"
recipe "gitlab", "Configures GitLab EE from Omnibus"
supports "ubuntu"
supports "centos"
depends "runit"
depends "gitlab"
depends "package"

View File

@ -0,0 +1,24 @@
#
# 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.
#
include_recipe 'gitlab::default'
if node['gitlab']['sentinel']['enable']
include_recipe 'gitlab-ee::sentinel'
else
include_recipe 'gitlab-ee::sentinel_disable'
end

View File

@ -0,0 +1,26 @@
#
# 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.
#
sentinel_helper = SentinelHelper.new(node)
sentinel_cfg = node['gitlab']['sentinel'].to_hash.merge({ 'myid' => sentinel_helper.myid })
sentinel_service 'redis' do
config_path File.join(node['gitlab']['sentinel']['dir'], 'sentinel.conf')
redis_configuration node['gitlab']['redis']
sentinel_configuration sentinel_cfg
logging_configuration node['gitlab']['logging']
end

View File

@ -0,0 +1,24 @@
#
# 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.
#
sentinel_service 'redis' do
config_path File.join(node['gitlab']['sentinel']['dir'], 'sentinel.conf')
redis_configuration node['gitlab']['redis']
sentinel_configuration node['gitlab']['sentinel']
logging_configuration node['gitlab']['logging']
action :disable
end

View File

@ -0,0 +1,205 @@
# 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`.
# *** IMPORTANT ***
#
# By default Sentinel will not be reachable from interfaces different than
# localhost, either use the 'bind' directive to bind to a list of network
# interfaces, or disable protected mode with "protected-mode no" by
# adding it to this configuration file.
#
# Before doing that MAKE SURE the instance is protected from the outside
# world via firewalling or other means.
#
# For example you may use one of the following:
#
# bind 127.0.0.1 192.168.1.1
#
# protected-mode no
bind <%= @sentinel['bind'] %>
# port <sentinel-port>
# The port that this sentinel instance will run on
port <%= @sentinel['port'] %>
# sentinel announce-ip <ip>
# sentinel announce-port <port>
#
# The above two configuration directives are useful in environments where,
# because of NAT, Sentinel is reachable from outside via a non-local address.
#
# When announce-ip is provided, the Sentinel will claim the specified IP address
# in HELLO messages used to gossip its presence, instead of auto-detecting the
# local address as it usually does.
#
# Similarly when announce-port is provided and is valid and non-zero, Sentinel
# will announce the specified TCP port.
#
# The two options don't need to be used together, if only announce-ip is
# provided, the Sentinel will announce the specified IP and the server port
# as specified by the "port" option. If only announce-port is provided, the
# Sentinel will announce the auto-detected local IP and the specified port.
#
# Example:
#
# sentinel announce-ip 1.2.3.4
# dir <working-directory>
# Every long running process should have a well-defined working directory.
# For Redis Sentinel to chdir to /tmp at startup is the simplest thing
# for the process to don't interfere with administrative tasks such as
# unmounting filesystems.
dir <%= %Q("#{@sentinel['dir']}") %>
# sentinel myid <id>
#
# Unique 40 hex-characters long identification of the instance in the cluster
# This value is spread across all sentinels and each instance keep a list of
# "known" instances to calculate majority in a failover consensus voting.
<%= "sentinel myid #{@sentinel['myid']}" if @sentinel['myid'] %>
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
#
# Tells Sentinel to monitor this master, and to consider it in O_DOWN
# (Objectively Down) state only if at least <quorum> sentinels agree.
#
# Note that whatever is the ODOWN quorum, a Sentinel will require to
# be elected by the majority of the known Sentinels in order to
# start a failover, so no failover can be performed in minority.
#
# Slaves are auto-discovered, so you don't need to specify slaves in
# any way. Sentinel itself will rewrite this configuration file adding
# the slaves using additional configuration options.
# Also note that the configuration file is rewritten when a
# slave is promoted to master.
#
# Note: master name should not include special characters or spaces.
# The valid charset is A-z 0-9 and the three characters ".-_".
sentinel monitor <%= @redis['master_name'] %> <%= @redis['master_ip'] %> <%= @redis['master_port'] %> <%= @sentinel['quorum'] %>
# sentinel down-after-milliseconds <master-name> <milliseconds>
#
# Number of milliseconds the master (or any attached slave or sentinel) should
# be unreachable (as in, not acceptable reply to PING, continuously, for the
# specified period) in order to consider it in S_DOWN state (Subjectively
# Down).
#
# Default is 30 seconds.
sentinel down-after-milliseconds <%= @redis['master_name'] %> <%= @sentinel['down_after_milliseconds'] %>
# sentinel parallel-syncs <master-name> <numslaves>
#
# How many slaves we can reconfigure to point to the new slave simultaneously
# during the failover. Use a low number if you use the slaves to serve query
# to avoid that all the slaves will be unreachable at about the same
# time while performing the synchronization with the master.
# sentinel parallel-syncs localhost 1
# sentinel failover-timeout <master-name> <milliseconds>
#
# Specifies the failover timeout in milliseconds. It is used in many ways:
#
# - The time needed to re-start a failover after a previous failover was
# already tried against the same master by a given Sentinel, is two
# times the failover timeout.
#
# - The time needed for a slave replicating to a wrong master according
# to a Sentinel current configuration, to be forced to replicate
# with the right master, is exactly the failover timeout (counting since
# the moment a Sentinel detected the misconfiguration).
#
# - The time needed to cancel a failover that is already in progress but
# did not produced any configuration change (SLAVEOF NO ONE yet not
# acknowledged by the promoted slave).
#
# - The maximum time a failover in progress waits for all the slaves to be
# reconfigured as slaves of the new master. However even after this time
# the slaves will be reconfigured by the Sentinels anyway, but not with
# the exact parallel-syncs progression as specified.
#
# Default is 3 minutes.
sentinel failover-timeout <%= @redis['master_name'] %> <%= @sentinel['failover_timeout'] %>
# sentinel auth-pass <master-name> <password>
#
# Set the password to use to authenticate with the master and slaves.
# Useful if there is a password set in the Redis instances to monitor.
#
# Note that the master password is also used for slaves, so it is not
# possible to set a different password in masters and slaves instances
# if you want to be able to monitor these instances with Sentinel.
#
# However you can have Redis instances without the authentication enabled
# mixed with Redis instances requiring the authentication (as long as the
# password set is the same for all the instances requiring the password) as
# the AUTH command will have no effect in Redis instances with authentication
# switched off.
#
# Example:
#
sentinel auth-pass <%= @redis['master_name'] %> <%= @redis['master_password'] %>
# SCRIPTS EXECUTION
#
# sentinel notification-script and sentinel reconfig-script are used in order
# to configure scripts that are called to notify the system administrator
# or to reconfigure clients after a failover. The scripts are executed
# with the following rules for error handling:
#
# If script exits with "1" the execution is retried later (up to a maximum
# number of times currently set to 10).
#
# If script exits with "2" (or an higher value) the script execution is
# not retried.
#
# If script terminates because it receives a signal the behavior is the same
# as exit code 1.
#
# A script has a maximum running time of 60 seconds. After this limit is
# reached the script is terminated with a SIGKILL and the execution retried.
# NOTIFICATION SCRIPT
#
# sentinel notification-script <master-name> <script-path>
#
# Call the specified notification script for any sentinel event that is
# generated in the WARNING level (for instance -sdown, -odown, and so forth).
# This script should notify the system administrator via email, SMS, or any
# other messaging system, that there is something wrong with the monitored
# Redis systems.
#
# The script is called with just two arguments: the first is the event type
# and the second the event description.
#
# The script must exist and be executable in order for sentinel to start if
# this option is provided.
#
# Example:
#
# sentinel notification-script mymaster /var/redis/notify.sh
# CLIENTS RECONFIGURATION SCRIPT
#
# sentinel client-reconfig-script <master-name> <script-path>
#
# When the master changed because of a failover a script can be called in
# order to perform application-specific tasks to notify the clients that the
# configuration has changed and the master is at a different address.
#
# The following arguments are passed to the script:
#
# <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port>
#
# <state> is currently always "failover"
# <role> is either "leader" or "observer"
#
# The arguments from-ip, from-port, to-ip, to-port are used to communicate
# the old address of the master and the new address of the elected slave
# (now a master).
#
# This script should be resistant to multiple invocations.
#
# Example:
#
# sentinel client-reconfig-script mymaster /var/redis/reconfig.sh

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,7 @@
#!/bin/sh
exec 2>&1
<%= render('mount_point_check.erb', cookbook: 'gitlab') %>
umask 077
<% user = @options[:user] %>
exec chpst -P -U <%= user %> -u <%= user %> /opt/gitlab/embedded/bin/redis-sentinel <%= @options[:config_path] %>

View File

@ -425,8 +425,10 @@ default['gitlab']['redis']['tcp_keepalive'] = 300
default['gitlab']['redis']['password'] = nil
default['gitlab']['redis']['unixsocket'] = "/var/opt/gitlab/redis/redis.socket"
default['gitlab']['redis']['unixsocketperm'] = "777"
default['gitlab']['redis']['master'] = true
default['gitlab']['redis']['master_name'] = 'gitlab-redis'
default['gitlab']['redis']['master_ip'] = nil
default['gitlab']['redis']['master_port'] = nil
default['gitlab']['redis']['master_port'] = 6379
default['gitlab']['redis']['master_password'] = nil
####

View File

@ -23,7 +23,8 @@ define :account, action: nil, username: nil, uid: nil, ugid: nil, groupname: nil
username = params[:username]
if manage && groupname
group groupname do
group params[:name] do
group_name groupname
gid params[:gid]
system params[:system]
if params[:append_to_group]
@ -35,7 +36,8 @@ define :account, action: nil, username: nil, uid: nil, ugid: nil, groupname: nil
end
if manage && username
user username do
user params[:name] do
username username
shell params[:shell]
home params[:home]
uid params[:uid]

View File

@ -22,7 +22,7 @@ define :redis_service, :socket_group => nil do
redis_log_dir = node['gitlab'][svc]['log_directory']
redis_user = AccountHelper.new(node).redis_user
account "Redis user and group" do
account 'user and group for redis' do
username redis_user
uid node['gitlab'][svc]['uid']
ugid redis_user
@ -33,6 +33,11 @@ define :redis_service, :socket_group => nil do
manage node['gitlab']['manage-accounts']['enable']
end
group 'Socket group' do
append true # we need this so we don't remove members
group_name params[:socket_group]
end
directory redis_dir do
owner redis_user
group params[:socket_group]
@ -45,12 +50,15 @@ define :redis_service, :socket_group => nil do
end
redis_config = File.join(redis_dir, "redis.conf")
is_slave = node['gitlab'][svc]['master_ip'] &&
node['gitlab'][svc]['master_port'] &&
!node['gitlab'][svc]['master']
template redis_config do
source "redis.conf.erb"
owner redis_user
mode "0644"
variables(node['gitlab'][svc].to_hash)
variables(node['gitlab'][svc].to_hash.merge({is_slave: is_slave}))
notifies :restart, "service[#{svc}]", :immediately if OmnibusHelper.should_notify?(svc)
end

View File

@ -1,40 +1,48 @@
:mailboxes:
<%
require '/opt/gitlab/embedded/service/gitlab-rails/config/environment.rb'
<%
require "/opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/mail_room" unless defined?(Gitlab::MailRoom)
config = Gitlab::MailRoom.config
if Gitlab::IncomingEmail.enabled?
config = Gitlab::IncomingEmail.config
redis_config_file = "/opt/gitlab/embedded/service/gitlab-rails/config/resque.yml"
redis_url =
if File.exists?(redis_config_file)
YAML.load_file(redis_config_file)[Rails.env]['url']
else
"redis://localhost:6379"
end
if Gitlab::MailRoom.enabled?
%>
-
:host: <%= config.host.to_json %>
:port: <%= config.port.to_json %>
:ssl: <%= config.ssl.to_json %>
:start_tls: <%= config.start_tls.to_json %>
:email: <%= config.user.to_json %>
:password: <%= config.password.to_json %>
:host: <%= config[:host].to_json %>
:port: <%= config[:port].to_json %>
:ssl: <%= config[:ssl].to_json %>
:start_tls: <%= config[:start_tls].to_json %>
:email: <%= config[:user].to_json %>
:password: <%= config[:password].to_json %>
:idle_timeout: 60
:name: <%= config.mailbox.to_json %>
:name: <%= config[:mailbox].to_json %>
:delete_after_delivery: true
:delivery_method: sidekiq
:delivery_options:
:redis_url: <%= redis_url.to_json %>
:namespace: resque:gitlab
:redis_url: <%= config[:redis_url].to_json %>
:namespace: <%= Gitlab::Redis::SIDEKIQ_NAMESPACE %>
:queue: email_receiver
:worker: EmailReceiverWorker
<% if config[:sentinels] %>
:sentinels:
<% config[:sentinels].each do |sentinel| %>
-
:host: <%= sentinel[:host] %>
:port: <%= sentinel[:port] %>
<% end %>
<% end %>
:arbitration_method: redis
:arbitration_options:
:redis_url: <%= redis_url.to_json %>
:namespace: mail_room:gitlab
<% end %>
:redis_url: <%= config[:redis_url].to_json %>
:namespace: <%= Gitlab::Redis::MAILROOM_NAMESPACE %>
<% if config[:sentinels] %>
:sentinels:
<% config[:sentinels].each do |sentinel| %>
-
:host: <%= sentinel[:host] %>
:port: <%= sentinel[:port] %>
<% end %>
<% end %>
<% end %>

View File

@ -78,6 +78,7 @@ module Gitlab
mattermost Mash.new
gitlab_pages Mash.new
registry Mash.new
sentinel Mash.new
node nil
external_url nil
pages_external_url nil
@ -86,6 +87,17 @@ module Gitlab
registry_external_url nil
git_data_dirs Mash.new
# roles
redis_sentinel_role Mash.new
redis_master_role Mash.new
redis_slave_role Mash.new
ROLES ||= [
'redis_sentinel',
'redis_master',
'redis_slave'
].freeze
class << self
# guards against creating secrets on non-bootstrap node
def generate_hex(chars)
@ -178,12 +190,19 @@ module Gitlab
"mattermost_external_url",
"pages_external_url",
"gitlab_pages",
"registry"
"registry",
"sentinel"
].each do |key|
rkey = key.gsub('_', '-')
results['gitlab'][rkey] = Gitlab[key]
end
results['roles'] = {}
ROLES.each do |key|
rkey = key.gsub('_', '-')
results['roles'][rkey] = Gitlab["#{key}_role"]
end
results
end
@ -204,7 +223,7 @@ module Gitlab
# Parse nginx variables last because we want all external_url to be
# parsed first
Nginx.parse_variables
GitlabRails.disable_gitlab_rails_services
GitlabRails.disable_services
# The last step is to convert underscores to hyphens in top-level keys
generate_hash
end

View File

@ -104,7 +104,7 @@ module GitlabRails
# append urls to the list but without relative_url
if Gitlab['gitlab_rails']['gitlab_relative_url']
paths_without_relative_url = []
Gitlab['gitlab_rails']['rack_attack_protected_paths'].each do |path|
Gitlab['gitlab_rails']['rack_attack_protected_paths'].each do |path|
if path.start_with?(Gitlab['gitlab_rails']['gitlab_relative_url'] + '/')
stripped_path = path.sub(Gitlab['gitlab_rails']['gitlab_relative_url'], '')
paths_without_relative_url.push(stripped_path)
@ -115,17 +115,63 @@ module GitlabRails
end
def disable_gitlab_rails_services
if Gitlab['gitlab_rails']["enable"] == false
Gitlab['redis']["enable"] = false
Gitlab['unicorn']["enable"] = false
Gitlab['sidekiq']["enable"] = false
Gitlab['gitlab_workhorse']["enable"] = false
end
def disable_services
disable_services_roles if any_role_defined?
disable_gitlab_rails_services
end
def public_path
"#{Gitlab['node']['package']['install-dir']}/embedded/service/gitlab-rails/public"
end
private
def any_role_defined?
Gitlab::ROLES.any? { |role| Gitlab["#{role}_role"]['enable'] }
end
def disable_services_roles
if Gitlab['redis_sentinel_role']['enable']
disable_non_redis_services
Gitlab['sentinel']['enable'] = true
else
Gitlab['sentinel']['enable'] = false
end
if Gitlab['redis_master_role']['enable']
disable_non_redis_services
Gitlab['redis']['enable'] = true
end
if Gitlab['redis_slave_role']['enable']
disable_non_redis_services
Gitlab['redis']['enable'] = true
end
if Gitlab['redis_master_role']['enable'] && Gitlab['redis_slave_role']['enable']
fail 'Cannot define both redis_master_role and redis_slave_role in the same machine.'
elsif Gitlab['redis_master_role']['enable'] || Gitlab['redis_slave_role']['enable']
disable_non_redis_services
else
Gitlab['redis']['enable'] = false
end
end
def disable_gitlab_rails_services
if Gitlab['gitlab_rails']['enable'] == false
Gitlab['unicorn']['enable'] = false
Gitlab['sidekiq']['enable'] = false
Gitlab['gitlab_workhorse']['enable'] = false
end
end
def disable_non_redis_services
Gitlab['gitlab_rails']['enable'] = false
Gitlab['bootstrap']['enable'] = false
Gitlab['nginx']['enable'] = false
Gitlab['postgresql']['enable'] = false
Gitlab['mailroom']['enable'] = false
end
end
end

View File

@ -289,12 +289,10 @@ class SecretsHelper
secret_tokens['mattermost'].merge!(gitlab_oauth)
end
if File.directory?("/etc/gitlab")
File.open("/etc/gitlab/gitlab-secrets.json", "w") do |f|
f.puts(
Chef::JSONCompat.to_json_pretty(secret_tokens)
)
system("chmod 0600 /etc/gitlab/gitlab-secrets.json")
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

View File

@ -28,17 +28,26 @@ module Redis
Gitlab['redis']['unixsocket'] = false
# Try to discover gitlab_rails redis connection params
# based on redis daemon definition if not defined
Gitlab['gitlab_rails']['redis_host'] ||= Gitlab['redis']['bind']
Gitlab['gitlab_rails']['redis_port'] ||= Gitlab['redis']['port']
if Gitlab['gitlab_rails']['redis_host'] != Gitlab['redis']['bind']
Chef::Log.warn "gitlab-rails 'redis_host' is different than 'bind' value defined for managed redis instance."
# based on redis daemon
unless has_sentinels?
parse_redis_daemon!
end
end
if Gitlab['gitlab_rails']['redis_port'] != Gitlab['redis']['port']
Chef::Log.warn "gitlab-rails 'redis_port' is different than 'port' value defined for managed redis instance."
end
if Gitlab['redis_slave_role']['enable']
Gitlab['redis']['master'] = false
end
if sentinel_daemon_enabled? || is_redis_slave?
fail "redis 'master_ip' is not defined" unless Gitlab['redis']['master_ip']
fail "redis 'master_port' is not defined" unless Gitlab['redis']['master_port']
fail "redis 'master_password' is not defined" unless Gitlab['redis']['master_password']
end
# Try to discover gitlab_rails redis connection params
# based on sentinels node data
if has_sentinels?
parse_sentinels!
end
if is_gitlab_rails_redis_tcp?
@ -53,12 +62,80 @@ module Redis
private
# Parses sentinel specific meta-data to fill gitlab_rails
#
# Redis sentinel requires the url to point to the 'master_name' instead of
# an IP or a valid host. We also need to ignore port and make sure we use
# correct password
def parse_sentinels!
master_name = Gitlab['redis']['master_name'] || node['gitlab']['redis']['master_name']
if Gitlab['gitlab_rails']['redis_host'] != master_name
Gitlab['gitlab_rails']['redis_host'] = master_name
Chef::Log.warn "gitlab-rails 'redis_host' will be ignored as sentinel is defined."
end
if Gitlab['gitlab_rails']['redis_port']
Gitlab['gitlab_rails']['redis_port'] = nil
Chef::Log.warn "gitlab-rails 'redis_port' will be ignored as sentinel is defined."
end
if Gitlab['gitlab_rails']['redis_password'] != Gitlab['redis']['master_password']
Gitlab['gitlab_rails']['redis_password'] = Gitlab['redis']['master_password']
Chef::Log.warn "gitlab-rails 'redis_password' will be ignored as sentinel is defined."
end
end
def parse_redis_daemon!
return unless redis_managed?
redis_bind = Gitlab['redis']['bind'] || node['gitlab']['redis']['bind']
Gitlab['gitlab_rails']['redis_host'] ||= redis_bind
Gitlab['gitlab_rails']['redis_port'] ||= Gitlab['redis']['port']
Gitlab['gitlab_rails']['redis_password'] ||= Gitlab['redis']['master_password']
if Gitlab['gitlab_rails']['redis_host'] != redis_bind
Chef::Log.warn "gitlab-rails 'redis_host' is different than 'bind' value defined for managed redis instance. Are you sure you are pointing to the same redis instance?"
end
if Gitlab['gitlab_rails']['redis_port'] != Gitlab['redis']['port']
Chef::Log.warn "gitlab-rails 'redis_port' is different than 'port' value defined for managed redis instance. Are you sure you are pointing to the same redis instance?"
end
if Gitlab['gitlab_rails']['redis_password'] != Gitlab['redis']['master_password']
Chef::Log.warn "gitlab-rails 'redis_password' is different than 'master_password' value defined for managed redis instance. Are you sure you are pointing to the same redis instance?"
end
end
def node
Gitlab[:node]
end
def is_redis_tcp?
Gitlab['redis']['bind'] && Gitlab['redis']['port'] != 0
Gitlab['redis']['port'] && Gitlab['redis']['port'] > 0
end
def is_redis_slave?
Gitlab['redis']['master'] == false
end
def sentinel_daemon_enabled?
Gitlab['sentinel']['enable']
end
def is_gitlab_rails_redis_tcp?
Gitlab['gitlab_rails']['redis_host']
end
def has_sentinels?
Gitlab['gitlab_rails']['redis_sentinels'] && !Gitlab['gitlab_rails']['redis_sentinels'].empty?
end
def redis_managed?
Gitlab['redis']['enable'].nil? ? node['gitlab']['redis']['enable'] : Gitlab['redis']['enable']
end
end
end

View File

@ -0,0 +1,24 @@
#
# Copyright:: Copyright (c) 2016 GitLab B.V.
# 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.
#
Gitlab[:node] = node
if File.exists?('/etc/gitlab/gitlab.rb')
Gitlab.from_file('/etc/gitlab/gitlab.rb')
end
node.consume_attributes(Gitlab.generate_config(node['fqdn']))

View File

@ -23,11 +23,7 @@ require 'openssl'
install_dir = node['package']['install-dir']
ENV['PATH'] = "#{install_dir}/bin:#{install_dir}/embedded/bin:#{ENV['PATH']}"
Gitlab[:node] = node
if File.exists?("/etc/gitlab/gitlab.rb")
Gitlab.from_file("/etc/gitlab/gitlab.rb")
end
node.consume_attributes(Gitlab.generate_config(node['fqdn']))
include_recipe 'gitlab::config'
directory "/etc/gitlab" do
owner "root"

View File

@ -151,7 +151,7 @@ daemonize no
#
# Creating a pid file is best effort: if Redis is not able to create it
# nothing bad happens, the server will start and run normally.
pidfile /var/run/redis_<%= @port %>.pid
pidfile "/var/run/redis_<%= @port %>.pid"
# Specify the server verbosity level.
# This can be one of:
@ -238,7 +238,7 @@ rdbcompression yes
rdbchecksum yes
# The filename where to dump the DB
dbfilename dump.rdb
dbfilename "dump.rdb"
# The working directory.
#
@ -248,7 +248,7 @@ dbfilename dump.rdb
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir <%= @dir %>
dir <%= %Q("#{@dir}") %>
################################# REPLICATION #################################
@ -267,7 +267,7 @@ dir <%= @dir %>
# and resynchronize with them.
#
# slaveof <masterip> <masterport>
<%= "slaveof #{@master_ip} #{@master_port}" if @master_ip && @master_port %>
<%= "slaveof #{@master_ip} #{@master_port}" if @is_slave %>
# If the master is password protected (using the "requirepass" configuration
# directive below) it is possible to tell the slave to authenticate before
@ -275,7 +275,7 @@ dir <%= @dir %>
# refuse the slave request.
#
# masterauth <master-password>
<%= %Q(masterauth "#{@master_password}") if @master_password %>
<%= %Q(masterauth "#{@master_password}") if @master_password%>
# When a slave loses its connection with the master, or when the replication
# is still in progress, the slave can act in two different ways:

View File

@ -0,0 +1,148 @@
require 'chef_helper'
describe 'gitlab::config' do
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab::config') }
let(:node) { chef_run.node }
before do
allow(Gitlab).to receive(:[]).and_call_original
end
shared_examples 'regular services are disabled' do
it 'disables regular services' do
expect(node['gitlab']['gitlab-rails']['enable']).to eq false
expect(node['gitlab']['unicorn']['enable']).to eq false
expect(node['gitlab']['sidekiq']['enable']).to eq false
expect(node['gitlab']['gitlab-workhorse']['enable']).to eq false
expect(node['gitlab']['bootstrap']['enable']).to eq false
expect(node['gitlab']['nginx']['enable']).to eq false
expect(node['gitlab']['postgresql']['enable']).to eq false
expect(node['gitlab']['mailroom']['enable']).to eq false
end
end
context 'with roles' do
context 'when redis_sentinel_role is enabled' do
before do
stub_gitlab_rb(
redis_sentinel_role: {
enable: true
}
)
end
it_behaves_like 'regular services are disabled'
it 'only sentinel is enabled' do
expect(node['gitlab']['sentinel']['enable']).to eq true
expect(node['gitlab']['redis']['enable']).to eq false
end
context 'when redis_sentinel_role is enabled with redis_master_role' do
before do
stub_gitlab_rb(
redis_sentinel_role: {
enable: true
},
redis_master_role: {
enable: true
}
)
end
it_behaves_like 'regular services are disabled'
it 'redis and sentinel are enabled' do
expect(node['gitlab']['sentinel']['enable']).to eq true
expect(node['gitlab']['redis']['enable']).to eq true
end
end
context 'when redis_sentinel_role is enabled with redis_slave_role' do
before do
stub_gitlab_rb(
redis_sentinel_role: {
enable: true
},
redis_slave_role: {
enable: true
},
redis: {
master_ip: '10.0.0.0',
master_port: 6379,
master_password: 'PASSWORD'
}
)
end
it_behaves_like 'regular services are disabled'
it 'only redis is enabled' do
expect(node['gitlab']['sentinel']['enable']).to eq true
expect(node['gitlab']['redis']['enable']).to eq true
end
end
end
context 'when redis_master_role is enabled' do
before do
stub_gitlab_rb(
redis_master_role: {
enable: true
}
)
end
it_behaves_like 'regular services are disabled'
it 'only redis is enabled' do
expect(node['gitlab']['redis']['enable']).to eq true
expect(node['gitlab']['sentinel']['enable']).to eq false
end
end
context 'when redis_slave_role is enabled' do
before do
stub_gitlab_rb(
redis_slave_role: {
enable: true
},
redis: {
master_ip: '10.0.0.0',
master_port: 6379,
master_password: 'PASSWORD'
}
)
end
it_behaves_like 'regular services are disabled'
it 'only redis is enabled' do
expect(node['gitlab']['redis']['enable']).to eq true
expect(node['gitlab']['sentinel']['enable']).to eq false
end
end
context 'when redis_master_role and redis_slave_role are enabled' do
before do
stub_gitlab_rb(
redis_master_role: {
enable: true
},
redis_slave_role: {
enable: true
},
redis: {
master_ip: '10.0.0.0',
master_port: 6379,
master_password: 'PASSWORD'
}
)
end
it 'fails with an error' do
expect { chef_run }.to raise_error RuntimeError
end
end
end
end

View File

@ -118,11 +118,7 @@ describe 'gitlab::gitlab-shell' do
redis_host: 'redis.example.com',
redis_port: 8888,
redis_database: 1,
redis_password: "PASSWORD!",
redis_sentinels: [
{'host' => 'redis1.sentinel', 'port' => 26370},
{'host' => 'redis2.sentinel', 'port' => 26371}
]
redis_password: 'PASSWORD!'
}
)
}
@ -140,6 +136,38 @@ describe 'gitlab::gitlab-shell' do
.with_content(/namespace: resque:gitlab/)
expect(chef_run).to render_file('/var/opt/gitlab/gitlab-shell/config.yml')
.with_content(/pass: PASSWORD!/)
expect(chef_run).to_not render_file('/var/opt/gitlab/gitlab-shell/config.yml')
.with_content(/socket: \/var\/opt\/gitlab\/redis\/redis.socket/)
end
end
context 'with sentinels configured' do
before {
stub_gitlab_rb(
gitlab_rails: {
redis_sentinels: [
{'host' => 'redis1.sentinel', 'port' => 26370},
{'host' => 'redis2.sentinel', 'port' => 26371}
]
},
redis: {
master_name: 'sentinel-master',
master_password: 'PASSWORD!'
}
)
}
it 'creates the config file with the required redis settings' do
expect(chef_run).to render_file('/var/opt/gitlab/gitlab-shell/config.yml')
.with_content(/bin: \/opt\/gitlab\/embedded\/bin\/redis-cli/)
expect(chef_run).to render_file('/var/opt/gitlab/gitlab-shell/config.yml')
.with_content(/host: sentinel-master/)
expect(chef_run).to render_file('/var/opt/gitlab/gitlab-shell/config.yml')
.with_content(/port: 6379/)
expect(chef_run).to render_file('/var/opt/gitlab/gitlab-shell/config.yml')
.with_content(/namespace: resque:gitlab/)
expect(chef_run).to render_file('/var/opt/gitlab/gitlab-shell/config.yml')
.with_content(/pass: PASSWORD!/)
expect(chef_run).to render_file('/var/opt/gitlab/gitlab-shell/config.yml')
.with_content(/- {"host":"redis1.sentinel","port":26370}/)
expect(chef_run).to render_file('/var/opt/gitlab/gitlab-shell/config.yml')

View File

@ -31,8 +31,9 @@ describe 'secrets' do
before do
allow(SecretsHelper).to receive(:system)
allow(File).to receive(:directory?).with('/etc/gitlab').and_return(true)
allow(File).to receive(:open).with('/etc/gitlab/gitlab-secrets.json', 'w').and_yield(file).once
allow(File).to receive(:open).with('/etc/gitlab/gitlab-secrets.json', 'w', 0600).and_yield(file).once
allow(file).to receive(:puts) { |json| @new_secrets = JSON.parse(json) }
allow(file).to receive(:chmod).and_return(true)
end
context 'when there are no existing secrets' do

View File

@ -2,7 +2,7 @@ require_relative '../../files/gitlab-cookbooks/gitlab/libraries/redis_helper.rb'
require 'chef_helper'
describe RedisHelper do
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab::default') }
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab::config') }
subject { described_class.new(chef_run.node) }
context '#redis_url' do

View File

@ -1,7 +1,7 @@
require 'chef_helper'
describe 'Redis' do
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab::default') }
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab::config') }
let(:node) { chef_run.node }
subject { ::Redis }
before { allow(Gitlab).to receive(:[]).and_call_original }
@ -17,47 +17,110 @@ describe 'Redis' do
context '.parse_redis_settings' do
context 'when no customization is made' do
it 'keeps unixsocket' do
expect(Gitlab['gitlab_rails']['unixsocket']).not_to eq false
expect(node['gitlab']['gitlab-rails']['unixsocket']).not_to eq false
subject.parse_redis_settings
end
end
context 'within redis host and port synchronization with gitlab_rails' do
let(:redis_host) { '0.0.0.0' }
let(:redis_port) { 6379 }
let(:redis_host) { '1.2.3.4' }
let(:redis_port) { 6370 }
before do
stub_gitlab_rb(
redis: {
bind: redis_host,
port: redis_port
}
)
node
context 'when not using sentinels' do
before do
stub_gitlab_rb(
redis: {
bind: redis_host,
port: redis_port
}
)
end
it 'disables unix socket when redis tcp params are defined' do
expect(node['gitlab']['redis']['unixsocket']).to eq false
subject.parse_redis_settings
end
it 'expects redis_host to match bind value from redis' do
expect(node['gitlab']['gitlab-rails']['redis_host']).to eq redis_host
subject.parse_redis_settings
end
it 'expects redis_port to match port value from redis' do
expect(node['gitlab']['gitlab-rails']['redis_port']).to eq redis_port
subject.parse_redis_settings
end
end
it 'disables unix socket when redis tcp params are defined' do
expect(Gitlab['redis']['unixsocket']).to eq false
context 'when using sentinels' do
let(:master_name) { 'gitlabredis' }
let(:master_pass) { 'PASSWORD' }
subject.parse_redis_settings
before do
stub_gitlab_rb(
redis: {
bind: redis_host,
port: redis_port,
master_name: master_name,
master_password: master_pass
},
gitlab_rails: {
redis_sentinels: [
{ host: '1.2.3.4', port: '26379' }
]
}
)
end
it 'disables unix socket when sentinel params are defined' do
expect(node['gitlab']['redis']['unixsocket']).to eq false
subject.parse_redis_settings
end
it 'expects redis_host to match bind value from redis' do
expect(node['gitlab']['gitlab-rails']['redis_host']).to eq master_name
subject.parse_redis_settings
end
it 'expects redis_port to match default port value from redis' do
expect(node['gitlab']['gitlab-rails']['redis_port']).to eq 6379
subject.parse_redis_settings
end
it 'expects redis_password to match master_password value from redis' do
expect(node['gitlab']['gitlab-rails']['redis_password']).to eq master_pass
end
end
it 'expects redis_host to match bind value from redis' do
expect(Gitlab['gitlab_rails']['redis_host']).to eq redis_host
context 'when with redis_slave_role enabled' do
before do
stub_gitlab_rb(
redis_slave_role: {
enable: true
},
redis: {
master_ip: '10.0.0.0',
master_port: 6379,
master_password: 'PASSWORD'
}
)
end
subject.parse_redis_settings
end
it 'expects redis_port to match port value from redis' do
expect(Gitlab['gitlab_rails']['redis_port']).to eq redis_port
subject.parse_redis_settings
it 'defined redis master as false' do
expect(node['gitlab']['redis']['master']).to eq false
end
end
end
context 'within gitlab-rails redis values' do
let(:redis_host) { '0.0.0.0' }
let(:redis_host) { '1.2.3.4' }
before do
stub_gitlab_rb(
@ -65,15 +128,14 @@ describe 'Redis' do
redis_host: redis_host
}
)
node
end
it 'disables unix socket when gitlab-rails tcp params are defined' do
expect(Gitlab['gitlab_rails']['redis_socket']).to eq false
expect(node['gitlab']['gitlab-rails']['redis_socket']).to eq false
end
it 'defaults port to 6379' do
expect(Gitlab['gitlab_rails']['redis_port']).to eq 6379
expect(node['gitlab']['gitlab-rails']['redis_port']).to eq 6379
end
end
end

View File

@ -0,0 +1,47 @@
require_relative '../../files/gitlab-cookbooks/gitlab-ee/libraries/sentinel_helper.rb'
require 'chef_helper'
describe SentinelHelper do
let(:chef_run) { ChefSpec::SoloRunner.converge('gitlab::config') }
subject { described_class.new(chef_run.node) }
before { allow(Gitlab).to receive(:[]).and_call_original }
context '#myid' do
context 'when retrieving from config' do
it 'fails when myid is not 40 hex-characters long' do
stub_gitlab_rb(
sentinel: {
myid: 'wrongid'
}
)
expect { subject.myid }.to raise_error RuntimeError
end
it 'works when myid is 40 hex-characters long' do
stub_gitlab_rb(
sentinel: {
myid: '1234567890abcdef1234567890abcdef12345678'
}
)
expect { subject.myid }.not_to raise_error
end
end
context 'when no config is defined' do
let(:myid) { 'abcdef1234567890abcdef1234567890abcdef1' }
it 'generates a random myid' do
expect(subject.myid).not_to be_empty
end
it 'persist generated value into JSON file' do
allow(subject).to receive(:generate_myid).at_least(:once) { myid }
expect(subject).to receive(:save_to_file).with({ 'myid' => myid })
subject.myid
end
end
end
end