Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds the Redis Sentinel recipe #308

Open
wants to merge 1 commit into
base: next-release
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cookbooks/redis-sentinel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Redis Sentinel

This recipe is used to run on Redis Sentinel the stable-v5 stack.

The `redis-sentinel` recipe is managed by Engine Yard. You should not copy this recipe to your repository but instead copy custom-redis-sentinel. Please check the [custom-redis-sentinel readme](../../custom-cookbooks/redis-sentinel/cookbooks/custom-redis-sentinel/README.md) for the complete instructions.

We accept contributions for changes that can be used by all customers.
19 changes: 19 additions & 0 deletions cookbooks/redis-sentinel/attributes/default.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
default['redis-sentinel'].tap do |sentinel|
sentinel['port'] = '26379'

# Install redis-sentinel on all app instances
# sentinel['install_type'] = 'ALL_APP_INSTANCES'
# Install redis-sentinel on all app and util instances
# sentinel['install_type'] = 'ALL_APP_AND_UTIL_INSTANCES'

# Install redis-sentinel on utility instances named 'sidekiq'
#sentinel['utility_name'] = 'sidekiq'
#sentinel['install_type'] = 'NAMED_UTILS'

# Install redis-sentinel on all app instances, plus utility instances named 'sidekiq'
sentinel['utility_name'] = 'sidekiq'
sentinel['install_type'] = 'ALL_APP_AND_NAMED_UTIL_INSTANCES'

# Timeout
sentinel['timeout'] = 300_000
end
23 changes: 23 additions & 0 deletions cookbooks/redis-sentinel/libraries/is_redis_sentinel_instance.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class Chef::Recipe
# Return true if the we should install redis-sentinel on the current instance
# Based on the settings in redis-sentinel/attributes/default.rb
def is_redis_sentinel_instance(node_name, node_instance_role)
case node['redis-sentinel']['install_type']
when 'ALL_APP_INSTANCES'
%w(solo app_master app).include?(node_instance_role)
when 'ALL_APP_AND_UTIL_INSTANCES'
%w(solo app_master app util).include?(node_instance_role)
when 'ALL_APP_AND_NAMED_UTIL_INSTANCES'
%w(solo app_master app).include?(node_instance_role) ||
(
(node_instance_role == 'util') &&
(/^#{node['redis-sentinel']['utility_name']}/.match(node_name))
)
when 'NAMED_UTILS'
(node_instance_role == 'util') &&
(/^#{node['redis-sentinel']['utility_name']}/.match(node_name))
else
false
end
end
end
33 changes: 33 additions & 0 deletions cookbooks/redis-sentinel/libraries/redis_sentinel_instances.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
class Chef::Recipe
# Returns the list of redis-sentinel instances
# Based on the settings in redis-sentinel/attributes/default.rb
def redis_sentinel_instances
all_app_instances = node['dna']['engineyard']['environment']['instances'].map do |i|
i['private_hostname'] if ['app_master', 'app', 'solo'].include?(i['role'])
end.compact

all_util_instances = node['dna']['engineyard']['environment']['instances'].map do |i|
i['private_hostname'] if i['role'] == 'util'
end.compact

named_utility_instances = node['dna']['utility_instances'].map do |i|
i['hostname'] if i['name'] == node['redis-sentinel']['utility_name']
end.compact

case node['redis-sentinel']['install_type']
when 'ALL_APP_INSTANCES'
all_app_instances
when 'ALL_APP_AND_UTIL_INSTANCES'
all_app_instances + all_util_instances
when 'ALL_APP_AND_NAMED_UTIL_INSTANCES'
all_app_instances + named_utility_instances
when 'NAMED_UTILS'
named_utility_instances
else
# We should never get to this case
# If we do, we return an empty array
# to help in debugging why node['redis-sentinel']['install_type'] wasn't properly set
[]
end
end
end
10 changes: 10 additions & 0 deletions cookbooks/redis-sentinel/metadata.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name 'redis-sentinel'
description 'Configuration & deployment of Redis Sentinel on Engine Yard'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
maintainer 'Engine Yard'
maintainer_email '[email protected]'
version '5.0.0'
source_url 'https://github.com/engineyard/ey-cookbooks-stable-v5'
issues_url 'https://github.com/engineyard/ey-cookbooks-stable-v5/issues'

depends 'redis'
60 changes: 60 additions & 0 deletions cookbooks/redis-sentinel/recipes/configure.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#
# Cookbook Name:: redis-sentinel
# Recipe:: configure
#

redis_master = node['dna']['utility_instances'].select{ |i| i[:name] == 'redis'}.first

# Skip everything if there is no redis instance
if redis_master
redis_master_hostname = redis_master[:hostname]

sentinel_instances = redis_sentinel_instances
sentinels_for_redis_yml = sentinel_instances.map do |i|
{ 'host' => i, 'port' => node['redis-sentinel']['port'] }
end

if is_redis_sentinel_instance(node['dna']['name'], node['dna']['instance_role'])
# Generate a redis-sentinel.yml in /data/appname/shared/config
# so that the application can know which redis-sentinel instances to talk to
if %w(solo app app_master util).include?(node['dna']['instance_role'])
node['dna']['applications'].each do |app, _data|
template "/data/#{app}/shared/config/redis-sentinel.yml" do
source 'redis-sentinel.yml.erb'
owner node['owner_name']
group node['owner_name']
mode 0655
backup 0
variables('sentinel_instances' => sentinel_instances,
'port' => node['redis-sentinel']['port'])
end
end
end

# Override the redis.yml in /data/appname/shared/config
# Redis clients should connect to the sentinels, not directly to redis master
if %w(solo app app_master util).include?(node['dna']['instance_role'])
node['dna']['applications'].each do |app, _data|
template "/data/#{app}/shared/config/redis.yml" do
source 'redis.yml.erb'
owner node['owner_name']
group node['owner_name']
mode 0655
backup 0
variables({
'environment' => node['dna']['environment']['framework_env'],
'sentinels' => sentinels_for_redis_yml,
'redis_url' => "redis://#{redis_master_hostname}"
})
end
end
end

# Reload monit and restart redis-sentinel
execute 'restart-redis-sentinel' do
command 'monit reload && sleep 10 && /usr/bin/redis-cli -p 26379 shutdown'
not_if { `ps aux | grep [r]edis-server` == '' }
end

end
end
6 changes: 6 additions & 0 deletions cookbooks/redis-sentinel/recipes/default.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#
# Cookbook Name:: redis-sentinel
#

include_recipe 'redis-sentinel::install'
include_recipe 'redis-sentinel::configure'
81 changes: 81 additions & 0 deletions cookbooks/redis-sentinel/recipes/install.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#
# Cookbook Name:: redis-sentinel
# Recipe:: install
#
# This installs redis-sentinel on selected instances in the environment
#
# redis-sentinel is essentially redis-server running in sentinel mode
# so the code here looks very much like redis/recipes/install.rb
#

redis_version = node['redis']['version']
redis_config_file_version = redis_version[0..2]
redis_download_url = node['redis']['download_url']
redis_base_directory = node['redis']['basedir']

run_installer = !FileTest.exists?(redis_base_directory) || node['redis']['force_upgrade']

if is_redis_sentinel_instance(node['dna']['name'], node['dna']['instance_role'])

sysctl 'Enable Overcommit Memory' do
variables 'vm.overcommit_memory' => 1
end

if run_installer
if node['redis']['install']
include_recipe 'redis-sentinel::install_from_source'
else
include_recipe 'redis-sentinel::install_from_package'
end

directory redis_base_directory do
owner 'redis'
group 'redis'
mode 0o755
recursive true
action :create
end
end

# Determine the redis master instance private IP
redis_master = node['dna']['utility_instances'].select{ |i| i['name'] == 'redis'}.first
redis_master_hostname = redis_master[:hostname] if redis_master
redis_sentinel_config_variables = {
'port' => node['redis-sentinel']['port'],
'redis_name' => 'redis',
'redis_master_hostname' => redis_master_hostname
}
template '/etc/redis-sentinel.conf' do
owner 'root'
group 'root'
mode 0o644
source 'redis-sentinel.conf.erb'
variables redis_sentinel_config_variables
end

bin_path = if node['redis']['install_from_source']
'/usr/local/bin'
else
'/usr/sbin'
end
template '/engineyard/bin/redis-sentinel' do
owner 'root'
group 'root'
mode 0o755
source 'redis-sentinel.erb'
variables('configfile' => '/etc/redis-sentinel.conf',
'bin_path' => bin_path)
end

template '/data/monit.d/redis-sentinel.monitrc' do
owner 'root'
group 'root'
mode 0o644
source 'redis-sentinel.monitrc.erb'
variables('port' => node['redis-sentinel']['port'])
end

execute 'monit reload' do
action :run
end
end
13 changes: 13 additions & 0 deletions cookbooks/redis-sentinel/recipes/install_from_package.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
redis_package = 'dev-db/redis'
redis_version = node['redis']['version']

enable_package redis_package do
version redis_version
override_hardmask true
unmask true
end

package redis_package do
version redis_version
action :install
end
21 changes: 21 additions & 0 deletions cookbooks/redis-sentinel/recipes/install_from_source.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
redis_version = node['redis']['version']
redis_download_url = node['redis']['download_url']
redis_installer_directory = "/opt/redis-#{redis_version}"

remote_file "/opt/redis-#{redis_version}.tar.gz" do
source redis_download_url.to_s
owner node['owner_name']
group node['owner_name']
mode 0o644
backup 0
end

execute 'unarchive Redis installer' do
cwd '/opt'
command "tar zxf redis-#{redis_version}.tar.gz && sync"
end

execute 'run redis-source/make install' do
cwd redis_installer_directory
command 'make install'
end
Loading