commit
a50a16d97d
4 changed files with 187 additions and 0 deletions
68
lib/puppet/provider/postgresql_replication_slot/ruby.rb
Normal file
68
lib/puppet/provider/postgresql_replication_slot/ruby.rb
Normal 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
|
16
lib/puppet/type/postgresql_replication_slot.rb
Normal file
16
lib/puppet/type/postgresql_replication_slot.rb
Normal 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
|
|
@ -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
|
11
spec/unit/puppet/type/postgresql_replication_slot_spec.rb
Normal file
11
spec/unit/puppet/type/postgresql_replication_slot_spec.rb
Normal 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
|
Loading…
Reference in a new issue