Merge pull request #580 from raphink/dev/replication

Replication type
This commit is contained in:
Hunter Haugen 2015-03-12 10:18:42 -07:00
commit a50a16d97d
4 changed files with 187 additions and 0 deletions

View file

@ -0,0 +1,68 @@
Puppet::Type.type(:postgresql_replication_slot).provide(:ruby) do
# For confinement
commands :psql => 'psql'
def self.instances
run_sql_command('SELECT * FROM pg_replication_slots;')[0].split("\n").select { |l| l =~ /\|/ }.map do |l|
name, *others = l.strip.split(/\s+\|\s+/)
new({
:name => name,
:ensure => :present,
})
end
end
def self.prefetch(resources)
instances.each do |i|
if slot = resources[i.name]
slot.provider = i
end
end
end
def exists?
@property_hash[:ensure] == :present
end
def create
output = self.class.run_sql_command("SELECT * FROM pg_create_physical_replication_slot('#{resource[:name]}');")
if output[1].success?
@property_hash[:ensure] = :present
else
raise Puppet::Error, "Failed to create replication slot #{resource[:name]}:\n#{output[0]}"
end
end
def destroy
output = self.class.run_sql_command("SELECT pg_drop_replication_slot('#{resource[:name]}');")
if output[1].success?
@property_hash[:ensure] = :absent
else
raise Puppet::Error, "Failed to destroy replication slot #{resource[:name]}:\n#{output[0]}"
end
end
private
def self.run_sql_command(sql)
command = ['psql', '-t', '-c', sql]
self.run_command(command, 'postgres', 'postgres')
end
def self.run_command(command, user, group)
if Puppet::PUPPETVERSION.to_f < 3.4
Puppet::Util::SUIDManager.run_and_capture(command, user, group)
else
output = Puppet::Util::Execution.execute(command, {
:uid => user,
:gid => group,
:failonfail => false,
:combine => true,
:override_locale => true,
:custom_environment => {}
})
[output, $CHILD_STATUS.dup]
end
end
end

View file

@ -0,0 +1,16 @@
Puppet::Type.newtype(:postgresql_replication_slot) do
@doc = "Manages Postgresql replication slots.
This type allows to create and destroy replication slots
to register warm standby replication on a Postgresql
master server.
"
ensurable
newparam(:name) do
desc "The name of the slot to create. Must be a valid replication slot name."
isnamevar
newvalues /^[a-z0-9_]+$/
end
end

View file

@ -0,0 +1,92 @@
require 'spec_helper'
type = Puppet::Type.type(:postgresql_replication_slot)
describe type.provider(:ruby) do
let(:name) { 'standby' }
let(:resource) do
type.new({ :name => name, :provider => :ruby }.merge attributes)
end
let(:sql_instances) do
"abc | | physical | | | t | | | 0/3000420
def | | physical | | | t | | | 0/3000420\n"
end
class SuccessStatus
def success?
true
end
end
let(:success_status) { SuccessStatus.new }
class FailStatus
def success?
false
end
end
let(:fail_status) { FailStatus.new }
let(:provider) { resource.provider }
context 'when listing instances' do
let(:attributes) do { } end
it 'should list instances' do
provider.class.expects(:run_command).with(
['psql', '-t', '-c', 'SELECT * FROM pg_replication_slots;'],
'postgres', 'postgres').returns([sql_instances, nil])
instances = type.instances
expect(instances.size).to eq 2
expect(instances[0].name).to eq 'abc'
expect(instances[1].name).to eq 'def'
end
end
context 'when creating slot' do
let(:attributes) do { :ensure => 'present' } end
context 'when creation works' do
it 'should call psql and succeed' do
provider.class.expects(:run_command).with(
['psql', '-t', '-c', "SELECT * FROM pg_create_physical_replication_slot('standby');"],
'postgres', 'postgres').returns([nil, success_status])
expect { provider.create }.not_to raise_error
end
end
context 'when creation fails' do
it 'should call psql and fail' do
provider.class.expects(:run_command).with(
['psql', '-t', '-c', "SELECT * FROM pg_create_physical_replication_slot('standby');"],
'postgres', 'postgres').returns([nil, fail_status])
expect { provider.create }.to raise_error(Puppet::Error, /Failed to create replication slot standby:/)
end
end
end
context 'when destroying slot' do
let(:attributes) do { :ensure => 'absent' } end
context 'when destruction works' do
it 'should call psql and succeed' do
provider.class.expects(:run_command).with(
['psql', '-t', '-c', "SELECT pg_drop_replication_slot('standby');"],
'postgres', 'postgres').returns([nil, success_status])
expect { provider.destroy }.not_to raise_error
end
end
context 'when destruction fails' do
it 'should call psql and fail' do
provider.class.expects(:run_command).with(
['psql', '-t', '-c', "SELECT pg_drop_replication_slot('standby');"],
'postgres', 'postgres').returns([nil, fail_status])
expect { provider.destroy }.to raise_error(Puppet::Error, /Failed to destroy replication slot standby:/)
end
end
end
end

View file

@ -0,0 +1,11 @@
require 'spec_helper'
describe Puppet::Type.type(:postgresql_replication_slot) do
subject do
Puppet::Type.type(:postgresql_psql).new({:name => 'standby'})
end
it 'should have a name parameter' do
expect(subject[:name]).to eq 'standby'
end
end