Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add replication set-up methods to be queued on UI side #17956

Merged
merged 5 commits into from
Sep 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/models/pglogical_subscription.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ def delete(reload_failover_monitor_service = true)
EvmDatabase.restart_failover_monitor_service_queue if reload_failover_monitor_service
end

def self.delete_all
find(:all).each { |sub| sub.delete(false) }
def self.delete_all(list = nil)
(list.nil? ? find(:all) : list)&.each { |sub| sub.delete(false) }
EvmDatabase.restart_failover_monitor_service_queue
nil
end
Expand Down
11 changes: 11 additions & 0 deletions lib/miq_pglogical.rb
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,17 @@ def self.default_excludes
YAML.load_file(Rails.root.join("config/default_replication_exclude_tables.yml"))[:exclude_tables] | ALWAYS_EXCLUDED_TABLES
end

def self.save_remote_region(exclusion_list)
MiqRegion.replication_type = :remote
refresh_excludes(YAML.safe_load(exclusion_list))
end

def self.save_global_region(subscriptions_to_save, subscriptions_to_remove)
MiqRegion.replication_type = :global
PglogicalSubscription.delete_all(subscriptions_to_remove)
PglogicalSubscription.save_all!(subscriptions_to_save)
end

private

def pglogical(refresh = false)
Expand Down
22 changes: 22 additions & 0 deletions spec/models/pglogical_subscription_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,28 @@
end
end

describe ".delete_all" do
let(:subscription1) { double }
let(:subscription2) { double }

after do
expect(MiqQueue.where(:method_name => "restart_failover_monitor_service").count).to eq(1)
end

it "deletes all subscriptions if no parameter passed" do
allow(described_class).to receive(:find).with(:all).and_return([subscription1, subscription2])
expect(subscription1).to receive(:delete)
expect(subscription2).to receive(:delete)
described_class.delete_all
end

it "only deletes subscriptions listed in parameter if parameter passed" do
expect(subscription1).to receive(:delete)
expect(subscription2).not_to receive(:delete)
described_class.delete_all([subscription1])
end
end

describe ".save_all!" do
after do
expect(MiqQueue.where(:method_name => "restart_failover_monitor_service").count).to eq(1)
Expand Down
236 changes: 137 additions & 99 deletions spec/replication/util/miq_pglogical_spec.rb
Original file line number Diff line number Diff line change
@@ -1,145 +1,183 @@
describe MiqPglogical do
let(:connection) { ApplicationRecord.connection }
let(:pglogical) { connection.pglogical }
context "requires pglogical been installed" do
let(:connection) { ApplicationRecord.connection }
let(:pglogical) { connection.pglogical }

before do
skip "pglogical must be installed" unless pglogical.installed?
MiqServer.seed
end

describe "#active_excludes" do
it "returns an empty array if a provider is not configured" do
expect(subject.active_excludes).to eq([])
end
end

describe "#provider?" do
it "is false when a provider is not configured" do
expect(subject.provider?).to be false
end
end

describe "#node?" do
it "is false when a provider is not configured" do
expect(subject.node?).to be false
end
end

describe "#configure_provider" do
it "enables the extenstion and creates the replication set" do
subject.configure_provider
expect(pglogical.enabled?).to be true
expect(pglogical.replication_sets).to include(described_class::REPLICATION_SET_NAME)
end

it "does not enable the extension when an exception is raised" do
expect(subject).to receive(:create_replication_set).and_raise(PG::UniqueViolation)
expect { subject.configure_provider }.to raise_error(PG::UniqueViolation)
expect(pglogical.enabled?).to be false
end
end

context "when configured as a provider" do
before do
subject.configure_provider
skip "pglogical must be installed" unless pglogical.installed?
MiqServer.seed
end

describe "#active_excludes" do
it "returns the initial set of excluded tables" do
expect(subject.active_excludes).to eq(connection.tables - subject.included_tables)
it "returns an empty array if a provider is not configured" do
expect(subject.active_excludes).to eq([])
end
end

describe "#provider?" do
it "is true" do
expect(subject.provider?).to be true
it "is false when a provider is not configured" do
expect(subject.provider?).to be false
end
end

describe "#node?" do
it "is true" do
expect(subject.node?).to be true
it "is false when a provider is not configured" do
expect(subject.node?).to be false
end
end

describe "#destroy_provider" do
it "removes the provider configuration" do
subject.destroy_provider
expect(subject.provider?).to be false
expect(subject.node?).to be false
expect(connection.extension_enabled?("pglogical")).to be false
describe "#configure_provider" do
it "enables the extenstion and creates the replication set" do
subject.configure_provider
expect(pglogical.enabled?).to be true
expect(pglogical.replication_sets).to include(described_class::REPLICATION_SET_NAME)
end
end

describe "#create_replication_set" do
it "creates the correct initial set" do
expected_excludes = subject.configured_excludes
extra_excludes = subject.configured_excludes - connection.tables
actual_excludes = connection.tables - subject.included_tables
expect(actual_excludes | extra_excludes).to match_array(expected_excludes)
it "does not enable the extension when an exception is raised" do
expect(subject).to receive(:create_replication_set).and_raise(PG::UniqueViolation)
expect { subject.configure_provider }.to raise_error(PG::UniqueViolation)
expect(pglogical.enabled?).to be false
end
end

describe ".refresh_excludes" do
it "sets the configured excludes and calls refresh on an instance" do
pgl = described_class.new
expect(described_class).to receive(:new).and_return(pgl)
expect(pgl).to receive(:refresh_excludes)
context "when configured as a provider" do
before do
subject.configure_provider
end

describe "#active_excludes" do
it "returns the initial set of excluded tables" do
expect(subject.active_excludes).to eq(connection.tables - subject.included_tables)
end
end

new_excludes = %w(my new exclude tables)
described_class.refresh_excludes(new_excludes)
describe "#provider?" do
it "is true" do
expect(subject.provider?).to be true
end
end

expect(pgl.configured_excludes).to match_array(new_excludes | described_class::ALWAYS_EXCLUDED_TABLES)
describe "#node?" do
it "is true" do
expect(subject.node?).to be true
end
end
end

describe "#refresh_excludes" do
it "adds a new non excluded table" do
connection.exec_query(<<-SQL)
CREATE TABLE test (id INTEGER PRIMARY KEY)
SQL
subject.refresh_excludes
expect(subject.included_tables).to include("test")
describe "#destroy_provider" do
it "removes the provider configuration" do
subject.destroy_provider
expect(subject.provider?).to be false
expect(subject.node?).to be false
expect(connection.extension_enabled?("pglogical")).to be false
end
end

it "removes a newly excluded table" do
table = subject.included_tables.first
subject.configured_excludes += [table]
describe "#create_replication_set" do
it "creates the correct initial set" do
expected_excludes = subject.configured_excludes
extra_excludes = subject.configured_excludes - connection.tables
actual_excludes = connection.tables - subject.included_tables
expect(actual_excludes | extra_excludes).to match_array(expected_excludes)
end
end

expect(subject.active_excludes).not_to include(table)
expect(subject.included_tables).to include(table)
describe ".refresh_excludes" do
it "sets the configured excludes and calls refresh on an instance" do
pgl = described_class.new
expect(described_class).to receive(:new).and_return(pgl)
expect(pgl).to receive(:refresh_excludes)

subject.refresh_excludes
new_excludes = %w(my new exclude tables)
described_class.refresh_excludes(new_excludes)

expect(subject.active_excludes).to include(table)
expect(subject.included_tables).not_to include(table)
expect(pgl.configured_excludes).to match_array(new_excludes | described_class::ALWAYS_EXCLUDED_TABLES)
end
end

it "adds a newly included table" do
current_excludes = subject.configured_excludes
table = current_excludes.pop
subject.configured_excludes = current_excludes
describe "#refresh_excludes" do
it "adds a new non excluded table" do
connection.exec_query(<<-SQL)
CREATE TABLE test (id INTEGER PRIMARY KEY)
SQL
subject.refresh_excludes
expect(subject.included_tables).to include("test")
end

it "removes a newly excluded table" do
table = subject.included_tables.first
subject.configured_excludes += [table]

expect(subject.active_excludes).not_to include(table)
expect(subject.included_tables).to include(table)

subject.refresh_excludes

expect(subject.active_excludes).to include(table)
expect(subject.included_tables).not_to include(table)
end

it "adds a newly included table" do
current_excludes = subject.configured_excludes
table = current_excludes.pop
subject.configured_excludes = current_excludes

expect(subject.active_excludes).to include(table)
expect(subject.included_tables).not_to include(table)

expect(subject.active_excludes).to include(table)
expect(subject.included_tables).not_to include(table)
subject.refresh_excludes

subject.refresh_excludes
expect(subject.active_excludes).not_to include(table)
expect(subject.included_tables).to include(table)
end
end
end

describe ".region_to_node_name" do
it "returns the correct name" do
expect(described_class.region_to_node_name(4)).to eq("region_4")
end
end

expect(subject.active_excludes).not_to include(table)
expect(subject.included_tables).to include(table)
describe ".node_name_to_region" do
it "returns the correct region" do
expect(described_class.node_name_to_region("region_5")).to eq(5)
end
end
end

describe ".region_to_node_name" do
it "returns the correct name" do
expect(described_class.region_to_node_name(4)).to eq("region_4")
describe ".save_remote_region" do
it "sets replication type for this region to 'remote'" do
allow(described_class).to receive(:refresh_excludes)
expect(MiqRegion).to receive(:replication_type=).with(:remote)
described_class.save_remote_region("")
end

it "updates list of tables to be excluded from replication" do
tables = "---\n- vmdb_databases\n- vmdb_indexes\n- vmdb_metrics\n- vmdb_tables\n"
allow(MiqRegion).to receive(:replication_type=)
expect(described_class).to receive(:refresh_excludes).with(YAML.safe_load(tables))
described_class.save_remote_region(tables)
end
end

describe ".node_name_to_region" do
it "returns the correct region" do
expect(described_class.node_name_to_region("region_5")).to eq(5)
describe ".save_global_region" do
let(:subscription) { double }
it "sets replication type for this region to 'global'" do
allow(described_class).to receive(:refresh_excludes)
expect(MiqRegion).to receive(:replication_type=).with(:global)
described_class.save_global_region([], [])
end

it "deletes subscriptions passed as second paramer" do
allow(MiqRegion).to receive(:replication_type=)
expect(subscription).to receive(:delete)
described_class.save_global_region([], [subscription])
end

it "saves subscriptions passed as first paramer" do
allow(MiqRegion).to receive(:replication_type=)
expect(subscription).to receive(:save!)
described_class.save_global_region([subscription], [])
end
end
end