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