libraries/helpers.rb
#
# Cookbook Name:: postgresql
# Library:: helpers
#
# Author:: LLC Express 42 (info@express42.com)
#
# Copyright (C) 2012-2014 LLC Express 42
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
class Chef
# Postgresql modules
module Postgresql
# Helpers module
module Helpers
def pg_installed?(pkg_name)
dpkg_status = Mixlib::ShellOut.new("dpkg-query -W -f='${Status}\n' #{pkg_name} 2>/dev/null | grep -c -q 'ok installed'")
dpkg_status.run_command
return false if dpkg_status.exitstatus == 0
true
end
def systemd_used?
systemd_checker = Mixlib::ShellOut.new('file /sbin/init')
systemd_checker.run_command
return true if systemd_checker.stdout =~ /systemd/
false
end
def exec_in_pg_cluster(cluster_version, cluster_name, *cluster_database, sql)
return [nil, "PostgreSQL cluster #{cluster_name} not running!"] unless pg_running?(cluster_version, cluster_name)
pg_port = get_pg_port(cluster_version, cluster_name)
psql_status = Mixlib::ShellOut.new("echo -n \"#{sql};\" | su -c 'psql -t -p #{pg_port} #{cluster_database.first}' postgres")
psql_status.run_command
[psql_status.stdout, psql_status.stderr]
end
def get_pg_port(cluster_version, cluster_name)
return [nil, nil] unless pg_running?(cluster_version, cluster_name)
postmaster_content = ::File.open("/var/lib/postgresql/#{cluster_version}/#{cluster_name}/postmaster.pid").readlines
postmaster_content[3].to_i
end
def need_to_restart?(allow_restart_cluster, first_time)
return first_time if allow_restart_cluster == :first
return true if allow_restart_cluster == :always
false
end
def pg_running?(cluster_version, cluster_name)
pg_status = Mixlib::ShellOut.new("su -c '/usr/lib/postgresql/#{cluster_version}/bin/pg_ctl \
-D /var/lib/postgresql/#{cluster_version}/#{cluster_name} status' postgres")
pg_status.run_command
return true if pg_status.stdout =~ /server\ is\ running/
false
end
def create_user(cluster_version, cluster_name, cluster_user, options)
stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, 'SELECT usename FROM pg_user')
raise "postgresql create_user: can't get users list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty?
if stdout.include? cluster_user
Chef::Log.info("postgresql create_user: user '#{cluster_user}' already exists, skiping")
return nil
else
stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, "CREATE USER \\\"#{cluster_user}\\\" #{options.map { |t| t.join(' ') }.join(' ')}")
raise "postgresql create_user: can't create user #{cluster_user}\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stdout.include?("CREATE ROLE\n")
Chef::Log.info("postgresql create_user: user '#{cluster_user}' created")
end
end
def create_database(cluster_version, cluster_name, cluster_database, options)
stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, 'SELECT datname FROM pg_database')
raise "postgresql create_database: can't get database list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty?
if stdout.gsub(/\s+/, ' ').split(' ').include? cluster_database
Chef::Log.info("postgresql create_database: database '#{cluster_database}' already exists, skiping")
return nil
else
stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, "CREATE DATABASE \\\"#{cluster_database}\\\" #{options.map { |t| t.join(' ') }.join(' ')}")
raise "postgresql create_database: can't create database #{cluster_database}\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stdout.include?("CREATE DATABASE\n")
Chef::Log.info("postgresql create_database: database '#{cluster_database}' created")
end
end
def extension_available?(cluster_version, cluster_name, extension)
stdout, _stderr = exec_in_pg_cluster(cluster_version, cluster_name, 'SELECT name FROM pg_available_extensions')
return true if stdout.include? extension
false
end
def install_extension(cluster_version, cluster_name, cluster_database, extension, options)
raise "extension '#{extension}' is not available, please use \'pgxn_extension\' resource to install the extention" unless extension_available?(cluster_version, cluster_name, extension)
stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, cluster_database, 'SELECT extname FROM pg_extension')
raise "postgresql install_extension: can't get extensions list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty?
if stdout.include? extension
Chef::Log.info("postgresql install: extension '#{extension}' already installed, skiping")
return nil
else
stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, cluster_database, "CREATE EXTENSION \\\"#{extension}\\\" #{options.map { |t| t.join(' ') }.join(' ')}")
raise "postgresql install_extension: can't install extension #{extension}\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stdout.include?("CREATE EXTENSION\n")
Chef::Log.info("postgresql install_extension: extension '#{extension}' installed")
end
end
def pgxn_install_extension(cluster_version, cluster_name, params, options)
pgxn_status = Mixlib::ShellOut.new("pgxn install '#{params[:name]}'='#{params[:version]}' --sudo --#{params[:stage]}")
pgxn_status.run_command
stdout, stderr = exec_in_pg_cluster(cluster_version, cluster_name, params[:db], 'SELECT extname FROM pg_extension')
raise "postgresql install_extension: can't get extensions list\nSTDOUT: #{stdout}\nSTDERR: #{stderr}" unless stderr.empty?
if stdout.include? params[:name].downcase
Chef::Log.info("postgresql install: extension '#{params[:name]}' already installed, skipping")
return nil
else
pgxn_status = Mixlib::ShellOut.new("sudo -u postgres pgxn load '#{params[:name]}'='#{params[:version]}' -d #{params[:db]} --#{params[:stage]} #{options.map { |t| t.join(' ') }.join(' ')}")
pgxn_status.run_command
raise "postgresql install_extension: can't install extension #{params[:name]}\nSTDOUT: #{pgxn_status.stdout}\nSTDERR: #{pgxn_status.stderr}" unless pgxn_status.stdout.include?('CREATE EXTENSION')
Chef::Log.info("postgresql install_extension: extension '#{params[:name]}' installed")
end
end
def configuration_hacks(configuration, cluster_version)
configuration['unix_socket_directory'] ||= '/var/run/postgresql' if cluster_version.to_f < 9.3
configuration['unix_socket_directories'] ||= '/var/run/postgresql' if cluster_version.to_f >= 9.3
configuration.delete('wal_receiver_status_interval') if cluster_version.to_f < 9.1
configuration.delete('hot_standby_feedback') if cluster_version.to_f < 9.1
end
end
end
end