action :run do base_piddir = new_resource.base_piddir if !new_resource.version redis_output = Mixlib::ShellOut.new("#{node['redisio']['bin_path']}/redis-server -v") redis_output.run_command redis_output.error! current_version = redis_output.stdout.gsub(/.*v=((\d+\.){2}\d+).*/, '\1').chomp else current_version = new_resource.version end version_hash = RedisioHelper.version_to_hash(current_version) # Setup a configuration file and init script for each configuration provided new_resource.servers.each do |current_instance| # Retrieve the default settings hash and the current server setups settings hash. current_instance_hash = current_instance.to_hash current_defaults_hash = new_resource.default_settings.to_hash # Merge the configuration defaults with the provided array of configurations provided current = current_defaults_hash.merge(current_instance_hash) # Merge in the default maxmemory node_memory_kb = node['memory']['total'] # On BSD platforms Ohai reports total memory as a Fixnum node_memory_kb = node_memory_kb.sub('kB', '').to_i if node_memory_kb.is_a?(String) # Here we determine what the logfile is. It has these possible states # # Redis 2.6 and lower can be # stdout # A path # nil # Redis 2.8 and higher can be # empty string, which means stdout) # A path # nil if current['logfile'].nil? log_file = nil log_directory = nil elsif current['logfile'] == 'stdout' || current['logfile'].empty? log_directory = nil log_file = current['logfile'] else log_directory = ::File.dirname(current['logfile']) log_file = ::File.basename(current['logfile']) if current['syslogenabled'] == 'yes' Chef::Log.warn("log file is set to #{current['logfile']} but syslogenabled is also set to 'yes'") end end maxmemory = current['maxmemory'].to_s if !maxmemory.empty? && maxmemory.include?('%') # Just assume this is sensible like "95%" or "95 %" percent_factor = current['maxmemory'].to_f / 100.0 # Ohai reports memory in KB as it looks in /proc/meminfo maxmemory = (node_memory_kb * 1024 * percent_factor / new_resource.servers.length).round.to_s end descriptors = if current['ulimit'] == 0 current['maxclients'] + 32 elsif current['ulimit'] > current['maxclients'] current['ulimit'] else current['maxclients'] end server_name = current['name'] || current['port'] piddir = "#{base_piddir}/#{server_name}" aof_file = current['appendfilename'] || "#{current['datadir']}/appendonly-#{server_name}.aof" rdb_file = current['dbfilename'] || "#{current['datadir']}/dump-#{server_name}.rdb" # Create the owner of the redis data directory user current['user'] do comment 'Redis service account' manage_home true home current['homedir'] shell current['shell'] system current['systemuser'] uid current['uid'] unless current['uid'].nil? end # Create the redis configuration directory directory current['configdir'] do owner 'root' group platform_family?('freebsd') ? 'wheel' : 'redis' mode '0775' recursive true action :create end # Create the instance data directory directory current['datadir'] do owner current['user'] group current['group'] mode '0775' recursive true action :create end # Create the pid file directory directory piddir do owner current['user'] group current['group'] mode '0755' recursive true action :create end # Create the log directory if syslog is not being used if log_directory directory log_directory do owner current['user'] group current['group'] mode '0755' recursive true action :create end end # Configure SELinux if it is enabled extend Chef::Util::Selinux if selinux_enabled? selinux_install 'install' selinux_fcontext "#{current['configdir']}(/.*)?" do secontext 'redis_conf_t' end selinux_fcontext "#{current['datadir']}(/.*)?" do secontext 'redis_var_lib_t' end selinux_fcontext "#{piddir}(/.*)?" do secontext 'redis_var_run_t' end if log_directory selinux_fcontext "#{log_directory}(/.*)?" do secontext 'redis_log_t' end end end # Create the log file if syslog is not being used if log_file file current['logfile'] do owner current['user'] group current['group'] mode '0644' backup false action :create # in version 2.8 or higher the empty string is used instead of stdout only_if { !log_file.empty? && log_file != 'stdout' } end end # Set proper permissions on the AOF or RDB files file aof_file do owner current['user'] group current['group'] mode '0644' only_if { current['backuptype'] == 'aof' || current['backuptype'] == 'both' } only_if { ::File.exist?(aof_file) } end file rdb_file do owner current['user'] group current['group'] mode '0644' only_if { current['backuptype'] == 'rdb' || current['backuptype'] == 'both' } only_if { ::File.exist?(rdb_file) } end # Setup the redis users descriptor limits # Pending response on https://github.com/brianbianco/redisio/commit/4ee9aad3b53029cc3b6c6cf741f5126755e712cd#diff-8ae42a59a6f4e8dc5b4e6dd2d6a34eab # TODO: ulimit cookbook v0.1.2 doesn't work with freeBSD if current['ulimit'] && !platform_family?('freebsd') user_ulimit current['user'] do filehandle_limit descriptors end end computed_save = current['save'] if current['save'] && current['save'].respond_to?(:each_line) computed_save = current['save'].each_line Chef::Log.warn("#{server_name}: given a save argument as a string, instead of an array.") Chef::Log.warn("#{server_name}: This will be deprecated in future versions of the redisio cookbook.") end # Load password for use with requirepass from data bag if needed if current['data_bag_name'] && current['data_bag_item'] && current['data_bag_key'] bag = data_bag_item(current['data_bag_name'], current['data_bag_item']) current['requirepass'] = bag[current['data_bag_key']] current['masterauth'] = bag[current['data_bag_key']] end # Lay down the configuration files for the current instance template "#{current['configdir']}/#{server_name}.conf" do source node['redisio']['redis_config']['template_source'] cookbook node['redisio']['redis_config']['template_cookbook'] owner current['user'] group current['group'] mode current['permissions'] action :create variables( version: version_hash, piddir: piddir, name: server_name, job_control: node['redisio']['job_control'], port: current['port'], tcpbacklog: current['tcpbacklog'], address: current['address'], databases: current['databases'], backuptype: current['backuptype'], datadir: current['datadir'], unixsocket: current['unixsocket'], unixsocketperm: current['unixsocketperm'], timeout: current['timeout'], keepalive: current['keepalive'], loglevel: current['loglevel'], logfile: current['logfile'], syslogenabled: current['syslogenabled'], syslogfacility: current['syslogfacility'], save: computed_save, stopwritesonbgsaveerror: current['stopwritesonbgsaveerror'], rdbcompression: current['rdbcompression'], rdbchecksum: current['rdbchecksum'], dbfilename: current['dbfilename'], slaveof: current['slaveof'], protected_mode: current['protected_mode'], masterauth: current['masterauth'], slaveservestaledata: current['slaveservestaledata'], slavereadonly: current['slavereadonly'], replpingslaveperiod: current['replpingslaveperiod'], repltimeout: current['repltimeout'], repldisabletcpnodelay: current['repldisabletcpnodelay'], replbacklogsize: current['replbacklogsize'], replbacklogttl: current['replbacklogttl'], slavepriority: current['slavepriority'], requirepass: current['requirepass'], rename_commands: current['rename_commands'], maxclients: current['maxclients'], maxmemory: maxmemory, maxmemorypolicy: current['maxmemorypolicy'], maxmemorysamples: current['maxmemorysamples'], appendfilename: current['appendfilename'], appendfsync: current['appendfsync'], noappendfsynconrewrite: current['noappendfsynconrewrite'], aofrewritepercentage: current['aofrewritepercentage'], aofrewriteminsize: current['aofrewriteminsize'], aofloadtruncated: current['aofloadtruncated'], luatimelimit: current['luatimelimit'], slowloglogslowerthan: current['slowloglogslowerthan'], slowlogmaxlen: current['slowlogmaxlen'], notifykeyspaceevents: current['notifykeyspaceevents'], hashmaxziplistentries: current['hashmaxziplistentries'], hashmaxziplistvalue: current['hashmaxziplistvalue'], listmaxziplistentries: current['listmaxziplistentries'], listmaxziplistvalue: current['listmaxziplistvalue'], setmaxintsetentries: current['setmaxintsetentries'], zsetmaxziplistentries: current['zsetmaxziplistentries'], zsetmaxziplistvalue: current['zsetmaxziplistvalue'], hllsparsemaxbytes: current['hllsparsemaxbytes'], activerehasing: current['activerehasing'], clientoutputbufferlimit: current['clientoutputbufferlimit'], hz: current['hz'], aofrewriteincrementalfsync: current['aofrewriteincrementalfsync'], clusterenabled: current['clusterenabled'], clusterconfigfile: current['clusterconfigfile'], clusternodetimeout: current['clusternodetimeout'], includes: current['includes'], minslavestowrite: current['minslavestowrite'], minslavesmaxlag: current['minslavesmaxlag'], repldisklesssync: current['repldisklesssync'], repldisklesssyncdelay: current['repldisklesssyncdelay'] ) not_if { ::File.exist?("#{current['configdir']}/#{server_name}.conf.breadcrumb") } end file "#{current['configdir']}/#{server_name}.conf.breadcrumb" do content 'This file prevents the chef cookbook from overwritting the redis config more than once' action :create_if_missing only_if { current['breadcrumb'] == true } end # Setup init.d file bin_path = if node['redisio']['install_dir'] ::File.join(node['redisio']['install_dir'], 'bin') else node['redisio']['bin_path'] end case node['redisio']['job_control'] when 'initd' template "/etc/init.d/redis#{server_name}" do source 'redis.init.erb' cookbook 'redisio' owner 'root' group 'root' mode '0755' variables( name: server_name, bin_path: bin_path, port: current['port'], address: current['address'], user: current['user'], configdir: current['configdir'], piddir: piddir, requirepass: current['requirepass'], shutdown_save: current['shutdown_save'], platform: node['platform'], unixsocket: current['unixsocket'], ulimit: descriptors, required_start: node['redisio']['init.d']['required_start'].join(' '), required_stop: node['redisio']['init.d']['required_stop'].join(' ') ) end when 'upstart' template "/etc/init/redis#{server_name}.conf" do source 'redis.upstart.conf.erb' cookbook 'redisio' owner current['user'] group current['group'] mode '0644' variables( name: server_name, bin_path: bin_path, port: current['port'], user: current['user'], group: current['group'], configdir: current['configdir'], piddir: piddir ) end when 'rcinit' template "/usr/local/etc/rc.d/redis#{server_name}" do source 'redis.rcinit.erb' cookbook 'redisio' owner current['user'] group current['group'] mode '0755' variables( name: server_name, bin_path: bin_path, user: current['user'], configdir: current['configdir'], piddir: piddir ) end when 'systemd' service_name = "redis@#{server_name}" reload_name = "#{service_name} systemd reload" file "/etc/tmpfiles.d/#{service_name}.conf" do content "d #{piddir} 0755 #{current['user']} #{current['group']}\n" owner 'root' group 'root' mode '0644' end execute reload_name do command 'systemctl daemon-reload' action :nothing end template "/lib/systemd/system/#{service_name}.service" do source 'redis@.service.erb' cookbook 'redisio' owner 'root' group 'root' mode '0644' variables( bin_path: bin_path, user: current['user'], group: current['group'], limit_nofile: descriptors ) notifies :run, "execute[#{reload_name}]", :immediately end end end # servers each loop end