diff --git a/app/models/pglogical_subscription.rb b/app/models/pglogical_subscription.rb index d3e21ee9e1c..eae8dd90007 100644 --- a/app/models/pglogical_subscription.rb +++ b/app/models/pglogical_subscription.rb @@ -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 diff --git a/lib/miq_pglogical.rb b/lib/miq_pglogical.rb index 443c15a1b3b..488892916c8 100644 --- a/lib/miq_pglogical.rb +++ b/lib/miq_pglogical.rb @@ -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) diff --git a/spec/models/pglogical_subscription_spec.rb b/spec/models/pglogical_subscription_spec.rb index b46a0bcf5ed..d8a47b3da6b 100644 --- a/spec/models/pglogical_subscription_spec.rb +++ b/spec/models/pglogical_subscription_spec.rb @@ -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) diff --git a/spec/replication/util/miq_pglogical_spec.rb b/spec/replication/util/miq_pglogical_spec.rb index cb7be850c2a..b041bd75797 100644 --- a/spec/replication/util/miq_pglogical_spec.rb +++ b/spec/replication/util/miq_pglogical_spec.rb @@ -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